2 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * multiple format streaming server based on the FFmpeg libraries
28 #define closesocket close
33 #include "libavformat/avformat.h"
34 // FIXME those are internal headers, ffserver _really_ shouldn't use them
35 #include "libavformat/ffm.h"
36 #include "libavformat/network.h"
37 #include "libavformat/os_support.h"
38 #include "libavformat/rtpdec.h"
39 #include "libavformat/rtpproto.h"
40 #include "libavformat/rtsp.h"
41 #include "libavformat/avio_internal.h"
42 #include "libavformat/internal.h"
43 #include "libavformat/url.h"
45 #include "libavutil/avassert.h"
46 #include "libavutil/avstring.h"
47 #include "libavutil/lfg.h"
48 #include "libavutil/dict.h"
49 #include "libavutil/intreadwrite.h"
50 #include "libavutil/mathematics.h"
51 #include "libavutil/pixdesc.h"
52 #include "libavutil/random_seed.h"
53 #include "libavutil/parseutils.h"
54 #include "libavutil/opt.h"
55 #include "libavutil/time.h"
60 #include <sys/ioctl.h>
71 const char program_name[] = "ffserver";
72 const int program_birth_year = 2000;
74 static const OptionDef options[];
77 HTTPSTATE_WAIT_REQUEST,
78 HTTPSTATE_SEND_HEADER,
79 HTTPSTATE_SEND_DATA_HEADER,
80 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
81 HTTPSTATE_SEND_DATA_TRAILER,
82 HTTPSTATE_RECEIVE_DATA,
83 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
86 RTSPSTATE_WAIT_REQUEST,
88 RTSPSTATE_SEND_PACKET,
91 static const char *http_state[] = {
107 #define MAX_STREAMS 20
109 #define IOBUFFER_INIT_SIZE 8192
111 /* timeouts are in ms */
112 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
113 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
115 #define SYNC_TIMEOUT (10 * 1000)
117 typedef struct RTSPActionServerSetup {
119 char transport_option[512];
120 } RTSPActionServerSetup;
123 int64_t count1, count2;
124 int64_t time1, time2;
127 /* context associated with one connection */
128 typedef struct HTTPContext {
129 enum HTTPState state;
130 int fd; /* socket file descriptor */
131 struct sockaddr_in from_addr; /* origin */
132 struct pollfd *poll_entry; /* used when polling */
134 uint8_t *buffer_ptr, *buffer_end;
137 int chunked_encoding;
138 int chunk_size; /* 0 if it needs to be read */
139 struct HTTPContext *next;
140 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
144 /* input format handling */
145 AVFormatContext *fmt_in;
146 int64_t start_time; /* In milliseconds - this wraps fairly often */
147 int64_t first_pts; /* initial pts value */
148 int64_t cur_pts; /* current pts value from the stream in us */
149 int64_t cur_frame_duration; /* duration of the current frame in us */
150 int cur_frame_bytes; /* output frame size, needed to compute
151 the time at which we send each
153 int pts_stream_index; /* stream we choose as clock reference */
154 int64_t cur_clock; /* current clock reference value in us */
155 /* output format handling */
156 struct FFStream *stream;
157 /* -1 is invalid stream */
158 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
159 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
161 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
162 int last_packet_sent; /* true if last data packet was sent */
164 DataRateData datarate;
171 int is_packetized; /* if true, the stream is packetized */
172 int packet_stream_index; /* current stream for output in state machine */
174 /* RTSP state specific */
175 uint8_t *pb_buffer; /* XXX: use that in all the code */
177 int seq; /* RTSP sequence number */
179 /* RTP state specific */
180 enum RTSPLowerTransport rtp_protocol;
181 char session_id[32]; /* session id */
182 AVFormatContext *rtp_ctx[MAX_STREAMS];
184 /* RTP/UDP specific */
185 URLContext *rtp_handles[MAX_STREAMS];
187 /* RTP/TCP specific */
188 struct HTTPContext *rtsp_c;
189 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
192 /* each generated stream is described here */
196 STREAM_TYPE_REDIRECT,
199 enum IPAddressAction {
204 typedef struct IPAddressACL {
205 struct IPAddressACL *next;
206 enum IPAddressAction action;
207 /* These are in host order */
208 struct in_addr first;
212 /* description of each stream of the ffserver.conf file */
213 typedef struct FFStream {
214 enum StreamType stream_type;
215 char filename[1024]; /* stream filename */
216 struct FFStream *feed; /* feed we are using (can be null if
218 AVDictionary *in_opts; /* input parameters */
219 AVInputFormat *ifmt; /* if non NULL, force input format */
222 char dynamic_acl[1024];
224 int prebuffer; /* Number of millseconds early to start */
225 int64_t max_time; /* Number of milliseconds to run */
227 AVStream *streams[MAX_STREAMS];
228 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
229 char feed_filename[1024]; /* file name of the feed storage, or
230 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_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
294 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
297 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
298 struct in_addr my_ip);
301 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
302 FFStream *stream, const char *session_id,
303 enum RTSPLowerTransport rtp_protocol);
304 static int rtp_new_av_stream(HTTPContext *c,
305 int stream_index, struct sockaddr_in *dest_addr,
306 HTTPContext *rtsp_c);
308 static const char *my_program_name;
310 static const char *config_filename;
312 static int ffserver_debug;
313 static int no_launch;
314 static int need_to_start_children;
316 /* maximum number of simultaneous HTTP connections */
317 static unsigned int nb_max_http_connections = 2000;
318 static unsigned int nb_max_connections = 5;
319 static unsigned int nb_connections;
321 static uint64_t max_bandwidth = 1000;
322 static uint64_t current_bandwidth;
324 static int64_t cur_time; // Making this global saves on passing it around everywhere
326 static AVLFG random_state;
328 static FILE *logfile = NULL;
330 static int64_t ffm_read_write_index(int fd)
334 if (lseek(fd, 8, SEEK_SET) < 0)
336 if (read(fd, buf, 8) != 8)
341 static int ffm_write_write_index(int fd, int64_t pos)
347 buf[i] = (pos >> (56 - i * 8)) & 0xff;
348 if (lseek(fd, 8, SEEK_SET) < 0)
350 if (write(fd, buf, 8) != 8)
355 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
358 FFMContext *ffm = s->priv_data;
359 ffm->write_index = pos;
360 ffm->file_size = file_size;
363 /* FIXME: make ffserver work with IPv6 */
364 /* resolve host with also IP address parsing */
365 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
368 if (!ff_inet_aton(hostname, sin_addr)) {
370 struct addrinfo *ai, *cur;
371 struct addrinfo hints = { 0 };
372 hints.ai_family = AF_INET;
373 if (getaddrinfo(hostname, NULL, &hints, &ai))
375 /* getaddrinfo returns a linked list of addrinfo structs.
376 * Even if we set ai_family = AF_INET above, make sure
377 * that the returned one actually is of the correct type. */
378 for (cur = ai; cur; cur = cur->ai_next) {
379 if (cur->ai_family == AF_INET) {
380 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
389 hp = gethostbyname(hostname);
392 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
398 static char *ctime1(char *buf2, int buf_size)
405 av_strlcpy(buf2, p, buf_size);
406 p = buf2 + strlen(p) - 1;
412 static void http_vlog(const char *fmt, va_list vargs)
414 static int print_prefix = 1;
418 ctime1(buf, sizeof(buf));
419 fprintf(logfile, "%s ", buf);
421 print_prefix = strstr(fmt, "\n") != NULL;
422 vfprintf(logfile, fmt, vargs);
428 __attribute__ ((format (printf, 1, 2)))
430 static void http_log(const char *fmt, ...)
433 va_start(vargs, fmt);
434 http_vlog(fmt, vargs);
438 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
440 static int print_prefix = 1;
441 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
442 if (level > av_log_get_level())
444 if (print_prefix && avc)
445 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
446 print_prefix = strstr(fmt, "\n") != NULL;
447 http_vlog(fmt, vargs);
450 static void log_connection(HTTPContext *c)
455 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
456 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
457 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
460 static void update_datarate(DataRateData *drd, int64_t count)
462 if (!drd->time1 && !drd->count1) {
463 drd->time1 = drd->time2 = cur_time;
464 drd->count1 = drd->count2 = count;
465 } else if (cur_time - drd->time2 > 5000) {
466 drd->time1 = drd->time2;
467 drd->count1 = drd->count2;
468 drd->time2 = cur_time;
473 /* In bytes per second */
474 static int compute_datarate(DataRateData *drd, int64_t count)
476 if (cur_time == drd->time1)
479 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
483 static void start_children(FFStream *feed)
488 for (; feed; feed = feed->next) {
489 if (feed->child_argv && !feed->pid) {
490 feed->pid_start = time(0);
495 http_log("Unable to create children\n");
504 av_strlcpy(pathname, my_program_name, sizeof(pathname));
506 slash = strrchr(pathname, '/');
511 strcpy(slash, "ffmpeg");
513 http_log("Launch command line: ");
514 http_log("%s ", pathname);
515 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
516 http_log("%s ", feed->child_argv[i]);
519 for (i = 3; i < 256; i++)
522 if (!ffserver_debug) {
523 if (!freopen("/dev/null", "r", stdin))
524 http_log("failed to redirect STDIN to /dev/null\n;");
525 if (!freopen("/dev/null", "w", stdout))
526 http_log("failed to redirect STDOUT to /dev/null\n;");
527 if (!freopen("/dev/null", "w", stderr))
528 http_log("failed to redirect STDERR to /dev/null\n;");
531 signal(SIGPIPE, SIG_DFL);
533 execvp(pathname, feed->child_argv);
541 /* open a listening socket */
542 static int socket_open_listen(struct sockaddr_in *my_addr)
546 server_fd = socket(AF_INET,SOCK_STREAM,0);
553 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
555 my_addr->sin_family = AF_INET;
556 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
558 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
560 closesocket(server_fd);
564 if (listen (server_fd, 5) < 0) {
566 closesocket(server_fd);
569 ff_socket_nonblock(server_fd, 1);
574 /* start all multicast streams */
575 static void start_multicast(void)
580 struct sockaddr_in dest_addr = {0};
581 int default_port, stream_index;
584 for(stream = first_stream; stream != NULL; stream = stream->next) {
585 if (stream->is_multicast) {
586 unsigned random0 = av_lfg_get(&random_state);
587 unsigned random1 = av_lfg_get(&random_state);
588 /* open the RTP connection */
589 snprintf(session_id, sizeof(session_id), "%08x%08x",
592 /* choose a port if none given */
593 if (stream->multicast_port == 0) {
594 stream->multicast_port = default_port;
598 dest_addr.sin_family = AF_INET;
599 dest_addr.sin_addr = stream->multicast_ip;
600 dest_addr.sin_port = htons(stream->multicast_port);
602 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
603 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
607 if (open_input_stream(rtp_c, "") < 0) {
608 http_log("Could not open input stream for stream '%s'\n",
613 /* open each RTP stream */
614 for(stream_index = 0; stream_index < stream->nb_streams;
616 dest_addr.sin_port = htons(stream->multicast_port +
618 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
619 http_log("Could not open output stream '%s/streamid=%d'\n",
620 stream->filename, stream_index);
625 /* change state to send data */
626 rtp_c->state = HTTPSTATE_SEND_DATA;
631 /* main loop of the http server */
632 static int http_server(void)
634 int server_fd = 0, rtsp_server_fd = 0;
635 int ret, delay, delay1;
636 struct pollfd *poll_table, *poll_entry;
637 HTTPContext *c, *c_next;
639 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
640 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
644 if (my_http_addr.sin_port) {
645 server_fd = socket_open_listen(&my_http_addr);
650 if (my_rtsp_addr.sin_port) {
651 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
652 if (rtsp_server_fd < 0)
656 if (!rtsp_server_fd && !server_fd) {
657 http_log("HTTP and RTSP disabled.\n");
661 http_log("FFserver started.\n");
663 start_children(first_feed);
668 poll_entry = poll_table;
670 poll_entry->fd = server_fd;
671 poll_entry->events = POLLIN;
674 if (rtsp_server_fd) {
675 poll_entry->fd = rtsp_server_fd;
676 poll_entry->events = POLLIN;
680 /* wait for events on each HTTP handle */
687 case HTTPSTATE_SEND_HEADER:
688 case RTSPSTATE_SEND_REPLY:
689 case RTSPSTATE_SEND_PACKET:
690 c->poll_entry = poll_entry;
692 poll_entry->events = POLLOUT;
695 case HTTPSTATE_SEND_DATA_HEADER:
696 case HTTPSTATE_SEND_DATA:
697 case HTTPSTATE_SEND_DATA_TRAILER:
698 if (!c->is_packetized) {
699 /* for TCP, we output as much as we can (may need to put a limit) */
700 c->poll_entry = poll_entry;
702 poll_entry->events = POLLOUT;
705 /* when ffserver is doing the timing, we work by
706 looking at which packet need to be sent every
708 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
713 case HTTPSTATE_WAIT_REQUEST:
714 case HTTPSTATE_RECEIVE_DATA:
715 case HTTPSTATE_WAIT_FEED:
716 case RTSPSTATE_WAIT_REQUEST:
717 /* need to catch errors */
718 c->poll_entry = poll_entry;
720 poll_entry->events = POLLIN;/* Maybe this will work */
724 c->poll_entry = NULL;
730 /* wait for an event on one connection. We poll at least every
731 second to handle timeouts */
733 ret = poll(poll_table, poll_entry - poll_table, delay);
734 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
735 ff_neterrno() != AVERROR(EINTR))
739 cur_time = av_gettime() / 1000;
741 if (need_to_start_children) {
742 need_to_start_children = 0;
743 start_children(first_feed);
746 /* now handle the events */
747 for(c = first_http_ctx; c != NULL; c = c_next) {
749 if (handle_connection(c) < 0) {
750 /* close and free the connection */
756 poll_entry = poll_table;
758 /* new HTTP connection request ? */
759 if (poll_entry->revents & POLLIN)
760 new_connection(server_fd, 0);
763 if (rtsp_server_fd) {
764 /* new RTSP connection request ? */
765 if (poll_entry->revents & POLLIN)
766 new_connection(rtsp_server_fd, 1);
771 /* start waiting for a new HTTP/RTSP request */
772 static void start_wait_request(HTTPContext *c, int is_rtsp)
774 c->buffer_ptr = c->buffer;
775 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
778 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
779 c->state = RTSPSTATE_WAIT_REQUEST;
781 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
782 c->state = HTTPSTATE_WAIT_REQUEST;
786 static void http_send_too_busy_reply(int fd)
789 int len = snprintf(buffer, sizeof(buffer),
790 "HTTP/1.0 503 Server too busy\r\n"
791 "Content-type: text/html\r\n"
793 "<html><head><title>Too busy</title></head><body>\r\n"
794 "<p>The server is too busy to serve your request at this time.</p>\r\n"
795 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
796 "</body></html>\r\n",
797 nb_connections, nb_max_connections);
798 av_assert0(len < sizeof(buffer));
799 send(fd, buffer, len, 0);
803 static void new_connection(int server_fd, int is_rtsp)
805 struct sockaddr_in from_addr;
808 HTTPContext *c = NULL;
810 len = sizeof(from_addr);
811 fd = accept(server_fd, (struct sockaddr *)&from_addr,
814 http_log("error during accept %s\n", strerror(errno));
817 ff_socket_nonblock(fd, 1);
819 if (nb_connections >= nb_max_connections) {
820 http_send_too_busy_reply(fd);
824 /* add a new connection */
825 c = av_mallocz(sizeof(HTTPContext));
830 c->poll_entry = NULL;
831 c->from_addr = from_addr;
832 c->buffer_size = IOBUFFER_INIT_SIZE;
833 c->buffer = av_malloc(c->buffer_size);
837 c->next = first_http_ctx;
841 start_wait_request(c, is_rtsp);
853 static void close_connection(HTTPContext *c)
855 HTTPContext **cp, *c1;
857 AVFormatContext *ctx;
861 /* remove connection from list */
862 cp = &first_http_ctx;
863 while ((*cp) != NULL) {
871 /* remove references, if any (XXX: do it faster) */
872 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
877 /* remove connection associated resources */
881 /* close each frame parser */
882 for(i=0;i<c->fmt_in->nb_streams;i++) {
883 st = c->fmt_in->streams[i];
884 if (st->codec->codec)
885 avcodec_close(st->codec);
887 avformat_close_input(&c->fmt_in);
890 /* free RTP output streams if any */
893 nb_streams = c->stream->nb_streams;
895 for(i=0;i<nb_streams;i++) {
898 av_write_trailer(ctx);
899 av_dict_free(&ctx->metadata);
900 av_free(ctx->streams[0]);
903 h = c->rtp_handles[i];
910 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
913 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
914 av_write_trailer(ctx);
915 av_freep(&c->pb_buffer);
916 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
921 for(i=0; i<ctx->nb_streams; i++)
922 av_free(ctx->streams[i]);
923 av_freep(&ctx->streams);
924 av_freep(&ctx->priv_data);
926 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
927 current_bandwidth -= c->stream->bandwidth;
929 /* signal that there is no feed if we are the feeder socket */
930 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
931 c->stream->feed_opened = 0;
935 av_freep(&c->pb_buffer);
936 av_freep(&c->packet_buffer);
942 static int handle_connection(HTTPContext *c)
947 case HTTPSTATE_WAIT_REQUEST:
948 case RTSPSTATE_WAIT_REQUEST:
950 if ((c->timeout - cur_time) < 0)
952 if (c->poll_entry->revents & (POLLERR | POLLHUP))
955 /* no need to read if no events */
956 if (!(c->poll_entry->revents & POLLIN))
960 len = recv(c->fd, c->buffer_ptr, 1, 0);
962 if (ff_neterrno() != AVERROR(EAGAIN) &&
963 ff_neterrno() != AVERROR(EINTR))
965 } else if (len == 0) {
968 /* search for end of request. */
970 c->buffer_ptr += len;
972 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
973 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
974 /* request found : parse it and reply */
975 if (c->state == HTTPSTATE_WAIT_REQUEST) {
976 ret = http_parse_request(c);
978 ret = rtsp_parse_request(c);
982 } else if (ptr >= c->buffer_end) {
983 /* request too long: cannot do anything */
985 } else goto read_loop;
989 case HTTPSTATE_SEND_HEADER:
990 if (c->poll_entry->revents & (POLLERR | POLLHUP))
993 /* no need to write if no events */
994 if (!(c->poll_entry->revents & POLLOUT))
996 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
998 if (ff_neterrno() != AVERROR(EAGAIN) &&
999 ff_neterrno() != AVERROR(EINTR)) {
1000 /* error : close connection */
1001 av_freep(&c->pb_buffer);
1005 c->buffer_ptr += len;
1007 c->stream->bytes_served += len;
1008 c->data_count += len;
1009 if (c->buffer_ptr >= c->buffer_end) {
1010 av_freep(&c->pb_buffer);
1011 /* if error, exit */
1014 /* all the buffer was sent : synchronize to the incoming stream */
1015 c->state = HTTPSTATE_SEND_DATA_HEADER;
1016 c->buffer_ptr = c->buffer_end = c->buffer;
1021 case HTTPSTATE_SEND_DATA:
1022 case HTTPSTATE_SEND_DATA_HEADER:
1023 case HTTPSTATE_SEND_DATA_TRAILER:
1024 /* for packetized output, we consider we can always write (the
1025 input streams sets the speed). It may be better to verify
1026 that we do not rely too much on the kernel queues */
1027 if (!c->is_packetized) {
1028 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1031 /* no need to read if no events */
1032 if (!(c->poll_entry->revents & POLLOUT))
1035 if (http_send_data(c) < 0)
1037 /* close connection if trailer sent */
1038 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1041 case HTTPSTATE_RECEIVE_DATA:
1042 /* no need to read if no events */
1043 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1045 if (!(c->poll_entry->revents & POLLIN))
1047 if (http_receive_data(c) < 0)
1050 case HTTPSTATE_WAIT_FEED:
1051 /* no need to read if no events */
1052 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1055 /* nothing to do, we'll be waken up by incoming feed packets */
1058 case RTSPSTATE_SEND_REPLY:
1059 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1060 av_freep(&c->pb_buffer);
1063 /* no need to write if no events */
1064 if (!(c->poll_entry->revents & POLLOUT))
1066 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1068 if (ff_neterrno() != AVERROR(EAGAIN) &&
1069 ff_neterrno() != AVERROR(EINTR)) {
1070 /* error : close connection */
1071 av_freep(&c->pb_buffer);
1075 c->buffer_ptr += len;
1076 c->data_count += len;
1077 if (c->buffer_ptr >= c->buffer_end) {
1078 /* all the buffer was sent : wait for a new request */
1079 av_freep(&c->pb_buffer);
1080 start_wait_request(c, 1);
1084 case RTSPSTATE_SEND_PACKET:
1085 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1086 av_freep(&c->packet_buffer);
1089 /* no need to write if no events */
1090 if (!(c->poll_entry->revents & POLLOUT))
1092 len = send(c->fd, c->packet_buffer_ptr,
1093 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1095 if (ff_neterrno() != AVERROR(EAGAIN) &&
1096 ff_neterrno() != AVERROR(EINTR)) {
1097 /* error : close connection */
1098 av_freep(&c->packet_buffer);
1102 c->packet_buffer_ptr += len;
1103 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1104 /* all the buffer was sent : wait for a new request */
1105 av_freep(&c->packet_buffer);
1106 c->state = RTSPSTATE_WAIT_REQUEST;
1110 case HTTPSTATE_READY:
1119 static int extract_rates(char *rates, int ratelen, const char *request)
1123 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1124 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1125 const char *q = p + 7;
1127 while (*q && *q != '\n' && av_isspace(*q))
1130 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1136 memset(rates, 0xff, ratelen);
1139 while (*q && *q != '\n' && *q != ':')
1142 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1146 if (stream_no < ratelen && stream_no >= 0)
1147 rates[stream_no] = rate_no;
1149 while (*q && *q != '\n' && !av_isspace(*q))
1156 p = strchr(p, '\n');
1166 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1169 int best_bitrate = 100000000;
1172 for (i = 0; i < feed->nb_streams; i++) {
1173 AVCodecContext *feed_codec = feed->streams[i]->codec;
1175 if (feed_codec->codec_id != codec->codec_id ||
1176 feed_codec->sample_rate != codec->sample_rate ||
1177 feed_codec->width != codec->width ||
1178 feed_codec->height != codec->height)
1181 /* Potential stream */
1183 /* We want the fastest stream less than bit_rate, or the slowest
1184 * faster than bit_rate
1187 if (feed_codec->bit_rate <= bit_rate) {
1188 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1189 best_bitrate = feed_codec->bit_rate;
1193 if (feed_codec->bit_rate < best_bitrate) {
1194 best_bitrate = feed_codec->bit_rate;
1203 static int modify_current_stream(HTTPContext *c, char *rates)
1206 FFStream *req = c->stream;
1207 int action_required = 0;
1209 /* Not much we can do for a feed */
1213 for (i = 0; i < req->nb_streams; i++) {
1214 AVCodecContext *codec = req->streams[i]->codec;
1218 c->switch_feed_streams[i] = req->feed_streams[i];
1221 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1224 /* Wants off or slow */
1225 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1227 /* This doesn't work well when it turns off the only stream! */
1228 c->switch_feed_streams[i] = -2;
1229 c->feed_streams[i] = -2;
1234 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1235 action_required = 1;
1238 return action_required;
1241 /* XXX: factorize in utils.c ? */
1242 /* XXX: take care with different space meaning */
1243 static void skip_spaces(const char **pp)
1247 while (*p == ' ' || *p == '\t')
1252 static void get_word(char *buf, int buf_size, const char **pp)
1260 while (!av_isspace(*p) && *p != '\0') {
1261 if ((q - buf) < buf_size - 1)
1270 static void get_arg(char *buf, int buf_size, const char **pp)
1277 while (av_isspace(*p)) p++;
1280 if (*p == '\"' || *p == '\'')
1292 if ((q - buf) < buf_size - 1)
1297 if (quote && *p == quote)
1302 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1303 const char *p, const char *filename, int line_num)
1309 get_arg(arg, sizeof(arg), &p);
1310 if (av_strcasecmp(arg, "allow") == 0)
1311 acl.action = IP_ALLOW;
1312 else if (av_strcasecmp(arg, "deny") == 0)
1313 acl.action = IP_DENY;
1315 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1316 filename, line_num, arg);
1320 get_arg(arg, sizeof(arg), &p);
1322 if (resolve_host(&acl.first, arg) != 0) {
1323 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1324 filename, line_num, arg);
1327 acl.last = acl.first;
1329 get_arg(arg, sizeof(arg), &p);
1332 if (resolve_host(&acl.last, arg) != 0) {
1333 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1334 filename, line_num, arg);
1340 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1341 IPAddressACL **naclp = 0;
1347 naclp = &stream->acl;
1353 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1354 filename, line_num);
1360 naclp = &(*naclp)->next;
1368 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1373 IPAddressACL *acl = NULL;
1377 f = fopen(stream->dynamic_acl, "r");
1379 perror(stream->dynamic_acl);
1383 acl = av_mallocz(sizeof(IPAddressACL));
1387 if (fgets(line, sizeof(line), f) == NULL)
1391 while (av_isspace(*p))
1393 if (*p == '\0' || *p == '#')
1395 get_arg(cmd, sizeof(cmd), &p);
1397 if (!av_strcasecmp(cmd, "ACL"))
1398 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1405 static void free_acl_list(IPAddressACL *in_acl)
1407 IPAddressACL *pacl,*pacl2;
1417 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1419 enum IPAddressAction last_action = IP_DENY;
1421 struct in_addr *src = &c->from_addr.sin_addr;
1422 unsigned long src_addr = src->s_addr;
1424 for (acl = in_acl; acl; acl = acl->next) {
1425 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1426 return (acl->action == IP_ALLOW) ? 1 : 0;
1427 last_action = acl->action;
1430 /* Nothing matched, so return not the last action */
1431 return (last_action == IP_DENY) ? 1 : 0;
1434 static int validate_acl(FFStream *stream, HTTPContext *c)
1440 /* if stream->acl is null validate_acl_list will return 1 */
1441 ret = validate_acl_list(stream->acl, c);
1443 if (stream->dynamic_acl[0]) {
1444 acl = parse_dynamic_acl(stream, c);
1446 ret = validate_acl_list(acl, c);
1454 /* compute the real filename of a file by matching it without its
1455 extensions to all the stream filenames */
1456 static void compute_real_filename(char *filename, int max_size)
1463 /* compute filename by matching without the file extensions */
1464 av_strlcpy(file1, filename, sizeof(file1));
1465 p = strrchr(file1, '.');
1468 for(stream = first_stream; stream != NULL; stream = stream->next) {
1469 av_strlcpy(file2, stream->filename, sizeof(file2));
1470 p = strrchr(file2, '.');
1473 if (!strcmp(file1, file2)) {
1474 av_strlcpy(filename, stream->filename, max_size);
1489 /* parse http request and prepare header */
1490 static int http_parse_request(HTTPContext *c)
1494 enum RedirType redir_type;
1496 char info[1024], filename[1024];
1500 const char *mime_type;
1504 const char *useragent = 0;
1507 get_word(cmd, sizeof(cmd), &p);
1508 av_strlcpy(c->method, cmd, sizeof(c->method));
1510 if (!strcmp(cmd, "GET"))
1512 else if (!strcmp(cmd, "POST"))
1517 get_word(url, sizeof(url), &p);
1518 av_strlcpy(c->url, url, sizeof(c->url));
1520 get_word(protocol, sizeof(protocol), (const char **)&p);
1521 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1524 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1527 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1529 /* find the filename and the optional info string in the request */
1530 p1 = strchr(url, '?');
1532 av_strlcpy(info, p1, sizeof(info));
1537 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1539 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1540 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1542 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1546 p = strchr(p, '\n');
1553 redir_type = REDIR_NONE;
1554 if (av_match_ext(filename, "asx")) {
1555 redir_type = REDIR_ASX;
1556 filename[strlen(filename)-1] = 'f';
1557 } else if (av_match_ext(filename, "asf") &&
1558 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1559 /* if this isn't WMP or lookalike, return the redirector file */
1560 redir_type = REDIR_ASF;
1561 } else if (av_match_ext(filename, "rpm,ram")) {
1562 redir_type = REDIR_RAM;
1563 strcpy(filename + strlen(filename)-2, "m");
1564 } else if (av_match_ext(filename, "rtsp")) {
1565 redir_type = REDIR_RTSP;
1566 compute_real_filename(filename, sizeof(filename) - 1);
1567 } else if (av_match_ext(filename, "sdp")) {
1568 redir_type = REDIR_SDP;
1569 compute_real_filename(filename, sizeof(filename) - 1);
1572 // "redirect" / request to index.html
1573 if (!strlen(filename))
1574 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1576 stream = first_stream;
1577 while (stream != NULL) {
1578 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1580 stream = stream->next;
1582 if (stream == NULL) {
1583 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1584 http_log("File '%s' not found\n", url);
1589 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1590 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1592 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1593 c->http_error = 301;
1595 snprintf(q, c->buffer_size,
1596 "HTTP/1.0 301 Moved\r\n"
1598 "Content-type: text/html\r\n"
1600 "<html><head><title>Moved</title></head><body>\r\n"
1601 "You should be <a href=\"%s\">redirected</a>.\r\n"
1602 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1604 /* prepare output buffer */
1605 c->buffer_ptr = c->buffer;
1607 c->state = HTTPSTATE_SEND_HEADER;
1611 /* If this is WMP, get the rate information */
1612 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1613 if (modify_current_stream(c, ratebuf)) {
1614 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1615 if (c->switch_feed_streams[i] >= 0)
1616 c->switch_feed_streams[i] = -1;
1621 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1622 current_bandwidth += stream->bandwidth;
1624 /* If already streaming this feed, do not let start another feeder. */
1625 if (stream->feed_opened) {
1626 snprintf(msg, sizeof(msg), "This feed is already being received.");
1627 http_log("Feed '%s' already being received\n", stream->feed_filename);
1631 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1632 c->http_error = 503;
1634 snprintf(q, c->buffer_size,
1635 "HTTP/1.0 503 Server too busy\r\n"
1636 "Content-type: text/html\r\n"
1638 "<html><head><title>Too busy</title></head><body>\r\n"
1639 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1640 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1641 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1642 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1644 /* prepare output buffer */
1645 c->buffer_ptr = c->buffer;
1647 c->state = HTTPSTATE_SEND_HEADER;
1651 if (redir_type != REDIR_NONE) {
1652 const char *hostinfo = 0;
1654 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1655 if (av_strncasecmp(p, "Host:", 5) == 0) {
1659 p = strchr(p, '\n');
1670 while (av_isspace(*hostinfo))
1673 eoh = strchr(hostinfo, '\n');
1675 if (eoh[-1] == '\r')
1678 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1679 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1680 hostbuf[eoh - hostinfo] = 0;
1682 c->http_error = 200;
1684 switch(redir_type) {
1686 snprintf(q, c->buffer_size,
1687 "HTTP/1.0 200 ASX Follows\r\n"
1688 "Content-type: video/x-ms-asf\r\n"
1690 "<ASX Version=\"3\">\r\n"
1691 //"<!-- Autogenerated by ffserver -->\r\n"
1692 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1693 "</ASX>\r\n", hostbuf, filename, info);
1697 snprintf(q, c->buffer_size,
1698 "HTTP/1.0 200 RAM Follows\r\n"
1699 "Content-type: audio/x-pn-realaudio\r\n"
1701 "# Autogenerated by ffserver\r\n"
1702 "http://%s/%s%s\r\n", hostbuf, filename, info);
1706 snprintf(q, c->buffer_size,
1707 "HTTP/1.0 200 ASF Redirect follows\r\n"
1708 "Content-type: video/x-ms-asf\r\n"
1711 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1716 char hostname[256], *p;
1717 /* extract only hostname */
1718 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1719 p = strrchr(hostname, ':');
1722 snprintf(q, c->buffer_size,
1723 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1724 /* XXX: incorrect mime type ? */
1725 "Content-type: application/x-rtsp\r\n"
1727 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1736 struct sockaddr_in my_addr;
1738 snprintf(q, c->buffer_size,
1739 "HTTP/1.0 200 OK\r\n"
1740 "Content-type: application/sdp\r\n"
1744 len = sizeof(my_addr);
1745 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1747 /* XXX: should use a dynamic buffer */
1748 sdp_data_size = prepare_sdp_description(stream,
1751 if (sdp_data_size > 0) {
1752 memcpy(q, sdp_data, sdp_data_size);
1764 /* prepare output buffer */
1765 c->buffer_ptr = c->buffer;
1767 c->state = HTTPSTATE_SEND_HEADER;
1773 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1777 stream->conns_served++;
1779 /* XXX: add there authenticate and IP match */
1782 /* if post, it means a feed is being sent */
1783 if (!stream->is_feed) {
1784 /* However it might be a status report from WMP! Let us log the
1785 * data as it might come in handy one day. */
1786 const char *logline = 0;
1789 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1790 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1794 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1795 client_id = strtol(p + 18, 0, 10);
1796 p = strchr(p, '\n');
1804 char *eol = strchr(logline, '\n');
1809 if (eol[-1] == '\r')
1811 http_log("%.*s\n", (int) (eol - logline), logline);
1812 c->suppress_log = 1;
1817 http_log("\nGot request:\n%s\n", c->buffer);
1820 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1823 /* Now we have to find the client_id */
1824 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1825 if (wmpc->wmp_client_id == client_id)
1829 if (wmpc && modify_current_stream(wmpc, ratebuf))
1830 wmpc->switch_pending = 1;
1833 snprintf(msg, sizeof(msg), "POST command not handled");
1837 if (http_start_receive_data(c) < 0) {
1838 snprintf(msg, sizeof(msg), "could not open feed");
1842 c->state = HTTPSTATE_RECEIVE_DATA;
1847 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1848 http_log("\nGot request:\n%s\n", c->buffer);
1851 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1854 /* open input stream */
1855 if (open_input_stream(c, info) < 0) {
1856 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1860 /* prepare http header */
1862 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1863 mime_type = c->stream->fmt->mime_type;
1865 mime_type = "application/x-octet-stream";
1866 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1868 /* for asf, we need extra headers */
1869 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1870 /* Need to allocate a client id */
1872 c->wmp_client_id = av_lfg_get(&random_state);
1874 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);
1876 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1877 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1878 q = c->buffer + strlen(c->buffer);
1880 /* prepare output buffer */
1882 c->buffer_ptr = c->buffer;
1884 c->state = HTTPSTATE_SEND_HEADER;
1887 c->http_error = 404;
1889 snprintf(q, c->buffer_size,
1890 "HTTP/1.0 404 Not Found\r\n"
1891 "Content-type: text/html\r\n"
1894 "<head><title>404 Not Found</title></head>\n"
1898 /* prepare output buffer */
1899 c->buffer_ptr = c->buffer;
1901 c->state = HTTPSTATE_SEND_HEADER;
1905 c->http_error = 200; /* horrible : we use this value to avoid
1906 going to the send data state */
1907 c->state = HTTPSTATE_SEND_HEADER;
1911 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1913 static const char suffix[] = " kMGTP";
1916 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1918 avio_printf(pb, "%"PRId64"%c", count, *s);
1921 static void compute_status(HTTPContext *c)
1930 if (avio_open_dyn_buf(&pb) < 0) {
1931 /* XXX: return an error ? */
1932 c->buffer_ptr = c->buffer;
1933 c->buffer_end = c->buffer;
1937 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1938 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1939 avio_printf(pb, "Pragma: no-cache\r\n");
1940 avio_printf(pb, "\r\n");
1942 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1943 if (c->stream->feed_filename[0])
1944 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1945 avio_printf(pb, "</head>\n<body>");
1946 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1948 avio_printf(pb, "<h2>Available Streams</h2>\n");
1949 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1950 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");
1951 stream = first_stream;
1952 while (stream != NULL) {
1953 char sfilename[1024];
1956 if (stream->feed != stream) {
1957 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1958 eosf = sfilename + strlen(sfilename);
1959 if (eosf - sfilename >= 4) {
1960 if (strcmp(eosf - 4, ".asf") == 0)
1961 strcpy(eosf - 4, ".asx");
1962 else if (strcmp(eosf - 3, ".rm") == 0)
1963 strcpy(eosf - 3, ".ram");
1964 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1965 /* generate a sample RTSP director if
1966 unicast. Generate an SDP redirector if
1968 eosf = strrchr(sfilename, '.');
1970 eosf = sfilename + strlen(sfilename);
1971 if (stream->is_multicast)
1972 strcpy(eosf, ".sdp");
1974 strcpy(eosf, ".rtsp");
1978 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1979 sfilename, stream->filename);
1980 avio_printf(pb, "<td align=right> %d <td align=right> ",
1981 stream->conns_served);
1982 fmt_bytecount(pb, stream->bytes_served);
1983 switch(stream->stream_type) {
1984 case STREAM_TYPE_LIVE: {
1985 int audio_bit_rate = 0;
1986 int video_bit_rate = 0;
1987 const char *audio_codec_name = "";
1988 const char *video_codec_name = "";
1989 const char *audio_codec_name_extra = "";
1990 const char *video_codec_name_extra = "";
1992 for(i=0;i<stream->nb_streams;i++) {
1993 AVStream *st = stream->streams[i];
1994 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1995 switch(st->codec->codec_type) {
1996 case AVMEDIA_TYPE_AUDIO:
1997 audio_bit_rate += st->codec->bit_rate;
1999 if (*audio_codec_name)
2000 audio_codec_name_extra = "...";
2001 audio_codec_name = codec->name;
2004 case AVMEDIA_TYPE_VIDEO:
2005 video_bit_rate += st->codec->bit_rate;
2007 if (*video_codec_name)
2008 video_codec_name_extra = "...";
2009 video_codec_name = codec->name;
2012 case AVMEDIA_TYPE_DATA:
2013 video_bit_rate += st->codec->bit_rate;
2019 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",
2022 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2023 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2025 avio_printf(pb, "<td>%s", stream->feed->filename);
2027 avio_printf(pb, "<td>%s", stream->feed_filename);
2028 avio_printf(pb, "\n");
2032 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2036 stream = stream->next;
2038 avio_printf(pb, "</table>\n");
2040 stream = first_stream;
2041 while (stream != NULL) {
2042 if (stream->feed == stream) {
2043 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2045 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2052 /* This is somewhat linux specific I guess */
2053 snprintf(ps_cmd, sizeof(ps_cmd),
2054 "ps -o \"%%cpu,cputime\" --no-headers %d",
2057 pid_stat = popen(ps_cmd, "r");
2062 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2064 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2072 avio_printf(pb, "<p>");
2074 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");
2076 for (i = 0; i < stream->nb_streams; i++) {
2077 AVStream *st = stream->streams[i];
2078 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2079 const char *type = "unknown";
2080 char parameters[64];
2084 switch(st->codec->codec_type) {
2085 case AVMEDIA_TYPE_AUDIO:
2087 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2089 case AVMEDIA_TYPE_VIDEO:
2091 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2092 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2097 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2098 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2100 avio_printf(pb, "</table>\n");
2103 stream = stream->next;
2106 /* connection status */
2107 avio_printf(pb, "<h2>Connection Status</h2>\n");
2109 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2110 nb_connections, nb_max_connections);
2112 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2113 current_bandwidth, max_bandwidth);
2115 avio_printf(pb, "<table>\n");
2116 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");
2117 c1 = first_http_ctx;
2119 while (c1 != NULL) {
2125 for (j = 0; j < c1->stream->nb_streams; j++) {
2126 if (!c1->stream->feed)
2127 bitrate += c1->stream->streams[j]->codec->bit_rate;
2128 else if (c1->feed_streams[j] >= 0)
2129 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2134 p = inet_ntoa(c1->from_addr.sin_addr);
2135 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2137 c1->stream ? c1->stream->filename : "",
2138 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2141 http_state[c1->state]);
2142 fmt_bytecount(pb, bitrate);
2143 avio_printf(pb, "<td align=right>");
2144 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2145 avio_printf(pb, "<td align=right>");
2146 fmt_bytecount(pb, c1->data_count);
2147 avio_printf(pb, "\n");
2150 avio_printf(pb, "</table>\n");
2155 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2156 avio_printf(pb, "</body>\n</html>\n");
2158 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2159 c->buffer_ptr = c->pb_buffer;
2160 c->buffer_end = c->pb_buffer + len;
2163 static int open_input_stream(HTTPContext *c, const char *info)
2166 char input_filename[1024];
2167 AVFormatContext *s = NULL;
2168 int buf_size, i, ret;
2171 /* find file name */
2172 if (c->stream->feed) {
2173 strcpy(input_filename, c->stream->feed->feed_filename);
2174 buf_size = FFM_PACKET_SIZE;
2175 /* compute position (absolute time) */
2176 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2177 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2179 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2180 int prebuffer = strtol(buf, 0, 10);
2181 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2183 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2185 strcpy(input_filename, c->stream->feed_filename);
2187 /* compute position (relative time) */
2188 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2189 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2194 if (input_filename[0] == '\0')
2198 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2199 http_log("could not open %s: %d\n", input_filename, ret);
2203 /* set buffer size */
2204 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2206 s->flags |= AVFMT_FLAG_GENPTS;
2208 if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
2209 http_log("Could not find stream info '%s'\n", input_filename);
2210 avformat_close_input(&s);
2214 /* choose stream as clock source (we favorize video stream if
2215 present) for packet sending */
2216 c->pts_stream_index = 0;
2217 for(i=0;i<c->stream->nb_streams;i++) {
2218 if (c->pts_stream_index == 0 &&
2219 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2220 c->pts_stream_index = i;
2224 if (c->fmt_in->iformat->read_seek)
2225 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2226 /* set the start time (needed for maxtime and RTP packet timing) */
2227 c->start_time = cur_time;
2228 c->first_pts = AV_NOPTS_VALUE;
2232 /* return the server clock (in us) */
2233 static int64_t get_server_clock(HTTPContext *c)
2235 /* compute current pts value from system time */
2236 return (cur_time - c->start_time) * 1000;
2239 /* return the estimated time at which the current packet must be sent
2241 static int64_t get_packet_send_clock(HTTPContext *c)
2243 int bytes_left, bytes_sent, frame_bytes;
2245 frame_bytes = c->cur_frame_bytes;
2246 if (frame_bytes <= 0)
2249 bytes_left = c->buffer_end - c->buffer_ptr;
2250 bytes_sent = frame_bytes - bytes_left;
2251 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2256 static int http_prepare_data(HTTPContext *c)
2259 AVFormatContext *ctx;
2261 av_freep(&c->pb_buffer);
2263 case HTTPSTATE_SEND_DATA_HEADER:
2264 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2265 av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2266 av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2267 av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2268 av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2270 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2272 for(i=0;i<c->stream->nb_streams;i++) {
2274 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2275 /* if file or feed, then just take streams from FFStream struct */
2276 if (!c->stream->feed ||
2277 c->stream->feed == c->stream)
2278 src = c->stream->streams[i];
2280 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2282 *(c->fmt_ctx.streams[i]) = *src;
2283 c->fmt_ctx.streams[i]->priv_data = 0;
2284 c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2285 AVStream, not in codec */
2287 /* set output format parameters */
2288 c->fmt_ctx.oformat = c->stream->fmt;
2289 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2291 c->got_key_frame = 0;
2293 /* prepare header and save header data in a stream */
2294 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2295 /* XXX: potential leak */
2298 c->fmt_ctx.pb->seekable = 0;
2301 * HACK to avoid mpeg ps muxer to spit many underflow errors
2302 * Default value from FFmpeg
2303 * Try to set it use configuration option
2305 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2307 if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2308 http_log("Error writing output header\n");
2311 av_dict_free(&c->fmt_ctx.metadata);
2313 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2314 c->buffer_ptr = c->pb_buffer;
2315 c->buffer_end = c->pb_buffer + len;
2317 c->state = HTTPSTATE_SEND_DATA;
2318 c->last_packet_sent = 0;
2320 case HTTPSTATE_SEND_DATA:
2321 /* find a new packet */
2322 /* read a packet from the input stream */
2323 if (c->stream->feed)
2324 ffm_set_write_index(c->fmt_in,
2325 c->stream->feed->feed_write_index,
2326 c->stream->feed->feed_size);
2328 if (c->stream->max_time &&
2329 c->stream->max_time + c->start_time - cur_time < 0)
2330 /* We have timed out */
2331 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2335 ret = av_read_frame(c->fmt_in, &pkt);
2337 if (c->stream->feed) {
2338 /* if coming from feed, it means we reached the end of the
2339 ffm file, so must wait for more data */
2340 c->state = HTTPSTATE_WAIT_FEED;
2341 return 1; /* state changed */
2342 } else if (ret == AVERROR(EAGAIN)) {
2343 /* input not ready, come back later */
2346 if (c->stream->loop) {
2347 avformat_close_input(&c->fmt_in);
2348 if (open_input_stream(c, "") < 0)
2353 /* must send trailer now because eof or error */
2354 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2358 int source_index = pkt.stream_index;
2359 /* update first pts if needed */
2360 if (c->first_pts == AV_NOPTS_VALUE) {
2361 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2362 c->start_time = cur_time;
2364 /* send it to the appropriate stream */
2365 if (c->stream->feed) {
2366 /* if coming from a feed, select the right stream */
2367 if (c->switch_pending) {
2368 c->switch_pending = 0;
2369 for(i=0;i<c->stream->nb_streams;i++) {
2370 if (c->switch_feed_streams[i] == pkt.stream_index)
2371 if (pkt.flags & AV_PKT_FLAG_KEY)
2372 c->switch_feed_streams[i] = -1;
2373 if (c->switch_feed_streams[i] >= 0)
2374 c->switch_pending = 1;
2377 for(i=0;i<c->stream->nb_streams;i++) {
2378 if (c->stream->feed_streams[i] == pkt.stream_index) {
2379 AVStream *st = c->fmt_in->streams[source_index];
2380 pkt.stream_index = i;
2381 if (pkt.flags & AV_PKT_FLAG_KEY &&
2382 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2383 c->stream->nb_streams == 1))
2384 c->got_key_frame = 1;
2385 if (!c->stream->send_on_key || c->got_key_frame)
2390 AVCodecContext *codec;
2391 AVStream *ist, *ost;
2393 ist = c->fmt_in->streams[source_index];
2394 /* specific handling for RTP: we use several
2395 output stream (one for each RTP
2396 connection). XXX: need more abstract handling */
2397 if (c->is_packetized) {
2398 /* compute send time and duration */
2399 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2400 c->cur_pts -= c->first_pts;
2401 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2402 /* find RTP context */
2403 c->packet_stream_index = pkt.stream_index;
2404 ctx = c->rtp_ctx[c->packet_stream_index];
2406 av_free_packet(&pkt);
2409 codec = ctx->streams[0]->codec;
2410 /* only one stream per RTP connection */
2411 pkt.stream_index = 0;
2415 codec = ctx->streams[pkt.stream_index]->codec;
2418 if (c->is_packetized) {
2419 int max_packet_size;
2420 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2421 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2423 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2424 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2426 ret = avio_open_dyn_buf(&ctx->pb);
2429 /* XXX: potential leak */
2432 ost = ctx->streams[pkt.stream_index];
2434 ctx->pb->seekable = 0;
2435 if (pkt.dts != AV_NOPTS_VALUE)
2436 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2437 if (pkt.pts != AV_NOPTS_VALUE)
2438 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2439 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2440 if (av_write_frame(ctx, &pkt) < 0) {
2441 http_log("Error writing frame to output\n");
2442 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2445 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2446 c->cur_frame_bytes = len;
2447 c->buffer_ptr = c->pb_buffer;
2448 c->buffer_end = c->pb_buffer + len;
2450 codec->frame_number++;
2452 av_free_packet(&pkt);
2456 av_free_packet(&pkt);
2461 case HTTPSTATE_SEND_DATA_TRAILER:
2462 /* last packet test ? */
2463 if (c->last_packet_sent || c->is_packetized)
2466 /* prepare header */
2467 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2468 /* XXX: potential leak */
2471 c->fmt_ctx.pb->seekable = 0;
2472 av_write_trailer(ctx);
2473 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2474 c->buffer_ptr = c->pb_buffer;
2475 c->buffer_end = c->pb_buffer + len;
2477 c->last_packet_sent = 1;
2483 /* should convert the format at the same time */
2484 /* send data starting at c->buffer_ptr to the output connection
2485 (either UDP or TCP connection) */
2486 static int http_send_data(HTTPContext *c)
2491 if (c->buffer_ptr >= c->buffer_end) {
2492 ret = http_prepare_data(c);
2496 /* state change requested */
2499 if (c->is_packetized) {
2500 /* RTP data output */
2501 len = c->buffer_end - c->buffer_ptr;
2503 /* fail safe - should never happen */
2505 c->buffer_ptr = c->buffer_end;
2508 len = (c->buffer_ptr[0] << 24) |
2509 (c->buffer_ptr[1] << 16) |
2510 (c->buffer_ptr[2] << 8) |
2512 if (len > (c->buffer_end - c->buffer_ptr))
2514 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2515 /* nothing to send yet: we can wait */
2519 c->data_count += len;
2520 update_datarate(&c->datarate, c->data_count);
2522 c->stream->bytes_served += len;
2524 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2525 /* RTP packets are sent inside the RTSP TCP connection */
2527 int interleaved_index, size;
2529 HTTPContext *rtsp_c;
2532 /* if no RTSP connection left, error */
2535 /* if already sending something, then wait. */
2536 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2538 if (avio_open_dyn_buf(&pb) < 0)
2540 interleaved_index = c->packet_stream_index * 2;
2541 /* RTCP packets are sent at odd indexes */
2542 if (c->buffer_ptr[1] == 200)
2543 interleaved_index++;
2544 /* write RTSP TCP header */
2546 header[1] = interleaved_index;
2547 header[2] = len >> 8;
2549 avio_write(pb, header, 4);
2550 /* write RTP packet data */
2552 avio_write(pb, c->buffer_ptr, len);
2553 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2554 /* prepare asynchronous TCP sending */
2555 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2556 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2557 c->buffer_ptr += len;
2559 /* send everything we can NOW */
2560 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2561 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2563 rtsp_c->packet_buffer_ptr += len;
2564 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2565 /* if we could not send all the data, we will
2566 send it later, so a new state is needed to
2567 "lock" the RTSP TCP connection */
2568 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2571 /* all data has been sent */
2572 av_freep(&c->packet_buffer);
2574 /* send RTP packet directly in UDP */
2576 ffurl_write(c->rtp_handles[c->packet_stream_index],
2577 c->buffer_ptr, len);
2578 c->buffer_ptr += len;
2579 /* here we continue as we can send several packets per 10 ms slot */
2582 /* TCP data output */
2583 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2585 if (ff_neterrno() != AVERROR(EAGAIN) &&
2586 ff_neterrno() != AVERROR(EINTR))
2587 /* error : close connection */
2592 c->buffer_ptr += len;
2594 c->data_count += len;
2595 update_datarate(&c->datarate, c->data_count);
2597 c->stream->bytes_served += len;
2605 static int http_start_receive_data(HTTPContext *c)
2609 if (c->stream->feed_opened)
2612 /* Don't permit writing to this one */
2613 if (c->stream->readonly)
2617 fd = open(c->stream->feed_filename, O_RDWR);
2619 http_log("Error opening feeder file: %s\n", strerror(errno));
2624 if (c->stream->truncate) {
2625 /* truncate feed file */
2626 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2627 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2628 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2629 http_log("Error truncating feed file: %s\n", strerror(errno));
2633 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2634 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2639 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2640 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2641 lseek(fd, 0, SEEK_SET);
2643 /* init buffer input */
2644 c->buffer_ptr = c->buffer;
2645 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2646 c->stream->feed_opened = 1;
2647 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2651 static int http_receive_data(HTTPContext *c)
2654 int len, loop_run = 0;
2656 while (c->chunked_encoding && !c->chunk_size &&
2657 c->buffer_end > c->buffer_ptr) {
2658 /* read chunk header, if present */
2659 len = recv(c->fd, c->buffer_ptr, 1, 0);
2662 if (ff_neterrno() != AVERROR(EAGAIN) &&
2663 ff_neterrno() != AVERROR(EINTR))
2664 /* error : close connection */
2667 } else if (len == 0) {
2668 /* end of connection : close it */
2670 } else if (c->buffer_ptr - c->buffer >= 2 &&
2671 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2672 c->chunk_size = strtol(c->buffer, 0, 16);
2673 if (c->chunk_size == 0) // end of stream
2675 c->buffer_ptr = c->buffer;
2677 } else if (++loop_run > 10) {
2678 /* no chunk header, abort */
2685 if (c->buffer_end > c->buffer_ptr) {
2686 len = recv(c->fd, c->buffer_ptr,
2687 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2689 if (ff_neterrno() != AVERROR(EAGAIN) &&
2690 ff_neterrno() != AVERROR(EINTR))
2691 /* error : close connection */
2693 } else if (len == 0)
2694 /* end of connection : close it */
2697 c->chunk_size -= len;
2698 c->buffer_ptr += len;
2699 c->data_count += len;
2700 update_datarate(&c->datarate, c->data_count);
2704 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2705 if (c->buffer[0] != 'f' ||
2706 c->buffer[1] != 'm') {
2707 http_log("Feed stream has become desynchronized -- disconnecting\n");
2712 if (c->buffer_ptr >= c->buffer_end) {
2713 FFStream *feed = c->stream;
2714 /* a packet has been received : write it in the store, except
2716 if (c->data_count > FFM_PACKET_SIZE) {
2717 /* XXX: use llseek or url_seek */
2718 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2719 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2720 http_log("Error writing to feed file: %s\n", strerror(errno));
2724 feed->feed_write_index += FFM_PACKET_SIZE;
2725 /* update file size */
2726 if (feed->feed_write_index > c->stream->feed_size)
2727 feed->feed_size = feed->feed_write_index;
2729 /* handle wrap around if max file size reached */
2730 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2731 feed->feed_write_index = FFM_PACKET_SIZE;
2734 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2735 http_log("Error writing index to feed file: %s\n", strerror(errno));
2739 /* wake up any waiting connections */
2740 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2741 if (c1->state == HTTPSTATE_WAIT_FEED &&
2742 c1->stream->feed == c->stream->feed)
2743 c1->state = HTTPSTATE_SEND_DATA;
2746 /* We have a header in our hands that contains useful data */
2747 AVFormatContext *s = avformat_alloc_context();
2749 AVInputFormat *fmt_in;
2755 /* use feed output format name to find corresponding input format */
2756 fmt_in = av_find_input_format(feed->fmt->name);
2760 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2761 0, NULL, NULL, NULL, NULL);
2765 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2770 /* Now we have the actual streams */
2771 if (s->nb_streams != feed->nb_streams) {
2772 avformat_close_input(&s);
2774 http_log("Feed '%s' stream number does not match registered feed\n",
2775 c->stream->feed_filename);
2779 for (i = 0; i < s->nb_streams; i++) {
2780 AVStream *fst = feed->streams[i];
2781 AVStream *st = s->streams[i];
2782 avcodec_copy_context(fst->codec, st->codec);
2785 avformat_close_input(&s);
2788 c->buffer_ptr = c->buffer;
2793 c->stream->feed_opened = 0;
2795 /* wake up any waiting connections to stop waiting for feed */
2796 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2797 if (c1->state == HTTPSTATE_WAIT_FEED &&
2798 c1->stream->feed == c->stream->feed)
2799 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2804 /********************************************************************/
2807 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2814 switch(error_number) {
2815 case RTSP_STATUS_OK:
2818 case RTSP_STATUS_METHOD:
2819 str = "Method Not Allowed";
2821 case RTSP_STATUS_BANDWIDTH:
2822 str = "Not Enough Bandwidth";
2824 case RTSP_STATUS_SESSION:
2825 str = "Session Not Found";
2827 case RTSP_STATUS_STATE:
2828 str = "Method Not Valid in This State";
2830 case RTSP_STATUS_AGGREGATE:
2831 str = "Aggregate operation not allowed";
2833 case RTSP_STATUS_ONLY_AGGREGATE:
2834 str = "Only aggregate operation allowed";
2836 case RTSP_STATUS_TRANSPORT:
2837 str = "Unsupported transport";
2839 case RTSP_STATUS_INTERNAL:
2840 str = "Internal Server Error";
2842 case RTSP_STATUS_SERVICE:
2843 str = "Service Unavailable";
2845 case RTSP_STATUS_VERSION:
2846 str = "RTSP Version not supported";
2849 str = "Unknown Error";
2853 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2854 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2856 /* output GMT time */
2859 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2860 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2863 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2865 rtsp_reply_header(c, error_number);
2866 avio_printf(c->pb, "\r\n");
2869 static int rtsp_parse_request(HTTPContext *c)
2871 const char *p, *p1, *p2;
2877 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2879 c->buffer_ptr[0] = '\0';
2882 get_word(cmd, sizeof(cmd), &p);
2883 get_word(url, sizeof(url), &p);
2884 get_word(protocol, sizeof(protocol), &p);
2886 av_strlcpy(c->method, cmd, sizeof(c->method));
2887 av_strlcpy(c->url, url, sizeof(c->url));
2888 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2890 if (avio_open_dyn_buf(&c->pb) < 0) {
2891 /* XXX: cannot do more */
2892 c->pb = NULL; /* safety */
2896 /* check version name */
2897 if (strcmp(protocol, "RTSP/1.0") != 0) {
2898 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2902 /* parse each header line */
2903 /* skip to next line */
2904 while (*p != '\n' && *p != '\0')
2908 while (*p != '\0') {
2909 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2913 if (p2 > p && p2[-1] == '\r')
2915 /* skip empty line */
2919 if (len > sizeof(line) - 1)
2920 len = sizeof(line) - 1;
2921 memcpy(line, p, len);
2923 ff_rtsp_parse_line(header, line, NULL, NULL);
2927 /* handle sequence number */
2928 c->seq = header->seq;
2930 if (!strcmp(cmd, "DESCRIBE"))
2931 rtsp_cmd_describe(c, url);
2932 else if (!strcmp(cmd, "OPTIONS"))
2933 rtsp_cmd_options(c, url);
2934 else if (!strcmp(cmd, "SETUP"))
2935 rtsp_cmd_setup(c, url, header);
2936 else if (!strcmp(cmd, "PLAY"))
2937 rtsp_cmd_play(c, url, header);
2938 else if (!strcmp(cmd, "PAUSE"))
2939 rtsp_cmd_pause(c, url, header);
2940 else if (!strcmp(cmd, "TEARDOWN"))
2941 rtsp_cmd_teardown(c, url, header);
2943 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2946 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2947 c->pb = NULL; /* safety */
2949 /* XXX: cannot do more */
2952 c->buffer_ptr = c->pb_buffer;
2953 c->buffer_end = c->pb_buffer + len;
2954 c->state = RTSPSTATE_SEND_REPLY;
2958 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2959 struct in_addr my_ip)
2961 AVFormatContext *avc;
2962 AVStream *avs = NULL;
2963 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2966 avc = avformat_alloc_context();
2967 if (avc == NULL || !rtp_format) {
2970 avc->oformat = rtp_format;
2971 av_dict_set(&avc->metadata, "title",
2972 stream->title[0] ? stream->title : "No Title", 0);
2973 avc->nb_streams = stream->nb_streams;
2974 if (stream->is_multicast) {
2975 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2976 inet_ntoa(stream->multicast_ip),
2977 stream->multicast_port, stream->multicast_ttl);
2979 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2982 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2983 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2985 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2986 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2989 for(i = 0; i < stream->nb_streams; i++) {
2990 avc->streams[i] = &avs[i];
2991 avc->streams[i]->codec = stream->streams[i]->codec;
2993 *pbuffer = av_mallocz(2048);
2994 av_sdp_create(&avc, 1, *pbuffer, 2048);
2997 av_free(avc->streams);
2998 av_dict_free(&avc->metadata);
3002 return strlen(*pbuffer);
3005 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3007 // rtsp_reply_header(c, RTSP_STATUS_OK);
3008 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3009 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3010 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3011 avio_printf(c->pb, "\r\n");
3014 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3022 struct sockaddr_in my_addr;
3024 /* find which url is asked */
3025 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3030 for(stream = first_stream; stream != NULL; stream = stream->next) {
3031 if (!stream->is_feed &&
3032 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3033 !strcmp(path, stream->filename)) {
3037 /* no stream found */
3038 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3042 /* prepare the media description in sdp format */
3044 /* get the host IP */
3045 len = sizeof(my_addr);
3046 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3047 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3048 if (content_length < 0) {
3049 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3052 rtsp_reply_header(c, RTSP_STATUS_OK);
3053 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3054 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3055 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3056 avio_printf(c->pb, "\r\n");
3057 avio_write(c->pb, content, content_length);
3061 static HTTPContext *find_rtp_session(const char *session_id)
3065 if (session_id[0] == '\0')
3068 for(c = first_http_ctx; c != NULL; c = c->next) {
3069 if (!strcmp(c->session_id, session_id))
3075 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3077 RTSPTransportField *th;
3080 for(i=0;i<h->nb_transports;i++) {
3081 th = &h->transports[i];
3082 if (th->lower_transport == lower_transport)
3088 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3089 RTSPMessageHeader *h)
3092 int stream_index, rtp_port, rtcp_port;
3097 RTSPTransportField *th;
3098 struct sockaddr_in dest_addr;
3099 RTSPActionServerSetup setup;
3101 /* find which url is asked */
3102 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3107 /* now check each stream */
3108 for(stream = first_stream; stream != NULL; stream = stream->next) {
3109 if (!stream->is_feed &&
3110 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3111 /* accept aggregate filenames only if single stream */
3112 if (!strcmp(path, stream->filename)) {
3113 if (stream->nb_streams != 1) {
3114 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3121 for(stream_index = 0; stream_index < stream->nb_streams;
3123 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3124 stream->filename, stream_index);
3125 if (!strcmp(path, buf))
3130 /* no stream found */
3131 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3135 /* generate session id if needed */
3136 if (h->session_id[0] == '\0') {
3137 unsigned random0 = av_lfg_get(&random_state);
3138 unsigned random1 = av_lfg_get(&random_state);
3139 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3143 /* find rtp session, and create it if none found */
3144 rtp_c = find_rtp_session(h->session_id);
3146 /* always prefer UDP */
3147 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3149 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3151 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3156 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3157 th->lower_transport);
3159 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3163 /* open input stream */
3164 if (open_input_stream(rtp_c, "") < 0) {
3165 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3170 /* test if stream is OK (test needed because several SETUP needs
3171 to be done for a given file) */
3172 if (rtp_c->stream != stream) {
3173 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3177 /* test if stream is already set up */
3178 if (rtp_c->rtp_ctx[stream_index]) {
3179 rtsp_reply_error(c, RTSP_STATUS_STATE);
3183 /* check transport */
3184 th = find_transport(h, rtp_c->rtp_protocol);
3185 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3186 th->client_port_min <= 0)) {
3187 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3191 /* setup default options */
3192 setup.transport_option[0] = '\0';
3193 dest_addr = rtp_c->from_addr;
3194 dest_addr.sin_port = htons(th->client_port_min);
3197 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3198 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3202 /* now everything is OK, so we can send the connection parameters */
3203 rtsp_reply_header(c, RTSP_STATUS_OK);
3205 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3207 switch(rtp_c->rtp_protocol) {
3208 case RTSP_LOWER_TRANSPORT_UDP:
3209 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3210 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3211 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3212 "client_port=%d-%d;server_port=%d-%d",
3213 th->client_port_min, th->client_port_max,
3214 rtp_port, rtcp_port);
3216 case RTSP_LOWER_TRANSPORT_TCP:
3217 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3218 stream_index * 2, stream_index * 2 + 1);
3223 if (setup.transport_option[0] != '\0')
3224 avio_printf(c->pb, ";%s", setup.transport_option);
3225 avio_printf(c->pb, "\r\n");
3228 avio_printf(c->pb, "\r\n");
3232 /* find an rtp connection by using the session ID. Check consistency
3234 static HTTPContext *find_rtp_session_with_url(const char *url,
3235 const char *session_id)
3243 rtp_c = find_rtp_session(session_id);
3247 /* find which url is asked */
3248 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3252 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3253 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3254 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3255 rtp_c->stream->filename, s);
3256 if(!strncmp(path, buf, sizeof(buf))) {
3257 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3262 if (len > 0 && path[len - 1] == '/' &&
3263 !strncmp(path, rtp_c->stream->filename, len - 1))
3268 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3272 rtp_c = find_rtp_session_with_url(url, h->session_id);
3274 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3278 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3279 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3280 rtp_c->state != HTTPSTATE_READY) {
3281 rtsp_reply_error(c, RTSP_STATUS_STATE);
3285 rtp_c->state = HTTPSTATE_SEND_DATA;
3287 /* now everything is OK, so we can send the connection parameters */
3288 rtsp_reply_header(c, RTSP_STATUS_OK);
3290 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3291 avio_printf(c->pb, "\r\n");
3294 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3298 rtp_c = find_rtp_session_with_url(url, h->session_id);
3300 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3304 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3305 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3306 rtsp_reply_error(c, RTSP_STATUS_STATE);
3310 rtp_c->state = HTTPSTATE_READY;
3311 rtp_c->first_pts = AV_NOPTS_VALUE;
3312 /* now everything is OK, so we can send the connection parameters */
3313 rtsp_reply_header(c, RTSP_STATUS_OK);
3315 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3316 avio_printf(c->pb, "\r\n");
3319 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3323 rtp_c = find_rtp_session_with_url(url, h->session_id);
3325 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3329 /* now everything is OK, so we can send the connection parameters */
3330 rtsp_reply_header(c, RTSP_STATUS_OK);
3332 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3333 avio_printf(c->pb, "\r\n");
3335 /* abort the session */
3336 close_connection(rtp_c);
3340 /********************************************************************/
3343 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3344 FFStream *stream, const char *session_id,
3345 enum RTSPLowerTransport rtp_protocol)
3347 HTTPContext *c = NULL;
3348 const char *proto_str;
3350 /* XXX: should output a warning page when coming
3351 close to the connection limit */
3352 if (nb_connections >= nb_max_connections)
3355 /* add a new connection */
3356 c = av_mallocz(sizeof(HTTPContext));
3361 c->poll_entry = NULL;
3362 c->from_addr = *from_addr;
3363 c->buffer_size = IOBUFFER_INIT_SIZE;
3364 c->buffer = av_malloc(c->buffer_size);
3369 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3370 c->state = HTTPSTATE_READY;
3371 c->is_packetized = 1;
3372 c->rtp_protocol = rtp_protocol;
3374 /* protocol is shown in statistics */
3375 switch(c->rtp_protocol) {
3376 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3377 proto_str = "MCAST";
3379 case RTSP_LOWER_TRANSPORT_UDP:
3382 case RTSP_LOWER_TRANSPORT_TCP:
3389 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3390 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3392 current_bandwidth += stream->bandwidth;
3394 c->next = first_http_ctx;
3406 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3407 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3409 static int rtp_new_av_stream(HTTPContext *c,
3410 int stream_index, struct sockaddr_in *dest_addr,
3411 HTTPContext *rtsp_c)
3413 AVFormatContext *ctx;
3416 URLContext *h = NULL;
3418 int max_packet_size;
3420 /* now we can open the relevant output stream */
3421 ctx = avformat_alloc_context();
3424 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3426 st = av_mallocz(sizeof(AVStream));
3429 ctx->nb_streams = 1;
3430 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3433 ctx->streams[0] = st;
3435 if (!c->stream->feed ||
3436 c->stream->feed == c->stream)
3437 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3440 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3442 st->priv_data = NULL;
3444 /* build destination RTP address */
3445 ipaddr = inet_ntoa(dest_addr->sin_addr);
3447 switch(c->rtp_protocol) {
3448 case RTSP_LOWER_TRANSPORT_UDP:
3449 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3452 /* XXX: also pass as parameter to function ? */
3453 if (c->stream->is_multicast) {
3455 ttl = c->stream->multicast_ttl;
3458 snprintf(ctx->filename, sizeof(ctx->filename),
3459 "rtp://%s:%d?multicast=1&ttl=%d",
3460 ipaddr, ntohs(dest_addr->sin_port), ttl);
3462 snprintf(ctx->filename, sizeof(ctx->filename),
3463 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3466 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3468 c->rtp_handles[stream_index] = h;
3469 max_packet_size = h->max_packet_size;
3471 case RTSP_LOWER_TRANSPORT_TCP:
3474 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3480 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3481 ipaddr, ntohs(dest_addr->sin_port),
3482 c->stream->filename, stream_index, c->protocol);
3484 /* normally, no packets should be output here, but the packet size may be checked */
3485 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3486 /* XXX: close stream */
3489 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 the streams.
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 http_log("Opening file '%s'\n", stream->feed_filename);
3664 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3665 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3666 /* remove stream (no need to spend more time on it) */
3668 remove_stream(stream);
3670 /* find all the AVStreams inside and reference them in
3672 if (avformat_find_stream_info(infile, NULL) < 0) {
3673 http_log("Could not find codec parameters from '%s'\n",
3674 stream->feed_filename);
3675 avformat_close_input(&infile);
3678 extract_mpeg4_header(infile);
3680 for(i=0;i<infile->nb_streams;i++)
3681 add_av_stream1(stream, infile->streams[i]->codec, 1);
3683 avformat_close_input(&infile);
3689 /* compute the needed AVStream for each feed */
3690 static void build_feed_streams(void)
3692 FFStream *stream, *feed;
3695 /* gather all streams */
3696 for(stream = first_stream; stream != NULL; stream = stream->next) {
3697 feed = stream->feed;
3699 if (stream->is_feed) {
3700 for(i=0;i<stream->nb_streams;i++)
3701 stream->feed_streams[i] = i;
3703 /* we handle a stream coming from a feed */
3704 for(i=0;i<stream->nb_streams;i++)
3705 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3710 /* create feed files if needed */
3711 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3714 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3715 /* See if it matches */
3716 AVFormatContext *s = NULL;
3719 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3720 /* set buffer size */
3721 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3722 /* Now see if it matches */
3723 if (s->nb_streams == feed->nb_streams) {
3725 for(i=0;i<s->nb_streams;i++) {
3727 sf = feed->streams[i];
3730 if (sf->index != ss->index ||
3732 http_log("Index & Id do not match for stream %d (%s)\n",
3733 i, feed->feed_filename);
3736 AVCodecContext *ccf, *ccs;
3740 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3742 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3743 http_log("Codecs do not match for stream %d\n", i);
3745 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3746 http_log("Codec bitrates do not match for stream %d\n", i);
3748 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3749 if (CHECK_CODEC(time_base.den) ||
3750 CHECK_CODEC(time_base.num) ||
3751 CHECK_CODEC(width) ||
3752 CHECK_CODEC(height)) {
3753 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3756 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3757 if (CHECK_CODEC(sample_rate) ||
3758 CHECK_CODEC(channels) ||
3759 CHECK_CODEC(frame_size)) {
3760 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3764 http_log("Unknown codec type\n");
3772 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3773 feed->feed_filename, s->nb_streams, feed->nb_streams);
3775 avformat_close_input(&s);
3777 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3778 feed->feed_filename);
3781 if (feed->readonly) {
3782 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3783 feed->feed_filename);
3786 unlink(feed->feed_filename);
3789 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3790 AVFormatContext s1 = {0}, *s = &s1;
3792 if (feed->readonly) {
3793 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3794 feed->feed_filename);
3798 /* only write the header of the ffm file */
3799 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3800 http_log("Could not open output feed file '%s'\n",
3801 feed->feed_filename);
3804 s->oformat = feed->fmt;
3805 s->nb_streams = feed->nb_streams;
3806 s->streams = feed->streams;
3807 if (avformat_write_header(s, NULL) < 0) {
3808 http_log("Container doesn't support the required parameters\n");
3811 /* XXX: need better api */
3812 av_freep(&s->priv_data);
3815 /* get feed size and write index */
3816 fd = open(feed->feed_filename, O_RDONLY);
3818 http_log("Could not open output feed file '%s'\n",
3819 feed->feed_filename);
3823 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3824 feed->feed_size = lseek(fd, 0, SEEK_END);
3825 /* ensure that we do not wrap before the end of file */
3826 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3827 feed->feed_max_size = feed->feed_size;
3833 /* compute the bandwidth used by each stream */
3834 static void compute_bandwidth(void)
3840 for(stream = first_stream; stream != NULL; stream = stream->next) {
3842 for(i=0;i<stream->nb_streams;i++) {
3843 AVStream *st = stream->streams[i];
3844 switch(st->codec->codec_type) {
3845 case AVMEDIA_TYPE_AUDIO:
3846 case AVMEDIA_TYPE_VIDEO:
3847 bandwidth += st->codec->bit_rate;
3853 stream->bandwidth = (bandwidth + 999) / 1000;
3857 /* add a codec and set the default parameters */
3858 static void add_codec(FFStream *stream, AVCodecContext *av)
3862 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3865 /* compute default parameters */
3866 switch(av->codec_type) {
3867 case AVMEDIA_TYPE_AUDIO:
3868 if (av->bit_rate == 0)
3869 av->bit_rate = 64000;
3870 if (av->sample_rate == 0)
3871 av->sample_rate = 22050;
3872 if (av->channels == 0)
3875 case AVMEDIA_TYPE_VIDEO:
3876 if (av->bit_rate == 0)
3877 av->bit_rate = 64000;
3878 if (av->time_base.num == 0){
3879 av->time_base.den = 5;
3880 av->time_base.num = 1;
3882 if (av->width == 0 || av->height == 0) {
3886 /* Bitrate tolerance is less for streaming */
3887 if (av->bit_rate_tolerance == 0)
3888 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3889 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3894 if (av->max_qdiff == 0)
3896 av->qcompress = 0.5;
3899 if (!av->nsse_weight)
3900 av->nsse_weight = 8;
3902 av->frame_skip_cmp = FF_CMP_DCTMAX;
3904 av->me_method = ME_EPZS;
3905 av->rc_buffer_aggressivity = 1.0;
3908 av->rc_eq = av_strdup("tex^qComp");
3909 if (!av->i_quant_factor)
3910 av->i_quant_factor = -0.8;
3911 if (!av->b_quant_factor)
3912 av->b_quant_factor = 1.25;
3913 if (!av->b_quant_offset)
3914 av->b_quant_offset = 1.25;
3915 if (!av->rc_max_rate)
3916 av->rc_max_rate = av->bit_rate * 2;
3918 if (av->rc_max_rate && !av->rc_buffer_size) {
3919 av->rc_buffer_size = av->rc_max_rate;
3928 st = av_mallocz(sizeof(AVStream));
3931 st->codec = avcodec_alloc_context3(NULL);
3932 stream->streams[stream->nb_streams++] = st;
3933 memcpy(st->codec, av, sizeof(AVCodecContext));
3936 static enum AVCodecID opt_audio_codec(const char *arg)
3938 AVCodec *p= avcodec_find_encoder_by_name(arg);
3940 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3941 return AV_CODEC_ID_NONE;
3946 static enum AVCodecID opt_video_codec(const char *arg)
3948 AVCodec *p= avcodec_find_encoder_by_name(arg);
3950 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3951 return AV_CODEC_ID_NONE;
3956 static int ffserver_opt_default(const char *opt, const char *arg,
3957 AVCodecContext *avctx, int type)
3960 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3962 ret = av_opt_set(avctx, opt, arg, 0);
3966 static int ffserver_opt_preset(const char *arg,
3967 AVCodecContext *avctx, int type,
3968 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3971 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3973 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3975 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3976 codec ? codec->name : NULL))) {
3977 fprintf(stderr, "File for preset '%s' not found\n", arg);
3982 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3983 if(line[0] == '#' && !e)
3985 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3987 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3991 if(!strcmp(tmp, "acodec")){
3992 *audio_id = opt_audio_codec(tmp2);
3993 }else if(!strcmp(tmp, "vcodec")){
3994 *video_id = opt_video_codec(tmp2);
3995 }else if(!strcmp(tmp, "scodec")){
3996 /* opt_subtitle_codec(tmp2); */
3997 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3998 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4009 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4010 const char *mime_type)
4012 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4015 AVOutputFormat *stream_fmt;
4016 char stream_format_name[64];
4018 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4019 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4028 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4032 fprintf(stderr, "%s:%d: ", filename, line_num);
4033 vfprintf(stderr, fmt, vl);
4039 static int parse_ffconfig(const char *filename)
4046 int val, errors, line_num;
4047 FFStream **last_stream, *stream, *redirect;
4048 FFStream **last_feed, *feed, *s;
4049 AVCodecContext audio_enc, video_enc;
4050 enum AVCodecID audio_id, video_id;
4052 f = fopen(filename, "r");
4060 first_stream = NULL;
4061 last_stream = &first_stream;
4063 last_feed = &first_feed;
4067 audio_id = AV_CODEC_ID_NONE;
4068 video_id = AV_CODEC_ID_NONE;
4070 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4072 if (fgets(line, sizeof(line), f) == NULL)
4076 while (av_isspace(*p))
4078 if (*p == '\0' || *p == '#')
4081 get_arg(cmd, sizeof(cmd), &p);
4083 if (!av_strcasecmp(cmd, "Port")) {
4084 get_arg(arg, sizeof(arg), &p);
4086 if (val < 1 || val > 65536) {
4087 ERROR("Invalid_port: %s\n", arg);
4089 my_http_addr.sin_port = htons(val);
4090 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4091 get_arg(arg, sizeof(arg), &p);
4092 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4093 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4095 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4096 // do nothing here, its the default now
4097 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4098 get_arg(arg, sizeof(arg), &p);
4100 if (val < 1 || val > 65536) {
4101 ERROR("%s:%d: Invalid port: %s\n", arg);
4103 my_rtsp_addr.sin_port = htons(atoi(arg));
4104 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4105 get_arg(arg, sizeof(arg), &p);
4106 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4107 ERROR("Invalid host/IP address: %s\n", arg);
4109 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4110 get_arg(arg, sizeof(arg), &p);
4112 if (val < 1 || val > 65536) {
4113 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4115 nb_max_http_connections = val;
4116 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4117 get_arg(arg, sizeof(arg), &p);
4119 if (val < 1 || val > nb_max_http_connections) {
4120 ERROR("Invalid MaxClients: %s\n", arg);
4122 nb_max_connections = val;
4124 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4126 get_arg(arg, sizeof(arg), &p);
4127 llval = strtoll(arg, NULL, 10);
4128 if (llval < 10 || llval > 10000000) {
4129 ERROR("Invalid MaxBandwidth: %s\n", arg);
4131 max_bandwidth = llval;
4132 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4133 if (!ffserver_debug)
4134 get_arg(logfilename, sizeof(logfilename), &p);
4135 } else if (!av_strcasecmp(cmd, "<Feed")) {
4136 /*********************************************/
4137 /* Feed related options */
4139 if (stream || feed) {
4140 ERROR("Already in a tag\n");
4142 feed = av_mallocz(sizeof(FFStream));
4143 get_arg(feed->filename, sizeof(feed->filename), &p);
4144 q = strrchr(feed->filename, '>');
4148 for (s = first_feed; s; s = s->next) {
4149 if (!strcmp(feed->filename, s->filename)) {
4150 ERROR("Feed '%s' already registered\n", s->filename);
4154 feed->fmt = av_guess_format("ffm", NULL, NULL);
4155 /* defaut feed file */
4156 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4157 "/tmp/%s.ffm", feed->filename);
4158 feed->feed_max_size = 5 * 1024 * 1024;
4160 feed->feed = feed; /* self feeding :-) */
4162 /* add in stream list */
4163 *last_stream = feed;
4164 last_stream = &feed->next;
4165 /* add in feed list */
4167 last_feed = &feed->next_feed;
4169 } else if (!av_strcasecmp(cmd, "Launch")) {
4173 feed->child_argv = av_mallocz(64 * sizeof(char *));
4175 for (i = 0; i < 62; i++) {
4176 get_arg(arg, sizeof(arg), &p);
4180 feed->child_argv[i] = av_strdup(arg);
4183 feed->child_argv[i] = av_asprintf("http://%s:%d/%s",
4184 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4185 inet_ntoa(my_http_addr.sin_addr),
4186 ntohs(my_http_addr.sin_port), feed->filename);
4188 } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
4190 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4192 } else if (stream) {
4193 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4195 } else if (!av_strcasecmp(cmd, "File")) {
4197 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4199 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4200 } else if (!av_strcasecmp(cmd, "Truncate")) {
4202 get_arg(arg, sizeof(arg), &p);
4203 feed->truncate = strtod(arg, NULL);
4205 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4210 get_arg(arg, sizeof(arg), &p);
4212 fsize = strtod(p1, &p1);
4213 switch(av_toupper(*p1)) {
4218 fsize *= 1024 * 1024;
4221 fsize *= 1024 * 1024 * 1024;
4224 feed->feed_max_size = (int64_t)fsize;
4225 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4226 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4229 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4231 ERROR("No corresponding <Feed> for </Feed>\n");
4234 } else if (!av_strcasecmp(cmd, "<Stream")) {
4235 /*********************************************/
4236 /* Stream related options */
4238 if (stream || feed) {
4239 ERROR("Already in a tag\n");
4242 stream = av_mallocz(sizeof(FFStream));
4243 get_arg(stream->filename, sizeof(stream->filename), &p);
4244 q = strrchr(stream->filename, '>');
4248 for (s = first_stream; s; s = s->next) {
4249 if (!strcmp(stream->filename, s->filename)) {
4250 ERROR("Stream '%s' already registered\n", s->filename);
4254 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4255 avcodec_get_context_defaults3(&video_enc, NULL);
4256 avcodec_get_context_defaults3(&audio_enc, NULL);
4258 audio_id = AV_CODEC_ID_NONE;
4259 video_id = AV_CODEC_ID_NONE;
4261 audio_id = stream->fmt->audio_codec;
4262 video_id = stream->fmt->video_codec;
4265 *last_stream = stream;
4266 last_stream = &stream->next;
4268 } else if (!av_strcasecmp(cmd, "Feed")) {
4269 get_arg(arg, sizeof(arg), &p);
4274 while (sfeed != NULL) {
4275 if (!strcmp(sfeed->filename, arg))
4277 sfeed = sfeed->next_feed;
4280 ERROR("feed '%s' not defined\n", arg);
4282 stream->feed = sfeed;
4284 } else if (!av_strcasecmp(cmd, "Format")) {
4285 get_arg(arg, sizeof(arg), &p);
4287 if (!strcmp(arg, "status")) {
4288 stream->stream_type = STREAM_TYPE_STATUS;
4291 stream->stream_type = STREAM_TYPE_LIVE;
4292 /* jpeg cannot be used here, so use single frame jpeg */
4293 if (!strcmp(arg, "jpeg"))
4294 strcpy(arg, "mjpeg");
4295 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4297 ERROR("Unknown Format: %s\n", arg);
4301 audio_id = stream->fmt->audio_codec;
4302 video_id = stream->fmt->video_codec;
4305 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4306 get_arg(arg, sizeof(arg), &p);
4308 stream->ifmt = av_find_input_format(arg);
4309 if (!stream->ifmt) {
4310 ERROR("Unknown input format: %s\n", arg);
4313 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4314 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4315 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4317 ERROR("FaviconURL only permitted for status streams\n");
4319 } else if (!av_strcasecmp(cmd, "Author")) {
4321 get_arg(stream->author, sizeof(stream->author), &p);
4322 } else if (!av_strcasecmp(cmd, "Comment")) {
4324 get_arg(stream->comment, sizeof(stream->comment), &p);
4325 } else if (!av_strcasecmp(cmd, "Copyright")) {
4327 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4328 } else if (!av_strcasecmp(cmd, "Title")) {
4330 get_arg(stream->title, sizeof(stream->title), &p);
4331 } else if (!av_strcasecmp(cmd, "Preroll")) {
4332 get_arg(arg, sizeof(arg), &p);
4334 stream->prebuffer = atof(arg) * 1000;
4335 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4337 stream->send_on_key = 1;
4338 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4339 get_arg(arg, sizeof(arg), &p);
4340 audio_id = opt_audio_codec(arg);
4341 if (audio_id == AV_CODEC_ID_NONE) {
4342 ERROR("Unknown AudioCodec: %s\n", arg);
4344 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4345 get_arg(arg, sizeof(arg), &p);
4346 video_id = opt_video_codec(arg);
4347 if (video_id == AV_CODEC_ID_NONE) {
4348 ERROR("Unknown VideoCodec: %s\n", arg);
4350 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4351 get_arg(arg, sizeof(arg), &p);
4353 stream->max_time = atof(arg) * 1000;
4354 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4355 get_arg(arg, sizeof(arg), &p);
4357 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4358 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4359 get_arg(arg, sizeof(arg), &p);
4361 audio_enc.channels = atoi(arg);
4362 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4363 get_arg(arg, sizeof(arg), &p);
4365 audio_enc.sample_rate = atoi(arg);
4366 } else if (!av_strcasecmp(cmd, "AudioQuality")) {
4367 get_arg(arg, sizeof(arg), &p);
4369 // audio_enc.quality = atof(arg) * 1000;
4371 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4373 int minrate, maxrate;
4375 get_arg(arg, sizeof(arg), &p);
4377 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4378 video_enc.rc_min_rate = minrate * 1000;
4379 video_enc.rc_max_rate = maxrate * 1000;
4381 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4384 } else if (!av_strcasecmp(cmd, "Debug")) {
4386 get_arg(arg, sizeof(arg), &p);
4387 video_enc.debug = strtol(arg,0,0);
4389 } else if (!av_strcasecmp(cmd, "Strict")) {
4391 get_arg(arg, sizeof(arg), &p);
4392 video_enc.strict_std_compliance = atoi(arg);
4394 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4396 get_arg(arg, sizeof(arg), &p);
4397 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4399 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4401 get_arg(arg, sizeof(arg), &p);
4402 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4404 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4405 get_arg(arg, sizeof(arg), &p);
4407 video_enc.bit_rate = atoi(arg) * 1000;
4409 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4410 get_arg(arg, sizeof(arg), &p);
4412 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4413 if ((video_enc.width % 16) != 0 ||
4414 (video_enc.height % 16) != 0) {
4415 ERROR("Image size must be a multiple of 16\n");
4418 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4419 get_arg(arg, sizeof(arg), &p);
4421 AVRational frame_rate;
4422 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4423 ERROR("Incorrect frame rate: %s\n", arg);
4425 video_enc.time_base.num = frame_rate.den;
4426 video_enc.time_base.den = frame_rate.num;
4429 } else if (!av_strcasecmp(cmd, "PixelFormat")) {
4430 get_arg(arg, sizeof(arg), &p);
4432 video_enc.pix_fmt = av_get_pix_fmt(arg);
4433 if (video_enc.pix_fmt == AV_PIX_FMT_NONE) {
4434 ERROR("Unknown pixel format: %s\n", arg);
4437 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4438 get_arg(arg, sizeof(arg), &p);
4440 video_enc.gop_size = atoi(arg);
4441 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4443 video_enc.gop_size = 1;
4444 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4446 video_enc.mb_decision = FF_MB_DECISION_BITS;
4447 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4449 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4450 video_enc.flags |= CODEC_FLAG_4MV;
4452 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4453 !av_strcasecmp(cmd, "AVOptionAudio")) {
4455 AVCodecContext *avctx;
4457 get_arg(arg, sizeof(arg), &p);
4458 get_arg(arg2, sizeof(arg2), &p);
4459 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4461 type = AV_OPT_FLAG_VIDEO_PARAM;
4464 type = AV_OPT_FLAG_AUDIO_PARAM;
4466 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4467 ERROR("AVOption error: %s %s\n", arg, arg2);
4469 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4470 !av_strcasecmp(cmd, "AVPresetAudio")) {
4471 AVCodecContext *avctx;
4473 get_arg(arg, sizeof(arg), &p);
4474 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4476 video_enc.codec_id = video_id;
4477 type = AV_OPT_FLAG_VIDEO_PARAM;
4480 audio_enc.codec_id = audio_id;
4481 type = AV_OPT_FLAG_AUDIO_PARAM;
4483 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4484 ERROR("AVPreset error: %s\n", arg);
4486 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4487 get_arg(arg, sizeof(arg), &p);
4488 if ((strlen(arg) == 4) && stream)
4489 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4490 } else if (!av_strcasecmp(cmd, "BitExact")) {
4492 video_enc.flags |= CODEC_FLAG_BITEXACT;
4493 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4495 video_enc.dct_algo = FF_DCT_FASTINT;
4496 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4498 video_enc.idct_algo = FF_IDCT_SIMPLE;
4499 } else if (!av_strcasecmp(cmd, "Qscale")) {
4500 get_arg(arg, sizeof(arg), &p);
4502 video_enc.flags |= CODEC_FLAG_QSCALE;
4503 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4505 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4506 get_arg(arg, sizeof(arg), &p);
4508 video_enc.max_qdiff = atoi(arg);
4509 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4510 ERROR("VideoQDiff out of range\n");
4513 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4514 get_arg(arg, sizeof(arg), &p);
4516 video_enc.qmax = atoi(arg);
4517 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4518 ERROR("VideoQMax out of range\n");
4521 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4522 get_arg(arg, sizeof(arg), &p);
4524 video_enc.qmin = atoi(arg);
4525 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4526 ERROR("VideoQMin out of range\n");
4529 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4530 get_arg(arg, sizeof(arg), &p);
4532 video_enc.lumi_masking = atof(arg);
4533 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4534 get_arg(arg, sizeof(arg), &p);
4536 video_enc.dark_masking = atof(arg);
4537 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4538 video_id = AV_CODEC_ID_NONE;
4539 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4540 audio_id = AV_CODEC_ID_NONE;
4541 } else if (!av_strcasecmp(cmd, "ACL")) {
4542 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4543 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4545 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4547 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4548 get_arg(arg, sizeof(arg), &p);
4550 av_freep(&stream->rtsp_option);
4551 stream->rtsp_option = av_strdup(arg);
4553 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4554 get_arg(arg, sizeof(arg), &p);
4556 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4557 ERROR("Invalid host/IP address: %s\n", arg);
4559 stream->is_multicast = 1;
4560 stream->loop = 1; /* default is looping */
4562 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4563 get_arg(arg, sizeof(arg), &p);
4565 stream->multicast_port = atoi(arg);
4566 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4567 get_arg(arg, sizeof(arg), &p);
4569 stream->multicast_ttl = atoi(arg);
4570 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4573 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4575 ERROR("No corresponding <Stream> for </Stream>\n");
4577 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4578 if (audio_id != AV_CODEC_ID_NONE) {
4579 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4580 audio_enc.codec_id = audio_id;
4581 add_codec(stream, &audio_enc);
4583 if (video_id != AV_CODEC_ID_NONE) {
4584 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4585 video_enc.codec_id = video_id;
4586 add_codec(stream, &video_enc);
4591 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4592 /*********************************************/
4594 if (stream || feed || redirect) {
4595 ERROR("Already in a tag\n");
4597 redirect = av_mallocz(sizeof(FFStream));
4598 *last_stream = redirect;
4599 last_stream = &redirect->next;
4601 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4602 q = strrchr(redirect->filename, '>');
4605 redirect->stream_type = STREAM_TYPE_REDIRECT;
4607 } else if (!av_strcasecmp(cmd, "URL")) {
4609 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4610 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4612 ERROR("No corresponding <Redirect> for </Redirect>\n");
4614 if (!redirect->feed_filename[0]) {
4615 ERROR("No URL found for <Redirect>\n");
4619 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4620 ERROR("Loadable modules no longer supported\n");
4622 ERROR("Incorrect keyword: '%s'\n", cmd);
4634 static void handle_child_exit(int sig)
4639 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4642 for (feed = first_feed; feed; feed = feed->next) {
4643 if (feed->pid == pid) {
4644 int uptime = time(0) - feed->pid_start;
4647 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4650 /* Turn off any more restarts */
4651 feed->child_argv = 0;
4656 need_to_start_children = 1;
4659 static void opt_debug(void)
4662 logfilename[0] = '-';
4665 void show_help_default(const char *opt, const char *arg)
4667 printf("usage: ffserver [options]\n"
4668 "Hyper fast multi format Audio/Video streaming server\n");
4670 show_help_options(options, "Main options:", 0, 0, 0);
4673 static const OptionDef options[] = {
4674 #include "cmdutils_common_opts.h"
4675 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4676 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4677 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4681 int main(int argc, char **argv)
4683 struct sigaction sigact = { { 0 } };
4685 config_filename = av_strdup("/etc/ffserver.conf");
4687 parse_loglevel(argc, argv, options);
4689 avformat_network_init();
4691 show_banner(argc, argv, options);
4693 my_program_name = argv[0];
4695 parse_options(NULL, argc, argv, options, NULL);
4697 unsetenv("http_proxy"); /* Kill the http_proxy */
4699 av_lfg_init(&random_state, av_get_random_seed());
4701 sigact.sa_handler = handle_child_exit;
4702 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4703 sigaction(SIGCHLD, &sigact, 0);
4705 if (parse_ffconfig(config_filename) < 0) {
4706 fprintf(stderr, "Incorrect config file - exiting.\n");
4709 av_freep(&config_filename);
4711 /* open log file if needed */
4712 if (logfilename[0] != '\0') {
4713 if (!strcmp(logfilename, "-"))
4716 logfile = fopen(logfilename, "a");
4717 av_log_set_callback(http_av_log);
4720 build_file_streams();
4722 build_feed_streams();
4724 compute_bandwidth();
4727 signal(SIGPIPE, SIG_IGN);
4729 if (http_server() < 0) {
4730 http_log("Could not start server\n");