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