2 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * multiple format streaming server based on the FFmpeg libraries
28 #define closesocket close
33 #include "libavformat/avformat.h"
34 // FIXME those are internal headers, ffserver _really_ shouldn't use them
35 #include "libavformat/ffm.h"
36 #include "libavformat/network.h"
37 #include "libavformat/os_support.h"
38 #include "libavformat/rtpdec.h"
39 #include "libavformat/rtpproto.h"
40 #include "libavformat/rtsp.h"
41 #include "libavformat/rtspcodes.h"
42 #include "libavformat/avio_internal.h"
43 #include "libavformat/internal.h"
44 #include "libavformat/url.h"
46 #include "libavutil/avassert.h"
47 #include "libavutil/avstring.h"
48 #include "libavutil/lfg.h"
49 #include "libavutil/dict.h"
50 #include "libavutil/intreadwrite.h"
51 #include "libavutil/mathematics.h"
52 #include "libavutil/pixdesc.h"
53 #include "libavutil/random_seed.h"
54 #include "libavutil/parseutils.h"
55 #include "libavutil/opt.h"
56 #include "libavutil/time.h"
61 #include <sys/ioctl.h>
72 const char program_name[] = "ffserver";
73 const int program_birth_year = 2000;
75 static const OptionDef options[];
78 HTTPSTATE_WAIT_REQUEST,
79 HTTPSTATE_SEND_HEADER,
80 HTTPSTATE_SEND_DATA_HEADER,
81 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
82 HTTPSTATE_SEND_DATA_TRAILER,
83 HTTPSTATE_RECEIVE_DATA,
84 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
87 RTSPSTATE_WAIT_REQUEST,
89 RTSPSTATE_SEND_PACKET,
92 static const char *http_state[] = {
108 #define MAX_STREAMS 20
110 #define IOBUFFER_INIT_SIZE 8192
112 /* timeouts are in ms */
113 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
114 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
116 #define SYNC_TIMEOUT (10 * 1000)
118 typedef struct RTSPActionServerSetup {
120 char transport_option[512];
121 } RTSPActionServerSetup;
124 int64_t count1, count2;
125 int64_t time1, time2;
128 /* context associated with one connection */
129 typedef struct HTTPContext {
130 enum HTTPState state;
131 int fd; /* socket file descriptor */
132 struct sockaddr_in from_addr; /* origin */
133 struct pollfd *poll_entry; /* used when polling */
135 uint8_t *buffer_ptr, *buffer_end;
138 int chunked_encoding;
139 int chunk_size; /* 0 if it needs to be read */
140 struct HTTPContext *next;
141 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
145 /* input format handling */
146 AVFormatContext *fmt_in;
147 int64_t start_time; /* In milliseconds - this wraps fairly often */
148 int64_t first_pts; /* initial pts value */
149 int64_t cur_pts; /* current pts value from the stream in us */
150 int64_t cur_frame_duration; /* duration of the current frame in us */
151 int cur_frame_bytes; /* output frame size, needed to compute
152 the time at which we send each
154 int pts_stream_index; /* stream we choose as clock reference */
155 int64_t cur_clock; /* current clock reference value in us */
156 /* output format handling */
157 struct FFStream *stream;
158 /* -1 is invalid stream */
159 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
160 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
162 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
163 int last_packet_sent; /* true if last data packet was sent */
165 DataRateData datarate;
172 int is_packetized; /* if true, the stream is packetized */
173 int packet_stream_index; /* current stream for output in state machine */
175 /* RTSP state specific */
176 uint8_t *pb_buffer; /* XXX: use that in all the code */
178 int seq; /* RTSP sequence number */
180 /* RTP state specific */
181 enum RTSPLowerTransport rtp_protocol;
182 char session_id[32]; /* session id */
183 AVFormatContext *rtp_ctx[MAX_STREAMS];
185 /* RTP/UDP specific */
186 URLContext *rtp_handles[MAX_STREAMS];
188 /* RTP/TCP specific */
189 struct HTTPContext *rtsp_c;
190 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
193 /* each generated stream is described here */
197 STREAM_TYPE_REDIRECT,
200 enum IPAddressAction {
205 typedef struct IPAddressACL {
206 struct IPAddressACL *next;
207 enum IPAddressAction action;
208 /* These are in host order */
209 struct in_addr first;
213 /* description of each stream of the ffserver.conf file */
214 typedef struct FFStream {
215 enum StreamType stream_type;
216 char filename[1024]; /* stream filename */
217 struct FFStream *feed; /* feed we are using (can be null if
219 AVDictionary *in_opts; /* input parameters */
220 AVDictionary *metadata; /* metadata to set on the stream */
221 AVInputFormat *ifmt; /* if non NULL, force input format */
224 char dynamic_acl[1024];
226 int prebuffer; /* Number of milliseconds early to start */
227 int64_t max_time; /* Number of milliseconds to run */
229 AVStream *streams[MAX_STREAMS];
230 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
231 char feed_filename[1024]; /* file name of the feed storage, or
232 input file name for a stream */
233 pid_t pid; /* Of ffmpeg process */
234 time_t pid_start; /* Of ffmpeg process */
236 struct FFStream *next;
237 unsigned bandwidth; /* bandwidth, in kbits/s */
240 /* multicast specific */
242 struct in_addr multicast_ip;
243 int multicast_port; /* first port used for multicast */
245 int loop; /* if true, send the stream in loops (only meaningful if file) */
248 int feed_opened; /* true if someone is writing to the feed */
249 int is_feed; /* true if it is a feed */
250 int readonly; /* True if writing is prohibited to the file */
251 int truncate; /* True if feeder connection truncate the feed file */
253 int64_t bytes_served;
254 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
255 int64_t feed_write_index; /* current write position in feed (it wraps around) */
256 int64_t feed_size; /* current size of feed */
257 struct FFStream *next_feed;
260 typedef struct FeedData {
261 long long data_count;
262 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
265 static struct sockaddr_in my_http_addr;
266 static struct sockaddr_in my_rtsp_addr;
268 static char logfilename[1024];
269 static HTTPContext *first_http_ctx;
270 static FFStream *first_feed; /* contains only feeds */
271 static FFStream *first_stream; /* contains all streams, including feeds */
273 static void new_connection(int server_fd, int is_rtsp);
274 static void close_connection(HTTPContext *c);
277 static int handle_connection(HTTPContext *c);
278 static int http_parse_request(HTTPContext *c);
279 static int http_send_data(HTTPContext *c);
280 static void compute_status(HTTPContext *c);
281 static int open_input_stream(HTTPContext *c, const char *info);
282 static int http_start_receive_data(HTTPContext *c);
283 static int http_receive_data(HTTPContext *c);
286 static int rtsp_parse_request(HTTPContext *c);
287 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
288 static void rtsp_cmd_options(HTTPContext *c, const char *url);
289 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
290 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
291 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only);
294 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
295 struct in_addr my_ip);
298 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
299 FFStream *stream, const char *session_id,
300 enum RTSPLowerTransport rtp_protocol);
301 static int rtp_new_av_stream(HTTPContext *c,
302 int stream_index, struct sockaddr_in *dest_addr,
303 HTTPContext *rtsp_c);
305 static const char *my_program_name;
307 static const char *config_filename;
309 static int ffserver_debug;
310 static int no_launch;
311 static int need_to_start_children;
313 /* maximum number of simultaneous HTTP connections */
314 static unsigned int nb_max_http_connections = 2000;
315 static unsigned int nb_max_connections = 5;
316 static unsigned int nb_connections;
318 static uint64_t max_bandwidth = 1000;
319 static uint64_t current_bandwidth;
321 static int64_t cur_time; // Making this global saves on passing it around everywhere
323 static AVLFG random_state;
325 static FILE *logfile = NULL;
327 static void htmlstrip(char *s) {
329 s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
335 static int64_t ffm_read_write_index(int fd)
339 if (lseek(fd, 8, SEEK_SET) < 0)
341 if (read(fd, buf, 8) != 8)
346 static int ffm_write_write_index(int fd, int64_t pos)
352 buf[i] = (pos >> (56 - i * 8)) & 0xff;
353 if (lseek(fd, 8, SEEK_SET) < 0)
355 if (write(fd, buf, 8) != 8)
360 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
363 FFMContext *ffm = s->priv_data;
364 ffm->write_index = pos;
365 ffm->file_size = file_size;
368 /* FIXME: make ffserver work with IPv6 */
369 /* resolve host with also IP address parsing */
370 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
373 if (!ff_inet_aton(hostname, sin_addr)) {
375 struct addrinfo *ai, *cur;
376 struct addrinfo hints = { 0 };
377 hints.ai_family = AF_INET;
378 if (getaddrinfo(hostname, NULL, &hints, &ai))
380 /* getaddrinfo returns a linked list of addrinfo structs.
381 * Even if we set ai_family = AF_INET above, make sure
382 * that the returned one actually is of the correct type. */
383 for (cur = ai; cur; cur = cur->ai_next) {
384 if (cur->ai_family == AF_INET) {
385 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
394 hp = gethostbyname(hostname);
397 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
403 static char *ctime1(char *buf2, int buf_size)
410 av_strlcpy(buf2, p, buf_size);
411 p = buf2 + strlen(p) - 1;
417 static void http_vlog(const char *fmt, va_list vargs)
419 static int print_prefix = 1;
423 ctime1(buf, sizeof(buf));
424 fprintf(logfile, "%s ", buf);
426 print_prefix = strstr(fmt, "\n") != NULL;
427 vfprintf(logfile, fmt, vargs);
433 __attribute__ ((format (printf, 1, 2)))
435 static void http_log(const char *fmt, ...)
438 va_start(vargs, fmt);
439 http_vlog(fmt, vargs);
443 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
445 static int print_prefix = 1;
446 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
447 if (level > av_log_get_level())
449 if (print_prefix && avc)
450 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
451 print_prefix = strstr(fmt, "\n") != NULL;
452 http_vlog(fmt, vargs);
455 static void log_connection(HTTPContext *c)
460 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
461 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
462 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
465 static void update_datarate(DataRateData *drd, int64_t count)
467 if (!drd->time1 && !drd->count1) {
468 drd->time1 = drd->time2 = cur_time;
469 drd->count1 = drd->count2 = count;
470 } else if (cur_time - drd->time2 > 5000) {
471 drd->time1 = drd->time2;
472 drd->count1 = drd->count2;
473 drd->time2 = cur_time;
478 /* In bytes per second */
479 static int compute_datarate(DataRateData *drd, int64_t count)
481 if (cur_time == drd->time1)
484 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
488 static void start_children(FFStream *feed)
493 for (; feed; feed = feed->next) {
494 if (feed->child_argv && !feed->pid) {
495 feed->pid_start = time(0);
500 http_log("Unable to create children\n");
509 /* replace "ffserver" with "ffmpeg" in the path of current
510 * program. Ignore user provided path */
511 av_strlcpy(pathname, my_program_name, sizeof(pathname));
512 slash = strrchr(pathname, '/');
517 strcpy(slash, "ffmpeg");
519 http_log("Launch command line: ");
520 http_log("%s ", pathname);
521 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
522 http_log("%s ", feed->child_argv[i]);
525 for (i = 3; i < 256; i++)
528 if (!ffserver_debug) {
529 if (!freopen("/dev/null", "r", stdin))
530 http_log("failed to redirect STDIN to /dev/null\n;");
531 if (!freopen("/dev/null", "w", stdout))
532 http_log("failed to redirect STDOUT to /dev/null\n;");
533 if (!freopen("/dev/null", "w", stderr))
534 http_log("failed to redirect STDERR to /dev/null\n;");
537 signal(SIGPIPE, SIG_DFL);
539 execvp(pathname, feed->child_argv);
547 /* open a listening socket */
548 static int socket_open_listen(struct sockaddr_in *my_addr)
552 server_fd = socket(AF_INET,SOCK_STREAM,0);
559 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)))
560 av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n");
562 my_addr->sin_family = AF_INET;
563 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
565 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
567 closesocket(server_fd);
571 if (listen (server_fd, 5) < 0) {
573 closesocket(server_fd);
577 if (ff_socket_nonblock(server_fd, 1) < 0)
578 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
583 /* start all multicast streams */
584 static void start_multicast(void)
589 struct sockaddr_in dest_addr = {0};
590 int default_port, stream_index;
593 for(stream = first_stream; stream != NULL; stream = stream->next) {
594 if (stream->is_multicast) {
595 unsigned random0 = av_lfg_get(&random_state);
596 unsigned random1 = av_lfg_get(&random_state);
597 /* open the RTP connection */
598 snprintf(session_id, sizeof(session_id), "%08x%08x",
601 /* choose a port if none given */
602 if (stream->multicast_port == 0) {
603 stream->multicast_port = default_port;
607 dest_addr.sin_family = AF_INET;
608 dest_addr.sin_addr = stream->multicast_ip;
609 dest_addr.sin_port = htons(stream->multicast_port);
611 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
612 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
616 if (open_input_stream(rtp_c, "") < 0) {
617 http_log("Could not open input stream for stream '%s'\n",
622 /* open each RTP stream */
623 for(stream_index = 0; stream_index < stream->nb_streams;
625 dest_addr.sin_port = htons(stream->multicast_port +
627 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
628 http_log("Could not open output stream '%s/streamid=%d'\n",
629 stream->filename, stream_index);
634 rtp_c->state = HTTPSTATE_SEND_DATA;
639 /* main loop of the HTTP server */
640 static int http_server(void)
642 int server_fd = 0, rtsp_server_fd = 0;
644 struct pollfd *poll_table, *poll_entry;
645 HTTPContext *c, *c_next;
647 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
648 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
652 if (my_http_addr.sin_port) {
653 server_fd = socket_open_listen(&my_http_addr);
660 if (my_rtsp_addr.sin_port) {
661 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
662 if (rtsp_server_fd < 0) {
664 closesocket(server_fd);
669 if (!rtsp_server_fd && !server_fd) {
670 http_log("HTTP and RTSP disabled.\n");
675 http_log("FFserver started.\n");
677 start_children(first_feed);
682 poll_entry = poll_table;
684 poll_entry->fd = server_fd;
685 poll_entry->events = POLLIN;
688 if (rtsp_server_fd) {
689 poll_entry->fd = rtsp_server_fd;
690 poll_entry->events = POLLIN;
694 /* wait for events on each HTTP handle */
701 case HTTPSTATE_SEND_HEADER:
702 case RTSPSTATE_SEND_REPLY:
703 case RTSPSTATE_SEND_PACKET:
704 c->poll_entry = poll_entry;
706 poll_entry->events = POLLOUT;
709 case HTTPSTATE_SEND_DATA_HEADER:
710 case HTTPSTATE_SEND_DATA:
711 case HTTPSTATE_SEND_DATA_TRAILER:
712 if (!c->is_packetized) {
713 /* for TCP, we output as much as we can
714 * (may need to put a limit) */
715 c->poll_entry = poll_entry;
717 poll_entry->events = POLLOUT;
720 /* when ffserver is doing the timing, we work by
721 looking at which packet needs to be sent every
723 /* one tick wait XXX: 10 ms assumed */
728 case HTTPSTATE_WAIT_REQUEST:
729 case HTTPSTATE_RECEIVE_DATA:
730 case HTTPSTATE_WAIT_FEED:
731 case RTSPSTATE_WAIT_REQUEST:
732 /* need to catch errors */
733 c->poll_entry = poll_entry;
735 poll_entry->events = POLLIN;/* Maybe this will work */
739 c->poll_entry = NULL;
745 /* wait for an event on one connection. We poll at least every
746 second to handle timeouts */
748 ret = poll(poll_table, poll_entry - poll_table, delay);
749 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
750 ff_neterrno() != AVERROR(EINTR))
754 cur_time = av_gettime() / 1000;
756 if (need_to_start_children) {
757 need_to_start_children = 0;
758 start_children(first_feed);
761 /* now handle the events */
762 for(c = first_http_ctx; c != NULL; c = c_next) {
764 if (handle_connection(c) < 0) {
766 /* close and free the connection */
771 poll_entry = poll_table;
773 /* new HTTP connection request ? */
774 if (poll_entry->revents & POLLIN)
775 new_connection(server_fd, 0);
778 if (rtsp_server_fd) {
779 /* new RTSP connection request ? */
780 if (poll_entry->revents & POLLIN)
781 new_connection(rtsp_server_fd, 1);
786 /* start waiting for a new HTTP/RTSP request */
787 static void start_wait_request(HTTPContext *c, int is_rtsp)
789 c->buffer_ptr = c->buffer;
790 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
793 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
794 c->state = RTSPSTATE_WAIT_REQUEST;
796 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
797 c->state = HTTPSTATE_WAIT_REQUEST;
801 static void http_send_too_busy_reply(int fd)
804 int len = snprintf(buffer, sizeof(buffer),
805 "HTTP/1.0 503 Server too busy\r\n"
806 "Content-type: text/html\r\n"
808 "<html><head><title>Too busy</title></head><body>\r\n"
809 "<p>The server is too busy to serve your request at this time.</p>\r\n"
810 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
811 "</body></html>\r\n",
812 nb_connections, nb_max_connections);
813 av_assert0(len < sizeof(buffer));
814 if (send(fd, buffer, len, 0) < len)
815 av_log(NULL, AV_LOG_WARNING, "Could not send too-busy reply, send() failed\n");
819 static void new_connection(int server_fd, int is_rtsp)
821 struct sockaddr_in from_addr;
824 HTTPContext *c = NULL;
826 len = sizeof(from_addr);
827 fd = accept(server_fd, (struct sockaddr *)&from_addr,
830 http_log("error during accept %s\n", strerror(errno));
833 if (ff_socket_nonblock(fd, 1) < 0)
834 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
836 if (nb_connections >= nb_max_connections) {
837 http_send_too_busy_reply(fd);
841 /* add a new connection */
842 c = av_mallocz(sizeof(HTTPContext));
847 c->poll_entry = NULL;
848 c->from_addr = from_addr;
849 c->buffer_size = IOBUFFER_INIT_SIZE;
850 c->buffer = av_malloc(c->buffer_size);
854 c->next = first_http_ctx;
858 start_wait_request(c, is_rtsp);
870 static void close_connection(HTTPContext *c)
872 HTTPContext **cp, *c1;
874 AVFormatContext *ctx;
878 /* remove connection from list */
879 cp = &first_http_ctx;
880 while ((*cp) != NULL) {
888 /* remove references, if any (XXX: do it faster) */
889 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
894 /* remove connection associated resources */
898 /* close each frame parser */
899 for(i=0;i<c->fmt_in->nb_streams;i++) {
900 st = c->fmt_in->streams[i];
901 if (st->codec->codec)
902 avcodec_close(st->codec);
904 avformat_close_input(&c->fmt_in);
907 /* free RTP output streams if any */
910 nb_streams = c->stream->nb_streams;
912 for(i=0;i<nb_streams;i++) {
915 av_write_trailer(ctx);
916 av_dict_free(&ctx->metadata);
917 av_free(ctx->streams[0]);
920 h = c->rtp_handles[i];
927 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
930 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
931 av_write_trailer(ctx);
932 av_freep(&c->pb_buffer);
933 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
938 for(i=0; i<ctx->nb_streams; i++)
939 av_free(ctx->streams[i]);
940 av_freep(&ctx->streams);
941 av_freep(&ctx->priv_data);
943 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
944 current_bandwidth -= c->stream->bandwidth;
946 /* signal that there is no feed if we are the feeder socket */
947 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
948 c->stream->feed_opened = 0;
952 av_freep(&c->pb_buffer);
953 av_freep(&c->packet_buffer);
959 static int handle_connection(HTTPContext *c)
964 case HTTPSTATE_WAIT_REQUEST:
965 case RTSPSTATE_WAIT_REQUEST:
967 if ((c->timeout - cur_time) < 0)
969 if (c->poll_entry->revents & (POLLERR | POLLHUP))
972 /* no need to read if no events */
973 if (!(c->poll_entry->revents & POLLIN))
977 len = recv(c->fd, c->buffer_ptr, 1, 0);
979 if (ff_neterrno() != AVERROR(EAGAIN) &&
980 ff_neterrno() != AVERROR(EINTR))
982 } else if (len == 0) {
985 /* search for end of request. */
987 c->buffer_ptr += len;
989 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
990 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
991 /* request found : parse it and reply */
992 if (c->state == HTTPSTATE_WAIT_REQUEST) {
993 ret = http_parse_request(c);
995 ret = rtsp_parse_request(c);
999 } else if (ptr >= c->buffer_end) {
1000 /* request too long: cannot do anything */
1002 } else goto read_loop;
1006 case HTTPSTATE_SEND_HEADER:
1007 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1010 /* no need to write if no events */
1011 if (!(c->poll_entry->revents & POLLOUT))
1013 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1015 if (ff_neterrno() != AVERROR(EAGAIN) &&
1016 ff_neterrno() != AVERROR(EINTR)) {
1017 goto close_connection;
1020 c->buffer_ptr += len;
1022 c->stream->bytes_served += len;
1023 c->data_count += len;
1024 if (c->buffer_ptr >= c->buffer_end) {
1025 av_freep(&c->pb_buffer);
1026 /* if error, exit */
1029 /* all the buffer was sent : synchronize to the incoming
1031 c->state = HTTPSTATE_SEND_DATA_HEADER;
1032 c->buffer_ptr = c->buffer_end = c->buffer;
1037 case HTTPSTATE_SEND_DATA:
1038 case HTTPSTATE_SEND_DATA_HEADER:
1039 case HTTPSTATE_SEND_DATA_TRAILER:
1040 /* for packetized output, we consider we can always write (the
1041 input streams set the speed). It may be better to verify
1042 that we do not rely too much on the kernel queues */
1043 if (!c->is_packetized) {
1044 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1047 /* no need to read if no events */
1048 if (!(c->poll_entry->revents & POLLOUT))
1051 if (http_send_data(c) < 0)
1053 /* close connection if trailer sent */
1054 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1057 case HTTPSTATE_RECEIVE_DATA:
1058 /* no need to read if no events */
1059 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1061 if (!(c->poll_entry->revents & POLLIN))
1063 if (http_receive_data(c) < 0)
1066 case HTTPSTATE_WAIT_FEED:
1067 /* no need to read if no events */
1068 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1071 /* nothing to do, we'll be waken up by incoming feed packets */
1074 case RTSPSTATE_SEND_REPLY:
1075 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1076 goto close_connection;
1077 /* no need to write if no events */
1078 if (!(c->poll_entry->revents & POLLOUT))
1080 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1082 if (ff_neterrno() != AVERROR(EAGAIN) &&
1083 ff_neterrno() != AVERROR(EINTR)) {
1084 goto close_connection;
1087 c->buffer_ptr += len;
1088 c->data_count += len;
1089 if (c->buffer_ptr >= c->buffer_end) {
1090 /* all the buffer was sent : wait for a new request */
1091 av_freep(&c->pb_buffer);
1092 start_wait_request(c, 1);
1096 case RTSPSTATE_SEND_PACKET:
1097 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1098 av_freep(&c->packet_buffer);
1101 /* no need to write if no events */
1102 if (!(c->poll_entry->revents & POLLOUT))
1104 len = send(c->fd, c->packet_buffer_ptr,
1105 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1107 if (ff_neterrno() != AVERROR(EAGAIN) &&
1108 ff_neterrno() != AVERROR(EINTR)) {
1109 /* error : close connection */
1110 av_freep(&c->packet_buffer);
1114 c->packet_buffer_ptr += len;
1115 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1116 /* all the buffer was sent : wait for a new request */
1117 av_freep(&c->packet_buffer);
1118 c->state = RTSPSTATE_WAIT_REQUEST;
1122 case HTTPSTATE_READY:
1131 av_freep(&c->pb_buffer);
1135 static int extract_rates(char *rates, int ratelen, const char *request)
1139 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1140 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1141 const char *q = p + 7;
1143 while (*q && *q != '\n' && av_isspace(*q))
1146 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1152 memset(rates, 0xff, ratelen);
1155 while (*q && *q != '\n' && *q != ':')
1158 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1162 if (stream_no < ratelen && stream_no >= 0)
1163 rates[stream_no] = rate_no;
1165 while (*q && *q != '\n' && !av_isspace(*q))
1172 p = strchr(p, '\n');
1182 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1185 int best_bitrate = 100000000;
1188 for (i = 0; i < feed->nb_streams; i++) {
1189 AVCodecContext *feed_codec = feed->streams[i]->codec;
1191 if (feed_codec->codec_id != codec->codec_id ||
1192 feed_codec->sample_rate != codec->sample_rate ||
1193 feed_codec->width != codec->width ||
1194 feed_codec->height != codec->height)
1197 /* Potential stream */
1199 /* We want the fastest stream less than bit_rate, or the slowest
1200 * faster than bit_rate
1203 if (feed_codec->bit_rate <= bit_rate) {
1204 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1205 best_bitrate = feed_codec->bit_rate;
1209 if (feed_codec->bit_rate < best_bitrate) {
1210 best_bitrate = feed_codec->bit_rate;
1219 static int modify_current_stream(HTTPContext *c, char *rates)
1222 FFStream *req = c->stream;
1223 int action_required = 0;
1225 /* Not much we can do for a feed */
1229 for (i = 0; i < req->nb_streams; i++) {
1230 AVCodecContext *codec = req->streams[i]->codec;
1234 c->switch_feed_streams[i] = req->feed_streams[i];
1237 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1240 /* Wants off or slow */
1241 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1243 /* This doesn't work well when it turns off the only stream! */
1244 c->switch_feed_streams[i] = -2;
1245 c->feed_streams[i] = -2;
1250 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1251 action_required = 1;
1254 return action_required;
1257 /* XXX: factorize in utils.c ? */
1258 /* XXX: take care with different space meaning */
1259 static void skip_spaces(const char **pp)
1263 while (*p == ' ' || *p == '\t')
1268 static void get_word(char *buf, int buf_size, const char **pp)
1276 while (!av_isspace(*p) && *p != '\0') {
1277 if ((q - buf) < buf_size - 1)
1286 static void get_arg(char *buf, int buf_size, const char **pp)
1293 while (av_isspace(*p)) p++;
1296 if (*p == '\"' || *p == '\'')
1308 if ((q - buf) < buf_size - 1)
1313 if (quote && *p == quote)
1318 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1319 const char *p, const char *filename, int line_num)
1325 get_arg(arg, sizeof(arg), &p);
1326 if (av_strcasecmp(arg, "allow") == 0)
1327 acl.action = IP_ALLOW;
1328 else if (av_strcasecmp(arg, "deny") == 0)
1329 acl.action = IP_DENY;
1331 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1332 filename, line_num, arg);
1336 get_arg(arg, sizeof(arg), &p);
1338 if (resolve_host(&acl.first, arg) != 0) {
1339 fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1340 filename, line_num, arg);
1343 acl.last = acl.first;
1345 get_arg(arg, sizeof(arg), &p);
1348 if (resolve_host(&acl.last, arg) != 0) {
1349 fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1350 filename, line_num, arg);
1356 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1357 IPAddressACL **naclp = 0;
1363 naclp = &stream->acl;
1369 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1370 filename, line_num);
1376 naclp = &(*naclp)->next;
1385 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1390 IPAddressACL *acl = NULL;
1394 f = fopen(stream->dynamic_acl, "r");
1396 perror(stream->dynamic_acl);
1400 acl = av_mallocz(sizeof(IPAddressACL));
1404 if (fgets(line, sizeof(line), f) == NULL)
1408 while (av_isspace(*p))
1410 if (*p == '\0' || *p == '#')
1412 get_arg(cmd, sizeof(cmd), &p);
1414 if (!av_strcasecmp(cmd, "ACL"))
1415 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1422 static void free_acl_list(IPAddressACL *in_acl)
1424 IPAddressACL *pacl,*pacl2;
1434 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1436 enum IPAddressAction last_action = IP_DENY;
1438 struct in_addr *src = &c->from_addr.sin_addr;
1439 unsigned long src_addr = src->s_addr;
1441 for (acl = in_acl; acl; acl = acl->next) {
1442 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1443 return (acl->action == IP_ALLOW) ? 1 : 0;
1444 last_action = acl->action;
1447 /* Nothing matched, so return not the last action */
1448 return (last_action == IP_DENY) ? 1 : 0;
1451 static int validate_acl(FFStream *stream, HTTPContext *c)
1457 /* if stream->acl is null validate_acl_list will return 1 */
1458 ret = validate_acl_list(stream->acl, c);
1460 if (stream->dynamic_acl[0]) {
1461 acl = parse_dynamic_acl(stream, c);
1463 ret = validate_acl_list(acl, c);
1471 /* compute the real filename of a file by matching it without its
1472 extensions to all the stream's filenames */
1473 static void compute_real_filename(char *filename, int max_size)
1480 /* compute filename by matching without the file extensions */
1481 av_strlcpy(file1, filename, sizeof(file1));
1482 p = strrchr(file1, '.');
1485 for(stream = first_stream; stream != NULL; stream = stream->next) {
1486 av_strlcpy(file2, stream->filename, sizeof(file2));
1487 p = strrchr(file2, '.');
1490 if (!strcmp(file1, file2)) {
1491 av_strlcpy(filename, stream->filename, max_size);
1506 /* parse HTTP request and prepare header */
1507 static int http_parse_request(HTTPContext *c)
1511 enum RedirType redir_type;
1513 char info[1024], filename[1024];
1517 const char *mime_type;
1521 const char *useragent = 0;
1524 get_word(cmd, sizeof(cmd), &p);
1525 av_strlcpy(c->method, cmd, sizeof(c->method));
1527 if (!strcmp(cmd, "GET"))
1529 else if (!strcmp(cmd, "POST"))
1534 get_word(url, sizeof(url), &p);
1535 av_strlcpy(c->url, url, sizeof(c->url));
1537 get_word(protocol, sizeof(protocol), (const char **)&p);
1538 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1541 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1544 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1546 /* find the filename and the optional info string in the request */
1547 p1 = strchr(url, '?');
1549 av_strlcpy(info, p1, sizeof(info));
1554 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1556 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1557 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1559 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1563 p = strchr(p, '\n');
1570 redir_type = REDIR_NONE;
1571 if (av_match_ext(filename, "asx")) {
1572 redir_type = REDIR_ASX;
1573 filename[strlen(filename)-1] = 'f';
1574 } else if (av_match_ext(filename, "asf") &&
1575 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1576 /* if this isn't WMP or lookalike, return the redirector file */
1577 redir_type = REDIR_ASF;
1578 } else if (av_match_ext(filename, "rpm,ram")) {
1579 redir_type = REDIR_RAM;
1580 strcpy(filename + strlen(filename)-2, "m");
1581 } else if (av_match_ext(filename, "rtsp")) {
1582 redir_type = REDIR_RTSP;
1583 compute_real_filename(filename, sizeof(filename) - 1);
1584 } else if (av_match_ext(filename, "sdp")) {
1585 redir_type = REDIR_SDP;
1586 compute_real_filename(filename, sizeof(filename) - 1);
1589 // "redirect" / request to index.html
1590 if (!strlen(filename))
1591 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1593 stream = first_stream;
1594 while (stream != NULL) {
1595 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1597 stream = stream->next;
1599 if (stream == NULL) {
1600 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1601 http_log("File '%s' not found\n", url);
1606 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1607 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1609 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1610 c->http_error = 301;
1612 snprintf(q, c->buffer_size,
1613 "HTTP/1.0 301 Moved\r\n"
1615 "Content-type: text/html\r\n"
1617 "<html><head><title>Moved</title></head><body>\r\n"
1618 "You should be <a href=\"%s\">redirected</a>.\r\n"
1619 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1621 /* prepare output buffer */
1622 c->buffer_ptr = c->buffer;
1624 c->state = HTTPSTATE_SEND_HEADER;
1628 /* If this is WMP, get the rate information */
1629 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1630 if (modify_current_stream(c, ratebuf)) {
1631 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1632 if (c->switch_feed_streams[i] >= 0)
1633 c->switch_feed_streams[i] = -1;
1638 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1639 current_bandwidth += stream->bandwidth;
1641 /* If already streaming this feed, do not let start another feeder. */
1642 if (stream->feed_opened) {
1643 snprintf(msg, sizeof(msg), "This feed is already being received.");
1644 http_log("Feed '%s' already being received\n", stream->feed_filename);
1648 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1649 c->http_error = 503;
1651 snprintf(q, c->buffer_size,
1652 "HTTP/1.0 503 Server too busy\r\n"
1653 "Content-type: text/html\r\n"
1655 "<html><head><title>Too busy</title></head><body>\r\n"
1656 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1657 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1658 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1659 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1661 /* prepare output buffer */
1662 c->buffer_ptr = c->buffer;
1664 c->state = HTTPSTATE_SEND_HEADER;
1668 if (redir_type != REDIR_NONE) {
1669 const char *hostinfo = 0;
1671 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1672 if (av_strncasecmp(p, "Host:", 5) == 0) {
1676 p = strchr(p, '\n');
1687 while (av_isspace(*hostinfo))
1690 eoh = strchr(hostinfo, '\n');
1692 if (eoh[-1] == '\r')
1695 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1696 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1697 hostbuf[eoh - hostinfo] = 0;
1699 c->http_error = 200;
1701 switch(redir_type) {
1703 snprintf(q, c->buffer_size,
1704 "HTTP/1.0 200 ASX Follows\r\n"
1705 "Content-type: video/x-ms-asf\r\n"
1707 "<ASX Version=\"3\">\r\n"
1708 //"<!-- Autogenerated by ffserver -->\r\n"
1709 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1710 "</ASX>\r\n", hostbuf, filename, info);
1714 snprintf(q, c->buffer_size,
1715 "HTTP/1.0 200 RAM Follows\r\n"
1716 "Content-type: audio/x-pn-realaudio\r\n"
1718 "# Autogenerated by ffserver\r\n"
1719 "http://%s/%s%s\r\n", hostbuf, filename, info);
1723 snprintf(q, c->buffer_size,
1724 "HTTP/1.0 200 ASF Redirect follows\r\n"
1725 "Content-type: video/x-ms-asf\r\n"
1728 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1733 char hostname[256], *p;
1734 /* extract only hostname */
1735 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1736 p = strrchr(hostname, ':');
1739 snprintf(q, c->buffer_size,
1740 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1741 /* XXX: incorrect MIME type ? */
1742 "Content-type: application/x-rtsp\r\n"
1744 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1753 struct sockaddr_in my_addr;
1755 snprintf(q, c->buffer_size,
1756 "HTTP/1.0 200 OK\r\n"
1757 "Content-type: application/sdp\r\n"
1761 len = sizeof(my_addr);
1763 /* XXX: Should probably fail? */
1764 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1765 http_log("getsockname() failed\n");
1767 /* XXX: should use a dynamic buffer */
1768 sdp_data_size = prepare_sdp_description(stream,
1771 if (sdp_data_size > 0) {
1772 memcpy(q, sdp_data, sdp_data_size);
1784 /* prepare output buffer */
1785 c->buffer_ptr = c->buffer;
1787 c->state = HTTPSTATE_SEND_HEADER;
1793 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1797 stream->conns_served++;
1799 /* XXX: add there authenticate and IP match */
1802 /* if post, it means a feed is being sent */
1803 if (!stream->is_feed) {
1804 /* However it might be a status report from WMP! Let us log the
1805 * data as it might come handy one day. */
1806 const char *logline = 0;
1809 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1810 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1814 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1815 client_id = strtol(p + 18, 0, 10);
1816 p = strchr(p, '\n');
1824 char *eol = strchr(logline, '\n');
1829 if (eol[-1] == '\r')
1831 http_log("%.*s\n", (int) (eol - logline), logline);
1832 c->suppress_log = 1;
1837 http_log("\nGot request:\n%s\n", c->buffer);
1840 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1843 /* Now we have to find the client_id */
1844 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1845 if (wmpc->wmp_client_id == client_id)
1849 if (wmpc && modify_current_stream(wmpc, ratebuf))
1850 wmpc->switch_pending = 1;
1853 snprintf(msg, sizeof(msg), "POST command not handled");
1857 if (http_start_receive_data(c) < 0) {
1858 snprintf(msg, sizeof(msg), "could not open feed");
1862 c->state = HTTPSTATE_RECEIVE_DATA;
1867 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1868 http_log("\nGot request:\n%s\n", c->buffer);
1871 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1874 /* open input stream */
1875 if (open_input_stream(c, info) < 0) {
1876 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1880 /* prepare HTTP header */
1882 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1883 mime_type = c->stream->fmt->mime_type;
1885 mime_type = "application/x-octet-stream";
1886 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1888 /* for asf, we need extra headers */
1889 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1890 /* Need to allocate a client id */
1892 c->wmp_client_id = av_lfg_get(&random_state);
1894 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);
1896 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1897 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1898 q = c->buffer + strlen(c->buffer);
1900 /* prepare output buffer */
1902 c->buffer_ptr = c->buffer;
1904 c->state = HTTPSTATE_SEND_HEADER;
1907 c->http_error = 404;
1910 snprintf(q, c->buffer_size,
1911 "HTTP/1.0 404 Not Found\r\n"
1912 "Content-type: text/html\r\n"
1915 "<head><title>404 Not Found</title></head>\n"
1919 /* prepare output buffer */
1920 c->buffer_ptr = c->buffer;
1922 c->state = HTTPSTATE_SEND_HEADER;
1926 c->http_error = 200; /* horrible : we use this value to avoid
1927 going to the send data state */
1928 c->state = HTTPSTATE_SEND_HEADER;
1932 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1934 static const char suffix[] = " kMGTP";
1937 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1939 avio_printf(pb, "%"PRId64"%c", count, *s);
1942 static void compute_status(HTTPContext *c)
1951 if (avio_open_dyn_buf(&pb) < 0) {
1952 /* XXX: return an error ? */
1953 c->buffer_ptr = c->buffer;
1954 c->buffer_end = c->buffer;
1958 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1959 avio_printf(pb, "Content-type: text/html\r\n");
1960 avio_printf(pb, "Pragma: no-cache\r\n");
1961 avio_printf(pb, "\r\n");
1963 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1964 if (c->stream->feed_filename[0])
1965 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1966 avio_printf(pb, "</head>\n<body>");
1967 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1969 avio_printf(pb, "<h2>Available Streams</h2>\n");
1970 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1971 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");
1972 stream = first_stream;
1973 while (stream != NULL) {
1974 char sfilename[1024];
1977 if (stream->feed != stream) {
1978 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1979 eosf = sfilename + strlen(sfilename);
1980 if (eosf - sfilename >= 4) {
1981 if (strcmp(eosf - 4, ".asf") == 0)
1982 strcpy(eosf - 4, ".asx");
1983 else if (strcmp(eosf - 3, ".rm") == 0)
1984 strcpy(eosf - 3, ".ram");
1985 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1986 /* generate a sample RTSP director if
1987 unicast. Generate an SDP redirector if
1989 eosf = strrchr(sfilename, '.');
1991 eosf = sfilename + strlen(sfilename);
1992 if (stream->is_multicast)
1993 strcpy(eosf, ".sdp");
1995 strcpy(eosf, ".rtsp");
1999 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
2000 sfilename, stream->filename);
2001 avio_printf(pb, "<td align=right> %d <td align=right> ",
2002 stream->conns_served);
2003 fmt_bytecount(pb, stream->bytes_served);
2004 switch(stream->stream_type) {
2005 case STREAM_TYPE_LIVE: {
2006 int audio_bit_rate = 0;
2007 int video_bit_rate = 0;
2008 const char *audio_codec_name = "";
2009 const char *video_codec_name = "";
2010 const char *audio_codec_name_extra = "";
2011 const char *video_codec_name_extra = "";
2013 for(i=0;i<stream->nb_streams;i++) {
2014 AVStream *st = stream->streams[i];
2015 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2016 switch(st->codec->codec_type) {
2017 case AVMEDIA_TYPE_AUDIO:
2018 audio_bit_rate += st->codec->bit_rate;
2020 if (*audio_codec_name)
2021 audio_codec_name_extra = "...";
2022 audio_codec_name = codec->name;
2025 case AVMEDIA_TYPE_VIDEO:
2026 video_bit_rate += st->codec->bit_rate;
2028 if (*video_codec_name)
2029 video_codec_name_extra = "...";
2030 video_codec_name = codec->name;
2033 case AVMEDIA_TYPE_DATA:
2034 video_bit_rate += st->codec->bit_rate;
2040 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",
2043 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2044 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2046 avio_printf(pb, "<td>%s", stream->feed->filename);
2048 avio_printf(pb, "<td>%s", stream->feed_filename);
2049 avio_printf(pb, "\n");
2053 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2057 stream = stream->next;
2059 avio_printf(pb, "</table>\n");
2061 stream = first_stream;
2062 while (stream != NULL) {
2063 if (stream->feed == stream) {
2064 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2066 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2073 /* This is somewhat linux specific I guess */
2074 snprintf(ps_cmd, sizeof(ps_cmd),
2075 "ps -o \"%%cpu,cputime\" --no-headers %d",
2078 pid_stat = popen(ps_cmd, "r");
2083 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2085 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2093 avio_printf(pb, "<p>");
2095 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");
2097 for (i = 0; i < stream->nb_streams; i++) {
2098 AVStream *st = stream->streams[i];
2099 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2100 const char *type = "unknown";
2101 char parameters[64];
2105 switch(st->codec->codec_type) {
2106 case AVMEDIA_TYPE_AUDIO:
2108 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2110 case AVMEDIA_TYPE_VIDEO:
2112 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2113 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2118 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2119 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2121 avio_printf(pb, "</table>\n");
2124 stream = stream->next;
2127 /* connection status */
2128 avio_printf(pb, "<h2>Connection Status</h2>\n");
2130 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2131 nb_connections, nb_max_connections);
2133 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2134 current_bandwidth, max_bandwidth);
2136 avio_printf(pb, "<table>\n");
2137 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");
2138 c1 = first_http_ctx;
2140 while (c1 != NULL) {
2146 for (j = 0; j < c1->stream->nb_streams; j++) {
2147 if (!c1->stream->feed)
2148 bitrate += c1->stream->streams[j]->codec->bit_rate;
2149 else if (c1->feed_streams[j] >= 0)
2150 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2155 p = inet_ntoa(c1->from_addr.sin_addr);
2156 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2158 c1->stream ? c1->stream->filename : "",
2159 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2162 http_state[c1->state]);
2163 fmt_bytecount(pb, bitrate);
2164 avio_printf(pb, "<td align=right>");
2165 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2166 avio_printf(pb, "<td align=right>");
2167 fmt_bytecount(pb, c1->data_count);
2168 avio_printf(pb, "\n");
2171 avio_printf(pb, "</table>\n");
2176 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2177 avio_printf(pb, "</body>\n</html>\n");
2179 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2180 c->buffer_ptr = c->pb_buffer;
2181 c->buffer_end = c->pb_buffer + len;
2184 static int open_input_stream(HTTPContext *c, const char *info)
2187 char input_filename[1024];
2188 AVFormatContext *s = NULL;
2189 int buf_size, i, ret;
2192 /* find file name */
2193 if (c->stream->feed) {
2194 strcpy(input_filename, c->stream->feed->feed_filename);
2195 buf_size = FFM_PACKET_SIZE;
2196 /* compute position (absolute time) */
2197 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2198 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2199 http_log("Invalid date specification '%s' for stream\n", buf);
2202 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2203 int prebuffer = strtol(buf, 0, 10);
2204 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2206 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2208 strcpy(input_filename, c->stream->feed_filename);
2210 /* compute position (relative time) */
2211 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2212 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2213 http_log("Invalid date specification '%s' for stream\n", buf);
2219 if (!input_filename[0]) {
2220 http_log("No filename was specified for stream\n");
2221 return AVERROR(EINVAL);
2225 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2226 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2230 /* set buffer size */
2231 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2233 s->flags |= AVFMT_FLAG_GENPTS;
2235 if (strcmp(s->iformat->name, "ffm") &&
2236 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2237 http_log("Could not find stream info for input '%s'\n", input_filename);
2238 avformat_close_input(&s);
2242 /* choose stream as clock source (we favor the video stream if
2243 * present) for packet sending */
2244 c->pts_stream_index = 0;
2245 for(i=0;i<c->stream->nb_streams;i++) {
2246 if (c->pts_stream_index == 0 &&
2247 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2248 c->pts_stream_index = i;
2252 if (c->fmt_in->iformat->read_seek)
2253 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2254 /* set the start time (needed for maxtime and RTP packet timing) */
2255 c->start_time = cur_time;
2256 c->first_pts = AV_NOPTS_VALUE;
2260 /* return the server clock (in us) */
2261 static int64_t get_server_clock(HTTPContext *c)
2263 /* compute current pts value from system time */
2264 return (cur_time - c->start_time) * 1000;
2267 /* return the estimated time at which the current packet must be sent
2269 static int64_t get_packet_send_clock(HTTPContext *c)
2271 int bytes_left, bytes_sent, frame_bytes;
2273 frame_bytes = c->cur_frame_bytes;
2274 if (frame_bytes <= 0)
2277 bytes_left = c->buffer_end - c->buffer_ptr;
2278 bytes_sent = frame_bytes - bytes_left;
2279 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2284 static int http_prepare_data(HTTPContext *c)
2287 AVFormatContext *ctx;
2289 av_freep(&c->pb_buffer);
2291 case HTTPSTATE_SEND_DATA_HEADER:
2292 ctx = avformat_alloc_context();
2295 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2296 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2298 for(i=0;i<c->stream->nb_streams;i++) {
2300 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2301 /* if file or feed, then just take streams from FFStream struct */
2302 if (!c->stream->feed ||
2303 c->stream->feed == c->stream)
2304 src = c->stream->streams[i];
2306 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2308 *(c->fmt_ctx.streams[i]) = *src;
2309 c->fmt_ctx.streams[i]->priv_data = 0;
2310 /* XXX: should be done in AVStream, not in codec */
2311 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2313 /* set output format parameters */
2314 c->fmt_ctx.oformat = c->stream->fmt;
2315 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2317 c->got_key_frame = 0;
2319 /* prepare header and save header data in a stream */
2320 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2321 /* XXX: potential leak */
2324 c->fmt_ctx.pb->seekable = 0;
2327 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2328 * Default value from FFmpeg
2329 * Try to set it using configuration option
2331 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2333 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2334 http_log("Error writing output header for stream '%s': %s\n",
2335 c->stream->filename, av_err2str(ret));
2338 av_dict_free(&c->fmt_ctx.metadata);
2340 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2341 c->buffer_ptr = c->pb_buffer;
2342 c->buffer_end = c->pb_buffer + len;
2344 c->state = HTTPSTATE_SEND_DATA;
2345 c->last_packet_sent = 0;
2347 case HTTPSTATE_SEND_DATA:
2348 /* find a new packet */
2349 /* read a packet from the input stream */
2350 if (c->stream->feed)
2351 ffm_set_write_index(c->fmt_in,
2352 c->stream->feed->feed_write_index,
2353 c->stream->feed->feed_size);
2355 if (c->stream->max_time &&
2356 c->stream->max_time + c->start_time - cur_time < 0)
2357 /* We have timed out */
2358 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2362 ret = av_read_frame(c->fmt_in, &pkt);
2364 if (c->stream->feed) {
2365 /* if coming from feed, it means we reached the end of the
2366 ffm file, so must wait for more data */
2367 c->state = HTTPSTATE_WAIT_FEED;
2368 return 1; /* state changed */
2369 } else if (ret == AVERROR(EAGAIN)) {
2370 /* input not ready, come back later */
2373 if (c->stream->loop) {
2374 avformat_close_input(&c->fmt_in);
2375 if (open_input_stream(c, "") < 0)
2380 /* must send trailer now because EOF or error */
2381 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2385 int source_index = pkt.stream_index;
2386 /* update first pts if needed */
2387 if (c->first_pts == AV_NOPTS_VALUE) {
2388 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2389 c->start_time = cur_time;
2391 /* send it to the appropriate stream */
2392 if (c->stream->feed) {
2393 /* if coming from a feed, select the right stream */
2394 if (c->switch_pending) {
2395 c->switch_pending = 0;
2396 for(i=0;i<c->stream->nb_streams;i++) {
2397 if (c->switch_feed_streams[i] == pkt.stream_index)
2398 if (pkt.flags & AV_PKT_FLAG_KEY)
2399 c->switch_feed_streams[i] = -1;
2400 if (c->switch_feed_streams[i] >= 0)
2401 c->switch_pending = 1;
2404 for(i=0;i<c->stream->nb_streams;i++) {
2405 if (c->stream->feed_streams[i] == pkt.stream_index) {
2406 AVStream *st = c->fmt_in->streams[source_index];
2407 pkt.stream_index = i;
2408 if (pkt.flags & AV_PKT_FLAG_KEY &&
2409 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2410 c->stream->nb_streams == 1))
2411 c->got_key_frame = 1;
2412 if (!c->stream->send_on_key || c->got_key_frame)
2417 AVCodecContext *codec;
2418 AVStream *ist, *ost;
2420 ist = c->fmt_in->streams[source_index];
2421 /* specific handling for RTP: we use several
2422 * output streams (one for each RTP connection).
2423 * XXX: need more abstract handling */
2424 if (c->is_packetized) {
2425 /* compute send time and duration */
2426 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2427 c->cur_pts -= c->first_pts;
2428 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2429 /* find RTP context */
2430 c->packet_stream_index = pkt.stream_index;
2431 ctx = c->rtp_ctx[c->packet_stream_index];
2433 av_free_packet(&pkt);
2436 codec = ctx->streams[0]->codec;
2437 /* only one stream per RTP connection */
2438 pkt.stream_index = 0;
2442 codec = ctx->streams[pkt.stream_index]->codec;
2445 if (c->is_packetized) {
2446 int max_packet_size;
2447 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2448 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2450 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2451 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2453 ret = avio_open_dyn_buf(&ctx->pb);
2456 /* XXX: potential leak */
2459 ost = ctx->streams[pkt.stream_index];
2461 ctx->pb->seekable = 0;
2462 if (pkt.dts != AV_NOPTS_VALUE)
2463 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2464 if (pkt.pts != AV_NOPTS_VALUE)
2465 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2466 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2467 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2468 http_log("Error writing frame to output for stream '%s': %s\n",
2469 c->stream->filename, av_err2str(ret));
2470 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2473 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2474 c->cur_frame_bytes = len;
2475 c->buffer_ptr = c->pb_buffer;
2476 c->buffer_end = c->pb_buffer + len;
2478 codec->frame_number++;
2480 av_free_packet(&pkt);
2484 av_free_packet(&pkt);
2489 case HTTPSTATE_SEND_DATA_TRAILER:
2490 /* last packet test ? */
2491 if (c->last_packet_sent || c->is_packetized)
2494 /* prepare header */
2495 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2496 /* XXX: potential leak */
2499 c->fmt_ctx.pb->seekable = 0;
2500 av_write_trailer(ctx);
2501 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2502 c->buffer_ptr = c->pb_buffer;
2503 c->buffer_end = c->pb_buffer + len;
2505 c->last_packet_sent = 1;
2511 /* should convert the format at the same time */
2512 /* send data starting at c->buffer_ptr to the output connection
2513 * (either UDP or TCP) */
2514 static int http_send_data(HTTPContext *c)
2519 if (c->buffer_ptr >= c->buffer_end) {
2520 ret = http_prepare_data(c);
2524 /* state change requested */
2527 if (c->is_packetized) {
2528 /* RTP data output */
2529 len = c->buffer_end - c->buffer_ptr;
2531 /* fail safe - should never happen */
2533 c->buffer_ptr = c->buffer_end;
2536 len = (c->buffer_ptr[0] << 24) |
2537 (c->buffer_ptr[1] << 16) |
2538 (c->buffer_ptr[2] << 8) |
2540 if (len > (c->buffer_end - c->buffer_ptr))
2542 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2543 /* nothing to send yet: we can wait */
2547 c->data_count += len;
2548 update_datarate(&c->datarate, c->data_count);
2550 c->stream->bytes_served += len;
2552 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2553 /* RTP packets are sent inside the RTSP TCP connection */
2555 int interleaved_index, size;
2557 HTTPContext *rtsp_c;
2560 /* if no RTSP connection left, error */
2563 /* if already sending something, then wait. */
2564 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2566 if (avio_open_dyn_buf(&pb) < 0)
2568 interleaved_index = c->packet_stream_index * 2;
2569 /* RTCP packets are sent at odd indexes */
2570 if (c->buffer_ptr[1] == 200)
2571 interleaved_index++;
2572 /* write RTSP TCP header */
2574 header[1] = interleaved_index;
2575 header[2] = len >> 8;
2577 avio_write(pb, header, 4);
2578 /* write RTP packet data */
2580 avio_write(pb, c->buffer_ptr, len);
2581 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2582 /* prepare asynchronous TCP sending */
2583 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2584 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2585 c->buffer_ptr += len;
2587 /* send everything we can NOW */
2588 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2589 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2591 rtsp_c->packet_buffer_ptr += len;
2592 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2593 /* if we could not send all the data, we will
2594 send it later, so a new state is needed to
2595 "lock" the RTSP TCP connection */
2596 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2599 /* all data has been sent */
2600 av_freep(&c->packet_buffer);
2602 /* send RTP packet directly in UDP */
2604 ffurl_write(c->rtp_handles[c->packet_stream_index],
2605 c->buffer_ptr, len);
2606 c->buffer_ptr += len;
2607 /* here we continue as we can send several packets per 10 ms slot */
2610 /* TCP data output */
2611 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2613 if (ff_neterrno() != AVERROR(EAGAIN) &&
2614 ff_neterrno() != AVERROR(EINTR))
2615 /* error : close connection */
2620 c->buffer_ptr += len;
2622 c->data_count += len;
2623 update_datarate(&c->datarate, c->data_count);
2625 c->stream->bytes_served += len;
2633 static int http_start_receive_data(HTTPContext *c)
2638 if (c->stream->feed_opened) {
2639 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2640 return AVERROR(EINVAL);
2643 /* Don't permit writing to this one */
2644 if (c->stream->readonly) {
2645 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2646 return AVERROR(EINVAL);
2650 fd = open(c->stream->feed_filename, O_RDWR);
2652 ret = AVERROR(errno);
2653 http_log("Could not open feed file '%s': %s\n",
2654 c->stream->feed_filename, strerror(errno));
2659 if (c->stream->truncate) {
2660 /* truncate feed file */
2661 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2662 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2663 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2664 ret = AVERROR(errno);
2665 http_log("Error truncating feed file '%s': %s\n",
2666 c->stream->feed_filename, strerror(errno));
2670 ret = ffm_read_write_index(fd);
2672 http_log("Error reading write index from feed file '%s': %s\n",
2673 c->stream->feed_filename, strerror(errno));
2676 c->stream->feed_write_index = ret;
2680 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2681 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2682 lseek(fd, 0, SEEK_SET);
2684 /* init buffer input */
2685 c->buffer_ptr = c->buffer;
2686 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2687 c->stream->feed_opened = 1;
2688 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2692 static int http_receive_data(HTTPContext *c)
2695 int len, loop_run = 0;
2697 while (c->chunked_encoding && !c->chunk_size &&
2698 c->buffer_end > c->buffer_ptr) {
2699 /* read chunk header, if present */
2700 len = recv(c->fd, c->buffer_ptr, 1, 0);
2703 if (ff_neterrno() != AVERROR(EAGAIN) &&
2704 ff_neterrno() != AVERROR(EINTR))
2705 /* error : close connection */
2708 } else if (len == 0) {
2709 /* end of connection : close it */
2711 } else if (c->buffer_ptr - c->buffer >= 2 &&
2712 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2713 c->chunk_size = strtol(c->buffer, 0, 16);
2714 if (c->chunk_size == 0) // end of stream
2716 c->buffer_ptr = c->buffer;
2718 } else if (++loop_run > 10) {
2719 /* no chunk header, abort */
2726 if (c->buffer_end > c->buffer_ptr) {
2727 len = recv(c->fd, c->buffer_ptr,
2728 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2730 if (ff_neterrno() != AVERROR(EAGAIN) &&
2731 ff_neterrno() != AVERROR(EINTR))
2732 /* error : close connection */
2734 } else if (len == 0)
2735 /* end of connection : close it */
2738 c->chunk_size -= len;
2739 c->buffer_ptr += len;
2740 c->data_count += len;
2741 update_datarate(&c->datarate, c->data_count);
2745 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2746 if (c->buffer[0] != 'f' ||
2747 c->buffer[1] != 'm') {
2748 http_log("Feed stream has become desynchronized -- disconnecting\n");
2753 if (c->buffer_ptr >= c->buffer_end) {
2754 FFStream *feed = c->stream;
2755 /* a packet has been received : write it in the store, except
2757 if (c->data_count > FFM_PACKET_SIZE) {
2758 /* XXX: use llseek or url_seek
2759 * XXX: Should probably fail? */
2760 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2761 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2763 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2764 http_log("Error writing to feed file: %s\n", strerror(errno));
2768 feed->feed_write_index += FFM_PACKET_SIZE;
2769 /* update file size */
2770 if (feed->feed_write_index > c->stream->feed_size)
2771 feed->feed_size = feed->feed_write_index;
2773 /* handle wrap around if max file size reached */
2774 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2775 feed->feed_write_index = FFM_PACKET_SIZE;
2778 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2779 http_log("Error writing index to feed file: %s\n", strerror(errno));
2783 /* wake up any waiting connections */
2784 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2785 if (c1->state == HTTPSTATE_WAIT_FEED &&
2786 c1->stream->feed == c->stream->feed)
2787 c1->state = HTTPSTATE_SEND_DATA;
2790 /* We have a header in our hands that contains useful data */
2791 AVFormatContext *s = avformat_alloc_context();
2793 AVInputFormat *fmt_in;
2799 /* use feed output format name to find corresponding input format */
2800 fmt_in = av_find_input_format(feed->fmt->name);
2804 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2805 0, NULL, NULL, NULL, NULL);
2809 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2814 /* Now we have the actual streams */
2815 if (s->nb_streams != feed->nb_streams) {
2816 avformat_close_input(&s);
2818 http_log("Feed '%s' stream number does not match registered feed\n",
2819 c->stream->feed_filename);
2823 for (i = 0; i < s->nb_streams; i++) {
2824 AVStream *fst = feed->streams[i];
2825 AVStream *st = s->streams[i];
2826 avcodec_copy_context(fst->codec, st->codec);
2829 avformat_close_input(&s);
2832 c->buffer_ptr = c->buffer;
2837 c->stream->feed_opened = 0;
2839 /* wake up any waiting connections to stop waiting for feed */
2840 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2841 if (c1->state == HTTPSTATE_WAIT_FEED &&
2842 c1->stream->feed == c->stream->feed)
2843 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2848 /********************************************************************/
2851 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2858 str = RTSP_STATUS_CODE2STRING(error_number);
2860 str = "Unknown Error";
2862 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2863 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2865 /* output GMT time */
2868 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2869 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2872 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2874 rtsp_reply_header(c, error_number);
2875 avio_printf(c->pb, "\r\n");
2878 static int rtsp_parse_request(HTTPContext *c)
2880 const char *p, *p1, *p2;
2886 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2888 c->buffer_ptr[0] = '\0';
2891 get_word(cmd, sizeof(cmd), &p);
2892 get_word(url, sizeof(url), &p);
2893 get_word(protocol, sizeof(protocol), &p);
2895 av_strlcpy(c->method, cmd, sizeof(c->method));
2896 av_strlcpy(c->url, url, sizeof(c->url));
2897 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2899 if (avio_open_dyn_buf(&c->pb) < 0) {
2900 /* XXX: cannot do more */
2901 c->pb = NULL; /* safety */
2905 /* check version name */
2906 if (strcmp(protocol, "RTSP/1.0") != 0) {
2907 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2911 /* parse each header line */
2912 /* skip to next line */
2913 while (*p != '\n' && *p != '\0')
2917 while (*p != '\0') {
2918 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2922 if (p2 > p && p2[-1] == '\r')
2924 /* skip empty line */
2928 if (len > sizeof(line) - 1)
2929 len = sizeof(line) - 1;
2930 memcpy(line, p, len);
2932 ff_rtsp_parse_line(header, line, NULL, NULL);
2936 /* handle sequence number */
2937 c->seq = header->seq;
2939 if (!strcmp(cmd, "DESCRIBE"))
2940 rtsp_cmd_describe(c, url);
2941 else if (!strcmp(cmd, "OPTIONS"))
2942 rtsp_cmd_options(c, url);
2943 else if (!strcmp(cmd, "SETUP"))
2944 rtsp_cmd_setup(c, url, header);
2945 else if (!strcmp(cmd, "PLAY"))
2946 rtsp_cmd_play(c, url, header);
2947 else if (!strcmp(cmd, "PAUSE"))
2948 rtsp_cmd_interrupt(c, url, header, 1);
2949 else if (!strcmp(cmd, "TEARDOWN"))
2950 rtsp_cmd_interrupt(c, url, header, 0);
2952 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2955 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2956 c->pb = NULL; /* safety */
2958 /* XXX: cannot do more */
2961 c->buffer_ptr = c->pb_buffer;
2962 c->buffer_end = c->pb_buffer + len;
2963 c->state = RTSPSTATE_SEND_REPLY;
2967 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2968 struct in_addr my_ip)
2970 AVFormatContext *avc;
2971 AVStream *avs = NULL;
2972 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2973 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2976 avc = avformat_alloc_context();
2977 if (avc == NULL || !rtp_format) {
2980 avc->oformat = rtp_format;
2981 av_dict_set(&avc->metadata, "title",
2982 entry ? entry->value : "No Title", 0);
2983 avc->nb_streams = stream->nb_streams;
2984 if (stream->is_multicast) {
2985 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2986 inet_ntoa(stream->multicast_ip),
2987 stream->multicast_port, stream->multicast_ttl);
2989 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2992 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2993 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2995 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2996 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2999 for(i = 0; i < stream->nb_streams; i++) {
3000 avc->streams[i] = &avs[i];
3001 avc->streams[i]->codec = stream->streams[i]->codec;
3003 *pbuffer = av_mallocz(2048);
3004 av_sdp_create(&avc, 1, *pbuffer, 2048);
3007 av_free(avc->streams);
3008 av_dict_free(&avc->metadata);
3012 return strlen(*pbuffer);
3015 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3017 // rtsp_reply_header(c, RTSP_STATUS_OK);
3018 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3019 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3020 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3021 avio_printf(c->pb, "\r\n");
3024 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3032 struct sockaddr_in my_addr;
3034 /* find which URL is asked */
3035 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3040 for(stream = first_stream; stream != NULL; stream = stream->next) {
3041 if (!stream->is_feed &&
3042 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3043 !strcmp(path, stream->filename)) {
3047 /* no stream found */
3048 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3052 /* prepare the media description in SDP format */
3054 /* get the host IP */
3055 len = sizeof(my_addr);
3056 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3057 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3058 if (content_length < 0) {
3059 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3062 rtsp_reply_header(c, RTSP_STATUS_OK);
3063 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3064 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3065 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3066 avio_printf(c->pb, "\r\n");
3067 avio_write(c->pb, content, content_length);
3071 static HTTPContext *find_rtp_session(const char *session_id)
3075 if (session_id[0] == '\0')
3078 for(c = first_http_ctx; c != NULL; c = c->next) {
3079 if (!strcmp(c->session_id, session_id))
3085 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3087 RTSPTransportField *th;
3090 for(i=0;i<h->nb_transports;i++) {
3091 th = &h->transports[i];
3092 if (th->lower_transport == lower_transport)
3098 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3099 RTSPMessageHeader *h)
3102 int stream_index, rtp_port, rtcp_port;
3107 RTSPTransportField *th;
3108 struct sockaddr_in dest_addr;
3109 RTSPActionServerSetup setup;
3111 /* find which URL is asked */
3112 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3117 /* now check each stream */
3118 for(stream = first_stream; stream != NULL; stream = stream->next) {
3119 if (!stream->is_feed &&
3120 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3121 /* accept aggregate filenames only if single stream */
3122 if (!strcmp(path, stream->filename)) {
3123 if (stream->nb_streams != 1) {
3124 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3131 for(stream_index = 0; stream_index < stream->nb_streams;
3133 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3134 stream->filename, stream_index);
3135 if (!strcmp(path, buf))
3140 /* no stream found */
3141 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3145 /* generate session id if needed */
3146 if (h->session_id[0] == '\0') {
3147 unsigned random0 = av_lfg_get(&random_state);
3148 unsigned random1 = av_lfg_get(&random_state);
3149 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3153 /* find RTP session, and create it if none found */
3154 rtp_c = find_rtp_session(h->session_id);
3156 /* always prefer UDP */
3157 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3159 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3161 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3166 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3167 th->lower_transport);
3169 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3173 /* open input stream */
3174 if (open_input_stream(rtp_c, "") < 0) {
3175 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3180 /* test if stream is OK (test needed because several SETUP needs
3181 to be done for a given file) */
3182 if (rtp_c->stream != stream) {
3183 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3187 /* test if stream is already set up */
3188 if (rtp_c->rtp_ctx[stream_index]) {
3189 rtsp_reply_error(c, RTSP_STATUS_STATE);
3193 /* check transport */
3194 th = find_transport(h, rtp_c->rtp_protocol);
3195 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3196 th->client_port_min <= 0)) {
3197 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3201 /* setup default options */
3202 setup.transport_option[0] = '\0';
3203 dest_addr = rtp_c->from_addr;
3204 dest_addr.sin_port = htons(th->client_port_min);
3207 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3208 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3212 /* now everything is OK, so we can send the connection parameters */
3213 rtsp_reply_header(c, RTSP_STATUS_OK);
3215 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3217 switch(rtp_c->rtp_protocol) {
3218 case RTSP_LOWER_TRANSPORT_UDP:
3219 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3220 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3221 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3222 "client_port=%d-%d;server_port=%d-%d",
3223 th->client_port_min, th->client_port_max,
3224 rtp_port, rtcp_port);
3226 case RTSP_LOWER_TRANSPORT_TCP:
3227 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3228 stream_index * 2, stream_index * 2 + 1);
3233 if (setup.transport_option[0] != '\0')
3234 avio_printf(c->pb, ";%s", setup.transport_option);
3235 avio_printf(c->pb, "\r\n");
3238 avio_printf(c->pb, "\r\n");
3242 /* find an RTP connection by using the session ID. Check consistency
3244 static HTTPContext *find_rtp_session_with_url(const char *url,
3245 const char *session_id)
3253 rtp_c = find_rtp_session(session_id);
3257 /* find which URL is asked */
3258 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3262 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3263 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3264 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3265 rtp_c->stream->filename, s);
3266 if(!strncmp(path, buf, sizeof(buf))) {
3267 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3272 if (len > 0 && path[len - 1] == '/' &&
3273 !strncmp(path, rtp_c->stream->filename, len - 1))
3278 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3282 rtp_c = find_rtp_session_with_url(url, h->session_id);
3284 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3288 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3289 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3290 rtp_c->state != HTTPSTATE_READY) {
3291 rtsp_reply_error(c, RTSP_STATUS_STATE);
3295 rtp_c->state = HTTPSTATE_SEND_DATA;
3297 /* now everything is OK, so we can send the connection parameters */
3298 rtsp_reply_header(c, RTSP_STATUS_OK);
3300 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3301 avio_printf(c->pb, "\r\n");
3304 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3308 rtp_c = find_rtp_session_with_url(url, h->session_id);
3310 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3315 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3316 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3317 rtsp_reply_error(c, RTSP_STATUS_STATE);
3320 rtp_c->state = HTTPSTATE_READY;
3321 rtp_c->first_pts = AV_NOPTS_VALUE;
3324 /* now everything is OK, so we can send the connection parameters */
3325 rtsp_reply_header(c, RTSP_STATUS_OK);
3327 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3328 avio_printf(c->pb, "\r\n");
3331 close_connection(rtp_c);
3334 /********************************************************************/
3337 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3338 FFStream *stream, const char *session_id,
3339 enum RTSPLowerTransport rtp_protocol)
3341 HTTPContext *c = NULL;
3342 const char *proto_str;
3344 /* XXX: should output a warning page when coming
3345 close to the connection limit */
3346 if (nb_connections >= nb_max_connections)
3349 /* add a new connection */
3350 c = av_mallocz(sizeof(HTTPContext));
3355 c->poll_entry = NULL;
3356 c->from_addr = *from_addr;
3357 c->buffer_size = IOBUFFER_INIT_SIZE;
3358 c->buffer = av_malloc(c->buffer_size);
3363 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3364 c->state = HTTPSTATE_READY;
3365 c->is_packetized = 1;
3366 c->rtp_protocol = rtp_protocol;
3368 /* protocol is shown in statistics */
3369 switch(c->rtp_protocol) {
3370 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3371 proto_str = "MCAST";
3373 case RTSP_LOWER_TRANSPORT_UDP:
3376 case RTSP_LOWER_TRANSPORT_TCP:
3383 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3384 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3386 current_bandwidth += stream->bandwidth;
3388 c->next = first_http_ctx;
3400 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3401 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3403 static int rtp_new_av_stream(HTTPContext *c,
3404 int stream_index, struct sockaddr_in *dest_addr,
3405 HTTPContext *rtsp_c)
3407 AVFormatContext *ctx;
3410 URLContext *h = NULL;
3412 int max_packet_size;
3414 /* now we can open the relevant output stream */
3415 ctx = avformat_alloc_context();
3418 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3420 st = av_mallocz(sizeof(AVStream));
3423 ctx->nb_streams = 1;
3424 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3427 ctx->streams[0] = st;
3429 if (!c->stream->feed ||
3430 c->stream->feed == c->stream)
3431 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3434 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3436 st->priv_data = NULL;
3438 /* build destination RTP address */
3439 ipaddr = inet_ntoa(dest_addr->sin_addr);
3441 switch(c->rtp_protocol) {
3442 case RTSP_LOWER_TRANSPORT_UDP:
3443 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3446 /* XXX: also pass as parameter to function ? */
3447 if (c->stream->is_multicast) {
3449 ttl = c->stream->multicast_ttl;
3452 snprintf(ctx->filename, sizeof(ctx->filename),
3453 "rtp://%s:%d?multicast=1&ttl=%d",
3454 ipaddr, ntohs(dest_addr->sin_port), ttl);
3456 snprintf(ctx->filename, sizeof(ctx->filename),
3457 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3460 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3462 c->rtp_handles[stream_index] = h;
3463 max_packet_size = h->max_packet_size;
3465 case RTSP_LOWER_TRANSPORT_TCP:
3468 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3474 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3475 ipaddr, ntohs(dest_addr->sin_port),
3476 c->stream->filename, stream_index, c->protocol);
3478 /* normally, no packets should be output here, but the packet size may
3480 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3481 /* XXX: close stream */
3484 if (avformat_write_header(ctx, NULL) < 0) {
3492 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3495 c->rtp_ctx[stream_index] = ctx;
3499 /********************************************************************/
3500 /* ffserver initialization */
3502 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3506 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3509 fst = av_mallocz(sizeof(AVStream));
3513 fst->codec = avcodec_alloc_context3(NULL);
3514 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3515 if (codec->extradata_size) {
3516 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3517 memcpy(fst->codec->extradata, codec->extradata,
3518 codec->extradata_size);
3521 /* live streams must use the actual feed's codec since it may be
3522 * updated later to carry extradata needed by them.
3526 fst->priv_data = av_mallocz(sizeof(FeedData));
3527 fst->index = stream->nb_streams;
3528 avpriv_set_pts_info(fst, 33, 1, 90000);
3529 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3530 stream->streams[stream->nb_streams++] = fst;
3534 /* return the stream number in the feed */
3535 static int add_av_stream(FFStream *feed, AVStream *st)
3538 AVCodecContext *av, *av1;
3542 for(i=0;i<feed->nb_streams;i++) {
3543 st = feed->streams[i];
3545 if (av1->codec_id == av->codec_id &&
3546 av1->codec_type == av->codec_type &&
3547 av1->bit_rate == av->bit_rate) {
3549 switch(av->codec_type) {
3550 case AVMEDIA_TYPE_AUDIO:
3551 if (av1->channels == av->channels &&
3552 av1->sample_rate == av->sample_rate)
3555 case AVMEDIA_TYPE_VIDEO:
3556 if (av1->width == av->width &&
3557 av1->height == av->height &&
3558 av1->time_base.den == av->time_base.den &&
3559 av1->time_base.num == av->time_base.num &&
3560 av1->gop_size == av->gop_size)
3569 fst = add_av_stream1(feed, av, 0);
3572 return feed->nb_streams - 1;
3575 static void remove_stream(FFStream *stream)
3579 while (*ps != NULL) {
3587 /* specific MPEG4 handling : we extract the raw parameters */
3588 static void extract_mpeg4_header(AVFormatContext *infile)
3590 int mpeg4_count, i, size;
3595 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3598 for(i=0;i<infile->nb_streams;i++) {
3599 st = infile->streams[i];
3600 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3601 st->codec->extradata_size == 0) {
3608 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3609 while (mpeg4_count > 0) {
3610 if (av_read_frame(infile, &pkt) < 0)
3612 st = infile->streams[pkt.stream_index];
3613 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3614 st->codec->extradata_size == 0) {
3615 av_freep(&st->codec->extradata);
3616 /* fill extradata with the header */
3617 /* XXX: we make hard suppositions here ! */
3619 while (p < pkt.data + pkt.size - 4) {
3620 /* stop when vop header is found */
3621 if (p[0] == 0x00 && p[1] == 0x00 &&
3622 p[2] == 0x01 && p[3] == 0xb6) {
3623 size = p - pkt.data;
3624 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3625 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3626 st->codec->extradata_size = size;
3627 memcpy(st->codec->extradata, pkt.data, size);
3634 av_free_packet(&pkt);
3638 /* compute the needed AVStream for each file */
3639 static void build_file_streams(void)
3641 FFStream *stream, *stream_next;
3644 /* gather all streams */
3645 for(stream = first_stream; stream != NULL; stream = stream_next) {
3646 AVFormatContext *infile = NULL;
3647 stream_next = stream->next;
3648 if (stream->stream_type == STREAM_TYPE_LIVE &&
3650 /* the stream comes from a file */
3651 /* try to open the file */
3653 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3654 /* specific case : if transport stream output to RTP,
3655 we use a raw transport stream reader */
3656 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3659 if (!stream->feed_filename[0]) {
3660 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3664 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3665 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3666 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3667 /* remove stream (no need to spend more time on it) */
3669 remove_stream(stream);
3671 /* find all the AVStreams inside and reference them in
3673 if (avformat_find_stream_info(infile, NULL) < 0) {
3674 http_log("Could not find codec parameters from '%s'\n",
3675 stream->feed_filename);
3676 avformat_close_input(&infile);
3679 extract_mpeg4_header(infile);
3681 for(i=0;i<infile->nb_streams;i++)
3682 add_av_stream1(stream, infile->streams[i]->codec, 1);
3684 avformat_close_input(&infile);
3690 /* compute the needed AVStream for each feed */
3691 static void build_feed_streams(void)
3693 FFStream *stream, *feed;
3696 /* gather all streams */
3697 for(stream = first_stream; stream != NULL; stream = stream->next) {
3698 feed = stream->feed;
3700 if (stream->is_feed) {
3701 for(i=0;i<stream->nb_streams;i++)
3702 stream->feed_streams[i] = i;
3704 /* we handle a stream coming from a feed */
3705 for(i=0;i<stream->nb_streams;i++)
3706 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3711 /* create feed files if needed */
3712 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3715 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3716 /* See if it matches */
3717 AVFormatContext *s = NULL;
3720 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3721 /* set buffer size */
3722 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3723 /* Now see if it matches */
3724 if (s->nb_streams == feed->nb_streams) {
3726 for(i=0;i<s->nb_streams;i++) {
3728 sf = feed->streams[i];
3731 if (sf->index != ss->index ||
3733 http_log("Index & Id do not match for stream %d (%s)\n",
3734 i, feed->feed_filename);
3737 AVCodecContext *ccf, *ccs;
3741 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3743 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3744 http_log("Codecs do not match for stream %d\n", i);
3746 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3747 http_log("Codec bitrates do not match for stream %d\n", i);
3749 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3750 if (CHECK_CODEC(time_base.den) ||
3751 CHECK_CODEC(time_base.num) ||
3752 CHECK_CODEC(width) ||
3753 CHECK_CODEC(height)) {
3754 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3757 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3758 if (CHECK_CODEC(sample_rate) ||
3759 CHECK_CODEC(channels) ||
3760 CHECK_CODEC(frame_size)) {
3761 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3765 http_log("Unknown codec type\n");
3773 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3774 feed->feed_filename, s->nb_streams, feed->nb_streams);
3776 avformat_close_input(&s);
3778 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3779 feed->feed_filename);
3782 if (feed->readonly) {
3783 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3784 feed->feed_filename);
3787 unlink(feed->feed_filename);
3790 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3791 AVFormatContext *s = avformat_alloc_context();
3793 if (feed->readonly) {
3794 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3795 feed->feed_filename);
3799 /* only write the header of the ffm file */
3800 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3801 http_log("Could not open output feed file '%s'\n",
3802 feed->feed_filename);
3805 s->oformat = feed->fmt;
3806 s->nb_streams = feed->nb_streams;
3807 s->streams = feed->streams;
3808 if (avformat_write_header(s, NULL) < 0) {
3809 http_log("Container doesn't support the required parameters\n");
3812 /* XXX: need better API */
3813 av_freep(&s->priv_data);
3817 avformat_free_context(s);
3819 /* get feed size and write index */
3820 fd = open(feed->feed_filename, O_RDONLY);
3822 http_log("Could not open output feed file '%s'\n",
3823 feed->feed_filename);
3827 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3828 feed->feed_size = lseek(fd, 0, SEEK_END);
3829 /* ensure that we do not wrap before the end of file */
3830 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3831 feed->feed_max_size = feed->feed_size;
3837 /* compute the bandwidth used by each stream */
3838 static void compute_bandwidth(void)
3844 for(stream = first_stream; stream != NULL; stream = stream->next) {
3846 for(i=0;i<stream->nb_streams;i++) {
3847 AVStream *st = stream->streams[i];
3848 switch(st->codec->codec_type) {
3849 case AVMEDIA_TYPE_AUDIO:
3850 case AVMEDIA_TYPE_VIDEO:
3851 bandwidth += st->codec->bit_rate;
3857 stream->bandwidth = (bandwidth + 999) / 1000;
3861 /* add a codec and set the default parameters */
3862 static void add_codec(FFStream *stream, AVCodecContext *av)
3866 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3869 /* compute default parameters */
3870 switch(av->codec_type) {
3871 case AVMEDIA_TYPE_AUDIO:
3872 if (av->bit_rate == 0)
3873 av->bit_rate = 64000;
3874 if (av->sample_rate == 0)
3875 av->sample_rate = 22050;
3876 if (av->channels == 0)
3879 case AVMEDIA_TYPE_VIDEO:
3880 if (av->bit_rate == 0)
3881 av->bit_rate = 64000;
3882 if (av->time_base.num == 0){
3883 av->time_base.den = 5;
3884 av->time_base.num = 1;
3886 if (av->width == 0 || av->height == 0) {
3890 /* Bitrate tolerance is less for streaming */
3891 if (av->bit_rate_tolerance == 0)
3892 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3893 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3898 if (av->max_qdiff == 0)
3900 av->qcompress = 0.5;
3903 if (!av->nsse_weight)
3904 av->nsse_weight = 8;
3906 av->frame_skip_cmp = FF_CMP_DCTMAX;
3908 av->me_method = ME_EPZS;
3909 av->rc_buffer_aggressivity = 1.0;
3912 av->rc_eq = av_strdup("tex^qComp");
3913 if (!av->i_quant_factor)
3914 av->i_quant_factor = -0.8;
3915 if (!av->b_quant_factor)
3916 av->b_quant_factor = 1.25;
3917 if (!av->b_quant_offset)
3918 av->b_quant_offset = 1.25;
3919 if (!av->rc_max_rate)
3920 av->rc_max_rate = av->bit_rate * 2;
3922 if (av->rc_max_rate && !av->rc_buffer_size) {
3923 av->rc_buffer_size = av->rc_max_rate;
3932 st = av_mallocz(sizeof(AVStream));
3935 st->codec = avcodec_alloc_context3(NULL);
3936 stream->streams[stream->nb_streams++] = st;
3937 memcpy(st->codec, av, sizeof(AVCodecContext));
3940 static enum AVCodecID opt_codec(const char *name, enum AVMediaType type)
3942 AVCodec *codec = avcodec_find_encoder_by_name(name);
3944 if (!codec || codec->type != type)
3945 return AV_CODEC_ID_NONE;
3949 static int ffserver_opt_default(const char *opt, const char *arg,
3950 AVCodecContext *avctx, int type)
3953 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3955 ret = av_opt_set(avctx, opt, arg, 0);
3959 static int ffserver_opt_preset(const char *arg,
3960 AVCodecContext *avctx, int type,
3961 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3964 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3966 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3968 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3969 codec ? codec->name : NULL))) {
3970 fprintf(stderr, "File for preset '%s' not found\n", arg);
3975 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3976 if(line[0] == '#' && !e)
3978 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3980 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3984 if(!strcmp(tmp, "acodec")){
3985 *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
3986 }else if(!strcmp(tmp, "vcodec")){
3987 *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
3988 }else if(!strcmp(tmp, "scodec")){
3989 /* opt_subtitle_codec(tmp2); */
3990 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3991 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4002 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename, const char *mime_type)
4004 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4007 AVOutputFormat *stream_fmt;
4008 char stream_format_name[64];
4010 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4011 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4020 static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...)
4024 av_log(NULL, log_level, "%s:%d: ", filename, line_num);
4025 av_vlog(NULL, log_level, fmt, vl);
4031 static int parse_ffconfig(const char *filename)
4036 char arg[1024], arg2[1024];
4038 int val, errors, warnings, line_num;
4039 FFStream **last_stream, *stream, *redirect;
4040 FFStream **last_feed, *feed, *s;
4041 AVCodecContext audio_enc, video_enc;
4042 enum AVCodecID audio_id, video_id;
4045 f = fopen(filename, "r");
4047 ret = AVERROR(errno);
4048 av_log(NULL, AV_LOG_ERROR, "Could not open the configuration file '%s'\n", filename);
4052 errors = warnings = 0;
4054 first_stream = NULL;
4055 last_stream = &first_stream;
4057 last_feed = &first_feed;
4061 audio_id = AV_CODEC_ID_NONE;
4062 video_id = AV_CODEC_ID_NONE;
4063 #define ERROR(...) report_config_error(filename, line_num, AV_LOG_ERROR, &errors, __VA_ARGS__)
4064 #define WARNING(...) report_config_error(filename, line_num, AV_LOG_WARNING, &warnings, __VA_ARGS__)
4067 if (fgets(line, sizeof(line), f) == NULL)
4071 while (av_isspace(*p))
4073 if (*p == '\0' || *p == '#')
4076 get_arg(cmd, sizeof(cmd), &p);
4078 if (!av_strcasecmp(cmd, "Port")) {
4079 get_arg(arg, sizeof(arg), &p);
4081 if (val < 1 || val > 65536) {
4082 ERROR("Invalid_port: %s\n", arg);
4084 my_http_addr.sin_port = htons(val);
4085 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4086 get_arg(arg, sizeof(arg), &p);
4087 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4088 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4090 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4091 WARNING("NoDaemon option has no effect, you should remove it\n");
4092 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4093 get_arg(arg, sizeof(arg), &p);
4095 if (val < 1 || val > 65536) {
4096 ERROR("%s:%d: Invalid port: %s\n", arg);
4098 my_rtsp_addr.sin_port = htons(atoi(arg));
4099 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4100 get_arg(arg, sizeof(arg), &p);
4101 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4102 ERROR("Invalid host/IP address: %s\n", arg);
4104 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4105 get_arg(arg, sizeof(arg), &p);
4107 if (val < 1 || val > 65536) {
4108 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4110 nb_max_http_connections = val;
4111 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4112 get_arg(arg, sizeof(arg), &p);
4114 if (val < 1 || val > nb_max_http_connections) {
4115 ERROR("Invalid MaxClients: %s\n", arg);
4117 nb_max_connections = val;
4119 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4121 get_arg(arg, sizeof(arg), &p);
4122 llval = strtoll(arg, NULL, 10);
4123 if (llval < 10 || llval > 10000000) {
4124 ERROR("Invalid MaxBandwidth: %s\n", arg);
4126 max_bandwidth = llval;
4127 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4128 if (!ffserver_debug)
4129 get_arg(logfilename, sizeof(logfilename), &p);
4130 } else if (!av_strcasecmp(cmd, "<Feed")) {
4131 /*********************************************/
4132 /* Feed related options */
4134 if (stream || feed) {
4135 ERROR("Already in a tag\n");
4137 feed = av_mallocz(sizeof(FFStream));
4139 ret = AVERROR(ENOMEM);
4142 get_arg(feed->filename, sizeof(feed->filename), &p);
4143 q = strrchr(feed->filename, '>');
4147 for (s = first_feed; s; s = s->next) {
4148 if (!strcmp(feed->filename, s->filename)) {
4149 ERROR("Feed '%s' already registered\n", s->filename);
4153 feed->fmt = av_guess_format("ffm", NULL, NULL);
4154 /* default feed file */
4155 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4156 "/tmp/%s.ffm", feed->filename);
4157 feed->feed_max_size = 5 * 1024 * 1024;
4159 feed->feed = feed; /* self feeding :-) */
4161 /* add in stream list */
4162 *last_stream = feed;
4163 last_stream = &feed->next;
4164 /* add in feed list */
4166 last_feed = &feed->next_feed;
4168 } else if (!av_strcasecmp(cmd, "Launch")) {
4172 feed->child_argv = av_mallocz(64 * sizeof(char *));
4173 if (!feed->child_argv) {
4174 ret = AVERROR(ENOMEM);
4177 for (i = 0; i < 62; i++) {
4178 get_arg(arg, sizeof(arg), &p);
4182 feed->child_argv[i] = av_strdup(arg);
4183 if (!feed->child_argv[i]) {
4184 ret = AVERROR(ENOMEM);
4189 feed->child_argv[i] =
4190 av_asprintf("http://%s:%d/%s",
4191 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4192 inet_ntoa(my_http_addr.sin_addr), ntohs(my_http_addr.sin_port),
4194 if (!feed->child_argv[i]) {
4195 ret = AVERROR(ENOMEM);
4199 } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
4201 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4202 feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile");
4203 } else if (stream) {
4204 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4206 } else if (!av_strcasecmp(cmd, "Truncate")) {
4208 get_arg(arg, sizeof(arg), &p);
4209 /* assume Truncate is true in case no argument is specified */
4213 WARNING("Truncate N syntax in configuration file is deprecated, "
4214 "use Truncate alone with no arguments\n");
4215 feed->truncate = strtod(arg, NULL);
4218 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4223 get_arg(arg, sizeof(arg), &p);
4225 fsize = strtod(p1, &p1);
4226 switch(av_toupper(*p1)) {
4231 fsize *= 1024 * 1024;
4234 fsize *= 1024 * 1024 * 1024;
4237 feed->feed_max_size = (int64_t)fsize;
4238 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4239 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4242 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4244 ERROR("No corresponding <Feed> for </Feed>\n");
4247 } else if (!av_strcasecmp(cmd, "<Stream")) {
4248 /*********************************************/
4249 /* Stream related options */
4251 if (stream || feed) {
4252 ERROR("Already in a tag\n");
4255 stream = av_mallocz(sizeof(FFStream));
4257 ret = AVERROR(ENOMEM);
4260 get_arg(stream->filename, sizeof(stream->filename), &p);
4261 q = strrchr(stream->filename, '>');
4265 for (s = first_stream; s; s = s->next) {
4266 if (!strcmp(stream->filename, s->filename)) {
4267 ERROR("Stream '%s' already registered\n", s->filename);
4271 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4272 avcodec_get_context_defaults3(&video_enc, NULL);
4273 avcodec_get_context_defaults3(&audio_enc, NULL);
4275 audio_id = AV_CODEC_ID_NONE;
4276 video_id = AV_CODEC_ID_NONE;
4278 audio_id = stream->fmt->audio_codec;
4279 video_id = stream->fmt->video_codec;
4282 *last_stream = stream;
4283 last_stream = &stream->next;
4285 } else if (!av_strcasecmp(cmd, "Feed")) {
4286 get_arg(arg, sizeof(arg), &p);
4291 while (sfeed != NULL) {
4292 if (!strcmp(sfeed->filename, arg))
4294 sfeed = sfeed->next_feed;
4297 ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg, stream->filename);
4299 stream->feed = sfeed;
4301 } else if (!av_strcasecmp(cmd, "Format")) {
4302 get_arg(arg, sizeof(arg), &p);
4304 if (!strcmp(arg, "status")) {
4305 stream->stream_type = STREAM_TYPE_STATUS;
4308 stream->stream_type = STREAM_TYPE_LIVE;
4309 /* JPEG cannot be used here, so use single frame MJPEG */
4310 if (!strcmp(arg, "jpeg"))
4311 strcpy(arg, "mjpeg");
4312 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4314 ERROR("Unknown Format: %s\n", arg);
4318 audio_id = stream->fmt->audio_codec;
4319 video_id = stream->fmt->video_codec;
4322 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4323 get_arg(arg, sizeof(arg), &p);
4325 stream->ifmt = av_find_input_format(arg);
4326 if (!stream->ifmt) {
4327 ERROR("Unknown input format: %s\n", arg);
4330 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4331 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4332 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4334 ERROR("FaviconURL only permitted for status streams\n");
4336 } else if (!av_strcasecmp(cmd, "Author") ||
4337 !av_strcasecmp(cmd, "Comment") ||
4338 !av_strcasecmp(cmd, "Copyright") ||
4339 !av_strcasecmp(cmd, "Title")) {
4340 get_arg(arg, sizeof(arg), &p);
4346 for (i = 0; i < strlen(cmd); i++)
4347 key[i] = av_tolower(cmd[i]);
4349 WARNING("'%s' option in configuration file is deprecated, "
4350 "use 'Metadata %s VALUE' instead\n", cmd, key);
4351 if ((ret = av_dict_set(&stream->metadata, key, arg, 0)) < 0) {
4352 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4353 key, arg, av_err2str(ret));
4356 } else if (!av_strcasecmp(cmd, "Metadata")) {
4357 get_arg(arg, sizeof(arg), &p);
4358 get_arg(arg2, sizeof(arg2), &p);
4361 if ((ret = av_dict_set(&stream->metadata, arg, arg2, 0)) < 0) {
4362 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4363 arg, arg2, av_err2str(ret));
4366 } else if (!av_strcasecmp(cmd, "Preroll")) {
4367 get_arg(arg, sizeof(arg), &p);
4369 stream->prebuffer = atof(arg) * 1000;
4370 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4372 stream->send_on_key = 1;
4373 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4374 get_arg(arg, sizeof(arg), &p);
4375 audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO);
4376 if (audio_id == AV_CODEC_ID_NONE) {
4377 ERROR("Unknown AudioCodec: %s\n", arg);
4379 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4380 get_arg(arg, sizeof(arg), &p);
4381 video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO);
4382 if (video_id == AV_CODEC_ID_NONE) {
4383 ERROR("Unknown VideoCodec: %s\n", arg);
4385 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4386 get_arg(arg, sizeof(arg), &p);
4388 stream->max_time = atof(arg) * 1000;
4389 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4390 get_arg(arg, sizeof(arg), &p);
4392 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4393 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4394 get_arg(arg, sizeof(arg), &p);
4396 audio_enc.channels = atoi(arg);
4397 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4398 get_arg(arg, sizeof(arg), &p);
4400 audio_enc.sample_rate = atoi(arg);
4401 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4403 int minrate, maxrate;
4405 get_arg(arg, sizeof(arg), &p);
4407 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4408 video_enc.rc_min_rate = minrate * 1000;
4409 video_enc.rc_max_rate = maxrate * 1000;
4411 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4414 } else if (!av_strcasecmp(cmd, "Debug")) {
4416 get_arg(arg, sizeof(arg), &p);
4417 video_enc.debug = strtol(arg,0,0);
4419 } else if (!av_strcasecmp(cmd, "Strict")) {
4421 get_arg(arg, sizeof(arg), &p);
4422 video_enc.strict_std_compliance = atoi(arg);
4424 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4426 get_arg(arg, sizeof(arg), &p);
4427 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4429 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4431 get_arg(arg, sizeof(arg), &p);
4432 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4434 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4435 get_arg(arg, sizeof(arg), &p);
4437 video_enc.bit_rate = atoi(arg) * 1000;
4439 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4440 get_arg(arg, sizeof(arg), &p);
4442 ret = av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4444 ERROR("Invalid video size '%s'\n", arg);
4446 if ((video_enc.width % 16) != 0 ||
4447 (video_enc.height % 16) != 0) {
4448 ERROR("Image size must be a multiple of 16\n");
4452 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4453 get_arg(arg, sizeof(arg), &p);
4455 AVRational frame_rate;
4456 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4457 ERROR("Incorrect frame rate: %s\n", arg);
4459 video_enc.time_base.num = frame_rate.den;
4460 video_enc.time_base.den = frame_rate.num;
4463 } else if (!av_strcasecmp(cmd, "PixelFormat")) {
4464 get_arg(arg, sizeof(arg), &p);
4466 video_enc.pix_fmt = av_get_pix_fmt(arg);
4467 if (video_enc.pix_fmt == AV_PIX_FMT_NONE) {
4468 ERROR("Unknown pixel format: %s\n", arg);
4471 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4472 get_arg(arg, sizeof(arg), &p);
4474 video_enc.gop_size = atoi(arg);
4475 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4477 video_enc.gop_size = 1;
4478 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4480 video_enc.mb_decision = FF_MB_DECISION_BITS;
4481 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4483 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4484 video_enc.flags |= CODEC_FLAG_4MV;
4486 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4487 !av_strcasecmp(cmd, "AVOptionAudio")) {
4488 AVCodecContext *avctx;
4490 get_arg(arg, sizeof(arg), &p);
4491 get_arg(arg2, sizeof(arg2), &p);
4492 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4494 type = AV_OPT_FLAG_VIDEO_PARAM;
4497 type = AV_OPT_FLAG_AUDIO_PARAM;
4499 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4500 ERROR("Error setting %s option to %s %s\n", cmd, arg, arg2);
4502 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4503 !av_strcasecmp(cmd, "AVPresetAudio")) {
4504 AVCodecContext *avctx;
4506 get_arg(arg, sizeof(arg), &p);
4507 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4509 video_enc.codec_id = video_id;
4510 type = AV_OPT_FLAG_VIDEO_PARAM;
4513 audio_enc.codec_id = audio_id;
4514 type = AV_OPT_FLAG_AUDIO_PARAM;
4516 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4517 ERROR("AVPreset error: %s\n", arg);
4519 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4520 get_arg(arg, sizeof(arg), &p);
4521 if ((strlen(arg) == 4) && stream)
4522 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4523 } else if (!av_strcasecmp(cmd, "BitExact")) {
4525 video_enc.flags |= CODEC_FLAG_BITEXACT;
4526 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4528 video_enc.dct_algo = FF_DCT_FASTINT;
4529 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4531 video_enc.idct_algo = FF_IDCT_SIMPLE;
4532 } else if (!av_strcasecmp(cmd, "Qscale")) {
4533 get_arg(arg, sizeof(arg), &p);
4535 video_enc.flags |= CODEC_FLAG_QSCALE;
4536 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4538 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4539 get_arg(arg, sizeof(arg), &p);
4541 video_enc.max_qdiff = atoi(arg);
4542 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4543 ERROR("VideoQDiff out of range\n");
4546 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4547 get_arg(arg, sizeof(arg), &p);
4549 video_enc.qmax = atoi(arg);
4550 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4551 ERROR("VideoQMax out of range\n");
4554 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4555 get_arg(arg, sizeof(arg), &p);
4557 video_enc.qmin = atoi(arg);
4558 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4559 ERROR("VideoQMin out of range\n");
4562 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4563 get_arg(arg, sizeof(arg), &p);
4565 video_enc.lumi_masking = atof(arg);
4566 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4567 get_arg(arg, sizeof(arg), &p);
4569 video_enc.dark_masking = atof(arg);
4570 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4571 video_id = AV_CODEC_ID_NONE;
4572 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4573 audio_id = AV_CODEC_ID_NONE;
4574 } else if (!av_strcasecmp(cmd, "ACL")) {
4575 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4576 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4578 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4580 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4581 get_arg(arg, sizeof(arg), &p);
4583 av_freep(&stream->rtsp_option);
4584 stream->rtsp_option = av_strdup(arg);
4586 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4587 get_arg(arg, sizeof(arg), &p);
4589 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4590 ERROR("Invalid host/IP address: %s\n", arg);
4592 stream->is_multicast = 1;
4593 stream->loop = 1; /* default is looping */
4595 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4596 get_arg(arg, sizeof(arg), &p);
4598 stream->multicast_port = atoi(arg);
4599 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4600 get_arg(arg, sizeof(arg), &p);
4602 stream->multicast_ttl = atoi(arg);
4603 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4606 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4608 ERROR("No corresponding <Stream> for </Stream>\n");
4610 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4611 if (audio_id != AV_CODEC_ID_NONE) {
4612 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4613 audio_enc.codec_id = audio_id;
4614 add_codec(stream, &audio_enc);
4616 if (video_id != AV_CODEC_ID_NONE) {
4617 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4618 video_enc.codec_id = video_id;
4619 add_codec(stream, &video_enc);
4624 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4625 /*********************************************/
4627 if (stream || feed || redirect) {
4628 ERROR("Already in a tag\n");
4630 redirect = av_mallocz(sizeof(FFStream));
4632 ret = AVERROR(ENOMEM);
4635 *last_stream = redirect;
4636 last_stream = &redirect->next;
4638 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4639 q = strrchr(redirect->filename, '>');
4642 redirect->stream_type = STREAM_TYPE_REDIRECT;
4644 } else if (!av_strcasecmp(cmd, "URL")) {
4646 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4647 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4649 ERROR("No corresponding <Redirect> for </Redirect>\n");
4651 if (!redirect->feed_filename[0]) {
4652 ERROR("No URL found for <Redirect>\n");
4656 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4657 ERROR("Loadable modules no longer supported\n");
4659 ERROR("Incorrect keyword: '%s'\n", cmd);
4669 return AVERROR(EINVAL);
4674 static void handle_child_exit(int sig)
4679 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4682 for (feed = first_feed; feed; feed = feed->next) {
4683 if (feed->pid == pid) {
4684 int uptime = time(0) - feed->pid_start;
4687 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4690 /* Turn off any more restarts */
4691 feed->child_argv = 0;
4696 need_to_start_children = 1;
4699 static void opt_debug(void)
4702 logfilename[0] = '-';
4705 void show_help_default(const char *opt, const char *arg)
4707 printf("usage: ffserver [options]\n"
4708 "Hyper fast multi format Audio/Video streaming server\n");
4710 show_help_options(options, "Main options:", 0, 0, 0);
4713 static const OptionDef options[] = {
4714 #include "cmdutils_common_opts.h"
4715 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4716 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4717 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4721 int main(int argc, char **argv)
4723 struct sigaction sigact = { { 0 } };
4726 config_filename = av_strdup("/etc/ffserver.conf");
4728 parse_loglevel(argc, argv, options);
4730 avformat_network_init();
4732 show_banner(argc, argv, options);
4734 my_program_name = argv[0];
4736 parse_options(NULL, argc, argv, options, NULL);
4738 unsetenv("http_proxy"); /* Kill the http_proxy */
4740 av_lfg_init(&random_state, av_get_random_seed());
4742 sigact.sa_handler = handle_child_exit;
4743 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4744 sigaction(SIGCHLD, &sigact, 0);
4746 if ((ret = parse_ffconfig(config_filename)) < 0) {
4747 fprintf(stderr, "Error reading configuration file '%s': %s\n",
4748 config_filename, av_err2str(ret));
4751 av_freep(&config_filename);
4753 /* open log file if needed */
4754 if (logfilename[0] != '\0') {
4755 if (!strcmp(logfilename, "-"))
4758 logfile = fopen(logfilename, "a");
4759 av_log_set_callback(http_av_log);
4762 build_file_streams();
4764 build_feed_streams();
4766 compute_bandwidth();
4769 signal(SIGPIPE, SIG_IGN);
4771 if (http_server() < 0) {
4772 http_log("Could not start server\n");