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