00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include "config.h"
00027 #if !HAVE_CLOSESOCKET
00028 #define closesocket close
00029 #endif
00030 #include <string.h>
00031 #include <stdlib.h>
00032 #include "libavformat/avformat.h"
00033
00034 #include "libavformat/ffm.h"
00035 #include "libavformat/network.h"
00036 #include "libavformat/os_support.h"
00037 #include "libavformat/rtpdec.h"
00038 #include "libavformat/rtsp.h"
00039 #include "libavformat/avio_internal.h"
00040 #include "libavformat/internal.h"
00041 #include "libavformat/url.h"
00042
00043 #include "libavutil/avassert.h"
00044 #include "libavutil/avstring.h"
00045 #include "libavutil/lfg.h"
00046 #include "libavutil/dict.h"
00047 #include "libavutil/mathematics.h"
00048 #include "libavutil/random_seed.h"
00049 #include "libavutil/parseutils.h"
00050 #include "libavutil/opt.h"
00051 #include "libavutil/time.h"
00052
00053 #include <stdarg.h>
00054 #include <unistd.h>
00055 #include <fcntl.h>
00056 #include <sys/ioctl.h>
00057 #if HAVE_POLL_H
00058 #include <poll.h>
00059 #endif
00060 #include <errno.h>
00061 #include <time.h>
00062 #include <sys/wait.h>
00063 #include <signal.h>
00064 #if HAVE_DLFCN_H
00065 #include <dlfcn.h>
00066 #endif
00067
00068 #include "cmdutils.h"
00069
00070 const char program_name[] = "ffserver";
00071 const int program_birth_year = 2000;
00072
00073 static const OptionDef options[];
00074
00075 enum HTTPState {
00076 HTTPSTATE_WAIT_REQUEST,
00077 HTTPSTATE_SEND_HEADER,
00078 HTTPSTATE_SEND_DATA_HEADER,
00079 HTTPSTATE_SEND_DATA,
00080 HTTPSTATE_SEND_DATA_TRAILER,
00081 HTTPSTATE_RECEIVE_DATA,
00082 HTTPSTATE_WAIT_FEED,
00083 HTTPSTATE_READY,
00084
00085 RTSPSTATE_WAIT_REQUEST,
00086 RTSPSTATE_SEND_REPLY,
00087 RTSPSTATE_SEND_PACKET,
00088 };
00089
00090 static const char *http_state[] = {
00091 "HTTP_WAIT_REQUEST",
00092 "HTTP_SEND_HEADER",
00093
00094 "SEND_DATA_HEADER",
00095 "SEND_DATA",
00096 "SEND_DATA_TRAILER",
00097 "RECEIVE_DATA",
00098 "WAIT_FEED",
00099 "READY",
00100
00101 "RTSP_WAIT_REQUEST",
00102 "RTSP_SEND_REPLY",
00103 "RTSP_SEND_PACKET",
00104 };
00105
00106 #define MAX_STREAMS 20
00107
00108 #define IOBUFFER_INIT_SIZE 8192
00109
00110
00111 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
00112 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
00113
00114 #define SYNC_TIMEOUT (10 * 1000)
00115
00116 typedef struct RTSPActionServerSetup {
00117 uint32_t ipaddr;
00118 char transport_option[512];
00119 } RTSPActionServerSetup;
00120
00121 typedef struct {
00122 int64_t count1, count2;
00123 int64_t time1, time2;
00124 } DataRateData;
00125
00126
00127 typedef struct HTTPContext {
00128 enum HTTPState state;
00129 int fd;
00130 struct sockaddr_in from_addr;
00131 struct pollfd *poll_entry;
00132 int64_t timeout;
00133 uint8_t *buffer_ptr, *buffer_end;
00134 int http_error;
00135 int post;
00136 int chunked_encoding;
00137 int chunk_size;
00138 struct HTTPContext *next;
00139 int got_key_frame;
00140 int64_t data_count;
00141
00142 int feed_fd;
00143
00144 AVFormatContext *fmt_in;
00145 int64_t start_time;
00146 int64_t first_pts;
00147 int64_t cur_pts;
00148 int64_t cur_frame_duration;
00149 int cur_frame_bytes;
00150
00151
00152 int pts_stream_index;
00153 int64_t cur_clock;
00154
00155 struct FFStream *stream;
00156
00157 int feed_streams[MAX_STREAMS];
00158 int switch_feed_streams[MAX_STREAMS];
00159 int switch_pending;
00160 AVFormatContext fmt_ctx;
00161 int last_packet_sent;
00162 int suppress_log;
00163 DataRateData datarate;
00164 int wmp_client_id;
00165 char protocol[16];
00166 char method[16];
00167 char url[128];
00168 int buffer_size;
00169 uint8_t *buffer;
00170 int is_packetized;
00171 int packet_stream_index;
00172
00173
00174 uint8_t *pb_buffer;
00175 AVIOContext *pb;
00176 int seq;
00177
00178
00179 enum RTSPLowerTransport rtp_protocol;
00180 char session_id[32];
00181 AVFormatContext *rtp_ctx[MAX_STREAMS];
00182
00183
00184 URLContext *rtp_handles[MAX_STREAMS];
00185
00186
00187 struct HTTPContext *rtsp_c;
00188 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
00189 } HTTPContext;
00190
00191
00192 enum StreamType {
00193 STREAM_TYPE_LIVE,
00194 STREAM_TYPE_STATUS,
00195 STREAM_TYPE_REDIRECT,
00196 };
00197
00198 enum IPAddressAction {
00199 IP_ALLOW = 1,
00200 IP_DENY,
00201 };
00202
00203 typedef struct IPAddressACL {
00204 struct IPAddressACL *next;
00205 enum IPAddressAction action;
00206
00207 struct in_addr first;
00208 struct in_addr last;
00209 } IPAddressACL;
00210
00211
00212 typedef struct FFStream {
00213 enum StreamType stream_type;
00214 char filename[1024];
00215 struct FFStream *feed;
00216
00217 AVDictionary *in_opts;
00218 AVInputFormat *ifmt;
00219 AVOutputFormat *fmt;
00220 IPAddressACL *acl;
00221 char dynamic_acl[1024];
00222 int nb_streams;
00223 int prebuffer;
00224 int64_t max_time;
00225 int send_on_key;
00226 AVStream *streams[MAX_STREAMS];
00227 int feed_streams[MAX_STREAMS];
00228 char feed_filename[1024];
00229
00230 char author[512];
00231 char title[512];
00232 char copyright[512];
00233 char comment[512];
00234 pid_t pid;
00235 time_t pid_start;
00236 char **child_argv;
00237 struct FFStream *next;
00238 unsigned bandwidth;
00239
00240 char *rtsp_option;
00241
00242 int is_multicast;
00243 struct in_addr multicast_ip;
00244 int multicast_port;
00245 int multicast_ttl;
00246 int loop;
00247
00248
00249 int feed_opened;
00250 int is_feed;
00251 int readonly;
00252 int truncate;
00253 int conns_served;
00254 int64_t bytes_served;
00255 int64_t feed_max_size;
00256 int64_t feed_write_index;
00257 int64_t feed_size;
00258 struct FFStream *next_feed;
00259 } FFStream;
00260
00261 typedef struct FeedData {
00262 long long data_count;
00263 float avg_frame_size;
00264 } FeedData;
00265
00266 static struct sockaddr_in my_http_addr;
00267 static struct sockaddr_in my_rtsp_addr;
00268
00269 static char logfilename[1024];
00270 static HTTPContext *first_http_ctx;
00271 static FFStream *first_feed;
00272 static FFStream *first_stream;
00273
00274 static void new_connection(int server_fd, int is_rtsp);
00275 static void close_connection(HTTPContext *c);
00276
00277
00278 static int handle_connection(HTTPContext *c);
00279 static int http_parse_request(HTTPContext *c);
00280 static int http_send_data(HTTPContext *c);
00281 static void compute_status(HTTPContext *c);
00282 static int open_input_stream(HTTPContext *c, const char *info);
00283 static int http_start_receive_data(HTTPContext *c);
00284 static int http_receive_data(HTTPContext *c);
00285
00286
00287 static int rtsp_parse_request(HTTPContext *c);
00288 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
00289 static void rtsp_cmd_options(HTTPContext *c, const char *url);
00290 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
00291 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
00292 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
00293 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
00294
00295
00296 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
00297 struct in_addr my_ip);
00298
00299
00300 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
00301 FFStream *stream, const char *session_id,
00302 enum RTSPLowerTransport rtp_protocol);
00303 static int rtp_new_av_stream(HTTPContext *c,
00304 int stream_index, struct sockaddr_in *dest_addr,
00305 HTTPContext *rtsp_c);
00306
00307 static const char *my_program_name;
00308 static const char *my_program_dir;
00309
00310 static const char *config_filename = "/etc/ffserver.conf";
00311
00312 static int ffserver_debug;
00313 static int ffserver_daemon;
00314 static int no_launch;
00315 static int need_to_start_children;
00316
00317
00318 static unsigned int nb_max_http_connections = 2000;
00319 static unsigned int nb_max_connections = 5;
00320 static unsigned int nb_connections;
00321
00322 static uint64_t max_bandwidth = 1000;
00323 static uint64_t current_bandwidth;
00324
00325 static int64_t cur_time;
00326
00327 static AVLFG random_state;
00328
00329 static FILE *logfile = NULL;
00330
00331
00332 void av_noreturn exit_program(int ret)
00333 {
00334 exit(ret);
00335 }
00336
00337
00338 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
00339 {
00340
00341 if (!ff_inet_aton(hostname, sin_addr)) {
00342 #if HAVE_GETADDRINFO
00343 struct addrinfo *ai, *cur;
00344 struct addrinfo hints = { 0 };
00345 hints.ai_family = AF_INET;
00346 if (getaddrinfo(hostname, NULL, &hints, &ai))
00347 return -1;
00348
00349
00350
00351 for (cur = ai; cur; cur = cur->ai_next) {
00352 if (cur->ai_family == AF_INET) {
00353 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
00354 freeaddrinfo(ai);
00355 return 0;
00356 }
00357 }
00358 freeaddrinfo(ai);
00359 return -1;
00360 #else
00361 struct hostent *hp;
00362 hp = gethostbyname(hostname);
00363 if (!hp)
00364 return -1;
00365 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
00366 #endif
00367 }
00368 return 0;
00369 }
00370
00371 static char *ctime1(char *buf2)
00372 {
00373 time_t ti;
00374 char *p;
00375
00376 ti = time(NULL);
00377 p = ctime(&ti);
00378 strcpy(buf2, p);
00379 p = buf2 + strlen(p) - 1;
00380 if (*p == '\n')
00381 *p = '\0';
00382 return buf2;
00383 }
00384
00385 static void http_vlog(const char *fmt, va_list vargs)
00386 {
00387 static int print_prefix = 1;
00388 if (logfile) {
00389 if (print_prefix) {
00390 char buf[32];
00391 ctime1(buf);
00392 fprintf(logfile, "%s ", buf);
00393 }
00394 print_prefix = strstr(fmt, "\n") != NULL;
00395 vfprintf(logfile, fmt, vargs);
00396 fflush(logfile);
00397 }
00398 }
00399
00400 #ifdef __GNUC__
00401 __attribute__ ((format (printf, 1, 2)))
00402 #endif
00403 static void http_log(const char *fmt, ...)
00404 {
00405 va_list vargs;
00406 va_start(vargs, fmt);
00407 http_vlog(fmt, vargs);
00408 va_end(vargs);
00409 }
00410
00411 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
00412 {
00413 static int print_prefix = 1;
00414 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
00415 if (level > av_log_get_level())
00416 return;
00417 if (print_prefix && avc)
00418 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
00419 print_prefix = strstr(fmt, "\n") != NULL;
00420 http_vlog(fmt, vargs);
00421 }
00422
00423 static void log_connection(HTTPContext *c)
00424 {
00425 if (c->suppress_log)
00426 return;
00427
00428 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
00429 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
00430 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
00431 }
00432
00433 static void update_datarate(DataRateData *drd, int64_t count)
00434 {
00435 if (!drd->time1 && !drd->count1) {
00436 drd->time1 = drd->time2 = cur_time;
00437 drd->count1 = drd->count2 = count;
00438 } else if (cur_time - drd->time2 > 5000) {
00439 drd->time1 = drd->time2;
00440 drd->count1 = drd->count2;
00441 drd->time2 = cur_time;
00442 drd->count2 = count;
00443 }
00444 }
00445
00446
00447 static int compute_datarate(DataRateData *drd, int64_t count)
00448 {
00449 if (cur_time == drd->time1)
00450 return 0;
00451
00452 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
00453 }
00454
00455
00456 static void start_children(FFStream *feed)
00457 {
00458 if (no_launch)
00459 return;
00460
00461 for (; feed; feed = feed->next) {
00462 if (feed->child_argv && !feed->pid) {
00463 feed->pid_start = time(0);
00464
00465 feed->pid = fork();
00466
00467 if (feed->pid < 0) {
00468 http_log("Unable to create children\n");
00469 exit(1);
00470 }
00471 if (!feed->pid) {
00472
00473 char pathname[1024];
00474 char *slash;
00475 int i;
00476
00477 av_strlcpy(pathname, my_program_name, sizeof(pathname));
00478
00479 slash = strrchr(pathname, '/');
00480 if (!slash)
00481 slash = pathname;
00482 else
00483 slash++;
00484 strcpy(slash, "ffmpeg");
00485
00486 http_log("Launch command line: ");
00487 http_log("%s ", pathname);
00488 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
00489 http_log("%s ", feed->child_argv[i]);
00490 http_log("\n");
00491
00492 for (i = 3; i < 256; i++)
00493 close(i);
00494
00495 if (!ffserver_debug) {
00496 i = open("/dev/null", O_RDWR);
00497 if (i != -1) {
00498 dup2(i, 0);
00499 dup2(i, 1);
00500 dup2(i, 2);
00501 close(i);
00502 }
00503 }
00504
00505
00506 if (chdir(my_program_dir) < 0) {
00507 http_log("chdir failed\n");
00508 exit(1);
00509 }
00510
00511 signal(SIGPIPE, SIG_DFL);
00512
00513 execvp(pathname, feed->child_argv);
00514
00515 _exit(1);
00516 }
00517 }
00518 }
00519 }
00520
00521
00522 static int socket_open_listen(struct sockaddr_in *my_addr)
00523 {
00524 int server_fd, tmp;
00525
00526 server_fd = socket(AF_INET,SOCK_STREAM,0);
00527 if (server_fd < 0) {
00528 perror ("socket");
00529 return -1;
00530 }
00531
00532 tmp = 1;
00533 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
00534
00535 my_addr->sin_family = AF_INET;
00536 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
00537 char bindmsg[32];
00538 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
00539 perror (bindmsg);
00540 closesocket(server_fd);
00541 return -1;
00542 }
00543
00544 if (listen (server_fd, 5) < 0) {
00545 perror ("listen");
00546 closesocket(server_fd);
00547 return -1;
00548 }
00549 ff_socket_nonblock(server_fd, 1);
00550
00551 return server_fd;
00552 }
00553
00554
00555 static void start_multicast(void)
00556 {
00557 FFStream *stream;
00558 char session_id[32];
00559 HTTPContext *rtp_c;
00560 struct sockaddr_in dest_addr;
00561 int default_port, stream_index;
00562
00563 default_port = 6000;
00564 for(stream = first_stream; stream != NULL; stream = stream->next) {
00565 if (stream->is_multicast) {
00566 unsigned random0 = av_lfg_get(&random_state);
00567 unsigned random1 = av_lfg_get(&random_state);
00568
00569 snprintf(session_id, sizeof(session_id), "%08x%08x",
00570 random0, random1);
00571
00572
00573 if (stream->multicast_port == 0) {
00574 stream->multicast_port = default_port;
00575 default_port += 100;
00576 }
00577
00578 dest_addr.sin_family = AF_INET;
00579 dest_addr.sin_addr = stream->multicast_ip;
00580 dest_addr.sin_port = htons(stream->multicast_port);
00581
00582 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
00583 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
00584 if (!rtp_c)
00585 continue;
00586
00587 if (open_input_stream(rtp_c, "") < 0) {
00588 http_log("Could not open input stream for stream '%s'\n",
00589 stream->filename);
00590 continue;
00591 }
00592
00593
00594 for(stream_index = 0; stream_index < stream->nb_streams;
00595 stream_index++) {
00596 dest_addr.sin_port = htons(stream->multicast_port +
00597 2 * stream_index);
00598 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
00599 http_log("Could not open output stream '%s/streamid=%d'\n",
00600 stream->filename, stream_index);
00601 exit(1);
00602 }
00603 }
00604
00605
00606 rtp_c->state = HTTPSTATE_SEND_DATA;
00607 }
00608 }
00609 }
00610
00611
00612 static int http_server(void)
00613 {
00614 int server_fd = 0, rtsp_server_fd = 0;
00615 int ret, delay, delay1;
00616 struct pollfd *poll_table, *poll_entry;
00617 HTTPContext *c, *c_next;
00618
00619 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
00620 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
00621 return -1;
00622 }
00623
00624 if (my_http_addr.sin_port) {
00625 server_fd = socket_open_listen(&my_http_addr);
00626 if (server_fd < 0)
00627 return -1;
00628 }
00629
00630 if (my_rtsp_addr.sin_port) {
00631 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
00632 if (rtsp_server_fd < 0)
00633 return -1;
00634 }
00635
00636 if (!rtsp_server_fd && !server_fd) {
00637 http_log("HTTP and RTSP disabled.\n");
00638 return -1;
00639 }
00640
00641 http_log("FFserver started.\n");
00642
00643 start_children(first_feed);
00644
00645 start_multicast();
00646
00647 for(;;) {
00648 poll_entry = poll_table;
00649 if (server_fd) {
00650 poll_entry->fd = server_fd;
00651 poll_entry->events = POLLIN;
00652 poll_entry++;
00653 }
00654 if (rtsp_server_fd) {
00655 poll_entry->fd = rtsp_server_fd;
00656 poll_entry->events = POLLIN;
00657 poll_entry++;
00658 }
00659
00660
00661 c = first_http_ctx;
00662 delay = 1000;
00663 while (c != NULL) {
00664 int fd;
00665 fd = c->fd;
00666 switch(c->state) {
00667 case HTTPSTATE_SEND_HEADER:
00668 case RTSPSTATE_SEND_REPLY:
00669 case RTSPSTATE_SEND_PACKET:
00670 c->poll_entry = poll_entry;
00671 poll_entry->fd = fd;
00672 poll_entry->events = POLLOUT;
00673 poll_entry++;
00674 break;
00675 case HTTPSTATE_SEND_DATA_HEADER:
00676 case HTTPSTATE_SEND_DATA:
00677 case HTTPSTATE_SEND_DATA_TRAILER:
00678 if (!c->is_packetized) {
00679
00680 c->poll_entry = poll_entry;
00681 poll_entry->fd = fd;
00682 poll_entry->events = POLLOUT;
00683 poll_entry++;
00684 } else {
00685
00686
00687
00688 delay1 = 10;
00689 if (delay1 < delay)
00690 delay = delay1;
00691 }
00692 break;
00693 case HTTPSTATE_WAIT_REQUEST:
00694 case HTTPSTATE_RECEIVE_DATA:
00695 case HTTPSTATE_WAIT_FEED:
00696 case RTSPSTATE_WAIT_REQUEST:
00697
00698 c->poll_entry = poll_entry;
00699 poll_entry->fd = fd;
00700 poll_entry->events = POLLIN;
00701 poll_entry++;
00702 break;
00703 default:
00704 c->poll_entry = NULL;
00705 break;
00706 }
00707 c = c->next;
00708 }
00709
00710
00711
00712 do {
00713 ret = poll(poll_table, poll_entry - poll_table, delay);
00714 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
00715 ff_neterrno() != AVERROR(EINTR))
00716 return -1;
00717 } while (ret < 0);
00718
00719 cur_time = av_gettime() / 1000;
00720
00721 if (need_to_start_children) {
00722 need_to_start_children = 0;
00723 start_children(first_feed);
00724 }
00725
00726
00727 for(c = first_http_ctx; c != NULL; c = c_next) {
00728 c_next = c->next;
00729 if (handle_connection(c) < 0) {
00730
00731 log_connection(c);
00732 close_connection(c);
00733 }
00734 }
00735
00736 poll_entry = poll_table;
00737 if (server_fd) {
00738
00739 if (poll_entry->revents & POLLIN)
00740 new_connection(server_fd, 0);
00741 poll_entry++;
00742 }
00743 if (rtsp_server_fd) {
00744
00745 if (poll_entry->revents & POLLIN)
00746 new_connection(rtsp_server_fd, 1);
00747 }
00748 }
00749 }
00750
00751
00752 static void start_wait_request(HTTPContext *c, int is_rtsp)
00753 {
00754 c->buffer_ptr = c->buffer;
00755 c->buffer_end = c->buffer + c->buffer_size - 1;
00756
00757 if (is_rtsp) {
00758 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
00759 c->state = RTSPSTATE_WAIT_REQUEST;
00760 } else {
00761 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
00762 c->state = HTTPSTATE_WAIT_REQUEST;
00763 }
00764 }
00765
00766 static void http_send_too_busy_reply(int fd)
00767 {
00768 char buffer[400];
00769 int len = snprintf(buffer, sizeof(buffer),
00770 "HTTP/1.0 503 Server too busy\r\n"
00771 "Content-type: text/html\r\n"
00772 "\r\n"
00773 "<html><head><title>Too busy</title></head><body>\r\n"
00774 "<p>The server is too busy to serve your request at this time.</p>\r\n"
00775 "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
00776 "</body></html>\r\n",
00777 nb_connections, nb_max_connections);
00778 av_assert0(len < sizeof(buffer));
00779 send(fd, buffer, len, 0);
00780 }
00781
00782
00783 static void new_connection(int server_fd, int is_rtsp)
00784 {
00785 struct sockaddr_in from_addr;
00786 int fd, len;
00787 HTTPContext *c = NULL;
00788
00789 len = sizeof(from_addr);
00790 fd = accept(server_fd, (struct sockaddr *)&from_addr,
00791 &len);
00792 if (fd < 0) {
00793 http_log("error during accept %s\n", strerror(errno));
00794 return;
00795 }
00796 ff_socket_nonblock(fd, 1);
00797
00798 if (nb_connections >= nb_max_connections) {
00799 http_send_too_busy_reply(fd);
00800 goto fail;
00801 }
00802
00803
00804 c = av_mallocz(sizeof(HTTPContext));
00805 if (!c)
00806 goto fail;
00807
00808 c->fd = fd;
00809 c->poll_entry = NULL;
00810 c->from_addr = from_addr;
00811 c->buffer_size = IOBUFFER_INIT_SIZE;
00812 c->buffer = av_malloc(c->buffer_size);
00813 if (!c->buffer)
00814 goto fail;
00815
00816 c->next = first_http_ctx;
00817 first_http_ctx = c;
00818 nb_connections++;
00819
00820 start_wait_request(c, is_rtsp);
00821
00822 return;
00823
00824 fail:
00825 if (c) {
00826 av_free(c->buffer);
00827 av_free(c);
00828 }
00829 closesocket(fd);
00830 }
00831
00832 static void close_connection(HTTPContext *c)
00833 {
00834 HTTPContext **cp, *c1;
00835 int i, nb_streams;
00836 AVFormatContext *ctx;
00837 URLContext *h;
00838 AVStream *st;
00839
00840
00841 cp = &first_http_ctx;
00842 while ((*cp) != NULL) {
00843 c1 = *cp;
00844 if (c1 == c)
00845 *cp = c->next;
00846 else
00847 cp = &c1->next;
00848 }
00849
00850
00851 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
00852 if (c1->rtsp_c == c)
00853 c1->rtsp_c = NULL;
00854 }
00855
00856
00857 if (c->fd >= 0)
00858 closesocket(c->fd);
00859 if (c->fmt_in) {
00860
00861 for(i=0;i<c->fmt_in->nb_streams;i++) {
00862 st = c->fmt_in->streams[i];
00863 if (st->codec->codec)
00864 avcodec_close(st->codec);
00865 }
00866 avformat_close_input(&c->fmt_in);
00867 }
00868
00869
00870 nb_streams = 0;
00871 if (c->stream)
00872 nb_streams = c->stream->nb_streams;
00873
00874 for(i=0;i<nb_streams;i++) {
00875 ctx = c->rtp_ctx[i];
00876 if (ctx) {
00877 av_write_trailer(ctx);
00878 av_dict_free(&ctx->metadata);
00879 av_free(ctx->streams[0]);
00880 av_free(ctx);
00881 }
00882 h = c->rtp_handles[i];
00883 if (h)
00884 ffurl_close(h);
00885 }
00886
00887 ctx = &c->fmt_ctx;
00888
00889 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
00890 if (ctx->oformat) {
00891
00892 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
00893 av_write_trailer(ctx);
00894 av_freep(&c->pb_buffer);
00895 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
00896 }
00897 }
00898 }
00899
00900 for(i=0; i<ctx->nb_streams; i++)
00901 av_free(ctx->streams[i]);
00902
00903 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
00904 current_bandwidth -= c->stream->bandwidth;
00905
00906
00907 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
00908 c->stream->feed_opened = 0;
00909 close(c->feed_fd);
00910 }
00911
00912 av_freep(&c->pb_buffer);
00913 av_freep(&c->packet_buffer);
00914 av_free(c->buffer);
00915 av_free(c);
00916 nb_connections--;
00917 }
00918
00919 static int handle_connection(HTTPContext *c)
00920 {
00921 int len, ret;
00922
00923 switch(c->state) {
00924 case HTTPSTATE_WAIT_REQUEST:
00925 case RTSPSTATE_WAIT_REQUEST:
00926
00927 if ((c->timeout - cur_time) < 0)
00928 return -1;
00929 if (c->poll_entry->revents & (POLLERR | POLLHUP))
00930 return -1;
00931
00932
00933 if (!(c->poll_entry->revents & POLLIN))
00934 return 0;
00935
00936 read_loop:
00937 len = recv(c->fd, c->buffer_ptr, 1, 0);
00938 if (len < 0) {
00939 if (ff_neterrno() != AVERROR(EAGAIN) &&
00940 ff_neterrno() != AVERROR(EINTR))
00941 return -1;
00942 } else if (len == 0) {
00943 return -1;
00944 } else {
00945
00946 uint8_t *ptr;
00947 c->buffer_ptr += len;
00948 ptr = c->buffer_ptr;
00949 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
00950 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
00951
00952 if (c->state == HTTPSTATE_WAIT_REQUEST) {
00953 ret = http_parse_request(c);
00954 } else {
00955 ret = rtsp_parse_request(c);
00956 }
00957 if (ret < 0)
00958 return -1;
00959 } else if (ptr >= c->buffer_end) {
00960
00961 return -1;
00962 } else goto read_loop;
00963 }
00964 break;
00965
00966 case HTTPSTATE_SEND_HEADER:
00967 if (c->poll_entry->revents & (POLLERR | POLLHUP))
00968 return -1;
00969
00970
00971 if (!(c->poll_entry->revents & POLLOUT))
00972 return 0;
00973 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
00974 if (len < 0) {
00975 if (ff_neterrno() != AVERROR(EAGAIN) &&
00976 ff_neterrno() != AVERROR(EINTR)) {
00977
00978 av_freep(&c->pb_buffer);
00979 return -1;
00980 }
00981 } else {
00982 c->buffer_ptr += len;
00983 if (c->stream)
00984 c->stream->bytes_served += len;
00985 c->data_count += len;
00986 if (c->buffer_ptr >= c->buffer_end) {
00987 av_freep(&c->pb_buffer);
00988
00989 if (c->http_error)
00990 return -1;
00991
00992 c->state = HTTPSTATE_SEND_DATA_HEADER;
00993 c->buffer_ptr = c->buffer_end = c->buffer;
00994 }
00995 }
00996 break;
00997
00998 case HTTPSTATE_SEND_DATA:
00999 case HTTPSTATE_SEND_DATA_HEADER:
01000 case HTTPSTATE_SEND_DATA_TRAILER:
01001
01002
01003
01004 if (!c->is_packetized) {
01005 if (c->poll_entry->revents & (POLLERR | POLLHUP))
01006 return -1;
01007
01008
01009 if (!(c->poll_entry->revents & POLLOUT))
01010 return 0;
01011 }
01012 if (http_send_data(c) < 0)
01013 return -1;
01014
01015 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
01016 return -1;
01017 break;
01018 case HTTPSTATE_RECEIVE_DATA:
01019
01020 if (c->poll_entry->revents & (POLLERR | POLLHUP))
01021 return -1;
01022 if (!(c->poll_entry->revents & POLLIN))
01023 return 0;
01024 if (http_receive_data(c) < 0)
01025 return -1;
01026 break;
01027 case HTTPSTATE_WAIT_FEED:
01028
01029 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
01030 return -1;
01031
01032
01033 break;
01034
01035 case RTSPSTATE_SEND_REPLY:
01036 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
01037 av_freep(&c->pb_buffer);
01038 return -1;
01039 }
01040
01041 if (!(c->poll_entry->revents & POLLOUT))
01042 return 0;
01043 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
01044 if (len < 0) {
01045 if (ff_neterrno() != AVERROR(EAGAIN) &&
01046 ff_neterrno() != AVERROR(EINTR)) {
01047
01048 av_freep(&c->pb_buffer);
01049 return -1;
01050 }
01051 } else {
01052 c->buffer_ptr += len;
01053 c->data_count += len;
01054 if (c->buffer_ptr >= c->buffer_end) {
01055
01056 av_freep(&c->pb_buffer);
01057 start_wait_request(c, 1);
01058 }
01059 }
01060 break;
01061 case RTSPSTATE_SEND_PACKET:
01062 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
01063 av_freep(&c->packet_buffer);
01064 return -1;
01065 }
01066
01067 if (!(c->poll_entry->revents & POLLOUT))
01068 return 0;
01069 len = send(c->fd, c->packet_buffer_ptr,
01070 c->packet_buffer_end - c->packet_buffer_ptr, 0);
01071 if (len < 0) {
01072 if (ff_neterrno() != AVERROR(EAGAIN) &&
01073 ff_neterrno() != AVERROR(EINTR)) {
01074
01075 av_freep(&c->packet_buffer);
01076 return -1;
01077 }
01078 } else {
01079 c->packet_buffer_ptr += len;
01080 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
01081
01082 av_freep(&c->packet_buffer);
01083 c->state = RTSPSTATE_WAIT_REQUEST;
01084 }
01085 }
01086 break;
01087 case HTTPSTATE_READY:
01088
01089 break;
01090 default:
01091 return -1;
01092 }
01093 return 0;
01094 }
01095
01096 static int extract_rates(char *rates, int ratelen, const char *request)
01097 {
01098 const char *p;
01099
01100 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
01101 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
01102 const char *q = p + 7;
01103
01104 while (*q && *q != '\n' && isspace(*q))
01105 q++;
01106
01107 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
01108 int stream_no;
01109 int rate_no;
01110
01111 q += 20;
01112
01113 memset(rates, 0xff, ratelen);
01114
01115 while (1) {
01116 while (*q && *q != '\n' && *q != ':')
01117 q++;
01118
01119 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
01120 break;
01121
01122 stream_no--;
01123 if (stream_no < ratelen && stream_no >= 0)
01124 rates[stream_no] = rate_no;
01125
01126 while (*q && *q != '\n' && !isspace(*q))
01127 q++;
01128 }
01129
01130 return 1;
01131 }
01132 }
01133 p = strchr(p, '\n');
01134 if (!p)
01135 break;
01136
01137 p++;
01138 }
01139
01140 return 0;
01141 }
01142
01143 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
01144 {
01145 int i;
01146 int best_bitrate = 100000000;
01147 int best = -1;
01148
01149 for (i = 0; i < feed->nb_streams; i++) {
01150 AVCodecContext *feed_codec = feed->streams[i]->codec;
01151
01152 if (feed_codec->codec_id != codec->codec_id ||
01153 feed_codec->sample_rate != codec->sample_rate ||
01154 feed_codec->width != codec->width ||
01155 feed_codec->height != codec->height)
01156 continue;
01157
01158
01159
01160
01161
01162
01163
01164 if (feed_codec->bit_rate <= bit_rate) {
01165 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
01166 best_bitrate = feed_codec->bit_rate;
01167 best = i;
01168 }
01169 } else {
01170 if (feed_codec->bit_rate < best_bitrate) {
01171 best_bitrate = feed_codec->bit_rate;
01172 best = i;
01173 }
01174 }
01175 }
01176
01177 return best;
01178 }
01179
01180 static int modify_current_stream(HTTPContext *c, char *rates)
01181 {
01182 int i;
01183 FFStream *req = c->stream;
01184 int action_required = 0;
01185
01186
01187 if (!req->feed)
01188 return 0;
01189
01190 for (i = 0; i < req->nb_streams; i++) {
01191 AVCodecContext *codec = req->streams[i]->codec;
01192
01193 switch(rates[i]) {
01194 case 0:
01195 c->switch_feed_streams[i] = req->feed_streams[i];
01196 break;
01197 case 1:
01198 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
01199 break;
01200 case 2:
01201
01202 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
01203 #ifdef WANTS_OFF
01204
01205 c->switch_feed_streams[i] = -2;
01206 c->feed_streams[i] = -2;
01207 #endif
01208 break;
01209 }
01210
01211 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
01212 action_required = 1;
01213 }
01214
01215 return action_required;
01216 }
01217
01218
01219
01220 static void skip_spaces(const char **pp)
01221 {
01222 const char *p;
01223 p = *pp;
01224 while (*p == ' ' || *p == '\t')
01225 p++;
01226 *pp = p;
01227 }
01228
01229 static void get_word(char *buf, int buf_size, const char **pp)
01230 {
01231 const char *p;
01232 char *q;
01233
01234 p = *pp;
01235 skip_spaces(&p);
01236 q = buf;
01237 while (!isspace(*p) && *p != '\0') {
01238 if ((q - buf) < buf_size - 1)
01239 *q++ = *p;
01240 p++;
01241 }
01242 if (buf_size > 0)
01243 *q = '\0';
01244 *pp = p;
01245 }
01246
01247 static void get_arg(char *buf, int buf_size, const char **pp)
01248 {
01249 const char *p;
01250 char *q;
01251 int quote;
01252
01253 p = *pp;
01254 while (isspace(*p)) p++;
01255 q = buf;
01256 quote = 0;
01257 if (*p == '\"' || *p == '\'')
01258 quote = *p++;
01259 for(;;) {
01260 if (quote) {
01261 if (*p == quote)
01262 break;
01263 } else {
01264 if (isspace(*p))
01265 break;
01266 }
01267 if (*p == '\0')
01268 break;
01269 if ((q - buf) < buf_size - 1)
01270 *q++ = *p;
01271 p++;
01272 }
01273 *q = '\0';
01274 if (quote && *p == quote)
01275 p++;
01276 *pp = p;
01277 }
01278
01279 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
01280 const char *p, const char *filename, int line_num)
01281 {
01282 char arg[1024];
01283 IPAddressACL acl;
01284 int errors = 0;
01285
01286 get_arg(arg, sizeof(arg), &p);
01287 if (av_strcasecmp(arg, "allow") == 0)
01288 acl.action = IP_ALLOW;
01289 else if (av_strcasecmp(arg, "deny") == 0)
01290 acl.action = IP_DENY;
01291 else {
01292 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
01293 filename, line_num, arg);
01294 errors++;
01295 }
01296
01297 get_arg(arg, sizeof(arg), &p);
01298
01299 if (resolve_host(&acl.first, arg) != 0) {
01300 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
01301 filename, line_num, arg);
01302 errors++;
01303 } else
01304 acl.last = acl.first;
01305
01306 get_arg(arg, sizeof(arg), &p);
01307
01308 if (arg[0]) {
01309 if (resolve_host(&acl.last, arg) != 0) {
01310 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
01311 filename, line_num, arg);
01312 errors++;
01313 }
01314 }
01315
01316 if (!errors) {
01317 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
01318 IPAddressACL **naclp = 0;
01319
01320 acl.next = 0;
01321 *nacl = acl;
01322
01323 if (stream)
01324 naclp = &stream->acl;
01325 else if (feed)
01326 naclp = &feed->acl;
01327 else if (ext_acl)
01328 naclp = &ext_acl;
01329 else {
01330 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
01331 filename, line_num);
01332 errors++;
01333 }
01334
01335 if (naclp) {
01336 while (*naclp)
01337 naclp = &(*naclp)->next;
01338
01339 *naclp = nacl;
01340 }
01341 }
01342 }
01343
01344
01345 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
01346 {
01347 FILE* f;
01348 char line[1024];
01349 char cmd[1024];
01350 IPAddressACL *acl = NULL;
01351 int line_num = 0;
01352 const char *p;
01353
01354 f = fopen(stream->dynamic_acl, "r");
01355 if (!f) {
01356 perror(stream->dynamic_acl);
01357 return NULL;
01358 }
01359
01360 acl = av_mallocz(sizeof(IPAddressACL));
01361
01362
01363 for(;;) {
01364 if (fgets(line, sizeof(line), f) == NULL)
01365 break;
01366 line_num++;
01367 p = line;
01368 while (isspace(*p))
01369 p++;
01370 if (*p == '\0' || *p == '#')
01371 continue;
01372 get_arg(cmd, sizeof(cmd), &p);
01373
01374 if (!av_strcasecmp(cmd, "ACL"))
01375 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
01376 }
01377 fclose(f);
01378 return acl;
01379 }
01380
01381
01382 static void free_acl_list(IPAddressACL *in_acl)
01383 {
01384 IPAddressACL *pacl,*pacl2;
01385
01386 pacl = in_acl;
01387 while(pacl) {
01388 pacl2 = pacl;
01389 pacl = pacl->next;
01390 av_freep(pacl2);
01391 }
01392 }
01393
01394 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
01395 {
01396 enum IPAddressAction last_action = IP_DENY;
01397 IPAddressACL *acl;
01398 struct in_addr *src = &c->from_addr.sin_addr;
01399 unsigned long src_addr = src->s_addr;
01400
01401 for (acl = in_acl; acl; acl = acl->next) {
01402 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
01403 return (acl->action == IP_ALLOW) ? 1 : 0;
01404 last_action = acl->action;
01405 }
01406
01407
01408 return (last_action == IP_DENY) ? 1 : 0;
01409 }
01410
01411 static int validate_acl(FFStream *stream, HTTPContext *c)
01412 {
01413 int ret = 0;
01414 IPAddressACL *acl;
01415
01416
01417
01418 ret = validate_acl_list(stream->acl, c);
01419
01420 if (stream->dynamic_acl[0]) {
01421 acl = parse_dynamic_acl(stream, c);
01422
01423 ret = validate_acl_list(acl, c);
01424
01425 free_acl_list(acl);
01426 }
01427
01428 return ret;
01429 }
01430
01431
01432
01433 static void compute_real_filename(char *filename, int max_size)
01434 {
01435 char file1[1024];
01436 char file2[1024];
01437 char *p;
01438 FFStream *stream;
01439
01440
01441 av_strlcpy(file1, filename, sizeof(file1));
01442 p = strrchr(file1, '.');
01443 if (p)
01444 *p = '\0';
01445 for(stream = first_stream; stream != NULL; stream = stream->next) {
01446 av_strlcpy(file2, stream->filename, sizeof(file2));
01447 p = strrchr(file2, '.');
01448 if (p)
01449 *p = '\0';
01450 if (!strcmp(file1, file2)) {
01451 av_strlcpy(filename, stream->filename, max_size);
01452 break;
01453 }
01454 }
01455 }
01456
01457 enum RedirType {
01458 REDIR_NONE,
01459 REDIR_ASX,
01460 REDIR_RAM,
01461 REDIR_ASF,
01462 REDIR_RTSP,
01463 REDIR_SDP,
01464 };
01465
01466
01467 static int http_parse_request(HTTPContext *c)
01468 {
01469 char *p;
01470 enum RedirType redir_type;
01471 char cmd[32];
01472 char info[1024], filename[1024];
01473 char url[1024], *q;
01474 char protocol[32];
01475 char msg[1024];
01476 const char *mime_type;
01477 FFStream *stream;
01478 int i;
01479 char ratebuf[32];
01480 char *useragent = 0;
01481
01482 p = c->buffer;
01483 get_word(cmd, sizeof(cmd), (const char **)&p);
01484 av_strlcpy(c->method, cmd, sizeof(c->method));
01485
01486 if (!strcmp(cmd, "GET"))
01487 c->post = 0;
01488 else if (!strcmp(cmd, "POST"))
01489 c->post = 1;
01490 else
01491 return -1;
01492
01493 get_word(url, sizeof(url), (const char **)&p);
01494 av_strlcpy(c->url, url, sizeof(c->url));
01495
01496 get_word(protocol, sizeof(protocol), (const char **)&p);
01497 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
01498 return -1;
01499
01500 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
01501
01502 if (ffserver_debug)
01503 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
01504
01505
01506 p = strchr(url, '?');
01507 if (p) {
01508 av_strlcpy(info, p, sizeof(info));
01509 *p = '\0';
01510 } else
01511 info[0] = '\0';
01512
01513 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
01514
01515 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
01516 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
01517 useragent = p + 11;
01518 if (*useragent && *useragent != '\n' && isspace(*useragent))
01519 useragent++;
01520 break;
01521 }
01522 p = strchr(p, '\n');
01523 if (!p)
01524 break;
01525
01526 p++;
01527 }
01528
01529 redir_type = REDIR_NONE;
01530 if (av_match_ext(filename, "asx")) {
01531 redir_type = REDIR_ASX;
01532 filename[strlen(filename)-1] = 'f';
01533 } else if (av_match_ext(filename, "asf") &&
01534 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
01535
01536 redir_type = REDIR_ASF;
01537 } else if (av_match_ext(filename, "rpm,ram")) {
01538 redir_type = REDIR_RAM;
01539 strcpy(filename + strlen(filename)-2, "m");
01540 } else if (av_match_ext(filename, "rtsp")) {
01541 redir_type = REDIR_RTSP;
01542 compute_real_filename(filename, sizeof(filename) - 1);
01543 } else if (av_match_ext(filename, "sdp")) {
01544 redir_type = REDIR_SDP;
01545 compute_real_filename(filename, sizeof(filename) - 1);
01546 }
01547
01548
01549 if (!strlen(filename))
01550 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
01551
01552 stream = first_stream;
01553 while (stream != NULL) {
01554 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
01555 break;
01556 stream = stream->next;
01557 }
01558 if (stream == NULL) {
01559 snprintf(msg, sizeof(msg), "File '%s' not found", url);
01560 http_log("File '%s' not found\n", url);
01561 goto send_error;
01562 }
01563
01564 c->stream = stream;
01565 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
01566 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
01567
01568 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
01569 c->http_error = 301;
01570 q = c->buffer;
01571 snprintf(q, c->buffer_size,
01572 "HTTP/1.0 301 Moved\r\n"
01573 "Location: %s\r\n"
01574 "Content-type: text/html\r\n"
01575 "\r\n"
01576 "<html><head><title>Moved</title></head><body>\r\n"
01577 "You should be <a href=\"%s\">redirected</a>.\r\n"
01578 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
01579 q += strlen(q);
01580
01581 c->buffer_ptr = c->buffer;
01582 c->buffer_end = q;
01583 c->state = HTTPSTATE_SEND_HEADER;
01584 return 0;
01585 }
01586
01587
01588 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
01589 if (modify_current_stream(c, ratebuf)) {
01590 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
01591 if (c->switch_feed_streams[i] >= 0)
01592 c->switch_feed_streams[i] = -1;
01593 }
01594 }
01595 }
01596
01597 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
01598 current_bandwidth += stream->bandwidth;
01599
01600
01601 if (stream->feed_opened) {
01602 snprintf(msg, sizeof(msg), "This feed is already being received.");
01603 http_log("Feed '%s' already being received\n", stream->feed_filename);
01604 goto send_error;
01605 }
01606
01607 if (c->post == 0 && max_bandwidth < current_bandwidth) {
01608 c->http_error = 503;
01609 q = c->buffer;
01610 snprintf(q, c->buffer_size,
01611 "HTTP/1.0 503 Server too busy\r\n"
01612 "Content-type: text/html\r\n"
01613 "\r\n"
01614 "<html><head><title>Too busy</title></head><body>\r\n"
01615 "<p>The server is too busy to serve your request at this time.</p>\r\n"
01616 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
01617 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
01618 "</body></html>\r\n", current_bandwidth, max_bandwidth);
01619 q += strlen(q);
01620
01621 c->buffer_ptr = c->buffer;
01622 c->buffer_end = q;
01623 c->state = HTTPSTATE_SEND_HEADER;
01624 return 0;
01625 }
01626
01627 if (redir_type != REDIR_NONE) {
01628 char *hostinfo = 0;
01629
01630 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
01631 if (av_strncasecmp(p, "Host:", 5) == 0) {
01632 hostinfo = p + 5;
01633 break;
01634 }
01635 p = strchr(p, '\n');
01636 if (!p)
01637 break;
01638
01639 p++;
01640 }
01641
01642 if (hostinfo) {
01643 char *eoh;
01644 char hostbuf[260];
01645
01646 while (isspace(*hostinfo))
01647 hostinfo++;
01648
01649 eoh = strchr(hostinfo, '\n');
01650 if (eoh) {
01651 if (eoh[-1] == '\r')
01652 eoh--;
01653
01654 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
01655 memcpy(hostbuf, hostinfo, eoh - hostinfo);
01656 hostbuf[eoh - hostinfo] = 0;
01657
01658 c->http_error = 200;
01659 q = c->buffer;
01660 switch(redir_type) {
01661 case REDIR_ASX:
01662 snprintf(q, c->buffer_size,
01663 "HTTP/1.0 200 ASX Follows\r\n"
01664 "Content-type: video/x-ms-asf\r\n"
01665 "\r\n"
01666 "<ASX Version=\"3\">\r\n"
01667
01668 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
01669 "</ASX>\r\n", hostbuf, filename, info);
01670 q += strlen(q);
01671 break;
01672 case REDIR_RAM:
01673 snprintf(q, c->buffer_size,
01674 "HTTP/1.0 200 RAM Follows\r\n"
01675 "Content-type: audio/x-pn-realaudio\r\n"
01676 "\r\n"
01677 "# Autogenerated by ffserver\r\n"
01678 "http://%s/%s%s\r\n", hostbuf, filename, info);
01679 q += strlen(q);
01680 break;
01681 case REDIR_ASF:
01682 snprintf(q, c->buffer_size,
01683 "HTTP/1.0 200 ASF Redirect follows\r\n"
01684 "Content-type: video/x-ms-asf\r\n"
01685 "\r\n"
01686 "[Reference]\r\n"
01687 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
01688 q += strlen(q);
01689 break;
01690 case REDIR_RTSP:
01691 {
01692 char hostname[256], *p;
01693
01694 av_strlcpy(hostname, hostbuf, sizeof(hostname));
01695 p = strrchr(hostname, ':');
01696 if (p)
01697 *p = '\0';
01698 snprintf(q, c->buffer_size,
01699 "HTTP/1.0 200 RTSP Redirect follows\r\n"
01700
01701 "Content-type: application/x-rtsp\r\n"
01702 "\r\n"
01703 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
01704 q += strlen(q);
01705 }
01706 break;
01707 case REDIR_SDP:
01708 {
01709 uint8_t *sdp_data;
01710 int sdp_data_size, len;
01711 struct sockaddr_in my_addr;
01712
01713 snprintf(q, c->buffer_size,
01714 "HTTP/1.0 200 OK\r\n"
01715 "Content-type: application/sdp\r\n"
01716 "\r\n");
01717 q += strlen(q);
01718
01719 len = sizeof(my_addr);
01720 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
01721
01722
01723 sdp_data_size = prepare_sdp_description(stream,
01724 &sdp_data,
01725 my_addr.sin_addr);
01726 if (sdp_data_size > 0) {
01727 memcpy(q, sdp_data, sdp_data_size);
01728 q += sdp_data_size;
01729 *q = '\0';
01730 av_free(sdp_data);
01731 }
01732 }
01733 break;
01734 default:
01735 abort();
01736 break;
01737 }
01738
01739
01740 c->buffer_ptr = c->buffer;
01741 c->buffer_end = q;
01742 c->state = HTTPSTATE_SEND_HEADER;
01743 return 0;
01744 }
01745 }
01746 }
01747
01748 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
01749 goto send_error;
01750 }
01751
01752 stream->conns_served++;
01753
01754
01755
01756 if (c->post) {
01757
01758 if (!stream->is_feed) {
01759
01760
01761 char *logline = 0;
01762 int client_id = 0;
01763
01764 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
01765 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
01766 logline = p;
01767 break;
01768 }
01769 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
01770 client_id = strtol(p + 18, 0, 10);
01771 p = strchr(p, '\n');
01772 if (!p)
01773 break;
01774
01775 p++;
01776 }
01777
01778 if (logline) {
01779 char *eol = strchr(logline, '\n');
01780
01781 logline += 17;
01782
01783 if (eol) {
01784 if (eol[-1] == '\r')
01785 eol--;
01786 http_log("%.*s\n", (int) (eol - logline), logline);
01787 c->suppress_log = 1;
01788 }
01789 }
01790
01791 #ifdef DEBUG
01792 http_log("\nGot request:\n%s\n", c->buffer);
01793 #endif
01794
01795 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
01796 HTTPContext *wmpc;
01797
01798
01799 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
01800 if (wmpc->wmp_client_id == client_id)
01801 break;
01802 }
01803
01804 if (wmpc && modify_current_stream(wmpc, ratebuf))
01805 wmpc->switch_pending = 1;
01806 }
01807
01808 snprintf(msg, sizeof(msg), "POST command not handled");
01809 c->stream = 0;
01810 goto send_error;
01811 }
01812 if (http_start_receive_data(c) < 0) {
01813 snprintf(msg, sizeof(msg), "could not open feed");
01814 goto send_error;
01815 }
01816 c->http_error = 0;
01817 c->state = HTTPSTATE_RECEIVE_DATA;
01818 return 0;
01819 }
01820
01821 #ifdef DEBUG
01822 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
01823 http_log("\nGot request:\n%s\n", c->buffer);
01824 #endif
01825
01826 if (c->stream->stream_type == STREAM_TYPE_STATUS)
01827 goto send_status;
01828
01829
01830 if (open_input_stream(c, info) < 0) {
01831 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
01832 goto send_error;
01833 }
01834
01835
01836 c->buffer[0] = 0;
01837 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
01838 mime_type = c->stream->fmt->mime_type;
01839 if (!mime_type)
01840 mime_type = "application/x-octet-stream";
01841 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
01842
01843
01844 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
01845
01846
01847 c->wmp_client_id = av_lfg_get(&random_state);
01848
01849 av_strlcatf(c->buffer, c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
01850 }
01851 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
01852 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
01853 q = c->buffer + strlen(c->buffer);
01854
01855
01856 c->http_error = 0;
01857 c->buffer_ptr = c->buffer;
01858 c->buffer_end = q;
01859 c->state = HTTPSTATE_SEND_HEADER;
01860 return 0;
01861 send_error:
01862 c->http_error = 404;
01863 q = c->buffer;
01864 snprintf(q, c->buffer_size,
01865 "HTTP/1.0 404 Not Found\r\n"
01866 "Content-type: text/html\r\n"
01867 "\r\n"
01868 "<html>\n"
01869 "<head><title>404 Not Found</title></head>\n"
01870 "<body>%s</body>\n"
01871 "</html>\n", msg);
01872 q += strlen(q);
01873
01874 c->buffer_ptr = c->buffer;
01875 c->buffer_end = q;
01876 c->state = HTTPSTATE_SEND_HEADER;
01877 return 0;
01878 send_status:
01879 compute_status(c);
01880 c->http_error = 200;
01881
01882 c->state = HTTPSTATE_SEND_HEADER;
01883 return 0;
01884 }
01885
01886 static void fmt_bytecount(AVIOContext *pb, int64_t count)
01887 {
01888 static const char suffix[] = " kMGTP";
01889 const char *s;
01890
01891 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
01892
01893 avio_printf(pb, "%"PRId64"%c", count, *s);
01894 }
01895
01896 static void compute_status(HTTPContext *c)
01897 {
01898 HTTPContext *c1;
01899 FFStream *stream;
01900 char *p;
01901 time_t ti;
01902 int i, len;
01903 AVIOContext *pb;
01904
01905 if (avio_open_dyn_buf(&pb) < 0) {
01906
01907 c->buffer_ptr = c->buffer;
01908 c->buffer_end = c->buffer;
01909 return;
01910 }
01911
01912 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
01913 avio_printf(pb, "Content-type: %s\r\n", "text/html");
01914 avio_printf(pb, "Pragma: no-cache\r\n");
01915 avio_printf(pb, "\r\n");
01916
01917 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
01918 if (c->stream->feed_filename[0])
01919 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
01920 avio_printf(pb, "</head>\n<body>");
01921 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
01922
01923 avio_printf(pb, "<h2>Available Streams</h2>\n");
01924 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
01925 avio_printf(pb, "<tr><th valign=top>Path<th align=left>Served<br>Conns<th><br>bytes<th valign=top>Format<th>Bit rate<br>kbits/s<th align=left>Video<br>kbits/s<th><br>Codec<th align=left>Audio<br>kbits/s<th><br>Codec<th align=left valign=top>Feed\n");
01926 stream = first_stream;
01927 while (stream != NULL) {
01928 char sfilename[1024];
01929 char *eosf;
01930
01931 if (stream->feed != stream) {
01932 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
01933 eosf = sfilename + strlen(sfilename);
01934 if (eosf - sfilename >= 4) {
01935 if (strcmp(eosf - 4, ".asf") == 0)
01936 strcpy(eosf - 4, ".asx");
01937 else if (strcmp(eosf - 3, ".rm") == 0)
01938 strcpy(eosf - 3, ".ram");
01939 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
01940
01941
01942
01943 eosf = strrchr(sfilename, '.');
01944 if (!eosf)
01945 eosf = sfilename + strlen(sfilename);
01946 if (stream->is_multicast)
01947 strcpy(eosf, ".sdp");
01948 else
01949 strcpy(eosf, ".rtsp");
01950 }
01951 }
01952
01953 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
01954 sfilename, stream->filename);
01955 avio_printf(pb, "<td align=right> %d <td align=right> ",
01956 stream->conns_served);
01957 fmt_bytecount(pb, stream->bytes_served);
01958 switch(stream->stream_type) {
01959 case STREAM_TYPE_LIVE: {
01960 int audio_bit_rate = 0;
01961 int video_bit_rate = 0;
01962 const char *audio_codec_name = "";
01963 const char *video_codec_name = "";
01964 const char *audio_codec_name_extra = "";
01965 const char *video_codec_name_extra = "";
01966
01967 for(i=0;i<stream->nb_streams;i++) {
01968 AVStream *st = stream->streams[i];
01969 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
01970 switch(st->codec->codec_type) {
01971 case AVMEDIA_TYPE_AUDIO:
01972 audio_bit_rate += st->codec->bit_rate;
01973 if (codec) {
01974 if (*audio_codec_name)
01975 audio_codec_name_extra = "...";
01976 audio_codec_name = codec->name;
01977 }
01978 break;
01979 case AVMEDIA_TYPE_VIDEO:
01980 video_bit_rate += st->codec->bit_rate;
01981 if (codec) {
01982 if (*video_codec_name)
01983 video_codec_name_extra = "...";
01984 video_codec_name = codec->name;
01985 }
01986 break;
01987 case AVMEDIA_TYPE_DATA:
01988 video_bit_rate += st->codec->bit_rate;
01989 break;
01990 default:
01991 abort();
01992 }
01993 }
01994 avio_printf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
01995 stream->fmt->name,
01996 stream->bandwidth,
01997 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
01998 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
01999 if (stream->feed)
02000 avio_printf(pb, "<td>%s", stream->feed->filename);
02001 else
02002 avio_printf(pb, "<td>%s", stream->feed_filename);
02003 avio_printf(pb, "\n");
02004 }
02005 break;
02006 default:
02007 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
02008 break;
02009 }
02010 }
02011 stream = stream->next;
02012 }
02013 avio_printf(pb, "</table>\n");
02014
02015 stream = first_stream;
02016 while (stream != NULL) {
02017 if (stream->feed == stream) {
02018 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
02019 if (stream->pid) {
02020 avio_printf(pb, "Running as pid %d.\n", stream->pid);
02021
02022 #if defined(linux) && !defined(CONFIG_NOCUTILS)
02023 {
02024 FILE *pid_stat;
02025 char ps_cmd[64];
02026
02027
02028 snprintf(ps_cmd, sizeof(ps_cmd),
02029 "ps -o \"%%cpu,cputime\" --no-headers %d",
02030 stream->pid);
02031
02032 pid_stat = popen(ps_cmd, "r");
02033 if (pid_stat) {
02034 char cpuperc[10];
02035 char cpuused[64];
02036
02037 if (fscanf(pid_stat, "%10s %64s", cpuperc,
02038 cpuused) == 2) {
02039 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
02040 cpuperc, cpuused);
02041 }
02042 fclose(pid_stat);
02043 }
02044 }
02045 #endif
02046
02047 avio_printf(pb, "<p>");
02048 }
02049 avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
02050
02051 for (i = 0; i < stream->nb_streams; i++) {
02052 AVStream *st = stream->streams[i];
02053 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
02054 const char *type = "unknown";
02055 char parameters[64];
02056
02057 parameters[0] = 0;
02058
02059 switch(st->codec->codec_type) {
02060 case AVMEDIA_TYPE_AUDIO:
02061 type = "audio";
02062 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
02063 break;
02064 case AVMEDIA_TYPE_VIDEO:
02065 type = "video";
02066 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
02067 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
02068 break;
02069 default:
02070 abort();
02071 }
02072 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
02073 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
02074 }
02075 avio_printf(pb, "</table>\n");
02076
02077 }
02078 stream = stream->next;
02079 }
02080
02081
02082 avio_printf(pb, "<h2>Connection Status</h2>\n");
02083
02084 avio_printf(pb, "Number of connections: %d / %d<br>\n",
02085 nb_connections, nb_max_connections);
02086
02087 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
02088 current_bandwidth, max_bandwidth);
02089
02090 avio_printf(pb, "<table>\n");
02091 avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
02092 c1 = first_http_ctx;
02093 i = 0;
02094 while (c1 != NULL) {
02095 int bitrate;
02096 int j;
02097
02098 bitrate = 0;
02099 if (c1->stream) {
02100 for (j = 0; j < c1->stream->nb_streams; j++) {
02101 if (!c1->stream->feed)
02102 bitrate += c1->stream->streams[j]->codec->bit_rate;
02103 else if (c1->feed_streams[j] >= 0)
02104 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
02105 }
02106 }
02107
02108 i++;
02109 p = inet_ntoa(c1->from_addr.sin_addr);
02110 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
02111 i,
02112 c1->stream ? c1->stream->filename : "",
02113 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
02114 p,
02115 c1->protocol,
02116 http_state[c1->state]);
02117 fmt_bytecount(pb, bitrate);
02118 avio_printf(pb, "<td align=right>");
02119 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
02120 avio_printf(pb, "<td align=right>");
02121 fmt_bytecount(pb, c1->data_count);
02122 avio_printf(pb, "\n");
02123 c1 = c1->next;
02124 }
02125 avio_printf(pb, "</table>\n");
02126
02127
02128 ti = time(NULL);
02129 p = ctime(&ti);
02130 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
02131 avio_printf(pb, "</body>\n</html>\n");
02132
02133 len = avio_close_dyn_buf(pb, &c->pb_buffer);
02134 c->buffer_ptr = c->pb_buffer;
02135 c->buffer_end = c->pb_buffer + len;
02136 }
02137
02138 static int open_input_stream(HTTPContext *c, const char *info)
02139 {
02140 char buf[128];
02141 char input_filename[1024];
02142 AVFormatContext *s = NULL;
02143 int buf_size, i, ret;
02144 int64_t stream_pos;
02145
02146
02147 if (c->stream->feed) {
02148 strcpy(input_filename, c->stream->feed->feed_filename);
02149 buf_size = FFM_PACKET_SIZE;
02150
02151 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
02152 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
02153 return ret;
02154 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
02155 int prebuffer = strtol(buf, 0, 10);
02156 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
02157 } else
02158 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
02159 } else {
02160 strcpy(input_filename, c->stream->feed_filename);
02161 buf_size = 0;
02162
02163 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
02164 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
02165 return ret;
02166 } else
02167 stream_pos = 0;
02168 }
02169 if (input_filename[0] == '\0')
02170 return -1;
02171
02172
02173 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
02174 http_log("could not open %s: %d\n", input_filename, ret);
02175 return -1;
02176 }
02177
02178
02179 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
02180
02181 s->flags |= AVFMT_FLAG_GENPTS;
02182 c->fmt_in = s;
02183 if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
02184 http_log("Could not find stream info '%s'\n", input_filename);
02185 avformat_close_input(&s);
02186 return -1;
02187 }
02188
02189
02190
02191 c->pts_stream_index = 0;
02192 for(i=0;i<c->stream->nb_streams;i++) {
02193 if (c->pts_stream_index == 0 &&
02194 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
02195 c->pts_stream_index = i;
02196 }
02197 }
02198
02199 if (c->fmt_in->iformat->read_seek)
02200 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
02201
02202 c->start_time = cur_time;
02203 c->first_pts = AV_NOPTS_VALUE;
02204 return 0;
02205 }
02206
02207
02208 static int64_t get_server_clock(HTTPContext *c)
02209 {
02210
02211 return (cur_time - c->start_time) * 1000;
02212 }
02213
02214
02215
02216 static int64_t get_packet_send_clock(HTTPContext *c)
02217 {
02218 int bytes_left, bytes_sent, frame_bytes;
02219
02220 frame_bytes = c->cur_frame_bytes;
02221 if (frame_bytes <= 0)
02222 return c->cur_pts;
02223 else {
02224 bytes_left = c->buffer_end - c->buffer_ptr;
02225 bytes_sent = frame_bytes - bytes_left;
02226 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
02227 }
02228 }
02229
02230
02231 static int http_prepare_data(HTTPContext *c)
02232 {
02233 int i, len, ret;
02234 AVFormatContext *ctx;
02235
02236 av_freep(&c->pb_buffer);
02237 switch(c->state) {
02238 case HTTPSTATE_SEND_DATA_HEADER:
02239 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
02240 av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
02241 av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
02242 av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
02243 av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
02244
02245 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
02246
02247 for(i=0;i<c->stream->nb_streams;i++) {
02248 AVStream *src;
02249 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
02250
02251 if (!c->stream->feed ||
02252 c->stream->feed == c->stream)
02253 src = c->stream->streams[i];
02254 else
02255 src = c->stream->feed->streams[c->stream->feed_streams[i]];
02256
02257 *(c->fmt_ctx.streams[i]) = *src;
02258 c->fmt_ctx.streams[i]->priv_data = 0;
02259 c->fmt_ctx.streams[i]->codec->frame_number = 0;
02260
02261 }
02262
02263 c->fmt_ctx.oformat = c->stream->fmt;
02264 c->fmt_ctx.nb_streams = c->stream->nb_streams;
02265
02266 c->got_key_frame = 0;
02267
02268
02269 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
02270
02271 return -1;
02272 }
02273 c->fmt_ctx.pb->seekable = 0;
02274
02275
02276
02277
02278
02279
02280 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
02281
02282 if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
02283 http_log("Error writing output header\n");
02284 return -1;
02285 }
02286 av_dict_free(&c->fmt_ctx.metadata);
02287
02288 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
02289 c->buffer_ptr = c->pb_buffer;
02290 c->buffer_end = c->pb_buffer + len;
02291
02292 c->state = HTTPSTATE_SEND_DATA;
02293 c->last_packet_sent = 0;
02294 break;
02295 case HTTPSTATE_SEND_DATA:
02296
02297
02298 if (c->stream->feed)
02299 ffm_set_write_index(c->fmt_in,
02300 c->stream->feed->feed_write_index,
02301 c->stream->feed->feed_size);
02302
02303 if (c->stream->max_time &&
02304 c->stream->max_time + c->start_time - cur_time < 0)
02305
02306 c->state = HTTPSTATE_SEND_DATA_TRAILER;
02307 else {
02308 AVPacket pkt;
02309 redo:
02310 ret = av_read_frame(c->fmt_in, &pkt);
02311 if (ret < 0) {
02312 if (c->stream->feed) {
02313
02314
02315 c->state = HTTPSTATE_WAIT_FEED;
02316 return 1;
02317 } else if (ret == AVERROR(EAGAIN)) {
02318
02319 return 0;
02320 } else {
02321 if (c->stream->loop) {
02322 avformat_close_input(&c->fmt_in);
02323 if (open_input_stream(c, "") < 0)
02324 goto no_loop;
02325 goto redo;
02326 } else {
02327 no_loop:
02328
02329 c->state = HTTPSTATE_SEND_DATA_TRAILER;
02330 }
02331 }
02332 } else {
02333 int source_index = pkt.stream_index;
02334
02335 if (c->first_pts == AV_NOPTS_VALUE) {
02336 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
02337 c->start_time = cur_time;
02338 }
02339
02340 if (c->stream->feed) {
02341
02342 if (c->switch_pending) {
02343 c->switch_pending = 0;
02344 for(i=0;i<c->stream->nb_streams;i++) {
02345 if (c->switch_feed_streams[i] == pkt.stream_index)
02346 if (pkt.flags & AV_PKT_FLAG_KEY)
02347 c->switch_feed_streams[i] = -1;
02348 if (c->switch_feed_streams[i] >= 0)
02349 c->switch_pending = 1;
02350 }
02351 }
02352 for(i=0;i<c->stream->nb_streams;i++) {
02353 if (c->stream->feed_streams[i] == pkt.stream_index) {
02354 AVStream *st = c->fmt_in->streams[source_index];
02355 pkt.stream_index = i;
02356 if (pkt.flags & AV_PKT_FLAG_KEY &&
02357 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
02358 c->stream->nb_streams == 1))
02359 c->got_key_frame = 1;
02360 if (!c->stream->send_on_key || c->got_key_frame)
02361 goto send_it;
02362 }
02363 }
02364 } else {
02365 AVCodecContext *codec;
02366 AVStream *ist, *ost;
02367 send_it:
02368 ist = c->fmt_in->streams[source_index];
02369
02370
02371
02372 if (c->is_packetized) {
02373
02374 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
02375 c->cur_pts -= c->first_pts;
02376 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
02377
02378 c->packet_stream_index = pkt.stream_index;
02379 ctx = c->rtp_ctx[c->packet_stream_index];
02380 if(!ctx) {
02381 av_free_packet(&pkt);
02382 break;
02383 }
02384 codec = ctx->streams[0]->codec;
02385
02386 pkt.stream_index = 0;
02387 } else {
02388 ctx = &c->fmt_ctx;
02389
02390 codec = ctx->streams[pkt.stream_index]->codec;
02391 }
02392
02393 if (c->is_packetized) {
02394 int max_packet_size;
02395 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
02396 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
02397 else
02398 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
02399 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
02400 } else {
02401 ret = avio_open_dyn_buf(&ctx->pb);
02402 }
02403 if (ret < 0) {
02404
02405 return -1;
02406 }
02407 ost = ctx->streams[pkt.stream_index];
02408
02409 ctx->pb->seekable = 0;
02410 if (pkt.dts != AV_NOPTS_VALUE)
02411 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
02412 if (pkt.pts != AV_NOPTS_VALUE)
02413 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
02414 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
02415 if (av_write_frame(ctx, &pkt) < 0) {
02416 http_log("Error writing frame to output\n");
02417 c->state = HTTPSTATE_SEND_DATA_TRAILER;
02418 }
02419
02420 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
02421 c->cur_frame_bytes = len;
02422 c->buffer_ptr = c->pb_buffer;
02423 c->buffer_end = c->pb_buffer + len;
02424
02425 codec->frame_number++;
02426 if (len == 0) {
02427 av_free_packet(&pkt);
02428 goto redo;
02429 }
02430 }
02431 av_free_packet(&pkt);
02432 }
02433 }
02434 break;
02435 default:
02436 case HTTPSTATE_SEND_DATA_TRAILER:
02437
02438 if (c->last_packet_sent || c->is_packetized)
02439 return -1;
02440 ctx = &c->fmt_ctx;
02441
02442 if (avio_open_dyn_buf(&ctx->pb) < 0) {
02443
02444 return -1;
02445 }
02446 c->fmt_ctx.pb->seekable = 0;
02447 av_write_trailer(ctx);
02448 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
02449 c->buffer_ptr = c->pb_buffer;
02450 c->buffer_end = c->pb_buffer + len;
02451
02452 c->last_packet_sent = 1;
02453 break;
02454 }
02455 return 0;
02456 }
02457
02458
02459
02460
02461 static int http_send_data(HTTPContext *c)
02462 {
02463 int len, ret;
02464
02465 for(;;) {
02466 if (c->buffer_ptr >= c->buffer_end) {
02467 ret = http_prepare_data(c);
02468 if (ret < 0)
02469 return -1;
02470 else if (ret != 0)
02471
02472 break;
02473 } else {
02474 if (c->is_packetized) {
02475
02476 len = c->buffer_end - c->buffer_ptr;
02477 if (len < 4) {
02478
02479 fail1:
02480 c->buffer_ptr = c->buffer_end;
02481 return 0;
02482 }
02483 len = (c->buffer_ptr[0] << 24) |
02484 (c->buffer_ptr[1] << 16) |
02485 (c->buffer_ptr[2] << 8) |
02486 (c->buffer_ptr[3]);
02487 if (len > (c->buffer_end - c->buffer_ptr))
02488 goto fail1;
02489 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
02490
02491 return 0;
02492 }
02493
02494 c->data_count += len;
02495 update_datarate(&c->datarate, c->data_count);
02496 if (c->stream)
02497 c->stream->bytes_served += len;
02498
02499 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
02500
02501 AVIOContext *pb;
02502 int interleaved_index, size;
02503 uint8_t header[4];
02504 HTTPContext *rtsp_c;
02505
02506 rtsp_c = c->rtsp_c;
02507
02508 if (!rtsp_c)
02509 return -1;
02510
02511 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
02512 break;
02513 if (avio_open_dyn_buf(&pb) < 0)
02514 goto fail1;
02515 interleaved_index = c->packet_stream_index * 2;
02516
02517 if (c->buffer_ptr[1] == 200)
02518 interleaved_index++;
02519
02520 header[0] = '$';
02521 header[1] = interleaved_index;
02522 header[2] = len >> 8;
02523 header[3] = len;
02524 avio_write(pb, header, 4);
02525
02526 c->buffer_ptr += 4;
02527 avio_write(pb, c->buffer_ptr, len);
02528 size = avio_close_dyn_buf(pb, &c->packet_buffer);
02529
02530 rtsp_c->packet_buffer_ptr = c->packet_buffer;
02531 rtsp_c->packet_buffer_end = c->packet_buffer + size;
02532 c->buffer_ptr += len;
02533
02534
02535 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
02536 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
02537 if (len > 0)
02538 rtsp_c->packet_buffer_ptr += len;
02539 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
02540
02541
02542
02543 rtsp_c->state = RTSPSTATE_SEND_PACKET;
02544 break;
02545 } else
02546
02547 av_freep(&c->packet_buffer);
02548 } else {
02549
02550 c->buffer_ptr += 4;
02551 ffurl_write(c->rtp_handles[c->packet_stream_index],
02552 c->buffer_ptr, len);
02553 c->buffer_ptr += len;
02554
02555 }
02556 } else {
02557
02558 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
02559 if (len < 0) {
02560 if (ff_neterrno() != AVERROR(EAGAIN) &&
02561 ff_neterrno() != AVERROR(EINTR))
02562
02563 return -1;
02564 else
02565 return 0;
02566 } else
02567 c->buffer_ptr += len;
02568
02569 c->data_count += len;
02570 update_datarate(&c->datarate, c->data_count);
02571 if (c->stream)
02572 c->stream->bytes_served += len;
02573 break;
02574 }
02575 }
02576 }
02577 return 0;
02578 }
02579
02580 static int http_start_receive_data(HTTPContext *c)
02581 {
02582 int fd;
02583
02584 if (c->stream->feed_opened)
02585 return -1;
02586
02587
02588 if (c->stream->readonly)
02589 return -1;
02590
02591
02592 fd = open(c->stream->feed_filename, O_RDWR);
02593 if (fd < 0) {
02594 http_log("Error opening feeder file: %s\n", strerror(errno));
02595 return -1;
02596 }
02597 c->feed_fd = fd;
02598
02599 if (c->stream->truncate) {
02600
02601 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
02602 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
02603 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
02604 http_log("Error truncating feed file: %s\n", strerror(errno));
02605 return -1;
02606 }
02607 } else {
02608 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
02609 http_log("Error reading write index from feed file: %s\n", strerror(errno));
02610 return -1;
02611 }
02612 }
02613
02614 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
02615 c->stream->feed_size = lseek(fd, 0, SEEK_END);
02616 lseek(fd, 0, SEEK_SET);
02617
02618
02619 c->buffer_ptr = c->buffer;
02620 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
02621 c->stream->feed_opened = 1;
02622 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
02623 return 0;
02624 }
02625
02626 static int http_receive_data(HTTPContext *c)
02627 {
02628 HTTPContext *c1;
02629 int len, loop_run = 0;
02630
02631 while (c->chunked_encoding && !c->chunk_size &&
02632 c->buffer_end > c->buffer_ptr) {
02633
02634 len = recv(c->fd, c->buffer_ptr, 1, 0);
02635
02636 if (len < 0) {
02637 if (ff_neterrno() != AVERROR(EAGAIN) &&
02638 ff_neterrno() != AVERROR(EINTR))
02639
02640 goto fail;
02641 return 0;
02642 } else if (len == 0) {
02643
02644 goto fail;
02645 } else if (c->buffer_ptr - c->buffer >= 2 &&
02646 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
02647 c->chunk_size = strtol(c->buffer, 0, 16);
02648 if (c->chunk_size == 0)
02649 goto fail;
02650 c->buffer_ptr = c->buffer;
02651 break;
02652 } else if (++loop_run > 10) {
02653
02654 goto fail;
02655 } else {
02656 c->buffer_ptr++;
02657 }
02658 }
02659
02660 if (c->buffer_end > c->buffer_ptr) {
02661 len = recv(c->fd, c->buffer_ptr,
02662 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
02663 if (len < 0) {
02664 if (ff_neterrno() != AVERROR(EAGAIN) &&
02665 ff_neterrno() != AVERROR(EINTR))
02666
02667 goto fail;
02668 } else if (len == 0)
02669
02670 goto fail;
02671 else {
02672 c->chunk_size -= len;
02673 c->buffer_ptr += len;
02674 c->data_count += len;
02675 update_datarate(&c->datarate, c->data_count);
02676 }
02677 }
02678
02679 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
02680 if (c->buffer[0] != 'f' ||
02681 c->buffer[1] != 'm') {
02682 http_log("Feed stream has become desynchronized -- disconnecting\n");
02683 goto fail;
02684 }
02685 }
02686
02687 if (c->buffer_ptr >= c->buffer_end) {
02688 FFStream *feed = c->stream;
02689
02690
02691 if (c->data_count > FFM_PACKET_SIZE) {
02692
02693
02694
02695 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
02696 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
02697 http_log("Error writing to feed file: %s\n", strerror(errno));
02698 goto fail;
02699 }
02700
02701 feed->feed_write_index += FFM_PACKET_SIZE;
02702
02703 if (feed->feed_write_index > c->stream->feed_size)
02704 feed->feed_size = feed->feed_write_index;
02705
02706
02707 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
02708 feed->feed_write_index = FFM_PACKET_SIZE;
02709
02710
02711 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
02712 http_log("Error writing index to feed file: %s\n", strerror(errno));
02713 goto fail;
02714 }
02715
02716
02717 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
02718 if (c1->state == HTTPSTATE_WAIT_FEED &&
02719 c1->stream->feed == c->stream->feed)
02720 c1->state = HTTPSTATE_SEND_DATA;
02721 }
02722 } else {
02723
02724 AVFormatContext *s = avformat_alloc_context();
02725 AVIOContext *pb;
02726 AVInputFormat *fmt_in;
02727 int i;
02728
02729 if (!s)
02730 goto fail;
02731
02732
02733 fmt_in = av_find_input_format(feed->fmt->name);
02734 if (!fmt_in)
02735 goto fail;
02736
02737 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
02738 0, NULL, NULL, NULL, NULL);
02739 pb->seekable = 0;
02740
02741 s->pb = pb;
02742 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
02743 av_free(pb);
02744 goto fail;
02745 }
02746
02747
02748 if (s->nb_streams != feed->nb_streams) {
02749 avformat_close_input(&s);
02750 av_free(pb);
02751 http_log("Feed '%s' stream number does not match registered feed\n",
02752 c->stream->feed_filename);
02753 goto fail;
02754 }
02755
02756 for (i = 0; i < s->nb_streams; i++) {
02757 AVStream *fst = feed->streams[i];
02758 AVStream *st = s->streams[i];
02759 avcodec_copy_context(fst->codec, st->codec);
02760 }
02761
02762 avformat_close_input(&s);
02763 av_free(pb);
02764 }
02765 c->buffer_ptr = c->buffer;
02766 }
02767
02768 return 0;
02769 fail:
02770 c->stream->feed_opened = 0;
02771 close(c->feed_fd);
02772
02773 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
02774 if (c1->state == HTTPSTATE_WAIT_FEED &&
02775 c1->stream->feed == c->stream->feed)
02776 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
02777 }
02778 return -1;
02779 }
02780
02781
02782
02783
02784 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
02785 {
02786 const char *str;
02787 time_t ti;
02788 struct tm *tm;
02789 char buf2[32];
02790
02791 switch(error_number) {
02792 case RTSP_STATUS_OK:
02793 str = "OK";
02794 break;
02795 case RTSP_STATUS_METHOD:
02796 str = "Method Not Allowed";
02797 break;
02798 case RTSP_STATUS_BANDWIDTH:
02799 str = "Not Enough Bandwidth";
02800 break;
02801 case RTSP_STATUS_SESSION:
02802 str = "Session Not Found";
02803 break;
02804 case RTSP_STATUS_STATE:
02805 str = "Method Not Valid in This State";
02806 break;
02807 case RTSP_STATUS_AGGREGATE:
02808 str = "Aggregate operation not allowed";
02809 break;
02810 case RTSP_STATUS_ONLY_AGGREGATE:
02811 str = "Only aggregate operation allowed";
02812 break;
02813 case RTSP_STATUS_TRANSPORT:
02814 str = "Unsupported transport";
02815 break;
02816 case RTSP_STATUS_INTERNAL:
02817 str = "Internal Server Error";
02818 break;
02819 case RTSP_STATUS_SERVICE:
02820 str = "Service Unavailable";
02821 break;
02822 case RTSP_STATUS_VERSION:
02823 str = "RTSP Version not supported";
02824 break;
02825 default:
02826 str = "Unknown Error";
02827 break;
02828 }
02829
02830 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
02831 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
02832
02833
02834 ti = time(NULL);
02835 tm = gmtime(&ti);
02836 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
02837 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
02838 }
02839
02840 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
02841 {
02842 rtsp_reply_header(c, error_number);
02843 avio_printf(c->pb, "\r\n");
02844 }
02845
02846 static int rtsp_parse_request(HTTPContext *c)
02847 {
02848 const char *p, *p1, *p2;
02849 char cmd[32];
02850 char url[1024];
02851 char protocol[32];
02852 char line[1024];
02853 int len;
02854 RTSPMessageHeader header1 = { 0 }, *header = &header1;
02855
02856 c->buffer_ptr[0] = '\0';
02857 p = c->buffer;
02858
02859 get_word(cmd, sizeof(cmd), &p);
02860 get_word(url, sizeof(url), &p);
02861 get_word(protocol, sizeof(protocol), &p);
02862
02863 av_strlcpy(c->method, cmd, sizeof(c->method));
02864 av_strlcpy(c->url, url, sizeof(c->url));
02865 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
02866
02867 if (avio_open_dyn_buf(&c->pb) < 0) {
02868
02869 c->pb = NULL;
02870 return -1;
02871 }
02872
02873
02874 if (strcmp(protocol, "RTSP/1.0") != 0) {
02875 rtsp_reply_error(c, RTSP_STATUS_VERSION);
02876 goto the_end;
02877 }
02878
02879
02880
02881 while (*p != '\n' && *p != '\0')
02882 p++;
02883 if (*p == '\n')
02884 p++;
02885 while (*p != '\0') {
02886 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
02887 if (!p1)
02888 break;
02889 p2 = p1;
02890 if (p2 > p && p2[-1] == '\r')
02891 p2--;
02892
02893 if (p2 == p)
02894 break;
02895 len = p2 - p;
02896 if (len > sizeof(line) - 1)
02897 len = sizeof(line) - 1;
02898 memcpy(line, p, len);
02899 line[len] = '\0';
02900 ff_rtsp_parse_line(header, line, NULL, NULL);
02901 p = p1 + 1;
02902 }
02903
02904
02905 c->seq = header->seq;
02906
02907 if (!strcmp(cmd, "DESCRIBE"))
02908 rtsp_cmd_describe(c, url);
02909 else if (!strcmp(cmd, "OPTIONS"))
02910 rtsp_cmd_options(c, url);
02911 else if (!strcmp(cmd, "SETUP"))
02912 rtsp_cmd_setup(c, url, header);
02913 else if (!strcmp(cmd, "PLAY"))
02914 rtsp_cmd_play(c, url, header);
02915 else if (!strcmp(cmd, "PAUSE"))
02916 rtsp_cmd_pause(c, url, header);
02917 else if (!strcmp(cmd, "TEARDOWN"))
02918 rtsp_cmd_teardown(c, url, header);
02919 else
02920 rtsp_reply_error(c, RTSP_STATUS_METHOD);
02921
02922 the_end:
02923 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
02924 c->pb = NULL;
02925 if (len < 0) {
02926
02927 return -1;
02928 }
02929 c->buffer_ptr = c->pb_buffer;
02930 c->buffer_end = c->pb_buffer + len;
02931 c->state = RTSPSTATE_SEND_REPLY;
02932 return 0;
02933 }
02934
02935 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
02936 struct in_addr my_ip)
02937 {
02938 AVFormatContext *avc;
02939 AVStream *avs = NULL;
02940 int i;
02941
02942 avc = avformat_alloc_context();
02943 if (avc == NULL) {
02944 return -1;
02945 }
02946 av_dict_set(&avc->metadata, "title",
02947 stream->title[0] ? stream->title : "No Title", 0);
02948 avc->nb_streams = stream->nb_streams;
02949 if (stream->is_multicast) {
02950 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
02951 inet_ntoa(stream->multicast_ip),
02952 stream->multicast_port, stream->multicast_ttl);
02953 } else {
02954 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
02955 }
02956
02957 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
02958 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
02959 goto sdp_done;
02960 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
02961 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
02962 goto sdp_done;
02963
02964 for(i = 0; i < stream->nb_streams; i++) {
02965 avc->streams[i] = &avs[i];
02966 avc->streams[i]->codec = stream->streams[i]->codec;
02967 }
02968 *pbuffer = av_mallocz(2048);
02969 av_sdp_create(&avc, 1, *pbuffer, 2048);
02970
02971 sdp_done:
02972 av_free(avc->streams);
02973 av_dict_free(&avc->metadata);
02974 av_free(avc);
02975 av_free(avs);
02976
02977 return strlen(*pbuffer);
02978 }
02979
02980 static void rtsp_cmd_options(HTTPContext *c, const char *url)
02981 {
02982
02983 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
02984 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
02985 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
02986 avio_printf(c->pb, "\r\n");
02987 }
02988
02989 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
02990 {
02991 FFStream *stream;
02992 char path1[1024];
02993 const char *path;
02994 uint8_t *content;
02995 int content_length, len;
02996 struct sockaddr_in my_addr;
02997
02998
02999 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
03000 path = path1;
03001 if (*path == '/')
03002 path++;
03003
03004 for(stream = first_stream; stream != NULL; stream = stream->next) {
03005 if (!stream->is_feed &&
03006 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
03007 !strcmp(path, stream->filename)) {
03008 goto found;
03009 }
03010 }
03011
03012 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
03013 return;
03014
03015 found:
03016
03017
03018
03019 len = sizeof(my_addr);
03020 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
03021 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
03022 if (content_length < 0) {
03023 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
03024 return;
03025 }
03026 rtsp_reply_header(c, RTSP_STATUS_OK);
03027 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
03028 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
03029 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
03030 avio_printf(c->pb, "\r\n");
03031 avio_write(c->pb, content, content_length);
03032 av_free(content);
03033 }
03034
03035 static HTTPContext *find_rtp_session(const char *session_id)
03036 {
03037 HTTPContext *c;
03038
03039 if (session_id[0] == '\0')
03040 return NULL;
03041
03042 for(c = first_http_ctx; c != NULL; c = c->next) {
03043 if (!strcmp(c->session_id, session_id))
03044 return c;
03045 }
03046 return NULL;
03047 }
03048
03049 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
03050 {
03051 RTSPTransportField *th;
03052 int i;
03053
03054 for(i=0;i<h->nb_transports;i++) {
03055 th = &h->transports[i];
03056 if (th->lower_transport == lower_transport)
03057 return th;
03058 }
03059 return NULL;
03060 }
03061
03062 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
03063 RTSPMessageHeader *h)
03064 {
03065 FFStream *stream;
03066 int stream_index, rtp_port, rtcp_port;
03067 char buf[1024];
03068 char path1[1024];
03069 const char *path;
03070 HTTPContext *rtp_c;
03071 RTSPTransportField *th;
03072 struct sockaddr_in dest_addr;
03073 RTSPActionServerSetup setup;
03074
03075
03076 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
03077 path = path1;
03078 if (*path == '/')
03079 path++;
03080
03081
03082 for(stream = first_stream; stream != NULL; stream = stream->next) {
03083 if (!stream->is_feed &&
03084 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
03085
03086 if (!strcmp(path, stream->filename)) {
03087 if (stream->nb_streams != 1) {
03088 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
03089 return;
03090 }
03091 stream_index = 0;
03092 goto found;
03093 }
03094
03095 for(stream_index = 0; stream_index < stream->nb_streams;
03096 stream_index++) {
03097 snprintf(buf, sizeof(buf), "%s/streamid=%d",
03098 stream->filename, stream_index);
03099 if (!strcmp(path, buf))
03100 goto found;
03101 }
03102 }
03103 }
03104
03105 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
03106 return;
03107 found:
03108
03109
03110 if (h->session_id[0] == '\0') {
03111 unsigned random0 = av_lfg_get(&random_state);
03112 unsigned random1 = av_lfg_get(&random_state);
03113 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
03114 random0, random1);
03115 }
03116
03117
03118 rtp_c = find_rtp_session(h->session_id);
03119 if (!rtp_c) {
03120
03121 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
03122 if (!th) {
03123 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
03124 if (!th) {
03125 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
03126 return;
03127 }
03128 }
03129
03130 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
03131 th->lower_transport);
03132 if (!rtp_c) {
03133 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
03134 return;
03135 }
03136
03137
03138 if (open_input_stream(rtp_c, "") < 0) {
03139 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
03140 return;
03141 }
03142 }
03143
03144
03145
03146 if (rtp_c->stream != stream) {
03147 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
03148 return;
03149 }
03150
03151
03152 if (rtp_c->rtp_ctx[stream_index]) {
03153 rtsp_reply_error(c, RTSP_STATUS_STATE);
03154 return;
03155 }
03156
03157
03158 th = find_transport(h, rtp_c->rtp_protocol);
03159 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
03160 th->client_port_min <= 0)) {
03161 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
03162 return;
03163 }
03164
03165
03166 setup.transport_option[0] = '\0';
03167 dest_addr = rtp_c->from_addr;
03168 dest_addr.sin_port = htons(th->client_port_min);
03169
03170
03171 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
03172 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
03173 return;
03174 }
03175
03176
03177 rtsp_reply_header(c, RTSP_STATUS_OK);
03178
03179 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
03180
03181 switch(rtp_c->rtp_protocol) {
03182 case RTSP_LOWER_TRANSPORT_UDP:
03183 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
03184 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
03185 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
03186 "client_port=%d-%d;server_port=%d-%d",
03187 th->client_port_min, th->client_port_max,
03188 rtp_port, rtcp_port);
03189 break;
03190 case RTSP_LOWER_TRANSPORT_TCP:
03191 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
03192 stream_index * 2, stream_index * 2 + 1);
03193 break;
03194 default:
03195 break;
03196 }
03197 if (setup.transport_option[0] != '\0')
03198 avio_printf(c->pb, ";%s", setup.transport_option);
03199 avio_printf(c->pb, "\r\n");
03200
03201
03202 avio_printf(c->pb, "\r\n");
03203 }
03204
03205
03206
03207
03208 static HTTPContext *find_rtp_session_with_url(const char *url,
03209 const char *session_id)
03210 {
03211 HTTPContext *rtp_c;
03212 char path1[1024];
03213 const char *path;
03214 char buf[1024];
03215 int s, len;
03216
03217 rtp_c = find_rtp_session(session_id);
03218 if (!rtp_c)
03219 return NULL;
03220
03221
03222 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
03223 path = path1;
03224 if (*path == '/')
03225 path++;
03226 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
03227 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
03228 snprintf(buf, sizeof(buf), "%s/streamid=%d",
03229 rtp_c->stream->filename, s);
03230 if(!strncmp(path, buf, sizeof(buf))) {
03231
03232 return rtp_c;
03233 }
03234 }
03235 len = strlen(path);
03236 if (len > 0 && path[len - 1] == '/' &&
03237 !strncmp(path, rtp_c->stream->filename, len - 1))
03238 return rtp_c;
03239 return NULL;
03240 }
03241
03242 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
03243 {
03244 HTTPContext *rtp_c;
03245
03246 rtp_c = find_rtp_session_with_url(url, h->session_id);
03247 if (!rtp_c) {
03248 rtsp_reply_error(c, RTSP_STATUS_SESSION);
03249 return;
03250 }
03251
03252 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
03253 rtp_c->state != HTTPSTATE_WAIT_FEED &&
03254 rtp_c->state != HTTPSTATE_READY) {
03255 rtsp_reply_error(c, RTSP_STATUS_STATE);
03256 return;
03257 }
03258
03259 rtp_c->state = HTTPSTATE_SEND_DATA;
03260
03261
03262 rtsp_reply_header(c, RTSP_STATUS_OK);
03263
03264 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
03265 avio_printf(c->pb, "\r\n");
03266 }
03267
03268 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
03269 {
03270 HTTPContext *rtp_c;
03271
03272 rtp_c = find_rtp_session_with_url(url, h->session_id);
03273 if (!rtp_c) {
03274 rtsp_reply_error(c, RTSP_STATUS_SESSION);
03275 return;
03276 }
03277
03278 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
03279 rtp_c->state != HTTPSTATE_WAIT_FEED) {
03280 rtsp_reply_error(c, RTSP_STATUS_STATE);
03281 return;
03282 }
03283
03284 rtp_c->state = HTTPSTATE_READY;
03285 rtp_c->first_pts = AV_NOPTS_VALUE;
03286
03287 rtsp_reply_header(c, RTSP_STATUS_OK);
03288
03289 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
03290 avio_printf(c->pb, "\r\n");
03291 }
03292
03293 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
03294 {
03295 HTTPContext *rtp_c;
03296
03297 rtp_c = find_rtp_session_with_url(url, h->session_id);
03298 if (!rtp_c) {
03299 rtsp_reply_error(c, RTSP_STATUS_SESSION);
03300 return;
03301 }
03302
03303
03304 rtsp_reply_header(c, RTSP_STATUS_OK);
03305
03306 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
03307 avio_printf(c->pb, "\r\n");
03308
03309
03310 close_connection(rtp_c);
03311 }
03312
03313
03314
03315
03316
03317 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
03318 FFStream *stream, const char *session_id,
03319 enum RTSPLowerTransport rtp_protocol)
03320 {
03321 HTTPContext *c = NULL;
03322 const char *proto_str;
03323
03324
03325
03326 if (nb_connections >= nb_max_connections)
03327 goto fail;
03328
03329
03330 c = av_mallocz(sizeof(HTTPContext));
03331 if (!c)
03332 goto fail;
03333
03334 c->fd = -1;
03335 c->poll_entry = NULL;
03336 c->from_addr = *from_addr;
03337 c->buffer_size = IOBUFFER_INIT_SIZE;
03338 c->buffer = av_malloc(c->buffer_size);
03339 if (!c->buffer)
03340 goto fail;
03341 nb_connections++;
03342 c->stream = stream;
03343 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
03344 c->state = HTTPSTATE_READY;
03345 c->is_packetized = 1;
03346 c->rtp_protocol = rtp_protocol;
03347
03348
03349 switch(c->rtp_protocol) {
03350 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
03351 proto_str = "MCAST";
03352 break;
03353 case RTSP_LOWER_TRANSPORT_UDP:
03354 proto_str = "UDP";
03355 break;
03356 case RTSP_LOWER_TRANSPORT_TCP:
03357 proto_str = "TCP";
03358 break;
03359 default:
03360 proto_str = "???";
03361 break;
03362 }
03363 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
03364 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
03365
03366 current_bandwidth += stream->bandwidth;
03367
03368 c->next = first_http_ctx;
03369 first_http_ctx = c;
03370 return c;
03371
03372 fail:
03373 if (c) {
03374 av_free(c->buffer);
03375 av_free(c);
03376 }
03377 return NULL;
03378 }
03379
03380
03381
03382
03383 static int rtp_new_av_stream(HTTPContext *c,
03384 int stream_index, struct sockaddr_in *dest_addr,
03385 HTTPContext *rtsp_c)
03386 {
03387 AVFormatContext *ctx;
03388 AVStream *st;
03389 char *ipaddr;
03390 URLContext *h = NULL;
03391 uint8_t *dummy_buf;
03392 int max_packet_size;
03393
03394
03395 ctx = avformat_alloc_context();
03396 if (!ctx)
03397 return -1;
03398 ctx->oformat = av_guess_format("rtp", NULL, NULL);
03399
03400 st = av_mallocz(sizeof(AVStream));
03401 if (!st)
03402 goto fail;
03403 ctx->nb_streams = 1;
03404 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
03405 if (!ctx->streams)
03406 goto fail;
03407 ctx->streams[0] = st;
03408
03409 if (!c->stream->feed ||
03410 c->stream->feed == c->stream)
03411 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
03412 else
03413 memcpy(st,
03414 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
03415 sizeof(AVStream));
03416 st->priv_data = NULL;
03417
03418
03419 ipaddr = inet_ntoa(dest_addr->sin_addr);
03420
03421 switch(c->rtp_protocol) {
03422 case RTSP_LOWER_TRANSPORT_UDP:
03423 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
03424
03425
03426
03427 if (c->stream->is_multicast) {
03428 int ttl;
03429 ttl = c->stream->multicast_ttl;
03430 if (!ttl)
03431 ttl = 16;
03432 snprintf(ctx->filename, sizeof(ctx->filename),
03433 "rtp://%s:%d?multicast=1&ttl=%d",
03434 ipaddr, ntohs(dest_addr->sin_port), ttl);
03435 } else {
03436 snprintf(ctx->filename, sizeof(ctx->filename),
03437 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
03438 }
03439
03440 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
03441 goto fail;
03442 c->rtp_handles[stream_index] = h;
03443 max_packet_size = h->max_packet_size;
03444 break;
03445 case RTSP_LOWER_TRANSPORT_TCP:
03446
03447 c->rtsp_c = rtsp_c;
03448 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
03449 break;
03450 default:
03451 goto fail;
03452 }
03453
03454 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
03455 ipaddr, ntohs(dest_addr->sin_port),
03456 c->stream->filename, stream_index, c->protocol);
03457
03458
03459 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
03460
03461 goto fail;
03462 }
03463 if (avformat_write_header(ctx, NULL) < 0) {
03464 fail:
03465 if (h)
03466 ffurl_close(h);
03467 av_free(ctx);
03468 return -1;
03469 }
03470 avio_close_dyn_buf(ctx->pb, &dummy_buf);
03471 av_free(dummy_buf);
03472
03473 c->rtp_ctx[stream_index] = ctx;
03474 return 0;
03475 }
03476
03477
03478
03479
03480 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
03481 {
03482 AVStream *fst;
03483
03484 fst = av_mallocz(sizeof(AVStream));
03485 if (!fst)
03486 return NULL;
03487 if (copy) {
03488 fst->codec = avcodec_alloc_context3(NULL);
03489 memcpy(fst->codec, codec, sizeof(AVCodecContext));
03490 if (codec->extradata_size) {
03491 fst->codec->extradata = av_malloc(codec->extradata_size);
03492 memcpy(fst->codec->extradata, codec->extradata,
03493 codec->extradata_size);
03494 }
03495 } else {
03496
03497
03498
03499 fst->codec = codec;
03500 }
03501 fst->priv_data = av_mallocz(sizeof(FeedData));
03502 fst->index = stream->nb_streams;
03503 avpriv_set_pts_info(fst, 33, 1, 90000);
03504 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
03505 stream->streams[stream->nb_streams++] = fst;
03506 return fst;
03507 }
03508
03509
03510 static int add_av_stream(FFStream *feed, AVStream *st)
03511 {
03512 AVStream *fst;
03513 AVCodecContext *av, *av1;
03514 int i;
03515
03516 av = st->codec;
03517 for(i=0;i<feed->nb_streams;i++) {
03518 st = feed->streams[i];
03519 av1 = st->codec;
03520 if (av1->codec_id == av->codec_id &&
03521 av1->codec_type == av->codec_type &&
03522 av1->bit_rate == av->bit_rate) {
03523
03524 switch(av->codec_type) {
03525 case AVMEDIA_TYPE_AUDIO:
03526 if (av1->channels == av->channels &&
03527 av1->sample_rate == av->sample_rate)
03528 return i;
03529 break;
03530 case AVMEDIA_TYPE_VIDEO:
03531 if (av1->width == av->width &&
03532 av1->height == av->height &&
03533 av1->time_base.den == av->time_base.den &&
03534 av1->time_base.num == av->time_base.num &&
03535 av1->gop_size == av->gop_size)
03536 return i;
03537 break;
03538 default:
03539 abort();
03540 }
03541 }
03542 }
03543
03544 fst = add_av_stream1(feed, av, 0);
03545 if (!fst)
03546 return -1;
03547 return feed->nb_streams - 1;
03548 }
03549
03550 static void remove_stream(FFStream *stream)
03551 {
03552 FFStream **ps;
03553 ps = &first_stream;
03554 while (*ps != NULL) {
03555 if (*ps == stream)
03556 *ps = (*ps)->next;
03557 else
03558 ps = &(*ps)->next;
03559 }
03560 }
03561
03562
03563 static void extract_mpeg4_header(AVFormatContext *infile)
03564 {
03565 int mpeg4_count, i, size;
03566 AVPacket pkt;
03567 AVStream *st;
03568 const uint8_t *p;
03569
03570 mpeg4_count = 0;
03571 for(i=0;i<infile->nb_streams;i++) {
03572 st = infile->streams[i];
03573 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
03574 st->codec->extradata_size == 0) {
03575 mpeg4_count++;
03576 }
03577 }
03578 if (!mpeg4_count)
03579 return;
03580
03581 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
03582 while (mpeg4_count > 0) {
03583 if (av_read_packet(infile, &pkt) < 0)
03584 break;
03585 st = infile->streams[pkt.stream_index];
03586 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
03587 st->codec->extradata_size == 0) {
03588 av_freep(&st->codec->extradata);
03589
03590
03591 p = pkt.data;
03592 while (p < pkt.data + pkt.size - 4) {
03593
03594 if (p[0] == 0x00 && p[1] == 0x00 &&
03595 p[2] == 0x01 && p[3] == 0xb6) {
03596 size = p - pkt.data;
03597
03598 st->codec->extradata = av_malloc(size);
03599 st->codec->extradata_size = size;
03600 memcpy(st->codec->extradata, pkt.data, size);
03601 break;
03602 }
03603 p++;
03604 }
03605 mpeg4_count--;
03606 }
03607 av_free_packet(&pkt);
03608 }
03609 }
03610
03611
03612 static void build_file_streams(void)
03613 {
03614 FFStream *stream, *stream_next;
03615 int i, ret;
03616
03617
03618 for(stream = first_stream; stream != NULL; stream = stream_next) {
03619 AVFormatContext *infile = NULL;
03620 stream_next = stream->next;
03621 if (stream->stream_type == STREAM_TYPE_LIVE &&
03622 !stream->feed) {
03623
03624
03625
03626 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
03627
03628
03629 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
03630 }
03631
03632 http_log("Opening file '%s'\n", stream->feed_filename);
03633 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
03634 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
03635
03636 fail:
03637 remove_stream(stream);
03638 } else {
03639
03640
03641 if (avformat_find_stream_info(infile, NULL) < 0) {
03642 http_log("Could not find codec parameters from '%s'\n",
03643 stream->feed_filename);
03644 avformat_close_input(&infile);
03645 goto fail;
03646 }
03647 extract_mpeg4_header(infile);
03648
03649 for(i=0;i<infile->nb_streams;i++)
03650 add_av_stream1(stream, infile->streams[i]->codec, 1);
03651
03652 avformat_close_input(&infile);
03653 }
03654 }
03655 }
03656 }
03657
03658
03659 static void build_feed_streams(void)
03660 {
03661 FFStream *stream, *feed;
03662 int i;
03663
03664
03665 for(stream = first_stream; stream != NULL; stream = stream->next) {
03666 feed = stream->feed;
03667 if (feed) {
03668 if (stream->is_feed) {
03669 for(i=0;i<stream->nb_streams;i++)
03670 stream->feed_streams[i] = i;
03671 } else {
03672
03673 for(i=0;i<stream->nb_streams;i++)
03674 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
03675 }
03676 }
03677 }
03678
03679
03680 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
03681 int fd;
03682
03683 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
03684
03685 AVFormatContext *s = NULL;
03686 int matches = 0;
03687
03688 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
03689
03690 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
03691
03692 if (s->nb_streams == feed->nb_streams) {
03693 matches = 1;
03694 for(i=0;i<s->nb_streams;i++) {
03695 AVStream *sf, *ss;
03696 sf = feed->streams[i];
03697 ss = s->streams[i];
03698
03699 if (sf->index != ss->index ||
03700 sf->id != ss->id) {
03701 http_log("Index & Id do not match for stream %d (%s)\n",
03702 i, feed->feed_filename);
03703 matches = 0;
03704 } else {
03705 AVCodecContext *ccf, *ccs;
03706
03707 ccf = sf->codec;
03708 ccs = ss->codec;
03709 #define CHECK_CODEC(x) (ccf->x != ccs->x)
03710
03711 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
03712 http_log("Codecs do not match for stream %d\n", i);
03713 matches = 0;
03714 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
03715 http_log("Codec bitrates do not match for stream %d\n", i);
03716 matches = 0;
03717 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
03718 if (CHECK_CODEC(time_base.den) ||
03719 CHECK_CODEC(time_base.num) ||
03720 CHECK_CODEC(width) ||
03721 CHECK_CODEC(height)) {
03722 http_log("Codec width, height and framerate do not match for stream %d\n", i);
03723 matches = 0;
03724 }
03725 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
03726 if (CHECK_CODEC(sample_rate) ||
03727 CHECK_CODEC(channels) ||
03728 CHECK_CODEC(frame_size)) {
03729 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
03730 matches = 0;
03731 }
03732 } else {
03733 http_log("Unknown codec type\n");
03734 matches = 0;
03735 }
03736 }
03737 if (!matches)
03738 break;
03739 }
03740 } else
03741 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
03742 feed->feed_filename, s->nb_streams, feed->nb_streams);
03743
03744 avformat_close_input(&s);
03745 } else
03746 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
03747 feed->feed_filename);
03748
03749 if (!matches) {
03750 if (feed->readonly) {
03751 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
03752 feed->feed_filename);
03753 exit(1);
03754 }
03755 unlink(feed->feed_filename);
03756 }
03757 }
03758 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
03759 AVFormatContext s1 = {0}, *s = &s1;
03760
03761 if (feed->readonly) {
03762 http_log("Unable to create feed file '%s' as it is marked readonly\n",
03763 feed->feed_filename);
03764 exit(1);
03765 }
03766
03767
03768 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
03769 http_log("Could not open output feed file '%s'\n",
03770 feed->feed_filename);
03771 exit(1);
03772 }
03773 s->oformat = feed->fmt;
03774 s->nb_streams = feed->nb_streams;
03775 s->streams = feed->streams;
03776 if (avformat_write_header(s, NULL) < 0) {
03777 http_log("Container doesn't support the required parameters\n");
03778 exit(1);
03779 }
03780
03781 av_freep(&s->priv_data);
03782 avio_close(s->pb);
03783 }
03784
03785 fd = open(feed->feed_filename, O_RDONLY);
03786 if (fd < 0) {
03787 http_log("Could not open output feed file '%s'\n",
03788 feed->feed_filename);
03789 exit(1);
03790 }
03791
03792 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
03793 feed->feed_size = lseek(fd, 0, SEEK_END);
03794
03795 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
03796 feed->feed_max_size = feed->feed_size;
03797
03798 close(fd);
03799 }
03800 }
03801
03802
03803 static void compute_bandwidth(void)
03804 {
03805 unsigned bandwidth;
03806 int i;
03807 FFStream *stream;
03808
03809 for(stream = first_stream; stream != NULL; stream = stream->next) {
03810 bandwidth = 0;
03811 for(i=0;i<stream->nb_streams;i++) {
03812 AVStream *st = stream->streams[i];
03813 switch(st->codec->codec_type) {
03814 case AVMEDIA_TYPE_AUDIO:
03815 case AVMEDIA_TYPE_VIDEO:
03816 bandwidth += st->codec->bit_rate;
03817 break;
03818 default:
03819 break;
03820 }
03821 }
03822 stream->bandwidth = (bandwidth + 999) / 1000;
03823 }
03824 }
03825
03826
03827 static void add_codec(FFStream *stream, AVCodecContext *av)
03828 {
03829 AVStream *st;
03830
03831
03832 switch(av->codec_type) {
03833 case AVMEDIA_TYPE_AUDIO:
03834 if (av->bit_rate == 0)
03835 av->bit_rate = 64000;
03836 if (av->sample_rate == 0)
03837 av->sample_rate = 22050;
03838 if (av->channels == 0)
03839 av->channels = 1;
03840 break;
03841 case AVMEDIA_TYPE_VIDEO:
03842 if (av->bit_rate == 0)
03843 av->bit_rate = 64000;
03844 if (av->time_base.num == 0){
03845 av->time_base.den = 5;
03846 av->time_base.num = 1;
03847 }
03848 if (av->width == 0 || av->height == 0) {
03849 av->width = 160;
03850 av->height = 128;
03851 }
03852
03853 if (av->bit_rate_tolerance == 0)
03854 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
03855 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
03856 if (av->qmin == 0)
03857 av->qmin = 3;
03858 if (av->qmax == 0)
03859 av->qmax = 31;
03860 if (av->max_qdiff == 0)
03861 av->max_qdiff = 3;
03862 av->qcompress = 0.5;
03863 av->qblur = 0.5;
03864
03865 if (!av->nsse_weight)
03866 av->nsse_weight = 8;
03867
03868 av->frame_skip_cmp = FF_CMP_DCTMAX;
03869 if (!av->me_method)
03870 av->me_method = ME_EPZS;
03871 av->rc_buffer_aggressivity = 1.0;
03872
03873 if (!av->rc_eq)
03874 av->rc_eq = "tex^qComp";
03875 if (!av->i_quant_factor)
03876 av->i_quant_factor = -0.8;
03877 if (!av->b_quant_factor)
03878 av->b_quant_factor = 1.25;
03879 if (!av->b_quant_offset)
03880 av->b_quant_offset = 1.25;
03881 if (!av->rc_max_rate)
03882 av->rc_max_rate = av->bit_rate * 2;
03883
03884 if (av->rc_max_rate && !av->rc_buffer_size) {
03885 av->rc_buffer_size = av->rc_max_rate;
03886 }
03887
03888
03889 break;
03890 default:
03891 abort();
03892 }
03893
03894 st = av_mallocz(sizeof(AVStream));
03895 if (!st)
03896 return;
03897 st->codec = avcodec_alloc_context3(NULL);
03898 stream->streams[stream->nb_streams++] = st;
03899 memcpy(st->codec, av, sizeof(AVCodecContext));
03900 }
03901
03902 static enum AVCodecID opt_audio_codec(const char *arg)
03903 {
03904 AVCodec *p= avcodec_find_encoder_by_name(arg);
03905
03906 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
03907 return AV_CODEC_ID_NONE;
03908
03909 return p->id;
03910 }
03911
03912 static enum AVCodecID opt_video_codec(const char *arg)
03913 {
03914 AVCodec *p= avcodec_find_encoder_by_name(arg);
03915
03916 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
03917 return AV_CODEC_ID_NONE;
03918
03919 return p->id;
03920 }
03921
03922
03923
03924 #if HAVE_DLOPEN
03925 static void load_module(const char *filename)
03926 {
03927 void *dll;
03928 void (*init_func)(void);
03929 dll = dlopen(filename, RTLD_NOW);
03930 if (!dll) {
03931 fprintf(stderr, "Could not load module '%s' - %s\n",
03932 filename, dlerror());
03933 return;
03934 }
03935
03936 init_func = dlsym(dll, "ffserver_module_init");
03937 if (!init_func) {
03938 fprintf(stderr,
03939 "%s: init function 'ffserver_module_init()' not found\n",
03940 filename);
03941 dlclose(dll);
03942 }
03943
03944 init_func();
03945 }
03946 #endif
03947
03948 static int ffserver_opt_default(const char *opt, const char *arg,
03949 AVCodecContext *avctx, int type)
03950 {
03951 int ret = 0;
03952 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
03953 if(o)
03954 ret = av_opt_set(avctx, opt, arg, 0);
03955 return ret;
03956 }
03957
03958 static int ffserver_opt_preset(const char *arg,
03959 AVCodecContext *avctx, int type,
03960 enum AVCodecID *audio_id, enum AVCodecID *video_id)
03961 {
03962 FILE *f=NULL;
03963 char filename[1000], tmp[1000], tmp2[1000], line[1000];
03964 int ret = 0;
03965 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
03966
03967 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
03968 codec ? codec->name : NULL))) {
03969 fprintf(stderr, "File for preset '%s' not found\n", arg);
03970 return 1;
03971 }
03972
03973 while(!feof(f)){
03974 int e= fscanf(f, "%999[^\n]\n", line) - 1;
03975 if(line[0] == '#' && !e)
03976 continue;
03977 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
03978 if(e){
03979 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
03980 ret = 1;
03981 break;
03982 }
03983 if(!strcmp(tmp, "acodec")){
03984 *audio_id = opt_audio_codec(tmp2);
03985 }else if(!strcmp(tmp, "vcodec")){
03986 *video_id = opt_video_codec(tmp2);
03987 }else if(!strcmp(tmp, "scodec")){
03988
03989 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
03990 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
03991 ret = 1;
03992 break;
03993 }
03994 }
03995
03996 fclose(f);
03997
03998 return ret;
03999 }
04000
04001 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
04002 const char *mime_type)
04003 {
04004 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
04005
04006 if (fmt) {
04007 AVOutputFormat *stream_fmt;
04008 char stream_format_name[64];
04009
04010 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
04011 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
04012
04013 if (stream_fmt)
04014 fmt = stream_fmt;
04015 }
04016
04017 return fmt;
04018 }
04019
04020 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
04021 {
04022 va_list vl;
04023 va_start(vl, fmt);
04024 fprintf(stderr, "%s:%d: ", filename, line_num);
04025 vfprintf(stderr, fmt, vl);
04026 va_end(vl);
04027
04028 (*errors)++;
04029 }
04030
04031 static int parse_ffconfig(const char *filename)
04032 {
04033 FILE *f;
04034 char line[1024];
04035 char cmd[64];
04036 char arg[1024];
04037 const char *p;
04038 int val, errors, line_num;
04039 FFStream **last_stream, *stream, *redirect;
04040 FFStream **last_feed, *feed, *s;
04041 AVCodecContext audio_enc, video_enc;
04042 enum AVCodecID audio_id, video_id;
04043
04044 f = fopen(filename, "r");
04045 if (!f) {
04046 perror(filename);
04047 return -1;
04048 }
04049
04050 errors = 0;
04051 line_num = 0;
04052 first_stream = NULL;
04053 last_stream = &first_stream;
04054 first_feed = NULL;
04055 last_feed = &first_feed;
04056 stream = NULL;
04057 feed = NULL;
04058 redirect = NULL;
04059 audio_id = AV_CODEC_ID_NONE;
04060 video_id = AV_CODEC_ID_NONE;
04061
04062 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
04063 for(;;) {
04064 if (fgets(line, sizeof(line), f) == NULL)
04065 break;
04066 line_num++;
04067 p = line;
04068 while (isspace(*p))
04069 p++;
04070 if (*p == '\0' || *p == '#')
04071 continue;
04072
04073 get_arg(cmd, sizeof(cmd), &p);
04074
04075 if (!av_strcasecmp(cmd, "Port")) {
04076 get_arg(arg, sizeof(arg), &p);
04077 val = atoi(arg);
04078 if (val < 1 || val > 65536) {
04079 ERROR("Invalid_port: %s\n", arg);
04080 }
04081 my_http_addr.sin_port = htons(val);
04082 } else if (!av_strcasecmp(cmd, "BindAddress")) {
04083 get_arg(arg, sizeof(arg), &p);
04084 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
04085 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
04086 }
04087 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
04088 ffserver_daemon = 0;
04089 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
04090 get_arg(arg, sizeof(arg), &p);
04091 val = atoi(arg);
04092 if (val < 1 || val > 65536) {
04093 ERROR("%s:%d: Invalid port: %s\n", arg);
04094 }
04095 my_rtsp_addr.sin_port = htons(atoi(arg));
04096 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
04097 get_arg(arg, sizeof(arg), &p);
04098 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
04099 ERROR("Invalid host/IP address: %s\n", arg);
04100 }
04101 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
04102 get_arg(arg, sizeof(arg), &p);
04103 val = atoi(arg);
04104 if (val < 1 || val > 65536) {
04105 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
04106 }
04107 nb_max_http_connections = val;
04108 } else if (!av_strcasecmp(cmd, "MaxClients")) {
04109 get_arg(arg, sizeof(arg), &p);
04110 val = atoi(arg);
04111 if (val < 1 || val > nb_max_http_connections) {
04112 ERROR("Invalid MaxClients: %s\n", arg);
04113 } else {
04114 nb_max_connections = val;
04115 }
04116 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
04117 int64_t llval;
04118 get_arg(arg, sizeof(arg), &p);
04119 llval = atoll(arg);
04120 if (llval < 10 || llval > 10000000) {
04121 ERROR("Invalid MaxBandwidth: %s\n", arg);
04122 } else
04123 max_bandwidth = llval;
04124 } else if (!av_strcasecmp(cmd, "CustomLog")) {
04125 if (!ffserver_debug)
04126 get_arg(logfilename, sizeof(logfilename), &p);
04127 } else if (!av_strcasecmp(cmd, "<Feed")) {
04128
04129
04130 char *q;
04131 if (stream || feed) {
04132 ERROR("Already in a tag\n");
04133 } else {
04134 feed = av_mallocz(sizeof(FFStream));
04135 get_arg(feed->filename, sizeof(feed->filename), &p);
04136 q = strrchr(feed->filename, '>');
04137 if (*q)
04138 *q = '\0';
04139
04140 for (s = first_feed; s; s = s->next) {
04141 if (!strcmp(feed->filename, s->filename)) {
04142 ERROR("Feed '%s' already registered\n", s->filename);
04143 }
04144 }
04145
04146 feed->fmt = av_guess_format("ffm", NULL, NULL);
04147
04148 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
04149 "/tmp/%s.ffm", feed->filename);
04150 feed->feed_max_size = 5 * 1024 * 1024;
04151 feed->is_feed = 1;
04152 feed->feed = feed;
04153
04154
04155 *last_stream = feed;
04156 last_stream = &feed->next;
04157
04158 *last_feed = feed;
04159 last_feed = &feed->next_feed;
04160 }
04161 } else if (!av_strcasecmp(cmd, "Launch")) {
04162 if (feed) {
04163 int i;
04164
04165 feed->child_argv = av_mallocz(64 * sizeof(char *));
04166
04167 for (i = 0; i < 62; i++) {
04168 get_arg(arg, sizeof(arg), &p);
04169 if (!arg[0])
04170 break;
04171
04172 feed->child_argv[i] = av_strdup(arg);
04173 }
04174
04175 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
04176
04177 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
04178 "http://%s:%d/%s",
04179 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
04180 inet_ntoa(my_http_addr.sin_addr),
04181 ntohs(my_http_addr.sin_port), feed->filename);
04182 }
04183 } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
04184 if (feed) {
04185 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
04186 feed->readonly = 1;
04187 } else if (stream) {
04188 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
04189 }
04190 } else if (!av_strcasecmp(cmd, "File")) {
04191 if (feed) {
04192 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
04193 } else if (stream)
04194 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
04195 } else if (!av_strcasecmp(cmd, "Truncate")) {
04196 if (feed) {
04197 get_arg(arg, sizeof(arg), &p);
04198 feed->truncate = strtod(arg, NULL);
04199 }
04200 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
04201 if (feed) {
04202 char *p1;
04203 double fsize;
04204
04205 get_arg(arg, sizeof(arg), &p);
04206 p1 = arg;
04207 fsize = strtod(p1, &p1);
04208 switch(toupper(*p1)) {
04209 case 'K':
04210 fsize *= 1024;
04211 break;
04212 case 'M':
04213 fsize *= 1024 * 1024;
04214 break;
04215 case 'G':
04216 fsize *= 1024 * 1024 * 1024;
04217 break;
04218 }
04219 feed->feed_max_size = (int64_t)fsize;
04220 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
04221 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
04222 }
04223 }
04224 } else if (!av_strcasecmp(cmd, "</Feed>")) {
04225 if (!feed) {
04226 ERROR("No corresponding <Feed> for </Feed>\n");
04227 }
04228 feed = NULL;
04229 } else if (!av_strcasecmp(cmd, "<Stream")) {
04230
04231
04232 char *q;
04233 if (stream || feed) {
04234 ERROR("Already in a tag\n");
04235 } else {
04236 FFStream *s;
04237 stream = av_mallocz(sizeof(FFStream));
04238 get_arg(stream->filename, sizeof(stream->filename), &p);
04239 q = strrchr(stream->filename, '>');
04240 if (*q)
04241 *q = '\0';
04242
04243 for (s = first_stream; s; s = s->next) {
04244 if (!strcmp(stream->filename, s->filename)) {
04245 ERROR("Stream '%s' already registered\n", s->filename);
04246 }
04247 }
04248
04249 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
04250 avcodec_get_context_defaults3(&video_enc, NULL);
04251 avcodec_get_context_defaults3(&audio_enc, NULL);
04252
04253 audio_id = AV_CODEC_ID_NONE;
04254 video_id = AV_CODEC_ID_NONE;
04255 if (stream->fmt) {
04256 audio_id = stream->fmt->audio_codec;
04257 video_id = stream->fmt->video_codec;
04258 }
04259
04260 *last_stream = stream;
04261 last_stream = &stream->next;
04262 }
04263 } else if (!av_strcasecmp(cmd, "Feed")) {
04264 get_arg(arg, sizeof(arg), &p);
04265 if (stream) {
04266 FFStream *sfeed;
04267
04268 sfeed = first_feed;
04269 while (sfeed != NULL) {
04270 if (!strcmp(sfeed->filename, arg))
04271 break;
04272 sfeed = sfeed->next_feed;
04273 }
04274 if (!sfeed)
04275 ERROR("feed '%s' not defined\n", arg);
04276 else
04277 stream->feed = sfeed;
04278 }
04279 } else if (!av_strcasecmp(cmd, "Format")) {
04280 get_arg(arg, sizeof(arg), &p);
04281 if (stream) {
04282 if (!strcmp(arg, "status")) {
04283 stream->stream_type = STREAM_TYPE_STATUS;
04284 stream->fmt = NULL;
04285 } else {
04286 stream->stream_type = STREAM_TYPE_LIVE;
04287
04288 if (!strcmp(arg, "jpeg"))
04289 strcpy(arg, "mjpeg");
04290 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
04291 if (!stream->fmt) {
04292 ERROR("Unknown Format: %s\n", arg);
04293 }
04294 }
04295 if (stream->fmt) {
04296 audio_id = stream->fmt->audio_codec;
04297 video_id = stream->fmt->video_codec;
04298 }
04299 }
04300 } else if (!av_strcasecmp(cmd, "InputFormat")) {
04301 get_arg(arg, sizeof(arg), &p);
04302 if (stream) {
04303 stream->ifmt = av_find_input_format(arg);
04304 if (!stream->ifmt) {
04305 ERROR("Unknown input format: %s\n", arg);
04306 }
04307 }
04308 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
04309 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
04310 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
04311 } else {
04312 ERROR("FaviconURL only permitted for status streams\n");
04313 }
04314 } else if (!av_strcasecmp(cmd, "Author")) {
04315 if (stream)
04316 get_arg(stream->author, sizeof(stream->author), &p);
04317 } else if (!av_strcasecmp(cmd, "Comment")) {
04318 if (stream)
04319 get_arg(stream->comment, sizeof(stream->comment), &p);
04320 } else if (!av_strcasecmp(cmd, "Copyright")) {
04321 if (stream)
04322 get_arg(stream->copyright, sizeof(stream->copyright), &p);
04323 } else if (!av_strcasecmp(cmd, "Title")) {
04324 if (stream)
04325 get_arg(stream->title, sizeof(stream->title), &p);
04326 } else if (!av_strcasecmp(cmd, "Preroll")) {
04327 get_arg(arg, sizeof(arg), &p);
04328 if (stream)
04329 stream->prebuffer = atof(arg) * 1000;
04330 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
04331 if (stream)
04332 stream->send_on_key = 1;
04333 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
04334 get_arg(arg, sizeof(arg), &p);
04335 audio_id = opt_audio_codec(arg);
04336 if (audio_id == AV_CODEC_ID_NONE) {
04337 ERROR("Unknown AudioCodec: %s\n", arg);
04338 }
04339 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
04340 get_arg(arg, sizeof(arg), &p);
04341 video_id = opt_video_codec(arg);
04342 if (video_id == AV_CODEC_ID_NONE) {
04343 ERROR("Unknown VideoCodec: %s\n", arg);
04344 }
04345 } else if (!av_strcasecmp(cmd, "MaxTime")) {
04346 get_arg(arg, sizeof(arg), &p);
04347 if (stream)
04348 stream->max_time = atof(arg) * 1000;
04349 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
04350 get_arg(arg, sizeof(arg), &p);
04351 if (stream)
04352 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
04353 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
04354 get_arg(arg, sizeof(arg), &p);
04355 if (stream)
04356 audio_enc.channels = atoi(arg);
04357 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
04358 get_arg(arg, sizeof(arg), &p);
04359 if (stream)
04360 audio_enc.sample_rate = atoi(arg);
04361 } else if (!av_strcasecmp(cmd, "AudioQuality")) {
04362 get_arg(arg, sizeof(arg), &p);
04363 if (stream) {
04364
04365 }
04366 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
04367 if (stream) {
04368 int minrate, maxrate;
04369
04370 get_arg(arg, sizeof(arg), &p);
04371
04372 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
04373 video_enc.rc_min_rate = minrate * 1000;
04374 video_enc.rc_max_rate = maxrate * 1000;
04375 } else {
04376 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
04377 }
04378 }
04379 } else if (!av_strcasecmp(cmd, "Debug")) {
04380 if (stream) {
04381 get_arg(arg, sizeof(arg), &p);
04382 video_enc.debug = strtol(arg,0,0);
04383 }
04384 } else if (!av_strcasecmp(cmd, "Strict")) {
04385 if (stream) {
04386 get_arg(arg, sizeof(arg), &p);
04387 video_enc.strict_std_compliance = atoi(arg);
04388 }
04389 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
04390 if (stream) {
04391 get_arg(arg, sizeof(arg), &p);
04392 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
04393 }
04394 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
04395 if (stream) {
04396 get_arg(arg, sizeof(arg), &p);
04397 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
04398 }
04399 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
04400 get_arg(arg, sizeof(arg), &p);
04401 if (stream) {
04402 video_enc.bit_rate = atoi(arg) * 1000;
04403 }
04404 } else if (!av_strcasecmp(cmd, "VideoSize")) {
04405 get_arg(arg, sizeof(arg), &p);
04406 if (stream) {
04407 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
04408 if ((video_enc.width % 16) != 0 ||
04409 (video_enc.height % 16) != 0) {
04410 ERROR("Image size must be a multiple of 16\n");
04411 }
04412 }
04413 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
04414 get_arg(arg, sizeof(arg), &p);
04415 if (stream) {
04416 AVRational frame_rate;
04417 if (av_parse_video_rate(&frame_rate, arg) < 0) {
04418 ERROR("Incorrect frame rate: %s\n", arg);
04419 } else {
04420 video_enc.time_base.num = frame_rate.den;
04421 video_enc.time_base.den = frame_rate.num;
04422 }
04423 }
04424 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
04425 get_arg(arg, sizeof(arg), &p);
04426 if (stream)
04427 video_enc.gop_size = atoi(arg);
04428 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
04429 if (stream)
04430 video_enc.gop_size = 1;
04431 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
04432 if (stream)
04433 video_enc.mb_decision = FF_MB_DECISION_BITS;
04434 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
04435 if (stream) {
04436 video_enc.mb_decision = FF_MB_DECISION_BITS;
04437 video_enc.flags |= CODEC_FLAG_4MV;
04438 }
04439 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
04440 !av_strcasecmp(cmd, "AVOptionAudio")) {
04441 char arg2[1024];
04442 AVCodecContext *avctx;
04443 int type;
04444 get_arg(arg, sizeof(arg), &p);
04445 get_arg(arg2, sizeof(arg2), &p);
04446 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
04447 avctx = &video_enc;
04448 type = AV_OPT_FLAG_VIDEO_PARAM;
04449 } else {
04450 avctx = &audio_enc;
04451 type = AV_OPT_FLAG_AUDIO_PARAM;
04452 }
04453 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
04454 ERROR("AVOption error: %s %s\n", arg, arg2);
04455 }
04456 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
04457 !av_strcasecmp(cmd, "AVPresetAudio")) {
04458 AVCodecContext *avctx;
04459 int type;
04460 get_arg(arg, sizeof(arg), &p);
04461 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
04462 avctx = &video_enc;
04463 video_enc.codec_id = video_id;
04464 type = AV_OPT_FLAG_VIDEO_PARAM;
04465 } else {
04466 avctx = &audio_enc;
04467 audio_enc.codec_id = audio_id;
04468 type = AV_OPT_FLAG_AUDIO_PARAM;
04469 }
04470 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
04471 ERROR("AVPreset error: %s\n", arg);
04472 }
04473 } else if (!av_strcasecmp(cmd, "VideoTag")) {
04474 get_arg(arg, sizeof(arg), &p);
04475 if ((strlen(arg) == 4) && stream)
04476 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
04477 } else if (!av_strcasecmp(cmd, "BitExact")) {
04478 if (stream)
04479 video_enc.flags |= CODEC_FLAG_BITEXACT;
04480 } else if (!av_strcasecmp(cmd, "DctFastint")) {
04481 if (stream)
04482 video_enc.dct_algo = FF_DCT_FASTINT;
04483 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
04484 if (stream)
04485 video_enc.idct_algo = FF_IDCT_SIMPLE;
04486 } else if (!av_strcasecmp(cmd, "Qscale")) {
04487 get_arg(arg, sizeof(arg), &p);
04488 if (stream) {
04489 video_enc.flags |= CODEC_FLAG_QSCALE;
04490 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
04491 }
04492 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
04493 get_arg(arg, sizeof(arg), &p);
04494 if (stream) {
04495 video_enc.max_qdiff = atoi(arg);
04496 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
04497 ERROR("VideoQDiff out of range\n");
04498 }
04499 }
04500 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
04501 get_arg(arg, sizeof(arg), &p);
04502 if (stream) {
04503 video_enc.qmax = atoi(arg);
04504 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
04505 ERROR("VideoQMax out of range\n");
04506 }
04507 }
04508 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
04509 get_arg(arg, sizeof(arg), &p);
04510 if (stream) {
04511 video_enc.qmin = atoi(arg);
04512 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
04513 ERROR("VideoQMin out of range\n");
04514 }
04515 }
04516 } else if (!av_strcasecmp(cmd, "LumaElim")) {
04517 get_arg(arg, sizeof(arg), &p);
04518 if (stream)
04519 video_enc.luma_elim_threshold = atoi(arg);
04520 } else if (!av_strcasecmp(cmd, "ChromaElim")) {
04521 get_arg(arg, sizeof(arg), &p);
04522 if (stream)
04523 video_enc.chroma_elim_threshold = atoi(arg);
04524 } else if (!av_strcasecmp(cmd, "LumiMask")) {
04525 get_arg(arg, sizeof(arg), &p);
04526 if (stream)
04527 video_enc.lumi_masking = atof(arg);
04528 } else if (!av_strcasecmp(cmd, "DarkMask")) {
04529 get_arg(arg, sizeof(arg), &p);
04530 if (stream)
04531 video_enc.dark_masking = atof(arg);
04532 } else if (!av_strcasecmp(cmd, "NoVideo")) {
04533 video_id = AV_CODEC_ID_NONE;
04534 } else if (!av_strcasecmp(cmd, "NoAudio")) {
04535 audio_id = AV_CODEC_ID_NONE;
04536 } else if (!av_strcasecmp(cmd, "ACL")) {
04537 parse_acl_row(stream, feed, NULL, p, filename, line_num);
04538 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
04539 if (stream) {
04540 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
04541 }
04542 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
04543 get_arg(arg, sizeof(arg), &p);
04544 if (stream) {
04545 av_freep(&stream->rtsp_option);
04546 stream->rtsp_option = av_strdup(arg);
04547 }
04548 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
04549 get_arg(arg, sizeof(arg), &p);
04550 if (stream) {
04551 if (resolve_host(&stream->multicast_ip, arg) != 0) {
04552 ERROR("Invalid host/IP address: %s\n", arg);
04553 }
04554 stream->is_multicast = 1;
04555 stream->loop = 1;
04556 }
04557 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
04558 get_arg(arg, sizeof(arg), &p);
04559 if (stream)
04560 stream->multicast_port = atoi(arg);
04561 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
04562 get_arg(arg, sizeof(arg), &p);
04563 if (stream)
04564 stream->multicast_ttl = atoi(arg);
04565 } else if (!av_strcasecmp(cmd, "NoLoop")) {
04566 if (stream)
04567 stream->loop = 0;
04568 } else if (!av_strcasecmp(cmd, "</Stream>")) {
04569 if (!stream) {
04570 ERROR("No corresponding <Stream> for </Stream>\n");
04571 } else {
04572 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
04573 if (audio_id != AV_CODEC_ID_NONE) {
04574 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
04575 audio_enc.codec_id = audio_id;
04576 add_codec(stream, &audio_enc);
04577 }
04578 if (video_id != AV_CODEC_ID_NONE) {
04579 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
04580 video_enc.codec_id = video_id;
04581 add_codec(stream, &video_enc);
04582 }
04583 }
04584 stream = NULL;
04585 }
04586 } else if (!av_strcasecmp(cmd, "<Redirect")) {
04587
04588 char *q;
04589 if (stream || feed || redirect) {
04590 ERROR("Already in a tag\n");
04591 } else {
04592 redirect = av_mallocz(sizeof(FFStream));
04593 *last_stream = redirect;
04594 last_stream = &redirect->next;
04595
04596 get_arg(redirect->filename, sizeof(redirect->filename), &p);
04597 q = strrchr(redirect->filename, '>');
04598 if (*q)
04599 *q = '\0';
04600 redirect->stream_type = STREAM_TYPE_REDIRECT;
04601 }
04602 } else if (!av_strcasecmp(cmd, "URL")) {
04603 if (redirect)
04604 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
04605 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
04606 if (!redirect) {
04607 ERROR("No corresponding <Redirect> for </Redirect>\n");
04608 } else {
04609 if (!redirect->feed_filename[0]) {
04610 ERROR("No URL found for <Redirect>\n");
04611 }
04612 redirect = NULL;
04613 }
04614 } else if (!av_strcasecmp(cmd, "LoadModule")) {
04615 get_arg(arg, sizeof(arg), &p);
04616 #if HAVE_DLOPEN
04617 load_module(arg);
04618 #else
04619 ERROR("Module support not compiled into this version: '%s'\n", arg);
04620 #endif
04621 } else {
04622 ERROR("Incorrect keyword: '%s'\n", cmd);
04623 }
04624 }
04625 #undef ERROR
04626
04627 fclose(f);
04628 if (errors)
04629 return -1;
04630 else
04631 return 0;
04632 }
04633
04634 static void handle_child_exit(int sig)
04635 {
04636 pid_t pid;
04637 int status;
04638
04639 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
04640 FFStream *feed;
04641
04642 for (feed = first_feed; feed; feed = feed->next) {
04643 if (feed->pid == pid) {
04644 int uptime = time(0) - feed->pid_start;
04645
04646 feed->pid = 0;
04647 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
04648
04649 if (uptime < 30)
04650
04651 feed->child_argv = 0;
04652 }
04653 }
04654 }
04655
04656 need_to_start_children = 1;
04657 }
04658
04659 static void opt_debug(void)
04660 {
04661 ffserver_debug = 1;
04662 ffserver_daemon = 0;
04663 logfilename[0] = '-';
04664 }
04665
04666 void show_help_default(const char *opt, const char *arg)
04667 {
04668 printf("usage: ffserver [options]\n"
04669 "Hyper fast multi format Audio/Video streaming server\n");
04670 printf("\n");
04671 show_help_options(options, "Main options:", 0, 0, 0);
04672 }
04673
04674 static const OptionDef options[] = {
04675 #include "cmdutils_common_opts.h"
04676 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
04677 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
04678 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
04679 { NULL },
04680 };
04681
04682 int main(int argc, char **argv)
04683 {
04684 struct sigaction sigact = { { 0 } };
04685
04686 parse_loglevel(argc, argv, options);
04687 av_register_all();
04688 avformat_network_init();
04689
04690 show_banner(argc, argv, options);
04691
04692 my_program_name = argv[0];
04693 my_program_dir = getcwd(0, 0);
04694 ffserver_daemon = 1;
04695
04696 parse_options(NULL, argc, argv, options, NULL);
04697
04698 unsetenv("http_proxy");
04699
04700 av_lfg_init(&random_state, av_get_random_seed());
04701
04702 sigact.sa_handler = handle_child_exit;
04703 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
04704 sigaction(SIGCHLD, &sigact, 0);
04705
04706 if (parse_ffconfig(config_filename) < 0) {
04707 fprintf(stderr, "Incorrect config file - exiting.\n");
04708 exit(1);
04709 }
04710
04711
04712 if (logfilename[0] != '\0') {
04713 if (!strcmp(logfilename, "-"))
04714 logfile = stdout;
04715 else
04716 logfile = fopen(logfilename, "a");
04717 av_log_set_callback(http_av_log);
04718 }
04719
04720 build_file_streams();
04721
04722 build_feed_streams();
04723
04724 compute_bandwidth();
04725
04726
04727 if (ffserver_daemon) {
04728 int pid;
04729
04730 pid = fork();
04731 if (pid < 0) {
04732 perror("fork");
04733 exit(1);
04734 } else if (pid > 0) {
04735
04736 exit(0);
04737 } else {
04738
04739 setsid();
04740 close(0);
04741 open("/dev/null", O_RDWR);
04742 if (strcmp(logfilename, "-") != 0) {
04743 close(1);
04744 dup(0);
04745 }
04746 close(2);
04747 dup(0);
04748 }
04749 }
04750
04751
04752 signal(SIGPIPE, SIG_IGN);
04753
04754 if (ffserver_daemon)
04755 chdir("/");
04756
04757 if (http_server() < 0) {
04758 http_log("Could not start server\n");
04759 exit(1);
04760 }
04761
04762 return 0;
04763 }