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