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