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