2 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * multiple format streaming server based on the FFmpeg libraries
28 #define closesocket close
33 #include "libavformat/avformat.h"
34 // FIXME those are internal headers, ffserver _really_ shouldn't use them
35 #include "libavformat/ffm.h"
36 #include "libavformat/network.h"
37 #include "libavformat/os_support.h"
38 #include "libavformat/rtpdec.h"
39 #include "libavformat/rtpproto.h"
40 #include "libavformat/rtsp.h"
41 #include "libavformat/rtspcodes.h"
42 #include "libavformat/avio_internal.h"
43 #include "libavformat/internal.h"
44 #include "libavformat/url.h"
46 #include "libavutil/avassert.h"
47 #include "libavutil/avstring.h"
48 #include "libavutil/lfg.h"
49 #include "libavutil/dict.h"
50 #include "libavutil/intreadwrite.h"
51 #include "libavutil/mathematics.h"
52 #include "libavutil/random_seed.h"
53 #include "libavutil/parseutils.h"
54 #include "libavutil/opt.h"
55 #include "libavutil/time.h"
62 #include <sys/ioctl.h>
72 #include "ffserver_config.h"
74 const char program_name[] = "ffserver";
75 const int program_birth_year = 2000;
77 static const OptionDef options[];
80 HTTPSTATE_WAIT_REQUEST,
81 HTTPSTATE_SEND_HEADER,
82 HTTPSTATE_SEND_DATA_HEADER,
83 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
84 HTTPSTATE_SEND_DATA_TRAILER,
85 HTTPSTATE_RECEIVE_DATA,
86 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
89 RTSPSTATE_WAIT_REQUEST,
91 RTSPSTATE_SEND_PACKET,
94 static const char * const http_state[] = {
110 #define IOBUFFER_INIT_SIZE 8192
112 /* timeouts are in ms */
113 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
114 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
116 #define SYNC_TIMEOUT (10 * 1000)
118 typedef struct RTSPActionServerSetup {
120 char transport_option[512];
121 } RTSPActionServerSetup;
124 int64_t count1, count2;
125 int64_t time1, time2;
128 /* context associated with one connection */
129 typedef struct HTTPContext {
130 enum HTTPState state;
131 int fd; /* socket file descriptor */
132 struct sockaddr_in from_addr; /* origin */
133 struct pollfd *poll_entry; /* used when polling */
135 uint8_t *buffer_ptr, *buffer_end;
138 int chunked_encoding;
139 int chunk_size; /* 0 if it needs to be read */
140 struct HTTPContext *next;
141 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
145 /* input format handling */
146 AVFormatContext *fmt_in;
147 int64_t start_time; /* In milliseconds - this wraps fairly often */
148 int64_t first_pts; /* initial pts value */
149 int64_t cur_pts; /* current pts value from the stream in us */
150 int64_t cur_frame_duration; /* duration of the current frame in us */
151 int cur_frame_bytes; /* output frame size, needed to compute
152 the time at which we send each
154 int pts_stream_index; /* stream we choose as clock reference */
155 int64_t cur_clock; /* current clock reference value in us */
156 /* output format handling */
157 struct FFServerStream *stream;
158 /* -1 is invalid stream */
159 int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
160 int switch_feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
162 AVFormatContext fmt_ctx; /* instance of FFServerStream for one user */
163 int last_packet_sent; /* true if last data packet was sent */
165 DataRateData datarate;
172 int is_packetized; /* if true, the stream is packetized */
173 int packet_stream_index; /* current stream for output in state machine */
175 /* RTSP state specific */
176 uint8_t *pb_buffer; /* XXX: use that in all the code */
178 int seq; /* RTSP sequence number */
180 /* RTP state specific */
181 enum RTSPLowerTransport rtp_protocol;
182 char session_id[32]; /* session id */
183 AVFormatContext *rtp_ctx[FFSERVER_MAX_STREAMS];
185 /* RTP/UDP specific */
186 URLContext *rtp_handles[FFSERVER_MAX_STREAMS];
188 /* RTP/TCP specific */
189 struct HTTPContext *rtsp_c;
190 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
193 typedef struct FeedData {
194 long long data_count;
195 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
198 static HTTPContext *first_http_ctx;
200 static FFServerConfig config = {
201 .nb_max_http_connections = 2000,
202 .nb_max_connections = 5,
203 .max_bandwidth = 1000,
206 static void new_connection(int server_fd, int is_rtsp);
207 static void close_connection(HTTPContext *c);
210 static int handle_connection(HTTPContext *c);
211 static int http_parse_request(HTTPContext *c);
212 static int http_send_data(HTTPContext *c);
213 static void compute_status(HTTPContext *c);
214 static int open_input_stream(HTTPContext *c, const char *info);
215 static int http_start_receive_data(HTTPContext *c);
216 static int http_receive_data(HTTPContext *c);
219 static int rtsp_parse_request(HTTPContext *c);
220 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
221 static void rtsp_cmd_options(HTTPContext *c, const char *url);
222 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
223 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
224 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only);
227 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
228 struct in_addr my_ip);
231 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
232 FFServerStream *stream, const char *session_id,
233 enum RTSPLowerTransport rtp_protocol);
234 static int rtp_new_av_stream(HTTPContext *c,
235 int stream_index, struct sockaddr_in *dest_addr,
236 HTTPContext *rtsp_c);
238 static const char *my_program_name;
240 static int no_launch;
241 static int need_to_start_children;
243 /* maximum number of simultaneous HTTP connections */
244 static unsigned int nb_connections;
246 static uint64_t current_bandwidth;
248 static int64_t cur_time; // Making this global saves on passing it around everywhere
250 static AVLFG random_state;
252 static FILE *logfile = NULL;
254 static void htmlstrip(char *s) {
256 s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
262 static int64_t ffm_read_write_index(int fd)
266 if (lseek(fd, 8, SEEK_SET) < 0)
268 if (read(fd, buf, 8) != 8)
273 static int ffm_write_write_index(int fd, int64_t pos)
279 buf[i] = (pos >> (56 - i * 8)) & 0xff;
280 if (lseek(fd, 8, SEEK_SET) < 0)
282 if (write(fd, buf, 8) != 8)
287 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
290 FFMContext *ffm = s->priv_data;
291 ffm->write_index = pos;
292 ffm->file_size = file_size;
295 static char *ctime1(char *buf2, int buf_size)
302 av_strlcpy(buf2, p, buf_size);
303 p = buf2 + strlen(p) - 1;
309 static void http_vlog(const char *fmt, va_list vargs)
311 static int print_prefix = 1;
315 ctime1(buf, sizeof(buf));
316 fprintf(logfile, "%s ", buf);
318 print_prefix = strstr(fmt, "\n") != NULL;
319 vfprintf(logfile, fmt, vargs);
325 __attribute__ ((format (printf, 1, 2)))
327 static void http_log(const char *fmt, ...)
330 va_start(vargs, fmt);
331 http_vlog(fmt, vargs);
335 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
337 static int print_prefix = 1;
338 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
339 if (level > av_log_get_level())
341 if (print_prefix && avc)
342 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
343 print_prefix = strstr(fmt, "\n") != NULL;
344 http_vlog(fmt, vargs);
347 static void log_connection(HTTPContext *c)
352 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
353 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
354 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
357 static void update_datarate(DataRateData *drd, int64_t count)
359 if (!drd->time1 && !drd->count1) {
360 drd->time1 = drd->time2 = cur_time;
361 drd->count1 = drd->count2 = count;
362 } else if (cur_time - drd->time2 > 5000) {
363 drd->time1 = drd->time2;
364 drd->count1 = drd->count2;
365 drd->time2 = cur_time;
370 /* In bytes per second */
371 static int compute_datarate(DataRateData *drd, int64_t count)
373 if (cur_time == drd->time1)
376 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
380 static void start_children(FFServerStream *feed)
385 for (; feed; feed = feed->next) {
386 if (feed->child_argv && !feed->pid) {
387 feed->pid_start = time(0);
392 http_log("Unable to create children\n");
401 /* replace "ffserver" with "ffmpeg" in the path of current
402 * program. Ignore user provided path */
403 av_strlcpy(pathname, my_program_name, sizeof(pathname));
404 slash = strrchr(pathname, '/');
409 strcpy(slash, "ffmpeg");
411 http_log("Launch command line: ");
412 http_log("%s ", pathname);
413 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
414 http_log("%s ", feed->child_argv[i]);
417 for (i = 3; i < 256; i++)
421 if (!freopen("/dev/null", "r", stdin))
422 http_log("failed to redirect STDIN to /dev/null\n;");
423 if (!freopen("/dev/null", "w", stdout))
424 http_log("failed to redirect STDOUT to /dev/null\n;");
425 if (!freopen("/dev/null", "w", stderr))
426 http_log("failed to redirect STDERR to /dev/null\n;");
429 signal(SIGPIPE, SIG_DFL);
431 execvp(pathname, feed->child_argv);
439 /* open a listening socket */
440 static int socket_open_listen(struct sockaddr_in *my_addr)
444 server_fd = socket(AF_INET,SOCK_STREAM,0);
451 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)))
452 av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n");
454 my_addr->sin_family = AF_INET;
455 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
457 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
459 closesocket(server_fd);
463 if (listen (server_fd, 5) < 0) {
465 closesocket(server_fd);
469 if (ff_socket_nonblock(server_fd, 1) < 0)
470 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
475 /* start all multicast streams */
476 static void start_multicast(void)
478 FFServerStream *stream;
481 struct sockaddr_in dest_addr = {0};
482 int default_port, stream_index;
485 for(stream = config.first_stream; stream; stream = stream->next) {
486 if (stream->is_multicast) {
487 unsigned random0 = av_lfg_get(&random_state);
488 unsigned random1 = av_lfg_get(&random_state);
489 /* open the RTP connection */
490 snprintf(session_id, sizeof(session_id), "%08x%08x",
493 /* choose a port if none given */
494 if (stream->multicast_port == 0) {
495 stream->multicast_port = default_port;
499 dest_addr.sin_family = AF_INET;
500 dest_addr.sin_addr = stream->multicast_ip;
501 dest_addr.sin_port = htons(stream->multicast_port);
503 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
504 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
508 if (open_input_stream(rtp_c, "") < 0) {
509 http_log("Could not open input stream for stream '%s'\n",
514 /* open each RTP stream */
515 for(stream_index = 0; stream_index < stream->nb_streams;
517 dest_addr.sin_port = htons(stream->multicast_port +
519 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
520 http_log("Could not open output stream '%s/streamid=%d'\n",
521 stream->filename, stream_index);
526 rtp_c->state = HTTPSTATE_SEND_DATA;
531 /* main loop of the HTTP server */
532 static int http_server(void)
534 int server_fd = 0, rtsp_server_fd = 0;
536 struct pollfd *poll_table, *poll_entry;
537 HTTPContext *c, *c_next;
539 if(!(poll_table = av_mallocz_array(config.nb_max_http_connections + 2, sizeof(*poll_table)))) {
540 http_log("Impossible to allocate a poll table handling %d connections.\n", config.nb_max_http_connections);
544 if (config.http_addr.sin_port) {
545 server_fd = socket_open_listen(&config.http_addr);
552 if (config.rtsp_addr.sin_port) {
553 rtsp_server_fd = socket_open_listen(&config.rtsp_addr);
554 if (rtsp_server_fd < 0) {
556 closesocket(server_fd);
561 if (!rtsp_server_fd && !server_fd) {
562 http_log("HTTP and RTSP disabled.\n");
567 http_log("FFserver started.\n");
569 start_children(config.first_feed);
574 poll_entry = poll_table;
576 poll_entry->fd = server_fd;
577 poll_entry->events = POLLIN;
580 if (rtsp_server_fd) {
581 poll_entry->fd = rtsp_server_fd;
582 poll_entry->events = POLLIN;
586 /* wait for events on each HTTP handle */
593 case HTTPSTATE_SEND_HEADER:
594 case RTSPSTATE_SEND_REPLY:
595 case RTSPSTATE_SEND_PACKET:
596 c->poll_entry = poll_entry;
598 poll_entry->events = POLLOUT;
601 case HTTPSTATE_SEND_DATA_HEADER:
602 case HTTPSTATE_SEND_DATA:
603 case HTTPSTATE_SEND_DATA_TRAILER:
604 if (!c->is_packetized) {
605 /* for TCP, we output as much as we can
606 * (may need to put a limit) */
607 c->poll_entry = poll_entry;
609 poll_entry->events = POLLOUT;
612 /* when ffserver is doing the timing, we work by
613 looking at which packet needs to be sent every
615 /* one tick wait XXX: 10 ms assumed */
620 case HTTPSTATE_WAIT_REQUEST:
621 case HTTPSTATE_RECEIVE_DATA:
622 case HTTPSTATE_WAIT_FEED:
623 case RTSPSTATE_WAIT_REQUEST:
624 /* need to catch errors */
625 c->poll_entry = poll_entry;
627 poll_entry->events = POLLIN;/* Maybe this will work */
631 c->poll_entry = NULL;
637 /* wait for an event on one connection. We poll at least every
638 second to handle timeouts */
640 ret = poll(poll_table, poll_entry - poll_table, delay);
641 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
642 ff_neterrno() != AVERROR(EINTR)) {
648 cur_time = av_gettime() / 1000;
650 if (need_to_start_children) {
651 need_to_start_children = 0;
652 start_children(config.first_feed);
655 /* now handle the events */
656 for(c = first_http_ctx; c; c = c_next) {
658 if (handle_connection(c) < 0) {
660 /* close and free the connection */
665 poll_entry = poll_table;
667 /* new HTTP connection request ? */
668 if (poll_entry->revents & POLLIN)
669 new_connection(server_fd, 0);
672 if (rtsp_server_fd) {
673 /* new RTSP connection request ? */
674 if (poll_entry->revents & POLLIN)
675 new_connection(rtsp_server_fd, 1);
680 /* start waiting for a new HTTP/RTSP request */
681 static void start_wait_request(HTTPContext *c, int is_rtsp)
683 c->buffer_ptr = c->buffer;
684 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
687 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
688 c->state = RTSPSTATE_WAIT_REQUEST;
690 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
691 c->state = HTTPSTATE_WAIT_REQUEST;
695 static void http_send_too_busy_reply(int fd)
698 int len = snprintf(buffer, sizeof(buffer),
699 "HTTP/1.0 503 Server too busy\r\n"
700 "Content-type: text/html\r\n"
702 "<html><head><title>Too busy</title></head><body>\r\n"
703 "<p>The server is too busy to serve your request at this time.</p>\r\n"
704 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
705 "</body></html>\r\n",
706 nb_connections, config.nb_max_connections);
707 av_assert0(len < sizeof(buffer));
708 if (send(fd, buffer, len, 0) < len)
709 av_log(NULL, AV_LOG_WARNING, "Could not send too-busy reply, send() failed\n");
713 static void new_connection(int server_fd, int is_rtsp)
715 struct sockaddr_in from_addr;
718 HTTPContext *c = NULL;
720 len = sizeof(from_addr);
721 fd = accept(server_fd, (struct sockaddr *)&from_addr,
724 http_log("error during accept %s\n", strerror(errno));
727 if (ff_socket_nonblock(fd, 1) < 0)
728 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
730 if (nb_connections >= config.nb_max_connections) {
731 http_send_too_busy_reply(fd);
735 /* add a new connection */
736 c = av_mallocz(sizeof(HTTPContext));
741 c->poll_entry = NULL;
742 c->from_addr = from_addr;
743 c->buffer_size = IOBUFFER_INIT_SIZE;
744 c->buffer = av_malloc(c->buffer_size);
748 c->next = first_http_ctx;
752 start_wait_request(c, is_rtsp);
758 av_freep(&c->buffer);
764 static void close_connection(HTTPContext *c)
766 HTTPContext **cp, *c1;
768 AVFormatContext *ctx;
772 /* remove connection from list */
773 cp = &first_http_ctx;
782 /* remove references, if any (XXX: do it faster) */
783 for(c1 = first_http_ctx; c1; c1 = c1->next) {
788 /* remove connection associated resources */
792 /* close each frame parser */
793 for(i=0;i<c->fmt_in->nb_streams;i++) {
794 st = c->fmt_in->streams[i];
795 if (st->codec->codec)
796 avcodec_close(st->codec);
798 avformat_close_input(&c->fmt_in);
801 /* free RTP output streams if any */
804 nb_streams = c->stream->nb_streams;
806 for(i=0;i<nb_streams;i++) {
809 av_write_trailer(ctx);
810 av_dict_free(&ctx->metadata);
811 av_freep(&ctx->streams[0]);
814 h = c->rtp_handles[i];
821 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
824 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
825 av_write_trailer(ctx);
826 av_freep(&c->pb_buffer);
827 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
832 for(i=0; i<ctx->nb_streams; i++)
833 av_freep(&ctx->streams[i]);
834 av_freep(&ctx->streams);
835 av_freep(&ctx->priv_data);
837 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
838 current_bandwidth -= c->stream->bandwidth;
840 /* signal that there is no feed if we are the feeder socket */
841 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
842 c->stream->feed_opened = 0;
846 av_freep(&c->pb_buffer);
847 av_freep(&c->packet_buffer);
848 av_freep(&c->buffer);
853 static int handle_connection(HTTPContext *c)
858 case HTTPSTATE_WAIT_REQUEST:
859 case RTSPSTATE_WAIT_REQUEST:
861 if ((c->timeout - cur_time) < 0)
863 if (c->poll_entry->revents & (POLLERR | POLLHUP))
866 /* no need to read if no events */
867 if (!(c->poll_entry->revents & POLLIN))
871 len = recv(c->fd, c->buffer_ptr, 1, 0);
873 if (ff_neterrno() != AVERROR(EAGAIN) &&
874 ff_neterrno() != AVERROR(EINTR))
876 } else if (len == 0) {
879 /* search for end of request. */
881 c->buffer_ptr += len;
883 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
884 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
885 /* request found : parse it and reply */
886 if (c->state == HTTPSTATE_WAIT_REQUEST) {
887 ret = http_parse_request(c);
889 ret = rtsp_parse_request(c);
893 } else if (ptr >= c->buffer_end) {
894 /* request too long: cannot do anything */
896 } else goto read_loop;
900 case HTTPSTATE_SEND_HEADER:
901 if (c->poll_entry->revents & (POLLERR | POLLHUP))
904 /* no need to write if no events */
905 if (!(c->poll_entry->revents & POLLOUT))
907 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
909 if (ff_neterrno() != AVERROR(EAGAIN) &&
910 ff_neterrno() != AVERROR(EINTR)) {
911 goto close_connection;
914 c->buffer_ptr += len;
916 c->stream->bytes_served += len;
917 c->data_count += len;
918 if (c->buffer_ptr >= c->buffer_end) {
919 av_freep(&c->pb_buffer);
923 /* all the buffer was sent : synchronize to the incoming
925 c->state = HTTPSTATE_SEND_DATA_HEADER;
926 c->buffer_ptr = c->buffer_end = c->buffer;
931 case HTTPSTATE_SEND_DATA:
932 case HTTPSTATE_SEND_DATA_HEADER:
933 case HTTPSTATE_SEND_DATA_TRAILER:
934 /* for packetized output, we consider we can always write (the
935 input streams set the speed). It may be better to verify
936 that we do not rely too much on the kernel queues */
937 if (!c->is_packetized) {
938 if (c->poll_entry->revents & (POLLERR | POLLHUP))
941 /* no need to read if no events */
942 if (!(c->poll_entry->revents & POLLOUT))
945 if (http_send_data(c) < 0)
947 /* close connection if trailer sent */
948 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
951 case HTTPSTATE_RECEIVE_DATA:
952 /* no need to read if no events */
953 if (c->poll_entry->revents & (POLLERR | POLLHUP))
955 if (!(c->poll_entry->revents & POLLIN))
957 if (http_receive_data(c) < 0)
960 case HTTPSTATE_WAIT_FEED:
961 /* no need to read if no events */
962 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
965 /* nothing to do, we'll be waken up by incoming feed packets */
968 case RTSPSTATE_SEND_REPLY:
969 if (c->poll_entry->revents & (POLLERR | POLLHUP))
970 goto close_connection;
971 /* no need to write if no events */
972 if (!(c->poll_entry->revents & POLLOUT))
974 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
976 if (ff_neterrno() != AVERROR(EAGAIN) &&
977 ff_neterrno() != AVERROR(EINTR)) {
978 goto close_connection;
981 c->buffer_ptr += len;
982 c->data_count += len;
983 if (c->buffer_ptr >= c->buffer_end) {
984 /* all the buffer was sent : wait for a new request */
985 av_freep(&c->pb_buffer);
986 start_wait_request(c, 1);
990 case RTSPSTATE_SEND_PACKET:
991 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
992 av_freep(&c->packet_buffer);
995 /* no need to write if no events */
996 if (!(c->poll_entry->revents & POLLOUT))
998 len = send(c->fd, c->packet_buffer_ptr,
999 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1001 if (ff_neterrno() != AVERROR(EAGAIN) &&
1002 ff_neterrno() != AVERROR(EINTR)) {
1003 /* error : close connection */
1004 av_freep(&c->packet_buffer);
1008 c->packet_buffer_ptr += len;
1009 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1010 /* all the buffer was sent : wait for a new request */
1011 av_freep(&c->packet_buffer);
1012 c->state = RTSPSTATE_WAIT_REQUEST;
1016 case HTTPSTATE_READY:
1025 av_freep(&c->pb_buffer);
1029 static int extract_rates(char *rates, int ratelen, const char *request)
1033 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1034 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1035 const char *q = p + 7;
1037 while (*q && *q != '\n' && av_isspace(*q))
1040 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1046 memset(rates, 0xff, ratelen);
1049 while (*q && *q != '\n' && *q != ':')
1052 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1056 if (stream_no < ratelen && stream_no >= 0)
1057 rates[stream_no] = rate_no;
1059 while (*q && *q != '\n' && !av_isspace(*q))
1066 p = strchr(p, '\n');
1076 static int find_stream_in_feed(FFServerStream *feed, AVCodecContext *codec, int bit_rate)
1079 int best_bitrate = 100000000;
1082 for (i = 0; i < feed->nb_streams; i++) {
1083 AVCodecContext *feed_codec = feed->streams[i]->codec;
1085 if (feed_codec->codec_id != codec->codec_id ||
1086 feed_codec->sample_rate != codec->sample_rate ||
1087 feed_codec->width != codec->width ||
1088 feed_codec->height != codec->height)
1091 /* Potential stream */
1093 /* We want the fastest stream less than bit_rate, or the slowest
1094 * faster than bit_rate
1097 if (feed_codec->bit_rate <= bit_rate) {
1098 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1099 best_bitrate = feed_codec->bit_rate;
1103 if (feed_codec->bit_rate < best_bitrate) {
1104 best_bitrate = feed_codec->bit_rate;
1113 static int modify_current_stream(HTTPContext *c, char *rates)
1116 FFServerStream *req = c->stream;
1117 int action_required = 0;
1119 /* Not much we can do for a feed */
1123 for (i = 0; i < req->nb_streams; i++) {
1124 AVCodecContext *codec = req->streams[i]->codec;
1128 c->switch_feed_streams[i] = req->feed_streams[i];
1131 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1134 /* Wants off or slow */
1135 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1137 /* This doesn't work well when it turns off the only stream! */
1138 c->switch_feed_streams[i] = -2;
1139 c->feed_streams[i] = -2;
1144 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1145 action_required = 1;
1148 return action_required;
1151 static void get_word(char *buf, int buf_size, const char **pp)
1157 p += strspn(p, SPACE_CHARS);
1159 while (!av_isspace(*p) && *p != '\0') {
1160 if ((q - buf) < buf_size - 1)
1169 static FFServerIPAddressACL* parse_dynamic_acl(FFServerStream *stream, HTTPContext *c)
1174 FFServerIPAddressACL *acl = NULL;
1178 f = fopen(stream->dynamic_acl, "r");
1180 perror(stream->dynamic_acl);
1184 acl = av_mallocz(sizeof(FFServerIPAddressACL));
1188 if (fgets(line, sizeof(line), f) == NULL)
1192 while (av_isspace(*p))
1194 if (*p == '\0' || *p == '#')
1196 ffserver_get_arg(cmd, sizeof(cmd), &p);
1198 if (!av_strcasecmp(cmd, "ACL"))
1199 ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1206 static void free_acl_list(FFServerIPAddressACL *in_acl)
1208 FFServerIPAddressACL *pacl, *pacl2;
1218 static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c)
1220 enum FFServerIPAddressAction last_action = IP_DENY;
1221 FFServerIPAddressACL *acl;
1222 struct in_addr *src = &c->from_addr.sin_addr;
1223 unsigned long src_addr = src->s_addr;
1225 for (acl = in_acl; acl; acl = acl->next) {
1226 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1227 return (acl->action == IP_ALLOW) ? 1 : 0;
1228 last_action = acl->action;
1231 /* Nothing matched, so return not the last action */
1232 return (last_action == IP_DENY) ? 1 : 0;
1235 static int validate_acl(FFServerStream *stream, HTTPContext *c)
1238 FFServerIPAddressACL *acl;
1240 /* if stream->acl is null validate_acl_list will return 1 */
1241 ret = validate_acl_list(stream->acl, c);
1243 if (stream->dynamic_acl[0]) {
1244 acl = parse_dynamic_acl(stream, c);
1246 ret = validate_acl_list(acl, c);
1254 /* compute the real filename of a file by matching it without its
1255 extensions to all the stream's filenames */
1256 static void compute_real_filename(char *filename, int max_size)
1261 FFServerStream *stream;
1263 /* compute filename by matching without the file extensions */
1264 av_strlcpy(file1, filename, sizeof(file1));
1265 p = strrchr(file1, '.');
1268 for(stream = config.first_stream; stream; stream = stream->next) {
1269 av_strlcpy(file2, stream->filename, sizeof(file2));
1270 p = strrchr(file2, '.');
1273 if (!strcmp(file1, file2)) {
1274 av_strlcpy(filename, stream->filename, max_size);
1289 /* parse HTTP request and prepare header */
1290 static int http_parse_request(HTTPContext *c)
1294 enum RedirType redir_type;
1296 char info[1024], filename[1024];
1300 const char *mime_type;
1301 FFServerStream *stream;
1304 const char *useragent = 0;
1307 get_word(cmd, sizeof(cmd), &p);
1308 av_strlcpy(c->method, cmd, sizeof(c->method));
1310 if (!strcmp(cmd, "GET"))
1312 else if (!strcmp(cmd, "POST"))
1317 get_word(url, sizeof(url), &p);
1318 av_strlcpy(c->url, url, sizeof(c->url));
1320 get_word(protocol, sizeof(protocol), (const char **)&p);
1321 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1324 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1327 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1329 /* find the filename and the optional info string in the request */
1330 p1 = strchr(url, '?');
1332 av_strlcpy(info, p1, sizeof(info));
1337 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1339 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1340 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1342 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1346 p = strchr(p, '\n');
1353 redir_type = REDIR_NONE;
1354 if (av_match_ext(filename, "asx")) {
1355 redir_type = REDIR_ASX;
1356 filename[strlen(filename)-1] = 'f';
1357 } else if (av_match_ext(filename, "asf") &&
1358 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1359 /* if this isn't WMP or lookalike, return the redirector file */
1360 redir_type = REDIR_ASF;
1361 } else if (av_match_ext(filename, "rpm,ram")) {
1362 redir_type = REDIR_RAM;
1363 strcpy(filename + strlen(filename)-2, "m");
1364 } else if (av_match_ext(filename, "rtsp")) {
1365 redir_type = REDIR_RTSP;
1366 compute_real_filename(filename, sizeof(filename) - 1);
1367 } else if (av_match_ext(filename, "sdp")) {
1368 redir_type = REDIR_SDP;
1369 compute_real_filename(filename, sizeof(filename) - 1);
1372 // "redirect" / request to index.html
1373 if (!strlen(filename))
1374 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1376 stream = config.first_stream;
1378 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1380 stream = stream->next;
1383 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1384 http_log("File '%s' not found\n", url);
1389 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1390 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1392 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1393 c->http_error = 301;
1395 snprintf(q, c->buffer_size,
1396 "HTTP/1.0 301 Moved\r\n"
1398 "Content-type: text/html\r\n"
1400 "<html><head><title>Moved</title></head><body>\r\n"
1401 "You should be <a href=\"%s\">redirected</a>.\r\n"
1402 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1404 /* prepare output buffer */
1405 c->buffer_ptr = c->buffer;
1407 c->state = HTTPSTATE_SEND_HEADER;
1411 /* If this is WMP, get the rate information */
1412 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1413 if (modify_current_stream(c, ratebuf)) {
1414 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1415 if (c->switch_feed_streams[i] >= 0)
1416 c->switch_feed_streams[i] = -1;
1421 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1422 current_bandwidth += stream->bandwidth;
1424 /* If already streaming this feed, do not let start another feeder. */
1425 if (stream->feed_opened) {
1426 snprintf(msg, sizeof(msg), "This feed is already being received.");
1427 http_log("Feed '%s' already being received\n", stream->feed_filename);
1431 if (c->post == 0 && config.max_bandwidth < current_bandwidth) {
1432 c->http_error = 503;
1434 snprintf(q, c->buffer_size,
1435 "HTTP/1.0 503 Server too busy\r\n"
1436 "Content-type: text/html\r\n"
1438 "<html><head><title>Too busy</title></head><body>\r\n"
1439 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1440 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1441 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1442 "</body></html>\r\n", current_bandwidth, config.max_bandwidth);
1444 /* prepare output buffer */
1445 c->buffer_ptr = c->buffer;
1447 c->state = HTTPSTATE_SEND_HEADER;
1451 if (redir_type != REDIR_NONE) {
1452 const char *hostinfo = 0;
1454 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1455 if (av_strncasecmp(p, "Host:", 5) == 0) {
1459 p = strchr(p, '\n');
1470 while (av_isspace(*hostinfo))
1473 eoh = strchr(hostinfo, '\n');
1475 if (eoh[-1] == '\r')
1478 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1479 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1480 hostbuf[eoh - hostinfo] = 0;
1482 c->http_error = 200;
1484 switch(redir_type) {
1486 snprintf(q, c->buffer_size,
1487 "HTTP/1.0 200 ASX Follows\r\n"
1488 "Content-type: video/x-ms-asf\r\n"
1490 "<ASX Version=\"3\">\r\n"
1491 //"<!-- Autogenerated by ffserver -->\r\n"
1492 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1493 "</ASX>\r\n", hostbuf, filename, info);
1497 snprintf(q, c->buffer_size,
1498 "HTTP/1.0 200 RAM Follows\r\n"
1499 "Content-type: audio/x-pn-realaudio\r\n"
1501 "# Autogenerated by ffserver\r\n"
1502 "http://%s/%s%s\r\n", hostbuf, filename, info);
1506 snprintf(q, c->buffer_size,
1507 "HTTP/1.0 200 ASF Redirect follows\r\n"
1508 "Content-type: video/x-ms-asf\r\n"
1511 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1516 char hostname[256], *p;
1517 /* extract only hostname */
1518 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1519 p = strrchr(hostname, ':');
1522 snprintf(q, c->buffer_size,
1523 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1524 /* XXX: incorrect MIME type ? */
1525 "Content-type: application/x-rtsp\r\n"
1527 "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
1536 struct sockaddr_in my_addr;
1538 snprintf(q, c->buffer_size,
1539 "HTTP/1.0 200 OK\r\n"
1540 "Content-type: application/sdp\r\n"
1544 len = sizeof(my_addr);
1546 /* XXX: Should probably fail? */
1547 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1548 http_log("getsockname() failed\n");
1550 /* XXX: should use a dynamic buffer */
1551 sdp_data_size = prepare_sdp_description(stream,
1554 if (sdp_data_size > 0) {
1555 memcpy(q, sdp_data, sdp_data_size);
1567 /* prepare output buffer */
1568 c->buffer_ptr = c->buffer;
1570 c->state = HTTPSTATE_SEND_HEADER;
1576 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1580 stream->conns_served++;
1582 /* XXX: add there authenticate and IP match */
1585 /* if post, it means a feed is being sent */
1586 if (!stream->is_feed) {
1587 /* However it might be a status report from WMP! Let us log the
1588 * data as it might come handy one day. */
1589 const char *logline = 0;
1592 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1593 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1597 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1598 client_id = strtol(p + 18, 0, 10);
1599 p = strchr(p, '\n');
1607 char *eol = strchr(logline, '\n');
1612 if (eol[-1] == '\r')
1614 http_log("%.*s\n", (int) (eol - logline), logline);
1615 c->suppress_log = 1;
1620 http_log("\nGot request:\n%s\n", c->buffer);
1623 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1626 /* Now we have to find the client_id */
1627 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1628 if (wmpc->wmp_client_id == client_id)
1632 if (wmpc && modify_current_stream(wmpc, ratebuf))
1633 wmpc->switch_pending = 1;
1636 snprintf(msg, sizeof(msg), "POST command not handled");
1640 if (http_start_receive_data(c) < 0) {
1641 snprintf(msg, sizeof(msg), "could not open feed");
1645 c->state = HTTPSTATE_RECEIVE_DATA;
1650 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1651 http_log("\nGot request:\n%s\n", c->buffer);
1654 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1657 /* open input stream */
1658 if (open_input_stream(c, info) < 0) {
1659 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1663 /* prepare HTTP header */
1665 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1666 mime_type = c->stream->fmt->mime_type;
1668 mime_type = "application/x-octet-stream";
1669 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1671 /* for asf, we need extra headers */
1672 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1673 /* Need to allocate a client id */
1675 c->wmp_client_id = av_lfg_get(&random_state);
1677 av_strlcatf(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);
1679 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1680 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1681 q = c->buffer + strlen(c->buffer);
1683 /* prepare output buffer */
1685 c->buffer_ptr = c->buffer;
1687 c->state = HTTPSTATE_SEND_HEADER;
1690 c->http_error = 404;
1693 snprintf(q, c->buffer_size,
1694 "HTTP/1.0 404 Not Found\r\n"
1695 "Content-type: text/html\r\n"
1698 "<head><title>404 Not Found</title></head>\n"
1702 /* prepare output buffer */
1703 c->buffer_ptr = c->buffer;
1705 c->state = HTTPSTATE_SEND_HEADER;
1709 c->http_error = 200; /* horrible : we use this value to avoid
1710 going to the send data state */
1711 c->state = HTTPSTATE_SEND_HEADER;
1715 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1717 static const char suffix[] = " kMGTP";
1720 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1722 avio_printf(pb, "%"PRId64"%c", count, *s);
1725 static void compute_status(HTTPContext *c)
1728 FFServerStream *stream;
1734 if (avio_open_dyn_buf(&pb) < 0) {
1735 /* XXX: return an error ? */
1736 c->buffer_ptr = c->buffer;
1737 c->buffer_end = c->buffer;
1741 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1742 avio_printf(pb, "Content-type: text/html\r\n");
1743 avio_printf(pb, "Pragma: no-cache\r\n");
1744 avio_printf(pb, "\r\n");
1746 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1747 if (c->stream->feed_filename[0])
1748 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1749 avio_printf(pb, "</head>\n<body>");
1750 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1752 avio_printf(pb, "<h2>Available Streams</h2>\n");
1753 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1754 avio_printf(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");
1755 stream = config.first_stream;
1757 char sfilename[1024];
1760 if (stream->feed != stream) {
1761 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1762 eosf = sfilename + strlen(sfilename);
1763 if (eosf - sfilename >= 4) {
1764 if (strcmp(eosf - 4, ".asf") == 0)
1765 strcpy(eosf - 4, ".asx");
1766 else if (strcmp(eosf - 3, ".rm") == 0)
1767 strcpy(eosf - 3, ".ram");
1768 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1769 /* generate a sample RTSP director if
1770 unicast. Generate an SDP redirector if
1772 eosf = strrchr(sfilename, '.');
1774 eosf = sfilename + strlen(sfilename);
1775 if (stream->is_multicast)
1776 strcpy(eosf, ".sdp");
1778 strcpy(eosf, ".rtsp");
1782 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1783 sfilename, stream->filename);
1784 avio_printf(pb, "<td align=right> %d <td align=right> ",
1785 stream->conns_served);
1786 fmt_bytecount(pb, stream->bytes_served);
1787 switch(stream->stream_type) {
1788 case STREAM_TYPE_LIVE: {
1789 int audio_bit_rate = 0;
1790 int video_bit_rate = 0;
1791 const char *audio_codec_name = "";
1792 const char *video_codec_name = "";
1793 const char *audio_codec_name_extra = "";
1794 const char *video_codec_name_extra = "";
1796 for(i=0;i<stream->nb_streams;i++) {
1797 AVStream *st = stream->streams[i];
1798 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1799 switch(st->codec->codec_type) {
1800 case AVMEDIA_TYPE_AUDIO:
1801 audio_bit_rate += st->codec->bit_rate;
1803 if (*audio_codec_name)
1804 audio_codec_name_extra = "...";
1805 audio_codec_name = codec->name;
1808 case AVMEDIA_TYPE_VIDEO:
1809 video_bit_rate += st->codec->bit_rate;
1811 if (*video_codec_name)
1812 video_codec_name_extra = "...";
1813 video_codec_name = codec->name;
1816 case AVMEDIA_TYPE_DATA:
1817 video_bit_rate += st->codec->bit_rate;
1823 avio_printf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
1826 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1827 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1829 avio_printf(pb, "<td>%s", stream->feed->filename);
1831 avio_printf(pb, "<td>%s", stream->feed_filename);
1832 avio_printf(pb, "\n");
1836 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1840 stream = stream->next;
1842 avio_printf(pb, "</table>\n");
1844 stream = config.first_stream;
1846 if (stream->feed == stream) {
1847 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1849 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1856 /* This is somewhat linux specific I guess */
1857 snprintf(ps_cmd, sizeof(ps_cmd),
1858 "ps -o \"%%cpu,cputime\" --no-headers %d",
1861 pid_stat = popen(ps_cmd, "r");
1866 if (fscanf(pid_stat, "%9s %63s", cpuperc,
1868 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1876 avio_printf(pb, "<p>");
1878 avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
1880 for (i = 0; i < stream->nb_streams; i++) {
1881 AVStream *st = stream->streams[i];
1882 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1883 const char *type = "unknown";
1884 char parameters[64];
1888 switch(st->codec->codec_type) {
1889 case AVMEDIA_TYPE_AUDIO:
1891 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1893 case AVMEDIA_TYPE_VIDEO:
1895 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1896 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1901 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1902 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1904 avio_printf(pb, "</table>\n");
1907 stream = stream->next;
1910 /* connection status */
1911 avio_printf(pb, "<h2>Connection Status</h2>\n");
1913 avio_printf(pb, "Number of connections: %d / %d<br>\n",
1914 nb_connections, config.nb_max_connections);
1916 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1917 current_bandwidth, config.max_bandwidth);
1919 avio_printf(pb, "<table>\n");
1920 avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1921 c1 = first_http_ctx;
1929 for (j = 0; j < c1->stream->nb_streams; j++) {
1930 if (!c1->stream->feed)
1931 bitrate += c1->stream->streams[j]->codec->bit_rate;
1932 else if (c1->feed_streams[j] >= 0)
1933 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1938 p = inet_ntoa(c1->from_addr.sin_addr);
1939 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
1941 c1->stream ? c1->stream->filename : "",
1942 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1945 http_state[c1->state]);
1946 fmt_bytecount(pb, bitrate);
1947 avio_printf(pb, "<td align=right>");
1948 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1949 avio_printf(pb, "<td align=right>");
1950 fmt_bytecount(pb, c1->data_count);
1951 avio_printf(pb, "\n");
1954 avio_printf(pb, "</table>\n");
1959 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
1960 avio_printf(pb, "</body>\n</html>\n");
1962 len = avio_close_dyn_buf(pb, &c->pb_buffer);
1963 c->buffer_ptr = c->pb_buffer;
1964 c->buffer_end = c->pb_buffer + len;
1967 static int open_input_stream(HTTPContext *c, const char *info)
1970 char input_filename[1024];
1971 AVFormatContext *s = NULL;
1972 int buf_size, i, ret;
1975 /* find file name */
1976 if (c->stream->feed) {
1977 strcpy(input_filename, c->stream->feed->feed_filename);
1978 buf_size = FFM_PACKET_SIZE;
1979 /* compute position (absolute time) */
1980 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
1981 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
1982 http_log("Invalid date specification '%s' for stream\n", buf);
1985 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
1986 int prebuffer = strtol(buf, 0, 10);
1987 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1989 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1991 strcpy(input_filename, c->stream->feed_filename);
1993 /* compute position (relative time) */
1994 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
1995 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
1996 http_log("Invalid date specification '%s' for stream\n", buf);
2002 if (!input_filename[0]) {
2003 http_log("No filename was specified for stream\n");
2004 return AVERROR(EINVAL);
2008 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2009 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2013 /* set buffer size */
2014 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2016 s->flags |= AVFMT_FLAG_GENPTS;
2018 if (strcmp(s->iformat->name, "ffm") &&
2019 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2020 http_log("Could not find stream info for input '%s'\n", input_filename);
2021 avformat_close_input(&s);
2025 /* choose stream as clock source (we favor the video stream if
2026 * present) for packet sending */
2027 c->pts_stream_index = 0;
2028 for(i=0;i<c->stream->nb_streams;i++) {
2029 if (c->pts_stream_index == 0 &&
2030 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2031 c->pts_stream_index = i;
2035 if (c->fmt_in->iformat->read_seek)
2036 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2037 /* set the start time (needed for maxtime and RTP packet timing) */
2038 c->start_time = cur_time;
2039 c->first_pts = AV_NOPTS_VALUE;
2043 /* return the server clock (in us) */
2044 static int64_t get_server_clock(HTTPContext *c)
2046 /* compute current pts value from system time */
2047 return (cur_time - c->start_time) * 1000;
2050 /* return the estimated time at which the current packet must be sent
2052 static int64_t get_packet_send_clock(HTTPContext *c)
2054 int bytes_left, bytes_sent, frame_bytes;
2056 frame_bytes = c->cur_frame_bytes;
2057 if (frame_bytes <= 0)
2060 bytes_left = c->buffer_end - c->buffer_ptr;
2061 bytes_sent = frame_bytes - bytes_left;
2062 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2067 static int http_prepare_data(HTTPContext *c)
2070 AVFormatContext *ctx;
2072 av_freep(&c->pb_buffer);
2074 case HTTPSTATE_SEND_DATA_HEADER:
2075 ctx = avformat_alloc_context();
2078 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2079 c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams, sizeof(AVStream *));
2081 for(i=0;i<c->stream->nb_streams;i++) {
2083 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2084 /* if file or feed, then just take streams from FFServerStream struct */
2085 if (!c->stream->feed ||
2086 c->stream->feed == c->stream)
2087 src = c->stream->streams[i];
2089 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2091 *(c->fmt_ctx.streams[i]) = *src;
2092 c->fmt_ctx.streams[i]->priv_data = 0;
2093 /* XXX: should be done in AVStream, not in codec */
2094 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2096 /* set output format parameters */
2097 c->fmt_ctx.oformat = c->stream->fmt;
2098 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2100 c->got_key_frame = 0;
2102 /* prepare header and save header data in a stream */
2103 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2104 /* XXX: potential leak */
2107 c->fmt_ctx.pb->seekable = 0;
2110 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2111 * Default value from FFmpeg
2112 * Try to set it using configuration option
2114 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2116 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2117 http_log("Error writing output header for stream '%s': %s\n",
2118 c->stream->filename, av_err2str(ret));
2121 av_dict_free(&c->fmt_ctx.metadata);
2123 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2124 c->buffer_ptr = c->pb_buffer;
2125 c->buffer_end = c->pb_buffer + len;
2127 c->state = HTTPSTATE_SEND_DATA;
2128 c->last_packet_sent = 0;
2130 case HTTPSTATE_SEND_DATA:
2131 /* find a new packet */
2132 /* read a packet from the input stream */
2133 if (c->stream->feed)
2134 ffm_set_write_index(c->fmt_in,
2135 c->stream->feed->feed_write_index,
2136 c->stream->feed->feed_size);
2138 if (c->stream->max_time &&
2139 c->stream->max_time + c->start_time - cur_time < 0)
2140 /* We have timed out */
2141 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2145 ret = av_read_frame(c->fmt_in, &pkt);
2147 if (c->stream->feed) {
2148 /* if coming from feed, it means we reached the end of the
2149 ffm file, so must wait for more data */
2150 c->state = HTTPSTATE_WAIT_FEED;
2151 return 1; /* state changed */
2152 } else if (ret == AVERROR(EAGAIN)) {
2153 /* input not ready, come back later */
2156 if (c->stream->loop) {
2157 avformat_close_input(&c->fmt_in);
2158 if (open_input_stream(c, "") < 0)
2163 /* must send trailer now because EOF or error */
2164 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2168 int source_index = pkt.stream_index;
2169 /* update first pts if needed */
2170 if (c->first_pts == AV_NOPTS_VALUE) {
2171 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2172 c->start_time = cur_time;
2174 /* send it to the appropriate stream */
2175 if (c->stream->feed) {
2176 /* if coming from a feed, select the right stream */
2177 if (c->switch_pending) {
2178 c->switch_pending = 0;
2179 for(i=0;i<c->stream->nb_streams;i++) {
2180 if (c->switch_feed_streams[i] == pkt.stream_index)
2181 if (pkt.flags & AV_PKT_FLAG_KEY)
2182 c->switch_feed_streams[i] = -1;
2183 if (c->switch_feed_streams[i] >= 0)
2184 c->switch_pending = 1;
2187 for(i=0;i<c->stream->nb_streams;i++) {
2188 if (c->stream->feed_streams[i] == pkt.stream_index) {
2189 AVStream *st = c->fmt_in->streams[source_index];
2190 pkt.stream_index = i;
2191 if (pkt.flags & AV_PKT_FLAG_KEY &&
2192 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2193 c->stream->nb_streams == 1))
2194 c->got_key_frame = 1;
2195 if (!c->stream->send_on_key || c->got_key_frame)
2200 AVCodecContext *codec;
2201 AVStream *ist, *ost;
2203 ist = c->fmt_in->streams[source_index];
2204 /* specific handling for RTP: we use several
2205 * output streams (one for each RTP connection).
2206 * XXX: need more abstract handling */
2207 if (c->is_packetized) {
2208 /* compute send time and duration */
2209 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2210 c->cur_pts -= c->first_pts;
2211 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2212 /* find RTP context */
2213 c->packet_stream_index = pkt.stream_index;
2214 ctx = c->rtp_ctx[c->packet_stream_index];
2216 av_free_packet(&pkt);
2219 codec = ctx->streams[0]->codec;
2220 /* only one stream per RTP connection */
2221 pkt.stream_index = 0;
2225 codec = ctx->streams[pkt.stream_index]->codec;
2228 if (c->is_packetized) {
2229 int max_packet_size;
2230 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2231 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2233 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2234 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2236 ret = avio_open_dyn_buf(&ctx->pb);
2239 /* XXX: potential leak */
2242 ost = ctx->streams[pkt.stream_index];
2244 ctx->pb->seekable = 0;
2245 if (pkt.dts != AV_NOPTS_VALUE)
2246 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2247 if (pkt.pts != AV_NOPTS_VALUE)
2248 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2249 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2250 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2251 http_log("Error writing frame to output for stream '%s': %s\n",
2252 c->stream->filename, av_err2str(ret));
2253 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2256 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2257 c->cur_frame_bytes = len;
2258 c->buffer_ptr = c->pb_buffer;
2259 c->buffer_end = c->pb_buffer + len;
2261 codec->frame_number++;
2263 av_free_packet(&pkt);
2267 av_free_packet(&pkt);
2272 case HTTPSTATE_SEND_DATA_TRAILER:
2273 /* last packet test ? */
2274 if (c->last_packet_sent || c->is_packetized)
2277 /* prepare header */
2278 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2279 /* XXX: potential leak */
2282 c->fmt_ctx.pb->seekable = 0;
2283 av_write_trailer(ctx);
2284 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2285 c->buffer_ptr = c->pb_buffer;
2286 c->buffer_end = c->pb_buffer + len;
2288 c->last_packet_sent = 1;
2294 /* should convert the format at the same time */
2295 /* send data starting at c->buffer_ptr to the output connection
2296 * (either UDP or TCP) */
2297 static int http_send_data(HTTPContext *c)
2302 if (c->buffer_ptr >= c->buffer_end) {
2303 ret = http_prepare_data(c);
2307 /* state change requested */
2310 if (c->is_packetized) {
2311 /* RTP data output */
2312 len = c->buffer_end - c->buffer_ptr;
2314 /* fail safe - should never happen */
2316 c->buffer_ptr = c->buffer_end;
2319 len = (c->buffer_ptr[0] << 24) |
2320 (c->buffer_ptr[1] << 16) |
2321 (c->buffer_ptr[2] << 8) |
2323 if (len > (c->buffer_end - c->buffer_ptr))
2325 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2326 /* nothing to send yet: we can wait */
2330 c->data_count += len;
2331 update_datarate(&c->datarate, c->data_count);
2333 c->stream->bytes_served += len;
2335 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2336 /* RTP packets are sent inside the RTSP TCP connection */
2338 int interleaved_index, size;
2340 HTTPContext *rtsp_c;
2343 /* if no RTSP connection left, error */
2346 /* if already sending something, then wait. */
2347 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2349 if (avio_open_dyn_buf(&pb) < 0)
2351 interleaved_index = c->packet_stream_index * 2;
2352 /* RTCP packets are sent at odd indexes */
2353 if (c->buffer_ptr[1] == 200)
2354 interleaved_index++;
2355 /* write RTSP TCP header */
2357 header[1] = interleaved_index;
2358 header[2] = len >> 8;
2360 avio_write(pb, header, 4);
2361 /* write RTP packet data */
2363 avio_write(pb, c->buffer_ptr, len);
2364 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2365 /* prepare asynchronous TCP sending */
2366 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2367 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2368 c->buffer_ptr += len;
2370 /* send everything we can NOW */
2371 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2372 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2374 rtsp_c->packet_buffer_ptr += len;
2375 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2376 /* if we could not send all the data, we will
2377 send it later, so a new state is needed to
2378 "lock" the RTSP TCP connection */
2379 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2382 /* all data has been sent */
2383 av_freep(&c->packet_buffer);
2385 /* send RTP packet directly in UDP */
2387 ffurl_write(c->rtp_handles[c->packet_stream_index],
2388 c->buffer_ptr, len);
2389 c->buffer_ptr += len;
2390 /* here we continue as we can send several packets per 10 ms slot */
2393 /* TCP data output */
2394 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2396 if (ff_neterrno() != AVERROR(EAGAIN) &&
2397 ff_neterrno() != AVERROR(EINTR))
2398 /* error : close connection */
2403 c->buffer_ptr += len;
2405 c->data_count += len;
2406 update_datarate(&c->datarate, c->data_count);
2408 c->stream->bytes_served += len;
2416 static int http_start_receive_data(HTTPContext *c)
2421 if (c->stream->feed_opened) {
2422 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2423 return AVERROR(EINVAL);
2426 /* Don't permit writing to this one */
2427 if (c->stream->readonly) {
2428 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2429 return AVERROR(EINVAL);
2433 fd = open(c->stream->feed_filename, O_RDWR);
2435 ret = AVERROR(errno);
2436 http_log("Could not open feed file '%s': %s\n",
2437 c->stream->feed_filename, strerror(errno));
2442 if (c->stream->truncate) {
2443 /* truncate feed file */
2444 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2445 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2446 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2447 ret = AVERROR(errno);
2448 http_log("Error truncating feed file '%s': %s\n",
2449 c->stream->feed_filename, strerror(errno));
2453 ret = ffm_read_write_index(fd);
2455 http_log("Error reading write index from feed file '%s': %s\n",
2456 c->stream->feed_filename, strerror(errno));
2459 c->stream->feed_write_index = ret;
2463 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2464 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2465 lseek(fd, 0, SEEK_SET);
2467 /* init buffer input */
2468 c->buffer_ptr = c->buffer;
2469 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2470 c->stream->feed_opened = 1;
2471 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2475 static int http_receive_data(HTTPContext *c)
2478 int len, loop_run = 0;
2480 while (c->chunked_encoding && !c->chunk_size &&
2481 c->buffer_end > c->buffer_ptr) {
2482 /* read chunk header, if present */
2483 len = recv(c->fd, c->buffer_ptr, 1, 0);
2486 if (ff_neterrno() != AVERROR(EAGAIN) &&
2487 ff_neterrno() != AVERROR(EINTR))
2488 /* error : close connection */
2491 } else if (len == 0) {
2492 /* end of connection : close it */
2494 } else if (c->buffer_ptr - c->buffer >= 2 &&
2495 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2496 c->chunk_size = strtol(c->buffer, 0, 16);
2497 if (c->chunk_size == 0) // end of stream
2499 c->buffer_ptr = c->buffer;
2501 } else if (++loop_run > 10) {
2502 /* no chunk header, abort */
2509 if (c->buffer_end > c->buffer_ptr) {
2510 len = recv(c->fd, c->buffer_ptr,
2511 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2513 if (ff_neterrno() != AVERROR(EAGAIN) &&
2514 ff_neterrno() != AVERROR(EINTR))
2515 /* error : close connection */
2517 } else if (len == 0)
2518 /* end of connection : close it */
2521 c->chunk_size -= len;
2522 c->buffer_ptr += len;
2523 c->data_count += len;
2524 update_datarate(&c->datarate, c->data_count);
2528 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2529 if (c->buffer[0] != 'f' ||
2530 c->buffer[1] != 'm') {
2531 http_log("Feed stream has become desynchronized -- disconnecting\n");
2536 if (c->buffer_ptr >= c->buffer_end) {
2537 FFServerStream *feed = c->stream;
2538 /* a packet has been received : write it in the store, except
2540 if (c->data_count > FFM_PACKET_SIZE) {
2541 /* XXX: use llseek or url_seek
2542 * XXX: Should probably fail? */
2543 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2544 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2546 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2547 http_log("Error writing to feed file: %s\n", strerror(errno));
2551 feed->feed_write_index += FFM_PACKET_SIZE;
2552 /* update file size */
2553 if (feed->feed_write_index > c->stream->feed_size)
2554 feed->feed_size = feed->feed_write_index;
2556 /* handle wrap around if max file size reached */
2557 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2558 feed->feed_write_index = FFM_PACKET_SIZE;
2561 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2562 http_log("Error writing index to feed file: %s\n", strerror(errno));
2566 /* wake up any waiting connections */
2567 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2568 if (c1->state == HTTPSTATE_WAIT_FEED &&
2569 c1->stream->feed == c->stream->feed)
2570 c1->state = HTTPSTATE_SEND_DATA;
2573 /* We have a header in our hands that contains useful data */
2574 AVFormatContext *s = avformat_alloc_context();
2576 AVInputFormat *fmt_in;
2582 /* use feed output format name to find corresponding input format */
2583 fmt_in = av_find_input_format(feed->fmt->name);
2587 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2588 0, NULL, NULL, NULL, NULL);
2592 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2597 /* Now we have the actual streams */
2598 if (s->nb_streams != feed->nb_streams) {
2599 avformat_close_input(&s);
2601 http_log("Feed '%s' stream number does not match registered feed\n",
2602 c->stream->feed_filename);
2606 for (i = 0; i < s->nb_streams; i++) {
2607 AVStream *fst = feed->streams[i];
2608 AVStream *st = s->streams[i];
2609 avcodec_copy_context(fst->codec, st->codec);
2612 avformat_close_input(&s);
2615 c->buffer_ptr = c->buffer;
2620 c->stream->feed_opened = 0;
2622 /* wake up any waiting connections to stop waiting for feed */
2623 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2624 if (c1->state == HTTPSTATE_WAIT_FEED &&
2625 c1->stream->feed == c->stream->feed)
2626 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2631 /********************************************************************/
2634 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2641 str = RTSP_STATUS_CODE2STRING(error_number);
2643 str = "Unknown Error";
2645 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2646 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2648 /* output GMT time */
2651 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2652 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2655 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2657 rtsp_reply_header(c, error_number);
2658 avio_printf(c->pb, "\r\n");
2661 static int rtsp_parse_request(HTTPContext *c)
2663 const char *p, *p1, *p2;
2669 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2671 c->buffer_ptr[0] = '\0';
2674 get_word(cmd, sizeof(cmd), &p);
2675 get_word(url, sizeof(url), &p);
2676 get_word(protocol, sizeof(protocol), &p);
2678 av_strlcpy(c->method, cmd, sizeof(c->method));
2679 av_strlcpy(c->url, url, sizeof(c->url));
2680 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2682 if (avio_open_dyn_buf(&c->pb) < 0) {
2683 /* XXX: cannot do more */
2684 c->pb = NULL; /* safety */
2688 /* check version name */
2689 if (strcmp(protocol, "RTSP/1.0") != 0) {
2690 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2694 /* parse each header line */
2695 /* skip to next line */
2696 while (*p != '\n' && *p != '\0')
2700 while (*p != '\0') {
2701 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2705 if (p2 > p && p2[-1] == '\r')
2707 /* skip empty line */
2711 if (len > sizeof(line) - 1)
2712 len = sizeof(line) - 1;
2713 memcpy(line, p, len);
2715 ff_rtsp_parse_line(header, line, NULL, NULL);
2719 /* handle sequence number */
2720 c->seq = header->seq;
2722 if (!strcmp(cmd, "DESCRIBE"))
2723 rtsp_cmd_describe(c, url);
2724 else if (!strcmp(cmd, "OPTIONS"))
2725 rtsp_cmd_options(c, url);
2726 else if (!strcmp(cmd, "SETUP"))
2727 rtsp_cmd_setup(c, url, header);
2728 else if (!strcmp(cmd, "PLAY"))
2729 rtsp_cmd_play(c, url, header);
2730 else if (!strcmp(cmd, "PAUSE"))
2731 rtsp_cmd_interrupt(c, url, header, 1);
2732 else if (!strcmp(cmd, "TEARDOWN"))
2733 rtsp_cmd_interrupt(c, url, header, 0);
2735 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2738 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2739 c->pb = NULL; /* safety */
2741 /* XXX: cannot do more */
2744 c->buffer_ptr = c->pb_buffer;
2745 c->buffer_end = c->pb_buffer + len;
2746 c->state = RTSPSTATE_SEND_REPLY;
2750 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2751 struct in_addr my_ip)
2753 AVFormatContext *avc;
2754 AVStream *avs = NULL;
2755 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2756 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2761 avc = avformat_alloc_context();
2762 if (!avc || !rtp_format) {
2765 avc->oformat = rtp_format;
2766 av_dict_set(&avc->metadata, "title",
2767 entry ? entry->value : "No Title", 0);
2768 avc->nb_streams = stream->nb_streams;
2769 if (stream->is_multicast) {
2770 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2771 inet_ntoa(stream->multicast_ip),
2772 stream->multicast_port, stream->multicast_ttl);
2774 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2777 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2778 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2780 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2781 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2784 for(i = 0; i < stream->nb_streams; i++) {
2785 avc->streams[i] = &avs[i];
2786 avc->streams[i]->codec = stream->streams[i]->codec;
2788 *pbuffer = av_mallocz(2048);
2789 av_sdp_create(&avc, 1, *pbuffer, 2048);
2792 av_freep(&avc->streams);
2793 av_dict_free(&avc->metadata);
2797 return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2800 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2802 // rtsp_reply_header(c, RTSP_STATUS_OK);
2803 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2804 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2805 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2806 avio_printf(c->pb, "\r\n");
2809 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2811 FFServerStream *stream;
2817 struct sockaddr_in my_addr;
2819 /* find which URL is asked */
2820 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2825 for(stream = config.first_stream; stream; stream = stream->next) {
2826 if (!stream->is_feed &&
2827 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2828 !strcmp(path, stream->filename)) {
2832 /* no stream found */
2833 rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
2837 /* prepare the media description in SDP format */
2839 /* get the host IP */
2840 len = sizeof(my_addr);
2841 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2842 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2843 if (content_length < 0) {
2844 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2847 rtsp_reply_header(c, RTSP_STATUS_OK);
2848 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2849 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2850 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2851 avio_printf(c->pb, "\r\n");
2852 avio_write(c->pb, content, content_length);
2856 static HTTPContext *find_rtp_session(const char *session_id)
2860 if (session_id[0] == '\0')
2863 for(c = first_http_ctx; c; c = c->next) {
2864 if (!strcmp(c->session_id, session_id))
2870 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2872 RTSPTransportField *th;
2875 for(i=0;i<h->nb_transports;i++) {
2876 th = &h->transports[i];
2877 if (th->lower_transport == lower_transport)
2883 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2884 RTSPMessageHeader *h)
2886 FFServerStream *stream;
2887 int stream_index, rtp_port, rtcp_port;
2892 RTSPTransportField *th;
2893 struct sockaddr_in dest_addr;
2894 RTSPActionServerSetup setup;
2896 /* find which URL is asked */
2897 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2902 /* now check each stream */
2903 for(stream = config.first_stream; stream; stream = stream->next) {
2904 if (!stream->is_feed &&
2905 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2906 /* accept aggregate filenames only if single stream */
2907 if (!strcmp(path, stream->filename)) {
2908 if (stream->nb_streams != 1) {
2909 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2916 for(stream_index = 0; stream_index < stream->nb_streams;
2918 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2919 stream->filename, stream_index);
2920 if (!strcmp(path, buf))
2925 /* no stream found */
2926 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2930 /* generate session id if needed */
2931 if (h->session_id[0] == '\0') {
2932 unsigned random0 = av_lfg_get(&random_state);
2933 unsigned random1 = av_lfg_get(&random_state);
2934 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2938 /* find RTP session, and create it if none found */
2939 rtp_c = find_rtp_session(h->session_id);
2941 /* always prefer UDP */
2942 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2944 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2946 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2951 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2952 th->lower_transport);
2954 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2958 /* open input stream */
2959 if (open_input_stream(rtp_c, "") < 0) {
2960 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2965 /* test if stream is OK (test needed because several SETUP needs
2966 to be done for a given file) */
2967 if (rtp_c->stream != stream) {
2968 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2972 /* test if stream is already set up */
2973 if (rtp_c->rtp_ctx[stream_index]) {
2974 rtsp_reply_error(c, RTSP_STATUS_STATE);
2978 /* check transport */
2979 th = find_transport(h, rtp_c->rtp_protocol);
2980 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2981 th->client_port_min <= 0)) {
2982 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2986 /* setup default options */
2987 setup.transport_option[0] = '\0';
2988 dest_addr = rtp_c->from_addr;
2989 dest_addr.sin_port = htons(th->client_port_min);
2992 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2993 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2997 /* now everything is OK, so we can send the connection parameters */
2998 rtsp_reply_header(c, RTSP_STATUS_OK);
3000 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3002 switch(rtp_c->rtp_protocol) {
3003 case RTSP_LOWER_TRANSPORT_UDP:
3004 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3005 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3006 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3007 "client_port=%d-%d;server_port=%d-%d",
3008 th->client_port_min, th->client_port_max,
3009 rtp_port, rtcp_port);
3011 case RTSP_LOWER_TRANSPORT_TCP:
3012 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3013 stream_index * 2, stream_index * 2 + 1);
3018 if (setup.transport_option[0] != '\0')
3019 avio_printf(c->pb, ";%s", setup.transport_option);
3020 avio_printf(c->pb, "\r\n");
3023 avio_printf(c->pb, "\r\n");
3027 /* find an RTP connection by using the session ID. Check consistency
3029 static HTTPContext *find_rtp_session_with_url(const char *url,
3030 const char *session_id)
3038 rtp_c = find_rtp_session(session_id);
3042 /* find which URL is asked */
3043 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3047 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3048 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3049 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3050 rtp_c->stream->filename, s);
3051 if(!strncmp(path, buf, sizeof(buf))) {
3052 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3057 if (len > 0 && path[len - 1] == '/' &&
3058 !strncmp(path, rtp_c->stream->filename, len - 1))
3063 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3067 rtp_c = find_rtp_session_with_url(url, h->session_id);
3069 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3073 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3074 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3075 rtp_c->state != HTTPSTATE_READY) {
3076 rtsp_reply_error(c, RTSP_STATUS_STATE);
3080 rtp_c->state = HTTPSTATE_SEND_DATA;
3082 /* now everything is OK, so we can send the connection parameters */
3083 rtsp_reply_header(c, RTSP_STATUS_OK);
3085 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3086 avio_printf(c->pb, "\r\n");
3089 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3093 rtp_c = find_rtp_session_with_url(url, h->session_id);
3095 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3100 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3101 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3102 rtsp_reply_error(c, RTSP_STATUS_STATE);
3105 rtp_c->state = HTTPSTATE_READY;
3106 rtp_c->first_pts = AV_NOPTS_VALUE;
3109 /* now everything is OK, so we can send the connection parameters */
3110 rtsp_reply_header(c, RTSP_STATUS_OK);
3112 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3113 avio_printf(c->pb, "\r\n");
3116 close_connection(rtp_c);
3119 /********************************************************************/
3122 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3123 FFServerStream *stream, const char *session_id,
3124 enum RTSPLowerTransport rtp_protocol)
3126 HTTPContext *c = NULL;
3127 const char *proto_str;
3129 /* XXX: should output a warning page when coming
3130 close to the connection limit */
3131 if (nb_connections >= config.nb_max_connections)
3134 /* add a new connection */
3135 c = av_mallocz(sizeof(HTTPContext));
3140 c->poll_entry = NULL;
3141 c->from_addr = *from_addr;
3142 c->buffer_size = IOBUFFER_INIT_SIZE;
3143 c->buffer = av_malloc(c->buffer_size);
3148 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3149 c->state = HTTPSTATE_READY;
3150 c->is_packetized = 1;
3151 c->rtp_protocol = rtp_protocol;
3153 /* protocol is shown in statistics */
3154 switch(c->rtp_protocol) {
3155 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3156 proto_str = "MCAST";
3158 case RTSP_LOWER_TRANSPORT_UDP:
3161 case RTSP_LOWER_TRANSPORT_TCP:
3168 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3169 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3171 current_bandwidth += stream->bandwidth;
3173 c->next = first_http_ctx;
3179 av_freep(&c->buffer);
3185 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3186 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3188 static int rtp_new_av_stream(HTTPContext *c,
3189 int stream_index, struct sockaddr_in *dest_addr,
3190 HTTPContext *rtsp_c)
3192 AVFormatContext *ctx;
3195 URLContext *h = NULL;
3197 int max_packet_size;
3199 /* now we can open the relevant output stream */
3200 ctx = avformat_alloc_context();
3203 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3205 st = av_mallocz(sizeof(AVStream));
3208 ctx->nb_streams = 1;
3209 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3212 ctx->streams[0] = st;
3214 if (!c->stream->feed ||
3215 c->stream->feed == c->stream)
3216 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3219 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3221 st->priv_data = NULL;
3223 /* build destination RTP address */
3224 ipaddr = inet_ntoa(dest_addr->sin_addr);
3226 switch(c->rtp_protocol) {
3227 case RTSP_LOWER_TRANSPORT_UDP:
3228 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3231 /* XXX: also pass as parameter to function ? */
3232 if (c->stream->is_multicast) {
3234 ttl = c->stream->multicast_ttl;
3237 snprintf(ctx->filename, sizeof(ctx->filename),
3238 "rtp://%s:%d?multicast=1&ttl=%d",
3239 ipaddr, ntohs(dest_addr->sin_port), ttl);
3241 snprintf(ctx->filename, sizeof(ctx->filename),
3242 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3245 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3247 c->rtp_handles[stream_index] = h;
3248 max_packet_size = h->max_packet_size;
3250 case RTSP_LOWER_TRANSPORT_TCP:
3253 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3259 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3260 ipaddr, ntohs(dest_addr->sin_port),
3261 c->stream->filename, stream_index, c->protocol);
3263 /* normally, no packets should be output here, but the packet size may
3265 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3266 /* XXX: close stream */
3269 if (avformat_write_header(ctx, NULL) < 0) {
3277 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3280 c->rtp_ctx[stream_index] = ctx;
3284 /********************************************************************/
3285 /* ffserver initialization */
3287 static AVStream *add_av_stream1(FFServerStream *stream, AVCodecContext *codec, int copy)
3291 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3294 fst = av_mallocz(sizeof(AVStream));
3298 fst->codec = avcodec_alloc_context3(NULL);
3299 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3300 if (codec->extradata_size) {
3301 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3302 memcpy(fst->codec->extradata, codec->extradata,
3303 codec->extradata_size);
3306 /* live streams must use the actual feed's codec since it may be
3307 * updated later to carry extradata needed by them.
3311 fst->priv_data = av_mallocz(sizeof(FeedData));
3312 fst->index = stream->nb_streams;
3313 avpriv_set_pts_info(fst, 33, 1, 90000);
3314 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3315 stream->streams[stream->nb_streams++] = fst;
3319 /* return the stream number in the feed */
3320 static int add_av_stream(FFServerStream *feed, AVStream *st)
3323 AVCodecContext *av, *av1;
3327 for(i=0;i<feed->nb_streams;i++) {
3328 st = feed->streams[i];
3330 if (av1->codec_id == av->codec_id &&
3331 av1->codec_type == av->codec_type &&
3332 av1->bit_rate == av->bit_rate) {
3334 switch(av->codec_type) {
3335 case AVMEDIA_TYPE_AUDIO:
3336 if (av1->channels == av->channels &&
3337 av1->sample_rate == av->sample_rate)
3340 case AVMEDIA_TYPE_VIDEO:
3341 if (av1->width == av->width &&
3342 av1->height == av->height &&
3343 av1->time_base.den == av->time_base.den &&
3344 av1->time_base.num == av->time_base.num &&
3345 av1->gop_size == av->gop_size)
3354 fst = add_av_stream1(feed, av, 0);
3357 return feed->nb_streams - 1;
3360 static void remove_stream(FFServerStream *stream)
3362 FFServerStream **ps;
3363 ps = &config.first_stream;
3372 /* specific MPEG4 handling : we extract the raw parameters */
3373 static void extract_mpeg4_header(AVFormatContext *infile)
3375 int mpeg4_count, i, size;
3380 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3383 for(i=0;i<infile->nb_streams;i++) {
3384 st = infile->streams[i];
3385 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3386 st->codec->extradata_size == 0) {
3393 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3394 while (mpeg4_count > 0) {
3395 if (av_read_frame(infile, &pkt) < 0)
3397 st = infile->streams[pkt.stream_index];
3398 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3399 st->codec->extradata_size == 0) {
3400 av_freep(&st->codec->extradata);
3401 /* fill extradata with the header */
3402 /* XXX: we make hard suppositions here ! */
3404 while (p < pkt.data + pkt.size - 4) {
3405 /* stop when vop header is found */
3406 if (p[0] == 0x00 && p[1] == 0x00 &&
3407 p[2] == 0x01 && p[3] == 0xb6) {
3408 size = p - pkt.data;
3409 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3410 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3411 st->codec->extradata_size = size;
3412 memcpy(st->codec->extradata, pkt.data, size);
3419 av_free_packet(&pkt);
3423 /* compute the needed AVStream for each file */
3424 static void build_file_streams(void)
3426 FFServerStream *stream, *stream_next;
3429 /* gather all streams */
3430 for(stream = config.first_stream; stream; stream = stream_next) {
3431 AVFormatContext *infile = NULL;
3432 stream_next = stream->next;
3433 if (stream->stream_type == STREAM_TYPE_LIVE &&
3435 /* the stream comes from a file */
3436 /* try to open the file */
3438 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3439 /* specific case : if transport stream output to RTP,
3440 we use a raw transport stream reader */
3441 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3444 if (!stream->feed_filename[0]) {
3445 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3449 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3450 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3451 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3452 /* remove stream (no need to spend more time on it) */
3454 remove_stream(stream);
3456 /* find all the AVStreams inside and reference them in
3458 if (avformat_find_stream_info(infile, NULL) < 0) {
3459 http_log("Could not find codec parameters from '%s'\n",
3460 stream->feed_filename);
3461 avformat_close_input(&infile);
3464 extract_mpeg4_header(infile);
3466 for(i=0;i<infile->nb_streams;i++)
3467 add_av_stream1(stream, infile->streams[i]->codec, 1);
3469 avformat_close_input(&infile);
3475 /* compute the needed AVStream for each feed */
3476 static void build_feed_streams(void)
3478 FFServerStream *stream, *feed;
3481 /* gather all streams */
3482 for(stream = config.first_stream; stream; stream = stream->next) {
3483 feed = stream->feed;
3485 if (stream->is_feed) {
3486 for(i=0;i<stream->nb_streams;i++)
3487 stream->feed_streams[i] = i;
3489 /* we handle a stream coming from a feed */
3490 for(i=0;i<stream->nb_streams;i++)
3491 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3496 /* create feed files if needed */
3497 for(feed = config.first_feed; feed; feed = feed->next_feed) {
3500 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3501 /* See if it matches */
3502 AVFormatContext *s = NULL;
3505 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3506 /* set buffer size */
3507 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3508 /* Now see if it matches */
3509 if (s->nb_streams == feed->nb_streams) {
3511 for(i=0;i<s->nb_streams;i++) {
3513 sf = feed->streams[i];
3516 if (sf->index != ss->index ||
3518 http_log("Index & Id do not match for stream %d (%s)\n",
3519 i, feed->feed_filename);
3522 AVCodecContext *ccf, *ccs;
3526 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3528 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3529 http_log("Codecs do not match for stream %d\n", i);
3531 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3532 http_log("Codec bitrates do not match for stream %d\n", i);
3534 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3535 if (CHECK_CODEC(time_base.den) ||
3536 CHECK_CODEC(time_base.num) ||
3537 CHECK_CODEC(width) ||
3538 CHECK_CODEC(height)) {
3539 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3542 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3543 if (CHECK_CODEC(sample_rate) ||
3544 CHECK_CODEC(channels) ||
3545 CHECK_CODEC(frame_size)) {
3546 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3550 http_log("Unknown codec type\n");
3558 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3559 feed->feed_filename, s->nb_streams, feed->nb_streams);
3561 avformat_close_input(&s);
3563 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3564 feed->feed_filename);
3567 if (feed->readonly) {
3568 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3569 feed->feed_filename);
3572 unlink(feed->feed_filename);
3575 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3576 AVFormatContext *s = avformat_alloc_context();
3578 if (feed->readonly) {
3579 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3580 feed->feed_filename);
3584 /* only write the header of the ffm file */
3585 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3586 http_log("Could not open output feed file '%s'\n",
3587 feed->feed_filename);
3590 s->oformat = feed->fmt;
3591 s->nb_streams = feed->nb_streams;
3592 s->streams = feed->streams;
3593 if (avformat_write_header(s, NULL) < 0) {
3594 http_log("Container doesn't support the required parameters\n");
3597 /* XXX: need better API */
3598 av_freep(&s->priv_data);
3602 avformat_free_context(s);
3604 /* get feed size and write index */
3605 fd = open(feed->feed_filename, O_RDONLY);
3607 http_log("Could not open output feed file '%s'\n",
3608 feed->feed_filename);
3612 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3613 feed->feed_size = lseek(fd, 0, SEEK_END);
3614 /* ensure that we do not wrap before the end of file */
3615 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3616 feed->feed_max_size = feed->feed_size;
3622 /* compute the bandwidth used by each stream */
3623 static void compute_bandwidth(void)
3627 FFServerStream *stream;
3629 for(stream = config.first_stream; stream; stream = stream->next) {
3631 for(i=0;i<stream->nb_streams;i++) {
3632 AVStream *st = stream->streams[i];
3633 switch(st->codec->codec_type) {
3634 case AVMEDIA_TYPE_AUDIO:
3635 case AVMEDIA_TYPE_VIDEO:
3636 bandwidth += st->codec->bit_rate;
3642 stream->bandwidth = (bandwidth + 999) / 1000;
3646 static void handle_child_exit(int sig)
3651 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3652 FFServerStream *feed;
3654 for (feed = config.first_feed; feed; feed = feed->next) {
3655 if (feed->pid == pid) {
3656 int uptime = time(0) - feed->pid_start;
3659 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
3662 /* Turn off any more restarts */
3663 feed->child_argv = 0;
3668 need_to_start_children = 1;
3671 static void opt_debug(void)
3674 snprintf(config.logfilename, sizeof(config.logfilename), "-");
3677 void show_help_default(const char *opt, const char *arg)
3679 printf("usage: ffserver [options]\n"
3680 "Hyper fast multi format Audio/Video streaming server\n");
3682 show_help_options(options, "Main options:", 0, 0, 0);
3685 static const OptionDef options[] = {
3686 #include "cmdutils_common_opts.h"
3687 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3688 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3689 { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3693 int main(int argc, char **argv)
3695 struct sigaction sigact = { { 0 } };
3698 config.filename = av_strdup("/etc/ffserver.conf");
3700 parse_loglevel(argc, argv, options);
3702 avformat_network_init();
3704 show_banner(argc, argv, options);
3706 my_program_name = argv[0];
3708 parse_options(NULL, argc, argv, options, NULL);
3710 unsetenv("http_proxy"); /* Kill the http_proxy */
3712 av_lfg_init(&random_state, av_get_random_seed());
3714 sigact.sa_handler = handle_child_exit;
3715 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3716 sigaction(SIGCHLD, &sigact, 0);
3718 if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3719 fprintf(stderr, "Error reading configuration file '%s': %s\n",
3720 config.filename, av_err2str(ret));
3723 av_freep(&config.filename);
3725 /* open log file if needed */
3726 if (config.logfilename[0] != '\0') {
3727 if (!strcmp(config.logfilename, "-"))
3730 logfile = fopen(config.logfilename, "a");
3731 av_log_set_callback(http_av_log);
3734 build_file_streams();
3736 build_feed_streams();
3738 compute_bandwidth();
3741 signal(SIGPIPE, SIG_IGN);
3743 if (http_server() < 0) {
3744 http_log("Could not start server\n");