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"
63 #include <sys/ioctl.h>
74 const char program_name[] = "ffserver";
75 const int program_birth_year = 2000;
77 static const OptionDef options[];
80 HTTPSTATE_WAIT_REQUEST,
81 HTTPSTATE_SEND_HEADER,
82 HTTPSTATE_SEND_DATA_HEADER,
83 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
84 HTTPSTATE_SEND_DATA_TRAILER,
85 HTTPSTATE_RECEIVE_DATA,
86 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
89 RTSPSTATE_WAIT_REQUEST,
91 RTSPSTATE_SEND_PACKET,
94 static const char *http_state[] = {
110 #define MAX_STREAMS 20
112 #define IOBUFFER_INIT_SIZE 8192
114 /* timeouts are in ms */
115 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
116 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
118 #define SYNC_TIMEOUT (10 * 1000)
120 typedef struct RTSPActionServerSetup {
122 char transport_option[512];
123 } RTSPActionServerSetup;
126 int64_t count1, count2;
127 int64_t time1, time2;
130 /* context associated with one connection */
131 typedef struct HTTPContext {
132 enum HTTPState state;
133 int fd; /* socket file descriptor */
134 struct sockaddr_in from_addr; /* origin */
135 struct pollfd *poll_entry; /* used when polling */
137 uint8_t *buffer_ptr, *buffer_end;
140 int chunked_encoding;
141 int chunk_size; /* 0 if it needs to be read */
142 struct HTTPContext *next;
143 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
147 /* input format handling */
148 AVFormatContext *fmt_in;
149 int64_t start_time; /* In milliseconds - this wraps fairly often */
150 int64_t first_pts; /* initial pts value */
151 int64_t cur_pts; /* current pts value from the stream in us */
152 int64_t cur_frame_duration; /* duration of the current frame in us */
153 int cur_frame_bytes; /* output frame size, needed to compute
154 the time at which we send each
156 int pts_stream_index; /* stream we choose as clock reference */
157 int64_t cur_clock; /* current clock reference value in us */
158 /* output format handling */
159 struct FFStream *stream;
160 /* -1 is invalid stream */
161 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
162 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
164 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
165 int last_packet_sent; /* true if last data packet was sent */
167 DataRateData datarate;
174 int is_packetized; /* if true, the stream is packetized */
175 int packet_stream_index; /* current stream for output in state machine */
177 /* RTSP state specific */
178 uint8_t *pb_buffer; /* XXX: use that in all the code */
180 int seq; /* RTSP sequence number */
182 /* RTP state specific */
183 enum RTSPLowerTransport rtp_protocol;
184 char session_id[32]; /* session id */
185 AVFormatContext *rtp_ctx[MAX_STREAMS];
187 /* RTP/UDP specific */
188 URLContext *rtp_handles[MAX_STREAMS];
190 /* RTP/TCP specific */
191 struct HTTPContext *rtsp_c;
192 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
195 /* each generated stream is described here */
199 STREAM_TYPE_REDIRECT,
202 enum IPAddressAction {
207 typedef struct IPAddressACL {
208 struct IPAddressACL *next;
209 enum IPAddressAction action;
210 /* These are in host order */
211 struct in_addr first;
215 /* description of each stream of the ffserver.conf file */
216 typedef struct FFStream {
217 enum StreamType stream_type;
218 char filename[1024]; /* stream filename */
219 struct FFStream *feed; /* feed we are using (can be null if
221 AVDictionary *in_opts; /* input parameters */
222 AVDictionary *metadata; /* metadata to set on the stream */
223 AVInputFormat *ifmt; /* if non NULL, force input format */
226 char dynamic_acl[1024];
228 int prebuffer; /* Number of milliseconds early to start */
229 int64_t max_time; /* Number of milliseconds to run */
231 AVStream *streams[MAX_STREAMS];
232 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
233 char feed_filename[1024]; /* file name of the feed storage, or
234 input file name for a stream */
235 pid_t pid; /* Of ffmpeg process */
236 time_t pid_start; /* Of ffmpeg process */
238 struct FFStream *next;
239 unsigned bandwidth; /* bandwidth, in kbits/s */
242 /* multicast specific */
244 struct in_addr multicast_ip;
245 int multicast_port; /* first port used for multicast */
247 int loop; /* if true, send the stream in loops (only meaningful if file) */
250 int feed_opened; /* true if someone is writing to the feed */
251 int is_feed; /* true if it is a feed */
252 int readonly; /* True if writing is prohibited to the file */
253 int truncate; /* True if feeder connection truncate the feed file */
255 int64_t bytes_served;
256 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
257 int64_t feed_write_index; /* current write position in feed (it wraps around) */
258 int64_t feed_size; /* current size of feed */
259 struct FFStream *next_feed;
262 typedef struct FeedData {
263 long long data_count;
264 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
267 static struct sockaddr_in my_http_addr;
268 static struct sockaddr_in my_rtsp_addr;
270 static char logfilename[1024];
271 static HTTPContext *first_http_ctx;
272 static FFStream *first_feed; /* contains only feeds */
273 static FFStream *first_stream; /* contains all streams, including feeds */
275 static void new_connection(int server_fd, int is_rtsp);
276 static void close_connection(HTTPContext *c);
279 static int handle_connection(HTTPContext *c);
280 static int http_parse_request(HTTPContext *c);
281 static int http_send_data(HTTPContext *c);
282 static void compute_status(HTTPContext *c);
283 static int open_input_stream(HTTPContext *c, const char *info);
284 static int http_start_receive_data(HTTPContext *c);
285 static int http_receive_data(HTTPContext *c);
288 static int rtsp_parse_request(HTTPContext *c);
289 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
290 static void rtsp_cmd_options(HTTPContext *c, const char *url);
291 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
292 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
293 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only);
296 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
297 struct in_addr my_ip);
300 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
301 FFStream *stream, const char *session_id,
302 enum RTSPLowerTransport rtp_protocol);
303 static int rtp_new_av_stream(HTTPContext *c,
304 int stream_index, struct sockaddr_in *dest_addr,
305 HTTPContext *rtsp_c);
307 static const char *my_program_name;
309 static const char *config_filename;
311 static int ffserver_debug;
312 static int no_launch;
313 static int need_to_start_children;
315 /* maximum number of simultaneous HTTP connections */
316 static unsigned int nb_max_http_connections = 2000;
317 static unsigned int nb_max_connections = 5;
318 static unsigned int nb_connections;
320 static uint64_t max_bandwidth = 1000;
321 static uint64_t current_bandwidth;
323 static int64_t cur_time; // Making this global saves on passing it around everywhere
325 static AVLFG random_state;
327 static FILE *logfile = NULL;
329 static void htmlstrip(char *s) {
331 s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
337 static int64_t ffm_read_write_index(int fd)
341 if (lseek(fd, 8, SEEK_SET) < 0)
343 if (read(fd, buf, 8) != 8)
348 static int ffm_write_write_index(int fd, int64_t pos)
354 buf[i] = (pos >> (56 - i * 8)) & 0xff;
355 if (lseek(fd, 8, SEEK_SET) < 0)
357 if (write(fd, buf, 8) != 8)
362 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
365 FFMContext *ffm = s->priv_data;
366 ffm->write_index = pos;
367 ffm->file_size = file_size;
370 /* FIXME: make ffserver work with IPv6 */
371 /* resolve host with also IP address parsing */
372 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
375 if (!ff_inet_aton(hostname, sin_addr)) {
377 struct addrinfo *ai, *cur;
378 struct addrinfo hints = { 0 };
379 hints.ai_family = AF_INET;
380 if (getaddrinfo(hostname, NULL, &hints, &ai))
382 /* getaddrinfo returns a linked list of addrinfo structs.
383 * Even if we set ai_family = AF_INET above, make sure
384 * that the returned one actually is of the correct type. */
385 for (cur = ai; cur; cur = cur->ai_next) {
386 if (cur->ai_family == AF_INET) {
387 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
396 hp = gethostbyname(hostname);
399 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
405 static char *ctime1(char *buf2, int buf_size)
412 av_strlcpy(buf2, p, buf_size);
413 p = buf2 + strlen(p) - 1;
419 static void http_vlog(const char *fmt, va_list vargs)
421 static int print_prefix = 1;
425 ctime1(buf, sizeof(buf));
426 fprintf(logfile, "%s ", buf);
428 print_prefix = strstr(fmt, "\n") != NULL;
429 vfprintf(logfile, fmt, vargs);
435 __attribute__ ((format (printf, 1, 2)))
437 static void http_log(const char *fmt, ...)
440 va_start(vargs, fmt);
441 http_vlog(fmt, vargs);
445 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
447 static int print_prefix = 1;
448 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
449 if (level > av_log_get_level())
451 if (print_prefix && avc)
452 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
453 print_prefix = strstr(fmt, "\n") != NULL;
454 http_vlog(fmt, vargs);
457 static void log_connection(HTTPContext *c)
462 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
463 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
464 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
467 static void update_datarate(DataRateData *drd, int64_t count)
469 if (!drd->time1 && !drd->count1) {
470 drd->time1 = drd->time2 = cur_time;
471 drd->count1 = drd->count2 = count;
472 } else if (cur_time - drd->time2 > 5000) {
473 drd->time1 = drd->time2;
474 drd->count1 = drd->count2;
475 drd->time2 = cur_time;
480 /* In bytes per second */
481 static int compute_datarate(DataRateData *drd, int64_t count)
483 if (cur_time == drd->time1)
486 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
490 static void start_children(FFStream *feed)
495 for (; feed; feed = feed->next) {
496 if (feed->child_argv && !feed->pid) {
497 feed->pid_start = time(0);
502 http_log("Unable to create children\n");
511 /* replace "ffserver" with "ffmpeg" in the path of current
512 * program. Ignore user provided path */
513 av_strlcpy(pathname, my_program_name, sizeof(pathname));
514 slash = strrchr(pathname, '/');
519 strcpy(slash, "ffmpeg");
521 http_log("Launch command line: ");
522 http_log("%s ", pathname);
523 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
524 http_log("%s ", feed->child_argv[i]);
527 for (i = 3; i < 256; i++)
530 if (!ffserver_debug) {
531 if (!freopen("/dev/null", "r", stdin))
532 http_log("failed to redirect STDIN to /dev/null\n;");
533 if (!freopen("/dev/null", "w", stdout))
534 http_log("failed to redirect STDOUT to /dev/null\n;");
535 if (!freopen("/dev/null", "w", stderr))
536 http_log("failed to redirect STDERR to /dev/null\n;");
539 signal(SIGPIPE, SIG_DFL);
541 execvp(pathname, feed->child_argv);
549 /* open a listening socket */
550 static int socket_open_listen(struct sockaddr_in *my_addr)
554 server_fd = socket(AF_INET,SOCK_STREAM,0);
561 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)))
562 av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n");
564 my_addr->sin_family = AF_INET;
565 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
567 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
569 closesocket(server_fd);
573 if (listen (server_fd, 5) < 0) {
575 closesocket(server_fd);
579 if (ff_socket_nonblock(server_fd, 1) < 0)
580 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
585 /* start all multicast streams */
586 static void start_multicast(void)
591 struct sockaddr_in dest_addr = {0};
592 int default_port, stream_index;
595 for(stream = first_stream; stream != NULL; stream = stream->next) {
596 if (stream->is_multicast) {
597 unsigned random0 = av_lfg_get(&random_state);
598 unsigned random1 = av_lfg_get(&random_state);
599 /* open the RTP connection */
600 snprintf(session_id, sizeof(session_id), "%08x%08x",
603 /* choose a port if none given */
604 if (stream->multicast_port == 0) {
605 stream->multicast_port = default_port;
609 dest_addr.sin_family = AF_INET;
610 dest_addr.sin_addr = stream->multicast_ip;
611 dest_addr.sin_port = htons(stream->multicast_port);
613 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
614 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
618 if (open_input_stream(rtp_c, "") < 0) {
619 http_log("Could not open input stream for stream '%s'\n",
624 /* open each RTP stream */
625 for(stream_index = 0; stream_index < stream->nb_streams;
627 dest_addr.sin_port = htons(stream->multicast_port +
629 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
630 http_log("Could not open output stream '%s/streamid=%d'\n",
631 stream->filename, stream_index);
636 rtp_c->state = HTTPSTATE_SEND_DATA;
641 /* main loop of the HTTP server */
642 static int http_server(void)
644 int server_fd = 0, rtsp_server_fd = 0;
646 struct pollfd *poll_table, *poll_entry;
647 HTTPContext *c, *c_next;
649 if(!(poll_table = av_mallocz_array(nb_max_http_connections + 2, sizeof(*poll_table)))) {
650 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
654 if (my_http_addr.sin_port) {
655 server_fd = socket_open_listen(&my_http_addr);
662 if (my_rtsp_addr.sin_port) {
663 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
664 if (rtsp_server_fd < 0) {
666 closesocket(server_fd);
671 if (!rtsp_server_fd && !server_fd) {
672 http_log("HTTP and RTSP disabled.\n");
677 http_log("FFserver started.\n");
679 start_children(first_feed);
684 poll_entry = poll_table;
686 poll_entry->fd = server_fd;
687 poll_entry->events = POLLIN;
690 if (rtsp_server_fd) {
691 poll_entry->fd = rtsp_server_fd;
692 poll_entry->events = POLLIN;
696 /* wait for events on each HTTP handle */
703 case HTTPSTATE_SEND_HEADER:
704 case RTSPSTATE_SEND_REPLY:
705 case RTSPSTATE_SEND_PACKET:
706 c->poll_entry = poll_entry;
708 poll_entry->events = POLLOUT;
711 case HTTPSTATE_SEND_DATA_HEADER:
712 case HTTPSTATE_SEND_DATA:
713 case HTTPSTATE_SEND_DATA_TRAILER:
714 if (!c->is_packetized) {
715 /* for TCP, we output as much as we can
716 * (may need to put a limit) */
717 c->poll_entry = poll_entry;
719 poll_entry->events = POLLOUT;
722 /* when ffserver is doing the timing, we work by
723 looking at which packet needs to be sent every
725 /* one tick wait XXX: 10 ms assumed */
730 case HTTPSTATE_WAIT_REQUEST:
731 case HTTPSTATE_RECEIVE_DATA:
732 case HTTPSTATE_WAIT_FEED:
733 case RTSPSTATE_WAIT_REQUEST:
734 /* need to catch errors */
735 c->poll_entry = poll_entry;
737 poll_entry->events = POLLIN;/* Maybe this will work */
741 c->poll_entry = NULL;
747 /* wait for an event on one connection. We poll at least every
748 second to handle timeouts */
750 ret = poll(poll_table, poll_entry - poll_table, delay);
751 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
752 ff_neterrno() != AVERROR(EINTR)) {
758 cur_time = av_gettime() / 1000;
760 if (need_to_start_children) {
761 need_to_start_children = 0;
762 start_children(first_feed);
765 /* now handle the events */
766 for(c = first_http_ctx; c != NULL; c = c_next) {
768 if (handle_connection(c) < 0) {
770 /* close and free the connection */
775 poll_entry = poll_table;
777 /* new HTTP connection request ? */
778 if (poll_entry->revents & POLLIN)
779 new_connection(server_fd, 0);
782 if (rtsp_server_fd) {
783 /* new RTSP connection request ? */
784 if (poll_entry->revents & POLLIN)
785 new_connection(rtsp_server_fd, 1);
790 /* start waiting for a new HTTP/RTSP request */
791 static void start_wait_request(HTTPContext *c, int is_rtsp)
793 c->buffer_ptr = c->buffer;
794 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
797 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
798 c->state = RTSPSTATE_WAIT_REQUEST;
800 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
801 c->state = HTTPSTATE_WAIT_REQUEST;
805 static void http_send_too_busy_reply(int fd)
808 int len = snprintf(buffer, sizeof(buffer),
809 "HTTP/1.0 503 Server too busy\r\n"
810 "Content-type: text/html\r\n"
812 "<html><head><title>Too busy</title></head><body>\r\n"
813 "<p>The server is too busy to serve your request at this time.</p>\r\n"
814 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
815 "</body></html>\r\n",
816 nb_connections, nb_max_connections);
817 av_assert0(len < sizeof(buffer));
818 if (send(fd, buffer, len, 0) < len)
819 av_log(NULL, AV_LOG_WARNING, "Could not send too-busy reply, send() failed\n");
823 static void new_connection(int server_fd, int is_rtsp)
825 struct sockaddr_in from_addr;
828 HTTPContext *c = NULL;
830 len = sizeof(from_addr);
831 fd = accept(server_fd, (struct sockaddr *)&from_addr,
834 http_log("error during accept %s\n", strerror(errno));
837 if (ff_socket_nonblock(fd, 1) < 0)
838 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
840 if (nb_connections >= nb_max_connections) {
841 http_send_too_busy_reply(fd);
845 /* add a new connection */
846 c = av_mallocz(sizeof(HTTPContext));
851 c->poll_entry = NULL;
852 c->from_addr = from_addr;
853 c->buffer_size = IOBUFFER_INIT_SIZE;
854 c->buffer = av_malloc(c->buffer_size);
858 c->next = first_http_ctx;
862 start_wait_request(c, is_rtsp);
874 static void close_connection(HTTPContext *c)
876 HTTPContext **cp, *c1;
878 AVFormatContext *ctx;
882 /* remove connection from list */
883 cp = &first_http_ctx;
884 while ((*cp) != NULL) {
892 /* remove references, if any (XXX: do it faster) */
893 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
898 /* remove connection associated resources */
902 /* close each frame parser */
903 for(i=0;i<c->fmt_in->nb_streams;i++) {
904 st = c->fmt_in->streams[i];
905 if (st->codec->codec)
906 avcodec_close(st->codec);
908 avformat_close_input(&c->fmt_in);
911 /* free RTP output streams if any */
914 nb_streams = c->stream->nb_streams;
916 for(i=0;i<nb_streams;i++) {
919 av_write_trailer(ctx);
920 av_dict_free(&ctx->metadata);
921 av_free(ctx->streams[0]);
924 h = c->rtp_handles[i];
931 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
934 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
935 av_write_trailer(ctx);
936 av_freep(&c->pb_buffer);
937 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
942 for(i=0; i<ctx->nb_streams; i++)
943 av_free(ctx->streams[i]);
944 av_freep(&ctx->streams);
945 av_freep(&ctx->priv_data);
947 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
948 current_bandwidth -= c->stream->bandwidth;
950 /* signal that there is no feed if we are the feeder socket */
951 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
952 c->stream->feed_opened = 0;
956 av_freep(&c->pb_buffer);
957 av_freep(&c->packet_buffer);
963 static int handle_connection(HTTPContext *c)
968 case HTTPSTATE_WAIT_REQUEST:
969 case RTSPSTATE_WAIT_REQUEST:
971 if ((c->timeout - cur_time) < 0)
973 if (c->poll_entry->revents & (POLLERR | POLLHUP))
976 /* no need to read if no events */
977 if (!(c->poll_entry->revents & POLLIN))
981 len = recv(c->fd, c->buffer_ptr, 1, 0);
983 if (ff_neterrno() != AVERROR(EAGAIN) &&
984 ff_neterrno() != AVERROR(EINTR))
986 } else if (len == 0) {
989 /* search for end of request. */
991 c->buffer_ptr += len;
993 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
994 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
995 /* request found : parse it and reply */
996 if (c->state == HTTPSTATE_WAIT_REQUEST) {
997 ret = http_parse_request(c);
999 ret = rtsp_parse_request(c);
1003 } else if (ptr >= c->buffer_end) {
1004 /* request too long: cannot do anything */
1006 } else goto read_loop;
1010 case HTTPSTATE_SEND_HEADER:
1011 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1014 /* no need to write if no events */
1015 if (!(c->poll_entry->revents & POLLOUT))
1017 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1019 if (ff_neterrno() != AVERROR(EAGAIN) &&
1020 ff_neterrno() != AVERROR(EINTR)) {
1021 goto close_connection;
1024 c->buffer_ptr += len;
1026 c->stream->bytes_served += len;
1027 c->data_count += len;
1028 if (c->buffer_ptr >= c->buffer_end) {
1029 av_freep(&c->pb_buffer);
1030 /* if error, exit */
1033 /* all the buffer was sent : synchronize to the incoming
1035 c->state = HTTPSTATE_SEND_DATA_HEADER;
1036 c->buffer_ptr = c->buffer_end = c->buffer;
1041 case HTTPSTATE_SEND_DATA:
1042 case HTTPSTATE_SEND_DATA_HEADER:
1043 case HTTPSTATE_SEND_DATA_TRAILER:
1044 /* for packetized output, we consider we can always write (the
1045 input streams set the speed). It may be better to verify
1046 that we do not rely too much on the kernel queues */
1047 if (!c->is_packetized) {
1048 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1051 /* no need to read if no events */
1052 if (!(c->poll_entry->revents & POLLOUT))
1055 if (http_send_data(c) < 0)
1057 /* close connection if trailer sent */
1058 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1061 case HTTPSTATE_RECEIVE_DATA:
1062 /* no need to read if no events */
1063 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1065 if (!(c->poll_entry->revents & POLLIN))
1067 if (http_receive_data(c) < 0)
1070 case HTTPSTATE_WAIT_FEED:
1071 /* no need to read if no events */
1072 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1075 /* nothing to do, we'll be waken up by incoming feed packets */
1078 case RTSPSTATE_SEND_REPLY:
1079 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1080 goto close_connection;
1081 /* no need to write if no events */
1082 if (!(c->poll_entry->revents & POLLOUT))
1084 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1086 if (ff_neterrno() != AVERROR(EAGAIN) &&
1087 ff_neterrno() != AVERROR(EINTR)) {
1088 goto close_connection;
1091 c->buffer_ptr += len;
1092 c->data_count += len;
1093 if (c->buffer_ptr >= c->buffer_end) {
1094 /* all the buffer was sent : wait for a new request */
1095 av_freep(&c->pb_buffer);
1096 start_wait_request(c, 1);
1100 case RTSPSTATE_SEND_PACKET:
1101 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1102 av_freep(&c->packet_buffer);
1105 /* no need to write if no events */
1106 if (!(c->poll_entry->revents & POLLOUT))
1108 len = send(c->fd, c->packet_buffer_ptr,
1109 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1111 if (ff_neterrno() != AVERROR(EAGAIN) &&
1112 ff_neterrno() != AVERROR(EINTR)) {
1113 /* error : close connection */
1114 av_freep(&c->packet_buffer);
1118 c->packet_buffer_ptr += len;
1119 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1120 /* all the buffer was sent : wait for a new request */
1121 av_freep(&c->packet_buffer);
1122 c->state = RTSPSTATE_WAIT_REQUEST;
1126 case HTTPSTATE_READY:
1135 av_freep(&c->pb_buffer);
1139 static int extract_rates(char *rates, int ratelen, const char *request)
1143 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1144 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1145 const char *q = p + 7;
1147 while (*q && *q != '\n' && av_isspace(*q))
1150 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1156 memset(rates, 0xff, ratelen);
1159 while (*q && *q != '\n' && *q != ':')
1162 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1166 if (stream_no < ratelen && stream_no >= 0)
1167 rates[stream_no] = rate_no;
1169 while (*q && *q != '\n' && !av_isspace(*q))
1176 p = strchr(p, '\n');
1186 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1189 int best_bitrate = 100000000;
1192 for (i = 0; i < feed->nb_streams; i++) {
1193 AVCodecContext *feed_codec = feed->streams[i]->codec;
1195 if (feed_codec->codec_id != codec->codec_id ||
1196 feed_codec->sample_rate != codec->sample_rate ||
1197 feed_codec->width != codec->width ||
1198 feed_codec->height != codec->height)
1201 /* Potential stream */
1203 /* We want the fastest stream less than bit_rate, or the slowest
1204 * faster than bit_rate
1207 if (feed_codec->bit_rate <= bit_rate) {
1208 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1209 best_bitrate = feed_codec->bit_rate;
1213 if (feed_codec->bit_rate < best_bitrate) {
1214 best_bitrate = feed_codec->bit_rate;
1223 static int modify_current_stream(HTTPContext *c, char *rates)
1226 FFStream *req = c->stream;
1227 int action_required = 0;
1229 /* Not much we can do for a feed */
1233 for (i = 0; i < req->nb_streams; i++) {
1234 AVCodecContext *codec = req->streams[i]->codec;
1238 c->switch_feed_streams[i] = req->feed_streams[i];
1241 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1244 /* Wants off or slow */
1245 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1247 /* This doesn't work well when it turns off the only stream! */
1248 c->switch_feed_streams[i] = -2;
1249 c->feed_streams[i] = -2;
1254 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1255 action_required = 1;
1258 return action_required;
1261 /* XXX: factorize in utils.c ? */
1262 /* XXX: take care with different space meaning */
1263 static void skip_spaces(const char **pp)
1267 while (*p == ' ' || *p == '\t')
1272 static void get_word(char *buf, int buf_size, const char **pp)
1280 while (!av_isspace(*p) && *p != '\0') {
1281 if ((q - buf) < buf_size - 1)
1290 static void get_arg(char *buf, int buf_size, const char **pp)
1297 while (av_isspace(*p)) p++;
1300 if (*p == '\"' || *p == '\'')
1312 if ((q - buf) < buf_size - 1)
1317 if (quote && *p == quote)
1322 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1323 const char *p, const char *filename, int line_num)
1329 get_arg(arg, sizeof(arg), &p);
1330 if (av_strcasecmp(arg, "allow") == 0)
1331 acl.action = IP_ALLOW;
1332 else if (av_strcasecmp(arg, "deny") == 0)
1333 acl.action = IP_DENY;
1335 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1336 filename, line_num, arg);
1340 get_arg(arg, sizeof(arg), &p);
1342 if (resolve_host(&acl.first, arg) != 0) {
1343 fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1344 filename, line_num, arg);
1347 acl.last = acl.first;
1349 get_arg(arg, sizeof(arg), &p);
1352 if (resolve_host(&acl.last, arg) != 0) {
1353 fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1354 filename, line_num, arg);
1360 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1361 IPAddressACL **naclp = 0;
1367 naclp = &stream->acl;
1373 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1374 filename, line_num);
1380 naclp = &(*naclp)->next;
1389 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1394 IPAddressACL *acl = NULL;
1398 f = fopen(stream->dynamic_acl, "r");
1400 perror(stream->dynamic_acl);
1404 acl = av_mallocz(sizeof(IPAddressACL));
1408 if (fgets(line, sizeof(line), f) == NULL)
1412 while (av_isspace(*p))
1414 if (*p == '\0' || *p == '#')
1416 get_arg(cmd, sizeof(cmd), &p);
1418 if (!av_strcasecmp(cmd, "ACL"))
1419 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1426 static void free_acl_list(IPAddressACL *in_acl)
1428 IPAddressACL *pacl,*pacl2;
1438 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1440 enum IPAddressAction last_action = IP_DENY;
1442 struct in_addr *src = &c->from_addr.sin_addr;
1443 unsigned long src_addr = src->s_addr;
1445 for (acl = in_acl; acl; acl = acl->next) {
1446 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1447 return (acl->action == IP_ALLOW) ? 1 : 0;
1448 last_action = acl->action;
1451 /* Nothing matched, so return not the last action */
1452 return (last_action == IP_DENY) ? 1 : 0;
1455 static int validate_acl(FFStream *stream, HTTPContext *c)
1461 /* if stream->acl is null validate_acl_list will return 1 */
1462 ret = validate_acl_list(stream->acl, c);
1464 if (stream->dynamic_acl[0]) {
1465 acl = parse_dynamic_acl(stream, c);
1467 ret = validate_acl_list(acl, c);
1475 /* compute the real filename of a file by matching it without its
1476 extensions to all the stream's filenames */
1477 static void compute_real_filename(char *filename, int max_size)
1484 /* compute filename by matching without the file extensions */
1485 av_strlcpy(file1, filename, sizeof(file1));
1486 p = strrchr(file1, '.');
1489 for(stream = first_stream; stream != NULL; stream = stream->next) {
1490 av_strlcpy(file2, stream->filename, sizeof(file2));
1491 p = strrchr(file2, '.');
1494 if (!strcmp(file1, file2)) {
1495 av_strlcpy(filename, stream->filename, max_size);
1510 /* parse HTTP request and prepare header */
1511 static int http_parse_request(HTTPContext *c)
1515 enum RedirType redir_type;
1517 char info[1024], filename[1024];
1521 const char *mime_type;
1525 const char *useragent = 0;
1528 get_word(cmd, sizeof(cmd), &p);
1529 av_strlcpy(c->method, cmd, sizeof(c->method));
1531 if (!strcmp(cmd, "GET"))
1533 else if (!strcmp(cmd, "POST"))
1538 get_word(url, sizeof(url), &p);
1539 av_strlcpy(c->url, url, sizeof(c->url));
1541 get_word(protocol, sizeof(protocol), (const char **)&p);
1542 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1545 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1548 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1550 /* find the filename and the optional info string in the request */
1551 p1 = strchr(url, '?');
1553 av_strlcpy(info, p1, sizeof(info));
1558 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1560 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1561 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1563 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1567 p = strchr(p, '\n');
1574 redir_type = REDIR_NONE;
1575 if (av_match_ext(filename, "asx")) {
1576 redir_type = REDIR_ASX;
1577 filename[strlen(filename)-1] = 'f';
1578 } else if (av_match_ext(filename, "asf") &&
1579 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1580 /* if this isn't WMP or lookalike, return the redirector file */
1581 redir_type = REDIR_ASF;
1582 } else if (av_match_ext(filename, "rpm,ram")) {
1583 redir_type = REDIR_RAM;
1584 strcpy(filename + strlen(filename)-2, "m");
1585 } else if (av_match_ext(filename, "rtsp")) {
1586 redir_type = REDIR_RTSP;
1587 compute_real_filename(filename, sizeof(filename) - 1);
1588 } else if (av_match_ext(filename, "sdp")) {
1589 redir_type = REDIR_SDP;
1590 compute_real_filename(filename, sizeof(filename) - 1);
1593 // "redirect" / request to index.html
1594 if (!strlen(filename))
1595 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1597 stream = first_stream;
1598 while (stream != NULL) {
1599 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1601 stream = stream->next;
1603 if (stream == NULL) {
1604 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1605 http_log("File '%s' not found\n", url);
1610 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1611 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1613 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1614 c->http_error = 301;
1616 snprintf(q, c->buffer_size,
1617 "HTTP/1.0 301 Moved\r\n"
1619 "Content-type: text/html\r\n"
1621 "<html><head><title>Moved</title></head><body>\r\n"
1622 "You should be <a href=\"%s\">redirected</a>.\r\n"
1623 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1625 /* prepare output buffer */
1626 c->buffer_ptr = c->buffer;
1628 c->state = HTTPSTATE_SEND_HEADER;
1632 /* If this is WMP, get the rate information */
1633 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1634 if (modify_current_stream(c, ratebuf)) {
1635 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1636 if (c->switch_feed_streams[i] >= 0)
1637 c->switch_feed_streams[i] = -1;
1642 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1643 current_bandwidth += stream->bandwidth;
1645 /* If already streaming this feed, do not let start another feeder. */
1646 if (stream->feed_opened) {
1647 snprintf(msg, sizeof(msg), "This feed is already being received.");
1648 http_log("Feed '%s' already being received\n", stream->feed_filename);
1652 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1653 c->http_error = 503;
1655 snprintf(q, c->buffer_size,
1656 "HTTP/1.0 503 Server too busy\r\n"
1657 "Content-type: text/html\r\n"
1659 "<html><head><title>Too busy</title></head><body>\r\n"
1660 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1661 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1662 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1663 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1665 /* prepare output buffer */
1666 c->buffer_ptr = c->buffer;
1668 c->state = HTTPSTATE_SEND_HEADER;
1672 if (redir_type != REDIR_NONE) {
1673 const char *hostinfo = 0;
1675 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1676 if (av_strncasecmp(p, "Host:", 5) == 0) {
1680 p = strchr(p, '\n');
1691 while (av_isspace(*hostinfo))
1694 eoh = strchr(hostinfo, '\n');
1696 if (eoh[-1] == '\r')
1699 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1700 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1701 hostbuf[eoh - hostinfo] = 0;
1703 c->http_error = 200;
1705 switch(redir_type) {
1707 snprintf(q, c->buffer_size,
1708 "HTTP/1.0 200 ASX Follows\r\n"
1709 "Content-type: video/x-ms-asf\r\n"
1711 "<ASX Version=\"3\">\r\n"
1712 //"<!-- Autogenerated by ffserver -->\r\n"
1713 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1714 "</ASX>\r\n", hostbuf, filename, info);
1718 snprintf(q, c->buffer_size,
1719 "HTTP/1.0 200 RAM Follows\r\n"
1720 "Content-type: audio/x-pn-realaudio\r\n"
1722 "# Autogenerated by ffserver\r\n"
1723 "http://%s/%s%s\r\n", hostbuf, filename, info);
1727 snprintf(q, c->buffer_size,
1728 "HTTP/1.0 200 ASF Redirect follows\r\n"
1729 "Content-type: video/x-ms-asf\r\n"
1732 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1737 char hostname[256], *p;
1738 /* extract only hostname */
1739 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1740 p = strrchr(hostname, ':');
1743 snprintf(q, c->buffer_size,
1744 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1745 /* XXX: incorrect MIME type ? */
1746 "Content-type: application/x-rtsp\r\n"
1748 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1757 struct sockaddr_in my_addr;
1759 snprintf(q, c->buffer_size,
1760 "HTTP/1.0 200 OK\r\n"
1761 "Content-type: application/sdp\r\n"
1765 len = sizeof(my_addr);
1767 /* XXX: Should probably fail? */
1768 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1769 http_log("getsockname() failed\n");
1771 /* XXX: should use a dynamic buffer */
1772 sdp_data_size = prepare_sdp_description(stream,
1775 if (sdp_data_size > 0) {
1776 memcpy(q, sdp_data, sdp_data_size);
1788 /* prepare output buffer */
1789 c->buffer_ptr = c->buffer;
1791 c->state = HTTPSTATE_SEND_HEADER;
1797 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1801 stream->conns_served++;
1803 /* XXX: add there authenticate and IP match */
1806 /* if post, it means a feed is being sent */
1807 if (!stream->is_feed) {
1808 /* However it might be a status report from WMP! Let us log the
1809 * data as it might come handy one day. */
1810 const char *logline = 0;
1813 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1814 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1818 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1819 client_id = strtol(p + 18, 0, 10);
1820 p = strchr(p, '\n');
1828 char *eol = strchr(logline, '\n');
1833 if (eol[-1] == '\r')
1835 http_log("%.*s\n", (int) (eol - logline), logline);
1836 c->suppress_log = 1;
1841 http_log("\nGot request:\n%s\n", c->buffer);
1844 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1847 /* Now we have to find the client_id */
1848 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1849 if (wmpc->wmp_client_id == client_id)
1853 if (wmpc && modify_current_stream(wmpc, ratebuf))
1854 wmpc->switch_pending = 1;
1857 snprintf(msg, sizeof(msg), "POST command not handled");
1861 if (http_start_receive_data(c) < 0) {
1862 snprintf(msg, sizeof(msg), "could not open feed");
1866 c->state = HTTPSTATE_RECEIVE_DATA;
1871 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1872 http_log("\nGot request:\n%s\n", c->buffer);
1875 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1878 /* open input stream */
1879 if (open_input_stream(c, info) < 0) {
1880 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1884 /* prepare HTTP header */
1886 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1887 mime_type = c->stream->fmt->mime_type;
1889 mime_type = "application/x-octet-stream";
1890 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1892 /* for asf, we need extra headers */
1893 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1894 /* Need to allocate a client id */
1896 c->wmp_client_id = av_lfg_get(&random_state);
1898 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);
1900 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1901 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1902 q = c->buffer + strlen(c->buffer);
1904 /* prepare output buffer */
1906 c->buffer_ptr = c->buffer;
1908 c->state = HTTPSTATE_SEND_HEADER;
1911 c->http_error = 404;
1914 snprintf(q, c->buffer_size,
1915 "HTTP/1.0 404 Not Found\r\n"
1916 "Content-type: text/html\r\n"
1919 "<head><title>404 Not Found</title></head>\n"
1923 /* prepare output buffer */
1924 c->buffer_ptr = c->buffer;
1926 c->state = HTTPSTATE_SEND_HEADER;
1930 c->http_error = 200; /* horrible : we use this value to avoid
1931 going to the send data state */
1932 c->state = HTTPSTATE_SEND_HEADER;
1936 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1938 static const char suffix[] = " kMGTP";
1941 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1943 avio_printf(pb, "%"PRId64"%c", count, *s);
1946 static void compute_status(HTTPContext *c)
1955 if (avio_open_dyn_buf(&pb) < 0) {
1956 /* XXX: return an error ? */
1957 c->buffer_ptr = c->buffer;
1958 c->buffer_end = c->buffer;
1962 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1963 avio_printf(pb, "Content-type: text/html\r\n");
1964 avio_printf(pb, "Pragma: no-cache\r\n");
1965 avio_printf(pb, "\r\n");
1967 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1968 if (c->stream->feed_filename[0])
1969 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1970 avio_printf(pb, "</head>\n<body>");
1971 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1973 avio_printf(pb, "<h2>Available Streams</h2>\n");
1974 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1975 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");
1976 stream = first_stream;
1977 while (stream != NULL) {
1978 char sfilename[1024];
1981 if (stream->feed != stream) {
1982 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1983 eosf = sfilename + strlen(sfilename);
1984 if (eosf - sfilename >= 4) {
1985 if (strcmp(eosf - 4, ".asf") == 0)
1986 strcpy(eosf - 4, ".asx");
1987 else if (strcmp(eosf - 3, ".rm") == 0)
1988 strcpy(eosf - 3, ".ram");
1989 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1990 /* generate a sample RTSP director if
1991 unicast. Generate an SDP redirector if
1993 eosf = strrchr(sfilename, '.');
1995 eosf = sfilename + strlen(sfilename);
1996 if (stream->is_multicast)
1997 strcpy(eosf, ".sdp");
1999 strcpy(eosf, ".rtsp");
2003 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
2004 sfilename, stream->filename);
2005 avio_printf(pb, "<td align=right> %d <td align=right> ",
2006 stream->conns_served);
2007 fmt_bytecount(pb, stream->bytes_served);
2008 switch(stream->stream_type) {
2009 case STREAM_TYPE_LIVE: {
2010 int audio_bit_rate = 0;
2011 int video_bit_rate = 0;
2012 const char *audio_codec_name = "";
2013 const char *video_codec_name = "";
2014 const char *audio_codec_name_extra = "";
2015 const char *video_codec_name_extra = "";
2017 for(i=0;i<stream->nb_streams;i++) {
2018 AVStream *st = stream->streams[i];
2019 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2020 switch(st->codec->codec_type) {
2021 case AVMEDIA_TYPE_AUDIO:
2022 audio_bit_rate += st->codec->bit_rate;
2024 if (*audio_codec_name)
2025 audio_codec_name_extra = "...";
2026 audio_codec_name = codec->name;
2029 case AVMEDIA_TYPE_VIDEO:
2030 video_bit_rate += st->codec->bit_rate;
2032 if (*video_codec_name)
2033 video_codec_name_extra = "...";
2034 video_codec_name = codec->name;
2037 case AVMEDIA_TYPE_DATA:
2038 video_bit_rate += st->codec->bit_rate;
2044 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",
2047 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2048 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2050 avio_printf(pb, "<td>%s", stream->feed->filename);
2052 avio_printf(pb, "<td>%s", stream->feed_filename);
2053 avio_printf(pb, "\n");
2057 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2061 stream = stream->next;
2063 avio_printf(pb, "</table>\n");
2065 stream = first_stream;
2066 while (stream != NULL) {
2067 if (stream->feed == stream) {
2068 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2070 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2077 /* This is somewhat linux specific I guess */
2078 snprintf(ps_cmd, sizeof(ps_cmd),
2079 "ps -o \"%%cpu,cputime\" --no-headers %d",
2082 pid_stat = popen(ps_cmd, "r");
2087 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2089 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2097 avio_printf(pb, "<p>");
2099 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");
2101 for (i = 0; i < stream->nb_streams; i++) {
2102 AVStream *st = stream->streams[i];
2103 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2104 const char *type = "unknown";
2105 char parameters[64];
2109 switch(st->codec->codec_type) {
2110 case AVMEDIA_TYPE_AUDIO:
2112 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2114 case AVMEDIA_TYPE_VIDEO:
2116 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2117 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2122 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2123 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2125 avio_printf(pb, "</table>\n");
2128 stream = stream->next;
2131 /* connection status */
2132 avio_printf(pb, "<h2>Connection Status</h2>\n");
2134 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2135 nb_connections, nb_max_connections);
2137 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2138 current_bandwidth, max_bandwidth);
2140 avio_printf(pb, "<table>\n");
2141 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");
2142 c1 = first_http_ctx;
2144 while (c1 != NULL) {
2150 for (j = 0; j < c1->stream->nb_streams; j++) {
2151 if (!c1->stream->feed)
2152 bitrate += c1->stream->streams[j]->codec->bit_rate;
2153 else if (c1->feed_streams[j] >= 0)
2154 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2159 p = inet_ntoa(c1->from_addr.sin_addr);
2160 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2162 c1->stream ? c1->stream->filename : "",
2163 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2166 http_state[c1->state]);
2167 fmt_bytecount(pb, bitrate);
2168 avio_printf(pb, "<td align=right>");
2169 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2170 avio_printf(pb, "<td align=right>");
2171 fmt_bytecount(pb, c1->data_count);
2172 avio_printf(pb, "\n");
2175 avio_printf(pb, "</table>\n");
2180 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2181 avio_printf(pb, "</body>\n</html>\n");
2183 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2184 c->buffer_ptr = c->pb_buffer;
2185 c->buffer_end = c->pb_buffer + len;
2188 static int open_input_stream(HTTPContext *c, const char *info)
2191 char input_filename[1024];
2192 AVFormatContext *s = NULL;
2193 int buf_size, i, ret;
2196 /* find file name */
2197 if (c->stream->feed) {
2198 strcpy(input_filename, c->stream->feed->feed_filename);
2199 buf_size = FFM_PACKET_SIZE;
2200 /* compute position (absolute time) */
2201 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2202 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2203 http_log("Invalid date specification '%s' for stream\n", buf);
2206 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2207 int prebuffer = strtol(buf, 0, 10);
2208 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2210 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2212 strcpy(input_filename, c->stream->feed_filename);
2214 /* compute position (relative time) */
2215 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2216 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2217 http_log("Invalid date specification '%s' for stream\n", buf);
2223 if (!input_filename[0]) {
2224 http_log("No filename was specified for stream\n");
2225 return AVERROR(EINVAL);
2229 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2230 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2234 /* set buffer size */
2235 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2237 s->flags |= AVFMT_FLAG_GENPTS;
2239 if (strcmp(s->iformat->name, "ffm") &&
2240 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2241 http_log("Could not find stream info for input '%s'\n", input_filename);
2242 avformat_close_input(&s);
2246 /* choose stream as clock source (we favor the video stream if
2247 * present) for packet sending */
2248 c->pts_stream_index = 0;
2249 for(i=0;i<c->stream->nb_streams;i++) {
2250 if (c->pts_stream_index == 0 &&
2251 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2252 c->pts_stream_index = i;
2256 if (c->fmt_in->iformat->read_seek)
2257 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2258 /* set the start time (needed for maxtime and RTP packet timing) */
2259 c->start_time = cur_time;
2260 c->first_pts = AV_NOPTS_VALUE;
2264 /* return the server clock (in us) */
2265 static int64_t get_server_clock(HTTPContext *c)
2267 /* compute current pts value from system time */
2268 return (cur_time - c->start_time) * 1000;
2271 /* return the estimated time at which the current packet must be sent
2273 static int64_t get_packet_send_clock(HTTPContext *c)
2275 int bytes_left, bytes_sent, frame_bytes;
2277 frame_bytes = c->cur_frame_bytes;
2278 if (frame_bytes <= 0)
2281 bytes_left = c->buffer_end - c->buffer_ptr;
2282 bytes_sent = frame_bytes - bytes_left;
2283 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2288 static int http_prepare_data(HTTPContext *c)
2291 AVFormatContext *ctx;
2293 av_freep(&c->pb_buffer);
2295 case HTTPSTATE_SEND_DATA_HEADER:
2296 ctx = avformat_alloc_context();
2299 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2300 c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams, sizeof(AVStream *));
2302 for(i=0;i<c->stream->nb_streams;i++) {
2304 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2305 /* if file or feed, then just take streams from FFStream struct */
2306 if (!c->stream->feed ||
2307 c->stream->feed == c->stream)
2308 src = c->stream->streams[i];
2310 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2312 *(c->fmt_ctx.streams[i]) = *src;
2313 c->fmt_ctx.streams[i]->priv_data = 0;
2314 /* XXX: should be done in AVStream, not in codec */
2315 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2317 /* set output format parameters */
2318 c->fmt_ctx.oformat = c->stream->fmt;
2319 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2321 c->got_key_frame = 0;
2323 /* prepare header and save header data in a stream */
2324 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2325 /* XXX: potential leak */
2328 c->fmt_ctx.pb->seekable = 0;
2331 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2332 * Default value from FFmpeg
2333 * Try to set it using configuration option
2335 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2337 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2338 http_log("Error writing output header for stream '%s': %s\n",
2339 c->stream->filename, av_err2str(ret));
2342 av_dict_free(&c->fmt_ctx.metadata);
2344 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2345 c->buffer_ptr = c->pb_buffer;
2346 c->buffer_end = c->pb_buffer + len;
2348 c->state = HTTPSTATE_SEND_DATA;
2349 c->last_packet_sent = 0;
2351 case HTTPSTATE_SEND_DATA:
2352 /* find a new packet */
2353 /* read a packet from the input stream */
2354 if (c->stream->feed)
2355 ffm_set_write_index(c->fmt_in,
2356 c->stream->feed->feed_write_index,
2357 c->stream->feed->feed_size);
2359 if (c->stream->max_time &&
2360 c->stream->max_time + c->start_time - cur_time < 0)
2361 /* We have timed out */
2362 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2366 ret = av_read_frame(c->fmt_in, &pkt);
2368 if (c->stream->feed) {
2369 /* if coming from feed, it means we reached the end of the
2370 ffm file, so must wait for more data */
2371 c->state = HTTPSTATE_WAIT_FEED;
2372 return 1; /* state changed */
2373 } else if (ret == AVERROR(EAGAIN)) {
2374 /* input not ready, come back later */
2377 if (c->stream->loop) {
2378 avformat_close_input(&c->fmt_in);
2379 if (open_input_stream(c, "") < 0)
2384 /* must send trailer now because EOF or error */
2385 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2389 int source_index = pkt.stream_index;
2390 /* update first pts if needed */
2391 if (c->first_pts == AV_NOPTS_VALUE) {
2392 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2393 c->start_time = cur_time;
2395 /* send it to the appropriate stream */
2396 if (c->stream->feed) {
2397 /* if coming from a feed, select the right stream */
2398 if (c->switch_pending) {
2399 c->switch_pending = 0;
2400 for(i=0;i<c->stream->nb_streams;i++) {
2401 if (c->switch_feed_streams[i] == pkt.stream_index)
2402 if (pkt.flags & AV_PKT_FLAG_KEY)
2403 c->switch_feed_streams[i] = -1;
2404 if (c->switch_feed_streams[i] >= 0)
2405 c->switch_pending = 1;
2408 for(i=0;i<c->stream->nb_streams;i++) {
2409 if (c->stream->feed_streams[i] == pkt.stream_index) {
2410 AVStream *st = c->fmt_in->streams[source_index];
2411 pkt.stream_index = i;
2412 if (pkt.flags & AV_PKT_FLAG_KEY &&
2413 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2414 c->stream->nb_streams == 1))
2415 c->got_key_frame = 1;
2416 if (!c->stream->send_on_key || c->got_key_frame)
2421 AVCodecContext *codec;
2422 AVStream *ist, *ost;
2424 ist = c->fmt_in->streams[source_index];
2425 /* specific handling for RTP: we use several
2426 * output streams (one for each RTP connection).
2427 * XXX: need more abstract handling */
2428 if (c->is_packetized) {
2429 /* compute send time and duration */
2430 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2431 c->cur_pts -= c->first_pts;
2432 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2433 /* find RTP context */
2434 c->packet_stream_index = pkt.stream_index;
2435 ctx = c->rtp_ctx[c->packet_stream_index];
2437 av_free_packet(&pkt);
2440 codec = ctx->streams[0]->codec;
2441 /* only one stream per RTP connection */
2442 pkt.stream_index = 0;
2446 codec = ctx->streams[pkt.stream_index]->codec;
2449 if (c->is_packetized) {
2450 int max_packet_size;
2451 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2452 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2454 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2455 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2457 ret = avio_open_dyn_buf(&ctx->pb);
2460 /* XXX: potential leak */
2463 ost = ctx->streams[pkt.stream_index];
2465 ctx->pb->seekable = 0;
2466 if (pkt.dts != AV_NOPTS_VALUE)
2467 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2468 if (pkt.pts != AV_NOPTS_VALUE)
2469 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2470 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2471 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2472 http_log("Error writing frame to output for stream '%s': %s\n",
2473 c->stream->filename, av_err2str(ret));
2474 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2477 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2478 c->cur_frame_bytes = len;
2479 c->buffer_ptr = c->pb_buffer;
2480 c->buffer_end = c->pb_buffer + len;
2482 codec->frame_number++;
2484 av_free_packet(&pkt);
2488 av_free_packet(&pkt);
2493 case HTTPSTATE_SEND_DATA_TRAILER:
2494 /* last packet test ? */
2495 if (c->last_packet_sent || c->is_packetized)
2498 /* prepare header */
2499 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2500 /* XXX: potential leak */
2503 c->fmt_ctx.pb->seekable = 0;
2504 av_write_trailer(ctx);
2505 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2506 c->buffer_ptr = c->pb_buffer;
2507 c->buffer_end = c->pb_buffer + len;
2509 c->last_packet_sent = 1;
2515 /* should convert the format at the same time */
2516 /* send data starting at c->buffer_ptr to the output connection
2517 * (either UDP or TCP) */
2518 static int http_send_data(HTTPContext *c)
2523 if (c->buffer_ptr >= c->buffer_end) {
2524 ret = http_prepare_data(c);
2528 /* state change requested */
2531 if (c->is_packetized) {
2532 /* RTP data output */
2533 len = c->buffer_end - c->buffer_ptr;
2535 /* fail safe - should never happen */
2537 c->buffer_ptr = c->buffer_end;
2540 len = (c->buffer_ptr[0] << 24) |
2541 (c->buffer_ptr[1] << 16) |
2542 (c->buffer_ptr[2] << 8) |
2544 if (len > (c->buffer_end - c->buffer_ptr))
2546 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2547 /* nothing to send yet: we can wait */
2551 c->data_count += len;
2552 update_datarate(&c->datarate, c->data_count);
2554 c->stream->bytes_served += len;
2556 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2557 /* RTP packets are sent inside the RTSP TCP connection */
2559 int interleaved_index, size;
2561 HTTPContext *rtsp_c;
2564 /* if no RTSP connection left, error */
2567 /* if already sending something, then wait. */
2568 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2570 if (avio_open_dyn_buf(&pb) < 0)
2572 interleaved_index = c->packet_stream_index * 2;
2573 /* RTCP packets are sent at odd indexes */
2574 if (c->buffer_ptr[1] == 200)
2575 interleaved_index++;
2576 /* write RTSP TCP header */
2578 header[1] = interleaved_index;
2579 header[2] = len >> 8;
2581 avio_write(pb, header, 4);
2582 /* write RTP packet data */
2584 avio_write(pb, c->buffer_ptr, len);
2585 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2586 /* prepare asynchronous TCP sending */
2587 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2588 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2589 c->buffer_ptr += len;
2591 /* send everything we can NOW */
2592 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2593 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2595 rtsp_c->packet_buffer_ptr += len;
2596 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2597 /* if we could not send all the data, we will
2598 send it later, so a new state is needed to
2599 "lock" the RTSP TCP connection */
2600 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2603 /* all data has been sent */
2604 av_freep(&c->packet_buffer);
2606 /* send RTP packet directly in UDP */
2608 ffurl_write(c->rtp_handles[c->packet_stream_index],
2609 c->buffer_ptr, len);
2610 c->buffer_ptr += len;
2611 /* here we continue as we can send several packets per 10 ms slot */
2614 /* TCP data output */
2615 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2617 if (ff_neterrno() != AVERROR(EAGAIN) &&
2618 ff_neterrno() != AVERROR(EINTR))
2619 /* error : close connection */
2624 c->buffer_ptr += len;
2626 c->data_count += len;
2627 update_datarate(&c->datarate, c->data_count);
2629 c->stream->bytes_served += len;
2637 static int http_start_receive_data(HTTPContext *c)
2642 if (c->stream->feed_opened) {
2643 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2644 return AVERROR(EINVAL);
2647 /* Don't permit writing to this one */
2648 if (c->stream->readonly) {
2649 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2650 return AVERROR(EINVAL);
2654 fd = open(c->stream->feed_filename, O_RDWR);
2656 ret = AVERROR(errno);
2657 http_log("Could not open feed file '%s': %s\n",
2658 c->stream->feed_filename, strerror(errno));
2663 if (c->stream->truncate) {
2664 /* truncate feed file */
2665 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2666 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2667 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2668 ret = AVERROR(errno);
2669 http_log("Error truncating feed file '%s': %s\n",
2670 c->stream->feed_filename, strerror(errno));
2674 ret = ffm_read_write_index(fd);
2676 http_log("Error reading write index from feed file '%s': %s\n",
2677 c->stream->feed_filename, strerror(errno));
2680 c->stream->feed_write_index = ret;
2684 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2685 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2686 lseek(fd, 0, SEEK_SET);
2688 /* init buffer input */
2689 c->buffer_ptr = c->buffer;
2690 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2691 c->stream->feed_opened = 1;
2692 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2696 static int http_receive_data(HTTPContext *c)
2699 int len, loop_run = 0;
2701 while (c->chunked_encoding && !c->chunk_size &&
2702 c->buffer_end > c->buffer_ptr) {
2703 /* read chunk header, if present */
2704 len = recv(c->fd, c->buffer_ptr, 1, 0);
2707 if (ff_neterrno() != AVERROR(EAGAIN) &&
2708 ff_neterrno() != AVERROR(EINTR))
2709 /* error : close connection */
2712 } else if (len == 0) {
2713 /* end of connection : close it */
2715 } else if (c->buffer_ptr - c->buffer >= 2 &&
2716 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2717 c->chunk_size = strtol(c->buffer, 0, 16);
2718 if (c->chunk_size == 0) // end of stream
2720 c->buffer_ptr = c->buffer;
2722 } else if (++loop_run > 10) {
2723 /* no chunk header, abort */
2730 if (c->buffer_end > c->buffer_ptr) {
2731 len = recv(c->fd, c->buffer_ptr,
2732 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2734 if (ff_neterrno() != AVERROR(EAGAIN) &&
2735 ff_neterrno() != AVERROR(EINTR))
2736 /* error : close connection */
2738 } else if (len == 0)
2739 /* end of connection : close it */
2742 c->chunk_size -= len;
2743 c->buffer_ptr += len;
2744 c->data_count += len;
2745 update_datarate(&c->datarate, c->data_count);
2749 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2750 if (c->buffer[0] != 'f' ||
2751 c->buffer[1] != 'm') {
2752 http_log("Feed stream has become desynchronized -- disconnecting\n");
2757 if (c->buffer_ptr >= c->buffer_end) {
2758 FFStream *feed = c->stream;
2759 /* a packet has been received : write it in the store, except
2761 if (c->data_count > FFM_PACKET_SIZE) {
2762 /* XXX: use llseek or url_seek
2763 * XXX: Should probably fail? */
2764 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2765 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2767 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2768 http_log("Error writing to feed file: %s\n", strerror(errno));
2772 feed->feed_write_index += FFM_PACKET_SIZE;
2773 /* update file size */
2774 if (feed->feed_write_index > c->stream->feed_size)
2775 feed->feed_size = feed->feed_write_index;
2777 /* handle wrap around if max file size reached */
2778 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2779 feed->feed_write_index = FFM_PACKET_SIZE;
2782 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2783 http_log("Error writing index to feed file: %s\n", strerror(errno));
2787 /* wake up any waiting connections */
2788 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2789 if (c1->state == HTTPSTATE_WAIT_FEED &&
2790 c1->stream->feed == c->stream->feed)
2791 c1->state = HTTPSTATE_SEND_DATA;
2794 /* We have a header in our hands that contains useful data */
2795 AVFormatContext *s = avformat_alloc_context();
2797 AVInputFormat *fmt_in;
2803 /* use feed output format name to find corresponding input format */
2804 fmt_in = av_find_input_format(feed->fmt->name);
2808 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2809 0, NULL, NULL, NULL, NULL);
2813 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2818 /* Now we have the actual streams */
2819 if (s->nb_streams != feed->nb_streams) {
2820 avformat_close_input(&s);
2822 http_log("Feed '%s' stream number does not match registered feed\n",
2823 c->stream->feed_filename);
2827 for (i = 0; i < s->nb_streams; i++) {
2828 AVStream *fst = feed->streams[i];
2829 AVStream *st = s->streams[i];
2830 avcodec_copy_context(fst->codec, st->codec);
2833 avformat_close_input(&s);
2836 c->buffer_ptr = c->buffer;
2841 c->stream->feed_opened = 0;
2843 /* wake up any waiting connections to stop waiting for feed */
2844 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2845 if (c1->state == HTTPSTATE_WAIT_FEED &&
2846 c1->stream->feed == c->stream->feed)
2847 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2852 /********************************************************************/
2855 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2862 str = RTSP_STATUS_CODE2STRING(error_number);
2864 str = "Unknown Error";
2866 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2867 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2869 /* output GMT time */
2872 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2873 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2876 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2878 rtsp_reply_header(c, error_number);
2879 avio_printf(c->pb, "\r\n");
2882 static int rtsp_parse_request(HTTPContext *c)
2884 const char *p, *p1, *p2;
2890 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2892 c->buffer_ptr[0] = '\0';
2895 get_word(cmd, sizeof(cmd), &p);
2896 get_word(url, sizeof(url), &p);
2897 get_word(protocol, sizeof(protocol), &p);
2899 av_strlcpy(c->method, cmd, sizeof(c->method));
2900 av_strlcpy(c->url, url, sizeof(c->url));
2901 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2903 if (avio_open_dyn_buf(&c->pb) < 0) {
2904 /* XXX: cannot do more */
2905 c->pb = NULL; /* safety */
2909 /* check version name */
2910 if (strcmp(protocol, "RTSP/1.0") != 0) {
2911 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2915 /* parse each header line */
2916 /* skip to next line */
2917 while (*p != '\n' && *p != '\0')
2921 while (*p != '\0') {
2922 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2926 if (p2 > p && p2[-1] == '\r')
2928 /* skip empty line */
2932 if (len > sizeof(line) - 1)
2933 len = sizeof(line) - 1;
2934 memcpy(line, p, len);
2936 ff_rtsp_parse_line(header, line, NULL, NULL);
2940 /* handle sequence number */
2941 c->seq = header->seq;
2943 if (!strcmp(cmd, "DESCRIBE"))
2944 rtsp_cmd_describe(c, url);
2945 else if (!strcmp(cmd, "OPTIONS"))
2946 rtsp_cmd_options(c, url);
2947 else if (!strcmp(cmd, "SETUP"))
2948 rtsp_cmd_setup(c, url, header);
2949 else if (!strcmp(cmd, "PLAY"))
2950 rtsp_cmd_play(c, url, header);
2951 else if (!strcmp(cmd, "PAUSE"))
2952 rtsp_cmd_interrupt(c, url, header, 1);
2953 else if (!strcmp(cmd, "TEARDOWN"))
2954 rtsp_cmd_interrupt(c, url, header, 0);
2956 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2959 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2960 c->pb = NULL; /* safety */
2962 /* XXX: cannot do more */
2965 c->buffer_ptr = c->pb_buffer;
2966 c->buffer_end = c->pb_buffer + len;
2967 c->state = RTSPSTATE_SEND_REPLY;
2971 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2972 struct in_addr my_ip)
2974 AVFormatContext *avc;
2975 AVStream *avs = NULL;
2976 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2977 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2980 avc = avformat_alloc_context();
2981 if (avc == NULL || !rtp_format) {
2984 avc->oformat = rtp_format;
2985 av_dict_set(&avc->metadata, "title",
2986 entry ? entry->value : "No Title", 0);
2987 avc->nb_streams = stream->nb_streams;
2988 if (stream->is_multicast) {
2989 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2990 inet_ntoa(stream->multicast_ip),
2991 stream->multicast_port, stream->multicast_ttl);
2993 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2996 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2997 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2999 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
3000 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
3003 for(i = 0; i < stream->nb_streams; i++) {
3004 avc->streams[i] = &avs[i];
3005 avc->streams[i]->codec = stream->streams[i]->codec;
3007 *pbuffer = av_mallocz(2048);
3008 av_sdp_create(&avc, 1, *pbuffer, 2048);
3011 av_free(avc->streams);
3012 av_dict_free(&avc->metadata);
3016 return strlen(*pbuffer);
3019 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3021 // rtsp_reply_header(c, RTSP_STATUS_OK);
3022 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3023 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3024 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3025 avio_printf(c->pb, "\r\n");
3028 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3036 struct sockaddr_in my_addr;
3038 /* find which URL is asked */
3039 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3044 for(stream = first_stream; stream != NULL; stream = stream->next) {
3045 if (!stream->is_feed &&
3046 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3047 !strcmp(path, stream->filename)) {
3051 /* no stream found */
3052 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3056 /* prepare the media description in SDP format */
3058 /* get the host IP */
3059 len = sizeof(my_addr);
3060 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3061 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3062 if (content_length < 0) {
3063 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3066 rtsp_reply_header(c, RTSP_STATUS_OK);
3067 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3068 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3069 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3070 avio_printf(c->pb, "\r\n");
3071 avio_write(c->pb, content, content_length);
3075 static HTTPContext *find_rtp_session(const char *session_id)
3079 if (session_id[0] == '\0')
3082 for(c = first_http_ctx; c != NULL; c = c->next) {
3083 if (!strcmp(c->session_id, session_id))
3089 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3091 RTSPTransportField *th;
3094 for(i=0;i<h->nb_transports;i++) {
3095 th = &h->transports[i];
3096 if (th->lower_transport == lower_transport)
3102 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3103 RTSPMessageHeader *h)
3106 int stream_index, rtp_port, rtcp_port;
3111 RTSPTransportField *th;
3112 struct sockaddr_in dest_addr;
3113 RTSPActionServerSetup setup;
3115 /* find which URL is asked */
3116 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3121 /* now check each stream */
3122 for(stream = first_stream; stream != NULL; stream = stream->next) {
3123 if (!stream->is_feed &&
3124 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3125 /* accept aggregate filenames only if single stream */
3126 if (!strcmp(path, stream->filename)) {
3127 if (stream->nb_streams != 1) {
3128 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3135 for(stream_index = 0; stream_index < stream->nb_streams;
3137 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3138 stream->filename, stream_index);
3139 if (!strcmp(path, buf))
3144 /* no stream found */
3145 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3149 /* generate session id if needed */
3150 if (h->session_id[0] == '\0') {
3151 unsigned random0 = av_lfg_get(&random_state);
3152 unsigned random1 = av_lfg_get(&random_state);
3153 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3157 /* find RTP session, and create it if none found */
3158 rtp_c = find_rtp_session(h->session_id);
3160 /* always prefer UDP */
3161 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3163 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3165 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3170 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3171 th->lower_transport);
3173 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3177 /* open input stream */
3178 if (open_input_stream(rtp_c, "") < 0) {
3179 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3184 /* test if stream is OK (test needed because several SETUP needs
3185 to be done for a given file) */
3186 if (rtp_c->stream != stream) {
3187 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3191 /* test if stream is already set up */
3192 if (rtp_c->rtp_ctx[stream_index]) {
3193 rtsp_reply_error(c, RTSP_STATUS_STATE);
3197 /* check transport */
3198 th = find_transport(h, rtp_c->rtp_protocol);
3199 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3200 th->client_port_min <= 0)) {
3201 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3205 /* setup default options */
3206 setup.transport_option[0] = '\0';
3207 dest_addr = rtp_c->from_addr;
3208 dest_addr.sin_port = htons(th->client_port_min);
3211 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3212 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3216 /* now everything is OK, so we can send the connection parameters */
3217 rtsp_reply_header(c, RTSP_STATUS_OK);
3219 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3221 switch(rtp_c->rtp_protocol) {
3222 case RTSP_LOWER_TRANSPORT_UDP:
3223 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3224 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3225 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3226 "client_port=%d-%d;server_port=%d-%d",
3227 th->client_port_min, th->client_port_max,
3228 rtp_port, rtcp_port);
3230 case RTSP_LOWER_TRANSPORT_TCP:
3231 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3232 stream_index * 2, stream_index * 2 + 1);
3237 if (setup.transport_option[0] != '\0')
3238 avio_printf(c->pb, ";%s", setup.transport_option);
3239 avio_printf(c->pb, "\r\n");
3242 avio_printf(c->pb, "\r\n");
3246 /* find an RTP connection by using the session ID. Check consistency
3248 static HTTPContext *find_rtp_session_with_url(const char *url,
3249 const char *session_id)
3257 rtp_c = find_rtp_session(session_id);
3261 /* find which URL is asked */
3262 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3266 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3267 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3268 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3269 rtp_c->stream->filename, s);
3270 if(!strncmp(path, buf, sizeof(buf))) {
3271 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3276 if (len > 0 && path[len - 1] == '/' &&
3277 !strncmp(path, rtp_c->stream->filename, len - 1))
3282 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3286 rtp_c = find_rtp_session_with_url(url, h->session_id);
3288 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3292 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3293 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3294 rtp_c->state != HTTPSTATE_READY) {
3295 rtsp_reply_error(c, RTSP_STATUS_STATE);
3299 rtp_c->state = HTTPSTATE_SEND_DATA;
3301 /* now everything is OK, so we can send the connection parameters */
3302 rtsp_reply_header(c, RTSP_STATUS_OK);
3304 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3305 avio_printf(c->pb, "\r\n");
3308 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3312 rtp_c = find_rtp_session_with_url(url, h->session_id);
3314 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3319 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3320 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3321 rtsp_reply_error(c, RTSP_STATUS_STATE);
3324 rtp_c->state = HTTPSTATE_READY;
3325 rtp_c->first_pts = AV_NOPTS_VALUE;
3328 /* now everything is OK, so we can send the connection parameters */
3329 rtsp_reply_header(c, RTSP_STATUS_OK);
3331 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3332 avio_printf(c->pb, "\r\n");
3335 close_connection(rtp_c);
3338 /********************************************************************/
3341 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3342 FFStream *stream, const char *session_id,
3343 enum RTSPLowerTransport rtp_protocol)
3345 HTTPContext *c = NULL;
3346 const char *proto_str;
3348 /* XXX: should output a warning page when coming
3349 close to the connection limit */
3350 if (nb_connections >= nb_max_connections)
3353 /* add a new connection */
3354 c = av_mallocz(sizeof(HTTPContext));
3359 c->poll_entry = NULL;
3360 c->from_addr = *from_addr;
3361 c->buffer_size = IOBUFFER_INIT_SIZE;
3362 c->buffer = av_malloc(c->buffer_size);
3367 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3368 c->state = HTTPSTATE_READY;
3369 c->is_packetized = 1;
3370 c->rtp_protocol = rtp_protocol;
3372 /* protocol is shown in statistics */
3373 switch(c->rtp_protocol) {
3374 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3375 proto_str = "MCAST";
3377 case RTSP_LOWER_TRANSPORT_UDP:
3380 case RTSP_LOWER_TRANSPORT_TCP:
3387 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3388 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3390 current_bandwidth += stream->bandwidth;
3392 c->next = first_http_ctx;
3404 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3405 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3407 static int rtp_new_av_stream(HTTPContext *c,
3408 int stream_index, struct sockaddr_in *dest_addr,
3409 HTTPContext *rtsp_c)
3411 AVFormatContext *ctx;
3414 URLContext *h = NULL;
3416 int max_packet_size;
3418 /* now we can open the relevant output stream */
3419 ctx = avformat_alloc_context();
3422 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3424 st = av_mallocz(sizeof(AVStream));
3427 ctx->nb_streams = 1;
3428 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3431 ctx->streams[0] = st;
3433 if (!c->stream->feed ||
3434 c->stream->feed == c->stream)
3435 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3438 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3440 st->priv_data = NULL;
3442 /* build destination RTP address */
3443 ipaddr = inet_ntoa(dest_addr->sin_addr);
3445 switch(c->rtp_protocol) {
3446 case RTSP_LOWER_TRANSPORT_UDP:
3447 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3450 /* XXX: also pass as parameter to function ? */
3451 if (c->stream->is_multicast) {
3453 ttl = c->stream->multicast_ttl;
3456 snprintf(ctx->filename, sizeof(ctx->filename),
3457 "rtp://%s:%d?multicast=1&ttl=%d",
3458 ipaddr, ntohs(dest_addr->sin_port), ttl);
3460 snprintf(ctx->filename, sizeof(ctx->filename),
3461 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3464 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3466 c->rtp_handles[stream_index] = h;
3467 max_packet_size = h->max_packet_size;
3469 case RTSP_LOWER_TRANSPORT_TCP:
3472 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3478 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3479 ipaddr, ntohs(dest_addr->sin_port),
3480 c->stream->filename, stream_index, c->protocol);
3482 /* normally, no packets should be output here, but the packet size may
3484 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3485 /* XXX: close stream */
3488 if (avformat_write_header(ctx, NULL) < 0) {
3496 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3499 c->rtp_ctx[stream_index] = ctx;
3503 /********************************************************************/
3504 /* ffserver initialization */
3506 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3510 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3513 fst = av_mallocz(sizeof(AVStream));
3517 fst->codec = avcodec_alloc_context3(NULL);
3518 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3519 if (codec->extradata_size) {
3520 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3521 memcpy(fst->codec->extradata, codec->extradata,
3522 codec->extradata_size);
3525 /* live streams must use the actual feed's codec since it may be
3526 * updated later to carry extradata needed by them.
3530 fst->priv_data = av_mallocz(sizeof(FeedData));
3531 fst->index = stream->nb_streams;
3532 avpriv_set_pts_info(fst, 33, 1, 90000);
3533 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3534 stream->streams[stream->nb_streams++] = fst;
3538 /* return the stream number in the feed */
3539 static int add_av_stream(FFStream *feed, AVStream *st)
3542 AVCodecContext *av, *av1;
3546 for(i=0;i<feed->nb_streams;i++) {
3547 st = feed->streams[i];
3549 if (av1->codec_id == av->codec_id &&
3550 av1->codec_type == av->codec_type &&
3551 av1->bit_rate == av->bit_rate) {
3553 switch(av->codec_type) {
3554 case AVMEDIA_TYPE_AUDIO:
3555 if (av1->channels == av->channels &&
3556 av1->sample_rate == av->sample_rate)
3559 case AVMEDIA_TYPE_VIDEO:
3560 if (av1->width == av->width &&
3561 av1->height == av->height &&
3562 av1->time_base.den == av->time_base.den &&
3563 av1->time_base.num == av->time_base.num &&
3564 av1->gop_size == av->gop_size)
3573 fst = add_av_stream1(feed, av, 0);
3576 return feed->nb_streams - 1;
3579 static void remove_stream(FFStream *stream)
3583 while (*ps != NULL) {
3591 /* specific MPEG4 handling : we extract the raw parameters */
3592 static void extract_mpeg4_header(AVFormatContext *infile)
3594 int mpeg4_count, i, size;
3599 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3602 for(i=0;i<infile->nb_streams;i++) {
3603 st = infile->streams[i];
3604 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3605 st->codec->extradata_size == 0) {
3612 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3613 while (mpeg4_count > 0) {
3614 if (av_read_frame(infile, &pkt) < 0)
3616 st = infile->streams[pkt.stream_index];
3617 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3618 st->codec->extradata_size == 0) {
3619 av_freep(&st->codec->extradata);
3620 /* fill extradata with the header */
3621 /* XXX: we make hard suppositions here ! */
3623 while (p < pkt.data + pkt.size - 4) {
3624 /* stop when vop header is found */
3625 if (p[0] == 0x00 && p[1] == 0x00 &&
3626 p[2] == 0x01 && p[3] == 0xb6) {
3627 size = p - pkt.data;
3628 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3629 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3630 st->codec->extradata_size = size;
3631 memcpy(st->codec->extradata, pkt.data, size);
3638 av_free_packet(&pkt);
3642 /* compute the needed AVStream for each file */
3643 static void build_file_streams(void)
3645 FFStream *stream, *stream_next;
3648 /* gather all streams */
3649 for(stream = first_stream; stream != NULL; stream = stream_next) {
3650 AVFormatContext *infile = NULL;
3651 stream_next = stream->next;
3652 if (stream->stream_type == STREAM_TYPE_LIVE &&
3654 /* the stream comes from a file */
3655 /* try to open the file */
3657 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3658 /* specific case : if transport stream output to RTP,
3659 we use a raw transport stream reader */
3660 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3663 if (!stream->feed_filename[0]) {
3664 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3668 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3669 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3670 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3671 /* remove stream (no need to spend more time on it) */
3673 remove_stream(stream);
3675 /* find all the AVStreams inside and reference them in
3677 if (avformat_find_stream_info(infile, NULL) < 0) {
3678 http_log("Could not find codec parameters from '%s'\n",
3679 stream->feed_filename);
3680 avformat_close_input(&infile);
3683 extract_mpeg4_header(infile);
3685 for(i=0;i<infile->nb_streams;i++)
3686 add_av_stream1(stream, infile->streams[i]->codec, 1);
3688 avformat_close_input(&infile);
3694 /* compute the needed AVStream for each feed */
3695 static void build_feed_streams(void)
3697 FFStream *stream, *feed;
3700 /* gather all streams */
3701 for(stream = first_stream; stream != NULL; stream = stream->next) {
3702 feed = stream->feed;
3704 if (stream->is_feed) {
3705 for(i=0;i<stream->nb_streams;i++)
3706 stream->feed_streams[i] = i;
3708 /* we handle a stream coming from a feed */
3709 for(i=0;i<stream->nb_streams;i++)
3710 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3715 /* create feed files if needed */
3716 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3719 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3720 /* See if it matches */
3721 AVFormatContext *s = NULL;
3724 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3725 /* set buffer size */
3726 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3727 /* Now see if it matches */
3728 if (s->nb_streams == feed->nb_streams) {
3730 for(i=0;i<s->nb_streams;i++) {
3732 sf = feed->streams[i];
3735 if (sf->index != ss->index ||
3737 http_log("Index & Id do not match for stream %d (%s)\n",
3738 i, feed->feed_filename);
3741 AVCodecContext *ccf, *ccs;
3745 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3747 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3748 http_log("Codecs do not match for stream %d\n", i);
3750 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3751 http_log("Codec bitrates do not match for stream %d\n", i);
3753 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3754 if (CHECK_CODEC(time_base.den) ||
3755 CHECK_CODEC(time_base.num) ||
3756 CHECK_CODEC(width) ||
3757 CHECK_CODEC(height)) {
3758 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3761 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3762 if (CHECK_CODEC(sample_rate) ||
3763 CHECK_CODEC(channels) ||
3764 CHECK_CODEC(frame_size)) {
3765 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3769 http_log("Unknown codec type\n");
3777 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3778 feed->feed_filename, s->nb_streams, feed->nb_streams);
3780 avformat_close_input(&s);
3782 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3783 feed->feed_filename);
3786 if (feed->readonly) {
3787 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3788 feed->feed_filename);
3791 unlink(feed->feed_filename);
3794 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3795 AVFormatContext *s = avformat_alloc_context();
3797 if (feed->readonly) {
3798 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3799 feed->feed_filename);
3803 /* only write the header of the ffm file */
3804 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3805 http_log("Could not open output feed file '%s'\n",
3806 feed->feed_filename);
3809 s->oformat = feed->fmt;
3810 s->nb_streams = feed->nb_streams;
3811 s->streams = feed->streams;
3812 if (avformat_write_header(s, NULL) < 0) {
3813 http_log("Container doesn't support the required parameters\n");
3816 /* XXX: need better API */
3817 av_freep(&s->priv_data);
3821 avformat_free_context(s);
3823 /* get feed size and write index */
3824 fd = open(feed->feed_filename, O_RDONLY);
3826 http_log("Could not open output feed file '%s'\n",
3827 feed->feed_filename);
3831 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3832 feed->feed_size = lseek(fd, 0, SEEK_END);
3833 /* ensure that we do not wrap before the end of file */
3834 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3835 feed->feed_max_size = feed->feed_size;
3841 /* compute the bandwidth used by each stream */
3842 static void compute_bandwidth(void)
3848 for(stream = first_stream; stream != NULL; stream = stream->next) {
3850 for(i=0;i<stream->nb_streams;i++) {
3851 AVStream *st = stream->streams[i];
3852 switch(st->codec->codec_type) {
3853 case AVMEDIA_TYPE_AUDIO:
3854 case AVMEDIA_TYPE_VIDEO:
3855 bandwidth += st->codec->bit_rate;
3861 stream->bandwidth = (bandwidth + 999) / 1000;
3865 /* add a codec and set the default parameters */
3866 static void add_codec(FFStream *stream, AVCodecContext *av)
3870 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3873 /* compute default parameters */
3874 switch(av->codec_type) {
3875 case AVMEDIA_TYPE_AUDIO:
3876 if (av->bit_rate == 0)
3877 av->bit_rate = 64000;
3878 if (av->sample_rate == 0)
3879 av->sample_rate = 22050;
3880 if (av->channels == 0)
3883 case AVMEDIA_TYPE_VIDEO:
3884 if (av->bit_rate == 0)
3885 av->bit_rate = 64000;
3886 if (av->time_base.num == 0){
3887 av->time_base.den = 5;
3888 av->time_base.num = 1;
3890 if (av->width == 0 || av->height == 0) {
3894 /* Bitrate tolerance is less for streaming */
3895 if (av->bit_rate_tolerance == 0)
3896 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3897 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3902 if (av->max_qdiff == 0)
3904 av->qcompress = 0.5;
3907 if (!av->nsse_weight)
3908 av->nsse_weight = 8;
3910 av->frame_skip_cmp = FF_CMP_DCTMAX;
3912 av->me_method = ME_EPZS;
3913 av->rc_buffer_aggressivity = 1.0;
3916 av->rc_eq = av_strdup("tex^qComp");
3917 if (!av->i_quant_factor)
3918 av->i_quant_factor = -0.8;
3919 if (!av->b_quant_factor)
3920 av->b_quant_factor = 1.25;
3921 if (!av->b_quant_offset)
3922 av->b_quant_offset = 1.25;
3923 if (!av->rc_max_rate)
3924 av->rc_max_rate = av->bit_rate * 2;
3926 if (av->rc_max_rate && !av->rc_buffer_size) {
3927 av->rc_buffer_size = av->rc_max_rate;
3936 st = av_mallocz(sizeof(AVStream));
3939 st->codec = avcodec_alloc_context3(NULL);
3940 stream->streams[stream->nb_streams++] = st;
3941 memcpy(st->codec, av, sizeof(AVCodecContext));
3944 static enum AVCodecID opt_codec(const char *name, enum AVMediaType type)
3946 AVCodec *codec = avcodec_find_encoder_by_name(name);
3948 if (!codec || codec->type != type)
3949 return AV_CODEC_ID_NONE;
3953 static int ffserver_opt_default(const char *opt, const char *arg,
3954 AVCodecContext *avctx, int type)
3957 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3959 ret = av_opt_set(avctx, opt, arg, 0);
3963 static int ffserver_opt_preset(const char *arg,
3964 AVCodecContext *avctx, int type,
3965 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3968 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3970 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3972 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3973 codec ? codec->name : NULL))) {
3974 fprintf(stderr, "File for preset '%s' not found\n", arg);
3979 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3980 if(line[0] == '#' && !e)
3982 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3984 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3988 if(!strcmp(tmp, "acodec")){
3989 *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
3990 }else if(!strcmp(tmp, "vcodec")){
3991 *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
3992 }else if(!strcmp(tmp, "scodec")){
3993 /* opt_subtitle_codec(tmp2); */
3994 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3995 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4006 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename, const char *mime_type)
4008 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4011 AVOutputFormat *stream_fmt;
4012 char stream_format_name[64];
4014 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4015 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4024 static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...)
4028 av_log(NULL, log_level, "%s:%d: ", filename, line_num);
4029 av_vlog(NULL, log_level, fmt, vl);
4035 static int parse_ffconfig(const char *filename)
4040 char arg[1024], arg2[1024];
4042 int val, errors, warnings, line_num;
4043 FFStream **last_stream, *stream, *redirect;
4044 FFStream **last_feed, *feed, *s;
4045 AVCodecContext audio_enc, video_enc;
4046 enum AVCodecID audio_id, video_id;
4049 f = fopen(filename, "r");
4051 ret = AVERROR(errno);
4052 av_log(NULL, AV_LOG_ERROR, "Could not open the configuration file '%s'\n", filename);
4056 errors = warnings = 0;
4058 first_stream = NULL;
4059 last_stream = &first_stream;
4061 last_feed = &first_feed;
4065 audio_id = AV_CODEC_ID_NONE;
4066 video_id = AV_CODEC_ID_NONE;
4067 #define ERROR(...) report_config_error(filename, line_num, AV_LOG_ERROR, &errors, __VA_ARGS__)
4068 #define WARNING(...) report_config_error(filename, line_num, AV_LOG_WARNING, &warnings, __VA_ARGS__)
4071 if (fgets(line, sizeof(line), f) == NULL)
4075 while (av_isspace(*p))
4077 if (*p == '\0' || *p == '#')
4080 get_arg(cmd, sizeof(cmd), &p);
4082 if (!av_strcasecmp(cmd, "Port")) {
4083 get_arg(arg, sizeof(arg), &p);
4085 if (val < 1 || val > 65536) {
4086 ERROR("Invalid_port: %s\n", arg);
4088 my_http_addr.sin_port = htons(val);
4089 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4090 get_arg(arg, sizeof(arg), &p);
4091 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4092 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4094 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4095 WARNING("NoDaemon option has no effect, you should remove it\n");
4096 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4097 get_arg(arg, sizeof(arg), &p);
4099 if (val < 1 || val > 65536) {
4100 ERROR("%s:%d: Invalid port: %s\n", arg);
4102 my_rtsp_addr.sin_port = htons(atoi(arg));
4103 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4104 get_arg(arg, sizeof(arg), &p);
4105 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4106 ERROR("Invalid host/IP address: %s\n", arg);
4108 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4109 get_arg(arg, sizeof(arg), &p);
4111 if (val < 1 || val > 65536) {
4112 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4114 nb_max_http_connections = val;
4115 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4116 get_arg(arg, sizeof(arg), &p);
4118 if (val < 1 || val > nb_max_http_connections) {
4119 ERROR("Invalid MaxClients: %s\n", arg);
4121 nb_max_connections = val;
4123 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4125 get_arg(arg, sizeof(arg), &p);
4126 llval = strtoll(arg, NULL, 10);
4127 if (llval < 10 || llval > 10000000) {
4128 ERROR("Invalid MaxBandwidth: %s\n", arg);
4130 max_bandwidth = llval;
4131 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4132 if (!ffserver_debug)
4133 get_arg(logfilename, sizeof(logfilename), &p);
4134 } else if (!av_strcasecmp(cmd, "<Feed")) {
4135 /*********************************************/
4136 /* Feed related options */
4138 if (stream || feed) {
4139 ERROR("Already in a tag\n");
4141 feed = av_mallocz(sizeof(FFStream));
4143 ret = AVERROR(ENOMEM);
4146 get_arg(feed->filename, sizeof(feed->filename), &p);
4147 q = strrchr(feed->filename, '>');
4151 for (s = first_feed; s; s = s->next) {
4152 if (!strcmp(feed->filename, s->filename)) {
4153 ERROR("Feed '%s' already registered\n", s->filename);
4157 feed->fmt = av_guess_format("ffm", NULL, NULL);
4158 /* default feed file */
4159 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4160 "/tmp/%s.ffm", feed->filename);
4161 feed->feed_max_size = 5 * 1024 * 1024;
4163 feed->feed = feed; /* self feeding :-) */
4165 /* add in stream list */
4166 *last_stream = feed;
4167 last_stream = &feed->next;
4168 /* add in feed list */
4170 last_feed = &feed->next_feed;
4172 } else if (!av_strcasecmp(cmd, "Launch")) {
4176 feed->child_argv = av_mallocz(64 * sizeof(char *));
4177 if (!feed->child_argv) {
4178 ret = AVERROR(ENOMEM);
4181 for (i = 0; i < 62; i++) {
4182 get_arg(arg, sizeof(arg), &p);
4186 feed->child_argv[i] = av_strdup(arg);
4187 if (!feed->child_argv[i]) {
4188 ret = AVERROR(ENOMEM);
4193 feed->child_argv[i] =
4194 av_asprintf("http://%s:%d/%s",
4195 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4196 inet_ntoa(my_http_addr.sin_addr), ntohs(my_http_addr.sin_port),
4198 if (!feed->child_argv[i]) {
4199 ret = AVERROR(ENOMEM);
4203 } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
4205 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4206 feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile");
4207 } else if (stream) {
4208 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4210 } else if (!av_strcasecmp(cmd, "Truncate")) {
4212 get_arg(arg, sizeof(arg), &p);
4213 /* assume Truncate is true in case no argument is specified */
4217 WARNING("Truncate N syntax in configuration file is deprecated, "
4218 "use Truncate alone with no arguments\n");
4219 feed->truncate = strtod(arg, NULL);
4222 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4227 get_arg(arg, sizeof(arg), &p);
4229 fsize = strtod(p1, &p1);
4230 switch(av_toupper(*p1)) {
4235 fsize *= 1024 * 1024;
4238 fsize *= 1024 * 1024 * 1024;
4241 feed->feed_max_size = (int64_t)fsize;
4242 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4243 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4246 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4248 ERROR("No corresponding <Feed> for </Feed>\n");
4251 } else if (!av_strcasecmp(cmd, "<Stream")) {
4252 /*********************************************/
4253 /* Stream related options */
4255 if (stream || feed) {
4256 ERROR("Already in a tag\n");
4259 stream = av_mallocz(sizeof(FFStream));
4261 ret = AVERROR(ENOMEM);
4264 get_arg(stream->filename, sizeof(stream->filename), &p);
4265 q = strrchr(stream->filename, '>');
4269 for (s = first_stream; s; s = s->next) {
4270 if (!strcmp(stream->filename, s->filename)) {
4271 ERROR("Stream '%s' already registered\n", s->filename);
4275 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4276 avcodec_get_context_defaults3(&video_enc, NULL);
4277 avcodec_get_context_defaults3(&audio_enc, NULL);
4279 audio_id = AV_CODEC_ID_NONE;
4280 video_id = AV_CODEC_ID_NONE;
4282 audio_id = stream->fmt->audio_codec;
4283 video_id = stream->fmt->video_codec;
4286 *last_stream = stream;
4287 last_stream = &stream->next;
4289 } else if (!av_strcasecmp(cmd, "Feed")) {
4290 get_arg(arg, sizeof(arg), &p);
4295 while (sfeed != NULL) {
4296 if (!strcmp(sfeed->filename, arg))
4298 sfeed = sfeed->next_feed;
4301 ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg, stream->filename);
4303 stream->feed = sfeed;
4305 } else if (!av_strcasecmp(cmd, "Format")) {
4306 get_arg(arg, sizeof(arg), &p);
4308 if (!strcmp(arg, "status")) {
4309 stream->stream_type = STREAM_TYPE_STATUS;
4312 stream->stream_type = STREAM_TYPE_LIVE;
4313 /* JPEG cannot be used here, so use single frame MJPEG */
4314 if (!strcmp(arg, "jpeg"))
4315 strcpy(arg, "mjpeg");
4316 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4318 ERROR("Unknown Format: %s\n", arg);
4322 audio_id = stream->fmt->audio_codec;
4323 video_id = stream->fmt->video_codec;
4326 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4327 get_arg(arg, sizeof(arg), &p);
4329 stream->ifmt = av_find_input_format(arg);
4330 if (!stream->ifmt) {
4331 ERROR("Unknown input format: %s\n", arg);
4334 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4335 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4336 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4338 ERROR("FaviconURL only permitted for status streams\n");
4340 } else if (!av_strcasecmp(cmd, "Author") ||
4341 !av_strcasecmp(cmd, "Comment") ||
4342 !av_strcasecmp(cmd, "Copyright") ||
4343 !av_strcasecmp(cmd, "Title")) {
4344 get_arg(arg, sizeof(arg), &p);
4350 for (i = 0; i < strlen(cmd); i++)
4351 key[i] = av_tolower(cmd[i]);
4353 WARNING("'%s' option in configuration file is deprecated, "
4354 "use 'Metadata %s VALUE' instead\n", cmd, key);
4355 if ((ret = av_dict_set(&stream->metadata, key, arg, 0)) < 0) {
4356 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4357 key, arg, av_err2str(ret));
4360 } else if (!av_strcasecmp(cmd, "Metadata")) {
4361 get_arg(arg, sizeof(arg), &p);
4362 get_arg(arg2, sizeof(arg2), &p);
4365 if ((ret = av_dict_set(&stream->metadata, arg, arg2, 0)) < 0) {
4366 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4367 arg, arg2, av_err2str(ret));
4370 } else if (!av_strcasecmp(cmd, "Preroll")) {
4371 get_arg(arg, sizeof(arg), &p);
4373 stream->prebuffer = atof(arg) * 1000;
4374 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4376 stream->send_on_key = 1;
4377 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4378 get_arg(arg, sizeof(arg), &p);
4379 audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO);
4380 if (audio_id == AV_CODEC_ID_NONE) {
4381 ERROR("Unknown AudioCodec: %s\n", arg);
4383 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4384 get_arg(arg, sizeof(arg), &p);
4385 video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO);
4386 if (video_id == AV_CODEC_ID_NONE) {
4387 ERROR("Unknown VideoCodec: %s\n", arg);
4389 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4390 get_arg(arg, sizeof(arg), &p);
4392 stream->max_time = atof(arg) * 1000;
4393 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4394 get_arg(arg, sizeof(arg), &p);
4396 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4397 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4398 get_arg(arg, sizeof(arg), &p);
4400 audio_enc.channels = atoi(arg);
4401 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4402 get_arg(arg, sizeof(arg), &p);
4404 audio_enc.sample_rate = atoi(arg);
4405 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4407 int minrate, maxrate;
4409 get_arg(arg, sizeof(arg), &p);
4411 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4412 video_enc.rc_min_rate = minrate * 1000;
4413 video_enc.rc_max_rate = maxrate * 1000;
4415 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4418 } else if (!av_strcasecmp(cmd, "Debug")) {
4420 get_arg(arg, sizeof(arg), &p);
4421 video_enc.debug = strtol(arg,0,0);
4423 } else if (!av_strcasecmp(cmd, "Strict")) {
4425 get_arg(arg, sizeof(arg), &p);
4426 video_enc.strict_std_compliance = atoi(arg);
4428 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4430 get_arg(arg, sizeof(arg), &p);
4431 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4433 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4435 get_arg(arg, sizeof(arg), &p);
4436 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4438 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4439 get_arg(arg, sizeof(arg), &p);
4441 video_enc.bit_rate = atoi(arg) * 1000;
4443 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4444 get_arg(arg, sizeof(arg), &p);
4446 ret = av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4448 ERROR("Invalid video size '%s'\n", arg);
4450 if ((video_enc.width % 16) != 0 ||
4451 (video_enc.height % 16) != 0) {
4452 ERROR("Image size must be a multiple of 16\n");
4456 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4457 get_arg(arg, sizeof(arg), &p);
4459 AVRational frame_rate;
4460 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4461 ERROR("Incorrect frame rate: %s\n", arg);
4463 video_enc.time_base.num = frame_rate.den;
4464 video_enc.time_base.den = frame_rate.num;
4467 } else if (!av_strcasecmp(cmd, "PixelFormat")) {
4468 get_arg(arg, sizeof(arg), &p);
4470 video_enc.pix_fmt = av_get_pix_fmt(arg);
4471 if (video_enc.pix_fmt == AV_PIX_FMT_NONE) {
4472 ERROR("Unknown pixel format: %s\n", arg);
4475 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4476 get_arg(arg, sizeof(arg), &p);
4478 video_enc.gop_size = atoi(arg);
4479 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4481 video_enc.gop_size = 1;
4482 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4484 video_enc.mb_decision = FF_MB_DECISION_BITS;
4485 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4487 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4488 video_enc.flags |= CODEC_FLAG_4MV;
4490 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4491 !av_strcasecmp(cmd, "AVOptionAudio")) {
4492 AVCodecContext *avctx;
4494 get_arg(arg, sizeof(arg), &p);
4495 get_arg(arg2, sizeof(arg2), &p);
4496 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4498 type = AV_OPT_FLAG_VIDEO_PARAM;
4501 type = AV_OPT_FLAG_AUDIO_PARAM;
4503 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4504 ERROR("Error setting %s option to %s %s\n", cmd, arg, arg2);
4506 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4507 !av_strcasecmp(cmd, "AVPresetAudio")) {
4508 AVCodecContext *avctx;
4510 get_arg(arg, sizeof(arg), &p);
4511 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4513 video_enc.codec_id = video_id;
4514 type = AV_OPT_FLAG_VIDEO_PARAM;
4517 audio_enc.codec_id = audio_id;
4518 type = AV_OPT_FLAG_AUDIO_PARAM;
4520 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4521 ERROR("AVPreset error: %s\n", arg);
4523 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4524 get_arg(arg, sizeof(arg), &p);
4525 if ((strlen(arg) == 4) && stream)
4526 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4527 } else if (!av_strcasecmp(cmd, "BitExact")) {
4529 video_enc.flags |= CODEC_FLAG_BITEXACT;
4530 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4532 video_enc.dct_algo = FF_DCT_FASTINT;
4533 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4535 video_enc.idct_algo = FF_IDCT_SIMPLE;
4536 } else if (!av_strcasecmp(cmd, "Qscale")) {
4537 get_arg(arg, sizeof(arg), &p);
4539 video_enc.flags |= CODEC_FLAG_QSCALE;
4540 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4542 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4543 get_arg(arg, sizeof(arg), &p);
4545 video_enc.max_qdiff = atoi(arg);
4546 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4547 ERROR("VideoQDiff out of range\n");
4550 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4551 get_arg(arg, sizeof(arg), &p);
4553 video_enc.qmax = atoi(arg);
4554 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4555 ERROR("VideoQMax out of range\n");
4558 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4559 get_arg(arg, sizeof(arg), &p);
4561 video_enc.qmin = atoi(arg);
4562 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4563 ERROR("VideoQMin out of range\n");
4566 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4567 get_arg(arg, sizeof(arg), &p);
4569 video_enc.lumi_masking = atof(arg);
4570 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4571 get_arg(arg, sizeof(arg), &p);
4573 video_enc.dark_masking = atof(arg);
4574 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4575 video_id = AV_CODEC_ID_NONE;
4576 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4577 audio_id = AV_CODEC_ID_NONE;
4578 } else if (!av_strcasecmp(cmd, "ACL")) {
4579 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4580 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4582 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4584 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4585 get_arg(arg, sizeof(arg), &p);
4587 av_freep(&stream->rtsp_option);
4588 stream->rtsp_option = av_strdup(arg);
4590 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4591 get_arg(arg, sizeof(arg), &p);
4593 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4594 ERROR("Invalid host/IP address: %s\n", arg);
4596 stream->is_multicast = 1;
4597 stream->loop = 1; /* default is looping */
4599 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4600 get_arg(arg, sizeof(arg), &p);
4602 stream->multicast_port = atoi(arg);
4603 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4604 get_arg(arg, sizeof(arg), &p);
4606 stream->multicast_ttl = atoi(arg);
4607 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4610 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4612 ERROR("No corresponding <Stream> for </Stream>\n");
4614 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4615 if (audio_id != AV_CODEC_ID_NONE) {
4616 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4617 audio_enc.codec_id = audio_id;
4618 add_codec(stream, &audio_enc);
4620 if (video_id != AV_CODEC_ID_NONE) {
4621 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4622 video_enc.codec_id = video_id;
4623 add_codec(stream, &video_enc);
4628 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4629 /*********************************************/
4631 if (stream || feed || redirect) {
4632 ERROR("Already in a tag\n");
4634 redirect = av_mallocz(sizeof(FFStream));
4636 ret = AVERROR(ENOMEM);
4639 *last_stream = redirect;
4640 last_stream = &redirect->next;
4642 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4643 q = strrchr(redirect->filename, '>');
4646 redirect->stream_type = STREAM_TYPE_REDIRECT;
4648 } else if (!av_strcasecmp(cmd, "URL")) {
4650 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4651 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4653 ERROR("No corresponding <Redirect> for </Redirect>\n");
4655 if (!redirect->feed_filename[0]) {
4656 ERROR("No URL found for <Redirect>\n");
4660 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4661 ERROR("Loadable modules no longer supported\n");
4663 ERROR("Incorrect keyword: '%s'\n", cmd);
4673 return AVERROR(EINVAL);
4678 static void handle_child_exit(int sig)
4683 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4686 for (feed = first_feed; feed; feed = feed->next) {
4687 if (feed->pid == pid) {
4688 int uptime = time(0) - feed->pid_start;
4691 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4694 /* Turn off any more restarts */
4695 feed->child_argv = 0;
4700 need_to_start_children = 1;
4703 static void opt_debug(void)
4706 logfilename[0] = '-';
4709 void show_help_default(const char *opt, const char *arg)
4711 printf("usage: ffserver [options]\n"
4712 "Hyper fast multi format Audio/Video streaming server\n");
4714 show_help_options(options, "Main options:", 0, 0, 0);
4717 static const OptionDef options[] = {
4718 #include "cmdutils_common_opts.h"
4719 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4720 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4721 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4725 int main(int argc, char **argv)
4727 struct sigaction sigact = { { 0 } };
4730 config_filename = av_strdup("/etc/ffserver.conf");
4732 parse_loglevel(argc, argv, options);
4734 avformat_network_init();
4736 show_banner(argc, argv, options);
4738 my_program_name = argv[0];
4740 parse_options(NULL, argc, argv, options, NULL);
4742 unsetenv("http_proxy"); /* Kill the http_proxy */
4744 av_lfg_init(&random_state, av_get_random_seed());
4746 sigact.sa_handler = handle_child_exit;
4747 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4748 sigaction(SIGCHLD, &sigact, 0);
4750 if ((ret = parse_ffconfig(config_filename)) < 0) {
4751 fprintf(stderr, "Error reading configuration file '%s': %s\n",
4752 config_filename, av_err2str(ret));
4755 av_freep(&config_filename);
4757 /* open log file if needed */
4758 if (logfilename[0] != '\0') {
4759 if (!strcmp(logfilename, "-"))
4762 logfile = fopen(logfilename, "a");
4763 av_log_set_callback(http_av_log);
4766 build_file_streams();
4768 build_feed_streams();
4770 compute_bandwidth();
4773 signal(SIGPIPE, SIG_IGN);
4775 if (http_server() < 0) {
4776 http_log("Could not start server\n");