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