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",
3983 static int ffserver_opt_default(const char *opt, const char *arg,
3984 AVCodecContext *avctx, int type)
3987 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3989 ret = av_opt_set(avctx, opt, arg, 0);
3993 static int ffserver_opt_preset(const char *arg,
3994 AVCodecContext *avctx, int type,
3995 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3998 char filename[1000], tmp[1000], tmp2[1000], line[1000];
4000 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
4002 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
4003 codec ? codec->name : NULL))) {
4004 fprintf(stderr, "File for preset '%s' not found\n", arg);
4009 int e= fscanf(f, "%999[^\n]\n", line) - 1;
4010 if(line[0] == '#' && !e)
4012 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
4014 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
4018 if(!strcmp(tmp, "acodec")){
4019 *audio_id = opt_audio_codec(tmp2);
4020 }else if(!strcmp(tmp, "vcodec")){
4021 *video_id = opt_video_codec(tmp2);
4022 }else if(!strcmp(tmp, "scodec")){
4023 /* opt_subtitle_codec(tmp2); */
4024 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
4025 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4036 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4037 const char *mime_type)
4039 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4042 AVOutputFormat *stream_fmt;
4043 char stream_format_name[64];
4045 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4046 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4055 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4059 fprintf(stderr, "%s:%d: ", filename, line_num);
4060 vfprintf(stderr, fmt, vl);
4066 static int parse_ffconfig(const char *filename)
4073 int val, errors, line_num;
4074 FFStream **last_stream, *stream, *redirect;
4075 FFStream **last_feed, *feed, *s;
4076 AVCodecContext audio_enc, video_enc;
4077 enum AVCodecID audio_id, video_id;
4079 f = fopen(filename, "r");
4087 first_stream = NULL;
4088 last_stream = &first_stream;
4090 last_feed = &first_feed;
4094 audio_id = AV_CODEC_ID_NONE;
4095 video_id = AV_CODEC_ID_NONE;
4097 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4099 if (fgets(line, sizeof(line), f) == NULL)
4103 while (av_isspace(*p))
4105 if (*p == '\0' || *p == '#')
4108 get_arg(cmd, sizeof(cmd), &p);
4110 if (!av_strcasecmp(cmd, "Port")) {
4111 get_arg(arg, sizeof(arg), &p);
4113 if (val < 1 || val > 65536) {
4114 ERROR("Invalid_port: %s\n", arg);
4116 my_http_addr.sin_port = htons(val);
4117 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4118 get_arg(arg, sizeof(arg), &p);
4119 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4120 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4122 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4123 // do nothing here, its the default now
4124 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4125 get_arg(arg, sizeof(arg), &p);
4127 if (val < 1 || val > 65536) {
4128 ERROR("%s:%d: Invalid port: %s\n", arg);
4130 my_rtsp_addr.sin_port = htons(atoi(arg));
4131 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4132 get_arg(arg, sizeof(arg), &p);
4133 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4134 ERROR("Invalid host/IP address: %s\n", arg);
4136 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4137 get_arg(arg, sizeof(arg), &p);
4139 if (val < 1 || val > 65536) {
4140 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4142 nb_max_http_connections = val;
4143 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4144 get_arg(arg, sizeof(arg), &p);
4146 if (val < 1 || val > nb_max_http_connections) {
4147 ERROR("Invalid MaxClients: %s\n", arg);
4149 nb_max_connections = val;
4151 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4153 get_arg(arg, sizeof(arg), &p);
4154 llval = strtoll(arg, NULL, 10);
4155 if (llval < 10 || llval > 10000000) {
4156 ERROR("Invalid MaxBandwidth: %s\n", arg);
4158 max_bandwidth = llval;
4159 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4160 if (!ffserver_debug)
4161 get_arg(logfilename, sizeof(logfilename), &p);
4162 } else if (!av_strcasecmp(cmd, "<Feed")) {
4163 /*********************************************/
4164 /* Feed related options */
4166 if (stream || feed) {
4167 ERROR("Already in a tag\n");
4169 feed = av_mallocz(sizeof(FFStream));
4170 get_arg(feed->filename, sizeof(feed->filename), &p);
4171 q = strrchr(feed->filename, '>');
4175 for (s = first_feed; s; s = s->next) {
4176 if (!strcmp(feed->filename, s->filename)) {
4177 ERROR("Feed '%s' already registered\n", s->filename);
4181 feed->fmt = av_guess_format("ffm", NULL, NULL);
4182 /* defaut feed file */
4183 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4184 "/tmp/%s.ffm", feed->filename);
4185 feed->feed_max_size = 5 * 1024 * 1024;
4187 feed->feed = feed; /* self feeding :-) */
4189 /* add in stream list */
4190 *last_stream = feed;
4191 last_stream = &feed->next;
4192 /* add in feed list */
4194 last_feed = &feed->next_feed;
4196 } else if (!av_strcasecmp(cmd, "Launch")) {
4200 feed->child_argv = av_mallocz(64 * sizeof(char *));
4202 for (i = 0; i < 62; i++) {
4203 get_arg(arg, sizeof(arg), &p);
4207 feed->child_argv[i] = av_strdup(arg);
4210 feed->child_argv[i] = av_asprintf("http://%s:%d/%s",
4211 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4212 inet_ntoa(my_http_addr.sin_addr),
4213 ntohs(my_http_addr.sin_port), feed->filename);
4215 } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
4217 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4219 } else if (stream) {
4220 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4222 } else if (!av_strcasecmp(cmd, "File")) {
4224 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4226 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4227 } else if (!av_strcasecmp(cmd, "Truncate")) {
4229 get_arg(arg, sizeof(arg), &p);
4230 feed->truncate = strtod(arg, NULL);
4232 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4237 get_arg(arg, sizeof(arg), &p);
4239 fsize = strtod(p1, &p1);
4240 switch(av_toupper(*p1)) {
4245 fsize *= 1024 * 1024;
4248 fsize *= 1024 * 1024 * 1024;
4251 feed->feed_max_size = (int64_t)fsize;
4252 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4253 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4256 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4258 ERROR("No corresponding <Feed> for </Feed>\n");
4261 } else if (!av_strcasecmp(cmd, "<Stream")) {
4262 /*********************************************/
4263 /* Stream related options */
4265 if (stream || feed) {
4266 ERROR("Already in a tag\n");
4269 stream = av_mallocz(sizeof(FFStream));
4270 get_arg(stream->filename, sizeof(stream->filename), &p);
4271 q = strrchr(stream->filename, '>');
4275 for (s = first_stream; s; s = s->next) {
4276 if (!strcmp(stream->filename, s->filename)) {
4277 ERROR("Stream '%s' already registered\n", s->filename);
4281 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4282 avcodec_get_context_defaults3(&video_enc, NULL);
4283 avcodec_get_context_defaults3(&audio_enc, NULL);
4285 audio_id = AV_CODEC_ID_NONE;
4286 video_id = AV_CODEC_ID_NONE;
4288 audio_id = stream->fmt->audio_codec;
4289 video_id = stream->fmt->video_codec;
4292 *last_stream = stream;
4293 last_stream = &stream->next;
4295 } else if (!av_strcasecmp(cmd, "Feed")) {
4296 get_arg(arg, sizeof(arg), &p);
4301 while (sfeed != NULL) {
4302 if (!strcmp(sfeed->filename, arg))
4304 sfeed = sfeed->next_feed;
4307 ERROR("feed '%s' not defined\n", arg);
4309 stream->feed = sfeed;
4311 } else if (!av_strcasecmp(cmd, "Format")) {
4312 get_arg(arg, sizeof(arg), &p);
4314 if (!strcmp(arg, "status")) {
4315 stream->stream_type = STREAM_TYPE_STATUS;
4318 stream->stream_type = STREAM_TYPE_LIVE;
4319 /* jpeg cannot be used here, so use single frame jpeg */
4320 if (!strcmp(arg, "jpeg"))
4321 strcpy(arg, "mjpeg");
4322 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4324 ERROR("Unknown Format: %s\n", arg);
4328 audio_id = stream->fmt->audio_codec;
4329 video_id = stream->fmt->video_codec;
4332 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4333 get_arg(arg, sizeof(arg), &p);
4335 stream->ifmt = av_find_input_format(arg);
4336 if (!stream->ifmt) {
4337 ERROR("Unknown input format: %s\n", arg);
4340 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4341 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4342 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4344 ERROR("FaviconURL only permitted for status streams\n");
4346 } else if (!av_strcasecmp(cmd, "Author")) {
4348 get_arg(stream->author, sizeof(stream->author), &p);
4349 } else if (!av_strcasecmp(cmd, "Comment")) {
4351 get_arg(stream->comment, sizeof(stream->comment), &p);
4352 } else if (!av_strcasecmp(cmd, "Copyright")) {
4354 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4355 } else if (!av_strcasecmp(cmd, "Title")) {
4357 get_arg(stream->title, sizeof(stream->title), &p);
4358 } else if (!av_strcasecmp(cmd, "Preroll")) {
4359 get_arg(arg, sizeof(arg), &p);
4361 stream->prebuffer = atof(arg) * 1000;
4362 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4364 stream->send_on_key = 1;
4365 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4366 get_arg(arg, sizeof(arg), &p);
4367 audio_id = opt_audio_codec(arg);
4368 if (audio_id == AV_CODEC_ID_NONE) {
4369 ERROR("Unknown AudioCodec: %s\n", arg);
4371 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4372 get_arg(arg, sizeof(arg), &p);
4373 video_id = opt_video_codec(arg);
4374 if (video_id == AV_CODEC_ID_NONE) {
4375 ERROR("Unknown VideoCodec: %s\n", arg);
4377 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4378 get_arg(arg, sizeof(arg), &p);
4380 stream->max_time = atof(arg) * 1000;
4381 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4382 get_arg(arg, sizeof(arg), &p);
4384 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4385 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4386 get_arg(arg, sizeof(arg), &p);
4388 audio_enc.channels = atoi(arg);
4389 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4390 get_arg(arg, sizeof(arg), &p);
4392 audio_enc.sample_rate = atoi(arg);
4393 } else if (!av_strcasecmp(cmd, "AudioQuality")) {
4394 get_arg(arg, sizeof(arg), &p);
4396 // audio_enc.quality = atof(arg) * 1000;
4398 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4400 int minrate, maxrate;
4402 get_arg(arg, sizeof(arg), &p);
4404 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4405 video_enc.rc_min_rate = minrate * 1000;
4406 video_enc.rc_max_rate = maxrate * 1000;
4408 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4411 } else if (!av_strcasecmp(cmd, "Debug")) {
4413 get_arg(arg, sizeof(arg), &p);
4414 video_enc.debug = strtol(arg,0,0);
4416 } else if (!av_strcasecmp(cmd, "Strict")) {
4418 get_arg(arg, sizeof(arg), &p);
4419 video_enc.strict_std_compliance = atoi(arg);
4421 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4423 get_arg(arg, sizeof(arg), &p);
4424 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4426 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4428 get_arg(arg, sizeof(arg), &p);
4429 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4431 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4432 get_arg(arg, sizeof(arg), &p);
4434 video_enc.bit_rate = atoi(arg) * 1000;
4436 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4437 get_arg(arg, sizeof(arg), &p);
4439 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4440 if ((video_enc.width % 16) != 0 ||
4441 (video_enc.height % 16) != 0) {
4442 ERROR("Image size must be a multiple of 16\n");
4445 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4446 get_arg(arg, sizeof(arg), &p);
4448 AVRational frame_rate;
4449 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4450 ERROR("Incorrect frame rate: %s\n", arg);
4452 video_enc.time_base.num = frame_rate.den;
4453 video_enc.time_base.den = frame_rate.num;
4456 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4457 get_arg(arg, sizeof(arg), &p);
4459 video_enc.gop_size = atoi(arg);
4460 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4462 video_enc.gop_size = 1;
4463 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4465 video_enc.mb_decision = FF_MB_DECISION_BITS;
4466 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4468 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4469 video_enc.flags |= CODEC_FLAG_4MV;
4471 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4472 !av_strcasecmp(cmd, "AVOptionAudio")) {
4474 AVCodecContext *avctx;
4476 get_arg(arg, sizeof(arg), &p);
4477 get_arg(arg2, sizeof(arg2), &p);
4478 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4480 type = AV_OPT_FLAG_VIDEO_PARAM;
4483 type = AV_OPT_FLAG_AUDIO_PARAM;
4485 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4486 ERROR("AVOption error: %s %s\n", arg, arg2);
4488 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4489 !av_strcasecmp(cmd, "AVPresetAudio")) {
4490 AVCodecContext *avctx;
4492 get_arg(arg, sizeof(arg), &p);
4493 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4495 video_enc.codec_id = video_id;
4496 type = AV_OPT_FLAG_VIDEO_PARAM;
4499 audio_enc.codec_id = audio_id;
4500 type = AV_OPT_FLAG_AUDIO_PARAM;
4502 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4503 ERROR("AVPreset error: %s\n", arg);
4505 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4506 get_arg(arg, sizeof(arg), &p);
4507 if ((strlen(arg) == 4) && stream)
4508 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4509 } else if (!av_strcasecmp(cmd, "BitExact")) {
4511 video_enc.flags |= CODEC_FLAG_BITEXACT;
4512 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4514 video_enc.dct_algo = FF_DCT_FASTINT;
4515 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4517 video_enc.idct_algo = FF_IDCT_SIMPLE;
4518 } else if (!av_strcasecmp(cmd, "Qscale")) {
4519 get_arg(arg, sizeof(arg), &p);
4521 video_enc.flags |= CODEC_FLAG_QSCALE;
4522 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4524 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4525 get_arg(arg, sizeof(arg), &p);
4527 video_enc.max_qdiff = atoi(arg);
4528 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4529 ERROR("VideoQDiff out of range\n");
4532 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4533 get_arg(arg, sizeof(arg), &p);
4535 video_enc.qmax = atoi(arg);
4536 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4537 ERROR("VideoQMax out of range\n");
4540 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4541 get_arg(arg, sizeof(arg), &p);
4543 video_enc.qmin = atoi(arg);
4544 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4545 ERROR("VideoQMin out of range\n");
4548 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4549 get_arg(arg, sizeof(arg), &p);
4551 video_enc.lumi_masking = atof(arg);
4552 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4553 get_arg(arg, sizeof(arg), &p);
4555 video_enc.dark_masking = atof(arg);
4556 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4557 video_id = AV_CODEC_ID_NONE;
4558 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4559 audio_id = AV_CODEC_ID_NONE;
4560 } else if (!av_strcasecmp(cmd, "ACL")) {
4561 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4562 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4564 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4566 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4567 get_arg(arg, sizeof(arg), &p);
4569 av_freep(&stream->rtsp_option);
4570 stream->rtsp_option = av_strdup(arg);
4572 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4573 get_arg(arg, sizeof(arg), &p);
4575 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4576 ERROR("Invalid host/IP address: %s\n", arg);
4578 stream->is_multicast = 1;
4579 stream->loop = 1; /* default is looping */
4581 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4582 get_arg(arg, sizeof(arg), &p);
4584 stream->multicast_port = atoi(arg);
4585 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4586 get_arg(arg, sizeof(arg), &p);
4588 stream->multicast_ttl = atoi(arg);
4589 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4592 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4594 ERROR("No corresponding <Stream> for </Stream>\n");
4596 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4597 if (audio_id != AV_CODEC_ID_NONE) {
4598 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4599 audio_enc.codec_id = audio_id;
4600 add_codec(stream, &audio_enc);
4602 if (video_id != AV_CODEC_ID_NONE) {
4603 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4604 video_enc.codec_id = video_id;
4605 add_codec(stream, &video_enc);
4610 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4611 /*********************************************/
4613 if (stream || feed || redirect) {
4614 ERROR("Already in a tag\n");
4616 redirect = av_mallocz(sizeof(FFStream));
4617 *last_stream = redirect;
4618 last_stream = &redirect->next;
4620 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4621 q = strrchr(redirect->filename, '>');
4624 redirect->stream_type = STREAM_TYPE_REDIRECT;
4626 } else if (!av_strcasecmp(cmd, "URL")) {
4628 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4629 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4631 ERROR("No corresponding <Redirect> for </Redirect>\n");
4633 if (!redirect->feed_filename[0]) {
4634 ERROR("No URL found for <Redirect>\n");
4638 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4639 get_arg(arg, sizeof(arg), &p);
4643 ERROR("Module support not compiled into this version: '%s'\n", arg);
4646 ERROR("Incorrect keyword: '%s'\n", cmd);
4658 static void handle_child_exit(int sig)
4663 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4666 for (feed = first_feed; feed; feed = feed->next) {
4667 if (feed->pid == pid) {
4668 int uptime = time(0) - feed->pid_start;
4671 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4674 /* Turn off any more restarts */
4675 feed->child_argv = 0;
4680 need_to_start_children = 1;
4683 static void opt_debug(void)
4686 logfilename[0] = '-';
4689 void show_help_default(const char *opt, const char *arg)
4691 printf("usage: ffserver [options]\n"
4692 "Hyper fast multi format Audio/Video streaming server\n");
4694 show_help_options(options, "Main options:", 0, 0, 0);
4697 static const OptionDef options[] = {
4698 #include "cmdutils_common_opts.h"
4699 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4700 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4701 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4705 int main(int argc, char **argv)
4707 struct sigaction sigact = { { 0 } };
4709 parse_loglevel(argc, argv, options);
4711 avformat_network_init();
4713 show_banner(argc, argv, options);
4715 my_program_name = argv[0];
4717 parse_options(NULL, argc, argv, options, NULL);
4719 if (!config_filename)
4720 config_filename = av_strdup("/etc/ffserver.conf");
4722 unsetenv("http_proxy"); /* Kill the http_proxy */
4724 av_lfg_init(&random_state, av_get_random_seed());
4726 sigact.sa_handler = handle_child_exit;
4727 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4728 sigaction(SIGCHLD, &sigact, 0);
4730 if (parse_ffconfig(config_filename) < 0) {
4731 fprintf(stderr, "Incorrect config file - exiting.\n");
4734 av_freep(&config_filename);
4736 /* open log file if needed */
4737 if (logfilename[0] != '\0') {
4738 if (!strcmp(logfilename, "-"))
4741 logfile = fopen(logfilename, "a");
4742 av_log_set_callback(http_av_log);
4745 build_file_streams();
4747 build_feed_streams();
4749 compute_bandwidth();
4752 signal(SIGPIPE, SIG_IGN);
4754 if (http_server() < 0) {
4755 http_log("Could not start server\n");