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/rtsp.h"
40 #include "libavformat/avio_internal.h"
41 #include "libavformat/internal.h"
42 #include "libavformat/url.h"
44 #include "libavutil/avassert.h"
45 #include "libavutil/avstring.h"
46 #include "libavutil/lfg.h"
47 #include "libavutil/dict.h"
48 #include "libavutil/intreadwrite.h"
49 #include "libavutil/mathematics.h"
50 #include "libavutil/random_seed.h"
51 #include "libavutil/parseutils.h"
52 #include "libavutil/opt.h"
53 #include "libavutil/time.h"
58 #include <sys/ioctl.h>
72 const char program_name[] = "ffserver";
73 const int program_birth_year = 2000;
75 static const OptionDef options[];
78 HTTPSTATE_WAIT_REQUEST,
79 HTTPSTATE_SEND_HEADER,
80 HTTPSTATE_SEND_DATA_HEADER,
81 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
82 HTTPSTATE_SEND_DATA_TRAILER,
83 HTTPSTATE_RECEIVE_DATA,
84 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
87 RTSPSTATE_WAIT_REQUEST,
89 RTSPSTATE_SEND_PACKET,
92 static const char *http_state[] = {
108 #define MAX_STREAMS 20
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 FFStream *stream;
158 /* -1 is invalid stream */
159 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
160 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
162 AVFormatContext fmt_ctx; /* instance of FFStream 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[MAX_STREAMS];
185 /* RTP/UDP specific */
186 URLContext *rtp_handles[MAX_STREAMS];
188 /* RTP/TCP specific */
189 struct HTTPContext *rtsp_c;
190 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
193 /* each generated stream is described here */
197 STREAM_TYPE_REDIRECT,
200 enum IPAddressAction {
205 typedef struct IPAddressACL {
206 struct IPAddressACL *next;
207 enum IPAddressAction action;
208 /* These are in host order */
209 struct in_addr first;
213 /* description of each stream of the ffserver.conf file */
214 typedef struct FFStream {
215 enum StreamType stream_type;
216 char filename[1024]; /* stream filename */
217 struct FFStream *feed; /* feed we are using (can be null if
219 AVDictionary *in_opts; /* input parameters */
220 AVInputFormat *ifmt; /* if non NULL, force input format */
223 char dynamic_acl[1024];
225 int prebuffer; /* Number of millseconds early to start */
226 int64_t max_time; /* Number of milliseconds to run */
228 AVStream *streams[MAX_STREAMS];
229 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
230 char feed_filename[1024]; /* file name of the feed storage, or
231 input file name for a stream */
236 pid_t pid; /* Of ffmpeg process */
237 time_t pid_start; /* Of ffmpeg process */
239 struct FFStream *next;
240 unsigned bandwidth; /* bandwidth, in kbits/s */
243 /* multicast specific */
245 struct in_addr multicast_ip;
246 int multicast_port; /* first port used for multicast */
248 int loop; /* if true, send the stream in loops (only meaningful if file) */
251 int feed_opened; /* true if someone is writing to the feed */
252 int is_feed; /* true if it is a feed */
253 int readonly; /* True if writing is prohibited to the file */
254 int truncate; /* True if feeder connection truncate the feed file */
256 int64_t bytes_served;
257 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
258 int64_t feed_write_index; /* current write position in feed (it wraps around) */
259 int64_t feed_size; /* current size of feed */
260 struct FFStream *next_feed;
263 typedef struct FeedData {
264 long long data_count;
265 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
268 static struct sockaddr_in my_http_addr;
269 static struct sockaddr_in my_rtsp_addr;
271 static char logfilename[1024];
272 static HTTPContext *first_http_ctx;
273 static FFStream *first_feed; /* contains only feeds */
274 static FFStream *first_stream; /* contains all streams, including feeds */
276 static void new_connection(int server_fd, int is_rtsp);
277 static void close_connection(HTTPContext *c);
280 static int handle_connection(HTTPContext *c);
281 static int http_parse_request(HTTPContext *c);
282 static int http_send_data(HTTPContext *c);
283 static void compute_status(HTTPContext *c);
284 static int open_input_stream(HTTPContext *c, const char *info);
285 static int http_start_receive_data(HTTPContext *c);
286 static int http_receive_data(HTTPContext *c);
289 static int rtsp_parse_request(HTTPContext *c);
290 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
291 static void rtsp_cmd_options(HTTPContext *c, const char *url);
292 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
293 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
294 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
295 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
298 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
299 struct in_addr my_ip);
302 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
303 FFStream *stream, const char *session_id,
304 enum RTSPLowerTransport rtp_protocol);
305 static int rtp_new_av_stream(HTTPContext *c,
306 int stream_index, struct sockaddr_in *dest_addr,
307 HTTPContext *rtsp_c);
309 static const char *my_program_name;
311 static const char *config_filename;
313 static int ffserver_debug;
314 static int no_launch;
315 static int need_to_start_children;
317 /* maximum number of simultaneous HTTP connections */
318 static unsigned int nb_max_http_connections = 2000;
319 static unsigned int nb_max_connections = 5;
320 static unsigned int nb_connections;
322 static uint64_t max_bandwidth = 1000;
323 static uint64_t current_bandwidth;
325 static int64_t cur_time; // Making this global saves on passing it around everywhere
327 static AVLFG random_state;
329 static FILE *logfile = NULL;
331 static int64_t ffm_read_write_index(int fd)
335 if (lseek(fd, 8, SEEK_SET) < 0)
337 if (read(fd, buf, 8) != 8)
342 static int ffm_write_write_index(int fd, int64_t pos)
348 buf[i] = (pos >> (56 - i * 8)) & 0xff;
349 if (lseek(fd, 8, SEEK_SET) < 0)
351 if (write(fd, buf, 8) != 8)
356 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
359 FFMContext *ffm = s->priv_data;
360 ffm->write_index = pos;
361 ffm->file_size = file_size;
364 /* FIXME: make ffserver work with IPv6 */
365 /* resolve host with also IP address parsing */
366 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
369 if (!ff_inet_aton(hostname, sin_addr)) {
371 struct addrinfo *ai, *cur;
372 struct addrinfo hints = { 0 };
373 hints.ai_family = AF_INET;
374 if (getaddrinfo(hostname, NULL, &hints, &ai))
376 /* getaddrinfo returns a linked list of addrinfo structs.
377 * Even if we set ai_family = AF_INET above, make sure
378 * that the returned one actually is of the correct type. */
379 for (cur = ai; cur; cur = cur->ai_next) {
380 if (cur->ai_family == AF_INET) {
381 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
390 hp = gethostbyname(hostname);
393 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
399 static char *ctime1(char *buf2, int buf_size)
406 av_strlcpy(buf2, p, buf_size);
407 p = buf2 + strlen(p) - 1;
413 static void http_vlog(const char *fmt, va_list vargs)
415 static int print_prefix = 1;
419 ctime1(buf, sizeof(buf));
420 fprintf(logfile, "%s ", buf);
422 print_prefix = strstr(fmt, "\n") != NULL;
423 vfprintf(logfile, fmt, vargs);
429 __attribute__ ((format (printf, 1, 2)))
431 static void http_log(const char *fmt, ...)
434 va_start(vargs, fmt);
435 http_vlog(fmt, vargs);
439 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
441 static int print_prefix = 1;
442 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
443 if (level > av_log_get_level())
445 if (print_prefix && avc)
446 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
447 print_prefix = strstr(fmt, "\n") != NULL;
448 http_vlog(fmt, vargs);
451 static void log_connection(HTTPContext *c)
456 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
457 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
458 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
461 static void update_datarate(DataRateData *drd, int64_t count)
463 if (!drd->time1 && !drd->count1) {
464 drd->time1 = drd->time2 = cur_time;
465 drd->count1 = drd->count2 = count;
466 } else if (cur_time - drd->time2 > 5000) {
467 drd->time1 = drd->time2;
468 drd->count1 = drd->count2;
469 drd->time2 = cur_time;
474 /* In bytes per second */
475 static int compute_datarate(DataRateData *drd, int64_t count)
477 if (cur_time == drd->time1)
480 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
484 static void start_children(FFStream *feed)
489 for (; feed; feed = feed->next) {
490 if (feed->child_argv && !feed->pid) {
491 feed->pid_start = time(0);
496 http_log("Unable to create children\n");
505 av_strlcpy(pathname, my_program_name, sizeof(pathname));
507 slash = strrchr(pathname, '/');
512 strcpy(slash, "ffmpeg");
514 http_log("Launch command line: ");
515 http_log("%s ", pathname);
516 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
517 http_log("%s ", feed->child_argv[i]);
520 for (i = 3; i < 256; i++)
523 if (!ffserver_debug) {
524 if (!freopen("/dev/null", "r", stdin))
525 http_log("failed to redirect STDIN to /dev/null\n;");
526 if (!freopen("/dev/null", "w", stdout))
527 http_log("failed to redirect STDOUT to /dev/null\n;");
528 if (!freopen("/dev/null", "w", stderr))
529 http_log("failed to redirect STDERR to /dev/null\n;");
532 signal(SIGPIPE, SIG_DFL);
534 execvp(pathname, feed->child_argv);
542 /* open a listening socket */
543 static int socket_open_listen(struct sockaddr_in *my_addr)
547 server_fd = socket(AF_INET,SOCK_STREAM,0);
554 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
556 my_addr->sin_family = AF_INET;
557 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
559 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
561 closesocket(server_fd);
565 if (listen (server_fd, 5) < 0) {
567 closesocket(server_fd);
570 ff_socket_nonblock(server_fd, 1);
575 /* start all multicast streams */
576 static void start_multicast(void)
581 struct sockaddr_in dest_addr = {0};
582 int default_port, stream_index;
585 for(stream = first_stream; stream != NULL; stream = stream->next) {
586 if (stream->is_multicast) {
587 unsigned random0 = av_lfg_get(&random_state);
588 unsigned random1 = av_lfg_get(&random_state);
589 /* open the RTP connection */
590 snprintf(session_id, sizeof(session_id), "%08x%08x",
593 /* choose a port if none given */
594 if (stream->multicast_port == 0) {
595 stream->multicast_port = default_port;
599 dest_addr.sin_family = AF_INET;
600 dest_addr.sin_addr = stream->multicast_ip;
601 dest_addr.sin_port = htons(stream->multicast_port);
603 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
604 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
608 if (open_input_stream(rtp_c, "") < 0) {
609 http_log("Could not open input stream for stream '%s'\n",
614 /* open each RTP stream */
615 for(stream_index = 0; stream_index < stream->nb_streams;
617 dest_addr.sin_port = htons(stream->multicast_port +
619 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
620 http_log("Could not open output stream '%s/streamid=%d'\n",
621 stream->filename, stream_index);
626 /* change state to send data */
627 rtp_c->state = HTTPSTATE_SEND_DATA;
632 /* main loop of the http server */
633 static int http_server(void)
635 int server_fd = 0, rtsp_server_fd = 0;
636 int ret, delay, delay1;
637 struct pollfd *poll_table, *poll_entry;
638 HTTPContext *c, *c_next;
640 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
641 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
645 if (my_http_addr.sin_port) {
646 server_fd = socket_open_listen(&my_http_addr);
651 if (my_rtsp_addr.sin_port) {
652 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
653 if (rtsp_server_fd < 0)
657 if (!rtsp_server_fd && !server_fd) {
658 http_log("HTTP and RTSP disabled.\n");
662 http_log("FFserver started.\n");
664 start_children(first_feed);
669 poll_entry = poll_table;
671 poll_entry->fd = server_fd;
672 poll_entry->events = POLLIN;
675 if (rtsp_server_fd) {
676 poll_entry->fd = rtsp_server_fd;
677 poll_entry->events = POLLIN;
681 /* wait for events on each HTTP handle */
688 case HTTPSTATE_SEND_HEADER:
689 case RTSPSTATE_SEND_REPLY:
690 case RTSPSTATE_SEND_PACKET:
691 c->poll_entry = poll_entry;
693 poll_entry->events = POLLOUT;
696 case HTTPSTATE_SEND_DATA_HEADER:
697 case HTTPSTATE_SEND_DATA:
698 case HTTPSTATE_SEND_DATA_TRAILER:
699 if (!c->is_packetized) {
700 /* for TCP, we output as much as we can (may need to put a limit) */
701 c->poll_entry = poll_entry;
703 poll_entry->events = POLLOUT;
706 /* when ffserver is doing the timing, we work by
707 looking at which packet need to be sent every
709 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
714 case HTTPSTATE_WAIT_REQUEST:
715 case HTTPSTATE_RECEIVE_DATA:
716 case HTTPSTATE_WAIT_FEED:
717 case RTSPSTATE_WAIT_REQUEST:
718 /* need to catch errors */
719 c->poll_entry = poll_entry;
721 poll_entry->events = POLLIN;/* Maybe this will work */
725 c->poll_entry = NULL;
731 /* wait for an event on one connection. We poll at least every
732 second to handle timeouts */
734 ret = poll(poll_table, poll_entry - poll_table, delay);
735 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
736 ff_neterrno() != AVERROR(EINTR))
740 cur_time = av_gettime() / 1000;
742 if (need_to_start_children) {
743 need_to_start_children = 0;
744 start_children(first_feed);
747 /* now handle the events */
748 for(c = first_http_ctx; c != NULL; c = c_next) {
750 if (handle_connection(c) < 0) {
751 /* close and free the connection */
757 poll_entry = poll_table;
759 /* new HTTP connection request ? */
760 if (poll_entry->revents & POLLIN)
761 new_connection(server_fd, 0);
764 if (rtsp_server_fd) {
765 /* new RTSP connection request ? */
766 if (poll_entry->revents & POLLIN)
767 new_connection(rtsp_server_fd, 1);
772 /* start waiting for a new HTTP/RTSP request */
773 static void start_wait_request(HTTPContext *c, int is_rtsp)
775 c->buffer_ptr = c->buffer;
776 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
779 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
780 c->state = RTSPSTATE_WAIT_REQUEST;
782 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
783 c->state = HTTPSTATE_WAIT_REQUEST;
787 static void http_send_too_busy_reply(int fd)
790 int len = snprintf(buffer, sizeof(buffer),
791 "HTTP/1.0 503 Server too busy\r\n"
792 "Content-type: text/html\r\n"
794 "<html><head><title>Too busy</title></head><body>\r\n"
795 "<p>The server is too busy to serve your request at this time.</p>\r\n"
796 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
797 "</body></html>\r\n",
798 nb_connections, nb_max_connections);
799 av_assert0(len < sizeof(buffer));
800 send(fd, buffer, len, 0);
804 static void new_connection(int server_fd, int is_rtsp)
806 struct sockaddr_in from_addr;
809 HTTPContext *c = NULL;
811 len = sizeof(from_addr);
812 fd = accept(server_fd, (struct sockaddr *)&from_addr,
815 http_log("error during accept %s\n", strerror(errno));
818 ff_socket_nonblock(fd, 1);
820 if (nb_connections >= nb_max_connections) {
821 http_send_too_busy_reply(fd);
825 /* add a new connection */
826 c = av_mallocz(sizeof(HTTPContext));
831 c->poll_entry = NULL;
832 c->from_addr = from_addr;
833 c->buffer_size = IOBUFFER_INIT_SIZE;
834 c->buffer = av_malloc(c->buffer_size);
838 c->next = first_http_ctx;
842 start_wait_request(c, is_rtsp);
854 static void close_connection(HTTPContext *c)
856 HTTPContext **cp, *c1;
858 AVFormatContext *ctx;
862 /* remove connection from list */
863 cp = &first_http_ctx;
864 while ((*cp) != NULL) {
872 /* remove references, if any (XXX: do it faster) */
873 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
878 /* remove connection associated resources */
882 /* close each frame parser */
883 for(i=0;i<c->fmt_in->nb_streams;i++) {
884 st = c->fmt_in->streams[i];
885 if (st->codec->codec)
886 avcodec_close(st->codec);
888 avformat_close_input(&c->fmt_in);
891 /* free RTP output streams if any */
894 nb_streams = c->stream->nb_streams;
896 for(i=0;i<nb_streams;i++) {
899 av_write_trailer(ctx);
900 av_dict_free(&ctx->metadata);
901 av_free(ctx->streams[0]);
904 h = c->rtp_handles[i];
911 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
914 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
915 av_write_trailer(ctx);
916 av_freep(&c->pb_buffer);
917 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
922 for(i=0; i<ctx->nb_streams; i++)
923 av_free(ctx->streams[i]);
924 av_freep(&ctx->streams);
925 av_freep(&ctx->priv_data);
927 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
928 current_bandwidth -= c->stream->bandwidth;
930 /* signal that there is no feed if we are the feeder socket */
931 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
932 c->stream->feed_opened = 0;
936 av_freep(&c->pb_buffer);
937 av_freep(&c->packet_buffer);
943 static int handle_connection(HTTPContext *c)
948 case HTTPSTATE_WAIT_REQUEST:
949 case RTSPSTATE_WAIT_REQUEST:
951 if ((c->timeout - cur_time) < 0)
953 if (c->poll_entry->revents & (POLLERR | POLLHUP))
956 /* no need to read if no events */
957 if (!(c->poll_entry->revents & POLLIN))
961 len = recv(c->fd, c->buffer_ptr, 1, 0);
963 if (ff_neterrno() != AVERROR(EAGAIN) &&
964 ff_neterrno() != AVERROR(EINTR))
966 } else if (len == 0) {
969 /* search for end of request. */
971 c->buffer_ptr += len;
973 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
974 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
975 /* request found : parse it and reply */
976 if (c->state == HTTPSTATE_WAIT_REQUEST) {
977 ret = http_parse_request(c);
979 ret = rtsp_parse_request(c);
983 } else if (ptr >= c->buffer_end) {
984 /* request too long: cannot do anything */
986 } else goto read_loop;
990 case HTTPSTATE_SEND_HEADER:
991 if (c->poll_entry->revents & (POLLERR | POLLHUP))
994 /* no need to write if no events */
995 if (!(c->poll_entry->revents & POLLOUT))
997 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
999 if (ff_neterrno() != AVERROR(EAGAIN) &&
1000 ff_neterrno() != AVERROR(EINTR)) {
1001 /* error : close connection */
1002 av_freep(&c->pb_buffer);
1006 c->buffer_ptr += len;
1008 c->stream->bytes_served += len;
1009 c->data_count += len;
1010 if (c->buffer_ptr >= c->buffer_end) {
1011 av_freep(&c->pb_buffer);
1012 /* if error, exit */
1015 /* all the buffer was sent : synchronize to the incoming stream */
1016 c->state = HTTPSTATE_SEND_DATA_HEADER;
1017 c->buffer_ptr = c->buffer_end = c->buffer;
1022 case HTTPSTATE_SEND_DATA:
1023 case HTTPSTATE_SEND_DATA_HEADER:
1024 case HTTPSTATE_SEND_DATA_TRAILER:
1025 /* for packetized output, we consider we can always write (the
1026 input streams sets the speed). It may be better to verify
1027 that we do not rely too much on the kernel queues */
1028 if (!c->is_packetized) {
1029 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1032 /* no need to read if no events */
1033 if (!(c->poll_entry->revents & POLLOUT))
1036 if (http_send_data(c) < 0)
1038 /* close connection if trailer sent */
1039 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1042 case HTTPSTATE_RECEIVE_DATA:
1043 /* no need to read if no events */
1044 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1046 if (!(c->poll_entry->revents & POLLIN))
1048 if (http_receive_data(c) < 0)
1051 case HTTPSTATE_WAIT_FEED:
1052 /* no need to read if no events */
1053 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1056 /* nothing to do, we'll be waken up by incoming feed packets */
1059 case RTSPSTATE_SEND_REPLY:
1060 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1061 av_freep(&c->pb_buffer);
1064 /* no need to write if no events */
1065 if (!(c->poll_entry->revents & POLLOUT))
1067 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1069 if (ff_neterrno() != AVERROR(EAGAIN) &&
1070 ff_neterrno() != AVERROR(EINTR)) {
1071 /* error : close connection */
1072 av_freep(&c->pb_buffer);
1076 c->buffer_ptr += len;
1077 c->data_count += len;
1078 if (c->buffer_ptr >= c->buffer_end) {
1079 /* all the buffer was sent : wait for a new request */
1080 av_freep(&c->pb_buffer);
1081 start_wait_request(c, 1);
1085 case RTSPSTATE_SEND_PACKET:
1086 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1087 av_freep(&c->packet_buffer);
1090 /* no need to write if no events */
1091 if (!(c->poll_entry->revents & POLLOUT))
1093 len = send(c->fd, c->packet_buffer_ptr,
1094 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1096 if (ff_neterrno() != AVERROR(EAGAIN) &&
1097 ff_neterrno() != AVERROR(EINTR)) {
1098 /* error : close connection */
1099 av_freep(&c->packet_buffer);
1103 c->packet_buffer_ptr += len;
1104 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1105 /* all the buffer was sent : wait for a new request */
1106 av_freep(&c->packet_buffer);
1107 c->state = RTSPSTATE_WAIT_REQUEST;
1111 case HTTPSTATE_READY:
1120 static int extract_rates(char *rates, int ratelen, const char *request)
1124 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1125 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1126 const char *q = p + 7;
1128 while (*q && *q != '\n' && av_isspace(*q))
1131 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1137 memset(rates, 0xff, ratelen);
1140 while (*q && *q != '\n' && *q != ':')
1143 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1147 if (stream_no < ratelen && stream_no >= 0)
1148 rates[stream_no] = rate_no;
1150 while (*q && *q != '\n' && !av_isspace(*q))
1157 p = strchr(p, '\n');
1167 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1170 int best_bitrate = 100000000;
1173 for (i = 0; i < feed->nb_streams; i++) {
1174 AVCodecContext *feed_codec = feed->streams[i]->codec;
1176 if (feed_codec->codec_id != codec->codec_id ||
1177 feed_codec->sample_rate != codec->sample_rate ||
1178 feed_codec->width != codec->width ||
1179 feed_codec->height != codec->height)
1182 /* Potential stream */
1184 /* We want the fastest stream less than bit_rate, or the slowest
1185 * faster than bit_rate
1188 if (feed_codec->bit_rate <= bit_rate) {
1189 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1190 best_bitrate = feed_codec->bit_rate;
1194 if (feed_codec->bit_rate < best_bitrate) {
1195 best_bitrate = feed_codec->bit_rate;
1204 static int modify_current_stream(HTTPContext *c, char *rates)
1207 FFStream *req = c->stream;
1208 int action_required = 0;
1210 /* Not much we can do for a feed */
1214 for (i = 0; i < req->nb_streams; i++) {
1215 AVCodecContext *codec = req->streams[i]->codec;
1219 c->switch_feed_streams[i] = req->feed_streams[i];
1222 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1225 /* Wants off or slow */
1226 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1228 /* This doesn't work well when it turns off the only stream! */
1229 c->switch_feed_streams[i] = -2;
1230 c->feed_streams[i] = -2;
1235 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1236 action_required = 1;
1239 return action_required;
1242 /* XXX: factorize in utils.c ? */
1243 /* XXX: take care with different space meaning */
1244 static void skip_spaces(const char **pp)
1248 while (*p == ' ' || *p == '\t')
1253 static void get_word(char *buf, int buf_size, const char **pp)
1261 while (!av_isspace(*p) && *p != '\0') {
1262 if ((q - buf) < buf_size - 1)
1271 static void get_arg(char *buf, int buf_size, const char **pp)
1278 while (av_isspace(*p)) p++;
1281 if (*p == '\"' || *p == '\'')
1293 if ((q - buf) < buf_size - 1)
1298 if (quote && *p == quote)
1303 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1304 const char *p, const char *filename, int line_num)
1310 get_arg(arg, sizeof(arg), &p);
1311 if (av_strcasecmp(arg, "allow") == 0)
1312 acl.action = IP_ALLOW;
1313 else if (av_strcasecmp(arg, "deny") == 0)
1314 acl.action = IP_DENY;
1316 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1317 filename, line_num, arg);
1321 get_arg(arg, sizeof(arg), &p);
1323 if (resolve_host(&acl.first, arg) != 0) {
1324 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1325 filename, line_num, arg);
1328 acl.last = acl.first;
1330 get_arg(arg, sizeof(arg), &p);
1333 if (resolve_host(&acl.last, arg) != 0) {
1334 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1335 filename, line_num, arg);
1341 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1342 IPAddressACL **naclp = 0;
1348 naclp = &stream->acl;
1354 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1355 filename, line_num);
1361 naclp = &(*naclp)->next;
1369 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1374 IPAddressACL *acl = NULL;
1378 f = fopen(stream->dynamic_acl, "r");
1380 perror(stream->dynamic_acl);
1384 acl = av_mallocz(sizeof(IPAddressACL));
1388 if (fgets(line, sizeof(line), f) == NULL)
1392 while (av_isspace(*p))
1394 if (*p == '\0' || *p == '#')
1396 get_arg(cmd, sizeof(cmd), &p);
1398 if (!av_strcasecmp(cmd, "ACL"))
1399 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1406 static void free_acl_list(IPAddressACL *in_acl)
1408 IPAddressACL *pacl,*pacl2;
1418 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1420 enum IPAddressAction last_action = IP_DENY;
1422 struct in_addr *src = &c->from_addr.sin_addr;
1423 unsigned long src_addr = src->s_addr;
1425 for (acl = in_acl; acl; acl = acl->next) {
1426 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1427 return (acl->action == IP_ALLOW) ? 1 : 0;
1428 last_action = acl->action;
1431 /* Nothing matched, so return not the last action */
1432 return (last_action == IP_DENY) ? 1 : 0;
1435 static int validate_acl(FFStream *stream, HTTPContext *c)
1441 /* if stream->acl is null validate_acl_list will return 1 */
1442 ret = validate_acl_list(stream->acl, c);
1444 if (stream->dynamic_acl[0]) {
1445 acl = parse_dynamic_acl(stream, c);
1447 ret = validate_acl_list(acl, c);
1455 /* compute the real filename of a file by matching it without its
1456 extensions to all the stream filenames */
1457 static void compute_real_filename(char *filename, int max_size)
1464 /* compute filename by matching without the file extensions */
1465 av_strlcpy(file1, filename, sizeof(file1));
1466 p = strrchr(file1, '.');
1469 for(stream = first_stream; stream != NULL; stream = stream->next) {
1470 av_strlcpy(file2, stream->filename, sizeof(file2));
1471 p = strrchr(file2, '.');
1474 if (!strcmp(file1, file2)) {
1475 av_strlcpy(filename, stream->filename, max_size);
1490 /* parse http request and prepare header */
1491 static int http_parse_request(HTTPContext *c)
1495 enum RedirType redir_type;
1497 char info[1024], filename[1024];
1501 const char *mime_type;
1505 const char *useragent = 0;
1508 get_word(cmd, sizeof(cmd), &p);
1509 av_strlcpy(c->method, cmd, sizeof(c->method));
1511 if (!strcmp(cmd, "GET"))
1513 else if (!strcmp(cmd, "POST"))
1518 get_word(url, sizeof(url), &p);
1519 av_strlcpy(c->url, url, sizeof(c->url));
1521 get_word(protocol, sizeof(protocol), (const char **)&p);
1522 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1525 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1528 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1530 /* find the filename and the optional info string in the request */
1531 p1 = strchr(url, '?');
1533 av_strlcpy(info, p1, sizeof(info));
1538 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1540 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1541 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1543 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1547 p = strchr(p, '\n');
1554 redir_type = REDIR_NONE;
1555 if (av_match_ext(filename, "asx")) {
1556 redir_type = REDIR_ASX;
1557 filename[strlen(filename)-1] = 'f';
1558 } else if (av_match_ext(filename, "asf") &&
1559 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1560 /* if this isn't WMP or lookalike, return the redirector file */
1561 redir_type = REDIR_ASF;
1562 } else if (av_match_ext(filename, "rpm,ram")) {
1563 redir_type = REDIR_RAM;
1564 strcpy(filename + strlen(filename)-2, "m");
1565 } else if (av_match_ext(filename, "rtsp")) {
1566 redir_type = REDIR_RTSP;
1567 compute_real_filename(filename, sizeof(filename) - 1);
1568 } else if (av_match_ext(filename, "sdp")) {
1569 redir_type = REDIR_SDP;
1570 compute_real_filename(filename, sizeof(filename) - 1);
1573 // "redirect" / request to index.html
1574 if (!strlen(filename))
1575 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1577 stream = first_stream;
1578 while (stream != NULL) {
1579 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1581 stream = stream->next;
1583 if (stream == NULL) {
1584 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1585 http_log("File '%s' not found\n", url);
1590 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1591 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1593 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1594 c->http_error = 301;
1596 snprintf(q, c->buffer_size,
1597 "HTTP/1.0 301 Moved\r\n"
1599 "Content-type: text/html\r\n"
1601 "<html><head><title>Moved</title></head><body>\r\n"
1602 "You should be <a href=\"%s\">redirected</a>.\r\n"
1603 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1605 /* prepare output buffer */
1606 c->buffer_ptr = c->buffer;
1608 c->state = HTTPSTATE_SEND_HEADER;
1612 /* If this is WMP, get the rate information */
1613 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1614 if (modify_current_stream(c, ratebuf)) {
1615 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1616 if (c->switch_feed_streams[i] >= 0)
1617 c->switch_feed_streams[i] = -1;
1622 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1623 current_bandwidth += stream->bandwidth;
1625 /* If already streaming this feed, do not let start another feeder. */
1626 if (stream->feed_opened) {
1627 snprintf(msg, sizeof(msg), "This feed is already being received.");
1628 http_log("Feed '%s' already being received\n", stream->feed_filename);
1632 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1633 c->http_error = 503;
1635 snprintf(q, c->buffer_size,
1636 "HTTP/1.0 503 Server too busy\r\n"
1637 "Content-type: text/html\r\n"
1639 "<html><head><title>Too busy</title></head><body>\r\n"
1640 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1641 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1642 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1643 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1645 /* prepare output buffer */
1646 c->buffer_ptr = c->buffer;
1648 c->state = HTTPSTATE_SEND_HEADER;
1652 if (redir_type != REDIR_NONE) {
1653 const char *hostinfo = 0;
1655 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1656 if (av_strncasecmp(p, "Host:", 5) == 0) {
1660 p = strchr(p, '\n');
1671 while (av_isspace(*hostinfo))
1674 eoh = strchr(hostinfo, '\n');
1676 if (eoh[-1] == '\r')
1679 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1680 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1681 hostbuf[eoh - hostinfo] = 0;
1683 c->http_error = 200;
1685 switch(redir_type) {
1687 snprintf(q, c->buffer_size,
1688 "HTTP/1.0 200 ASX Follows\r\n"
1689 "Content-type: video/x-ms-asf\r\n"
1691 "<ASX Version=\"3\">\r\n"
1692 //"<!-- Autogenerated by ffserver -->\r\n"
1693 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1694 "</ASX>\r\n", hostbuf, filename, info);
1698 snprintf(q, c->buffer_size,
1699 "HTTP/1.0 200 RAM Follows\r\n"
1700 "Content-type: audio/x-pn-realaudio\r\n"
1702 "# Autogenerated by ffserver\r\n"
1703 "http://%s/%s%s\r\n", hostbuf, filename, info);
1707 snprintf(q, c->buffer_size,
1708 "HTTP/1.0 200 ASF Redirect follows\r\n"
1709 "Content-type: video/x-ms-asf\r\n"
1712 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1717 char hostname[256], *p;
1718 /* extract only hostname */
1719 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1720 p = strrchr(hostname, ':');
1723 snprintf(q, c->buffer_size,
1724 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1725 /* XXX: incorrect mime type ? */
1726 "Content-type: application/x-rtsp\r\n"
1728 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1737 struct sockaddr_in my_addr;
1739 snprintf(q, c->buffer_size,
1740 "HTTP/1.0 200 OK\r\n"
1741 "Content-type: application/sdp\r\n"
1745 len = sizeof(my_addr);
1746 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1748 /* XXX: should use a dynamic buffer */
1749 sdp_data_size = prepare_sdp_description(stream,
1752 if (sdp_data_size > 0) {
1753 memcpy(q, sdp_data, sdp_data_size);
1765 /* prepare output buffer */
1766 c->buffer_ptr = c->buffer;
1768 c->state = HTTPSTATE_SEND_HEADER;
1774 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1778 stream->conns_served++;
1780 /* XXX: add there authenticate and IP match */
1783 /* if post, it means a feed is being sent */
1784 if (!stream->is_feed) {
1785 /* However it might be a status report from WMP! Let us log the
1786 * data as it might come in handy one day. */
1787 const char *logline = 0;
1790 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1791 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1795 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1796 client_id = strtol(p + 18, 0, 10);
1797 p = strchr(p, '\n');
1805 char *eol = strchr(logline, '\n');
1810 if (eol[-1] == '\r')
1812 http_log("%.*s\n", (int) (eol - logline), logline);
1813 c->suppress_log = 1;
1818 http_log("\nGot request:\n%s\n", c->buffer);
1821 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1824 /* Now we have to find the client_id */
1825 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1826 if (wmpc->wmp_client_id == client_id)
1830 if (wmpc && modify_current_stream(wmpc, ratebuf))
1831 wmpc->switch_pending = 1;
1834 snprintf(msg, sizeof(msg), "POST command not handled");
1838 if (http_start_receive_data(c) < 0) {
1839 snprintf(msg, sizeof(msg), "could not open feed");
1843 c->state = HTTPSTATE_RECEIVE_DATA;
1848 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1849 http_log("\nGot request:\n%s\n", c->buffer);
1852 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1855 /* open input stream */
1856 if (open_input_stream(c, info) < 0) {
1857 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1861 /* prepare http header */
1863 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1864 mime_type = c->stream->fmt->mime_type;
1866 mime_type = "application/x-octet-stream";
1867 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1869 /* for asf, we need extra headers */
1870 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1871 /* Need to allocate a client id */
1873 c->wmp_client_id = av_lfg_get(&random_state);
1875 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);
1877 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1878 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1879 q = c->buffer + strlen(c->buffer);
1881 /* prepare output buffer */
1883 c->buffer_ptr = c->buffer;
1885 c->state = HTTPSTATE_SEND_HEADER;
1888 c->http_error = 404;
1890 snprintf(q, c->buffer_size,
1891 "HTTP/1.0 404 Not Found\r\n"
1892 "Content-type: text/html\r\n"
1895 "<head><title>404 Not Found</title></head>\n"
1899 /* prepare output buffer */
1900 c->buffer_ptr = c->buffer;
1902 c->state = HTTPSTATE_SEND_HEADER;
1906 c->http_error = 200; /* horrible : we use this value to avoid
1907 going to the send data state */
1908 c->state = HTTPSTATE_SEND_HEADER;
1912 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1914 static const char suffix[] = " kMGTP";
1917 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1919 avio_printf(pb, "%"PRId64"%c", count, *s);
1922 static void compute_status(HTTPContext *c)
1931 if (avio_open_dyn_buf(&pb) < 0) {
1932 /* XXX: return an error ? */
1933 c->buffer_ptr = c->buffer;
1934 c->buffer_end = c->buffer;
1938 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1939 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1940 avio_printf(pb, "Pragma: no-cache\r\n");
1941 avio_printf(pb, "\r\n");
1943 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1944 if (c->stream->feed_filename[0])
1945 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1946 avio_printf(pb, "</head>\n<body>");
1947 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1949 avio_printf(pb, "<h2>Available Streams</h2>\n");
1950 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1951 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");
1952 stream = first_stream;
1953 while (stream != NULL) {
1954 char sfilename[1024];
1957 if (stream->feed != stream) {
1958 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1959 eosf = sfilename + strlen(sfilename);
1960 if (eosf - sfilename >= 4) {
1961 if (strcmp(eosf - 4, ".asf") == 0)
1962 strcpy(eosf - 4, ".asx");
1963 else if (strcmp(eosf - 3, ".rm") == 0)
1964 strcpy(eosf - 3, ".ram");
1965 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1966 /* generate a sample RTSP director if
1967 unicast. Generate an SDP redirector if
1969 eosf = strrchr(sfilename, '.');
1971 eosf = sfilename + strlen(sfilename);
1972 if (stream->is_multicast)
1973 strcpy(eosf, ".sdp");
1975 strcpy(eosf, ".rtsp");
1979 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1980 sfilename, stream->filename);
1981 avio_printf(pb, "<td align=right> %d <td align=right> ",
1982 stream->conns_served);
1983 fmt_bytecount(pb, stream->bytes_served);
1984 switch(stream->stream_type) {
1985 case STREAM_TYPE_LIVE: {
1986 int audio_bit_rate = 0;
1987 int video_bit_rate = 0;
1988 const char *audio_codec_name = "";
1989 const char *video_codec_name = "";
1990 const char *audio_codec_name_extra = "";
1991 const char *video_codec_name_extra = "";
1993 for(i=0;i<stream->nb_streams;i++) {
1994 AVStream *st = stream->streams[i];
1995 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1996 switch(st->codec->codec_type) {
1997 case AVMEDIA_TYPE_AUDIO:
1998 audio_bit_rate += st->codec->bit_rate;
2000 if (*audio_codec_name)
2001 audio_codec_name_extra = "...";
2002 audio_codec_name = codec->name;
2005 case AVMEDIA_TYPE_VIDEO:
2006 video_bit_rate += st->codec->bit_rate;
2008 if (*video_codec_name)
2009 video_codec_name_extra = "...";
2010 video_codec_name = codec->name;
2013 case AVMEDIA_TYPE_DATA:
2014 video_bit_rate += st->codec->bit_rate;
2020 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",
2023 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2024 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2026 avio_printf(pb, "<td>%s", stream->feed->filename);
2028 avio_printf(pb, "<td>%s", stream->feed_filename);
2029 avio_printf(pb, "\n");
2033 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2037 stream = stream->next;
2039 avio_printf(pb, "</table>\n");
2041 stream = first_stream;
2042 while (stream != NULL) {
2043 if (stream->feed == stream) {
2044 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2046 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2053 /* This is somewhat linux specific I guess */
2054 snprintf(ps_cmd, sizeof(ps_cmd),
2055 "ps -o \"%%cpu,cputime\" --no-headers %d",
2058 pid_stat = popen(ps_cmd, "r");
2063 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2065 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2073 avio_printf(pb, "<p>");
2075 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");
2077 for (i = 0; i < stream->nb_streams; i++) {
2078 AVStream *st = stream->streams[i];
2079 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2080 const char *type = "unknown";
2081 char parameters[64];
2085 switch(st->codec->codec_type) {
2086 case AVMEDIA_TYPE_AUDIO:
2088 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2090 case AVMEDIA_TYPE_VIDEO:
2092 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2093 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2098 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2099 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2101 avio_printf(pb, "</table>\n");
2104 stream = stream->next;
2107 /* connection status */
2108 avio_printf(pb, "<h2>Connection Status</h2>\n");
2110 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2111 nb_connections, nb_max_connections);
2113 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2114 current_bandwidth, max_bandwidth);
2116 avio_printf(pb, "<table>\n");
2117 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");
2118 c1 = first_http_ctx;
2120 while (c1 != NULL) {
2126 for (j = 0; j < c1->stream->nb_streams; j++) {
2127 if (!c1->stream->feed)
2128 bitrate += c1->stream->streams[j]->codec->bit_rate;
2129 else if (c1->feed_streams[j] >= 0)
2130 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2135 p = inet_ntoa(c1->from_addr.sin_addr);
2136 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2138 c1->stream ? c1->stream->filename : "",
2139 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2142 http_state[c1->state]);
2143 fmt_bytecount(pb, bitrate);
2144 avio_printf(pb, "<td align=right>");
2145 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2146 avio_printf(pb, "<td align=right>");
2147 fmt_bytecount(pb, c1->data_count);
2148 avio_printf(pb, "\n");
2151 avio_printf(pb, "</table>\n");
2156 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2157 avio_printf(pb, "</body>\n</html>\n");
2159 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2160 c->buffer_ptr = c->pb_buffer;
2161 c->buffer_end = c->pb_buffer + len;
2164 static int open_input_stream(HTTPContext *c, const char *info)
2167 char input_filename[1024];
2168 AVFormatContext *s = NULL;
2169 int buf_size, i, ret;
2172 /* find file name */
2173 if (c->stream->feed) {
2174 strcpy(input_filename, c->stream->feed->feed_filename);
2175 buf_size = FFM_PACKET_SIZE;
2176 /* compute position (absolute time) */
2177 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2178 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2180 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2181 int prebuffer = strtol(buf, 0, 10);
2182 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2184 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2186 strcpy(input_filename, c->stream->feed_filename);
2188 /* compute position (relative time) */
2189 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2190 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2195 if (input_filename[0] == '\0')
2199 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2200 http_log("could not open %s: %d\n", input_filename, ret);
2204 /* set buffer size */
2205 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2207 s->flags |= AVFMT_FLAG_GENPTS;
2209 if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
2210 http_log("Could not find stream info '%s'\n", input_filename);
2211 avformat_close_input(&s);
2215 /* choose stream as clock source (we favorize video stream if
2216 present) for packet sending */
2217 c->pts_stream_index = 0;
2218 for(i=0;i<c->stream->nb_streams;i++) {
2219 if (c->pts_stream_index == 0 &&
2220 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2221 c->pts_stream_index = i;
2225 if (c->fmt_in->iformat->read_seek)
2226 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2227 /* set the start time (needed for maxtime and RTP packet timing) */
2228 c->start_time = cur_time;
2229 c->first_pts = AV_NOPTS_VALUE;
2233 /* return the server clock (in us) */
2234 static int64_t get_server_clock(HTTPContext *c)
2236 /* compute current pts value from system time */
2237 return (cur_time - c->start_time) * 1000;
2240 /* return the estimated time at which the current packet must be sent
2242 static int64_t get_packet_send_clock(HTTPContext *c)
2244 int bytes_left, bytes_sent, frame_bytes;
2246 frame_bytes = c->cur_frame_bytes;
2247 if (frame_bytes <= 0)
2250 bytes_left = c->buffer_end - c->buffer_ptr;
2251 bytes_sent = frame_bytes - bytes_left;
2252 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2257 static int http_prepare_data(HTTPContext *c)
2260 AVFormatContext *ctx;
2262 av_freep(&c->pb_buffer);
2264 case HTTPSTATE_SEND_DATA_HEADER:
2265 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2266 av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2267 av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2268 av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2269 av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2271 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2273 for(i=0;i<c->stream->nb_streams;i++) {
2275 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2276 /* if file or feed, then just take streams from FFStream struct */
2277 if (!c->stream->feed ||
2278 c->stream->feed == c->stream)
2279 src = c->stream->streams[i];
2281 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2283 *(c->fmt_ctx.streams[i]) = *src;
2284 c->fmt_ctx.streams[i]->priv_data = 0;
2285 c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2286 AVStream, not in codec */
2288 /* set output format parameters */
2289 c->fmt_ctx.oformat = c->stream->fmt;
2290 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2292 c->got_key_frame = 0;
2294 /* prepare header and save header data in a stream */
2295 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2296 /* XXX: potential leak */
2299 c->fmt_ctx.pb->seekable = 0;
2302 * HACK to avoid mpeg ps muxer to spit many underflow errors
2303 * Default value from FFmpeg
2304 * Try to set it use configuration option
2306 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2308 if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2309 http_log("Error writing output header\n");
2312 av_dict_free(&c->fmt_ctx.metadata);
2314 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2315 c->buffer_ptr = c->pb_buffer;
2316 c->buffer_end = c->pb_buffer + len;
2318 c->state = HTTPSTATE_SEND_DATA;
2319 c->last_packet_sent = 0;
2321 case HTTPSTATE_SEND_DATA:
2322 /* find a new packet */
2323 /* read a packet from the input stream */
2324 if (c->stream->feed)
2325 ffm_set_write_index(c->fmt_in,
2326 c->stream->feed->feed_write_index,
2327 c->stream->feed->feed_size);
2329 if (c->stream->max_time &&
2330 c->stream->max_time + c->start_time - cur_time < 0)
2331 /* We have timed out */
2332 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2336 ret = av_read_frame(c->fmt_in, &pkt);
2338 if (c->stream->feed) {
2339 /* if coming from feed, it means we reached the end of the
2340 ffm file, so must wait for more data */
2341 c->state = HTTPSTATE_WAIT_FEED;
2342 return 1; /* state changed */
2343 } else if (ret == AVERROR(EAGAIN)) {
2344 /* input not ready, come back later */
2347 if (c->stream->loop) {
2348 avformat_close_input(&c->fmt_in);
2349 if (open_input_stream(c, "") < 0)
2354 /* must send trailer now because eof or error */
2355 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2359 int source_index = pkt.stream_index;
2360 /* update first pts if needed */
2361 if (c->first_pts == AV_NOPTS_VALUE) {
2362 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2363 c->start_time = cur_time;
2365 /* send it to the appropriate stream */
2366 if (c->stream->feed) {
2367 /* if coming from a feed, select the right stream */
2368 if (c->switch_pending) {
2369 c->switch_pending = 0;
2370 for(i=0;i<c->stream->nb_streams;i++) {
2371 if (c->switch_feed_streams[i] == pkt.stream_index)
2372 if (pkt.flags & AV_PKT_FLAG_KEY)
2373 c->switch_feed_streams[i] = -1;
2374 if (c->switch_feed_streams[i] >= 0)
2375 c->switch_pending = 1;
2378 for(i=0;i<c->stream->nb_streams;i++) {
2379 if (c->stream->feed_streams[i] == pkt.stream_index) {
2380 AVStream *st = c->fmt_in->streams[source_index];
2381 pkt.stream_index = i;
2382 if (pkt.flags & AV_PKT_FLAG_KEY &&
2383 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2384 c->stream->nb_streams == 1))
2385 c->got_key_frame = 1;
2386 if (!c->stream->send_on_key || c->got_key_frame)
2391 AVCodecContext *codec;
2392 AVStream *ist, *ost;
2394 ist = c->fmt_in->streams[source_index];
2395 /* specific handling for RTP: we use several
2396 output stream (one for each RTP
2397 connection). XXX: need more abstract handling */
2398 if (c->is_packetized) {
2399 /* compute send time and duration */
2400 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2401 c->cur_pts -= c->first_pts;
2402 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2403 /* find RTP context */
2404 c->packet_stream_index = pkt.stream_index;
2405 ctx = c->rtp_ctx[c->packet_stream_index];
2407 av_free_packet(&pkt);
2410 codec = ctx->streams[0]->codec;
2411 /* only one stream per RTP connection */
2412 pkt.stream_index = 0;
2416 codec = ctx->streams[pkt.stream_index]->codec;
2419 if (c->is_packetized) {
2420 int max_packet_size;
2421 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2422 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2424 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2425 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2427 ret = avio_open_dyn_buf(&ctx->pb);
2430 /* XXX: potential leak */
2433 ost = ctx->streams[pkt.stream_index];
2435 ctx->pb->seekable = 0;
2436 if (pkt.dts != AV_NOPTS_VALUE)
2437 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2438 if (pkt.pts != AV_NOPTS_VALUE)
2439 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2440 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2441 if (av_write_frame(ctx, &pkt) < 0) {
2442 http_log("Error writing frame to output\n");
2443 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2446 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2447 c->cur_frame_bytes = len;
2448 c->buffer_ptr = c->pb_buffer;
2449 c->buffer_end = c->pb_buffer + len;
2451 codec->frame_number++;
2453 av_free_packet(&pkt);
2457 av_free_packet(&pkt);
2462 case HTTPSTATE_SEND_DATA_TRAILER:
2463 /* last packet test ? */
2464 if (c->last_packet_sent || c->is_packetized)
2467 /* prepare header */
2468 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2469 /* XXX: potential leak */
2472 c->fmt_ctx.pb->seekable = 0;
2473 av_write_trailer(ctx);
2474 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2475 c->buffer_ptr = c->pb_buffer;
2476 c->buffer_end = c->pb_buffer + len;
2478 c->last_packet_sent = 1;
2484 /* should convert the format at the same time */
2485 /* send data starting at c->buffer_ptr to the output connection
2486 (either UDP or TCP connection) */
2487 static int http_send_data(HTTPContext *c)
2492 if (c->buffer_ptr >= c->buffer_end) {
2493 ret = http_prepare_data(c);
2497 /* state change requested */
2500 if (c->is_packetized) {
2501 /* RTP data output */
2502 len = c->buffer_end - c->buffer_ptr;
2504 /* fail safe - should never happen */
2506 c->buffer_ptr = c->buffer_end;
2509 len = (c->buffer_ptr[0] << 24) |
2510 (c->buffer_ptr[1] << 16) |
2511 (c->buffer_ptr[2] << 8) |
2513 if (len > (c->buffer_end - c->buffer_ptr))
2515 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2516 /* nothing to send yet: we can wait */
2520 c->data_count += len;
2521 update_datarate(&c->datarate, c->data_count);
2523 c->stream->bytes_served += len;
2525 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2526 /* RTP packets are sent inside the RTSP TCP connection */
2528 int interleaved_index, size;
2530 HTTPContext *rtsp_c;
2533 /* if no RTSP connection left, error */
2536 /* if already sending something, then wait. */
2537 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2539 if (avio_open_dyn_buf(&pb) < 0)
2541 interleaved_index = c->packet_stream_index * 2;
2542 /* RTCP packets are sent at odd indexes */
2543 if (c->buffer_ptr[1] == 200)
2544 interleaved_index++;
2545 /* write RTSP TCP header */
2547 header[1] = interleaved_index;
2548 header[2] = len >> 8;
2550 avio_write(pb, header, 4);
2551 /* write RTP packet data */
2553 avio_write(pb, c->buffer_ptr, len);
2554 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2555 /* prepare asynchronous TCP sending */
2556 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2557 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2558 c->buffer_ptr += len;
2560 /* send everything we can NOW */
2561 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2562 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2564 rtsp_c->packet_buffer_ptr += len;
2565 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2566 /* if we could not send all the data, we will
2567 send it later, so a new state is needed to
2568 "lock" the RTSP TCP connection */
2569 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2572 /* all data has been sent */
2573 av_freep(&c->packet_buffer);
2575 /* send RTP packet directly in UDP */
2577 ffurl_write(c->rtp_handles[c->packet_stream_index],
2578 c->buffer_ptr, len);
2579 c->buffer_ptr += len;
2580 /* here we continue as we can send several packets per 10 ms slot */
2583 /* TCP data output */
2584 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2586 if (ff_neterrno() != AVERROR(EAGAIN) &&
2587 ff_neterrno() != AVERROR(EINTR))
2588 /* error : close connection */
2593 c->buffer_ptr += len;
2595 c->data_count += len;
2596 update_datarate(&c->datarate, c->data_count);
2598 c->stream->bytes_served += len;
2606 static int http_start_receive_data(HTTPContext *c)
2610 if (c->stream->feed_opened)
2613 /* Don't permit writing to this one */
2614 if (c->stream->readonly)
2618 fd = open(c->stream->feed_filename, O_RDWR);
2620 http_log("Error opening feeder file: %s\n", strerror(errno));
2625 if (c->stream->truncate) {
2626 /* truncate feed file */
2627 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2628 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2629 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2630 http_log("Error truncating feed file: %s\n", strerror(errno));
2634 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2635 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2640 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2641 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2642 lseek(fd, 0, SEEK_SET);
2644 /* init buffer input */
2645 c->buffer_ptr = c->buffer;
2646 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2647 c->stream->feed_opened = 1;
2648 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2652 static int http_receive_data(HTTPContext *c)
2655 int len, loop_run = 0;
2657 while (c->chunked_encoding && !c->chunk_size &&
2658 c->buffer_end > c->buffer_ptr) {
2659 /* read chunk header, if present */
2660 len = recv(c->fd, c->buffer_ptr, 1, 0);
2663 if (ff_neterrno() != AVERROR(EAGAIN) &&
2664 ff_neterrno() != AVERROR(EINTR))
2665 /* error : close connection */
2668 } else if (len == 0) {
2669 /* end of connection : close it */
2671 } else if (c->buffer_ptr - c->buffer >= 2 &&
2672 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2673 c->chunk_size = strtol(c->buffer, 0, 16);
2674 if (c->chunk_size == 0) // end of stream
2676 c->buffer_ptr = c->buffer;
2678 } else if (++loop_run > 10) {
2679 /* no chunk header, abort */
2686 if (c->buffer_end > c->buffer_ptr) {
2687 len = recv(c->fd, c->buffer_ptr,
2688 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2690 if (ff_neterrno() != AVERROR(EAGAIN) &&
2691 ff_neterrno() != AVERROR(EINTR))
2692 /* error : close connection */
2694 } else if (len == 0)
2695 /* end of connection : close it */
2698 c->chunk_size -= len;
2699 c->buffer_ptr += len;
2700 c->data_count += len;
2701 update_datarate(&c->datarate, c->data_count);
2705 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2706 if (c->buffer[0] != 'f' ||
2707 c->buffer[1] != 'm') {
2708 http_log("Feed stream has become desynchronized -- disconnecting\n");
2713 if (c->buffer_ptr >= c->buffer_end) {
2714 FFStream *feed = c->stream;
2715 /* a packet has been received : write it in the store, except
2717 if (c->data_count > FFM_PACKET_SIZE) {
2718 /* XXX: use llseek or url_seek */
2719 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2720 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2721 http_log("Error writing to feed file: %s\n", strerror(errno));
2725 feed->feed_write_index += FFM_PACKET_SIZE;
2726 /* update file size */
2727 if (feed->feed_write_index > c->stream->feed_size)
2728 feed->feed_size = feed->feed_write_index;
2730 /* handle wrap around if max file size reached */
2731 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2732 feed->feed_write_index = FFM_PACKET_SIZE;
2735 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2736 http_log("Error writing index to feed file: %s\n", strerror(errno));
2740 /* wake up any waiting connections */
2741 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2742 if (c1->state == HTTPSTATE_WAIT_FEED &&
2743 c1->stream->feed == c->stream->feed)
2744 c1->state = HTTPSTATE_SEND_DATA;
2747 /* We have a header in our hands that contains useful data */
2748 AVFormatContext *s = avformat_alloc_context();
2750 AVInputFormat *fmt_in;
2756 /* use feed output format name to find corresponding input format */
2757 fmt_in = av_find_input_format(feed->fmt->name);
2761 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2762 0, NULL, NULL, NULL, NULL);
2766 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2771 /* Now we have the actual streams */
2772 if (s->nb_streams != feed->nb_streams) {
2773 avformat_close_input(&s);
2775 http_log("Feed '%s' stream number does not match registered feed\n",
2776 c->stream->feed_filename);
2780 for (i = 0; i < s->nb_streams; i++) {
2781 AVStream *fst = feed->streams[i];
2782 AVStream *st = s->streams[i];
2783 avcodec_copy_context(fst->codec, st->codec);
2786 avformat_close_input(&s);
2789 c->buffer_ptr = c->buffer;
2794 c->stream->feed_opened = 0;
2796 /* wake up any waiting connections to stop waiting for feed */
2797 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2798 if (c1->state == HTTPSTATE_WAIT_FEED &&
2799 c1->stream->feed == c->stream->feed)
2800 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2805 /********************************************************************/
2808 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2815 switch(error_number) {
2816 case RTSP_STATUS_OK:
2819 case RTSP_STATUS_METHOD:
2820 str = "Method Not Allowed";
2822 case RTSP_STATUS_BANDWIDTH:
2823 str = "Not Enough Bandwidth";
2825 case RTSP_STATUS_SESSION:
2826 str = "Session Not Found";
2828 case RTSP_STATUS_STATE:
2829 str = "Method Not Valid in This State";
2831 case RTSP_STATUS_AGGREGATE:
2832 str = "Aggregate operation not allowed";
2834 case RTSP_STATUS_ONLY_AGGREGATE:
2835 str = "Only aggregate operation allowed";
2837 case RTSP_STATUS_TRANSPORT:
2838 str = "Unsupported transport";
2840 case RTSP_STATUS_INTERNAL:
2841 str = "Internal Server Error";
2843 case RTSP_STATUS_SERVICE:
2844 str = "Service Unavailable";
2846 case RTSP_STATUS_VERSION:
2847 str = "RTSP Version not supported";
2850 str = "Unknown Error";
2854 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2855 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2857 /* output GMT time */
2860 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2861 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2864 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2866 rtsp_reply_header(c, error_number);
2867 avio_printf(c->pb, "\r\n");
2870 static int rtsp_parse_request(HTTPContext *c)
2872 const char *p, *p1, *p2;
2878 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2880 c->buffer_ptr[0] = '\0';
2883 get_word(cmd, sizeof(cmd), &p);
2884 get_word(url, sizeof(url), &p);
2885 get_word(protocol, sizeof(protocol), &p);
2887 av_strlcpy(c->method, cmd, sizeof(c->method));
2888 av_strlcpy(c->url, url, sizeof(c->url));
2889 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2891 if (avio_open_dyn_buf(&c->pb) < 0) {
2892 /* XXX: cannot do more */
2893 c->pb = NULL; /* safety */
2897 /* check version name */
2898 if (strcmp(protocol, "RTSP/1.0") != 0) {
2899 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2903 /* parse each header line */
2904 /* skip to next line */
2905 while (*p != '\n' && *p != '\0')
2909 while (*p != '\0') {
2910 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2914 if (p2 > p && p2[-1] == '\r')
2916 /* skip empty line */
2920 if (len > sizeof(line) - 1)
2921 len = sizeof(line) - 1;
2922 memcpy(line, p, len);
2924 ff_rtsp_parse_line(header, line, NULL, NULL);
2928 /* handle sequence number */
2929 c->seq = header->seq;
2931 if (!strcmp(cmd, "DESCRIBE"))
2932 rtsp_cmd_describe(c, url);
2933 else if (!strcmp(cmd, "OPTIONS"))
2934 rtsp_cmd_options(c, url);
2935 else if (!strcmp(cmd, "SETUP"))
2936 rtsp_cmd_setup(c, url, header);
2937 else if (!strcmp(cmd, "PLAY"))
2938 rtsp_cmd_play(c, url, header);
2939 else if (!strcmp(cmd, "PAUSE"))
2940 rtsp_cmd_pause(c, url, header);
2941 else if (!strcmp(cmd, "TEARDOWN"))
2942 rtsp_cmd_teardown(c, url, header);
2944 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2947 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2948 c->pb = NULL; /* safety */
2950 /* XXX: cannot do more */
2953 c->buffer_ptr = c->pb_buffer;
2954 c->buffer_end = c->pb_buffer + len;
2955 c->state = RTSPSTATE_SEND_REPLY;
2959 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2960 struct in_addr my_ip)
2962 AVFormatContext *avc;
2963 AVStream *avs = NULL;
2964 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2967 avc = avformat_alloc_context();
2968 if (avc == NULL || !rtp_format) {
2971 avc->oformat = rtp_format;
2972 av_dict_set(&avc->metadata, "title",
2973 stream->title[0] ? stream->title : "No Title", 0);
2974 avc->nb_streams = stream->nb_streams;
2975 if (stream->is_multicast) {
2976 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2977 inet_ntoa(stream->multicast_ip),
2978 stream->multicast_port, stream->multicast_ttl);
2980 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2983 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2984 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2986 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2987 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2990 for(i = 0; i < stream->nb_streams; i++) {
2991 avc->streams[i] = &avs[i];
2992 avc->streams[i]->codec = stream->streams[i]->codec;
2994 *pbuffer = av_mallocz(2048);
2995 av_sdp_create(&avc, 1, *pbuffer, 2048);
2998 av_free(avc->streams);
2999 av_dict_free(&avc->metadata);
3003 return strlen(*pbuffer);
3006 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3008 // rtsp_reply_header(c, RTSP_STATUS_OK);
3009 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3010 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3011 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3012 avio_printf(c->pb, "\r\n");
3015 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3023 struct sockaddr_in my_addr;
3025 /* find which url is asked */
3026 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3031 for(stream = first_stream; stream != NULL; stream = stream->next) {
3032 if (!stream->is_feed &&
3033 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3034 !strcmp(path, stream->filename)) {
3038 /* no stream found */
3039 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3043 /* prepare the media description in sdp format */
3045 /* get the host IP */
3046 len = sizeof(my_addr);
3047 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3048 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3049 if (content_length < 0) {
3050 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3053 rtsp_reply_header(c, RTSP_STATUS_OK);
3054 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3055 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3056 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3057 avio_printf(c->pb, "\r\n");
3058 avio_write(c->pb, content, content_length);
3062 static HTTPContext *find_rtp_session(const char *session_id)
3066 if (session_id[0] == '\0')
3069 for(c = first_http_ctx; c != NULL; c = c->next) {
3070 if (!strcmp(c->session_id, session_id))
3076 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3078 RTSPTransportField *th;
3081 for(i=0;i<h->nb_transports;i++) {
3082 th = &h->transports[i];
3083 if (th->lower_transport == lower_transport)
3089 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3090 RTSPMessageHeader *h)
3093 int stream_index, rtp_port, rtcp_port;
3098 RTSPTransportField *th;
3099 struct sockaddr_in dest_addr;
3100 RTSPActionServerSetup setup;
3102 /* find which url is asked */
3103 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3108 /* now check each stream */
3109 for(stream = first_stream; stream != NULL; stream = stream->next) {
3110 if (!stream->is_feed &&
3111 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3112 /* accept aggregate filenames only if single stream */
3113 if (!strcmp(path, stream->filename)) {
3114 if (stream->nb_streams != 1) {
3115 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3122 for(stream_index = 0; stream_index < stream->nb_streams;
3124 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3125 stream->filename, stream_index);
3126 if (!strcmp(path, buf))
3131 /* no stream found */
3132 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3136 /* generate session id if needed */
3137 if (h->session_id[0] == '\0') {
3138 unsigned random0 = av_lfg_get(&random_state);
3139 unsigned random1 = av_lfg_get(&random_state);
3140 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3144 /* find rtp session, and create it if none found */
3145 rtp_c = find_rtp_session(h->session_id);
3147 /* always prefer UDP */
3148 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3150 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3152 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3157 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3158 th->lower_transport);
3160 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3164 /* open input stream */
3165 if (open_input_stream(rtp_c, "") < 0) {
3166 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3171 /* test if stream is OK (test needed because several SETUP needs
3172 to be done for a given file) */
3173 if (rtp_c->stream != stream) {
3174 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3178 /* test if stream is already set up */
3179 if (rtp_c->rtp_ctx[stream_index]) {
3180 rtsp_reply_error(c, RTSP_STATUS_STATE);
3184 /* check transport */
3185 th = find_transport(h, rtp_c->rtp_protocol);
3186 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3187 th->client_port_min <= 0)) {
3188 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3192 /* setup default options */
3193 setup.transport_option[0] = '\0';
3194 dest_addr = rtp_c->from_addr;
3195 dest_addr.sin_port = htons(th->client_port_min);
3198 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3199 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3203 /* now everything is OK, so we can send the connection parameters */
3204 rtsp_reply_header(c, RTSP_STATUS_OK);
3206 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3208 switch(rtp_c->rtp_protocol) {
3209 case RTSP_LOWER_TRANSPORT_UDP:
3210 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3211 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3212 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3213 "client_port=%d-%d;server_port=%d-%d",
3214 th->client_port_min, th->client_port_max,
3215 rtp_port, rtcp_port);
3217 case RTSP_LOWER_TRANSPORT_TCP:
3218 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3219 stream_index * 2, stream_index * 2 + 1);
3224 if (setup.transport_option[0] != '\0')
3225 avio_printf(c->pb, ";%s", setup.transport_option);
3226 avio_printf(c->pb, "\r\n");
3229 avio_printf(c->pb, "\r\n");
3233 /* find an rtp connection by using the session ID. Check consistency
3235 static HTTPContext *find_rtp_session_with_url(const char *url,
3236 const char *session_id)
3244 rtp_c = find_rtp_session(session_id);
3248 /* find which url is asked */
3249 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3253 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3254 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3255 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3256 rtp_c->stream->filename, s);
3257 if(!strncmp(path, buf, sizeof(buf))) {
3258 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3263 if (len > 0 && path[len - 1] == '/' &&
3264 !strncmp(path, rtp_c->stream->filename, len - 1))
3269 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3273 rtp_c = find_rtp_session_with_url(url, h->session_id);
3275 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3279 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3280 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3281 rtp_c->state != HTTPSTATE_READY) {
3282 rtsp_reply_error(c, RTSP_STATUS_STATE);
3286 rtp_c->state = HTTPSTATE_SEND_DATA;
3288 /* now everything is OK, so we can send the connection parameters */
3289 rtsp_reply_header(c, RTSP_STATUS_OK);
3291 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3292 avio_printf(c->pb, "\r\n");
3295 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3299 rtp_c = find_rtp_session_with_url(url, h->session_id);
3301 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3305 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3306 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3307 rtsp_reply_error(c, RTSP_STATUS_STATE);
3311 rtp_c->state = HTTPSTATE_READY;
3312 rtp_c->first_pts = AV_NOPTS_VALUE;
3313 /* now everything is OK, so we can send the connection parameters */
3314 rtsp_reply_header(c, RTSP_STATUS_OK);
3316 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3317 avio_printf(c->pb, "\r\n");
3320 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3324 rtp_c = find_rtp_session_with_url(url, h->session_id);
3326 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3330 /* now everything is OK, so we can send the connection parameters */
3331 rtsp_reply_header(c, RTSP_STATUS_OK);
3333 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3334 avio_printf(c->pb, "\r\n");
3336 /* abort the session */
3337 close_connection(rtp_c);
3341 /********************************************************************/
3344 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3345 FFStream *stream, const char *session_id,
3346 enum RTSPLowerTransport rtp_protocol)
3348 HTTPContext *c = NULL;
3349 const char *proto_str;
3351 /* XXX: should output a warning page when coming
3352 close to the connection limit */
3353 if (nb_connections >= nb_max_connections)
3356 /* add a new connection */
3357 c = av_mallocz(sizeof(HTTPContext));
3362 c->poll_entry = NULL;
3363 c->from_addr = *from_addr;
3364 c->buffer_size = IOBUFFER_INIT_SIZE;
3365 c->buffer = av_malloc(c->buffer_size);
3370 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3371 c->state = HTTPSTATE_READY;
3372 c->is_packetized = 1;
3373 c->rtp_protocol = rtp_protocol;
3375 /* protocol is shown in statistics */
3376 switch(c->rtp_protocol) {
3377 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3378 proto_str = "MCAST";
3380 case RTSP_LOWER_TRANSPORT_UDP:
3383 case RTSP_LOWER_TRANSPORT_TCP:
3390 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3391 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3393 current_bandwidth += stream->bandwidth;
3395 c->next = first_http_ctx;
3407 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3408 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3410 static int rtp_new_av_stream(HTTPContext *c,
3411 int stream_index, struct sockaddr_in *dest_addr,
3412 HTTPContext *rtsp_c)
3414 AVFormatContext *ctx;
3417 URLContext *h = NULL;
3419 int max_packet_size;
3421 /* now we can open the relevant output stream */
3422 ctx = avformat_alloc_context();
3425 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3427 st = av_mallocz(sizeof(AVStream));
3430 ctx->nb_streams = 1;
3431 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3434 ctx->streams[0] = st;
3436 if (!c->stream->feed ||
3437 c->stream->feed == c->stream)
3438 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3441 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3443 st->priv_data = NULL;
3445 /* build destination RTP address */
3446 ipaddr = inet_ntoa(dest_addr->sin_addr);
3448 switch(c->rtp_protocol) {
3449 case RTSP_LOWER_TRANSPORT_UDP:
3450 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3453 /* XXX: also pass as parameter to function ? */
3454 if (c->stream->is_multicast) {
3456 ttl = c->stream->multicast_ttl;
3459 snprintf(ctx->filename, sizeof(ctx->filename),
3460 "rtp://%s:%d?multicast=1&ttl=%d",
3461 ipaddr, ntohs(dest_addr->sin_port), ttl);
3463 snprintf(ctx->filename, sizeof(ctx->filename),
3464 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3467 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3469 c->rtp_handles[stream_index] = h;
3470 max_packet_size = h->max_packet_size;
3472 case RTSP_LOWER_TRANSPORT_TCP:
3475 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3481 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3482 ipaddr, ntohs(dest_addr->sin_port),
3483 c->stream->filename, stream_index, c->protocol);
3485 /* normally, no packets should be output here, but the packet size may be checked */
3486 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3487 /* XXX: close stream */
3490 if (avformat_write_header(ctx, NULL) < 0) {
3497 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3500 c->rtp_ctx[stream_index] = ctx;
3504 /********************************************************************/
3505 /* ffserver initialization */
3507 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3511 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3514 fst = av_mallocz(sizeof(AVStream));
3518 fst->codec = avcodec_alloc_context3(NULL);
3519 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3520 if (codec->extradata_size) {
3521 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3522 memcpy(fst->codec->extradata, codec->extradata,
3523 codec->extradata_size);
3526 /* live streams must use the actual feed's codec since it may be
3527 * updated later to carry extradata needed by the streams.
3531 fst->priv_data = av_mallocz(sizeof(FeedData));
3532 fst->index = stream->nb_streams;
3533 avpriv_set_pts_info(fst, 33, 1, 90000);
3534 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3535 stream->streams[stream->nb_streams++] = fst;
3539 /* return the stream number in the feed */
3540 static int add_av_stream(FFStream *feed, AVStream *st)
3543 AVCodecContext *av, *av1;
3547 for(i=0;i<feed->nb_streams;i++) {
3548 st = feed->streams[i];
3550 if (av1->codec_id == av->codec_id &&
3551 av1->codec_type == av->codec_type &&
3552 av1->bit_rate == av->bit_rate) {
3554 switch(av->codec_type) {
3555 case AVMEDIA_TYPE_AUDIO:
3556 if (av1->channels == av->channels &&
3557 av1->sample_rate == av->sample_rate)
3560 case AVMEDIA_TYPE_VIDEO:
3561 if (av1->width == av->width &&
3562 av1->height == av->height &&
3563 av1->time_base.den == av->time_base.den &&
3564 av1->time_base.num == av->time_base.num &&
3565 av1->gop_size == av->gop_size)
3574 fst = add_av_stream1(feed, av, 0);
3577 return feed->nb_streams - 1;
3580 static void remove_stream(FFStream *stream)
3584 while (*ps != NULL) {
3592 /* specific mpeg4 handling : we extract the raw parameters */
3593 static void extract_mpeg4_header(AVFormatContext *infile)
3595 int mpeg4_count, i, size;
3600 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3603 for(i=0;i<infile->nb_streams;i++) {
3604 st = infile->streams[i];
3605 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3606 st->codec->extradata_size == 0) {
3613 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3614 while (mpeg4_count > 0) {
3615 if (av_read_frame(infile, &pkt) < 0)
3617 st = infile->streams[pkt.stream_index];
3618 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3619 st->codec->extradata_size == 0) {
3620 av_freep(&st->codec->extradata);
3621 /* fill extradata with the header */
3622 /* XXX: we make hard suppositions here ! */
3624 while (p < pkt.data + pkt.size - 4) {
3625 /* stop when vop header is found */
3626 if (p[0] == 0x00 && p[1] == 0x00 &&
3627 p[2] == 0x01 && p[3] == 0xb6) {
3628 size = p - pkt.data;
3629 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3630 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3631 st->codec->extradata_size = size;
3632 memcpy(st->codec->extradata, pkt.data, size);
3639 av_free_packet(&pkt);
3643 /* compute the needed AVStream for each file */
3644 static void build_file_streams(void)
3646 FFStream *stream, *stream_next;
3649 /* gather all streams */
3650 for(stream = first_stream; stream != NULL; stream = stream_next) {
3651 AVFormatContext *infile = NULL;
3652 stream_next = stream->next;
3653 if (stream->stream_type == STREAM_TYPE_LIVE &&
3655 /* the stream comes from a file */
3656 /* try to open the file */
3658 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3659 /* specific case : if transport stream output to RTP,
3660 we use a raw transport stream reader */
3661 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3664 http_log("Opening file '%s'\n", stream->feed_filename);
3665 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3666 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3667 /* remove stream (no need to spend more time on it) */
3669 remove_stream(stream);
3671 /* find all the AVStreams inside and reference them in
3673 if (avformat_find_stream_info(infile, NULL) < 0) {
3674 http_log("Could not find codec parameters from '%s'\n",
3675 stream->feed_filename);
3676 avformat_close_input(&infile);
3679 extract_mpeg4_header(infile);
3681 for(i=0;i<infile->nb_streams;i++)
3682 add_av_stream1(stream, infile->streams[i]->codec, 1);
3684 avformat_close_input(&infile);
3690 /* compute the needed AVStream for each feed */
3691 static void build_feed_streams(void)
3693 FFStream *stream, *feed;
3696 /* gather all streams */
3697 for(stream = first_stream; stream != NULL; stream = stream->next) {
3698 feed = stream->feed;
3700 if (stream->is_feed) {
3701 for(i=0;i<stream->nb_streams;i++)
3702 stream->feed_streams[i] = i;
3704 /* we handle a stream coming from a feed */
3705 for(i=0;i<stream->nb_streams;i++)
3706 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3711 /* create feed files if needed */
3712 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3715 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3716 /* See if it matches */
3717 AVFormatContext *s = NULL;
3720 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3721 /* set buffer size */
3722 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3723 /* Now see if it matches */
3724 if (s->nb_streams == feed->nb_streams) {
3726 for(i=0;i<s->nb_streams;i++) {
3728 sf = feed->streams[i];
3731 if (sf->index != ss->index ||
3733 http_log("Index & Id do not match for stream %d (%s)\n",
3734 i, feed->feed_filename);
3737 AVCodecContext *ccf, *ccs;
3741 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3743 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3744 http_log("Codecs do not match for stream %d\n", i);
3746 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3747 http_log("Codec bitrates do not match for stream %d\n", i);
3749 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3750 if (CHECK_CODEC(time_base.den) ||
3751 CHECK_CODEC(time_base.num) ||
3752 CHECK_CODEC(width) ||
3753 CHECK_CODEC(height)) {
3754 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3757 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3758 if (CHECK_CODEC(sample_rate) ||
3759 CHECK_CODEC(channels) ||
3760 CHECK_CODEC(frame_size)) {
3761 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3765 http_log("Unknown codec type\n");
3773 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3774 feed->feed_filename, s->nb_streams, feed->nb_streams);
3776 avformat_close_input(&s);
3778 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3779 feed->feed_filename);
3782 if (feed->readonly) {
3783 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3784 feed->feed_filename);
3787 unlink(feed->feed_filename);
3790 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3791 AVFormatContext s1 = {0}, *s = &s1;
3793 if (feed->readonly) {
3794 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3795 feed->feed_filename);
3799 /* only write the header of the ffm file */
3800 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3801 http_log("Could not open output feed file '%s'\n",
3802 feed->feed_filename);
3805 s->oformat = feed->fmt;
3806 s->nb_streams = feed->nb_streams;
3807 s->streams = feed->streams;
3808 if (avformat_write_header(s, NULL) < 0) {
3809 http_log("Container doesn't support the required parameters\n");
3812 /* XXX: need better api */
3813 av_freep(&s->priv_data);
3816 /* get feed size and write index */
3817 fd = open(feed->feed_filename, O_RDONLY);
3819 http_log("Could not open output feed file '%s'\n",
3820 feed->feed_filename);
3824 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3825 feed->feed_size = lseek(fd, 0, SEEK_END);
3826 /* ensure that we do not wrap before the end of file */
3827 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3828 feed->feed_max_size = feed->feed_size;
3834 /* compute the bandwidth used by each stream */
3835 static void compute_bandwidth(void)
3841 for(stream = first_stream; stream != NULL; stream = stream->next) {
3843 for(i=0;i<stream->nb_streams;i++) {
3844 AVStream *st = stream->streams[i];
3845 switch(st->codec->codec_type) {
3846 case AVMEDIA_TYPE_AUDIO:
3847 case AVMEDIA_TYPE_VIDEO:
3848 bandwidth += st->codec->bit_rate;
3854 stream->bandwidth = (bandwidth + 999) / 1000;
3858 /* add a codec and set the default parameters */
3859 static void add_codec(FFStream *stream, AVCodecContext *av)
3863 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3866 /* compute default parameters */
3867 switch(av->codec_type) {
3868 case AVMEDIA_TYPE_AUDIO:
3869 if (av->bit_rate == 0)
3870 av->bit_rate = 64000;
3871 if (av->sample_rate == 0)
3872 av->sample_rate = 22050;
3873 if (av->channels == 0)
3876 case AVMEDIA_TYPE_VIDEO:
3877 if (av->bit_rate == 0)
3878 av->bit_rate = 64000;
3879 if (av->time_base.num == 0){
3880 av->time_base.den = 5;
3881 av->time_base.num = 1;
3883 if (av->width == 0 || av->height == 0) {
3887 /* Bitrate tolerance is less for streaming */
3888 if (av->bit_rate_tolerance == 0)
3889 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3890 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3895 if (av->max_qdiff == 0)
3897 av->qcompress = 0.5;
3900 if (!av->nsse_weight)
3901 av->nsse_weight = 8;
3903 av->frame_skip_cmp = FF_CMP_DCTMAX;
3905 av->me_method = ME_EPZS;
3906 av->rc_buffer_aggressivity = 1.0;
3909 av->rc_eq = "tex^qComp";
3910 if (!av->i_quant_factor)
3911 av->i_quant_factor = -0.8;
3912 if (!av->b_quant_factor)
3913 av->b_quant_factor = 1.25;
3914 if (!av->b_quant_offset)
3915 av->b_quant_offset = 1.25;
3916 if (!av->rc_max_rate)
3917 av->rc_max_rate = av->bit_rate * 2;
3919 if (av->rc_max_rate && !av->rc_buffer_size) {
3920 av->rc_buffer_size = av->rc_max_rate;
3929 st = av_mallocz(sizeof(AVStream));
3932 st->codec = avcodec_alloc_context3(NULL);
3933 stream->streams[stream->nb_streams++] = st;
3934 memcpy(st->codec, av, sizeof(AVCodecContext));
3937 static enum AVCodecID opt_audio_codec(const char *arg)
3939 AVCodec *p= avcodec_find_encoder_by_name(arg);
3941 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3942 return AV_CODEC_ID_NONE;
3947 static enum AVCodecID opt_video_codec(const char *arg)
3949 AVCodec *p= avcodec_find_encoder_by_name(arg);
3951 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3952 return AV_CODEC_ID_NONE;
3957 /* simplistic plugin support */
3960 static void load_module(const char *filename)
3963 void (*init_func)(void);
3964 dll = dlopen(filename, RTLD_NOW);
3966 fprintf(stderr, "Could not load module '%s' - %s\n",
3967 filename, dlerror());
3971 init_func = dlsym(dll, "ffserver_module_init");
3974 "%s: init function 'ffserver_module_init()' not found\n",
3984 static int ffserver_opt_default(const char *opt, const char *arg,
3985 AVCodecContext *avctx, int type)
3988 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3990 ret = av_opt_set(avctx, opt, arg, 0);
3994 static int ffserver_opt_preset(const char *arg,
3995 AVCodecContext *avctx, int type,
3996 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3999 char filename[1000], tmp[1000], tmp2[1000], line[1000];
4001 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
4003 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
4004 codec ? codec->name : NULL))) {
4005 fprintf(stderr, "File for preset '%s' not found\n", arg);
4010 int e= fscanf(f, "%999[^\n]\n", line) - 1;
4011 if(line[0] == '#' && !e)
4013 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
4015 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
4019 if(!strcmp(tmp, "acodec")){
4020 *audio_id = opt_audio_codec(tmp2);
4021 }else if(!strcmp(tmp, "vcodec")){
4022 *video_id = opt_video_codec(tmp2);
4023 }else if(!strcmp(tmp, "scodec")){
4024 /* opt_subtitle_codec(tmp2); */
4025 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
4026 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4037 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4038 const char *mime_type)
4040 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4043 AVOutputFormat *stream_fmt;
4044 char stream_format_name[64];
4046 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4047 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4056 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4060 fprintf(stderr, "%s:%d: ", filename, line_num);
4061 vfprintf(stderr, fmt, vl);
4067 static int parse_ffconfig(const char *filename)
4074 int val, errors, line_num;
4075 FFStream **last_stream, *stream, *redirect;
4076 FFStream **last_feed, *feed, *s;
4077 AVCodecContext audio_enc, video_enc;
4078 enum AVCodecID audio_id, video_id;
4080 f = fopen(filename, "r");
4088 first_stream = NULL;
4089 last_stream = &first_stream;
4091 last_feed = &first_feed;
4095 audio_id = AV_CODEC_ID_NONE;
4096 video_id = AV_CODEC_ID_NONE;
4098 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4100 if (fgets(line, sizeof(line), f) == NULL)
4104 while (av_isspace(*p))
4106 if (*p == '\0' || *p == '#')
4109 get_arg(cmd, sizeof(cmd), &p);
4111 if (!av_strcasecmp(cmd, "Port")) {
4112 get_arg(arg, sizeof(arg), &p);
4114 if (val < 1 || val > 65536) {
4115 ERROR("Invalid_port: %s\n", arg);
4117 my_http_addr.sin_port = htons(val);
4118 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4119 get_arg(arg, sizeof(arg), &p);
4120 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4121 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4123 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4124 // do nothing here, its the default now
4125 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4126 get_arg(arg, sizeof(arg), &p);
4128 if (val < 1 || val > 65536) {
4129 ERROR("%s:%d: Invalid port: %s\n", arg);
4131 my_rtsp_addr.sin_port = htons(atoi(arg));
4132 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4133 get_arg(arg, sizeof(arg), &p);
4134 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4135 ERROR("Invalid host/IP address: %s\n", arg);
4137 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4138 get_arg(arg, sizeof(arg), &p);
4140 if (val < 1 || val > 65536) {
4141 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4143 nb_max_http_connections = val;
4144 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4145 get_arg(arg, sizeof(arg), &p);
4147 if (val < 1 || val > nb_max_http_connections) {
4148 ERROR("Invalid MaxClients: %s\n", arg);
4150 nb_max_connections = val;
4152 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4154 get_arg(arg, sizeof(arg), &p);
4155 llval = strtoll(arg, NULL, 10);
4156 if (llval < 10 || llval > 10000000) {
4157 ERROR("Invalid MaxBandwidth: %s\n", arg);
4159 max_bandwidth = llval;
4160 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4161 if (!ffserver_debug)
4162 get_arg(logfilename, sizeof(logfilename), &p);
4163 } else if (!av_strcasecmp(cmd, "<Feed")) {
4164 /*********************************************/
4165 /* Feed related options */
4167 if (stream || feed) {
4168 ERROR("Already in a tag\n");
4170 feed = av_mallocz(sizeof(FFStream));
4171 get_arg(feed->filename, sizeof(feed->filename), &p);
4172 q = strrchr(feed->filename, '>');
4176 for (s = first_feed; s; s = s->next) {
4177 if (!strcmp(feed->filename, s->filename)) {
4178 ERROR("Feed '%s' already registered\n", s->filename);
4182 feed->fmt = av_guess_format("ffm", NULL, NULL);
4183 /* defaut feed file */
4184 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4185 "/tmp/%s.ffm", feed->filename);
4186 feed->feed_max_size = 5 * 1024 * 1024;
4188 feed->feed = feed; /* self feeding :-) */
4190 /* add in stream list */
4191 *last_stream = feed;
4192 last_stream = &feed->next;
4193 /* add in feed list */
4195 last_feed = &feed->next_feed;
4197 } else if (!av_strcasecmp(cmd, "Launch")) {
4201 feed->child_argv = av_mallocz(64 * sizeof(char *));
4203 for (i = 0; i < 62; i++) {
4204 get_arg(arg, sizeof(arg), &p);
4208 feed->child_argv[i] = av_strdup(arg);
4211 feed->child_argv[i] = av_asprintf("http://%s:%d/%s",
4212 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4213 inet_ntoa(my_http_addr.sin_addr),
4214 ntohs(my_http_addr.sin_port), feed->filename);
4216 } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
4218 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4220 } else if (stream) {
4221 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4223 } else if (!av_strcasecmp(cmd, "File")) {
4225 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4227 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4228 } else if (!av_strcasecmp(cmd, "Truncate")) {
4230 get_arg(arg, sizeof(arg), &p);
4231 feed->truncate = strtod(arg, NULL);
4233 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4238 get_arg(arg, sizeof(arg), &p);
4240 fsize = strtod(p1, &p1);
4241 switch(av_toupper(*p1)) {
4246 fsize *= 1024 * 1024;
4249 fsize *= 1024 * 1024 * 1024;
4252 feed->feed_max_size = (int64_t)fsize;
4253 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4254 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4257 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4259 ERROR("No corresponding <Feed> for </Feed>\n");
4262 } else if (!av_strcasecmp(cmd, "<Stream")) {
4263 /*********************************************/
4264 /* Stream related options */
4266 if (stream || feed) {
4267 ERROR("Already in a tag\n");
4270 stream = av_mallocz(sizeof(FFStream));
4271 get_arg(stream->filename, sizeof(stream->filename), &p);
4272 q = strrchr(stream->filename, '>');
4276 for (s = first_stream; s; s = s->next) {
4277 if (!strcmp(stream->filename, s->filename)) {
4278 ERROR("Stream '%s' already registered\n", s->filename);
4282 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4283 avcodec_get_context_defaults3(&video_enc, NULL);
4284 avcodec_get_context_defaults3(&audio_enc, NULL);
4286 audio_id = AV_CODEC_ID_NONE;
4287 video_id = AV_CODEC_ID_NONE;
4289 audio_id = stream->fmt->audio_codec;
4290 video_id = stream->fmt->video_codec;
4293 *last_stream = stream;
4294 last_stream = &stream->next;
4296 } else if (!av_strcasecmp(cmd, "Feed")) {
4297 get_arg(arg, sizeof(arg), &p);
4302 while (sfeed != NULL) {
4303 if (!strcmp(sfeed->filename, arg))
4305 sfeed = sfeed->next_feed;
4308 ERROR("feed '%s' not defined\n", arg);
4310 stream->feed = sfeed;
4312 } else if (!av_strcasecmp(cmd, "Format")) {
4313 get_arg(arg, sizeof(arg), &p);
4315 if (!strcmp(arg, "status")) {
4316 stream->stream_type = STREAM_TYPE_STATUS;
4319 stream->stream_type = STREAM_TYPE_LIVE;
4320 /* jpeg cannot be used here, so use single frame jpeg */
4321 if (!strcmp(arg, "jpeg"))
4322 strcpy(arg, "mjpeg");
4323 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4325 ERROR("Unknown Format: %s\n", arg);
4329 audio_id = stream->fmt->audio_codec;
4330 video_id = stream->fmt->video_codec;
4333 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4334 get_arg(arg, sizeof(arg), &p);
4336 stream->ifmt = av_find_input_format(arg);
4337 if (!stream->ifmt) {
4338 ERROR("Unknown input format: %s\n", arg);
4341 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4342 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4343 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4345 ERROR("FaviconURL only permitted for status streams\n");
4347 } else if (!av_strcasecmp(cmd, "Author")) {
4349 get_arg(stream->author, sizeof(stream->author), &p);
4350 } else if (!av_strcasecmp(cmd, "Comment")) {
4352 get_arg(stream->comment, sizeof(stream->comment), &p);
4353 } else if (!av_strcasecmp(cmd, "Copyright")) {
4355 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4356 } else if (!av_strcasecmp(cmd, "Title")) {
4358 get_arg(stream->title, sizeof(stream->title), &p);
4359 } else if (!av_strcasecmp(cmd, "Preroll")) {
4360 get_arg(arg, sizeof(arg), &p);
4362 stream->prebuffer = atof(arg) * 1000;
4363 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4365 stream->send_on_key = 1;
4366 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4367 get_arg(arg, sizeof(arg), &p);
4368 audio_id = opt_audio_codec(arg);
4369 if (audio_id == AV_CODEC_ID_NONE) {
4370 ERROR("Unknown AudioCodec: %s\n", arg);
4372 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4373 get_arg(arg, sizeof(arg), &p);
4374 video_id = opt_video_codec(arg);
4375 if (video_id == AV_CODEC_ID_NONE) {
4376 ERROR("Unknown VideoCodec: %s\n", arg);
4378 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4379 get_arg(arg, sizeof(arg), &p);
4381 stream->max_time = atof(arg) * 1000;
4382 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4383 get_arg(arg, sizeof(arg), &p);
4385 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4386 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4387 get_arg(arg, sizeof(arg), &p);
4389 audio_enc.channels = atoi(arg);
4390 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4391 get_arg(arg, sizeof(arg), &p);
4393 audio_enc.sample_rate = atoi(arg);
4394 } else if (!av_strcasecmp(cmd, "AudioQuality")) {
4395 get_arg(arg, sizeof(arg), &p);
4397 // audio_enc.quality = atof(arg) * 1000;
4399 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4401 int minrate, maxrate;
4403 get_arg(arg, sizeof(arg), &p);
4405 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4406 video_enc.rc_min_rate = minrate * 1000;
4407 video_enc.rc_max_rate = maxrate * 1000;
4409 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4412 } else if (!av_strcasecmp(cmd, "Debug")) {
4414 get_arg(arg, sizeof(arg), &p);
4415 video_enc.debug = strtol(arg,0,0);
4417 } else if (!av_strcasecmp(cmd, "Strict")) {
4419 get_arg(arg, sizeof(arg), &p);
4420 video_enc.strict_std_compliance = atoi(arg);
4422 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4424 get_arg(arg, sizeof(arg), &p);
4425 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4427 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4429 get_arg(arg, sizeof(arg), &p);
4430 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4432 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4433 get_arg(arg, sizeof(arg), &p);
4435 video_enc.bit_rate = atoi(arg) * 1000;
4437 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4438 get_arg(arg, sizeof(arg), &p);
4440 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4441 if ((video_enc.width % 16) != 0 ||
4442 (video_enc.height % 16) != 0) {
4443 ERROR("Image size must be a multiple of 16\n");
4446 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4447 get_arg(arg, sizeof(arg), &p);
4449 AVRational frame_rate;
4450 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4451 ERROR("Incorrect frame rate: %s\n", arg);
4453 video_enc.time_base.num = frame_rate.den;
4454 video_enc.time_base.den = frame_rate.num;
4457 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4458 get_arg(arg, sizeof(arg), &p);
4460 video_enc.gop_size = atoi(arg);
4461 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4463 video_enc.gop_size = 1;
4464 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4466 video_enc.mb_decision = FF_MB_DECISION_BITS;
4467 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4469 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4470 video_enc.flags |= CODEC_FLAG_4MV;
4472 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4473 !av_strcasecmp(cmd, "AVOptionAudio")) {
4475 AVCodecContext *avctx;
4477 get_arg(arg, sizeof(arg), &p);
4478 get_arg(arg2, sizeof(arg2), &p);
4479 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4481 type = AV_OPT_FLAG_VIDEO_PARAM;
4484 type = AV_OPT_FLAG_AUDIO_PARAM;
4486 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4487 ERROR("AVOption error: %s %s\n", arg, arg2);
4489 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4490 !av_strcasecmp(cmd, "AVPresetAudio")) {
4491 AVCodecContext *avctx;
4493 get_arg(arg, sizeof(arg), &p);
4494 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4496 video_enc.codec_id = video_id;
4497 type = AV_OPT_FLAG_VIDEO_PARAM;
4500 audio_enc.codec_id = audio_id;
4501 type = AV_OPT_FLAG_AUDIO_PARAM;
4503 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4504 ERROR("AVPreset error: %s\n", arg);
4506 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4507 get_arg(arg, sizeof(arg), &p);
4508 if ((strlen(arg) == 4) && stream)
4509 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4510 } else if (!av_strcasecmp(cmd, "BitExact")) {
4512 video_enc.flags |= CODEC_FLAG_BITEXACT;
4513 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4515 video_enc.dct_algo = FF_DCT_FASTINT;
4516 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4518 video_enc.idct_algo = FF_IDCT_SIMPLE;
4519 } else if (!av_strcasecmp(cmd, "Qscale")) {
4520 get_arg(arg, sizeof(arg), &p);
4522 video_enc.flags |= CODEC_FLAG_QSCALE;
4523 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4525 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4526 get_arg(arg, sizeof(arg), &p);
4528 video_enc.max_qdiff = atoi(arg);
4529 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4530 ERROR("VideoQDiff out of range\n");
4533 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4534 get_arg(arg, sizeof(arg), &p);
4536 video_enc.qmax = atoi(arg);
4537 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4538 ERROR("VideoQMax out of range\n");
4541 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4542 get_arg(arg, sizeof(arg), &p);
4544 video_enc.qmin = atoi(arg);
4545 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4546 ERROR("VideoQMin out of range\n");
4549 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4550 get_arg(arg, sizeof(arg), &p);
4552 video_enc.lumi_masking = atof(arg);
4553 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4554 get_arg(arg, sizeof(arg), &p);
4556 video_enc.dark_masking = atof(arg);
4557 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4558 video_id = AV_CODEC_ID_NONE;
4559 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4560 audio_id = AV_CODEC_ID_NONE;
4561 } else if (!av_strcasecmp(cmd, "ACL")) {
4562 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4563 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4565 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4567 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4568 get_arg(arg, sizeof(arg), &p);
4570 av_freep(&stream->rtsp_option);
4571 stream->rtsp_option = av_strdup(arg);
4573 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4574 get_arg(arg, sizeof(arg), &p);
4576 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4577 ERROR("Invalid host/IP address: %s\n", arg);
4579 stream->is_multicast = 1;
4580 stream->loop = 1; /* default is looping */
4582 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4583 get_arg(arg, sizeof(arg), &p);
4585 stream->multicast_port = atoi(arg);
4586 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4587 get_arg(arg, sizeof(arg), &p);
4589 stream->multicast_ttl = atoi(arg);
4590 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4593 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4595 ERROR("No corresponding <Stream> for </Stream>\n");
4597 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4598 if (audio_id != AV_CODEC_ID_NONE) {
4599 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4600 audio_enc.codec_id = audio_id;
4601 add_codec(stream, &audio_enc);
4603 if (video_id != AV_CODEC_ID_NONE) {
4604 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4605 video_enc.codec_id = video_id;
4606 add_codec(stream, &video_enc);
4611 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4612 /*********************************************/
4614 if (stream || feed || redirect) {
4615 ERROR("Already in a tag\n");
4617 redirect = av_mallocz(sizeof(FFStream));
4618 *last_stream = redirect;
4619 last_stream = &redirect->next;
4621 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4622 q = strrchr(redirect->filename, '>');
4625 redirect->stream_type = STREAM_TYPE_REDIRECT;
4627 } else if (!av_strcasecmp(cmd, "URL")) {
4629 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4630 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4632 ERROR("No corresponding <Redirect> for </Redirect>\n");
4634 if (!redirect->feed_filename[0]) {
4635 ERROR("No URL found for <Redirect>\n");
4639 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4640 get_arg(arg, sizeof(arg), &p);
4644 ERROR("Module support not compiled into this version: '%s'\n", arg);
4647 ERROR("Incorrect keyword: '%s'\n", cmd);
4659 static void handle_child_exit(int sig)
4664 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4667 for (feed = first_feed; feed; feed = feed->next) {
4668 if (feed->pid == pid) {
4669 int uptime = time(0) - feed->pid_start;
4672 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4675 /* Turn off any more restarts */
4676 feed->child_argv = 0;
4681 need_to_start_children = 1;
4684 static void opt_debug(void)
4687 logfilename[0] = '-';
4690 void show_help_default(const char *opt, const char *arg)
4692 printf("usage: ffserver [options]\n"
4693 "Hyper fast multi format Audio/Video streaming server\n");
4695 show_help_options(options, "Main options:", 0, 0, 0);
4698 static const OptionDef options[] = {
4699 #include "cmdutils_common_opts.h"
4700 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4701 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4702 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4706 int main(int argc, char **argv)
4708 struct sigaction sigact = { { 0 } };
4710 parse_loglevel(argc, argv, options);
4712 avformat_network_init();
4714 show_banner(argc, argv, options);
4716 my_program_name = argv[0];
4718 parse_options(NULL, argc, argv, options, NULL);
4720 if (!config_filename)
4721 config_filename = av_strdup("/etc/ffserver.conf");
4723 unsetenv("http_proxy"); /* Kill the http_proxy */
4725 av_lfg_init(&random_state, av_get_random_seed());
4727 sigact.sa_handler = handle_child_exit;
4728 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4729 sigaction(SIGCHLD, &sigact, 0);
4731 if (parse_ffconfig(config_filename) < 0) {
4732 fprintf(stderr, "Incorrect config file - exiting.\n");
4735 av_freep(&config_filename);
4737 /* open log file if needed */
4738 if (logfilename[0] != '\0') {
4739 if (!strcmp(logfilename, "-"))
4742 logfile = fopen(logfilename, "a");
4743 av_log_set_callback(http_av_log);
4746 build_file_streams();
4748 build_feed_streams();
4750 compute_bandwidth();
4753 signal(SIGPIPE, SIG_IGN);
4755 if (http_server() < 0) {
4756 http_log("Could not start server\n");