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