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