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)) {
756 cur_time = av_gettime() / 1000;
758 if (need_to_start_children) {
759 need_to_start_children = 0;
760 start_children(first_feed);
763 /* now handle the events */
764 for(c = first_http_ctx; c != NULL; c = c_next) {
766 if (handle_connection(c) < 0) {
768 /* close and free the connection */
773 poll_entry = poll_table;
775 /* new HTTP connection request ? */
776 if (poll_entry->revents & POLLIN)
777 new_connection(server_fd, 0);
780 if (rtsp_server_fd) {
781 /* new RTSP connection request ? */
782 if (poll_entry->revents & POLLIN)
783 new_connection(rtsp_server_fd, 1);
788 /* start waiting for a new HTTP/RTSP request */
789 static void start_wait_request(HTTPContext *c, int is_rtsp)
791 c->buffer_ptr = c->buffer;
792 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
795 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
796 c->state = RTSPSTATE_WAIT_REQUEST;
798 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
799 c->state = HTTPSTATE_WAIT_REQUEST;
803 static void http_send_too_busy_reply(int fd)
806 int len = snprintf(buffer, sizeof(buffer),
807 "HTTP/1.0 503 Server too busy\r\n"
808 "Content-type: text/html\r\n"
810 "<html><head><title>Too busy</title></head><body>\r\n"
811 "<p>The server is too busy to serve your request at this time.</p>\r\n"
812 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
813 "</body></html>\r\n",
814 nb_connections, nb_max_connections);
815 av_assert0(len < sizeof(buffer));
816 if (send(fd, buffer, len, 0) < len)
817 av_log(NULL, AV_LOG_WARNING, "Could not send too-busy reply, send() failed\n");
821 static void new_connection(int server_fd, int is_rtsp)
823 struct sockaddr_in from_addr;
826 HTTPContext *c = NULL;
828 len = sizeof(from_addr);
829 fd = accept(server_fd, (struct sockaddr *)&from_addr,
832 http_log("error during accept %s\n", strerror(errno));
835 if (ff_socket_nonblock(fd, 1) < 0)
836 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
838 if (nb_connections >= nb_max_connections) {
839 http_send_too_busy_reply(fd);
843 /* add a new connection */
844 c = av_mallocz(sizeof(HTTPContext));
849 c->poll_entry = NULL;
850 c->from_addr = from_addr;
851 c->buffer_size = IOBUFFER_INIT_SIZE;
852 c->buffer = av_malloc(c->buffer_size);
856 c->next = first_http_ctx;
860 start_wait_request(c, is_rtsp);
872 static void close_connection(HTTPContext *c)
874 HTTPContext **cp, *c1;
876 AVFormatContext *ctx;
880 /* remove connection from list */
881 cp = &first_http_ctx;
882 while ((*cp) != NULL) {
890 /* remove references, if any (XXX: do it faster) */
891 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
896 /* remove connection associated resources */
900 /* close each frame parser */
901 for(i=0;i<c->fmt_in->nb_streams;i++) {
902 st = c->fmt_in->streams[i];
903 if (st->codec->codec)
904 avcodec_close(st->codec);
906 avformat_close_input(&c->fmt_in);
909 /* free RTP output streams if any */
912 nb_streams = c->stream->nb_streams;
914 for(i=0;i<nb_streams;i++) {
917 av_write_trailer(ctx);
918 av_dict_free(&ctx->metadata);
919 av_free(ctx->streams[0]);
922 h = c->rtp_handles[i];
929 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
932 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
933 av_write_trailer(ctx);
934 av_freep(&c->pb_buffer);
935 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
940 for(i=0; i<ctx->nb_streams; i++)
941 av_free(ctx->streams[i]);
942 av_freep(&ctx->streams);
943 av_freep(&ctx->priv_data);
945 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
946 current_bandwidth -= c->stream->bandwidth;
948 /* signal that there is no feed if we are the feeder socket */
949 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
950 c->stream->feed_opened = 0;
954 av_freep(&c->pb_buffer);
955 av_freep(&c->packet_buffer);
961 static int handle_connection(HTTPContext *c)
966 case HTTPSTATE_WAIT_REQUEST:
967 case RTSPSTATE_WAIT_REQUEST:
969 if ((c->timeout - cur_time) < 0)
971 if (c->poll_entry->revents & (POLLERR | POLLHUP))
974 /* no need to read if no events */
975 if (!(c->poll_entry->revents & POLLIN))
979 len = recv(c->fd, c->buffer_ptr, 1, 0);
981 if (ff_neterrno() != AVERROR(EAGAIN) &&
982 ff_neterrno() != AVERROR(EINTR))
984 } else if (len == 0) {
987 /* search for end of request. */
989 c->buffer_ptr += len;
991 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
992 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
993 /* request found : parse it and reply */
994 if (c->state == HTTPSTATE_WAIT_REQUEST) {
995 ret = http_parse_request(c);
997 ret = rtsp_parse_request(c);
1001 } else if (ptr >= c->buffer_end) {
1002 /* request too long: cannot do anything */
1004 } else goto read_loop;
1008 case HTTPSTATE_SEND_HEADER:
1009 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1012 /* no need to write if no events */
1013 if (!(c->poll_entry->revents & POLLOUT))
1015 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1017 if (ff_neterrno() != AVERROR(EAGAIN) &&
1018 ff_neterrno() != AVERROR(EINTR)) {
1019 goto close_connection;
1022 c->buffer_ptr += len;
1024 c->stream->bytes_served += len;
1025 c->data_count += len;
1026 if (c->buffer_ptr >= c->buffer_end) {
1027 av_freep(&c->pb_buffer);
1028 /* if error, exit */
1031 /* all the buffer was sent : synchronize to the incoming
1033 c->state = HTTPSTATE_SEND_DATA_HEADER;
1034 c->buffer_ptr = c->buffer_end = c->buffer;
1039 case HTTPSTATE_SEND_DATA:
1040 case HTTPSTATE_SEND_DATA_HEADER:
1041 case HTTPSTATE_SEND_DATA_TRAILER:
1042 /* for packetized output, we consider we can always write (the
1043 input streams set the speed). It may be better to verify
1044 that we do not rely too much on the kernel queues */
1045 if (!c->is_packetized) {
1046 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1049 /* no need to read if no events */
1050 if (!(c->poll_entry->revents & POLLOUT))
1053 if (http_send_data(c) < 0)
1055 /* close connection if trailer sent */
1056 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1059 case HTTPSTATE_RECEIVE_DATA:
1060 /* no need to read if no events */
1061 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1063 if (!(c->poll_entry->revents & POLLIN))
1065 if (http_receive_data(c) < 0)
1068 case HTTPSTATE_WAIT_FEED:
1069 /* no need to read if no events */
1070 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1073 /* nothing to do, we'll be waken up by incoming feed packets */
1076 case RTSPSTATE_SEND_REPLY:
1077 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1078 goto close_connection;
1079 /* no need to write if no events */
1080 if (!(c->poll_entry->revents & POLLOUT))
1082 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1084 if (ff_neterrno() != AVERROR(EAGAIN) &&
1085 ff_neterrno() != AVERROR(EINTR)) {
1086 goto close_connection;
1089 c->buffer_ptr += len;
1090 c->data_count += len;
1091 if (c->buffer_ptr >= c->buffer_end) {
1092 /* all the buffer was sent : wait for a new request */
1093 av_freep(&c->pb_buffer);
1094 start_wait_request(c, 1);
1098 case RTSPSTATE_SEND_PACKET:
1099 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1100 av_freep(&c->packet_buffer);
1103 /* no need to write if no events */
1104 if (!(c->poll_entry->revents & POLLOUT))
1106 len = send(c->fd, c->packet_buffer_ptr,
1107 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1109 if (ff_neterrno() != AVERROR(EAGAIN) &&
1110 ff_neterrno() != AVERROR(EINTR)) {
1111 /* error : close connection */
1112 av_freep(&c->packet_buffer);
1116 c->packet_buffer_ptr += len;
1117 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1118 /* all the buffer was sent : wait for a new request */
1119 av_freep(&c->packet_buffer);
1120 c->state = RTSPSTATE_WAIT_REQUEST;
1124 case HTTPSTATE_READY:
1133 av_freep(&c->pb_buffer);
1137 static int extract_rates(char *rates, int ratelen, const char *request)
1141 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1142 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1143 const char *q = p + 7;
1145 while (*q && *q != '\n' && av_isspace(*q))
1148 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1154 memset(rates, 0xff, ratelen);
1157 while (*q && *q != '\n' && *q != ':')
1160 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1164 if (stream_no < ratelen && stream_no >= 0)
1165 rates[stream_no] = rate_no;
1167 while (*q && *q != '\n' && !av_isspace(*q))
1174 p = strchr(p, '\n');
1184 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1187 int best_bitrate = 100000000;
1190 for (i = 0; i < feed->nb_streams; i++) {
1191 AVCodecContext *feed_codec = feed->streams[i]->codec;
1193 if (feed_codec->codec_id != codec->codec_id ||
1194 feed_codec->sample_rate != codec->sample_rate ||
1195 feed_codec->width != codec->width ||
1196 feed_codec->height != codec->height)
1199 /* Potential stream */
1201 /* We want the fastest stream less than bit_rate, or the slowest
1202 * faster than bit_rate
1205 if (feed_codec->bit_rate <= bit_rate) {
1206 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1207 best_bitrate = feed_codec->bit_rate;
1211 if (feed_codec->bit_rate < best_bitrate) {
1212 best_bitrate = feed_codec->bit_rate;
1221 static int modify_current_stream(HTTPContext *c, char *rates)
1224 FFStream *req = c->stream;
1225 int action_required = 0;
1227 /* Not much we can do for a feed */
1231 for (i = 0; i < req->nb_streams; i++) {
1232 AVCodecContext *codec = req->streams[i]->codec;
1236 c->switch_feed_streams[i] = req->feed_streams[i];
1239 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1242 /* Wants off or slow */
1243 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1245 /* This doesn't work well when it turns off the only stream! */
1246 c->switch_feed_streams[i] = -2;
1247 c->feed_streams[i] = -2;
1252 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1253 action_required = 1;
1256 return action_required;
1259 /* XXX: factorize in utils.c ? */
1260 /* XXX: take care with different space meaning */
1261 static void skip_spaces(const char **pp)
1265 while (*p == ' ' || *p == '\t')
1270 static void get_word(char *buf, int buf_size, const char **pp)
1278 while (!av_isspace(*p) && *p != '\0') {
1279 if ((q - buf) < buf_size - 1)
1288 static void get_arg(char *buf, int buf_size, const char **pp)
1295 while (av_isspace(*p)) p++;
1298 if (*p == '\"' || *p == '\'')
1310 if ((q - buf) < buf_size - 1)
1315 if (quote && *p == quote)
1320 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1321 const char *p, const char *filename, int line_num)
1327 get_arg(arg, sizeof(arg), &p);
1328 if (av_strcasecmp(arg, "allow") == 0)
1329 acl.action = IP_ALLOW;
1330 else if (av_strcasecmp(arg, "deny") == 0)
1331 acl.action = IP_DENY;
1333 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1334 filename, line_num, arg);
1338 get_arg(arg, sizeof(arg), &p);
1340 if (resolve_host(&acl.first, arg) != 0) {
1341 fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1342 filename, line_num, arg);
1345 acl.last = acl.first;
1347 get_arg(arg, sizeof(arg), &p);
1350 if (resolve_host(&acl.last, arg) != 0) {
1351 fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1352 filename, line_num, arg);
1358 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1359 IPAddressACL **naclp = 0;
1365 naclp = &stream->acl;
1371 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1372 filename, line_num);
1378 naclp = &(*naclp)->next;
1387 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1392 IPAddressACL *acl = NULL;
1396 f = fopen(stream->dynamic_acl, "r");
1398 perror(stream->dynamic_acl);
1402 acl = av_mallocz(sizeof(IPAddressACL));
1406 if (fgets(line, sizeof(line), f) == NULL)
1410 while (av_isspace(*p))
1412 if (*p == '\0' || *p == '#')
1414 get_arg(cmd, sizeof(cmd), &p);
1416 if (!av_strcasecmp(cmd, "ACL"))
1417 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1424 static void free_acl_list(IPAddressACL *in_acl)
1426 IPAddressACL *pacl,*pacl2;
1436 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1438 enum IPAddressAction last_action = IP_DENY;
1440 struct in_addr *src = &c->from_addr.sin_addr;
1441 unsigned long src_addr = src->s_addr;
1443 for (acl = in_acl; acl; acl = acl->next) {
1444 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1445 return (acl->action == IP_ALLOW) ? 1 : 0;
1446 last_action = acl->action;
1449 /* Nothing matched, so return not the last action */
1450 return (last_action == IP_DENY) ? 1 : 0;
1453 static int validate_acl(FFStream *stream, HTTPContext *c)
1459 /* if stream->acl is null validate_acl_list will return 1 */
1460 ret = validate_acl_list(stream->acl, c);
1462 if (stream->dynamic_acl[0]) {
1463 acl = parse_dynamic_acl(stream, c);
1465 ret = validate_acl_list(acl, c);
1473 /* compute the real filename of a file by matching it without its
1474 extensions to all the stream's filenames */
1475 static void compute_real_filename(char *filename, int max_size)
1482 /* compute filename by matching without the file extensions */
1483 av_strlcpy(file1, filename, sizeof(file1));
1484 p = strrchr(file1, '.');
1487 for(stream = first_stream; stream != NULL; stream = stream->next) {
1488 av_strlcpy(file2, stream->filename, sizeof(file2));
1489 p = strrchr(file2, '.');
1492 if (!strcmp(file1, file2)) {
1493 av_strlcpy(filename, stream->filename, max_size);
1508 /* parse HTTP request and prepare header */
1509 static int http_parse_request(HTTPContext *c)
1513 enum RedirType redir_type;
1515 char info[1024], filename[1024];
1519 const char *mime_type;
1523 const char *useragent = 0;
1526 get_word(cmd, sizeof(cmd), &p);
1527 av_strlcpy(c->method, cmd, sizeof(c->method));
1529 if (!strcmp(cmd, "GET"))
1531 else if (!strcmp(cmd, "POST"))
1536 get_word(url, sizeof(url), &p);
1537 av_strlcpy(c->url, url, sizeof(c->url));
1539 get_word(protocol, sizeof(protocol), (const char **)&p);
1540 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1543 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1546 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1548 /* find the filename and the optional info string in the request */
1549 p1 = strchr(url, '?');
1551 av_strlcpy(info, p1, sizeof(info));
1556 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1558 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1559 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1561 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1565 p = strchr(p, '\n');
1572 redir_type = REDIR_NONE;
1573 if (av_match_ext(filename, "asx")) {
1574 redir_type = REDIR_ASX;
1575 filename[strlen(filename)-1] = 'f';
1576 } else if (av_match_ext(filename, "asf") &&
1577 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1578 /* if this isn't WMP or lookalike, return the redirector file */
1579 redir_type = REDIR_ASF;
1580 } else if (av_match_ext(filename, "rpm,ram")) {
1581 redir_type = REDIR_RAM;
1582 strcpy(filename + strlen(filename)-2, "m");
1583 } else if (av_match_ext(filename, "rtsp")) {
1584 redir_type = REDIR_RTSP;
1585 compute_real_filename(filename, sizeof(filename) - 1);
1586 } else if (av_match_ext(filename, "sdp")) {
1587 redir_type = REDIR_SDP;
1588 compute_real_filename(filename, sizeof(filename) - 1);
1591 // "redirect" / request to index.html
1592 if (!strlen(filename))
1593 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1595 stream = first_stream;
1596 while (stream != NULL) {
1597 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1599 stream = stream->next;
1601 if (stream == NULL) {
1602 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1603 http_log("File '%s' not found\n", url);
1608 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1609 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1611 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1612 c->http_error = 301;
1614 snprintf(q, c->buffer_size,
1615 "HTTP/1.0 301 Moved\r\n"
1617 "Content-type: text/html\r\n"
1619 "<html><head><title>Moved</title></head><body>\r\n"
1620 "You should be <a href=\"%s\">redirected</a>.\r\n"
1621 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1623 /* prepare output buffer */
1624 c->buffer_ptr = c->buffer;
1626 c->state = HTTPSTATE_SEND_HEADER;
1630 /* If this is WMP, get the rate information */
1631 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1632 if (modify_current_stream(c, ratebuf)) {
1633 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1634 if (c->switch_feed_streams[i] >= 0)
1635 c->switch_feed_streams[i] = -1;
1640 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1641 current_bandwidth += stream->bandwidth;
1643 /* If already streaming this feed, do not let start another feeder. */
1644 if (stream->feed_opened) {
1645 snprintf(msg, sizeof(msg), "This feed is already being received.");
1646 http_log("Feed '%s' already being received\n", stream->feed_filename);
1650 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1651 c->http_error = 503;
1653 snprintf(q, c->buffer_size,
1654 "HTTP/1.0 503 Server too busy\r\n"
1655 "Content-type: text/html\r\n"
1657 "<html><head><title>Too busy</title></head><body>\r\n"
1658 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1659 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1660 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1661 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1663 /* prepare output buffer */
1664 c->buffer_ptr = c->buffer;
1666 c->state = HTTPSTATE_SEND_HEADER;
1670 if (redir_type != REDIR_NONE) {
1671 const char *hostinfo = 0;
1673 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1674 if (av_strncasecmp(p, "Host:", 5) == 0) {
1678 p = strchr(p, '\n');
1689 while (av_isspace(*hostinfo))
1692 eoh = strchr(hostinfo, '\n');
1694 if (eoh[-1] == '\r')
1697 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1698 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1699 hostbuf[eoh - hostinfo] = 0;
1701 c->http_error = 200;
1703 switch(redir_type) {
1705 snprintf(q, c->buffer_size,
1706 "HTTP/1.0 200 ASX Follows\r\n"
1707 "Content-type: video/x-ms-asf\r\n"
1709 "<ASX Version=\"3\">\r\n"
1710 //"<!-- Autogenerated by ffserver -->\r\n"
1711 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1712 "</ASX>\r\n", hostbuf, filename, info);
1716 snprintf(q, c->buffer_size,
1717 "HTTP/1.0 200 RAM Follows\r\n"
1718 "Content-type: audio/x-pn-realaudio\r\n"
1720 "# Autogenerated by ffserver\r\n"
1721 "http://%s/%s%s\r\n", hostbuf, filename, info);
1725 snprintf(q, c->buffer_size,
1726 "HTTP/1.0 200 ASF Redirect follows\r\n"
1727 "Content-type: video/x-ms-asf\r\n"
1730 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1735 char hostname[256], *p;
1736 /* extract only hostname */
1737 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1738 p = strrchr(hostname, ':');
1741 snprintf(q, c->buffer_size,
1742 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1743 /* XXX: incorrect MIME type ? */
1744 "Content-type: application/x-rtsp\r\n"
1746 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1755 struct sockaddr_in my_addr;
1757 snprintf(q, c->buffer_size,
1758 "HTTP/1.0 200 OK\r\n"
1759 "Content-type: application/sdp\r\n"
1763 len = sizeof(my_addr);
1765 /* XXX: Should probably fail? */
1766 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1767 http_log("getsockname() failed\n");
1769 /* XXX: should use a dynamic buffer */
1770 sdp_data_size = prepare_sdp_description(stream,
1773 if (sdp_data_size > 0) {
1774 memcpy(q, sdp_data, sdp_data_size);
1786 /* prepare output buffer */
1787 c->buffer_ptr = c->buffer;
1789 c->state = HTTPSTATE_SEND_HEADER;
1795 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1799 stream->conns_served++;
1801 /* XXX: add there authenticate and IP match */
1804 /* if post, it means a feed is being sent */
1805 if (!stream->is_feed) {
1806 /* However it might be a status report from WMP! Let us log the
1807 * data as it might come handy one day. */
1808 const char *logline = 0;
1811 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1812 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1816 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1817 client_id = strtol(p + 18, 0, 10);
1818 p = strchr(p, '\n');
1826 char *eol = strchr(logline, '\n');
1831 if (eol[-1] == '\r')
1833 http_log("%.*s\n", (int) (eol - logline), logline);
1834 c->suppress_log = 1;
1839 http_log("\nGot request:\n%s\n", c->buffer);
1842 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1845 /* Now we have to find the client_id */
1846 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1847 if (wmpc->wmp_client_id == client_id)
1851 if (wmpc && modify_current_stream(wmpc, ratebuf))
1852 wmpc->switch_pending = 1;
1855 snprintf(msg, sizeof(msg), "POST command not handled");
1859 if (http_start_receive_data(c) < 0) {
1860 snprintf(msg, sizeof(msg), "could not open feed");
1864 c->state = HTTPSTATE_RECEIVE_DATA;
1869 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1870 http_log("\nGot request:\n%s\n", c->buffer);
1873 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1876 /* open input stream */
1877 if (open_input_stream(c, info) < 0) {
1878 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1882 /* prepare HTTP header */
1884 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1885 mime_type = c->stream->fmt->mime_type;
1887 mime_type = "application/x-octet-stream";
1888 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1890 /* for asf, we need extra headers */
1891 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1892 /* Need to allocate a client id */
1894 c->wmp_client_id = av_lfg_get(&random_state);
1896 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);
1898 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1899 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1900 q = c->buffer + strlen(c->buffer);
1902 /* prepare output buffer */
1904 c->buffer_ptr = c->buffer;
1906 c->state = HTTPSTATE_SEND_HEADER;
1909 c->http_error = 404;
1912 snprintf(q, c->buffer_size,
1913 "HTTP/1.0 404 Not Found\r\n"
1914 "Content-type: text/html\r\n"
1917 "<head><title>404 Not Found</title></head>\n"
1921 /* prepare output buffer */
1922 c->buffer_ptr = c->buffer;
1924 c->state = HTTPSTATE_SEND_HEADER;
1928 c->http_error = 200; /* horrible : we use this value to avoid
1929 going to the send data state */
1930 c->state = HTTPSTATE_SEND_HEADER;
1934 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1936 static const char suffix[] = " kMGTP";
1939 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1941 avio_printf(pb, "%"PRId64"%c", count, *s);
1944 static void compute_status(HTTPContext *c)
1953 if (avio_open_dyn_buf(&pb) < 0) {
1954 /* XXX: return an error ? */
1955 c->buffer_ptr = c->buffer;
1956 c->buffer_end = c->buffer;
1960 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1961 avio_printf(pb, "Content-type: text/html\r\n");
1962 avio_printf(pb, "Pragma: no-cache\r\n");
1963 avio_printf(pb, "\r\n");
1965 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1966 if (c->stream->feed_filename[0])
1967 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1968 avio_printf(pb, "</head>\n<body>");
1969 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1971 avio_printf(pb, "<h2>Available Streams</h2>\n");
1972 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1973 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");
1974 stream = first_stream;
1975 while (stream != NULL) {
1976 char sfilename[1024];
1979 if (stream->feed != stream) {
1980 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1981 eosf = sfilename + strlen(sfilename);
1982 if (eosf - sfilename >= 4) {
1983 if (strcmp(eosf - 4, ".asf") == 0)
1984 strcpy(eosf - 4, ".asx");
1985 else if (strcmp(eosf - 3, ".rm") == 0)
1986 strcpy(eosf - 3, ".ram");
1987 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1988 /* generate a sample RTSP director if
1989 unicast. Generate an SDP redirector if
1991 eosf = strrchr(sfilename, '.');
1993 eosf = sfilename + strlen(sfilename);
1994 if (stream->is_multicast)
1995 strcpy(eosf, ".sdp");
1997 strcpy(eosf, ".rtsp");
2001 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
2002 sfilename, stream->filename);
2003 avio_printf(pb, "<td align=right> %d <td align=right> ",
2004 stream->conns_served);
2005 fmt_bytecount(pb, stream->bytes_served);
2006 switch(stream->stream_type) {
2007 case STREAM_TYPE_LIVE: {
2008 int audio_bit_rate = 0;
2009 int video_bit_rate = 0;
2010 const char *audio_codec_name = "";
2011 const char *video_codec_name = "";
2012 const char *audio_codec_name_extra = "";
2013 const char *video_codec_name_extra = "";
2015 for(i=0;i<stream->nb_streams;i++) {
2016 AVStream *st = stream->streams[i];
2017 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2018 switch(st->codec->codec_type) {
2019 case AVMEDIA_TYPE_AUDIO:
2020 audio_bit_rate += st->codec->bit_rate;
2022 if (*audio_codec_name)
2023 audio_codec_name_extra = "...";
2024 audio_codec_name = codec->name;
2027 case AVMEDIA_TYPE_VIDEO:
2028 video_bit_rate += st->codec->bit_rate;
2030 if (*video_codec_name)
2031 video_codec_name_extra = "...";
2032 video_codec_name = codec->name;
2035 case AVMEDIA_TYPE_DATA:
2036 video_bit_rate += st->codec->bit_rate;
2042 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",
2045 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2046 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2048 avio_printf(pb, "<td>%s", stream->feed->filename);
2050 avio_printf(pb, "<td>%s", stream->feed_filename);
2051 avio_printf(pb, "\n");
2055 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2059 stream = stream->next;
2061 avio_printf(pb, "</table>\n");
2063 stream = first_stream;
2064 while (stream != NULL) {
2065 if (stream->feed == stream) {
2066 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2068 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2075 /* This is somewhat linux specific I guess */
2076 snprintf(ps_cmd, sizeof(ps_cmd),
2077 "ps -o \"%%cpu,cputime\" --no-headers %d",
2080 pid_stat = popen(ps_cmd, "r");
2085 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2087 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2095 avio_printf(pb, "<p>");
2097 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");
2099 for (i = 0; i < stream->nb_streams; i++) {
2100 AVStream *st = stream->streams[i];
2101 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2102 const char *type = "unknown";
2103 char parameters[64];
2107 switch(st->codec->codec_type) {
2108 case AVMEDIA_TYPE_AUDIO:
2110 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2112 case AVMEDIA_TYPE_VIDEO:
2114 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2115 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2120 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2121 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2123 avio_printf(pb, "</table>\n");
2126 stream = stream->next;
2129 /* connection status */
2130 avio_printf(pb, "<h2>Connection Status</h2>\n");
2132 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2133 nb_connections, nb_max_connections);
2135 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2136 current_bandwidth, max_bandwidth);
2138 avio_printf(pb, "<table>\n");
2139 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");
2140 c1 = first_http_ctx;
2142 while (c1 != NULL) {
2148 for (j = 0; j < c1->stream->nb_streams; j++) {
2149 if (!c1->stream->feed)
2150 bitrate += c1->stream->streams[j]->codec->bit_rate;
2151 else if (c1->feed_streams[j] >= 0)
2152 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2157 p = inet_ntoa(c1->from_addr.sin_addr);
2158 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2160 c1->stream ? c1->stream->filename : "",
2161 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2164 http_state[c1->state]);
2165 fmt_bytecount(pb, bitrate);
2166 avio_printf(pb, "<td align=right>");
2167 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2168 avio_printf(pb, "<td align=right>");
2169 fmt_bytecount(pb, c1->data_count);
2170 avio_printf(pb, "\n");
2173 avio_printf(pb, "</table>\n");
2178 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2179 avio_printf(pb, "</body>\n</html>\n");
2181 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2182 c->buffer_ptr = c->pb_buffer;
2183 c->buffer_end = c->pb_buffer + len;
2186 static int open_input_stream(HTTPContext *c, const char *info)
2189 char input_filename[1024];
2190 AVFormatContext *s = NULL;
2191 int buf_size, i, ret;
2194 /* find file name */
2195 if (c->stream->feed) {
2196 strcpy(input_filename, c->stream->feed->feed_filename);
2197 buf_size = FFM_PACKET_SIZE;
2198 /* compute position (absolute time) */
2199 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2200 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2201 http_log("Invalid date specification '%s' for stream\n", buf);
2204 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2205 int prebuffer = strtol(buf, 0, 10);
2206 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2208 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2210 strcpy(input_filename, c->stream->feed_filename);
2212 /* compute position (relative time) */
2213 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2214 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2215 http_log("Invalid date specification '%s' for stream\n", buf);
2221 if (!input_filename[0]) {
2222 http_log("No filename was specified for stream\n");
2223 return AVERROR(EINVAL);
2227 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2228 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2232 /* set buffer size */
2233 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2235 s->flags |= AVFMT_FLAG_GENPTS;
2237 if (strcmp(s->iformat->name, "ffm") &&
2238 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2239 http_log("Could not find stream info for input '%s'\n", input_filename);
2240 avformat_close_input(&s);
2244 /* choose stream as clock source (we favor the video stream if
2245 * present) for packet sending */
2246 c->pts_stream_index = 0;
2247 for(i=0;i<c->stream->nb_streams;i++) {
2248 if (c->pts_stream_index == 0 &&
2249 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2250 c->pts_stream_index = i;
2254 if (c->fmt_in->iformat->read_seek)
2255 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2256 /* set the start time (needed for maxtime and RTP packet timing) */
2257 c->start_time = cur_time;
2258 c->first_pts = AV_NOPTS_VALUE;
2262 /* return the server clock (in us) */
2263 static int64_t get_server_clock(HTTPContext *c)
2265 /* compute current pts value from system time */
2266 return (cur_time - c->start_time) * 1000;
2269 /* return the estimated time at which the current packet must be sent
2271 static int64_t get_packet_send_clock(HTTPContext *c)
2273 int bytes_left, bytes_sent, frame_bytes;
2275 frame_bytes = c->cur_frame_bytes;
2276 if (frame_bytes <= 0)
2279 bytes_left = c->buffer_end - c->buffer_ptr;
2280 bytes_sent = frame_bytes - bytes_left;
2281 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2286 static int http_prepare_data(HTTPContext *c)
2289 AVFormatContext *ctx;
2291 av_freep(&c->pb_buffer);
2293 case HTTPSTATE_SEND_DATA_HEADER:
2294 ctx = avformat_alloc_context();
2297 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2298 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2300 for(i=0;i<c->stream->nb_streams;i++) {
2302 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2303 /* if file or feed, then just take streams from FFStream struct */
2304 if (!c->stream->feed ||
2305 c->stream->feed == c->stream)
2306 src = c->stream->streams[i];
2308 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2310 *(c->fmt_ctx.streams[i]) = *src;
2311 c->fmt_ctx.streams[i]->priv_data = 0;
2312 /* XXX: should be done in AVStream, not in codec */
2313 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2315 /* set output format parameters */
2316 c->fmt_ctx.oformat = c->stream->fmt;
2317 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2319 c->got_key_frame = 0;
2321 /* prepare header and save header data in a stream */
2322 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2323 /* XXX: potential leak */
2326 c->fmt_ctx.pb->seekable = 0;
2329 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2330 * Default value from FFmpeg
2331 * Try to set it using configuration option
2333 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2335 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2336 http_log("Error writing output header for stream '%s': %s\n",
2337 c->stream->filename, av_err2str(ret));
2340 av_dict_free(&c->fmt_ctx.metadata);
2342 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2343 c->buffer_ptr = c->pb_buffer;
2344 c->buffer_end = c->pb_buffer + len;
2346 c->state = HTTPSTATE_SEND_DATA;
2347 c->last_packet_sent = 0;
2349 case HTTPSTATE_SEND_DATA:
2350 /* find a new packet */
2351 /* read a packet from the input stream */
2352 if (c->stream->feed)
2353 ffm_set_write_index(c->fmt_in,
2354 c->stream->feed->feed_write_index,
2355 c->stream->feed->feed_size);
2357 if (c->stream->max_time &&
2358 c->stream->max_time + c->start_time - cur_time < 0)
2359 /* We have timed out */
2360 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2364 ret = av_read_frame(c->fmt_in, &pkt);
2366 if (c->stream->feed) {
2367 /* if coming from feed, it means we reached the end of the
2368 ffm file, so must wait for more data */
2369 c->state = HTTPSTATE_WAIT_FEED;
2370 return 1; /* state changed */
2371 } else if (ret == AVERROR(EAGAIN)) {
2372 /* input not ready, come back later */
2375 if (c->stream->loop) {
2376 avformat_close_input(&c->fmt_in);
2377 if (open_input_stream(c, "") < 0)
2382 /* must send trailer now because EOF or error */
2383 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2387 int source_index = pkt.stream_index;
2388 /* update first pts if needed */
2389 if (c->first_pts == AV_NOPTS_VALUE) {
2390 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2391 c->start_time = cur_time;
2393 /* send it to the appropriate stream */
2394 if (c->stream->feed) {
2395 /* if coming from a feed, select the right stream */
2396 if (c->switch_pending) {
2397 c->switch_pending = 0;
2398 for(i=0;i<c->stream->nb_streams;i++) {
2399 if (c->switch_feed_streams[i] == pkt.stream_index)
2400 if (pkt.flags & AV_PKT_FLAG_KEY)
2401 c->switch_feed_streams[i] = -1;
2402 if (c->switch_feed_streams[i] >= 0)
2403 c->switch_pending = 1;
2406 for(i=0;i<c->stream->nb_streams;i++) {
2407 if (c->stream->feed_streams[i] == pkt.stream_index) {
2408 AVStream *st = c->fmt_in->streams[source_index];
2409 pkt.stream_index = i;
2410 if (pkt.flags & AV_PKT_FLAG_KEY &&
2411 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2412 c->stream->nb_streams == 1))
2413 c->got_key_frame = 1;
2414 if (!c->stream->send_on_key || c->got_key_frame)
2419 AVCodecContext *codec;
2420 AVStream *ist, *ost;
2422 ist = c->fmt_in->streams[source_index];
2423 /* specific handling for RTP: we use several
2424 * output streams (one for each RTP connection).
2425 * XXX: need more abstract handling */
2426 if (c->is_packetized) {
2427 /* compute send time and duration */
2428 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2429 c->cur_pts -= c->first_pts;
2430 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2431 /* find RTP context */
2432 c->packet_stream_index = pkt.stream_index;
2433 ctx = c->rtp_ctx[c->packet_stream_index];
2435 av_free_packet(&pkt);
2438 codec = ctx->streams[0]->codec;
2439 /* only one stream per RTP connection */
2440 pkt.stream_index = 0;
2444 codec = ctx->streams[pkt.stream_index]->codec;
2447 if (c->is_packetized) {
2448 int max_packet_size;
2449 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2450 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2452 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2453 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2455 ret = avio_open_dyn_buf(&ctx->pb);
2458 /* XXX: potential leak */
2461 ost = ctx->streams[pkt.stream_index];
2463 ctx->pb->seekable = 0;
2464 if (pkt.dts != AV_NOPTS_VALUE)
2465 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2466 if (pkt.pts != AV_NOPTS_VALUE)
2467 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2468 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2469 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2470 http_log("Error writing frame to output for stream '%s': %s\n",
2471 c->stream->filename, av_err2str(ret));
2472 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2475 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2476 c->cur_frame_bytes = len;
2477 c->buffer_ptr = c->pb_buffer;
2478 c->buffer_end = c->pb_buffer + len;
2480 codec->frame_number++;
2482 av_free_packet(&pkt);
2486 av_free_packet(&pkt);
2491 case HTTPSTATE_SEND_DATA_TRAILER:
2492 /* last packet test ? */
2493 if (c->last_packet_sent || c->is_packetized)
2496 /* prepare header */
2497 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2498 /* XXX: potential leak */
2501 c->fmt_ctx.pb->seekable = 0;
2502 av_write_trailer(ctx);
2503 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2504 c->buffer_ptr = c->pb_buffer;
2505 c->buffer_end = c->pb_buffer + len;
2507 c->last_packet_sent = 1;
2513 /* should convert the format at the same time */
2514 /* send data starting at c->buffer_ptr to the output connection
2515 * (either UDP or TCP) */
2516 static int http_send_data(HTTPContext *c)
2521 if (c->buffer_ptr >= c->buffer_end) {
2522 ret = http_prepare_data(c);
2526 /* state change requested */
2529 if (c->is_packetized) {
2530 /* RTP data output */
2531 len = c->buffer_end - c->buffer_ptr;
2533 /* fail safe - should never happen */
2535 c->buffer_ptr = c->buffer_end;
2538 len = (c->buffer_ptr[0] << 24) |
2539 (c->buffer_ptr[1] << 16) |
2540 (c->buffer_ptr[2] << 8) |
2542 if (len > (c->buffer_end - c->buffer_ptr))
2544 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2545 /* nothing to send yet: we can wait */
2549 c->data_count += len;
2550 update_datarate(&c->datarate, c->data_count);
2552 c->stream->bytes_served += len;
2554 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2555 /* RTP packets are sent inside the RTSP TCP connection */
2557 int interleaved_index, size;
2559 HTTPContext *rtsp_c;
2562 /* if no RTSP connection left, error */
2565 /* if already sending something, then wait. */
2566 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2568 if (avio_open_dyn_buf(&pb) < 0)
2570 interleaved_index = c->packet_stream_index * 2;
2571 /* RTCP packets are sent at odd indexes */
2572 if (c->buffer_ptr[1] == 200)
2573 interleaved_index++;
2574 /* write RTSP TCP header */
2576 header[1] = interleaved_index;
2577 header[2] = len >> 8;
2579 avio_write(pb, header, 4);
2580 /* write RTP packet data */
2582 avio_write(pb, c->buffer_ptr, len);
2583 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2584 /* prepare asynchronous TCP sending */
2585 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2586 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2587 c->buffer_ptr += len;
2589 /* send everything we can NOW */
2590 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2591 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2593 rtsp_c->packet_buffer_ptr += len;
2594 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2595 /* if we could not send all the data, we will
2596 send it later, so a new state is needed to
2597 "lock" the RTSP TCP connection */
2598 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2601 /* all data has been sent */
2602 av_freep(&c->packet_buffer);
2604 /* send RTP packet directly in UDP */
2606 ffurl_write(c->rtp_handles[c->packet_stream_index],
2607 c->buffer_ptr, len);
2608 c->buffer_ptr += len;
2609 /* here we continue as we can send several packets per 10 ms slot */
2612 /* TCP data output */
2613 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2615 if (ff_neterrno() != AVERROR(EAGAIN) &&
2616 ff_neterrno() != AVERROR(EINTR))
2617 /* error : close connection */
2622 c->buffer_ptr += len;
2624 c->data_count += len;
2625 update_datarate(&c->datarate, c->data_count);
2627 c->stream->bytes_served += len;
2635 static int http_start_receive_data(HTTPContext *c)
2640 if (c->stream->feed_opened) {
2641 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2642 return AVERROR(EINVAL);
2645 /* Don't permit writing to this one */
2646 if (c->stream->readonly) {
2647 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2648 return AVERROR(EINVAL);
2652 fd = open(c->stream->feed_filename, O_RDWR);
2654 ret = AVERROR(errno);
2655 http_log("Could not open feed file '%s': %s\n",
2656 c->stream->feed_filename, strerror(errno));
2661 if (c->stream->truncate) {
2662 /* truncate feed file */
2663 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2664 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2665 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2666 ret = AVERROR(errno);
2667 http_log("Error truncating feed file '%s': %s\n",
2668 c->stream->feed_filename, strerror(errno));
2672 ret = ffm_read_write_index(fd);
2674 http_log("Error reading write index from feed file '%s': %s\n",
2675 c->stream->feed_filename, strerror(errno));
2678 c->stream->feed_write_index = ret;
2682 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2683 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2684 lseek(fd, 0, SEEK_SET);
2686 /* init buffer input */
2687 c->buffer_ptr = c->buffer;
2688 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2689 c->stream->feed_opened = 1;
2690 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2694 static int http_receive_data(HTTPContext *c)
2697 int len, loop_run = 0;
2699 while (c->chunked_encoding && !c->chunk_size &&
2700 c->buffer_end > c->buffer_ptr) {
2701 /* read chunk header, if present */
2702 len = recv(c->fd, c->buffer_ptr, 1, 0);
2705 if (ff_neterrno() != AVERROR(EAGAIN) &&
2706 ff_neterrno() != AVERROR(EINTR))
2707 /* error : close connection */
2710 } else if (len == 0) {
2711 /* end of connection : close it */
2713 } else if (c->buffer_ptr - c->buffer >= 2 &&
2714 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2715 c->chunk_size = strtol(c->buffer, 0, 16);
2716 if (c->chunk_size == 0) // end of stream
2718 c->buffer_ptr = c->buffer;
2720 } else if (++loop_run > 10) {
2721 /* no chunk header, abort */
2728 if (c->buffer_end > c->buffer_ptr) {
2729 len = recv(c->fd, c->buffer_ptr,
2730 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2732 if (ff_neterrno() != AVERROR(EAGAIN) &&
2733 ff_neterrno() != AVERROR(EINTR))
2734 /* error : close connection */
2736 } else if (len == 0)
2737 /* end of connection : close it */
2740 c->chunk_size -= len;
2741 c->buffer_ptr += len;
2742 c->data_count += len;
2743 update_datarate(&c->datarate, c->data_count);
2747 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2748 if (c->buffer[0] != 'f' ||
2749 c->buffer[1] != 'm') {
2750 http_log("Feed stream has become desynchronized -- disconnecting\n");
2755 if (c->buffer_ptr >= c->buffer_end) {
2756 FFStream *feed = c->stream;
2757 /* a packet has been received : write it in the store, except
2759 if (c->data_count > FFM_PACKET_SIZE) {
2760 /* XXX: use llseek or url_seek
2761 * XXX: Should probably fail? */
2762 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2763 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2765 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2766 http_log("Error writing to feed file: %s\n", strerror(errno));
2770 feed->feed_write_index += FFM_PACKET_SIZE;
2771 /* update file size */
2772 if (feed->feed_write_index > c->stream->feed_size)
2773 feed->feed_size = feed->feed_write_index;
2775 /* handle wrap around if max file size reached */
2776 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2777 feed->feed_write_index = FFM_PACKET_SIZE;
2780 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2781 http_log("Error writing index to feed file: %s\n", strerror(errno));
2785 /* wake up any waiting connections */
2786 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2787 if (c1->state == HTTPSTATE_WAIT_FEED &&
2788 c1->stream->feed == c->stream->feed)
2789 c1->state = HTTPSTATE_SEND_DATA;
2792 /* We have a header in our hands that contains useful data */
2793 AVFormatContext *s = avformat_alloc_context();
2795 AVInputFormat *fmt_in;
2801 /* use feed output format name to find corresponding input format */
2802 fmt_in = av_find_input_format(feed->fmt->name);
2806 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2807 0, NULL, NULL, NULL, NULL);
2811 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2816 /* Now we have the actual streams */
2817 if (s->nb_streams != feed->nb_streams) {
2818 avformat_close_input(&s);
2820 http_log("Feed '%s' stream number does not match registered feed\n",
2821 c->stream->feed_filename);
2825 for (i = 0; i < s->nb_streams; i++) {
2826 AVStream *fst = feed->streams[i];
2827 AVStream *st = s->streams[i];
2828 avcodec_copy_context(fst->codec, st->codec);
2831 avformat_close_input(&s);
2834 c->buffer_ptr = c->buffer;
2839 c->stream->feed_opened = 0;
2841 /* wake up any waiting connections to stop waiting for feed */
2842 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2843 if (c1->state == HTTPSTATE_WAIT_FEED &&
2844 c1->stream->feed == c->stream->feed)
2845 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2850 /********************************************************************/
2853 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2860 str = RTSP_STATUS_CODE2STRING(error_number);
2862 str = "Unknown Error";
2864 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2865 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2867 /* output GMT time */
2870 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2871 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2874 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2876 rtsp_reply_header(c, error_number);
2877 avio_printf(c->pb, "\r\n");
2880 static int rtsp_parse_request(HTTPContext *c)
2882 const char *p, *p1, *p2;
2888 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2890 c->buffer_ptr[0] = '\0';
2893 get_word(cmd, sizeof(cmd), &p);
2894 get_word(url, sizeof(url), &p);
2895 get_word(protocol, sizeof(protocol), &p);
2897 av_strlcpy(c->method, cmd, sizeof(c->method));
2898 av_strlcpy(c->url, url, sizeof(c->url));
2899 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2901 if (avio_open_dyn_buf(&c->pb) < 0) {
2902 /* XXX: cannot do more */
2903 c->pb = NULL; /* safety */
2907 /* check version name */
2908 if (strcmp(protocol, "RTSP/1.0") != 0) {
2909 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2913 /* parse each header line */
2914 /* skip to next line */
2915 while (*p != '\n' && *p != '\0')
2919 while (*p != '\0') {
2920 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2924 if (p2 > p && p2[-1] == '\r')
2926 /* skip empty line */
2930 if (len > sizeof(line) - 1)
2931 len = sizeof(line) - 1;
2932 memcpy(line, p, len);
2934 ff_rtsp_parse_line(header, line, NULL, NULL);
2938 /* handle sequence number */
2939 c->seq = header->seq;
2941 if (!strcmp(cmd, "DESCRIBE"))
2942 rtsp_cmd_describe(c, url);
2943 else if (!strcmp(cmd, "OPTIONS"))
2944 rtsp_cmd_options(c, url);
2945 else if (!strcmp(cmd, "SETUP"))
2946 rtsp_cmd_setup(c, url, header);
2947 else if (!strcmp(cmd, "PLAY"))
2948 rtsp_cmd_play(c, url, header);
2949 else if (!strcmp(cmd, "PAUSE"))
2950 rtsp_cmd_interrupt(c, url, header, 1);
2951 else if (!strcmp(cmd, "TEARDOWN"))
2952 rtsp_cmd_interrupt(c, url, header, 0);
2954 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2957 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2958 c->pb = NULL; /* safety */
2960 /* XXX: cannot do more */
2963 c->buffer_ptr = c->pb_buffer;
2964 c->buffer_end = c->pb_buffer + len;
2965 c->state = RTSPSTATE_SEND_REPLY;
2969 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2970 struct in_addr my_ip)
2972 AVFormatContext *avc;
2973 AVStream *avs = NULL;
2974 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2975 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2978 avc = avformat_alloc_context();
2979 if (avc == NULL || !rtp_format) {
2982 avc->oformat = rtp_format;
2983 av_dict_set(&avc->metadata, "title",
2984 entry ? entry->value : "No Title", 0);
2985 avc->nb_streams = stream->nb_streams;
2986 if (stream->is_multicast) {
2987 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2988 inet_ntoa(stream->multicast_ip),
2989 stream->multicast_port, stream->multicast_ttl);
2991 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2994 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2995 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2997 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2998 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
3001 for(i = 0; i < stream->nb_streams; i++) {
3002 avc->streams[i] = &avs[i];
3003 avc->streams[i]->codec = stream->streams[i]->codec;
3005 *pbuffer = av_mallocz(2048);
3006 av_sdp_create(&avc, 1, *pbuffer, 2048);
3009 av_free(avc->streams);
3010 av_dict_free(&avc->metadata);
3014 return strlen(*pbuffer);
3017 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3019 // rtsp_reply_header(c, RTSP_STATUS_OK);
3020 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3021 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3022 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3023 avio_printf(c->pb, "\r\n");
3026 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3034 struct sockaddr_in my_addr;
3036 /* find which URL is asked */
3037 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3042 for(stream = first_stream; stream != NULL; stream = stream->next) {
3043 if (!stream->is_feed &&
3044 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3045 !strcmp(path, stream->filename)) {
3049 /* no stream found */
3050 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3054 /* prepare the media description in SDP format */
3056 /* get the host IP */
3057 len = sizeof(my_addr);
3058 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3059 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3060 if (content_length < 0) {
3061 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3064 rtsp_reply_header(c, RTSP_STATUS_OK);
3065 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3066 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3067 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3068 avio_printf(c->pb, "\r\n");
3069 avio_write(c->pb, content, content_length);
3073 static HTTPContext *find_rtp_session(const char *session_id)
3077 if (session_id[0] == '\0')
3080 for(c = first_http_ctx; c != NULL; c = c->next) {
3081 if (!strcmp(c->session_id, session_id))
3087 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3089 RTSPTransportField *th;
3092 for(i=0;i<h->nb_transports;i++) {
3093 th = &h->transports[i];
3094 if (th->lower_transport == lower_transport)
3100 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3101 RTSPMessageHeader *h)
3104 int stream_index, rtp_port, rtcp_port;
3109 RTSPTransportField *th;
3110 struct sockaddr_in dest_addr;
3111 RTSPActionServerSetup setup;
3113 /* find which URL is asked */
3114 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3119 /* now check each stream */
3120 for(stream = first_stream; stream != NULL; stream = stream->next) {
3121 if (!stream->is_feed &&
3122 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3123 /* accept aggregate filenames only if single stream */
3124 if (!strcmp(path, stream->filename)) {
3125 if (stream->nb_streams != 1) {
3126 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3133 for(stream_index = 0; stream_index < stream->nb_streams;
3135 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3136 stream->filename, stream_index);
3137 if (!strcmp(path, buf))
3142 /* no stream found */
3143 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3147 /* generate session id if needed */
3148 if (h->session_id[0] == '\0') {
3149 unsigned random0 = av_lfg_get(&random_state);
3150 unsigned random1 = av_lfg_get(&random_state);
3151 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3155 /* find RTP session, and create it if none found */
3156 rtp_c = find_rtp_session(h->session_id);
3158 /* always prefer UDP */
3159 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3161 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3163 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3168 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3169 th->lower_transport);
3171 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3175 /* open input stream */
3176 if (open_input_stream(rtp_c, "") < 0) {
3177 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3182 /* test if stream is OK (test needed because several SETUP needs
3183 to be done for a given file) */
3184 if (rtp_c->stream != stream) {
3185 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3189 /* test if stream is already set up */
3190 if (rtp_c->rtp_ctx[stream_index]) {
3191 rtsp_reply_error(c, RTSP_STATUS_STATE);
3195 /* check transport */
3196 th = find_transport(h, rtp_c->rtp_protocol);
3197 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3198 th->client_port_min <= 0)) {
3199 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3203 /* setup default options */
3204 setup.transport_option[0] = '\0';
3205 dest_addr = rtp_c->from_addr;
3206 dest_addr.sin_port = htons(th->client_port_min);
3209 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3210 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3214 /* now everything is OK, so we can send the connection parameters */
3215 rtsp_reply_header(c, RTSP_STATUS_OK);
3217 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3219 switch(rtp_c->rtp_protocol) {
3220 case RTSP_LOWER_TRANSPORT_UDP:
3221 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3222 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3223 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3224 "client_port=%d-%d;server_port=%d-%d",
3225 th->client_port_min, th->client_port_max,
3226 rtp_port, rtcp_port);
3228 case RTSP_LOWER_TRANSPORT_TCP:
3229 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3230 stream_index * 2, stream_index * 2 + 1);
3235 if (setup.transport_option[0] != '\0')
3236 avio_printf(c->pb, ";%s", setup.transport_option);
3237 avio_printf(c->pb, "\r\n");
3240 avio_printf(c->pb, "\r\n");
3244 /* find an RTP connection by using the session ID. Check consistency
3246 static HTTPContext *find_rtp_session_with_url(const char *url,
3247 const char *session_id)
3255 rtp_c = find_rtp_session(session_id);
3259 /* find which URL is asked */
3260 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3264 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3265 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3266 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3267 rtp_c->stream->filename, s);
3268 if(!strncmp(path, buf, sizeof(buf))) {
3269 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3274 if (len > 0 && path[len - 1] == '/' &&
3275 !strncmp(path, rtp_c->stream->filename, len - 1))
3280 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3284 rtp_c = find_rtp_session_with_url(url, h->session_id);
3286 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3290 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3291 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3292 rtp_c->state != HTTPSTATE_READY) {
3293 rtsp_reply_error(c, RTSP_STATUS_STATE);
3297 rtp_c->state = HTTPSTATE_SEND_DATA;
3299 /* now everything is OK, so we can send the connection parameters */
3300 rtsp_reply_header(c, RTSP_STATUS_OK);
3302 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3303 avio_printf(c->pb, "\r\n");
3306 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3310 rtp_c = find_rtp_session_with_url(url, h->session_id);
3312 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3317 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3318 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3319 rtsp_reply_error(c, RTSP_STATUS_STATE);
3322 rtp_c->state = HTTPSTATE_READY;
3323 rtp_c->first_pts = AV_NOPTS_VALUE;
3326 /* now everything is OK, so we can send the connection parameters */
3327 rtsp_reply_header(c, RTSP_STATUS_OK);
3329 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3330 avio_printf(c->pb, "\r\n");
3333 close_connection(rtp_c);
3336 /********************************************************************/
3339 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3340 FFStream *stream, const char *session_id,
3341 enum RTSPLowerTransport rtp_protocol)
3343 HTTPContext *c = NULL;
3344 const char *proto_str;
3346 /* XXX: should output a warning page when coming
3347 close to the connection limit */
3348 if (nb_connections >= nb_max_connections)
3351 /* add a new connection */
3352 c = av_mallocz(sizeof(HTTPContext));
3357 c->poll_entry = NULL;
3358 c->from_addr = *from_addr;
3359 c->buffer_size = IOBUFFER_INIT_SIZE;
3360 c->buffer = av_malloc(c->buffer_size);
3365 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3366 c->state = HTTPSTATE_READY;
3367 c->is_packetized = 1;
3368 c->rtp_protocol = rtp_protocol;
3370 /* protocol is shown in statistics */
3371 switch(c->rtp_protocol) {
3372 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3373 proto_str = "MCAST";
3375 case RTSP_LOWER_TRANSPORT_UDP:
3378 case RTSP_LOWER_TRANSPORT_TCP:
3385 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3386 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3388 current_bandwidth += stream->bandwidth;
3390 c->next = first_http_ctx;
3402 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3403 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3405 static int rtp_new_av_stream(HTTPContext *c,
3406 int stream_index, struct sockaddr_in *dest_addr,
3407 HTTPContext *rtsp_c)
3409 AVFormatContext *ctx;
3412 URLContext *h = NULL;
3414 int max_packet_size;
3416 /* now we can open the relevant output stream */
3417 ctx = avformat_alloc_context();
3420 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3422 st = av_mallocz(sizeof(AVStream));
3425 ctx->nb_streams = 1;
3426 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3429 ctx->streams[0] = st;
3431 if (!c->stream->feed ||
3432 c->stream->feed == c->stream)
3433 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3436 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3438 st->priv_data = NULL;
3440 /* build destination RTP address */
3441 ipaddr = inet_ntoa(dest_addr->sin_addr);
3443 switch(c->rtp_protocol) {
3444 case RTSP_LOWER_TRANSPORT_UDP:
3445 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3448 /* XXX: also pass as parameter to function ? */
3449 if (c->stream->is_multicast) {
3451 ttl = c->stream->multicast_ttl;
3454 snprintf(ctx->filename, sizeof(ctx->filename),
3455 "rtp://%s:%d?multicast=1&ttl=%d",
3456 ipaddr, ntohs(dest_addr->sin_port), ttl);
3458 snprintf(ctx->filename, sizeof(ctx->filename),
3459 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3462 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3464 c->rtp_handles[stream_index] = h;
3465 max_packet_size = h->max_packet_size;
3467 case RTSP_LOWER_TRANSPORT_TCP:
3470 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3476 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3477 ipaddr, ntohs(dest_addr->sin_port),
3478 c->stream->filename, stream_index, c->protocol);
3480 /* normally, no packets should be output here, but the packet size may
3482 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3483 /* XXX: close stream */
3486 if (avformat_write_header(ctx, NULL) < 0) {
3494 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3497 c->rtp_ctx[stream_index] = ctx;
3501 /********************************************************************/
3502 /* ffserver initialization */
3504 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3508 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3511 fst = av_mallocz(sizeof(AVStream));
3515 fst->codec = avcodec_alloc_context3(NULL);
3516 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3517 if (codec->extradata_size) {
3518 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3519 memcpy(fst->codec->extradata, codec->extradata,
3520 codec->extradata_size);
3523 /* live streams must use the actual feed's codec since it may be
3524 * updated later to carry extradata needed by them.
3528 fst->priv_data = av_mallocz(sizeof(FeedData));
3529 fst->index = stream->nb_streams;
3530 avpriv_set_pts_info(fst, 33, 1, 90000);
3531 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3532 stream->streams[stream->nb_streams++] = fst;
3536 /* return the stream number in the feed */
3537 static int add_av_stream(FFStream *feed, AVStream *st)
3540 AVCodecContext *av, *av1;
3544 for(i=0;i<feed->nb_streams;i++) {
3545 st = feed->streams[i];
3547 if (av1->codec_id == av->codec_id &&
3548 av1->codec_type == av->codec_type &&
3549 av1->bit_rate == av->bit_rate) {
3551 switch(av->codec_type) {
3552 case AVMEDIA_TYPE_AUDIO:
3553 if (av1->channels == av->channels &&
3554 av1->sample_rate == av->sample_rate)
3557 case AVMEDIA_TYPE_VIDEO:
3558 if (av1->width == av->width &&
3559 av1->height == av->height &&
3560 av1->time_base.den == av->time_base.den &&
3561 av1->time_base.num == av->time_base.num &&
3562 av1->gop_size == av->gop_size)
3571 fst = add_av_stream1(feed, av, 0);
3574 return feed->nb_streams - 1;
3577 static void remove_stream(FFStream *stream)
3581 while (*ps != NULL) {
3589 /* specific MPEG4 handling : we extract the raw parameters */
3590 static void extract_mpeg4_header(AVFormatContext *infile)
3592 int mpeg4_count, i, size;
3597 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3600 for(i=0;i<infile->nb_streams;i++) {
3601 st = infile->streams[i];
3602 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3603 st->codec->extradata_size == 0) {
3610 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3611 while (mpeg4_count > 0) {
3612 if (av_read_frame(infile, &pkt) < 0)
3614 st = infile->streams[pkt.stream_index];
3615 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3616 st->codec->extradata_size == 0) {
3617 av_freep(&st->codec->extradata);
3618 /* fill extradata with the header */
3619 /* XXX: we make hard suppositions here ! */
3621 while (p < pkt.data + pkt.size - 4) {
3622 /* stop when vop header is found */
3623 if (p[0] == 0x00 && p[1] == 0x00 &&
3624 p[2] == 0x01 && p[3] == 0xb6) {
3625 size = p - pkt.data;
3626 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3627 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3628 st->codec->extradata_size = size;
3629 memcpy(st->codec->extradata, pkt.data, size);
3636 av_free_packet(&pkt);
3640 /* compute the needed AVStream for each file */
3641 static void build_file_streams(void)
3643 FFStream *stream, *stream_next;
3646 /* gather all streams */
3647 for(stream = first_stream; stream != NULL; stream = stream_next) {
3648 AVFormatContext *infile = NULL;
3649 stream_next = stream->next;
3650 if (stream->stream_type == STREAM_TYPE_LIVE &&
3652 /* the stream comes from a file */
3653 /* try to open the file */
3655 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3656 /* specific case : if transport stream output to RTP,
3657 we use a raw transport stream reader */
3658 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3661 if (!stream->feed_filename[0]) {
3662 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3666 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3667 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3668 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3669 /* remove stream (no need to spend more time on it) */
3671 remove_stream(stream);
3673 /* find all the AVStreams inside and reference them in
3675 if (avformat_find_stream_info(infile, NULL) < 0) {
3676 http_log("Could not find codec parameters from '%s'\n",
3677 stream->feed_filename);
3678 avformat_close_input(&infile);
3681 extract_mpeg4_header(infile);
3683 for(i=0;i<infile->nb_streams;i++)
3684 add_av_stream1(stream, infile->streams[i]->codec, 1);
3686 avformat_close_input(&infile);
3692 /* compute the needed AVStream for each feed */
3693 static void build_feed_streams(void)
3695 FFStream *stream, *feed;
3698 /* gather all streams */
3699 for(stream = first_stream; stream != NULL; stream = stream->next) {
3700 feed = stream->feed;
3702 if (stream->is_feed) {
3703 for(i=0;i<stream->nb_streams;i++)
3704 stream->feed_streams[i] = i;
3706 /* we handle a stream coming from a feed */
3707 for(i=0;i<stream->nb_streams;i++)
3708 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3713 /* create feed files if needed */
3714 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3717 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3718 /* See if it matches */
3719 AVFormatContext *s = NULL;
3722 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3723 /* set buffer size */
3724 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3725 /* Now see if it matches */
3726 if (s->nb_streams == feed->nb_streams) {
3728 for(i=0;i<s->nb_streams;i++) {
3730 sf = feed->streams[i];
3733 if (sf->index != ss->index ||
3735 http_log("Index & Id do not match for stream %d (%s)\n",
3736 i, feed->feed_filename);
3739 AVCodecContext *ccf, *ccs;
3743 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3745 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3746 http_log("Codecs do not match for stream %d\n", i);
3748 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3749 http_log("Codec bitrates do not match for stream %d\n", i);
3751 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3752 if (CHECK_CODEC(time_base.den) ||
3753 CHECK_CODEC(time_base.num) ||
3754 CHECK_CODEC(width) ||
3755 CHECK_CODEC(height)) {
3756 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3759 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3760 if (CHECK_CODEC(sample_rate) ||
3761 CHECK_CODEC(channels) ||
3762 CHECK_CODEC(frame_size)) {
3763 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3767 http_log("Unknown codec type\n");
3775 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3776 feed->feed_filename, s->nb_streams, feed->nb_streams);
3778 avformat_close_input(&s);
3780 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3781 feed->feed_filename);
3784 if (feed->readonly) {
3785 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3786 feed->feed_filename);
3789 unlink(feed->feed_filename);
3792 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3793 AVFormatContext *s = avformat_alloc_context();
3795 if (feed->readonly) {
3796 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3797 feed->feed_filename);
3801 /* only write the header of the ffm file */
3802 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3803 http_log("Could not open output feed file '%s'\n",
3804 feed->feed_filename);
3807 s->oformat = feed->fmt;
3808 s->nb_streams = feed->nb_streams;
3809 s->streams = feed->streams;
3810 if (avformat_write_header(s, NULL) < 0) {
3811 http_log("Container doesn't support the required parameters\n");
3814 /* XXX: need better API */
3815 av_freep(&s->priv_data);
3819 avformat_free_context(s);
3821 /* get feed size and write index */
3822 fd = open(feed->feed_filename, O_RDONLY);
3824 http_log("Could not open output feed file '%s'\n",
3825 feed->feed_filename);
3829 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3830 feed->feed_size = lseek(fd, 0, SEEK_END);
3831 /* ensure that we do not wrap before the end of file */
3832 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3833 feed->feed_max_size = feed->feed_size;
3839 /* compute the bandwidth used by each stream */
3840 static void compute_bandwidth(void)
3846 for(stream = first_stream; stream != NULL; stream = stream->next) {
3848 for(i=0;i<stream->nb_streams;i++) {
3849 AVStream *st = stream->streams[i];
3850 switch(st->codec->codec_type) {
3851 case AVMEDIA_TYPE_AUDIO:
3852 case AVMEDIA_TYPE_VIDEO:
3853 bandwidth += st->codec->bit_rate;
3859 stream->bandwidth = (bandwidth + 999) / 1000;
3863 /* add a codec and set the default parameters */
3864 static void add_codec(FFStream *stream, AVCodecContext *av)
3868 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3871 /* compute default parameters */
3872 switch(av->codec_type) {
3873 case AVMEDIA_TYPE_AUDIO:
3874 if (av->bit_rate == 0)
3875 av->bit_rate = 64000;
3876 if (av->sample_rate == 0)
3877 av->sample_rate = 22050;
3878 if (av->channels == 0)
3881 case AVMEDIA_TYPE_VIDEO:
3882 if (av->bit_rate == 0)
3883 av->bit_rate = 64000;
3884 if (av->time_base.num == 0){
3885 av->time_base.den = 5;
3886 av->time_base.num = 1;
3888 if (av->width == 0 || av->height == 0) {
3892 /* Bitrate tolerance is less for streaming */
3893 if (av->bit_rate_tolerance == 0)
3894 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3895 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3900 if (av->max_qdiff == 0)
3902 av->qcompress = 0.5;
3905 if (!av->nsse_weight)
3906 av->nsse_weight = 8;
3908 av->frame_skip_cmp = FF_CMP_DCTMAX;
3910 av->me_method = ME_EPZS;
3911 av->rc_buffer_aggressivity = 1.0;
3914 av->rc_eq = av_strdup("tex^qComp");
3915 if (!av->i_quant_factor)
3916 av->i_quant_factor = -0.8;
3917 if (!av->b_quant_factor)
3918 av->b_quant_factor = 1.25;
3919 if (!av->b_quant_offset)
3920 av->b_quant_offset = 1.25;
3921 if (!av->rc_max_rate)
3922 av->rc_max_rate = av->bit_rate * 2;
3924 if (av->rc_max_rate && !av->rc_buffer_size) {
3925 av->rc_buffer_size = av->rc_max_rate;
3934 st = av_mallocz(sizeof(AVStream));
3937 st->codec = avcodec_alloc_context3(NULL);
3938 stream->streams[stream->nb_streams++] = st;
3939 memcpy(st->codec, av, sizeof(AVCodecContext));
3942 static enum AVCodecID opt_codec(const char *name, enum AVMediaType type)
3944 AVCodec *codec = avcodec_find_encoder_by_name(name);
3946 if (!codec || codec->type != type)
3947 return AV_CODEC_ID_NONE;
3951 static int ffserver_opt_default(const char *opt, const char *arg,
3952 AVCodecContext *avctx, int type)
3955 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3957 ret = av_opt_set(avctx, opt, arg, 0);
3961 static int ffserver_opt_preset(const char *arg,
3962 AVCodecContext *avctx, int type,
3963 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3966 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3968 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3970 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3971 codec ? codec->name : NULL))) {
3972 fprintf(stderr, "File for preset '%s' not found\n", arg);
3977 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3978 if(line[0] == '#' && !e)
3980 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3982 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3986 if(!strcmp(tmp, "acodec")){
3987 *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
3988 }else if(!strcmp(tmp, "vcodec")){
3989 *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
3990 }else if(!strcmp(tmp, "scodec")){
3991 /* opt_subtitle_codec(tmp2); */
3992 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3993 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4004 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename, const char *mime_type)
4006 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4009 AVOutputFormat *stream_fmt;
4010 char stream_format_name[64];
4012 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4013 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4022 static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...)
4026 av_log(NULL, log_level, "%s:%d: ", filename, line_num);
4027 av_vlog(NULL, log_level, fmt, vl);
4033 static int parse_ffconfig(const char *filename)
4038 char arg[1024], arg2[1024];
4040 int val, errors, warnings, line_num;
4041 FFStream **last_stream, *stream, *redirect;
4042 FFStream **last_feed, *feed, *s;
4043 AVCodecContext audio_enc, video_enc;
4044 enum AVCodecID audio_id, video_id;
4047 f = fopen(filename, "r");
4049 ret = AVERROR(errno);
4050 av_log(NULL, AV_LOG_ERROR, "Could not open the configuration file '%s'\n", filename);
4054 errors = warnings = 0;
4056 first_stream = NULL;
4057 last_stream = &first_stream;
4059 last_feed = &first_feed;
4063 audio_id = AV_CODEC_ID_NONE;
4064 video_id = AV_CODEC_ID_NONE;
4065 #define ERROR(...) report_config_error(filename, line_num, AV_LOG_ERROR, &errors, __VA_ARGS__)
4066 #define WARNING(...) report_config_error(filename, line_num, AV_LOG_WARNING, &warnings, __VA_ARGS__)
4069 if (fgets(line, sizeof(line), f) == NULL)
4073 while (av_isspace(*p))
4075 if (*p == '\0' || *p == '#')
4078 get_arg(cmd, sizeof(cmd), &p);
4080 if (!av_strcasecmp(cmd, "Port")) {
4081 get_arg(arg, sizeof(arg), &p);
4083 if (val < 1 || val > 65536) {
4084 ERROR("Invalid_port: %s\n", arg);
4086 my_http_addr.sin_port = htons(val);
4087 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4088 get_arg(arg, sizeof(arg), &p);
4089 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4090 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4092 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4093 WARNING("NoDaemon option has no effect, you should remove it\n");
4094 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4095 get_arg(arg, sizeof(arg), &p);
4097 if (val < 1 || val > 65536) {
4098 ERROR("%s:%d: Invalid port: %s\n", arg);
4100 my_rtsp_addr.sin_port = htons(atoi(arg));
4101 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4102 get_arg(arg, sizeof(arg), &p);
4103 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4104 ERROR("Invalid host/IP address: %s\n", arg);
4106 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4107 get_arg(arg, sizeof(arg), &p);
4109 if (val < 1 || val > 65536) {
4110 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4112 nb_max_http_connections = val;
4113 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4114 get_arg(arg, sizeof(arg), &p);
4116 if (val < 1 || val > nb_max_http_connections) {
4117 ERROR("Invalid MaxClients: %s\n", arg);
4119 nb_max_connections = val;
4121 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4123 get_arg(arg, sizeof(arg), &p);
4124 llval = strtoll(arg, NULL, 10);
4125 if (llval < 10 || llval > 10000000) {
4126 ERROR("Invalid MaxBandwidth: %s\n", arg);
4128 max_bandwidth = llval;
4129 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4130 if (!ffserver_debug)
4131 get_arg(logfilename, sizeof(logfilename), &p);
4132 } else if (!av_strcasecmp(cmd, "<Feed")) {
4133 /*********************************************/
4134 /* Feed related options */
4136 if (stream || feed) {
4137 ERROR("Already in a tag\n");
4139 feed = av_mallocz(sizeof(FFStream));
4141 ret = AVERROR(ENOMEM);
4144 get_arg(feed->filename, sizeof(feed->filename), &p);
4145 q = strrchr(feed->filename, '>');
4149 for (s = first_feed; s; s = s->next) {
4150 if (!strcmp(feed->filename, s->filename)) {
4151 ERROR("Feed '%s' already registered\n", s->filename);
4155 feed->fmt = av_guess_format("ffm", NULL, NULL);
4156 /* default feed file */
4157 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4158 "/tmp/%s.ffm", feed->filename);
4159 feed->feed_max_size = 5 * 1024 * 1024;
4161 feed->feed = feed; /* self feeding :-) */
4163 /* add in stream list */
4164 *last_stream = feed;
4165 last_stream = &feed->next;
4166 /* add in feed list */
4168 last_feed = &feed->next_feed;
4170 } else if (!av_strcasecmp(cmd, "Launch")) {
4174 feed->child_argv = av_mallocz(64 * sizeof(char *));
4175 if (!feed->child_argv) {
4176 ret = AVERROR(ENOMEM);
4179 for (i = 0; i < 62; i++) {
4180 get_arg(arg, sizeof(arg), &p);
4184 feed->child_argv[i] = av_strdup(arg);
4185 if (!feed->child_argv[i]) {
4186 ret = AVERROR(ENOMEM);
4191 feed->child_argv[i] =
4192 av_asprintf("http://%s:%d/%s",
4193 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4194 inet_ntoa(my_http_addr.sin_addr), ntohs(my_http_addr.sin_port),
4196 if (!feed->child_argv[i]) {
4197 ret = AVERROR(ENOMEM);
4201 } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
4203 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4204 feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile");
4205 } else if (stream) {
4206 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4208 } else if (!av_strcasecmp(cmd, "Truncate")) {
4210 get_arg(arg, sizeof(arg), &p);
4211 /* assume Truncate is true in case no argument is specified */
4215 WARNING("Truncate N syntax in configuration file is deprecated, "
4216 "use Truncate alone with no arguments\n");
4217 feed->truncate = strtod(arg, NULL);
4220 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4225 get_arg(arg, sizeof(arg), &p);
4227 fsize = strtod(p1, &p1);
4228 switch(av_toupper(*p1)) {
4233 fsize *= 1024 * 1024;
4236 fsize *= 1024 * 1024 * 1024;
4239 feed->feed_max_size = (int64_t)fsize;
4240 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4241 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4244 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4246 ERROR("No corresponding <Feed> for </Feed>\n");
4249 } else if (!av_strcasecmp(cmd, "<Stream")) {
4250 /*********************************************/
4251 /* Stream related options */
4253 if (stream || feed) {
4254 ERROR("Already in a tag\n");
4257 stream = av_mallocz(sizeof(FFStream));
4259 ret = AVERROR(ENOMEM);
4262 get_arg(stream->filename, sizeof(stream->filename), &p);
4263 q = strrchr(stream->filename, '>');
4267 for (s = first_stream; s; s = s->next) {
4268 if (!strcmp(stream->filename, s->filename)) {
4269 ERROR("Stream '%s' already registered\n", s->filename);
4273 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4274 avcodec_get_context_defaults3(&video_enc, NULL);
4275 avcodec_get_context_defaults3(&audio_enc, NULL);
4277 audio_id = AV_CODEC_ID_NONE;
4278 video_id = AV_CODEC_ID_NONE;
4280 audio_id = stream->fmt->audio_codec;
4281 video_id = stream->fmt->video_codec;
4284 *last_stream = stream;
4285 last_stream = &stream->next;
4287 } else if (!av_strcasecmp(cmd, "Feed")) {
4288 get_arg(arg, sizeof(arg), &p);
4293 while (sfeed != NULL) {
4294 if (!strcmp(sfeed->filename, arg))
4296 sfeed = sfeed->next_feed;
4299 ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg, stream->filename);
4301 stream->feed = sfeed;
4303 } else if (!av_strcasecmp(cmd, "Format")) {
4304 get_arg(arg, sizeof(arg), &p);
4306 if (!strcmp(arg, "status")) {
4307 stream->stream_type = STREAM_TYPE_STATUS;
4310 stream->stream_type = STREAM_TYPE_LIVE;
4311 /* JPEG cannot be used here, so use single frame MJPEG */
4312 if (!strcmp(arg, "jpeg"))
4313 strcpy(arg, "mjpeg");
4314 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4316 ERROR("Unknown Format: %s\n", arg);
4320 audio_id = stream->fmt->audio_codec;
4321 video_id = stream->fmt->video_codec;
4324 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4325 get_arg(arg, sizeof(arg), &p);
4327 stream->ifmt = av_find_input_format(arg);
4328 if (!stream->ifmt) {
4329 ERROR("Unknown input format: %s\n", arg);
4332 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4333 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4334 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4336 ERROR("FaviconURL only permitted for status streams\n");
4338 } else if (!av_strcasecmp(cmd, "Author") ||
4339 !av_strcasecmp(cmd, "Comment") ||
4340 !av_strcasecmp(cmd, "Copyright") ||
4341 !av_strcasecmp(cmd, "Title")) {
4342 get_arg(arg, sizeof(arg), &p);
4348 for (i = 0; i < strlen(cmd); i++)
4349 key[i] = av_tolower(cmd[i]);
4351 WARNING("'%s' option in configuration file is deprecated, "
4352 "use 'Metadata %s VALUE' instead\n", cmd, key);
4353 if ((ret = av_dict_set(&stream->metadata, key, arg, 0)) < 0) {
4354 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4355 key, arg, av_err2str(ret));
4358 } else if (!av_strcasecmp(cmd, "Metadata")) {
4359 get_arg(arg, sizeof(arg), &p);
4360 get_arg(arg2, sizeof(arg2), &p);
4363 if ((ret = av_dict_set(&stream->metadata, arg, arg2, 0)) < 0) {
4364 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4365 arg, arg2, av_err2str(ret));
4368 } else if (!av_strcasecmp(cmd, "Preroll")) {
4369 get_arg(arg, sizeof(arg), &p);
4371 stream->prebuffer = atof(arg) * 1000;
4372 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4374 stream->send_on_key = 1;
4375 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4376 get_arg(arg, sizeof(arg), &p);
4377 audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO);
4378 if (audio_id == AV_CODEC_ID_NONE) {
4379 ERROR("Unknown AudioCodec: %s\n", arg);
4381 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4382 get_arg(arg, sizeof(arg), &p);
4383 video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO);
4384 if (video_id == AV_CODEC_ID_NONE) {
4385 ERROR("Unknown VideoCodec: %s\n", arg);
4387 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4388 get_arg(arg, sizeof(arg), &p);
4390 stream->max_time = atof(arg) * 1000;
4391 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4392 get_arg(arg, sizeof(arg), &p);
4394 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4395 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4396 get_arg(arg, sizeof(arg), &p);
4398 audio_enc.channels = atoi(arg);
4399 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4400 get_arg(arg, sizeof(arg), &p);
4402 audio_enc.sample_rate = atoi(arg);
4403 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4405 int minrate, maxrate;
4407 get_arg(arg, sizeof(arg), &p);
4409 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4410 video_enc.rc_min_rate = minrate * 1000;
4411 video_enc.rc_max_rate = maxrate * 1000;
4413 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4416 } else if (!av_strcasecmp(cmd, "Debug")) {
4418 get_arg(arg, sizeof(arg), &p);
4419 video_enc.debug = strtol(arg,0,0);
4421 } else if (!av_strcasecmp(cmd, "Strict")) {
4423 get_arg(arg, sizeof(arg), &p);
4424 video_enc.strict_std_compliance = atoi(arg);
4426 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4428 get_arg(arg, sizeof(arg), &p);
4429 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4431 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4433 get_arg(arg, sizeof(arg), &p);
4434 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4436 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4437 get_arg(arg, sizeof(arg), &p);
4439 video_enc.bit_rate = atoi(arg) * 1000;
4441 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4442 get_arg(arg, sizeof(arg), &p);
4444 ret = av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4446 ERROR("Invalid video size '%s'\n", arg);
4448 if ((video_enc.width % 16) != 0 ||
4449 (video_enc.height % 16) != 0) {
4450 ERROR("Image size must be a multiple of 16\n");
4454 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4455 get_arg(arg, sizeof(arg), &p);
4457 AVRational frame_rate;
4458 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4459 ERROR("Incorrect frame rate: %s\n", arg);
4461 video_enc.time_base.num = frame_rate.den;
4462 video_enc.time_base.den = frame_rate.num;
4465 } else if (!av_strcasecmp(cmd, "PixelFormat")) {
4466 get_arg(arg, sizeof(arg), &p);
4468 video_enc.pix_fmt = av_get_pix_fmt(arg);
4469 if (video_enc.pix_fmt == AV_PIX_FMT_NONE) {
4470 ERROR("Unknown pixel format: %s\n", arg);
4473 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4474 get_arg(arg, sizeof(arg), &p);
4476 video_enc.gop_size = atoi(arg);
4477 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4479 video_enc.gop_size = 1;
4480 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4482 video_enc.mb_decision = FF_MB_DECISION_BITS;
4483 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4485 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4486 video_enc.flags |= CODEC_FLAG_4MV;
4488 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4489 !av_strcasecmp(cmd, "AVOptionAudio")) {
4490 AVCodecContext *avctx;
4492 get_arg(arg, sizeof(arg), &p);
4493 get_arg(arg2, sizeof(arg2), &p);
4494 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4496 type = AV_OPT_FLAG_VIDEO_PARAM;
4499 type = AV_OPT_FLAG_AUDIO_PARAM;
4501 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4502 ERROR("Error setting %s option to %s %s\n", cmd, arg, arg2);
4504 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4505 !av_strcasecmp(cmd, "AVPresetAudio")) {
4506 AVCodecContext *avctx;
4508 get_arg(arg, sizeof(arg), &p);
4509 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4511 video_enc.codec_id = video_id;
4512 type = AV_OPT_FLAG_VIDEO_PARAM;
4515 audio_enc.codec_id = audio_id;
4516 type = AV_OPT_FLAG_AUDIO_PARAM;
4518 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4519 ERROR("AVPreset error: %s\n", arg);
4521 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4522 get_arg(arg, sizeof(arg), &p);
4523 if ((strlen(arg) == 4) && stream)
4524 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4525 } else if (!av_strcasecmp(cmd, "BitExact")) {
4527 video_enc.flags |= CODEC_FLAG_BITEXACT;
4528 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4530 video_enc.dct_algo = FF_DCT_FASTINT;
4531 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4533 video_enc.idct_algo = FF_IDCT_SIMPLE;
4534 } else if (!av_strcasecmp(cmd, "Qscale")) {
4535 get_arg(arg, sizeof(arg), &p);
4537 video_enc.flags |= CODEC_FLAG_QSCALE;
4538 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4540 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4541 get_arg(arg, sizeof(arg), &p);
4543 video_enc.max_qdiff = atoi(arg);
4544 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4545 ERROR("VideoQDiff out of range\n");
4548 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4549 get_arg(arg, sizeof(arg), &p);
4551 video_enc.qmax = atoi(arg);
4552 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4553 ERROR("VideoQMax out of range\n");
4556 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4557 get_arg(arg, sizeof(arg), &p);
4559 video_enc.qmin = atoi(arg);
4560 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4561 ERROR("VideoQMin out of range\n");
4564 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4565 get_arg(arg, sizeof(arg), &p);
4567 video_enc.lumi_masking = atof(arg);
4568 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4569 get_arg(arg, sizeof(arg), &p);
4571 video_enc.dark_masking = atof(arg);
4572 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4573 video_id = AV_CODEC_ID_NONE;
4574 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4575 audio_id = AV_CODEC_ID_NONE;
4576 } else if (!av_strcasecmp(cmd, "ACL")) {
4577 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4578 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4580 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4582 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4583 get_arg(arg, sizeof(arg), &p);
4585 av_freep(&stream->rtsp_option);
4586 stream->rtsp_option = av_strdup(arg);
4588 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4589 get_arg(arg, sizeof(arg), &p);
4591 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4592 ERROR("Invalid host/IP address: %s\n", arg);
4594 stream->is_multicast = 1;
4595 stream->loop = 1; /* default is looping */
4597 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4598 get_arg(arg, sizeof(arg), &p);
4600 stream->multicast_port = atoi(arg);
4601 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4602 get_arg(arg, sizeof(arg), &p);
4604 stream->multicast_ttl = atoi(arg);
4605 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4608 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4610 ERROR("No corresponding <Stream> for </Stream>\n");
4612 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4613 if (audio_id != AV_CODEC_ID_NONE) {
4614 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4615 audio_enc.codec_id = audio_id;
4616 add_codec(stream, &audio_enc);
4618 if (video_id != AV_CODEC_ID_NONE) {
4619 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4620 video_enc.codec_id = video_id;
4621 add_codec(stream, &video_enc);
4626 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4627 /*********************************************/
4629 if (stream || feed || redirect) {
4630 ERROR("Already in a tag\n");
4632 redirect = av_mallocz(sizeof(FFStream));
4634 ret = AVERROR(ENOMEM);
4637 *last_stream = redirect;
4638 last_stream = &redirect->next;
4640 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4641 q = strrchr(redirect->filename, '>');
4644 redirect->stream_type = STREAM_TYPE_REDIRECT;
4646 } else if (!av_strcasecmp(cmd, "URL")) {
4648 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4649 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4651 ERROR("No corresponding <Redirect> for </Redirect>\n");
4653 if (!redirect->feed_filename[0]) {
4654 ERROR("No URL found for <Redirect>\n");
4658 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4659 ERROR("Loadable modules no longer supported\n");
4661 ERROR("Incorrect keyword: '%s'\n", cmd);
4671 return AVERROR(EINVAL);
4676 static void handle_child_exit(int sig)
4681 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4684 for (feed = first_feed; feed; feed = feed->next) {
4685 if (feed->pid == pid) {
4686 int uptime = time(0) - feed->pid_start;
4689 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4692 /* Turn off any more restarts */
4693 feed->child_argv = 0;
4698 need_to_start_children = 1;
4701 static void opt_debug(void)
4704 logfilename[0] = '-';
4707 void show_help_default(const char *opt, const char *arg)
4709 printf("usage: ffserver [options]\n"
4710 "Hyper fast multi format Audio/Video streaming server\n");
4712 show_help_options(options, "Main options:", 0, 0, 0);
4715 static const OptionDef options[] = {
4716 #include "cmdutils_common_opts.h"
4717 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4718 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4719 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4723 int main(int argc, char **argv)
4725 struct sigaction sigact = { { 0 } };
4728 config_filename = av_strdup("/etc/ffserver.conf");
4730 parse_loglevel(argc, argv, options);
4732 avformat_network_init();
4734 show_banner(argc, argv, options);
4736 my_program_name = argv[0];
4738 parse_options(NULL, argc, argv, options, NULL);
4740 unsetenv("http_proxy"); /* Kill the http_proxy */
4742 av_lfg_init(&random_state, av_get_random_seed());
4744 sigact.sa_handler = handle_child_exit;
4745 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4746 sigaction(SIGCHLD, &sigact, 0);
4748 if ((ret = parse_ffconfig(config_filename)) < 0) {
4749 fprintf(stderr, "Error reading configuration file '%s': %s\n",
4750 config_filename, av_err2str(ret));
4753 av_freep(&config_filename);
4755 /* open log file if needed */
4756 if (logfilename[0] != '\0') {
4757 if (!strcmp(logfilename, "-"))
4760 logfile = fopen(logfilename, "a");
4761 av_log_set_callback(http_av_log);
4764 build_file_streams();
4766 build_feed_streams();
4768 compute_bandwidth();
4771 signal(SIGPIPE, SIG_IGN);
4773 if (http_server() < 0) {
4774 http_log("Could not start server\n");