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