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