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