2 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * multiple format streaming server based on the FFmpeg libraries
28 #define closesocket close
33 #include "libavformat/avformat.h"
34 // FIXME those are internal headers, ffserver _really_ shouldn't use them
35 #include "libavformat/ffm.h"
36 #include "libavformat/network.h"
37 #include "libavformat/os_support.h"
38 #include "libavformat/rtpdec.h"
39 #include "libavformat/rtpproto.h"
40 #include "libavformat/rtsp.h"
41 #include "libavformat/avio_internal.h"
42 #include "libavformat/internal.h"
43 #include "libavformat/url.h"
45 #include "libavutil/avassert.h"
46 #include "libavutil/avstring.h"
47 #include "libavutil/lfg.h"
48 #include "libavutil/dict.h"
49 #include "libavutil/intreadwrite.h"
50 #include "libavutil/mathematics.h"
51 #include "libavutil/pixdesc.h"
52 #include "libavutil/random_seed.h"
53 #include "libavutil/parseutils.h"
54 #include "libavutil/opt.h"
55 #include "libavutil/time.h"
60 #include <sys/ioctl.h>
71 const char program_name[] = "ffserver";
72 const int program_birth_year = 2000;
74 static const OptionDef options[];
77 HTTPSTATE_WAIT_REQUEST,
78 HTTPSTATE_SEND_HEADER,
79 HTTPSTATE_SEND_DATA_HEADER,
80 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
81 HTTPSTATE_SEND_DATA_TRAILER,
82 HTTPSTATE_RECEIVE_DATA,
83 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
86 RTSPSTATE_WAIT_REQUEST,
88 RTSPSTATE_SEND_PACKET,
91 static const char *http_state[] = {
107 #define MAX_STREAMS 20
109 #define IOBUFFER_INIT_SIZE 8192
111 /* timeouts are in ms */
112 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
113 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
115 #define SYNC_TIMEOUT (10 * 1000)
117 typedef struct RTSPActionServerSetup {
119 char transport_option[512];
120 } RTSPActionServerSetup;
123 int64_t count1, count2;
124 int64_t time1, time2;
127 /* context associated with one connection */
128 typedef struct HTTPContext {
129 enum HTTPState state;
130 int fd; /* socket file descriptor */
131 struct sockaddr_in from_addr; /* origin */
132 struct pollfd *poll_entry; /* used when polling */
134 uint8_t *buffer_ptr, *buffer_end;
137 int chunked_encoding;
138 int chunk_size; /* 0 if it needs to be read */
139 struct HTTPContext *next;
140 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
144 /* input format handling */
145 AVFormatContext *fmt_in;
146 int64_t start_time; /* In milliseconds - this wraps fairly often */
147 int64_t first_pts; /* initial pts value */
148 int64_t cur_pts; /* current pts value from the stream in us */
149 int64_t cur_frame_duration; /* duration of the current frame in us */
150 int cur_frame_bytes; /* output frame size, needed to compute
151 the time at which we send each
153 int pts_stream_index; /* stream we choose as clock reference */
154 int64_t cur_clock; /* current clock reference value in us */
155 /* output format handling */
156 struct FFStream *stream;
157 /* -1 is invalid stream */
158 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
159 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
161 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
162 int last_packet_sent; /* true if last data packet was sent */
164 DataRateData datarate;
171 int is_packetized; /* if true, the stream is packetized */
172 int packet_stream_index; /* current stream for output in state machine */
174 /* RTSP state specific */
175 uint8_t *pb_buffer; /* XXX: use that in all the code */
177 int seq; /* RTSP sequence number */
179 /* RTP state specific */
180 enum RTSPLowerTransport rtp_protocol;
181 char session_id[32]; /* session id */
182 AVFormatContext *rtp_ctx[MAX_STREAMS];
184 /* RTP/UDP specific */
185 URLContext *rtp_handles[MAX_STREAMS];
187 /* RTP/TCP specific */
188 struct HTTPContext *rtsp_c;
189 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
192 /* each generated stream is described here */
196 STREAM_TYPE_REDIRECT,
199 enum IPAddressAction {
204 typedef struct IPAddressACL {
205 struct IPAddressACL *next;
206 enum IPAddressAction action;
207 /* These are in host order */
208 struct in_addr first;
212 /* description of each stream of the ffserver.conf file */
213 typedef struct FFStream {
214 enum StreamType stream_type;
215 char filename[1024]; /* stream filename */
216 struct FFStream *feed; /* feed we are using (can be null if
218 AVDictionary *in_opts; /* input parameters */
219 AVDictionary *metadata; /* metadata to set on the stream */
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 */
232 pid_t pid; /* Of ffmpeg process */
233 time_t pid_start; /* Of ffmpeg process */
235 struct FFStream *next;
236 unsigned bandwidth; /* bandwidth, in kbits/s */
239 /* multicast specific */
241 struct in_addr multicast_ip;
242 int multicast_port; /* first port used for multicast */
244 int loop; /* if true, send the stream in loops (only meaningful if file) */
247 int feed_opened; /* true if someone is writing to the feed */
248 int is_feed; /* true if it is a feed */
249 int readonly; /* True if writing is prohibited to the file */
250 int truncate; /* True if feeder connection truncate the feed file */
252 int64_t bytes_served;
253 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
254 int64_t feed_write_index; /* current write position in feed (it wraps around) */
255 int64_t feed_size; /* current size of feed */
256 struct FFStream *next_feed;
259 typedef struct FeedData {
260 long long data_count;
261 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
264 static struct sockaddr_in my_http_addr;
265 static struct sockaddr_in my_rtsp_addr;
267 static char logfilename[1024];
268 static HTTPContext *first_http_ctx;
269 static FFStream *first_feed; /* contains only feeds */
270 static FFStream *first_stream; /* contains all streams, including feeds */
272 static void new_connection(int server_fd, int is_rtsp);
273 static void close_connection(HTTPContext *c);
276 static int handle_connection(HTTPContext *c);
277 static int http_parse_request(HTTPContext *c);
278 static int http_send_data(HTTPContext *c);
279 static void compute_status(HTTPContext *c);
280 static int open_input_stream(HTTPContext *c, const char *info);
281 static int http_start_receive_data(HTTPContext *c);
282 static int http_receive_data(HTTPContext *c);
285 static int rtsp_parse_request(HTTPContext *c);
286 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
287 static void rtsp_cmd_options(HTTPContext *c, const char *url);
288 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
289 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
290 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only);
293 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
294 struct in_addr my_ip);
297 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
298 FFStream *stream, const char *session_id,
299 enum RTSPLowerTransport rtp_protocol);
300 static int rtp_new_av_stream(HTTPContext *c,
301 int stream_index, struct sockaddr_in *dest_addr,
302 HTTPContext *rtsp_c);
304 static const char *my_program_name;
306 static const char *config_filename;
308 static int ffserver_debug;
309 static int no_launch;
310 static int need_to_start_children;
312 /* maximum number of simultaneous HTTP connections */
313 static unsigned int nb_max_http_connections = 2000;
314 static unsigned int nb_max_connections = 5;
315 static unsigned int nb_connections;
317 static uint64_t max_bandwidth = 1000;
318 static uint64_t current_bandwidth;
320 static int64_t cur_time; // Making this global saves on passing it around everywhere
322 static AVLFG random_state;
324 static FILE *logfile = NULL;
326 static void htmlstrip(char *s) {
328 s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
334 static int64_t ffm_read_write_index(int fd)
338 if (lseek(fd, 8, SEEK_SET) < 0)
340 if (read(fd, buf, 8) != 8)
345 static int ffm_write_write_index(int fd, int64_t pos)
351 buf[i] = (pos >> (56 - i * 8)) & 0xff;
352 if (lseek(fd, 8, SEEK_SET) < 0)
354 if (write(fd, buf, 8) != 8)
359 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
362 FFMContext *ffm = s->priv_data;
363 ffm->write_index = pos;
364 ffm->file_size = file_size;
367 /* FIXME: make ffserver work with IPv6 */
368 /* resolve host with also IP address parsing */
369 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
372 if (!ff_inet_aton(hostname, sin_addr)) {
374 struct addrinfo *ai, *cur;
375 struct addrinfo hints = { 0 };
376 hints.ai_family = AF_INET;
377 if (getaddrinfo(hostname, NULL, &hints, &ai))
379 /* getaddrinfo returns a linked list of addrinfo structs.
380 * Even if we set ai_family = AF_INET above, make sure
381 * that the returned one actually is of the correct type. */
382 for (cur = ai; cur; cur = cur->ai_next) {
383 if (cur->ai_family == AF_INET) {
384 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
393 hp = gethostbyname(hostname);
396 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
402 static char *ctime1(char *buf2, int buf_size)
409 av_strlcpy(buf2, p, buf_size);
410 p = buf2 + strlen(p) - 1;
416 static void http_vlog(const char *fmt, va_list vargs)
418 static int print_prefix = 1;
422 ctime1(buf, sizeof(buf));
423 fprintf(logfile, "%s ", buf);
425 print_prefix = strstr(fmt, "\n") != NULL;
426 vfprintf(logfile, fmt, vargs);
432 __attribute__ ((format (printf, 1, 2)))
434 static void http_log(const char *fmt, ...)
437 va_start(vargs, fmt);
438 http_vlog(fmt, vargs);
442 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
444 static int print_prefix = 1;
445 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
446 if (level > av_log_get_level())
448 if (print_prefix && avc)
449 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
450 print_prefix = strstr(fmt, "\n") != NULL;
451 http_vlog(fmt, vargs);
454 static void log_connection(HTTPContext *c)
459 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
460 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
461 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
464 static void update_datarate(DataRateData *drd, int64_t count)
466 if (!drd->time1 && !drd->count1) {
467 drd->time1 = drd->time2 = cur_time;
468 drd->count1 = drd->count2 = count;
469 } else if (cur_time - drd->time2 > 5000) {
470 drd->time1 = drd->time2;
471 drd->count1 = drd->count2;
472 drd->time2 = cur_time;
477 /* In bytes per second */
478 static int compute_datarate(DataRateData *drd, int64_t count)
480 if (cur_time == drd->time1)
483 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
487 static void start_children(FFStream *feed)
492 for (; feed; feed = feed->next) {
493 if (feed->child_argv && !feed->pid) {
494 feed->pid_start = time(0);
499 http_log("Unable to create children\n");
508 /* replace "ffserver" with "ffmpeg" in the path of current
509 * program. Ignore user provided path */
510 av_strlcpy(pathname, my_program_name, sizeof(pathname));
511 slash = strrchr(pathname, '/');
516 strcpy(slash, "ffmpeg");
518 http_log("Launch command line: ");
519 http_log("%s ", pathname);
520 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
521 http_log("%s ", feed->child_argv[i]);
524 for (i = 3; i < 256; i++)
527 if (!ffserver_debug) {
528 if (!freopen("/dev/null", "r", stdin))
529 http_log("failed to redirect STDIN to /dev/null\n;");
530 if (!freopen("/dev/null", "w", stdout))
531 http_log("failed to redirect STDOUT to /dev/null\n;");
532 if (!freopen("/dev/null", "w", stderr))
533 http_log("failed to redirect STDERR to /dev/null\n;");
536 signal(SIGPIPE, SIG_DFL);
538 execvp(pathname, feed->child_argv);
546 /* open a listening socket */
547 static int socket_open_listen(struct sockaddr_in *my_addr)
551 server_fd = socket(AF_INET,SOCK_STREAM,0);
558 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
560 my_addr->sin_family = AF_INET;
561 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
563 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
565 closesocket(server_fd);
569 if (listen (server_fd, 5) < 0) {
571 closesocket(server_fd);
574 ff_socket_nonblock(server_fd, 1);
579 /* start all multicast streams */
580 static void start_multicast(void)
585 struct sockaddr_in dest_addr = {0};
586 int default_port, stream_index;
589 for(stream = first_stream; stream != NULL; stream = stream->next) {
590 if (stream->is_multicast) {
591 unsigned random0 = av_lfg_get(&random_state);
592 unsigned random1 = av_lfg_get(&random_state);
593 /* open the RTP connection */
594 snprintf(session_id, sizeof(session_id), "%08x%08x",
597 /* choose a port if none given */
598 if (stream->multicast_port == 0) {
599 stream->multicast_port = default_port;
603 dest_addr.sin_family = AF_INET;
604 dest_addr.sin_addr = stream->multicast_ip;
605 dest_addr.sin_port = htons(stream->multicast_port);
607 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
608 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
612 if (open_input_stream(rtp_c, "") < 0) {
613 http_log("Could not open input stream for stream '%s'\n",
618 /* open each RTP stream */
619 for(stream_index = 0; stream_index < stream->nb_streams;
621 dest_addr.sin_port = htons(stream->multicast_port +
623 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
624 http_log("Could not open output stream '%s/streamid=%d'\n",
625 stream->filename, stream_index);
630 rtp_c->state = HTTPSTATE_SEND_DATA;
635 /* main loop of the HTTP server */
636 static int http_server(void)
638 int server_fd = 0, rtsp_server_fd = 0;
640 struct pollfd *poll_table, *poll_entry;
641 HTTPContext *c, *c_next;
643 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
644 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
648 if (my_http_addr.sin_port) {
649 server_fd = socket_open_listen(&my_http_addr);
654 if (my_rtsp_addr.sin_port) {
655 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
656 if (rtsp_server_fd < 0)
660 if (!rtsp_server_fd && !server_fd) {
661 http_log("HTTP and RTSP disabled.\n");
665 http_log("FFserver started.\n");
667 start_children(first_feed);
672 poll_entry = poll_table;
674 poll_entry->fd = server_fd;
675 poll_entry->events = POLLIN;
678 if (rtsp_server_fd) {
679 poll_entry->fd = rtsp_server_fd;
680 poll_entry->events = POLLIN;
684 /* wait for events on each HTTP handle */
691 case HTTPSTATE_SEND_HEADER:
692 case RTSPSTATE_SEND_REPLY:
693 case RTSPSTATE_SEND_PACKET:
694 c->poll_entry = poll_entry;
696 poll_entry->events = POLLOUT;
699 case HTTPSTATE_SEND_DATA_HEADER:
700 case HTTPSTATE_SEND_DATA:
701 case HTTPSTATE_SEND_DATA_TRAILER:
702 if (!c->is_packetized) {
703 /* for TCP, we output as much as we can
704 * (may need to put a limit) */
705 c->poll_entry = poll_entry;
707 poll_entry->events = POLLOUT;
710 /* when ffserver is doing the timing, we work by
711 looking at which packet needs to be sent every
713 /* one tick wait XXX: 10 ms assumed */
718 case HTTPSTATE_WAIT_REQUEST:
719 case HTTPSTATE_RECEIVE_DATA:
720 case HTTPSTATE_WAIT_FEED:
721 case RTSPSTATE_WAIT_REQUEST:
722 /* need to catch errors */
723 c->poll_entry = poll_entry;
725 poll_entry->events = POLLIN;/* Maybe this will work */
729 c->poll_entry = NULL;
735 /* wait for an event on one connection. We poll at least every
736 second to handle timeouts */
738 ret = poll(poll_table, poll_entry - poll_table, delay);
739 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
740 ff_neterrno() != AVERROR(EINTR))
744 cur_time = av_gettime() / 1000;
746 if (need_to_start_children) {
747 need_to_start_children = 0;
748 start_children(first_feed);
751 /* now handle the events */
752 for(c = first_http_ctx; c != NULL; c = c_next) {
754 if (handle_connection(c) < 0) {
756 /* close and free the connection */
761 poll_entry = poll_table;
763 /* new HTTP connection request ? */
764 if (poll_entry->revents & POLLIN)
765 new_connection(server_fd, 0);
768 if (rtsp_server_fd) {
769 /* new RTSP connection request ? */
770 if (poll_entry->revents & POLLIN)
771 new_connection(rtsp_server_fd, 1);
776 /* start waiting for a new HTTP/RTSP request */
777 static void start_wait_request(HTTPContext *c, int is_rtsp)
779 c->buffer_ptr = c->buffer;
780 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
783 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
784 c->state = RTSPSTATE_WAIT_REQUEST;
786 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
787 c->state = HTTPSTATE_WAIT_REQUEST;
791 static void http_send_too_busy_reply(int fd)
794 int len = snprintf(buffer, sizeof(buffer),
795 "HTTP/1.0 503 Server too busy\r\n"
796 "Content-type: text/html\r\n"
798 "<html><head><title>Too busy</title></head><body>\r\n"
799 "<p>The server is too busy to serve your request at this time.</p>\r\n"
800 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
801 "</body></html>\r\n",
802 nb_connections, nb_max_connections);
803 av_assert0(len < sizeof(buffer));
804 send(fd, buffer, len, 0);
808 static void new_connection(int server_fd, int is_rtsp)
810 struct sockaddr_in from_addr;
813 HTTPContext *c = NULL;
815 len = sizeof(from_addr);
816 fd = accept(server_fd, (struct sockaddr *)&from_addr,
819 http_log("error during accept %s\n", strerror(errno));
822 ff_socket_nonblock(fd, 1);
824 if (nb_connections >= nb_max_connections) {
825 http_send_too_busy_reply(fd);
829 /* add a new connection */
830 c = av_mallocz(sizeof(HTTPContext));
835 c->poll_entry = NULL;
836 c->from_addr = from_addr;
837 c->buffer_size = IOBUFFER_INIT_SIZE;
838 c->buffer = av_malloc(c->buffer_size);
842 c->next = first_http_ctx;
846 start_wait_request(c, is_rtsp);
858 static void close_connection(HTTPContext *c)
860 HTTPContext **cp, *c1;
862 AVFormatContext *ctx;
866 /* remove connection from list */
867 cp = &first_http_ctx;
868 while ((*cp) != NULL) {
876 /* remove references, if any (XXX: do it faster) */
877 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
882 /* remove connection associated resources */
886 /* close each frame parser */
887 for(i=0;i<c->fmt_in->nb_streams;i++) {
888 st = c->fmt_in->streams[i];
889 if (st->codec->codec)
890 avcodec_close(st->codec);
892 avformat_close_input(&c->fmt_in);
895 /* free RTP output streams if any */
898 nb_streams = c->stream->nb_streams;
900 for(i=0;i<nb_streams;i++) {
903 av_write_trailer(ctx);
904 av_dict_free(&ctx->metadata);
905 av_free(ctx->streams[0]);
908 h = c->rtp_handles[i];
915 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
918 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
919 av_write_trailer(ctx);
920 av_freep(&c->pb_buffer);
921 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
926 for(i=0; i<ctx->nb_streams; i++)
927 av_free(ctx->streams[i]);
928 av_freep(&ctx->streams);
929 av_freep(&ctx->priv_data);
931 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
932 current_bandwidth -= c->stream->bandwidth;
934 /* signal that there is no feed if we are the feeder socket */
935 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
936 c->stream->feed_opened = 0;
940 av_freep(&c->pb_buffer);
941 av_freep(&c->packet_buffer);
947 static int handle_connection(HTTPContext *c)
952 case HTTPSTATE_WAIT_REQUEST:
953 case RTSPSTATE_WAIT_REQUEST:
955 if ((c->timeout - cur_time) < 0)
957 if (c->poll_entry->revents & (POLLERR | POLLHUP))
960 /* no need to read if no events */
961 if (!(c->poll_entry->revents & POLLIN))
965 len = recv(c->fd, c->buffer_ptr, 1, 0);
967 if (ff_neterrno() != AVERROR(EAGAIN) &&
968 ff_neterrno() != AVERROR(EINTR))
970 } else if (len == 0) {
973 /* search for end of request. */
975 c->buffer_ptr += len;
977 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
978 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
979 /* request found : parse it and reply */
980 if (c->state == HTTPSTATE_WAIT_REQUEST) {
981 ret = http_parse_request(c);
983 ret = rtsp_parse_request(c);
987 } else if (ptr >= c->buffer_end) {
988 /* request too long: cannot do anything */
990 } else goto read_loop;
994 case HTTPSTATE_SEND_HEADER:
995 if (c->poll_entry->revents & (POLLERR | POLLHUP))
998 /* no need to write if no events */
999 if (!(c->poll_entry->revents & POLLOUT))
1001 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1003 if (ff_neterrno() != AVERROR(EAGAIN) &&
1004 ff_neterrno() != AVERROR(EINTR)) {
1005 goto close_connection;
1008 c->buffer_ptr += len;
1010 c->stream->bytes_served += len;
1011 c->data_count += len;
1012 if (c->buffer_ptr >= c->buffer_end) {
1013 av_freep(&c->pb_buffer);
1014 /* if error, exit */
1017 /* all the buffer was sent : synchronize to the incoming
1019 c->state = HTTPSTATE_SEND_DATA_HEADER;
1020 c->buffer_ptr = c->buffer_end = c->buffer;
1025 case HTTPSTATE_SEND_DATA:
1026 case HTTPSTATE_SEND_DATA_HEADER:
1027 case HTTPSTATE_SEND_DATA_TRAILER:
1028 /* for packetized output, we consider we can always write (the
1029 input streams set the speed). It may be better to verify
1030 that we do not rely too much on the kernel queues */
1031 if (!c->is_packetized) {
1032 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1035 /* no need to read if no events */
1036 if (!(c->poll_entry->revents & POLLOUT))
1039 if (http_send_data(c) < 0)
1041 /* close connection if trailer sent */
1042 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1045 case HTTPSTATE_RECEIVE_DATA:
1046 /* no need to read if no events */
1047 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1049 if (!(c->poll_entry->revents & POLLIN))
1051 if (http_receive_data(c) < 0)
1054 case HTTPSTATE_WAIT_FEED:
1055 /* no need to read if no events */
1056 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1059 /* nothing to do, we'll be waken up by incoming feed packets */
1062 case RTSPSTATE_SEND_REPLY:
1063 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1064 goto close_connection;
1065 /* no need to write if no events */
1066 if (!(c->poll_entry->revents & POLLOUT))
1068 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1070 if (ff_neterrno() != AVERROR(EAGAIN) &&
1071 ff_neterrno() != AVERROR(EINTR)) {
1072 goto close_connection;
1075 c->buffer_ptr += len;
1076 c->data_count += len;
1077 if (c->buffer_ptr >= c->buffer_end) {
1078 /* all the buffer was sent : wait for a new request */
1079 av_freep(&c->pb_buffer);
1080 start_wait_request(c, 1);
1084 case RTSPSTATE_SEND_PACKET:
1085 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1086 av_freep(&c->packet_buffer);
1089 /* no need to write if no events */
1090 if (!(c->poll_entry->revents & POLLOUT))
1092 len = send(c->fd, c->packet_buffer_ptr,
1093 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1095 if (ff_neterrno() != AVERROR(EAGAIN) &&
1096 ff_neterrno() != AVERROR(EINTR)) {
1097 /* error : close connection */
1098 av_freep(&c->packet_buffer);
1102 c->packet_buffer_ptr += len;
1103 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1104 /* all the buffer was sent : wait for a new request */
1105 av_freep(&c->packet_buffer);
1106 c->state = RTSPSTATE_WAIT_REQUEST;
1110 case HTTPSTATE_READY:
1119 av_freep(&c->pb_buffer);
1123 static int extract_rates(char *rates, int ratelen, const char *request)
1127 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1128 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1129 const char *q = p + 7;
1131 while (*q && *q != '\n' && av_isspace(*q))
1134 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1140 memset(rates, 0xff, ratelen);
1143 while (*q && *q != '\n' && *q != ':')
1146 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1150 if (stream_no < ratelen && stream_no >= 0)
1151 rates[stream_no] = rate_no;
1153 while (*q && *q != '\n' && !av_isspace(*q))
1160 p = strchr(p, '\n');
1170 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1173 int best_bitrate = 100000000;
1176 for (i = 0; i < feed->nb_streams; i++) {
1177 AVCodecContext *feed_codec = feed->streams[i]->codec;
1179 if (feed_codec->codec_id != codec->codec_id ||
1180 feed_codec->sample_rate != codec->sample_rate ||
1181 feed_codec->width != codec->width ||
1182 feed_codec->height != codec->height)
1185 /* Potential stream */
1187 /* We want the fastest stream less than bit_rate, or the slowest
1188 * faster than bit_rate
1191 if (feed_codec->bit_rate <= bit_rate) {
1192 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1193 best_bitrate = feed_codec->bit_rate;
1197 if (feed_codec->bit_rate < best_bitrate) {
1198 best_bitrate = feed_codec->bit_rate;
1207 static int modify_current_stream(HTTPContext *c, char *rates)
1210 FFStream *req = c->stream;
1211 int action_required = 0;
1213 /* Not much we can do for a feed */
1217 for (i = 0; i < req->nb_streams; i++) {
1218 AVCodecContext *codec = req->streams[i]->codec;
1222 c->switch_feed_streams[i] = req->feed_streams[i];
1225 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1228 /* Wants off or slow */
1229 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1231 /* This doesn't work well when it turns off the only stream! */
1232 c->switch_feed_streams[i] = -2;
1233 c->feed_streams[i] = -2;
1238 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1239 action_required = 1;
1242 return action_required;
1245 /* XXX: factorize in utils.c ? */
1246 /* XXX: take care with different space meaning */
1247 static void skip_spaces(const char **pp)
1251 while (*p == ' ' || *p == '\t')
1256 static void get_word(char *buf, int buf_size, const char **pp)
1264 while (!av_isspace(*p) && *p != '\0') {
1265 if ((q - buf) < buf_size - 1)
1274 static void get_arg(char *buf, int buf_size, const char **pp)
1281 while (av_isspace(*p)) p++;
1284 if (*p == '\"' || *p == '\'')
1296 if ((q - buf) < buf_size - 1)
1301 if (quote && *p == quote)
1306 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1307 const char *p, const char *filename, int line_num)
1313 get_arg(arg, sizeof(arg), &p);
1314 if (av_strcasecmp(arg, "allow") == 0)
1315 acl.action = IP_ALLOW;
1316 else if (av_strcasecmp(arg, "deny") == 0)
1317 acl.action = IP_DENY;
1319 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1320 filename, line_num, arg);
1324 get_arg(arg, sizeof(arg), &p);
1326 if (resolve_host(&acl.first, arg) != 0) {
1327 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1328 filename, line_num, arg);
1331 acl.last = acl.first;
1333 get_arg(arg, sizeof(arg), &p);
1336 if (resolve_host(&acl.last, arg) != 0) {
1337 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1338 filename, line_num, arg);
1344 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1345 IPAddressACL **naclp = 0;
1351 naclp = &stream->acl;
1357 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1358 filename, line_num);
1364 naclp = &(*naclp)->next;
1372 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1377 IPAddressACL *acl = NULL;
1381 f = fopen(stream->dynamic_acl, "r");
1383 perror(stream->dynamic_acl);
1387 acl = av_mallocz(sizeof(IPAddressACL));
1391 if (fgets(line, sizeof(line), f) == NULL)
1395 while (av_isspace(*p))
1397 if (*p == '\0' || *p == '#')
1399 get_arg(cmd, sizeof(cmd), &p);
1401 if (!av_strcasecmp(cmd, "ACL"))
1402 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1409 static void free_acl_list(IPAddressACL *in_acl)
1411 IPAddressACL *pacl,*pacl2;
1421 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1423 enum IPAddressAction last_action = IP_DENY;
1425 struct in_addr *src = &c->from_addr.sin_addr;
1426 unsigned long src_addr = src->s_addr;
1428 for (acl = in_acl; acl; acl = acl->next) {
1429 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1430 return (acl->action == IP_ALLOW) ? 1 : 0;
1431 last_action = acl->action;
1434 /* Nothing matched, so return not the last action */
1435 return (last_action == IP_DENY) ? 1 : 0;
1438 static int validate_acl(FFStream *stream, HTTPContext *c)
1444 /* if stream->acl is null validate_acl_list will return 1 */
1445 ret = validate_acl_list(stream->acl, c);
1447 if (stream->dynamic_acl[0]) {
1448 acl = parse_dynamic_acl(stream, c);
1450 ret = validate_acl_list(acl, c);
1458 /* compute the real filename of a file by matching it without its
1459 extensions to all the stream's filenames */
1460 static void compute_real_filename(char *filename, int max_size)
1467 /* compute filename by matching without the file extensions */
1468 av_strlcpy(file1, filename, sizeof(file1));
1469 p = strrchr(file1, '.');
1472 for(stream = first_stream; stream != NULL; stream = stream->next) {
1473 av_strlcpy(file2, stream->filename, sizeof(file2));
1474 p = strrchr(file2, '.');
1477 if (!strcmp(file1, file2)) {
1478 av_strlcpy(filename, stream->filename, max_size);
1493 /* parse HTTP request and prepare header */
1494 static int http_parse_request(HTTPContext *c)
1498 enum RedirType redir_type;
1500 char info[1024], filename[1024];
1504 const char *mime_type;
1508 const char *useragent = 0;
1511 get_word(cmd, sizeof(cmd), &p);
1512 av_strlcpy(c->method, cmd, sizeof(c->method));
1514 if (!strcmp(cmd, "GET"))
1516 else if (!strcmp(cmd, "POST"))
1521 get_word(url, sizeof(url), &p);
1522 av_strlcpy(c->url, url, sizeof(c->url));
1524 get_word(protocol, sizeof(protocol), (const char **)&p);
1525 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1528 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1531 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1533 /* find the filename and the optional info string in the request */
1534 p1 = strchr(url, '?');
1536 av_strlcpy(info, p1, sizeof(info));
1541 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1543 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1544 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1546 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1550 p = strchr(p, '\n');
1557 redir_type = REDIR_NONE;
1558 if (av_match_ext(filename, "asx")) {
1559 redir_type = REDIR_ASX;
1560 filename[strlen(filename)-1] = 'f';
1561 } else if (av_match_ext(filename, "asf") &&
1562 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1563 /* if this isn't WMP or lookalike, return the redirector file */
1564 redir_type = REDIR_ASF;
1565 } else if (av_match_ext(filename, "rpm,ram")) {
1566 redir_type = REDIR_RAM;
1567 strcpy(filename + strlen(filename)-2, "m");
1568 } else if (av_match_ext(filename, "rtsp")) {
1569 redir_type = REDIR_RTSP;
1570 compute_real_filename(filename, sizeof(filename) - 1);
1571 } else if (av_match_ext(filename, "sdp")) {
1572 redir_type = REDIR_SDP;
1573 compute_real_filename(filename, sizeof(filename) - 1);
1576 // "redirect" / request to index.html
1577 if (!strlen(filename))
1578 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1580 stream = first_stream;
1581 while (stream != NULL) {
1582 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1584 stream = stream->next;
1586 if (stream == NULL) {
1587 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1588 http_log("File '%s' not found\n", url);
1593 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1594 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1596 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1597 c->http_error = 301;
1599 snprintf(q, c->buffer_size,
1600 "HTTP/1.0 301 Moved\r\n"
1602 "Content-type: text/html\r\n"
1604 "<html><head><title>Moved</title></head><body>\r\n"
1605 "You should be <a href=\"%s\">redirected</a>.\r\n"
1606 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1608 /* prepare output buffer */
1609 c->buffer_ptr = c->buffer;
1611 c->state = HTTPSTATE_SEND_HEADER;
1615 /* If this is WMP, get the rate information */
1616 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1617 if (modify_current_stream(c, ratebuf)) {
1618 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1619 if (c->switch_feed_streams[i] >= 0)
1620 c->switch_feed_streams[i] = -1;
1625 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1626 current_bandwidth += stream->bandwidth;
1628 /* If already streaming this feed, do not let start another feeder. */
1629 if (stream->feed_opened) {
1630 snprintf(msg, sizeof(msg), "This feed is already being received.");
1631 http_log("Feed '%s' already being received\n", stream->feed_filename);
1635 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1636 c->http_error = 503;
1638 snprintf(q, c->buffer_size,
1639 "HTTP/1.0 503 Server too busy\r\n"
1640 "Content-type: text/html\r\n"
1642 "<html><head><title>Too busy</title></head><body>\r\n"
1643 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1644 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1645 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1646 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1648 /* prepare output buffer */
1649 c->buffer_ptr = c->buffer;
1651 c->state = HTTPSTATE_SEND_HEADER;
1655 if (redir_type != REDIR_NONE) {
1656 const char *hostinfo = 0;
1658 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1659 if (av_strncasecmp(p, "Host:", 5) == 0) {
1663 p = strchr(p, '\n');
1674 while (av_isspace(*hostinfo))
1677 eoh = strchr(hostinfo, '\n');
1679 if (eoh[-1] == '\r')
1682 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1683 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1684 hostbuf[eoh - hostinfo] = 0;
1686 c->http_error = 200;
1688 switch(redir_type) {
1690 snprintf(q, c->buffer_size,
1691 "HTTP/1.0 200 ASX Follows\r\n"
1692 "Content-type: video/x-ms-asf\r\n"
1694 "<ASX Version=\"3\">\r\n"
1695 //"<!-- Autogenerated by ffserver -->\r\n"
1696 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1697 "</ASX>\r\n", hostbuf, filename, info);
1701 snprintf(q, c->buffer_size,
1702 "HTTP/1.0 200 RAM Follows\r\n"
1703 "Content-type: audio/x-pn-realaudio\r\n"
1705 "# Autogenerated by ffserver\r\n"
1706 "http://%s/%s%s\r\n", hostbuf, filename, info);
1710 snprintf(q, c->buffer_size,
1711 "HTTP/1.0 200 ASF Redirect follows\r\n"
1712 "Content-type: video/x-ms-asf\r\n"
1715 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1720 char hostname[256], *p;
1721 /* extract only hostname */
1722 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1723 p = strrchr(hostname, ':');
1726 snprintf(q, c->buffer_size,
1727 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1728 /* XXX: incorrect mime type ? */
1729 "Content-type: application/x-rtsp\r\n"
1731 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1740 struct sockaddr_in my_addr;
1742 snprintf(q, c->buffer_size,
1743 "HTTP/1.0 200 OK\r\n"
1744 "Content-type: application/sdp\r\n"
1748 len = sizeof(my_addr);
1749 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1751 /* XXX: should use a dynamic buffer */
1752 sdp_data_size = prepare_sdp_description(stream,
1755 if (sdp_data_size > 0) {
1756 memcpy(q, sdp_data, sdp_data_size);
1768 /* prepare output buffer */
1769 c->buffer_ptr = c->buffer;
1771 c->state = HTTPSTATE_SEND_HEADER;
1777 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1781 stream->conns_served++;
1783 /* XXX: add there authenticate and IP match */
1786 /* if post, it means a feed is being sent */
1787 if (!stream->is_feed) {
1788 /* However it might be a status report from WMP! Let us log the
1789 * data as it might come in handy one day. */
1790 const char *logline = 0;
1793 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1794 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1798 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1799 client_id = strtol(p + 18, 0, 10);
1800 p = strchr(p, '\n');
1808 char *eol = strchr(logline, '\n');
1813 if (eol[-1] == '\r')
1815 http_log("%.*s\n", (int) (eol - logline), logline);
1816 c->suppress_log = 1;
1821 http_log("\nGot request:\n%s\n", c->buffer);
1824 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1827 /* Now we have to find the client_id */
1828 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1829 if (wmpc->wmp_client_id == client_id)
1833 if (wmpc && modify_current_stream(wmpc, ratebuf))
1834 wmpc->switch_pending = 1;
1837 snprintf(msg, sizeof(msg), "POST command not handled");
1841 if (http_start_receive_data(c) < 0) {
1842 snprintf(msg, sizeof(msg), "could not open feed");
1846 c->state = HTTPSTATE_RECEIVE_DATA;
1851 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1852 http_log("\nGot request:\n%s\n", c->buffer);
1855 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1858 /* open input stream */
1859 if (open_input_stream(c, info) < 0) {
1860 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1864 /* prepare HTTP header */
1866 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1867 mime_type = c->stream->fmt->mime_type;
1869 mime_type = "application/x-octet-stream";
1870 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1872 /* for asf, we need extra headers */
1873 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1874 /* Need to allocate a client id */
1876 c->wmp_client_id = av_lfg_get(&random_state);
1878 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);
1880 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1881 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1882 q = c->buffer + strlen(c->buffer);
1884 /* prepare output buffer */
1886 c->buffer_ptr = c->buffer;
1888 c->state = HTTPSTATE_SEND_HEADER;
1891 c->http_error = 404;
1894 snprintf(q, c->buffer_size,
1895 "HTTP/1.0 404 Not Found\r\n"
1896 "Content-type: text/html\r\n"
1899 "<head><title>404 Not Found</title></head>\n"
1903 /* prepare output buffer */
1904 c->buffer_ptr = c->buffer;
1906 c->state = HTTPSTATE_SEND_HEADER;
1910 c->http_error = 200; /* horrible : we use this value to avoid
1911 going to the send data state */
1912 c->state = HTTPSTATE_SEND_HEADER;
1916 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1918 static const char suffix[] = " kMGTP";
1921 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1923 avio_printf(pb, "%"PRId64"%c", count, *s);
1926 static void compute_status(HTTPContext *c)
1935 if (avio_open_dyn_buf(&pb) < 0) {
1936 /* XXX: return an error ? */
1937 c->buffer_ptr = c->buffer;
1938 c->buffer_end = c->buffer;
1942 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1943 avio_printf(pb, "Content-type: text/html\r\n");
1944 avio_printf(pb, "Pragma: no-cache\r\n");
1945 avio_printf(pb, "\r\n");
1947 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1948 if (c->stream->feed_filename[0])
1949 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1950 avio_printf(pb, "</head>\n<body>");
1951 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1953 avio_printf(pb, "<h2>Available Streams</h2>\n");
1954 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1955 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");
1956 stream = first_stream;
1957 while (stream != NULL) {
1958 char sfilename[1024];
1961 if (stream->feed != stream) {
1962 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1963 eosf = sfilename + strlen(sfilename);
1964 if (eosf - sfilename >= 4) {
1965 if (strcmp(eosf - 4, ".asf") == 0)
1966 strcpy(eosf - 4, ".asx");
1967 else if (strcmp(eosf - 3, ".rm") == 0)
1968 strcpy(eosf - 3, ".ram");
1969 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1970 /* generate a sample RTSP director if
1971 unicast. Generate an SDP redirector if
1973 eosf = strrchr(sfilename, '.');
1975 eosf = sfilename + strlen(sfilename);
1976 if (stream->is_multicast)
1977 strcpy(eosf, ".sdp");
1979 strcpy(eosf, ".rtsp");
1983 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1984 sfilename, stream->filename);
1985 avio_printf(pb, "<td align=right> %d <td align=right> ",
1986 stream->conns_served);
1987 fmt_bytecount(pb, stream->bytes_served);
1988 switch(stream->stream_type) {
1989 case STREAM_TYPE_LIVE: {
1990 int audio_bit_rate = 0;
1991 int video_bit_rate = 0;
1992 const char *audio_codec_name = "";
1993 const char *video_codec_name = "";
1994 const char *audio_codec_name_extra = "";
1995 const char *video_codec_name_extra = "";
1997 for(i=0;i<stream->nb_streams;i++) {
1998 AVStream *st = stream->streams[i];
1999 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2000 switch(st->codec->codec_type) {
2001 case AVMEDIA_TYPE_AUDIO:
2002 audio_bit_rate += st->codec->bit_rate;
2004 if (*audio_codec_name)
2005 audio_codec_name_extra = "...";
2006 audio_codec_name = codec->name;
2009 case AVMEDIA_TYPE_VIDEO:
2010 video_bit_rate += st->codec->bit_rate;
2012 if (*video_codec_name)
2013 video_codec_name_extra = "...";
2014 video_codec_name = codec->name;
2017 case AVMEDIA_TYPE_DATA:
2018 video_bit_rate += st->codec->bit_rate;
2024 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",
2027 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2028 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2030 avio_printf(pb, "<td>%s", stream->feed->filename);
2032 avio_printf(pb, "<td>%s", stream->feed_filename);
2033 avio_printf(pb, "\n");
2037 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2041 stream = stream->next;
2043 avio_printf(pb, "</table>\n");
2045 stream = first_stream;
2046 while (stream != NULL) {
2047 if (stream->feed == stream) {
2048 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2050 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2057 /* This is somewhat linux specific I guess */
2058 snprintf(ps_cmd, sizeof(ps_cmd),
2059 "ps -o \"%%cpu,cputime\" --no-headers %d",
2062 pid_stat = popen(ps_cmd, "r");
2067 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2069 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2077 avio_printf(pb, "<p>");
2079 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");
2081 for (i = 0; i < stream->nb_streams; i++) {
2082 AVStream *st = stream->streams[i];
2083 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2084 const char *type = "unknown";
2085 char parameters[64];
2089 switch(st->codec->codec_type) {
2090 case AVMEDIA_TYPE_AUDIO:
2092 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2094 case AVMEDIA_TYPE_VIDEO:
2096 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2097 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2102 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2103 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2105 avio_printf(pb, "</table>\n");
2108 stream = stream->next;
2111 /* connection status */
2112 avio_printf(pb, "<h2>Connection Status</h2>\n");
2114 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2115 nb_connections, nb_max_connections);
2117 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2118 current_bandwidth, max_bandwidth);
2120 avio_printf(pb, "<table>\n");
2121 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");
2122 c1 = first_http_ctx;
2124 while (c1 != NULL) {
2130 for (j = 0; j < c1->stream->nb_streams; j++) {
2131 if (!c1->stream->feed)
2132 bitrate += c1->stream->streams[j]->codec->bit_rate;
2133 else if (c1->feed_streams[j] >= 0)
2134 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2139 p = inet_ntoa(c1->from_addr.sin_addr);
2140 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2142 c1->stream ? c1->stream->filename : "",
2143 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2146 http_state[c1->state]);
2147 fmt_bytecount(pb, bitrate);
2148 avio_printf(pb, "<td align=right>");
2149 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2150 avio_printf(pb, "<td align=right>");
2151 fmt_bytecount(pb, c1->data_count);
2152 avio_printf(pb, "\n");
2155 avio_printf(pb, "</table>\n");
2160 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2161 avio_printf(pb, "</body>\n</html>\n");
2163 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2164 c->buffer_ptr = c->pb_buffer;
2165 c->buffer_end = c->pb_buffer + len;
2168 static int open_input_stream(HTTPContext *c, const char *info)
2171 char input_filename[1024];
2172 AVFormatContext *s = NULL;
2173 int buf_size, i, ret;
2176 /* find file name */
2177 if (c->stream->feed) {
2178 strcpy(input_filename, c->stream->feed->feed_filename);
2179 buf_size = FFM_PACKET_SIZE;
2180 /* compute position (absolute time) */
2181 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2182 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2183 http_log("Invalid date specification '%s' for stream\n", buf);
2186 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2187 int prebuffer = strtol(buf, 0, 10);
2188 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2190 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2192 strcpy(input_filename, c->stream->feed_filename);
2194 /* compute position (relative time) */
2195 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2196 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2197 http_log("Invalid date specification '%s' for stream\n", buf);
2203 if (!input_filename[0]) {
2204 http_log("No filename was specified for stream\n");
2205 return AVERROR(EINVAL);
2209 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2210 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2214 /* set buffer size */
2215 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2217 s->flags |= AVFMT_FLAG_GENPTS;
2219 if (strcmp(s->iformat->name, "ffm") &&
2220 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2221 http_log("Could not find stream info for input '%s'\n", input_filename);
2222 avformat_close_input(&s);
2226 /* choose stream as clock source (we favor the video stream if
2227 * present) for packet sending */
2228 c->pts_stream_index = 0;
2229 for(i=0;i<c->stream->nb_streams;i++) {
2230 if (c->pts_stream_index == 0 &&
2231 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2232 c->pts_stream_index = i;
2236 if (c->fmt_in->iformat->read_seek)
2237 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2238 /* set the start time (needed for maxtime and RTP packet timing) */
2239 c->start_time = cur_time;
2240 c->first_pts = AV_NOPTS_VALUE;
2244 /* return the server clock (in us) */
2245 static int64_t get_server_clock(HTTPContext *c)
2247 /* compute current pts value from system time */
2248 return (cur_time - c->start_time) * 1000;
2251 /* return the estimated time at which the current packet must be sent
2253 static int64_t get_packet_send_clock(HTTPContext *c)
2255 int bytes_left, bytes_sent, frame_bytes;
2257 frame_bytes = c->cur_frame_bytes;
2258 if (frame_bytes <= 0)
2261 bytes_left = c->buffer_end - c->buffer_ptr;
2262 bytes_sent = frame_bytes - bytes_left;
2263 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2268 static int http_prepare_data(HTTPContext *c)
2271 AVFormatContext *ctx;
2273 av_freep(&c->pb_buffer);
2275 case HTTPSTATE_SEND_DATA_HEADER:
2276 ctx = avformat_alloc_context();
2279 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2280 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2282 for(i=0;i<c->stream->nb_streams;i++) {
2284 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2285 /* if file or feed, then just take streams from FFStream struct */
2286 if (!c->stream->feed ||
2287 c->stream->feed == c->stream)
2288 src = c->stream->streams[i];
2290 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2292 *(c->fmt_ctx.streams[i]) = *src;
2293 c->fmt_ctx.streams[i]->priv_data = 0;
2294 /* XXX: should be done in AVStream, not in codec */
2295 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2297 /* set output format parameters */
2298 c->fmt_ctx.oformat = c->stream->fmt;
2299 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2301 c->got_key_frame = 0;
2303 /* prepare header and save header data in a stream */
2304 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2305 /* XXX: potential leak */
2308 c->fmt_ctx.pb->seekable = 0;
2311 * HACK to avoid mpeg ps muxer to spit many underflow errors
2312 * Default value from FFmpeg
2313 * Try to set it using configuration option
2315 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2317 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2318 http_log("Error writing output header for stream '%s': %s\n",
2319 c->stream->filename, av_err2str(ret));
2322 av_dict_free(&c->fmt_ctx.metadata);
2324 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2325 c->buffer_ptr = c->pb_buffer;
2326 c->buffer_end = c->pb_buffer + len;
2328 c->state = HTTPSTATE_SEND_DATA;
2329 c->last_packet_sent = 0;
2331 case HTTPSTATE_SEND_DATA:
2332 /* find a new packet */
2333 /* read a packet from the input stream */
2334 if (c->stream->feed)
2335 ffm_set_write_index(c->fmt_in,
2336 c->stream->feed->feed_write_index,
2337 c->stream->feed->feed_size);
2339 if (c->stream->max_time &&
2340 c->stream->max_time + c->start_time - cur_time < 0)
2341 /* We have timed out */
2342 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2346 ret = av_read_frame(c->fmt_in, &pkt);
2348 if (c->stream->feed) {
2349 /* if coming from feed, it means we reached the end of the
2350 ffm file, so must wait for more data */
2351 c->state = HTTPSTATE_WAIT_FEED;
2352 return 1; /* state changed */
2353 } else if (ret == AVERROR(EAGAIN)) {
2354 /* input not ready, come back later */
2357 if (c->stream->loop) {
2358 avformat_close_input(&c->fmt_in);
2359 if (open_input_stream(c, "") < 0)
2364 /* must send trailer now because EOF or error */
2365 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2369 int source_index = pkt.stream_index;
2370 /* update first pts if needed */
2371 if (c->first_pts == AV_NOPTS_VALUE) {
2372 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2373 c->start_time = cur_time;
2375 /* send it to the appropriate stream */
2376 if (c->stream->feed) {
2377 /* if coming from a feed, select the right stream */
2378 if (c->switch_pending) {
2379 c->switch_pending = 0;
2380 for(i=0;i<c->stream->nb_streams;i++) {
2381 if (c->switch_feed_streams[i] == pkt.stream_index)
2382 if (pkt.flags & AV_PKT_FLAG_KEY)
2383 c->switch_feed_streams[i] = -1;
2384 if (c->switch_feed_streams[i] >= 0)
2385 c->switch_pending = 1;
2388 for(i=0;i<c->stream->nb_streams;i++) {
2389 if (c->stream->feed_streams[i] == pkt.stream_index) {
2390 AVStream *st = c->fmt_in->streams[source_index];
2391 pkt.stream_index = i;
2392 if (pkt.flags & AV_PKT_FLAG_KEY &&
2393 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2394 c->stream->nb_streams == 1))
2395 c->got_key_frame = 1;
2396 if (!c->stream->send_on_key || c->got_key_frame)
2401 AVCodecContext *codec;
2402 AVStream *ist, *ost;
2404 ist = c->fmt_in->streams[source_index];
2405 /* specific handling for RTP: we use several
2406 * output streams (one for each RTP connection).
2407 * XXX: need more abstract handling */
2408 if (c->is_packetized) {
2409 /* compute send time and duration */
2410 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2411 c->cur_pts -= c->first_pts;
2412 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2413 /* find RTP context */
2414 c->packet_stream_index = pkt.stream_index;
2415 ctx = c->rtp_ctx[c->packet_stream_index];
2417 av_free_packet(&pkt);
2420 codec = ctx->streams[0]->codec;
2421 /* only one stream per RTP connection */
2422 pkt.stream_index = 0;
2426 codec = ctx->streams[pkt.stream_index]->codec;
2429 if (c->is_packetized) {
2430 int max_packet_size;
2431 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2432 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2434 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2435 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2437 ret = avio_open_dyn_buf(&ctx->pb);
2440 /* XXX: potential leak */
2443 ost = ctx->streams[pkt.stream_index];
2445 ctx->pb->seekable = 0;
2446 if (pkt.dts != AV_NOPTS_VALUE)
2447 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2448 if (pkt.pts != AV_NOPTS_VALUE)
2449 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2450 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2451 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2452 http_log("Error writing frame to output for stream '%s': %s\n",
2453 c->stream->filename, av_err2str(ret));
2454 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2457 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2458 c->cur_frame_bytes = len;
2459 c->buffer_ptr = c->pb_buffer;
2460 c->buffer_end = c->pb_buffer + len;
2462 codec->frame_number++;
2464 av_free_packet(&pkt);
2468 av_free_packet(&pkt);
2473 case HTTPSTATE_SEND_DATA_TRAILER:
2474 /* last packet test ? */
2475 if (c->last_packet_sent || c->is_packetized)
2478 /* prepare header */
2479 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2480 /* XXX: potential leak */
2483 c->fmt_ctx.pb->seekable = 0;
2484 av_write_trailer(ctx);
2485 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2486 c->buffer_ptr = c->pb_buffer;
2487 c->buffer_end = c->pb_buffer + len;
2489 c->last_packet_sent = 1;
2495 /* should convert the format at the same time */
2496 /* send data starting at c->buffer_ptr to the output connection
2497 * (either UDP or TCP) */
2498 static int http_send_data(HTTPContext *c)
2503 if (c->buffer_ptr >= c->buffer_end) {
2504 ret = http_prepare_data(c);
2508 /* state change requested */
2511 if (c->is_packetized) {
2512 /* RTP data output */
2513 len = c->buffer_end - c->buffer_ptr;
2515 /* fail safe - should never happen */
2517 c->buffer_ptr = c->buffer_end;
2520 len = (c->buffer_ptr[0] << 24) |
2521 (c->buffer_ptr[1] << 16) |
2522 (c->buffer_ptr[2] << 8) |
2524 if (len > (c->buffer_end - c->buffer_ptr))
2526 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2527 /* nothing to send yet: we can wait */
2531 c->data_count += len;
2532 update_datarate(&c->datarate, c->data_count);
2534 c->stream->bytes_served += len;
2536 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2537 /* RTP packets are sent inside the RTSP TCP connection */
2539 int interleaved_index, size;
2541 HTTPContext *rtsp_c;
2544 /* if no RTSP connection left, error */
2547 /* if already sending something, then wait. */
2548 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2550 if (avio_open_dyn_buf(&pb) < 0)
2552 interleaved_index = c->packet_stream_index * 2;
2553 /* RTCP packets are sent at odd indexes */
2554 if (c->buffer_ptr[1] == 200)
2555 interleaved_index++;
2556 /* write RTSP TCP header */
2558 header[1] = interleaved_index;
2559 header[2] = len >> 8;
2561 avio_write(pb, header, 4);
2562 /* write RTP packet data */
2564 avio_write(pb, c->buffer_ptr, len);
2565 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2566 /* prepare asynchronous TCP sending */
2567 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2568 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2569 c->buffer_ptr += len;
2571 /* send everything we can NOW */
2572 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2573 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2575 rtsp_c->packet_buffer_ptr += len;
2576 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2577 /* if we could not send all the data, we will
2578 send it later, so a new state is needed to
2579 "lock" the RTSP TCP connection */
2580 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2583 /* all data has been sent */
2584 av_freep(&c->packet_buffer);
2586 /* send RTP packet directly in UDP */
2588 ffurl_write(c->rtp_handles[c->packet_stream_index],
2589 c->buffer_ptr, len);
2590 c->buffer_ptr += len;
2591 /* here we continue as we can send several packets per 10 ms slot */
2594 /* TCP data output */
2595 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2597 if (ff_neterrno() != AVERROR(EAGAIN) &&
2598 ff_neterrno() != AVERROR(EINTR))
2599 /* error : close connection */
2604 c->buffer_ptr += len;
2606 c->data_count += len;
2607 update_datarate(&c->datarate, c->data_count);
2609 c->stream->bytes_served += len;
2617 static int http_start_receive_data(HTTPContext *c)
2622 if (c->stream->feed_opened) {
2623 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2624 return AVERROR(EINVAL);
2627 /* Don't permit writing to this one */
2628 if (c->stream->readonly) {
2629 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2630 return AVERROR(EINVAL);
2634 fd = open(c->stream->feed_filename, O_RDWR);
2636 ret = AVERROR(errno);
2637 http_log("Could not open feed file '%s': %s\n",
2638 c->stream->feed_filename, strerror(errno));
2643 if (c->stream->truncate) {
2644 /* truncate feed file */
2645 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2646 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2647 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2648 ret = AVERROR(errno);
2649 http_log("Error truncating feed file '%s': %s\n",
2650 c->stream->feed_filename, strerror(errno));
2654 ret = ffm_read_write_index(fd);
2656 http_log("Error reading write index from feed file '%s': %s\n",
2657 c->stream->feed_filename, strerror(errno));
2660 c->stream->feed_write_index = ret;
2664 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2665 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2666 lseek(fd, 0, SEEK_SET);
2668 /* init buffer input */
2669 c->buffer_ptr = c->buffer;
2670 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2671 c->stream->feed_opened = 1;
2672 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2676 static int http_receive_data(HTTPContext *c)
2679 int len, loop_run = 0;
2681 while (c->chunked_encoding && !c->chunk_size &&
2682 c->buffer_end > c->buffer_ptr) {
2683 /* read chunk header, if present */
2684 len = recv(c->fd, c->buffer_ptr, 1, 0);
2687 if (ff_neterrno() != AVERROR(EAGAIN) &&
2688 ff_neterrno() != AVERROR(EINTR))
2689 /* error : close connection */
2692 } else if (len == 0) {
2693 /* end of connection : close it */
2695 } else if (c->buffer_ptr - c->buffer >= 2 &&
2696 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2697 c->chunk_size = strtol(c->buffer, 0, 16);
2698 if (c->chunk_size == 0) // end of stream
2700 c->buffer_ptr = c->buffer;
2702 } else if (++loop_run > 10) {
2703 /* no chunk header, abort */
2710 if (c->buffer_end > c->buffer_ptr) {
2711 len = recv(c->fd, c->buffer_ptr,
2712 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2714 if (ff_neterrno() != AVERROR(EAGAIN) &&
2715 ff_neterrno() != AVERROR(EINTR))
2716 /* error : close connection */
2718 } else if (len == 0)
2719 /* end of connection : close it */
2722 c->chunk_size -= len;
2723 c->buffer_ptr += len;
2724 c->data_count += len;
2725 update_datarate(&c->datarate, c->data_count);
2729 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2730 if (c->buffer[0] != 'f' ||
2731 c->buffer[1] != 'm') {
2732 http_log("Feed stream has become desynchronized -- disconnecting\n");
2737 if (c->buffer_ptr >= c->buffer_end) {
2738 FFStream *feed = c->stream;
2739 /* a packet has been received : write it in the store, except
2741 if (c->data_count > FFM_PACKET_SIZE) {
2742 /* XXX: use llseek or url_seek */
2743 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2744 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2745 http_log("Error writing to feed file: %s\n", strerror(errno));
2749 feed->feed_write_index += FFM_PACKET_SIZE;
2750 /* update file size */
2751 if (feed->feed_write_index > c->stream->feed_size)
2752 feed->feed_size = feed->feed_write_index;
2754 /* handle wrap around if max file size reached */
2755 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2756 feed->feed_write_index = FFM_PACKET_SIZE;
2759 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2760 http_log("Error writing index to feed file: %s\n", strerror(errno));
2764 /* wake up any waiting connections */
2765 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2766 if (c1->state == HTTPSTATE_WAIT_FEED &&
2767 c1->stream->feed == c->stream->feed)
2768 c1->state = HTTPSTATE_SEND_DATA;
2771 /* We have a header in our hands that contains useful data */
2772 AVFormatContext *s = avformat_alloc_context();
2774 AVInputFormat *fmt_in;
2780 /* use feed output format name to find corresponding input format */
2781 fmt_in = av_find_input_format(feed->fmt->name);
2785 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2786 0, NULL, NULL, NULL, NULL);
2790 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2795 /* Now we have the actual streams */
2796 if (s->nb_streams != feed->nb_streams) {
2797 avformat_close_input(&s);
2799 http_log("Feed '%s' stream number does not match registered feed\n",
2800 c->stream->feed_filename);
2804 for (i = 0; i < s->nb_streams; i++) {
2805 AVStream *fst = feed->streams[i];
2806 AVStream *st = s->streams[i];
2807 avcodec_copy_context(fst->codec, st->codec);
2810 avformat_close_input(&s);
2813 c->buffer_ptr = c->buffer;
2818 c->stream->feed_opened = 0;
2820 /* wake up any waiting connections to stop waiting for feed */
2821 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2822 if (c1->state == HTTPSTATE_WAIT_FEED &&
2823 c1->stream->feed == c->stream->feed)
2824 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2829 /********************************************************************/
2832 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2839 switch(error_number) {
2840 case RTSP_STATUS_OK:
2843 case RTSP_STATUS_METHOD:
2844 str = "Method Not Allowed";
2846 case RTSP_STATUS_BANDWIDTH:
2847 str = "Not Enough Bandwidth";
2849 case RTSP_STATUS_SESSION:
2850 str = "Session Not Found";
2852 case RTSP_STATUS_STATE:
2853 str = "Method Not Valid in This State";
2855 case RTSP_STATUS_AGGREGATE:
2856 str = "Aggregate operation not allowed";
2858 case RTSP_STATUS_ONLY_AGGREGATE:
2859 str = "Only aggregate operation allowed";
2861 case RTSP_STATUS_TRANSPORT:
2862 str = "Unsupported transport";
2864 case RTSP_STATUS_INTERNAL:
2865 str = "Internal Server Error";
2867 case RTSP_STATUS_SERVICE:
2868 str = "Service Unavailable";
2870 case RTSP_STATUS_VERSION:
2871 str = "RTSP Version not supported";
2874 str = "Unknown Error";
2878 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2879 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2881 /* output GMT time */
2884 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2885 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2888 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2890 rtsp_reply_header(c, error_number);
2891 avio_printf(c->pb, "\r\n");
2894 static int rtsp_parse_request(HTTPContext *c)
2896 const char *p, *p1, *p2;
2902 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2904 c->buffer_ptr[0] = '\0';
2907 get_word(cmd, sizeof(cmd), &p);
2908 get_word(url, sizeof(url), &p);
2909 get_word(protocol, sizeof(protocol), &p);
2911 av_strlcpy(c->method, cmd, sizeof(c->method));
2912 av_strlcpy(c->url, url, sizeof(c->url));
2913 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2915 if (avio_open_dyn_buf(&c->pb) < 0) {
2916 /* XXX: cannot do more */
2917 c->pb = NULL; /* safety */
2921 /* check version name */
2922 if (strcmp(protocol, "RTSP/1.0") != 0) {
2923 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2927 /* parse each header line */
2928 /* skip to next line */
2929 while (*p != '\n' && *p != '\0')
2933 while (*p != '\0') {
2934 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2938 if (p2 > p && p2[-1] == '\r')
2940 /* skip empty line */
2944 if (len > sizeof(line) - 1)
2945 len = sizeof(line) - 1;
2946 memcpy(line, p, len);
2948 ff_rtsp_parse_line(header, line, NULL, NULL);
2952 /* handle sequence number */
2953 c->seq = header->seq;
2955 if (!strcmp(cmd, "DESCRIBE"))
2956 rtsp_cmd_describe(c, url);
2957 else if (!strcmp(cmd, "OPTIONS"))
2958 rtsp_cmd_options(c, url);
2959 else if (!strcmp(cmd, "SETUP"))
2960 rtsp_cmd_setup(c, url, header);
2961 else if (!strcmp(cmd, "PLAY"))
2962 rtsp_cmd_play(c, url, header);
2963 else if (!strcmp(cmd, "PAUSE"))
2964 rtsp_cmd_interrupt(c, url, header, 1);
2965 else if (!strcmp(cmd, "TEARDOWN"))
2966 rtsp_cmd_interrupt(c, url, header, 0);
2968 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2971 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2972 c->pb = NULL; /* safety */
2974 /* XXX: cannot do more */
2977 c->buffer_ptr = c->pb_buffer;
2978 c->buffer_end = c->pb_buffer + len;
2979 c->state = RTSPSTATE_SEND_REPLY;
2983 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2984 struct in_addr my_ip)
2986 AVFormatContext *avc;
2987 AVStream *avs = NULL;
2988 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2989 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2992 avc = avformat_alloc_context();
2993 if (avc == NULL || !rtp_format) {
2996 avc->oformat = rtp_format;
2997 av_dict_set(&avc->metadata, "title",
2998 entry ? entry->value : "No Title", 0);
2999 avc->nb_streams = stream->nb_streams;
3000 if (stream->is_multicast) {
3001 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
3002 inet_ntoa(stream->multicast_ip),
3003 stream->multicast_port, stream->multicast_ttl);
3005 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
3008 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
3009 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
3011 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
3012 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
3015 for(i = 0; i < stream->nb_streams; i++) {
3016 avc->streams[i] = &avs[i];
3017 avc->streams[i]->codec = stream->streams[i]->codec;
3019 *pbuffer = av_mallocz(2048);
3020 av_sdp_create(&avc, 1, *pbuffer, 2048);
3023 av_free(avc->streams);
3024 av_dict_free(&avc->metadata);
3028 return strlen(*pbuffer);
3031 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3033 // rtsp_reply_header(c, RTSP_STATUS_OK);
3034 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3035 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3036 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3037 avio_printf(c->pb, "\r\n");
3040 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3048 struct sockaddr_in my_addr;
3050 /* find which url is asked */
3051 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3056 for(stream = first_stream; stream != NULL; stream = stream->next) {
3057 if (!stream->is_feed &&
3058 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3059 !strcmp(path, stream->filename)) {
3063 /* no stream found */
3064 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3068 /* prepare the media description in sdp format */
3070 /* get the host IP */
3071 len = sizeof(my_addr);
3072 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3073 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3074 if (content_length < 0) {
3075 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3078 rtsp_reply_header(c, RTSP_STATUS_OK);
3079 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3080 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3081 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3082 avio_printf(c->pb, "\r\n");
3083 avio_write(c->pb, content, content_length);
3087 static HTTPContext *find_rtp_session(const char *session_id)
3091 if (session_id[0] == '\0')
3094 for(c = first_http_ctx; c != NULL; c = c->next) {
3095 if (!strcmp(c->session_id, session_id))
3101 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3103 RTSPTransportField *th;
3106 for(i=0;i<h->nb_transports;i++) {
3107 th = &h->transports[i];
3108 if (th->lower_transport == lower_transport)
3114 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3115 RTSPMessageHeader *h)
3118 int stream_index, rtp_port, rtcp_port;
3123 RTSPTransportField *th;
3124 struct sockaddr_in dest_addr;
3125 RTSPActionServerSetup setup;
3127 /* find which url is asked */
3128 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3133 /* now check each stream */
3134 for(stream = first_stream; stream != NULL; stream = stream->next) {
3135 if (!stream->is_feed &&
3136 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3137 /* accept aggregate filenames only if single stream */
3138 if (!strcmp(path, stream->filename)) {
3139 if (stream->nb_streams != 1) {
3140 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3147 for(stream_index = 0; stream_index < stream->nb_streams;
3149 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3150 stream->filename, stream_index);
3151 if (!strcmp(path, buf))
3156 /* no stream found */
3157 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3161 /* generate session id if needed */
3162 if (h->session_id[0] == '\0') {
3163 unsigned random0 = av_lfg_get(&random_state);
3164 unsigned random1 = av_lfg_get(&random_state);
3165 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3169 /* find rtp session, and create it if none found */
3170 rtp_c = find_rtp_session(h->session_id);
3172 /* always prefer UDP */
3173 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3175 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3177 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3182 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3183 th->lower_transport);
3185 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3189 /* open input stream */
3190 if (open_input_stream(rtp_c, "") < 0) {
3191 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3196 /* test if stream is OK (test needed because several SETUP needs
3197 to be done for a given file) */
3198 if (rtp_c->stream != stream) {
3199 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3203 /* test if stream is already set up */
3204 if (rtp_c->rtp_ctx[stream_index]) {
3205 rtsp_reply_error(c, RTSP_STATUS_STATE);
3209 /* check transport */
3210 th = find_transport(h, rtp_c->rtp_protocol);
3211 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3212 th->client_port_min <= 0)) {
3213 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3217 /* setup default options */
3218 setup.transport_option[0] = '\0';
3219 dest_addr = rtp_c->from_addr;
3220 dest_addr.sin_port = htons(th->client_port_min);
3223 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3224 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3228 /* now everything is OK, so we can send the connection parameters */
3229 rtsp_reply_header(c, RTSP_STATUS_OK);
3231 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3233 switch(rtp_c->rtp_protocol) {
3234 case RTSP_LOWER_TRANSPORT_UDP:
3235 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3236 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3237 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3238 "client_port=%d-%d;server_port=%d-%d",
3239 th->client_port_min, th->client_port_max,
3240 rtp_port, rtcp_port);
3242 case RTSP_LOWER_TRANSPORT_TCP:
3243 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3244 stream_index * 2, stream_index * 2 + 1);
3249 if (setup.transport_option[0] != '\0')
3250 avio_printf(c->pb, ";%s", setup.transport_option);
3251 avio_printf(c->pb, "\r\n");
3254 avio_printf(c->pb, "\r\n");
3258 /* find an rtp connection by using the session ID. Check consistency
3260 static HTTPContext *find_rtp_session_with_url(const char *url,
3261 const char *session_id)
3269 rtp_c = find_rtp_session(session_id);
3273 /* find which url is asked */
3274 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3278 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3279 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3280 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3281 rtp_c->stream->filename, s);
3282 if(!strncmp(path, buf, sizeof(buf))) {
3283 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3288 if (len > 0 && path[len - 1] == '/' &&
3289 !strncmp(path, rtp_c->stream->filename, len - 1))
3294 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3298 rtp_c = find_rtp_session_with_url(url, h->session_id);
3300 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3304 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3305 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3306 rtp_c->state != HTTPSTATE_READY) {
3307 rtsp_reply_error(c, RTSP_STATUS_STATE);
3311 rtp_c->state = HTTPSTATE_SEND_DATA;
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_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3324 rtp_c = find_rtp_session_with_url(url, h->session_id);
3326 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3331 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3332 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3333 rtsp_reply_error(c, RTSP_STATUS_STATE);
3336 rtp_c->state = HTTPSTATE_READY;
3337 rtp_c->first_pts = AV_NOPTS_VALUE;
3340 /* now everything is OK, so we can send the connection parameters */
3341 rtsp_reply_header(c, RTSP_STATUS_OK);
3343 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3344 avio_printf(c->pb, "\r\n");
3347 close_connection(rtp_c);
3350 /********************************************************************/
3353 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3354 FFStream *stream, const char *session_id,
3355 enum RTSPLowerTransport rtp_protocol)
3357 HTTPContext *c = NULL;
3358 const char *proto_str;
3360 /* XXX: should output a warning page when coming
3361 close to the connection limit */
3362 if (nb_connections >= nb_max_connections)
3365 /* add a new connection */
3366 c = av_mallocz(sizeof(HTTPContext));
3371 c->poll_entry = NULL;
3372 c->from_addr = *from_addr;
3373 c->buffer_size = IOBUFFER_INIT_SIZE;
3374 c->buffer = av_malloc(c->buffer_size);
3379 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3380 c->state = HTTPSTATE_READY;
3381 c->is_packetized = 1;
3382 c->rtp_protocol = rtp_protocol;
3384 /* protocol is shown in statistics */
3385 switch(c->rtp_protocol) {
3386 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3387 proto_str = "MCAST";
3389 case RTSP_LOWER_TRANSPORT_UDP:
3392 case RTSP_LOWER_TRANSPORT_TCP:
3399 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3400 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3402 current_bandwidth += stream->bandwidth;
3404 c->next = first_http_ctx;
3416 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3417 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3419 static int rtp_new_av_stream(HTTPContext *c,
3420 int stream_index, struct sockaddr_in *dest_addr,
3421 HTTPContext *rtsp_c)
3423 AVFormatContext *ctx;
3426 URLContext *h = NULL;
3428 int max_packet_size;
3430 /* now we can open the relevant output stream */
3431 ctx = avformat_alloc_context();
3434 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3436 st = av_mallocz(sizeof(AVStream));
3439 ctx->nb_streams = 1;
3440 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3443 ctx->streams[0] = st;
3445 if (!c->stream->feed ||
3446 c->stream->feed == c->stream)
3447 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3450 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3452 st->priv_data = NULL;
3454 /* build destination RTP address */
3455 ipaddr = inet_ntoa(dest_addr->sin_addr);
3457 switch(c->rtp_protocol) {
3458 case RTSP_LOWER_TRANSPORT_UDP:
3459 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3462 /* XXX: also pass as parameter to function ? */
3463 if (c->stream->is_multicast) {
3465 ttl = c->stream->multicast_ttl;
3468 snprintf(ctx->filename, sizeof(ctx->filename),
3469 "rtp://%s:%d?multicast=1&ttl=%d",
3470 ipaddr, ntohs(dest_addr->sin_port), ttl);
3472 snprintf(ctx->filename, sizeof(ctx->filename),
3473 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3476 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3478 c->rtp_handles[stream_index] = h;
3479 max_packet_size = h->max_packet_size;
3481 case RTSP_LOWER_TRANSPORT_TCP:
3484 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3490 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3491 ipaddr, ntohs(dest_addr->sin_port),
3492 c->stream->filename, stream_index, c->protocol);
3494 /* normally, no packets should be output here, but the packet size may
3496 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3497 /* XXX: close stream */
3500 if (avformat_write_header(ctx, NULL) < 0) {
3507 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3510 c->rtp_ctx[stream_index] = ctx;
3514 /********************************************************************/
3515 /* ffserver initialization */
3517 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3521 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3524 fst = av_mallocz(sizeof(AVStream));
3528 fst->codec = avcodec_alloc_context3(NULL);
3529 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3530 if (codec->extradata_size) {
3531 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3532 memcpy(fst->codec->extradata, codec->extradata,
3533 codec->extradata_size);
3536 /* live streams must use the actual feed's codec since it may be
3537 * updated later to carry extradata needed by them.
3541 fst->priv_data = av_mallocz(sizeof(FeedData));
3542 fst->index = stream->nb_streams;
3543 avpriv_set_pts_info(fst, 33, 1, 90000);
3544 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3545 stream->streams[stream->nb_streams++] = fst;
3549 /* return the stream number in the feed */
3550 static int add_av_stream(FFStream *feed, AVStream *st)
3553 AVCodecContext *av, *av1;
3557 for(i=0;i<feed->nb_streams;i++) {
3558 st = feed->streams[i];
3560 if (av1->codec_id == av->codec_id &&
3561 av1->codec_type == av->codec_type &&
3562 av1->bit_rate == av->bit_rate) {
3564 switch(av->codec_type) {
3565 case AVMEDIA_TYPE_AUDIO:
3566 if (av1->channels == av->channels &&
3567 av1->sample_rate == av->sample_rate)
3570 case AVMEDIA_TYPE_VIDEO:
3571 if (av1->width == av->width &&
3572 av1->height == av->height &&
3573 av1->time_base.den == av->time_base.den &&
3574 av1->time_base.num == av->time_base.num &&
3575 av1->gop_size == av->gop_size)
3584 fst = add_av_stream1(feed, av, 0);
3587 return feed->nb_streams - 1;
3590 static void remove_stream(FFStream *stream)
3594 while (*ps != NULL) {
3602 /* specific mpeg4 handling : we extract the raw parameters */
3603 static void extract_mpeg4_header(AVFormatContext *infile)
3605 int mpeg4_count, i, size;
3610 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3613 for(i=0;i<infile->nb_streams;i++) {
3614 st = infile->streams[i];
3615 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3616 st->codec->extradata_size == 0) {
3623 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3624 while (mpeg4_count > 0) {
3625 if (av_read_frame(infile, &pkt) < 0)
3627 st = infile->streams[pkt.stream_index];
3628 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3629 st->codec->extradata_size == 0) {
3630 av_freep(&st->codec->extradata);
3631 /* fill extradata with the header */
3632 /* XXX: we make hard suppositions here ! */
3634 while (p < pkt.data + pkt.size - 4) {
3635 /* stop when vop header is found */
3636 if (p[0] == 0x00 && p[1] == 0x00 &&
3637 p[2] == 0x01 && p[3] == 0xb6) {
3638 size = p - pkt.data;
3639 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3640 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3641 st->codec->extradata_size = size;
3642 memcpy(st->codec->extradata, pkt.data, size);
3649 av_free_packet(&pkt);
3653 /* compute the needed AVStream for each file */
3654 static void build_file_streams(void)
3656 FFStream *stream, *stream_next;
3659 /* gather all streams */
3660 for(stream = first_stream; stream != NULL; stream = stream_next) {
3661 AVFormatContext *infile = NULL;
3662 stream_next = stream->next;
3663 if (stream->stream_type == STREAM_TYPE_LIVE &&
3665 /* the stream comes from a file */
3666 /* try to open the file */
3668 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3669 /* specific case : if transport stream output to RTP,
3670 we use a raw transport stream reader */
3671 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3674 if (!stream->feed_filename[0]) {
3675 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3679 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3680 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3681 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3682 /* remove stream (no need to spend more time on it) */
3684 remove_stream(stream);
3686 /* find all the AVStreams inside and reference them in
3688 if (avformat_find_stream_info(infile, NULL) < 0) {
3689 http_log("Could not find codec parameters from '%s'\n",
3690 stream->feed_filename);
3691 avformat_close_input(&infile);
3694 extract_mpeg4_header(infile);
3696 for(i=0;i<infile->nb_streams;i++)
3697 add_av_stream1(stream, infile->streams[i]->codec, 1);
3699 avformat_close_input(&infile);
3705 /* compute the needed AVStream for each feed */
3706 static void build_feed_streams(void)
3708 FFStream *stream, *feed;
3711 /* gather all streams */
3712 for(stream = first_stream; stream != NULL; stream = stream->next) {
3713 feed = stream->feed;
3715 if (stream->is_feed) {
3716 for(i=0;i<stream->nb_streams;i++)
3717 stream->feed_streams[i] = i;
3719 /* we handle a stream coming from a feed */
3720 for(i=0;i<stream->nb_streams;i++)
3721 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3726 /* create feed files if needed */
3727 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3730 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3731 /* See if it matches */
3732 AVFormatContext *s = NULL;
3735 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3736 /* set buffer size */
3737 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3738 /* Now see if it matches */
3739 if (s->nb_streams == feed->nb_streams) {
3741 for(i=0;i<s->nb_streams;i++) {
3743 sf = feed->streams[i];
3746 if (sf->index != ss->index ||
3748 http_log("Index & Id do not match for stream %d (%s)\n",
3749 i, feed->feed_filename);
3752 AVCodecContext *ccf, *ccs;
3756 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3758 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3759 http_log("Codecs do not match for stream %d\n", i);
3761 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3762 http_log("Codec bitrates do not match for stream %d\n", i);
3764 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3765 if (CHECK_CODEC(time_base.den) ||
3766 CHECK_CODEC(time_base.num) ||
3767 CHECK_CODEC(width) ||
3768 CHECK_CODEC(height)) {
3769 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3772 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3773 if (CHECK_CODEC(sample_rate) ||
3774 CHECK_CODEC(channels) ||
3775 CHECK_CODEC(frame_size)) {
3776 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3780 http_log("Unknown codec type\n");
3788 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3789 feed->feed_filename, s->nb_streams, feed->nb_streams);
3791 avformat_close_input(&s);
3793 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3794 feed->feed_filename);
3797 if (feed->readonly) {
3798 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3799 feed->feed_filename);
3802 unlink(feed->feed_filename);
3805 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3806 AVFormatContext *s = avformat_alloc_context();
3808 if (feed->readonly) {
3809 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3810 feed->feed_filename);
3814 /* only write the header of the ffm file */
3815 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3816 http_log("Could not open output feed file '%s'\n",
3817 feed->feed_filename);
3820 s->oformat = feed->fmt;
3821 s->nb_streams = feed->nb_streams;
3822 s->streams = feed->streams;
3823 if (avformat_write_header(s, NULL) < 0) {
3824 http_log("Container doesn't support the required parameters\n");
3827 /* XXX: need better api */
3828 av_freep(&s->priv_data);
3832 avformat_free_context(s);
3834 /* get feed size and write index */
3835 fd = open(feed->feed_filename, O_RDONLY);
3837 http_log("Could not open output feed file '%s'\n",
3838 feed->feed_filename);
3842 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3843 feed->feed_size = lseek(fd, 0, SEEK_END);
3844 /* ensure that we do not wrap before the end of file */
3845 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3846 feed->feed_max_size = feed->feed_size;
3852 /* compute the bandwidth used by each stream */
3853 static void compute_bandwidth(void)
3859 for(stream = first_stream; stream != NULL; stream = stream->next) {
3861 for(i=0;i<stream->nb_streams;i++) {
3862 AVStream *st = stream->streams[i];
3863 switch(st->codec->codec_type) {
3864 case AVMEDIA_TYPE_AUDIO:
3865 case AVMEDIA_TYPE_VIDEO:
3866 bandwidth += st->codec->bit_rate;
3872 stream->bandwidth = (bandwidth + 999) / 1000;
3876 /* add a codec and set the default parameters */
3877 static void add_codec(FFStream *stream, AVCodecContext *av)
3881 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3884 /* compute default parameters */
3885 switch(av->codec_type) {
3886 case AVMEDIA_TYPE_AUDIO:
3887 if (av->bit_rate == 0)
3888 av->bit_rate = 64000;
3889 if (av->sample_rate == 0)
3890 av->sample_rate = 22050;
3891 if (av->channels == 0)
3894 case AVMEDIA_TYPE_VIDEO:
3895 if (av->bit_rate == 0)
3896 av->bit_rate = 64000;
3897 if (av->time_base.num == 0){
3898 av->time_base.den = 5;
3899 av->time_base.num = 1;
3901 if (av->width == 0 || av->height == 0) {
3905 /* Bitrate tolerance is less for streaming */
3906 if (av->bit_rate_tolerance == 0)
3907 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3908 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3913 if (av->max_qdiff == 0)
3915 av->qcompress = 0.5;
3918 if (!av->nsse_weight)
3919 av->nsse_weight = 8;
3921 av->frame_skip_cmp = FF_CMP_DCTMAX;
3923 av->me_method = ME_EPZS;
3924 av->rc_buffer_aggressivity = 1.0;
3927 av->rc_eq = av_strdup("tex^qComp");
3928 if (!av->i_quant_factor)
3929 av->i_quant_factor = -0.8;
3930 if (!av->b_quant_factor)
3931 av->b_quant_factor = 1.25;
3932 if (!av->b_quant_offset)
3933 av->b_quant_offset = 1.25;
3934 if (!av->rc_max_rate)
3935 av->rc_max_rate = av->bit_rate * 2;
3937 if (av->rc_max_rate && !av->rc_buffer_size) {
3938 av->rc_buffer_size = av->rc_max_rate;
3947 st = av_mallocz(sizeof(AVStream));
3950 st->codec = avcodec_alloc_context3(NULL);
3951 stream->streams[stream->nb_streams++] = st;
3952 memcpy(st->codec, av, sizeof(AVCodecContext));
3955 static enum AVCodecID opt_codec(const char *name, enum AVMediaType type)
3957 AVCodec *codec = avcodec_find_encoder_by_name(name);
3959 if (!codec || codec->type != type)
3960 return AV_CODEC_ID_NONE;
3964 static int ffserver_opt_default(const char *opt, const char *arg,
3965 AVCodecContext *avctx, int type)
3968 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3970 ret = av_opt_set(avctx, opt, arg, 0);
3974 static int ffserver_opt_preset(const char *arg,
3975 AVCodecContext *avctx, int type,
3976 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3979 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3981 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3983 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3984 codec ? codec->name : NULL))) {
3985 fprintf(stderr, "File for preset '%s' not found\n", arg);
3990 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3991 if(line[0] == '#' && !e)
3993 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3995 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3999 if(!strcmp(tmp, "acodec")){
4000 *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
4001 }else if(!strcmp(tmp, "vcodec")){
4002 *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
4003 }else if(!strcmp(tmp, "scodec")){
4004 /* opt_subtitle_codec(tmp2); */
4005 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
4006 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4017 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename, const char *mime_type)
4019 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4022 AVOutputFormat *stream_fmt;
4023 char stream_format_name[64];
4025 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4026 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4035 static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...)
4039 av_log(NULL, log_level, "%s:%d: ", filename, line_num);
4040 av_vlog(NULL, log_level, fmt, vl);
4046 static int parse_ffconfig(const char *filename)
4051 char arg[1024], arg2[1024];
4053 int val, errors, warnings, line_num;
4054 FFStream **last_stream, *stream, *redirect;
4055 FFStream **last_feed, *feed, *s;
4056 AVCodecContext audio_enc, video_enc;
4057 enum AVCodecID audio_id, video_id;
4060 f = fopen(filename, "r");
4062 ret = AVERROR(errno);
4063 av_log(NULL, AV_LOG_ERROR, "Could not open the configuration file '%s'\n", filename);
4067 errors = warnings = 0;
4069 first_stream = NULL;
4070 last_stream = &first_stream;
4072 last_feed = &first_feed;
4076 audio_id = AV_CODEC_ID_NONE;
4077 video_id = AV_CODEC_ID_NONE;
4078 #define ERROR(...) report_config_error(filename, line_num, AV_LOG_ERROR, &errors, __VA_ARGS__)
4079 #define WARNING(...) report_config_error(filename, line_num, AV_LOG_WARNING, &warnings, __VA_ARGS__)
4082 if (fgets(line, sizeof(line), f) == NULL)
4086 while (av_isspace(*p))
4088 if (*p == '\0' || *p == '#')
4091 get_arg(cmd, sizeof(cmd), &p);
4093 if (!av_strcasecmp(cmd, "Port")) {
4094 get_arg(arg, sizeof(arg), &p);
4096 if (val < 1 || val > 65536) {
4097 ERROR("Invalid_port: %s\n", arg);
4099 my_http_addr.sin_port = htons(val);
4100 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4101 get_arg(arg, sizeof(arg), &p);
4102 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4103 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4105 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4106 WARNING("NoDaemon option has no effect, you should remove it\n");
4107 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4108 get_arg(arg, sizeof(arg), &p);
4110 if (val < 1 || val > 65536) {
4111 ERROR("%s:%d: Invalid port: %s\n", arg);
4113 my_rtsp_addr.sin_port = htons(atoi(arg));
4114 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4115 get_arg(arg, sizeof(arg), &p);
4116 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4117 ERROR("Invalid host/IP address: %s\n", arg);
4119 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4120 get_arg(arg, sizeof(arg), &p);
4122 if (val < 1 || val > 65536) {
4123 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4125 nb_max_http_connections = val;
4126 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4127 get_arg(arg, sizeof(arg), &p);
4129 if (val < 1 || val > nb_max_http_connections) {
4130 ERROR("Invalid MaxClients: %s\n", arg);
4132 nb_max_connections = val;
4134 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4136 get_arg(arg, sizeof(arg), &p);
4137 llval = strtoll(arg, NULL, 10);
4138 if (llval < 10 || llval > 10000000) {
4139 ERROR("Invalid MaxBandwidth: %s\n", arg);
4141 max_bandwidth = llval;
4142 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4143 if (!ffserver_debug)
4144 get_arg(logfilename, sizeof(logfilename), &p);
4145 } else if (!av_strcasecmp(cmd, "<Feed")) {
4146 /*********************************************/
4147 /* Feed related options */
4149 if (stream || feed) {
4150 ERROR("Already in a tag\n");
4152 feed = av_mallocz(sizeof(FFStream));
4154 ret = AVERROR(ENOMEM);
4157 get_arg(feed->filename, sizeof(feed->filename), &p);
4158 q = strrchr(feed->filename, '>');
4162 for (s = first_feed; s; s = s->next) {
4163 if (!strcmp(feed->filename, s->filename)) {
4164 ERROR("Feed '%s' already registered\n", s->filename);
4168 feed->fmt = av_guess_format("ffm", NULL, NULL);
4169 /* default feed file */
4170 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4171 "/tmp/%s.ffm", feed->filename);
4172 feed->feed_max_size = 5 * 1024 * 1024;
4174 feed->feed = feed; /* self feeding :-) */
4176 /* add in stream list */
4177 *last_stream = feed;
4178 last_stream = &feed->next;
4179 /* add in feed list */
4181 last_feed = &feed->next_feed;
4183 } else if (!av_strcasecmp(cmd, "Launch")) {
4187 feed->child_argv = av_mallocz(64 * sizeof(char *));
4188 if (!feed->child_argv) {
4189 ret = AVERROR(ENOMEM);
4192 for (i = 0; i < 62; i++) {
4193 get_arg(arg, sizeof(arg), &p);
4197 feed->child_argv[i] = av_strdup(arg);
4198 if (!feed->child_argv[i]) {
4199 ret = AVERROR(ENOMEM);
4204 feed->child_argv[i] =
4205 av_asprintf("http://%s:%d/%s",
4206 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4207 inet_ntoa(my_http_addr.sin_addr), ntohs(my_http_addr.sin_port),
4209 if (!feed->child_argv[i]) {
4210 ret = AVERROR(ENOMEM);
4214 } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
4216 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4217 feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile");
4218 } else if (stream) {
4219 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4221 } else if (!av_strcasecmp(cmd, "Truncate")) {
4223 get_arg(arg, sizeof(arg), &p);
4224 /* assume Truncate is true in case no argument is specified */
4228 WARNING("Truncate N syntax in configuration file is deprecated, "
4229 "use Truncate alone with no arguments\n");
4230 feed->truncate = strtod(arg, NULL);
4233 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4238 get_arg(arg, sizeof(arg), &p);
4240 fsize = strtod(p1, &p1);
4241 switch(av_toupper(*p1)) {
4246 fsize *= 1024 * 1024;
4249 fsize *= 1024 * 1024 * 1024;
4252 feed->feed_max_size = (int64_t)fsize;
4253 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4254 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4257 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4259 ERROR("No corresponding <Feed> for </Feed>\n");
4262 } else if (!av_strcasecmp(cmd, "<Stream")) {
4263 /*********************************************/
4264 /* Stream related options */
4266 if (stream || feed) {
4267 ERROR("Already in a tag\n");
4270 stream = av_mallocz(sizeof(FFStream));
4272 ret = AVERROR(ENOMEM);
4275 get_arg(stream->filename, sizeof(stream->filename), &p);
4276 q = strrchr(stream->filename, '>');
4280 for (s = first_stream; s; s = s->next) {
4281 if (!strcmp(stream->filename, s->filename)) {
4282 ERROR("Stream '%s' already registered\n", s->filename);
4286 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4287 avcodec_get_context_defaults3(&video_enc, NULL);
4288 avcodec_get_context_defaults3(&audio_enc, NULL);
4290 audio_id = AV_CODEC_ID_NONE;
4291 video_id = AV_CODEC_ID_NONE;
4293 audio_id = stream->fmt->audio_codec;
4294 video_id = stream->fmt->video_codec;
4297 *last_stream = stream;
4298 last_stream = &stream->next;
4300 } else if (!av_strcasecmp(cmd, "Feed")) {
4301 get_arg(arg, sizeof(arg), &p);
4306 while (sfeed != NULL) {
4307 if (!strcmp(sfeed->filename, arg))
4309 sfeed = sfeed->next_feed;
4312 ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg, stream->filename);
4314 stream->feed = sfeed;
4316 } else if (!av_strcasecmp(cmd, "Format")) {
4317 get_arg(arg, sizeof(arg), &p);
4319 if (!strcmp(arg, "status")) {
4320 stream->stream_type = STREAM_TYPE_STATUS;
4323 stream->stream_type = STREAM_TYPE_LIVE;
4324 /* jpeg cannot be used here, so use single frame jpeg */
4325 if (!strcmp(arg, "jpeg"))
4326 strcpy(arg, "mjpeg");
4327 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4329 ERROR("Unknown Format: %s\n", arg);
4333 audio_id = stream->fmt->audio_codec;
4334 video_id = stream->fmt->video_codec;
4337 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4338 get_arg(arg, sizeof(arg), &p);
4340 stream->ifmt = av_find_input_format(arg);
4341 if (!stream->ifmt) {
4342 ERROR("Unknown input format: %s\n", arg);
4345 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4346 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4347 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4349 ERROR("FaviconURL only permitted for status streams\n");
4351 } else if (!av_strcasecmp(cmd, "Author") ||
4352 !av_strcasecmp(cmd, "Comment") ||
4353 !av_strcasecmp(cmd, "Copyright") ||
4354 !av_strcasecmp(cmd, "Title")) {
4355 get_arg(arg, sizeof(arg), &p);
4361 for (i = 0; i < strlen(cmd); i++)
4362 key[i] = av_tolower(cmd[i]);
4364 WARNING("'%s' option in configuration file is deprecated, "
4365 "use 'Metadata %s VALUE' instead\n", cmd, key);
4366 if ((ret = av_dict_set(&stream->metadata, key, arg, 0)) < 0) {
4367 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4368 key, arg, av_err2str(ret));
4371 } else if (!av_strcasecmp(cmd, "Metadata")) {
4372 get_arg(arg, sizeof(arg), &p);
4373 get_arg(arg2, sizeof(arg2), &p);
4376 if ((ret = av_dict_set(&stream->metadata, arg, arg2, 0)) < 0) {
4377 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4378 arg, arg2, av_err2str(ret));
4381 } else if (!av_strcasecmp(cmd, "Preroll")) {
4382 get_arg(arg, sizeof(arg), &p);
4384 stream->prebuffer = atof(arg) * 1000;
4385 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4387 stream->send_on_key = 1;
4388 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4389 get_arg(arg, sizeof(arg), &p);
4390 audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO);
4391 if (audio_id == AV_CODEC_ID_NONE) {
4392 ERROR("Unknown AudioCodec: %s\n", arg);
4394 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4395 get_arg(arg, sizeof(arg), &p);
4396 video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO);
4397 if (video_id == AV_CODEC_ID_NONE) {
4398 ERROR("Unknown VideoCodec: %s\n", arg);
4400 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4401 get_arg(arg, sizeof(arg), &p);
4403 stream->max_time = atof(arg) * 1000;
4404 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4405 get_arg(arg, sizeof(arg), &p);
4407 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4408 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4409 get_arg(arg, sizeof(arg), &p);
4411 audio_enc.channels = atoi(arg);
4412 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4413 get_arg(arg, sizeof(arg), &p);
4415 audio_enc.sample_rate = atoi(arg);
4416 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4418 int minrate, maxrate;
4420 get_arg(arg, sizeof(arg), &p);
4422 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4423 video_enc.rc_min_rate = minrate * 1000;
4424 video_enc.rc_max_rate = maxrate * 1000;
4426 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4429 } else if (!av_strcasecmp(cmd, "Debug")) {
4431 get_arg(arg, sizeof(arg), &p);
4432 video_enc.debug = strtol(arg,0,0);
4434 } else if (!av_strcasecmp(cmd, "Strict")) {
4436 get_arg(arg, sizeof(arg), &p);
4437 video_enc.strict_std_compliance = atoi(arg);
4439 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4441 get_arg(arg, sizeof(arg), &p);
4442 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4444 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4446 get_arg(arg, sizeof(arg), &p);
4447 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4449 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4450 get_arg(arg, sizeof(arg), &p);
4452 video_enc.bit_rate = atoi(arg) * 1000;
4454 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4455 get_arg(arg, sizeof(arg), &p);
4457 ret = av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4459 ERROR("Invalid video size '%s'\n", arg);
4461 if ((video_enc.width % 16) != 0 ||
4462 (video_enc.height % 16) != 0) {
4463 ERROR("Image size must be a multiple of 16\n");
4467 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4468 get_arg(arg, sizeof(arg), &p);
4470 AVRational frame_rate;
4471 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4472 ERROR("Incorrect frame rate: %s\n", arg);
4474 video_enc.time_base.num = frame_rate.den;
4475 video_enc.time_base.den = frame_rate.num;
4478 } else if (!av_strcasecmp(cmd, "PixelFormat")) {
4479 get_arg(arg, sizeof(arg), &p);
4481 video_enc.pix_fmt = av_get_pix_fmt(arg);
4482 if (video_enc.pix_fmt == AV_PIX_FMT_NONE) {
4483 ERROR("Unknown pixel format: %s\n", arg);
4486 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4487 get_arg(arg, sizeof(arg), &p);
4489 video_enc.gop_size = atoi(arg);
4490 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4492 video_enc.gop_size = 1;
4493 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4495 video_enc.mb_decision = FF_MB_DECISION_BITS;
4496 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4498 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4499 video_enc.flags |= CODEC_FLAG_4MV;
4501 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4502 !av_strcasecmp(cmd, "AVOptionAudio")) {
4503 AVCodecContext *avctx;
4505 get_arg(arg, sizeof(arg), &p);
4506 get_arg(arg2, sizeof(arg2), &p);
4507 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4509 type = AV_OPT_FLAG_VIDEO_PARAM;
4512 type = AV_OPT_FLAG_AUDIO_PARAM;
4514 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4515 ERROR("Error setting %s option to %s %s\n", cmd, arg, arg2);
4517 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4518 !av_strcasecmp(cmd, "AVPresetAudio")) {
4519 AVCodecContext *avctx;
4521 get_arg(arg, sizeof(arg), &p);
4522 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4524 video_enc.codec_id = video_id;
4525 type = AV_OPT_FLAG_VIDEO_PARAM;
4528 audio_enc.codec_id = audio_id;
4529 type = AV_OPT_FLAG_AUDIO_PARAM;
4531 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4532 ERROR("AVPreset error: %s\n", arg);
4534 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4535 get_arg(arg, sizeof(arg), &p);
4536 if ((strlen(arg) == 4) && stream)
4537 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4538 } else if (!av_strcasecmp(cmd, "BitExact")) {
4540 video_enc.flags |= CODEC_FLAG_BITEXACT;
4541 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4543 video_enc.dct_algo = FF_DCT_FASTINT;
4544 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4546 video_enc.idct_algo = FF_IDCT_SIMPLE;
4547 } else if (!av_strcasecmp(cmd, "Qscale")) {
4548 get_arg(arg, sizeof(arg), &p);
4550 video_enc.flags |= CODEC_FLAG_QSCALE;
4551 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4553 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4554 get_arg(arg, sizeof(arg), &p);
4556 video_enc.max_qdiff = atoi(arg);
4557 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4558 ERROR("VideoQDiff out of range\n");
4561 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4562 get_arg(arg, sizeof(arg), &p);
4564 video_enc.qmax = atoi(arg);
4565 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4566 ERROR("VideoQMax out of range\n");
4569 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4570 get_arg(arg, sizeof(arg), &p);
4572 video_enc.qmin = atoi(arg);
4573 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4574 ERROR("VideoQMin out of range\n");
4577 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4578 get_arg(arg, sizeof(arg), &p);
4580 video_enc.lumi_masking = atof(arg);
4581 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4582 get_arg(arg, sizeof(arg), &p);
4584 video_enc.dark_masking = atof(arg);
4585 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4586 video_id = AV_CODEC_ID_NONE;
4587 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4588 audio_id = AV_CODEC_ID_NONE;
4589 } else if (!av_strcasecmp(cmd, "ACL")) {
4590 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4591 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4593 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4595 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4596 get_arg(arg, sizeof(arg), &p);
4598 av_freep(&stream->rtsp_option);
4599 stream->rtsp_option = av_strdup(arg);
4601 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4602 get_arg(arg, sizeof(arg), &p);
4604 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4605 ERROR("Invalid host/IP address: %s\n", arg);
4607 stream->is_multicast = 1;
4608 stream->loop = 1; /* default is looping */
4610 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4611 get_arg(arg, sizeof(arg), &p);
4613 stream->multicast_port = atoi(arg);
4614 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4615 get_arg(arg, sizeof(arg), &p);
4617 stream->multicast_ttl = atoi(arg);
4618 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4621 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4623 ERROR("No corresponding <Stream> for </Stream>\n");
4625 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4626 if (audio_id != AV_CODEC_ID_NONE) {
4627 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4628 audio_enc.codec_id = audio_id;
4629 add_codec(stream, &audio_enc);
4631 if (video_id != AV_CODEC_ID_NONE) {
4632 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4633 video_enc.codec_id = video_id;
4634 add_codec(stream, &video_enc);
4639 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4640 /*********************************************/
4642 if (stream || feed || redirect) {
4643 ERROR("Already in a tag\n");
4645 redirect = av_mallocz(sizeof(FFStream));
4647 ret = AVERROR(ENOMEM);
4650 *last_stream = redirect;
4651 last_stream = &redirect->next;
4653 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4654 q = strrchr(redirect->filename, '>');
4657 redirect->stream_type = STREAM_TYPE_REDIRECT;
4659 } else if (!av_strcasecmp(cmd, "URL")) {
4661 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4662 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4664 ERROR("No corresponding <Redirect> for </Redirect>\n");
4666 if (!redirect->feed_filename[0]) {
4667 ERROR("No URL found for <Redirect>\n");
4671 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4672 ERROR("Loadable modules no longer supported\n");
4674 ERROR("Incorrect keyword: '%s'\n", cmd);
4684 return AVERROR(EINVAL);
4689 static void handle_child_exit(int sig)
4694 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4697 for (feed = first_feed; feed; feed = feed->next) {
4698 if (feed->pid == pid) {
4699 int uptime = time(0) - feed->pid_start;
4702 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4705 /* Turn off any more restarts */
4706 feed->child_argv = 0;
4711 need_to_start_children = 1;
4714 static void opt_debug(void)
4717 logfilename[0] = '-';
4720 void show_help_default(const char *opt, const char *arg)
4722 printf("usage: ffserver [options]\n"
4723 "Hyper fast multi format Audio/Video streaming server\n");
4725 show_help_options(options, "Main options:", 0, 0, 0);
4728 static const OptionDef options[] = {
4729 #include "cmdutils_common_opts.h"
4730 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4731 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4732 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4736 int main(int argc, char **argv)
4738 struct sigaction sigact = { { 0 } };
4741 config_filename = av_strdup("/etc/ffserver.conf");
4743 parse_loglevel(argc, argv, options);
4745 avformat_network_init();
4747 show_banner(argc, argv, options);
4749 my_program_name = argv[0];
4751 parse_options(NULL, argc, argv, options, NULL);
4753 unsetenv("http_proxy"); /* Kill the http_proxy */
4755 av_lfg_init(&random_state, av_get_random_seed());
4757 sigact.sa_handler = handle_child_exit;
4758 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4759 sigaction(SIGCHLD, &sigact, 0);
4761 if ((ret = parse_ffconfig(config_filename)) < 0) {
4762 fprintf(stderr, "Error reading configuration file '%s': %s\n",
4763 config_filename, av_err2str(ret));
4766 av_freep(&config_filename);
4768 /* open log file if needed */
4769 if (logfilename[0] != '\0') {
4770 if (!strcmp(logfilename, "-"))
4773 logfile = fopen(logfilename, "a");
4774 av_log_set_callback(http_av_log);
4777 build_file_streams();
4779 build_feed_streams();
4781 compute_bandwidth();
4784 signal(SIGPIPE, SIG_IGN);
4786 if (http_server() < 0) {
4787 http_log("Could not start server\n");