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 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473 04473