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/random_seed.h"
52 #include "libavutil/parseutils.h"
53 #include "libavutil/opt.h"
54 #include "libavutil/time.h"
59 #include <sys/ioctl.h>
70 const char program_name[] = "ffserver";
71 const int program_birth_year = 2000;
73 static const OptionDef options[];
76 HTTPSTATE_WAIT_REQUEST,
77 HTTPSTATE_SEND_HEADER,
78 HTTPSTATE_SEND_DATA_HEADER,
79 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
80 HTTPSTATE_SEND_DATA_TRAILER,
81 HTTPSTATE_RECEIVE_DATA,
82 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
85 RTSPSTATE_WAIT_REQUEST,
87 RTSPSTATE_SEND_PACKET,
90 static const char *http_state[] = {
106 #define MAX_STREAMS 20
108 #define IOBUFFER_INIT_SIZE 8192
110 /* timeouts are in ms */
111 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
112 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
114 #define SYNC_TIMEOUT (10 * 1000)
116 typedef struct RTSPActionServerSetup {
118 char transport_option[512];
119 } RTSPActionServerSetup;
122 int64_t count1, count2;
123 int64_t time1, time2;
126 /* context associated with one connection */
127 typedef struct HTTPContext {
128 enum HTTPState state;
129 int fd; /* socket file descriptor */
130 struct sockaddr_in from_addr; /* origin */
131 struct pollfd *poll_entry; /* used when polling */
133 uint8_t *buffer_ptr, *buffer_end;
136 int chunked_encoding;
137 int chunk_size; /* 0 if it needs to be read */
138 struct HTTPContext *next;
139 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
143 /* input format handling */
144 AVFormatContext *fmt_in;
145 int64_t start_time; /* In milliseconds - this wraps fairly often */
146 int64_t first_pts; /* initial pts value */
147 int64_t cur_pts; /* current pts value from the stream in us */
148 int64_t cur_frame_duration; /* duration of the current frame in us */
149 int cur_frame_bytes; /* output frame size, needed to compute
150 the time at which we send each
152 int pts_stream_index; /* stream we choose as clock reference */
153 int64_t cur_clock; /* current clock reference value in us */
154 /* output format handling */
155 struct FFStream *stream;
156 /* -1 is invalid stream */
157 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
158 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
160 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
161 int last_packet_sent; /* true if last data packet was sent */
163 DataRateData datarate;
170 int is_packetized; /* if true, the stream is packetized */
171 int packet_stream_index; /* current stream for output in state machine */
173 /* RTSP state specific */
174 uint8_t *pb_buffer; /* XXX: use that in all the code */
176 int seq; /* RTSP sequence number */
178 /* RTP state specific */
179 enum RTSPLowerTransport rtp_protocol;
180 char session_id[32]; /* session id */
181 AVFormatContext *rtp_ctx[MAX_STREAMS];
183 /* RTP/UDP specific */
184 URLContext *rtp_handles[MAX_STREAMS];
186 /* RTP/TCP specific */
187 struct HTTPContext *rtsp_c;
188 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
191 /* each generated stream is described here */
195 STREAM_TYPE_REDIRECT,
198 enum IPAddressAction {
203 typedef struct IPAddressACL {
204 struct IPAddressACL *next;
205 enum IPAddressAction action;
206 /* These are in host order */
207 struct in_addr first;
211 /* description of each stream of the ffserver.conf file */
212 typedef struct FFStream {
213 enum StreamType stream_type;
214 char filename[1024]; /* stream filename */
215 struct FFStream *feed; /* feed we are using (can be null if
217 AVDictionary *in_opts; /* input parameters */
218 AVInputFormat *ifmt; /* if non NULL, force input format */
221 char dynamic_acl[1024];
223 int prebuffer; /* Number of millseconds early to start */
224 int64_t max_time; /* Number of milliseconds to run */
226 AVStream *streams[MAX_STREAMS];
227 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
228 char feed_filename[1024]; /* file name of the feed storage, or
229 input file name for a stream */
234 pid_t pid; /* Of ffmpeg process */
235 time_t pid_start; /* Of ffmpeg process */
237 struct FFStream *next;
238 unsigned bandwidth; /* bandwidth, in kbits/s */
241 /* multicast specific */
243 struct in_addr multicast_ip;
244 int multicast_port; /* first port used for multicast */
246 int loop; /* if true, send the stream in loops (only meaningful if file) */
249 int feed_opened; /* true if someone is writing to the feed */
250 int is_feed; /* true if it is a feed */
251 int readonly; /* True if writing is prohibited to the file */
252 int truncate; /* True if feeder connection truncate the feed file */
254 int64_t bytes_served;
255 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
256 int64_t feed_write_index; /* current write position in feed (it wraps around) */
257 int64_t feed_size; /* current size of feed */
258 struct FFStream *next_feed;
261 typedef struct FeedData {
262 long long data_count;
263 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
266 static struct sockaddr_in my_http_addr;
267 static struct sockaddr_in my_rtsp_addr;
269 static char logfilename[1024];
270 static HTTPContext *first_http_ctx;
271 static FFStream *first_feed; /* contains only feeds */
272 static FFStream *first_stream; /* contains all streams, including feeds */
274 static void new_connection(int server_fd, int is_rtsp);
275 static void close_connection(HTTPContext *c);
278 static int handle_connection(HTTPContext *c);
279 static int http_parse_request(HTTPContext *c);
280 static int http_send_data(HTTPContext *c);
281 static void compute_status(HTTPContext *c);
282 static int open_input_stream(HTTPContext *c, const char *info);
283 static int http_start_receive_data(HTTPContext *c);
284 static int http_receive_data(HTTPContext *c);
287 static int rtsp_parse_request(HTTPContext *c);
288 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
289 static void rtsp_cmd_options(HTTPContext *c, const char *url);
290 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
291 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
292 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
293 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
296 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
297 struct in_addr my_ip);
300 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
301 FFStream *stream, const char *session_id,
302 enum RTSPLowerTransport rtp_protocol);
303 static int rtp_new_av_stream(HTTPContext *c,
304 int stream_index, struct sockaddr_in *dest_addr,
305 HTTPContext *rtsp_c);
307 static const char *my_program_name;
309 static const char *config_filename;
311 static int ffserver_debug;
312 static int no_launch;
313 static int need_to_start_children;
315 /* maximum number of simultaneous HTTP connections */
316 static unsigned int nb_max_http_connections = 2000;
317 static unsigned int nb_max_connections = 5;
318 static unsigned int nb_connections;
320 static uint64_t max_bandwidth = 1000;
321 static uint64_t current_bandwidth;
323 static int64_t cur_time; // Making this global saves on passing it around everywhere
325 static AVLFG random_state;
327 static FILE *logfile = NULL;
329 static int64_t ffm_read_write_index(int fd)
333 if (lseek(fd, 8, SEEK_SET) < 0)
335 if (read(fd, buf, 8) != 8)
340 static int ffm_write_write_index(int fd, int64_t pos)
346 buf[i] = (pos >> (56 - i * 8)) & 0xff;
347 if (lseek(fd, 8, SEEK_SET) < 0)
349 if (write(fd, buf, 8) != 8)
354 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
357 FFMContext *ffm = s->priv_data;
358 ffm->write_index = pos;
359 ffm->file_size = file_size;
362 /* FIXME: make ffserver work with IPv6 */
363 /* resolve host with also IP address parsing */
364 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
367 if (!ff_inet_aton(hostname, sin_addr)) {
369 struct addrinfo *ai, *cur;
370 struct addrinfo hints = { 0 };
371 hints.ai_family = AF_INET;
372 if (getaddrinfo(hostname, NULL, &hints, &ai))
374 /* getaddrinfo returns a linked list of addrinfo structs.
375 * Even if we set ai_family = AF_INET above, make sure
376 * that the returned one actually is of the correct type. */
377 for (cur = ai; cur; cur = cur->ai_next) {
378 if (cur->ai_family == AF_INET) {
379 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
388 hp = gethostbyname(hostname);
391 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
397 static char *ctime1(char *buf2, int buf_size)
404 av_strlcpy(buf2, p, buf_size);
405 p = buf2 + strlen(p) - 1;
411 static void http_vlog(const char *fmt, va_list vargs)
413 static int print_prefix = 1;
417 ctime1(buf, sizeof(buf));
418 fprintf(logfile, "%s ", buf);
420 print_prefix = strstr(fmt, "\n") != NULL;
421 vfprintf(logfile, fmt, vargs);
427 __attribute__ ((format (printf, 1, 2)))
429 static void http_log(const char *fmt, ...)
432 va_start(vargs, fmt);
433 http_vlog(fmt, vargs);
437 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
439 static int print_prefix = 1;
440 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
441 if (level > av_log_get_level())
443 if (print_prefix && avc)
444 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
445 print_prefix = strstr(fmt, "\n") != NULL;
446 http_vlog(fmt, vargs);
449 static void log_connection(HTTPContext *c)
454 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
455 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
456 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
459 static void update_datarate(DataRateData *drd, int64_t count)
461 if (!drd->time1 && !drd->count1) {
462 drd->time1 = drd->time2 = cur_time;
463 drd->count1 = drd->count2 = count;
464 } else if (cur_time - drd->time2 > 5000) {
465 drd->time1 = drd->time2;
466 drd->count1 = drd->count2;
467 drd->time2 = cur_time;
472 /* In bytes per second */
473 static int compute_datarate(DataRateData *drd, int64_t count)
475 if (cur_time == drd->time1)
478 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
482 static void start_children(FFStream *feed)
487 for (; feed; feed = feed->next) {
488 if (feed->child_argv && !feed->pid) {
489 feed->pid_start = time(0);
494 http_log("Unable to create children\n");
503 av_strlcpy(pathname, my_program_name, sizeof(pathname));
505 slash = strrchr(pathname, '/');
510 strcpy(slash, "ffmpeg");
512 http_log("Launch command line: ");
513 http_log("%s ", pathname);
514 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
515 http_log("%s ", feed->child_argv[i]);
518 for (i = 3; i < 256; i++)
521 if (!ffserver_debug) {
522 if (!freopen("/dev/null", "r", stdin))
523 http_log("failed to redirect STDIN to /dev/null\n;");
524 if (!freopen("/dev/null", "w", stdout))
525 http_log("failed to redirect STDOUT to /dev/null\n;");
526 if (!freopen("/dev/null", "w", stderr))
527 http_log("failed to redirect STDERR to /dev/null\n;");
530 signal(SIGPIPE, SIG_DFL);
532 execvp(pathname, feed->child_argv);
540 /* open a listening socket */
541 static int socket_open_listen(struct sockaddr_in *my_addr)
545 server_fd = socket(AF_INET,SOCK_STREAM,0);
552 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
554 my_addr->sin_family = AF_INET;
555 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
557 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
559 closesocket(server_fd);
563 if (listen (server_fd, 5) < 0) {
565 closesocket(server_fd);
568 ff_socket_nonblock(server_fd, 1);
573 /* start all multicast streams */
574 static void start_multicast(void)
579 struct sockaddr_in dest_addr = {0};
580 int default_port, stream_index;
583 for(stream = first_stream; stream != NULL; stream = stream->next) {
584 if (stream->is_multicast) {
585 unsigned random0 = av_lfg_get(&random_state);
586 unsigned random1 = av_lfg_get(&random_state);
587 /* open the RTP connection */
588 snprintf(session_id, sizeof(session_id), "%08x%08x",
591 /* choose a port if none given */
592 if (stream->multicast_port == 0) {
593 stream->multicast_port = default_port;
597 dest_addr.sin_family = AF_INET;
598 dest_addr.sin_addr = stream->multicast_ip;
599 dest_addr.sin_port = htons(stream->multicast_port);
601 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
602 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
606 if (open_input_stream(rtp_c, "") < 0) {
607 http_log("Could not open input stream for stream '%s'\n",
612 /* open each RTP stream */
613 for(stream_index = 0; stream_index < stream->nb_streams;
615 dest_addr.sin_port = htons(stream->multicast_port +
617 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
618 http_log("Could not open output stream '%s/streamid=%d'\n",
619 stream->filename, stream_index);
624 /* change state to send data */
625 rtp_c->state = HTTPSTATE_SEND_DATA;
630 /* main loop of the http server */
631 static int http_server(void)
633 int server_fd = 0, rtsp_server_fd = 0;
634 int ret, delay, delay1;
635 struct pollfd *poll_table, *poll_entry;
636 HTTPContext *c, *c_next;
638 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
639 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
643 if (my_http_addr.sin_port) {
644 server_fd = socket_open_listen(&my_http_addr);
649 if (my_rtsp_addr.sin_port) {
650 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
651 if (rtsp_server_fd < 0)
655 if (!rtsp_server_fd && !server_fd) {
656 http_log("HTTP and RTSP disabled.\n");
660 http_log("FFserver started.\n");
662 start_children(first_feed);
667 poll_entry = poll_table;
669 poll_entry->fd = server_fd;
670 poll_entry->events = POLLIN;
673 if (rtsp_server_fd) {
674 poll_entry->fd = rtsp_server_fd;
675 poll_entry->events = POLLIN;
679 /* wait for events on each HTTP handle */
686 case HTTPSTATE_SEND_HEADER:
687 case RTSPSTATE_SEND_REPLY:
688 case RTSPSTATE_SEND_PACKET:
689 c->poll_entry = poll_entry;
691 poll_entry->events = POLLOUT;
694 case HTTPSTATE_SEND_DATA_HEADER:
695 case HTTPSTATE_SEND_DATA:
696 case HTTPSTATE_SEND_DATA_TRAILER:
697 if (!c->is_packetized) {
698 /* for TCP, we output as much as we can (may need to put a limit) */
699 c->poll_entry = poll_entry;
701 poll_entry->events = POLLOUT;
704 /* when ffserver is doing the timing, we work by
705 looking at which packet need to be sent every
707 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
712 case HTTPSTATE_WAIT_REQUEST:
713 case HTTPSTATE_RECEIVE_DATA:
714 case HTTPSTATE_WAIT_FEED:
715 case RTSPSTATE_WAIT_REQUEST:
716 /* need to catch errors */
717 c->poll_entry = poll_entry;
719 poll_entry->events = POLLIN;/* Maybe this will work */
723 c->poll_entry = NULL;
729 /* wait for an event on one connection. We poll at least every
730 second to handle timeouts */
732 ret = poll(poll_table, poll_entry - poll_table, delay);
733 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
734 ff_neterrno() != AVERROR(EINTR))
738 cur_time = av_gettime() / 1000;
740 if (need_to_start_children) {
741 need_to_start_children = 0;
742 start_children(first_feed);
745 /* now handle the events */
746 for(c = first_http_ctx; c != NULL; c = c_next) {
748 if (handle_connection(c) < 0) {
749 /* close and free the connection */
755 poll_entry = poll_table;
757 /* new HTTP connection request ? */
758 if (poll_entry->revents & POLLIN)
759 new_connection(server_fd, 0);
762 if (rtsp_server_fd) {
763 /* new RTSP connection request ? */
764 if (poll_entry->revents & POLLIN)
765 new_connection(rtsp_server_fd, 1);
770 /* start waiting for a new HTTP/RTSP request */
771 static void start_wait_request(HTTPContext *c, int is_rtsp)
773 c->buffer_ptr = c->buffer;
774 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
777 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
778 c->state = RTSPSTATE_WAIT_REQUEST;
780 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
781 c->state = HTTPSTATE_WAIT_REQUEST;
785 static void http_send_too_busy_reply(int fd)
788 int len = snprintf(buffer, sizeof(buffer),
789 "HTTP/1.0 503 Server too busy\r\n"
790 "Content-type: text/html\r\n"
792 "<html><head><title>Too busy</title></head><body>\r\n"
793 "<p>The server is too busy to serve your request at this time.</p>\r\n"
794 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
795 "</body></html>\r\n",
796 nb_connections, nb_max_connections);
797 av_assert0(len < sizeof(buffer));
798 send(fd, buffer, len, 0);
802 static void new_connection(int server_fd, int is_rtsp)
804 struct sockaddr_in from_addr;
807 HTTPContext *c = NULL;
809 len = sizeof(from_addr);
810 fd = accept(server_fd, (struct sockaddr *)&from_addr,
813 http_log("error during accept %s\n", strerror(errno));
816 ff_socket_nonblock(fd, 1);
818 if (nb_connections >= nb_max_connections) {
819 http_send_too_busy_reply(fd);
823 /* add a new connection */
824 c = av_mallocz(sizeof(HTTPContext));
829 c->poll_entry = NULL;
830 c->from_addr = from_addr;
831 c->buffer_size = IOBUFFER_INIT_SIZE;
832 c->buffer = av_malloc(c->buffer_size);
836 c->next = first_http_ctx;
840 start_wait_request(c, is_rtsp);
852 static void close_connection(HTTPContext *c)
854 HTTPContext **cp, *c1;
856 AVFormatContext *ctx;
860 /* remove connection from list */
861 cp = &first_http_ctx;
862 while ((*cp) != NULL) {
870 /* remove references, if any (XXX: do it faster) */
871 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
876 /* remove connection associated resources */
880 /* close each frame parser */
881 for(i=0;i<c->fmt_in->nb_streams;i++) {
882 st = c->fmt_in->streams[i];
883 if (st->codec->codec)
884 avcodec_close(st->codec);
886 avformat_close_input(&c->fmt_in);
889 /* free RTP output streams if any */
892 nb_streams = c->stream->nb_streams;
894 for(i=0;i<nb_streams;i++) {
897 av_write_trailer(ctx);
898 av_dict_free(&ctx->metadata);
899 av_free(ctx->streams[0]);
902 h = c->rtp_handles[i];
909 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
912 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
913 av_write_trailer(ctx);
914 av_freep(&c->pb_buffer);
915 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
920 for(i=0; i<ctx->nb_streams; i++)
921 av_free(ctx->streams[i]);
922 av_freep(&ctx->streams);
923 av_freep(&ctx->priv_data);
925 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
926 current_bandwidth -= c->stream->bandwidth;
928 /* signal that there is no feed if we are the feeder socket */
929 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
930 c->stream->feed_opened = 0;
934 av_freep(&c->pb_buffer);
935 av_freep(&c->packet_buffer);
941 static int handle_connection(HTTPContext *c)
946 case HTTPSTATE_WAIT_REQUEST:
947 case RTSPSTATE_WAIT_REQUEST:
949 if ((c->timeout - cur_time) < 0)
951 if (c->poll_entry->revents & (POLLERR | POLLHUP))
954 /* no need to read if no events */
955 if (!(c->poll_entry->revents & POLLIN))
959 len = recv(c->fd, c->buffer_ptr, 1, 0);
961 if (ff_neterrno() != AVERROR(EAGAIN) &&
962 ff_neterrno() != AVERROR(EINTR))
964 } else if (len == 0) {
967 /* search for end of request. */
969 c->buffer_ptr += len;
971 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
972 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
973 /* request found : parse it and reply */
974 if (c->state == HTTPSTATE_WAIT_REQUEST) {
975 ret = http_parse_request(c);
977 ret = rtsp_parse_request(c);
981 } else if (ptr >= c->buffer_end) {
982 /* request too long: cannot do anything */
984 } else goto read_loop;
988 case HTTPSTATE_SEND_HEADER:
989 if (c->poll_entry->revents & (POLLERR | POLLHUP))
992 /* no need to write if no events */
993 if (!(c->poll_entry->revents & POLLOUT))
995 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
997 if (ff_neterrno() != AVERROR(EAGAIN) &&
998 ff_neterrno() != AVERROR(EINTR)) {
999 /* error : close connection */
1000 av_freep(&c->pb_buffer);
1004 c->buffer_ptr += len;
1006 c->stream->bytes_served += len;
1007 c->data_count += len;
1008 if (c->buffer_ptr >= c->buffer_end) {
1009 av_freep(&c->pb_buffer);
1010 /* if error, exit */
1013 /* all the buffer was sent : synchronize to the incoming stream */
1014 c->state = HTTPSTATE_SEND_DATA_HEADER;
1015 c->buffer_ptr = c->buffer_end = c->buffer;
1020 case HTTPSTATE_SEND_DATA:
1021 case HTTPSTATE_SEND_DATA_HEADER:
1022 case HTTPSTATE_SEND_DATA_TRAILER:
1023 /* for packetized output, we consider we can always write (the
1024 input streams sets the speed). It may be better to verify
1025 that we do not rely too much on the kernel queues */
1026 if (!c->is_packetized) {
1027 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1030 /* no need to read if no events */
1031 if (!(c->poll_entry->revents & POLLOUT))
1034 if (http_send_data(c) < 0)
1036 /* close connection if trailer sent */
1037 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1040 case HTTPSTATE_RECEIVE_DATA:
1041 /* no need to read if no events */
1042 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1044 if (!(c->poll_entry->revents & POLLIN))
1046 if (http_receive_data(c) < 0)
1049 case HTTPSTATE_WAIT_FEED:
1050 /* no need to read if no events */
1051 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1054 /* nothing to do, we'll be waken up by incoming feed packets */
1057 case RTSPSTATE_SEND_REPLY:
1058 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1059 av_freep(&c->pb_buffer);
1062 /* no need to write if no events */
1063 if (!(c->poll_entry->revents & POLLOUT))
1065 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1067 if (ff_neterrno() != AVERROR(EAGAIN) &&
1068 ff_neterrno() != AVERROR(EINTR)) {
1069 /* error : close connection */
1070 av_freep(&c->pb_buffer);
1074 c->buffer_ptr += len;
1075 c->data_count += len;
1076 if (c->buffer_ptr >= c->buffer_end) {
1077 /* all the buffer was sent : wait for a new request */
1078 av_freep(&c->pb_buffer);
1079 start_wait_request(c, 1);
1083 case RTSPSTATE_SEND_PACKET:
1084 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1085 av_freep(&c->packet_buffer);
1088 /* no need to write if no events */
1089 if (!(c->poll_entry->revents & POLLOUT))
1091 len = send(c->fd, c->packet_buffer_ptr,
1092 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1094 if (ff_neterrno() != AVERROR(EAGAIN) &&
1095 ff_neterrno() != AVERROR(EINTR)) {
1096 /* error : close connection */
1097 av_freep(&c->packet_buffer);
1101 c->packet_buffer_ptr += len;
1102 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1103 /* all the buffer was sent : wait for a new request */
1104 av_freep(&c->packet_buffer);
1105 c->state = RTSPSTATE_WAIT_REQUEST;
1109 case HTTPSTATE_READY:
1118 static int extract_rates(char *rates, int ratelen, const char *request)
1122 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1123 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1124 const char *q = p + 7;
1126 while (*q && *q != '\n' && av_isspace(*q))
1129 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1135 memset(rates, 0xff, ratelen);
1138 while (*q && *q != '\n' && *q != ':')
1141 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1145 if (stream_no < ratelen && stream_no >= 0)
1146 rates[stream_no] = rate_no;
1148 while (*q && *q != '\n' && !av_isspace(*q))
1155 p = strchr(p, '\n');
1165 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1168 int best_bitrate = 100000000;
1171 for (i = 0; i < feed->nb_streams; i++) {
1172 AVCodecContext *feed_codec = feed->streams[i]->codec;
1174 if (feed_codec->codec_id != codec->codec_id ||
1175 feed_codec->sample_rate != codec->sample_rate ||
1176 feed_codec->width != codec->width ||
1177 feed_codec->height != codec->height)
1180 /* Potential stream */
1182 /* We want the fastest stream less than bit_rate, or the slowest
1183 * faster than bit_rate
1186 if (feed_codec->bit_rate <= bit_rate) {
1187 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1188 best_bitrate = feed_codec->bit_rate;
1192 if (feed_codec->bit_rate < best_bitrate) {
1193 best_bitrate = feed_codec->bit_rate;
1202 static int modify_current_stream(HTTPContext *c, char *rates)
1205 FFStream *req = c->stream;
1206 int action_required = 0;
1208 /* Not much we can do for a feed */
1212 for (i = 0; i < req->nb_streams; i++) {
1213 AVCodecContext *codec = req->streams[i]->codec;
1217 c->switch_feed_streams[i] = req->feed_streams[i];
1220 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1223 /* Wants off or slow */
1224 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1226 /* This doesn't work well when it turns off the only stream! */
1227 c->switch_feed_streams[i] = -2;
1228 c->feed_streams[i] = -2;
1233 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1234 action_required = 1;
1237 return action_required;
1240 /* XXX: factorize in utils.c ? */
1241 /* XXX: take care with different space meaning */
1242 static void skip_spaces(const char **pp)
1246 while (*p == ' ' || *p == '\t')
1251 static void get_word(char *buf, int buf_size, const char **pp)
1259 while (!av_isspace(*p) && *p != '\0') {
1260 if ((q - buf) < buf_size - 1)
1269 static void get_arg(char *buf, int buf_size, const char **pp)
1276 while (av_isspace(*p)) p++;
1279 if (*p == '\"' || *p == '\'')
1291 if ((q - buf) < buf_size - 1)
1296 if (quote && *p == quote)
1301 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1302 const char *p, const char *filename, int line_num)
1308 get_arg(arg, sizeof(arg), &p);
1309 if (av_strcasecmp(arg, "allow") == 0)
1310 acl.action = IP_ALLOW;
1311 else if (av_strcasecmp(arg, "deny") == 0)
1312 acl.action = IP_DENY;
1314 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1315 filename, line_num, arg);
1319 get_arg(arg, sizeof(arg), &p);
1321 if (resolve_host(&acl.first, arg) != 0) {
1322 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1323 filename, line_num, arg);
1326 acl.last = acl.first;
1328 get_arg(arg, sizeof(arg), &p);
1331 if (resolve_host(&acl.last, arg) != 0) {
1332 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1333 filename, line_num, arg);
1339 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1340 IPAddressACL **naclp = 0;
1346 naclp = &stream->acl;
1352 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1353 filename, line_num);
1359 naclp = &(*naclp)->next;
1367 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1372 IPAddressACL *acl = NULL;
1376 f = fopen(stream->dynamic_acl, "r");
1378 perror(stream->dynamic_acl);
1382 acl = av_mallocz(sizeof(IPAddressACL));
1386 if (fgets(line, sizeof(line), f) == NULL)
1390 while (av_isspace(*p))
1392 if (*p == '\0' || *p == '#')
1394 get_arg(cmd, sizeof(cmd), &p);
1396 if (!av_strcasecmp(cmd, "ACL"))
1397 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1404 static void free_acl_list(IPAddressACL *in_acl)
1406 IPAddressACL *pacl,*pacl2;
1416 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1418 enum IPAddressAction last_action = IP_DENY;
1420 struct in_addr *src = &c->from_addr.sin_addr;
1421 unsigned long src_addr = src->s_addr;
1423 for (acl = in_acl; acl; acl = acl->next) {
1424 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1425 return (acl->action == IP_ALLOW) ? 1 : 0;
1426 last_action = acl->action;
1429 /* Nothing matched, so return not the last action */
1430 return (last_action == IP_DENY) ? 1 : 0;
1433 static int validate_acl(FFStream *stream, HTTPContext *c)
1439 /* if stream->acl is null validate_acl_list will return 1 */
1440 ret = validate_acl_list(stream->acl, c);
1442 if (stream->dynamic_acl[0]) {
1443 acl = parse_dynamic_acl(stream, c);
1445 ret = validate_acl_list(acl, c);
1453 /* compute the real filename of a file by matching it without its
1454 extensions to all the stream filenames */
1455 static void compute_real_filename(char *filename, int max_size)
1462 /* compute filename by matching without the file extensions */
1463 av_strlcpy(file1, filename, sizeof(file1));
1464 p = strrchr(file1, '.');
1467 for(stream = first_stream; stream != NULL; stream = stream->next) {
1468 av_strlcpy(file2, stream->filename, sizeof(file2));
1469 p = strrchr(file2, '.');
1472 if (!strcmp(file1, file2)) {
1473 av_strlcpy(filename, stream->filename, max_size);
1488 /* parse http request and prepare header */
1489 static int http_parse_request(HTTPContext *c)
1493 enum RedirType redir_type;
1495 char info[1024], filename[1024];
1499 const char *mime_type;
1503 const char *useragent = 0;
1506 get_word(cmd, sizeof(cmd), &p);
1507 av_strlcpy(c->method, cmd, sizeof(c->method));
1509 if (!strcmp(cmd, "GET"))
1511 else if (!strcmp(cmd, "POST"))
1516 get_word(url, sizeof(url), &p);
1517 av_strlcpy(c->url, url, sizeof(c->url));
1519 get_word(protocol, sizeof(protocol), (const char **)&p);
1520 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1523 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1526 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1528 /* find the filename and the optional info string in the request */
1529 p1 = strchr(url, '?');
1531 av_strlcpy(info, p1, sizeof(info));
1536 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1538 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1539 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1541 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1545 p = strchr(p, '\n');
1552 redir_type = REDIR_NONE;
1553 if (av_match_ext(filename, "asx")) {
1554 redir_type = REDIR_ASX;
1555 filename[strlen(filename)-1] = 'f';
1556 } else if (av_match_ext(filename, "asf") &&
1557 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1558 /* if this isn't WMP or lookalike, return the redirector file */
1559 redir_type = REDIR_ASF;
1560 } else if (av_match_ext(filename, "rpm,ram")) {
1561 redir_type = REDIR_RAM;
1562 strcpy(filename + strlen(filename)-2, "m");
1563 } else if (av_match_ext(filename, "rtsp")) {
1564 redir_type = REDIR_RTSP;
1565 compute_real_filename(filename, sizeof(filename) - 1);
1566 } else if (av_match_ext(filename, "sdp")) {
1567 redir_type = REDIR_SDP;
1568 compute_real_filename(filename, sizeof(filename) - 1);
1571 // "redirect" / request to index.html
1572 if (!strlen(filename))
1573 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1575 stream = first_stream;
1576 while (stream != NULL) {
1577 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1579 stream = stream->next;
1581 if (stream == NULL) {
1582 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1583 http_log("File '%s' not found\n", url);
1588 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1589 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1591 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1592 c->http_error = 301;
1594 snprintf(q, c->buffer_size,
1595 "HTTP/1.0 301 Moved\r\n"
1597 "Content-type: text/html\r\n"
1599 "<html><head><title>Moved</title></head><body>\r\n"
1600 "You should be <a href=\"%s\">redirected</a>.\r\n"
1601 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1603 /* prepare output buffer */
1604 c->buffer_ptr = c->buffer;
1606 c->state = HTTPSTATE_SEND_HEADER;
1610 /* If this is WMP, get the rate information */
1611 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1612 if (modify_current_stream(c, ratebuf)) {
1613 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1614 if (c->switch_feed_streams[i] >= 0)
1615 c->switch_feed_streams[i] = -1;
1620 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1621 current_bandwidth += stream->bandwidth;
1623 /* If already streaming this feed, do not let start another feeder. */
1624 if (stream->feed_opened) {
1625 snprintf(msg, sizeof(msg), "This feed is already being received.");
1626 http_log("Feed '%s' already being received\n", stream->feed_filename);
1630 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1631 c->http_error = 503;
1633 snprintf(q, c->buffer_size,
1634 "HTTP/1.0 503 Server too busy\r\n"
1635 "Content-type: text/html\r\n"
1637 "<html><head><title>Too busy</title></head><body>\r\n"
1638 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1639 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1640 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1641 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1643 /* prepare output buffer */
1644 c->buffer_ptr = c->buffer;
1646 c->state = HTTPSTATE_SEND_HEADER;
1650 if (redir_type != REDIR_NONE) {
1651 const char *hostinfo = 0;
1653 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1654 if (av_strncasecmp(p, "Host:", 5) == 0) {
1658 p = strchr(p, '\n');
1669 while (av_isspace(*hostinfo))
1672 eoh = strchr(hostinfo, '\n');
1674 if (eoh[-1] == '\r')
1677 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1678 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1679 hostbuf[eoh - hostinfo] = 0;
1681 c->http_error = 200;
1683 switch(redir_type) {
1685 snprintf(q, c->buffer_size,
1686 "HTTP/1.0 200 ASX Follows\r\n"
1687 "Content-type: video/x-ms-asf\r\n"
1689 "<ASX Version=\"3\">\r\n"
1690 //"<!-- Autogenerated by ffserver -->\r\n"
1691 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1692 "</ASX>\r\n", hostbuf, filename, info);
1696 snprintf(q, c->buffer_size,
1697 "HTTP/1.0 200 RAM Follows\r\n"
1698 "Content-type: audio/x-pn-realaudio\r\n"
1700 "# Autogenerated by ffserver\r\n"
1701 "http://%s/%s%s\r\n", hostbuf, filename, info);
1705 snprintf(q, c->buffer_size,
1706 "HTTP/1.0 200 ASF Redirect follows\r\n"
1707 "Content-type: video/x-ms-asf\r\n"
1710 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1715 char hostname[256], *p;
1716 /* extract only hostname */
1717 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1718 p = strrchr(hostname, ':');
1721 snprintf(q, c->buffer_size,
1722 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1723 /* XXX: incorrect mime type ? */
1724 "Content-type: application/x-rtsp\r\n"
1726 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1735 struct sockaddr_in my_addr;
1737 snprintf(q, c->buffer_size,
1738 "HTTP/1.0 200 OK\r\n"
1739 "Content-type: application/sdp\r\n"
1743 len = sizeof(my_addr);
1744 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1746 /* XXX: should use a dynamic buffer */
1747 sdp_data_size = prepare_sdp_description(stream,
1750 if (sdp_data_size > 0) {
1751 memcpy(q, sdp_data, sdp_data_size);
1763 /* prepare output buffer */
1764 c->buffer_ptr = c->buffer;
1766 c->state = HTTPSTATE_SEND_HEADER;
1772 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1776 stream->conns_served++;
1778 /* XXX: add there authenticate and IP match */
1781 /* if post, it means a feed is being sent */
1782 if (!stream->is_feed) {
1783 /* However it might be a status report from WMP! Let us log the
1784 * data as it might come in handy one day. */
1785 const char *logline = 0;
1788 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1789 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1793 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1794 client_id = strtol(p + 18, 0, 10);
1795 p = strchr(p, '\n');
1803 char *eol = strchr(logline, '\n');
1808 if (eol[-1] == '\r')
1810 http_log("%.*s\n", (int) (eol - logline), logline);
1811 c->suppress_log = 1;
1816 http_log("\nGot request:\n%s\n", c->buffer);
1819 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1822 /* Now we have to find the client_id */
1823 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1824 if (wmpc->wmp_client_id == client_id)
1828 if (wmpc && modify_current_stream(wmpc, ratebuf))
1829 wmpc->switch_pending = 1;
1832 snprintf(msg, sizeof(msg), "POST command not handled");
1836 if (http_start_receive_data(c) < 0) {
1837 snprintf(msg, sizeof(msg), "could not open feed");
1841 c->state = HTTPSTATE_RECEIVE_DATA;
1846 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1847 http_log("\nGot request:\n%s\n", c->buffer);
1850 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1853 /* open input stream */
1854 if (open_input_stream(c, info) < 0) {
1855 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1859 /* prepare http header */
1861 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1862 mime_type = c->stream->fmt->mime_type;
1864 mime_type = "application/x-octet-stream";
1865 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1867 /* for asf, we need extra headers */
1868 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1869 /* Need to allocate a client id */
1871 c->wmp_client_id = av_lfg_get(&random_state);
1873 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);
1875 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1876 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1877 q = c->buffer + strlen(c->buffer);
1879 /* prepare output buffer */
1881 c->buffer_ptr = c->buffer;
1883 c->state = HTTPSTATE_SEND_HEADER;
1886 c->http_error = 404;
1888 snprintf(q, c->buffer_size,
1889 "HTTP/1.0 404 Not Found\r\n"
1890 "Content-type: text/html\r\n"
1893 "<head><title>404 Not Found</title></head>\n"
1897 /* prepare output buffer */
1898 c->buffer_ptr = c->buffer;
1900 c->state = HTTPSTATE_SEND_HEADER;
1904 c->http_error = 200; /* horrible : we use this value to avoid
1905 going to the send data state */
1906 c->state = HTTPSTATE_SEND_HEADER;
1910 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1912 static const char suffix[] = " kMGTP";
1915 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1917 avio_printf(pb, "%"PRId64"%c", count, *s);
1920 static void compute_status(HTTPContext *c)
1929 if (avio_open_dyn_buf(&pb) < 0) {
1930 /* XXX: return an error ? */
1931 c->buffer_ptr = c->buffer;
1932 c->buffer_end = c->buffer;
1936 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1937 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1938 avio_printf(pb, "Pragma: no-cache\r\n");
1939 avio_printf(pb, "\r\n");
1941 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1942 if (c->stream->feed_filename[0])
1943 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1944 avio_printf(pb, "</head>\n<body>");
1945 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1947 avio_printf(pb, "<h2>Available Streams</h2>\n");
1948 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1949 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");
1950 stream = first_stream;
1951 while (stream != NULL) {
1952 char sfilename[1024];
1955 if (stream->feed != stream) {
1956 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1957 eosf = sfilename + strlen(sfilename);
1958 if (eosf - sfilename >= 4) {
1959 if (strcmp(eosf - 4, ".asf") == 0)
1960 strcpy(eosf - 4, ".asx");
1961 else if (strcmp(eosf - 3, ".rm") == 0)
1962 strcpy(eosf - 3, ".ram");
1963 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1964 /* generate a sample RTSP director if
1965 unicast. Generate an SDP redirector if
1967 eosf = strrchr(sfilename, '.');
1969 eosf = sfilename + strlen(sfilename);
1970 if (stream->is_multicast)
1971 strcpy(eosf, ".sdp");
1973 strcpy(eosf, ".rtsp");
1977 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1978 sfilename, stream->filename);
1979 avio_printf(pb, "<td align=right> %d <td align=right> ",
1980 stream->conns_served);
1981 fmt_bytecount(pb, stream->bytes_served);
1982 switch(stream->stream_type) {
1983 case STREAM_TYPE_LIVE: {
1984 int audio_bit_rate = 0;
1985 int video_bit_rate = 0;
1986 const char *audio_codec_name = "";
1987 const char *video_codec_name = "";
1988 const char *audio_codec_name_extra = "";
1989 const char *video_codec_name_extra = "";
1991 for(i=0;i<stream->nb_streams;i++) {
1992 AVStream *st = stream->streams[i];
1993 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1994 switch(st->codec->codec_type) {
1995 case AVMEDIA_TYPE_AUDIO:
1996 audio_bit_rate += st->codec->bit_rate;
1998 if (*audio_codec_name)
1999 audio_codec_name_extra = "...";
2000 audio_codec_name = codec->name;
2003 case AVMEDIA_TYPE_VIDEO:
2004 video_bit_rate += st->codec->bit_rate;
2006 if (*video_codec_name)
2007 video_codec_name_extra = "...";
2008 video_codec_name = codec->name;
2011 case AVMEDIA_TYPE_DATA:
2012 video_bit_rate += st->codec->bit_rate;
2018 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",
2021 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2022 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2024 avio_printf(pb, "<td>%s", stream->feed->filename);
2026 avio_printf(pb, "<td>%s", stream->feed_filename);
2027 avio_printf(pb, "\n");
2031 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2035 stream = stream->next;
2037 avio_printf(pb, "</table>\n");
2039 stream = first_stream;
2040 while (stream != NULL) {
2041 if (stream->feed == stream) {
2042 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2044 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2051 /* This is somewhat linux specific I guess */
2052 snprintf(ps_cmd, sizeof(ps_cmd),
2053 "ps -o \"%%cpu,cputime\" --no-headers %d",
2056 pid_stat = popen(ps_cmd, "r");
2061 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2063 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2071 avio_printf(pb, "<p>");
2073 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");
2075 for (i = 0; i < stream->nb_streams; i++) {
2076 AVStream *st = stream->streams[i];
2077 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2078 const char *type = "unknown";
2079 char parameters[64];
2083 switch(st->codec->codec_type) {
2084 case AVMEDIA_TYPE_AUDIO:
2086 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2088 case AVMEDIA_TYPE_VIDEO:
2090 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2091 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2096 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2097 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2099 avio_printf(pb, "</table>\n");
2102 stream = stream->next;
2105 /* connection status */
2106 avio_printf(pb, "<h2>Connection Status</h2>\n");
2108 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2109 nb_connections, nb_max_connections);
2111 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2112 current_bandwidth, max_bandwidth);
2114 avio_printf(pb, "<table>\n");
2115 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");
2116 c1 = first_http_ctx;
2118 while (c1 != NULL) {
2124 for (j = 0; j < c1->stream->nb_streams; j++) {
2125 if (!c1->stream->feed)
2126 bitrate += c1->stream->streams[j]->codec->bit_rate;
2127 else if (c1->feed_streams[j] >= 0)
2128 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2133 p = inet_ntoa(c1->from_addr.sin_addr);
2134 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2136 c1->stream ? c1->stream->filename : "",
2137 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2140 http_state[c1->state]);
2141 fmt_bytecount(pb, bitrate);
2142 avio_printf(pb, "<td align=right>");
2143 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2144 avio_printf(pb, "<td align=right>");
2145 fmt_bytecount(pb, c1->data_count);
2146 avio_printf(pb, "\n");
2149 avio_printf(pb, "</table>\n");
2154 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2155 avio_printf(pb, "</body>\n</html>\n");
2157 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2158 c->buffer_ptr = c->pb_buffer;
2159 c->buffer_end = c->pb_buffer + len;
2162 static int open_input_stream(HTTPContext *c, const char *info)
2165 char input_filename[1024];
2166 AVFormatContext *s = NULL;
2167 int buf_size, i, ret;
2170 /* find file name */
2171 if (c->stream->feed) {
2172 strcpy(input_filename, c->stream->feed->feed_filename);
2173 buf_size = FFM_PACKET_SIZE;
2174 /* compute position (absolute time) */
2175 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2176 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2178 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2179 int prebuffer = strtol(buf, 0, 10);
2180 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2182 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2184 strcpy(input_filename, c->stream->feed_filename);
2186 /* compute position (relative time) */
2187 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2188 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2193 if (input_filename[0] == '\0')
2197 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2198 http_log("could not open %s: %d\n", input_filename, ret);
2202 /* set buffer size */
2203 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2205 s->flags |= AVFMT_FLAG_GENPTS;
2207 if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
2208 http_log("Could not find stream info '%s'\n", input_filename);
2209 avformat_close_input(&s);
2213 /* choose stream as clock source (we favorize video stream if
2214 present) for packet sending */
2215 c->pts_stream_index = 0;
2216 for(i=0;i<c->stream->nb_streams;i++) {
2217 if (c->pts_stream_index == 0 &&
2218 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2219 c->pts_stream_index = i;
2223 if (c->fmt_in->iformat->read_seek)
2224 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2225 /* set the start time (needed for maxtime and RTP packet timing) */
2226 c->start_time = cur_time;
2227 c->first_pts = AV_NOPTS_VALUE;
2231 /* return the server clock (in us) */
2232 static int64_t get_server_clock(HTTPContext *c)
2234 /* compute current pts value from system time */
2235 return (cur_time - c->start_time) * 1000;
2238 /* return the estimated time at which the current packet must be sent
2240 static int64_t get_packet_send_clock(HTTPContext *c)
2242 int bytes_left, bytes_sent, frame_bytes;
2244 frame_bytes = c->cur_frame_bytes;
2245 if (frame_bytes <= 0)
2248 bytes_left = c->buffer_end - c->buffer_ptr;
2249 bytes_sent = frame_bytes - bytes_left;
2250 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2255 static int http_prepare_data(HTTPContext *c)
2258 AVFormatContext *ctx;
2260 av_freep(&c->pb_buffer);
2262 case HTTPSTATE_SEND_DATA_HEADER:
2263 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2264 av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2265 av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2266 av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2267 av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2269 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2271 for(i=0;i<c->stream->nb_streams;i++) {
2273 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2274 /* if file or feed, then just take streams from FFStream struct */
2275 if (!c->stream->feed ||
2276 c->stream->feed == c->stream)
2277 src = c->stream->streams[i];
2279 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2281 *(c->fmt_ctx.streams[i]) = *src;
2282 c->fmt_ctx.streams[i]->priv_data = 0;
2283 c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2284 AVStream, not in codec */
2286 /* set output format parameters */
2287 c->fmt_ctx.oformat = c->stream->fmt;
2288 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2290 c->got_key_frame = 0;
2292 /* prepare header and save header data in a stream */
2293 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2294 /* XXX: potential leak */
2297 c->fmt_ctx.pb->seekable = 0;
2300 * HACK to avoid mpeg ps muxer to spit many underflow errors
2301 * Default value from FFmpeg
2302 * Try to set it use configuration option
2304 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2306 if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2307 http_log("Error writing output header\n");
2310 av_dict_free(&c->fmt_ctx.metadata);
2312 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2313 c->buffer_ptr = c->pb_buffer;
2314 c->buffer_end = c->pb_buffer + len;
2316 c->state = HTTPSTATE_SEND_DATA;
2317 c->last_packet_sent = 0;
2319 case HTTPSTATE_SEND_DATA:
2320 /* find a new packet */
2321 /* read a packet from the input stream */
2322 if (c->stream->feed)
2323 ffm_set_write_index(c->fmt_in,
2324 c->stream->feed->feed_write_index,
2325 c->stream->feed->feed_size);
2327 if (c->stream->max_time &&
2328 c->stream->max_time + c->start_time - cur_time < 0)
2329 /* We have timed out */
2330 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2334 ret = av_read_frame(c->fmt_in, &pkt);
2336 if (c->stream->feed) {
2337 /* if coming from feed, it means we reached the end of the
2338 ffm file, so must wait for more data */
2339 c->state = HTTPSTATE_WAIT_FEED;
2340 return 1; /* state changed */
2341 } else if (ret == AVERROR(EAGAIN)) {
2342 /* input not ready, come back later */
2345 if (c->stream->loop) {
2346 avformat_close_input(&c->fmt_in);
2347 if (open_input_stream(c, "") < 0)
2352 /* must send trailer now because eof or error */
2353 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2357 int source_index = pkt.stream_index;
2358 /* update first pts if needed */
2359 if (c->first_pts == AV_NOPTS_VALUE) {
2360 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2361 c->start_time = cur_time;
2363 /* send it to the appropriate stream */
2364 if (c->stream->feed) {
2365 /* if coming from a feed, select the right stream */
2366 if (c->switch_pending) {
2367 c->switch_pending = 0;
2368 for(i=0;i<c->stream->nb_streams;i++) {
2369 if (c->switch_feed_streams[i] == pkt.stream_index)
2370 if (pkt.flags & AV_PKT_FLAG_KEY)
2371 c->switch_feed_streams[i] = -1;
2372 if (c->switch_feed_streams[i] >= 0)
2373 c->switch_pending = 1;
2376 for(i=0;i<c->stream->nb_streams;i++) {
2377 if (c->stream->feed_streams[i] == pkt.stream_index) {
2378 AVStream *st = c->fmt_in->streams[source_index];
2379 pkt.stream_index = i;
2380 if (pkt.flags & AV_PKT_FLAG_KEY &&
2381 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2382 c->stream->nb_streams == 1))
2383 c->got_key_frame = 1;
2384 if (!c->stream->send_on_key || c->got_key_frame)
2389 AVCodecContext *codec;
2390 AVStream *ist, *ost;
2392 ist = c->fmt_in->streams[source_index];
2393 /* specific handling for RTP: we use several
2394 output stream (one for each RTP
2395 connection). XXX: need more abstract handling */
2396 if (c->is_packetized) {
2397 /* compute send time and duration */
2398 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2399 c->cur_pts -= c->first_pts;
2400 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2401 /* find RTP context */
2402 c->packet_stream_index = pkt.stream_index;
2403 ctx = c->rtp_ctx[c->packet_stream_index];
2405 av_free_packet(&pkt);
2408 codec = ctx->streams[0]->codec;
2409 /* only one stream per RTP connection */
2410 pkt.stream_index = 0;
2414 codec = ctx->streams[pkt.stream_index]->codec;
2417 if (c->is_packetized) {
2418 int max_packet_size;
2419 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2420 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2422 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2423 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2425 ret = avio_open_dyn_buf(&ctx->pb);
2428 /* XXX: potential leak */
2431 ost = ctx->streams[pkt.stream_index];
2433 ctx->pb->seekable = 0;
2434 if (pkt.dts != AV_NOPTS_VALUE)
2435 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2436 if (pkt.pts != AV_NOPTS_VALUE)
2437 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2438 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2439 if (av_write_frame(ctx, &pkt) < 0) {
2440 http_log("Error writing frame to output\n");
2441 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2444 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2445 c->cur_frame_bytes = len;
2446 c->buffer_ptr = c->pb_buffer;
2447 c->buffer_end = c->pb_buffer + len;
2449 codec->frame_number++;
2451 av_free_packet(&pkt);
2455 av_free_packet(&pkt);
2460 case HTTPSTATE_SEND_DATA_TRAILER:
2461 /* last packet test ? */
2462 if (c->last_packet_sent || c->is_packetized)
2465 /* prepare header */
2466 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2467 /* XXX: potential leak */
2470 c->fmt_ctx.pb->seekable = 0;
2471 av_write_trailer(ctx);
2472 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2473 c->buffer_ptr = c->pb_buffer;
2474 c->buffer_end = c->pb_buffer + len;
2476 c->last_packet_sent = 1;
2482 /* should convert the format at the same time */
2483 /* send data starting at c->buffer_ptr to the output connection
2484 (either UDP or TCP connection) */
2485 static int http_send_data(HTTPContext *c)
2490 if (c->buffer_ptr >= c->buffer_end) {
2491 ret = http_prepare_data(c);
2495 /* state change requested */
2498 if (c->is_packetized) {
2499 /* RTP data output */
2500 len = c->buffer_end - c->buffer_ptr;
2502 /* fail safe - should never happen */
2504 c->buffer_ptr = c->buffer_end;
2507 len = (c->buffer_ptr[0] << 24) |
2508 (c->buffer_ptr[1] << 16) |
2509 (c->buffer_ptr[2] << 8) |
2511 if (len > (c->buffer_end - c->buffer_ptr))
2513 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2514 /* nothing to send yet: we can wait */
2518 c->data_count += len;
2519 update_datarate(&c->datarate, c->data_count);
2521 c->stream->bytes_served += len;
2523 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2524 /* RTP packets are sent inside the RTSP TCP connection */
2526 int interleaved_index, size;
2528 HTTPContext *rtsp_c;
2531 /* if no RTSP connection left, error */
2534 /* if already sending something, then wait. */
2535 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2537 if (avio_open_dyn_buf(&pb) < 0)
2539 interleaved_index = c->packet_stream_index * 2;
2540 /* RTCP packets are sent at odd indexes */
2541 if (c->buffer_ptr[1] == 200)
2542 interleaved_index++;
2543 /* write RTSP TCP header */
2545 header[1] = interleaved_index;
2546 header[2] = len >> 8;
2548 avio_write(pb, header, 4);
2549 /* write RTP packet data */
2551 avio_write(pb, c->buffer_ptr, len);
2552 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2553 /* prepare asynchronous TCP sending */
2554 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2555 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2556 c->buffer_ptr += len;
2558 /* send everything we can NOW */
2559 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2560 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2562 rtsp_c->packet_buffer_ptr += len;
2563 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2564 /* if we could not send all the data, we will
2565 send it later, so a new state is needed to
2566 "lock" the RTSP TCP connection */
2567 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2570 /* all data has been sent */
2571 av_freep(&c->packet_buffer);
2573 /* send RTP packet directly in UDP */
2575 ffurl_write(c->rtp_handles[c->packet_stream_index],
2576 c->buffer_ptr, len);
2577 c->buffer_ptr += len;
2578 /* here we continue as we can send several packets per 10 ms slot */
2581 /* TCP data output */
2582 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2584 if (ff_neterrno() != AVERROR(EAGAIN) &&
2585 ff_neterrno() != AVERROR(EINTR))
2586 /* error : close connection */
2591 c->buffer_ptr += len;
2593 c->data_count += len;
2594 update_datarate(&c->datarate, c->data_count);
2596 c->stream->bytes_served += len;
2604 static int http_start_receive_data(HTTPContext *c)
2608 if (c->stream->feed_opened)
2611 /* Don't permit writing to this one */
2612 if (c->stream->readonly)
2616 fd = open(c->stream->feed_filename, O_RDWR);
2618 http_log("Error opening feeder file: %s\n", strerror(errno));
2623 if (c->stream->truncate) {
2624 /* truncate feed file */
2625 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2626 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2627 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2628 http_log("Error truncating feed file: %s\n", strerror(errno));
2632 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2633 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2638 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2639 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2640 lseek(fd, 0, SEEK_SET);
2642 /* init buffer input */
2643 c->buffer_ptr = c->buffer;
2644 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2645 c->stream->feed_opened = 1;
2646 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2650 static int http_receive_data(HTTPContext *c)
2653 int len, loop_run = 0;
2655 while (c->chunked_encoding && !c->chunk_size &&
2656 c->buffer_end > c->buffer_ptr) {
2657 /* read chunk header, if present */
2658 len = recv(c->fd, c->buffer_ptr, 1, 0);
2661 if (ff_neterrno() != AVERROR(EAGAIN) &&
2662 ff_neterrno() != AVERROR(EINTR))
2663 /* error : close connection */
2666 } else if (len == 0) {
2667 /* end of connection : close it */
2669 } else if (c->buffer_ptr - c->buffer >= 2 &&
2670 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2671 c->chunk_size = strtol(c->buffer, 0, 16);
2672 if (c->chunk_size == 0) // end of stream
2674 c->buffer_ptr = c->buffer;
2676 } else if (++loop_run > 10) {
2677 /* no chunk header, abort */
2684 if (c->buffer_end > c->buffer_ptr) {
2685 len = recv(c->fd, c->buffer_ptr,
2686 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2688 if (ff_neterrno() != AVERROR(EAGAIN) &&
2689 ff_neterrno() != AVERROR(EINTR))
2690 /* error : close connection */
2692 } else if (len == 0)
2693 /* end of connection : close it */
2696 c->chunk_size -= len;
2697 c->buffer_ptr += len;
2698 c->data_count += len;
2699 update_datarate(&c->datarate, c->data_count);
2703 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2704 if (c->buffer[0] != 'f' ||
2705 c->buffer[1] != 'm') {
2706 http_log("Feed stream has become desynchronized -- disconnecting\n");
2711 if (c->buffer_ptr >= c->buffer_end) {
2712 FFStream *feed = c->stream;
2713 /* a packet has been received : write it in the store, except
2715 if (c->data_count > FFM_PACKET_SIZE) {
2716 /* XXX: use llseek or url_seek */
2717 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2718 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2719 http_log("Error writing to feed file: %s\n", strerror(errno));
2723 feed->feed_write_index += FFM_PACKET_SIZE;
2724 /* update file size */
2725 if (feed->feed_write_index > c->stream->feed_size)
2726 feed->feed_size = feed->feed_write_index;
2728 /* handle wrap around if max file size reached */
2729 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2730 feed->feed_write_index = FFM_PACKET_SIZE;
2733 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2734 http_log("Error writing index to feed file: %s\n", strerror(errno));
2738 /* wake up any waiting connections */
2739 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2740 if (c1->state == HTTPSTATE_WAIT_FEED &&
2741 c1->stream->feed == c->stream->feed)
2742 c1->state = HTTPSTATE_SEND_DATA;
2745 /* We have a header in our hands that contains useful data */
2746 AVFormatContext *s = avformat_alloc_context();
2748 AVInputFormat *fmt_in;
2754 /* use feed output format name to find corresponding input format */
2755 fmt_in = av_find_input_format(feed->fmt->name);
2759 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2760 0, NULL, NULL, NULL, NULL);
2764 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2769 /* Now we have the actual streams */
2770 if (s->nb_streams != feed->nb_streams) {
2771 avformat_close_input(&s);
2773 http_log("Feed '%s' stream number does not match registered feed\n",
2774 c->stream->feed_filename);
2778 for (i = 0; i < s->nb_streams; i++) {
2779 AVStream *fst = feed->streams[i];
2780 AVStream *st = s->streams[i];
2781 avcodec_copy_context(fst->codec, st->codec);
2784 avformat_close_input(&s);
2787 c->buffer_ptr = c->buffer;
2792 c->stream->feed_opened = 0;
2794 /* wake up any waiting connections to stop waiting for feed */
2795 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2796 if (c1->state == HTTPSTATE_WAIT_FEED &&
2797 c1->stream->feed == c->stream->feed)
2798 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2803 /********************************************************************/
2806 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2813 switch(error_number) {
2814 case RTSP_STATUS_OK:
2817 case RTSP_STATUS_METHOD:
2818 str = "Method Not Allowed";
2820 case RTSP_STATUS_BANDWIDTH:
2821 str = "Not Enough Bandwidth";
2823 case RTSP_STATUS_SESSION:
2824 str = "Session Not Found";
2826 case RTSP_STATUS_STATE:
2827 str = "Method Not Valid in This State";
2829 case RTSP_STATUS_AGGREGATE:
2830 str = "Aggregate operation not allowed";
2832 case RTSP_STATUS_ONLY_AGGREGATE:
2833 str = "Only aggregate operation allowed";
2835 case RTSP_STATUS_TRANSPORT:
2836 str = "Unsupported transport";
2838 case RTSP_STATUS_INTERNAL:
2839 str = "Internal Server Error";
2841 case RTSP_STATUS_SERVICE:
2842 str = "Service Unavailable";
2844 case RTSP_STATUS_VERSION:
2845 str = "RTSP Version not supported";
2848 str = "Unknown Error";
2852 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2853 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2855 /* output GMT time */
2858 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2859 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2862 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2864 rtsp_reply_header(c, error_number);
2865 avio_printf(c->pb, "\r\n");
2868 static int rtsp_parse_request(HTTPContext *c)
2870 const char *p, *p1, *p2;
2876 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2878 c->buffer_ptr[0] = '\0';
2881 get_word(cmd, sizeof(cmd), &p);
2882 get_word(url, sizeof(url), &p);
2883 get_word(protocol, sizeof(protocol), &p);
2885 av_strlcpy(c->method, cmd, sizeof(c->method));
2886 av_strlcpy(c->url, url, sizeof(c->url));
2887 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2889 if (avio_open_dyn_buf(&c->pb) < 0) {
2890 /* XXX: cannot do more */
2891 c->pb = NULL; /* safety */
2895 /* check version name */
2896 if (strcmp(protocol, "RTSP/1.0") != 0) {
2897 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2901 /* parse each header line */
2902 /* skip to next line */
2903 while (*p != '\n' && *p != '\0')
2907 while (*p != '\0') {
2908 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2912 if (p2 > p && p2[-1] == '\r')
2914 /* skip empty line */
2918 if (len > sizeof(line) - 1)
2919 len = sizeof(line) - 1;
2920 memcpy(line, p, len);
2922 ff_rtsp_parse_line(header, line, NULL, NULL);
2926 /* handle sequence number */
2927 c->seq = header->seq;
2929 if (!strcmp(cmd, "DESCRIBE"))
2930 rtsp_cmd_describe(c, url);
2931 else if (!strcmp(cmd, "OPTIONS"))
2932 rtsp_cmd_options(c, url);
2933 else if (!strcmp(cmd, "SETUP"))
2934 rtsp_cmd_setup(c, url, header);
2935 else if (!strcmp(cmd, "PLAY"))
2936 rtsp_cmd_play(c, url, header);
2937 else if (!strcmp(cmd, "PAUSE"))
2938 rtsp_cmd_pause(c, url, header);
2939 else if (!strcmp(cmd, "TEARDOWN"))
2940 rtsp_cmd_teardown(c, url, header);
2942 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2945 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2946 c->pb = NULL; /* safety */
2948 /* XXX: cannot do more */
2951 c->buffer_ptr = c->pb_buffer;
2952 c->buffer_end = c->pb_buffer + len;
2953 c->state = RTSPSTATE_SEND_REPLY;
2957 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2958 struct in_addr my_ip)
2960 AVFormatContext *avc;
2961 AVStream *avs = NULL;
2962 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2965 avc = avformat_alloc_context();
2966 if (avc == NULL || !rtp_format) {
2969 avc->oformat = rtp_format;
2970 av_dict_set(&avc->metadata, "title",
2971 stream->title[0] ? stream->title : "No Title", 0);
2972 avc->nb_streams = stream->nb_streams;
2973 if (stream->is_multicast) {
2974 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2975 inet_ntoa(stream->multicast_ip),
2976 stream->multicast_port, stream->multicast_ttl);
2978 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2981 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2982 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2984 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2985 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2988 for(i = 0; i < stream->nb_streams; i++) {
2989 avc->streams[i] = &avs[i];
2990 avc->streams[i]->codec = stream->streams[i]->codec;
2992 *pbuffer = av_mallocz(2048);
2993 av_sdp_create(&avc, 1, *pbuffer, 2048);
2996 av_free(avc->streams);
2997 av_dict_free(&avc->metadata);
3001 return strlen(*pbuffer);
3004 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3006 // rtsp_reply_header(c, RTSP_STATUS_OK);
3007 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3008 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3009 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3010 avio_printf(c->pb, "\r\n");
3013 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3021 struct sockaddr_in my_addr;
3023 /* find which url is asked */
3024 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3029 for(stream = first_stream; stream != NULL; stream = stream->next) {
3030 if (!stream->is_feed &&
3031 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3032 !strcmp(path, stream->filename)) {
3036 /* no stream found */
3037 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3041 /* prepare the media description in sdp format */
3043 /* get the host IP */
3044 len = sizeof(my_addr);
3045 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3046 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3047 if (content_length < 0) {
3048 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3051 rtsp_reply_header(c, RTSP_STATUS_OK);
3052 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3053 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3054 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3055 avio_printf(c->pb, "\r\n");
3056 avio_write(c->pb, content, content_length);
3060 static HTTPContext *find_rtp_session(const char *session_id)
3064 if (session_id[0] == '\0')
3067 for(c = first_http_ctx; c != NULL; c = c->next) {
3068 if (!strcmp(c->session_id, session_id))
3074 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3076 RTSPTransportField *th;
3079 for(i=0;i<h->nb_transports;i++) {
3080 th = &h->transports[i];
3081 if (th->lower_transport == lower_transport)
3087 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3088 RTSPMessageHeader *h)
3091 int stream_index, rtp_port, rtcp_port;
3096 RTSPTransportField *th;
3097 struct sockaddr_in dest_addr;
3098 RTSPActionServerSetup setup;
3100 /* find which url is asked */
3101 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3106 /* now check each stream */
3107 for(stream = first_stream; stream != NULL; stream = stream->next) {
3108 if (!stream->is_feed &&
3109 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3110 /* accept aggregate filenames only if single stream */
3111 if (!strcmp(path, stream->filename)) {
3112 if (stream->nb_streams != 1) {
3113 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3120 for(stream_index = 0; stream_index < stream->nb_streams;
3122 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3123 stream->filename, stream_index);
3124 if (!strcmp(path, buf))
3129 /* no stream found */
3130 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3134 /* generate session id if needed */
3135 if (h->session_id[0] == '\0') {
3136 unsigned random0 = av_lfg_get(&random_state);
3137 unsigned random1 = av_lfg_get(&random_state);
3138 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3142 /* find rtp session, and create it if none found */
3143 rtp_c = find_rtp_session(h->session_id);
3145 /* always prefer UDP */
3146 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3148 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3150 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3155 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3156 th->lower_transport);
3158 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3162 /* open input stream */
3163 if (open_input_stream(rtp_c, "") < 0) {
3164 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3169 /* test if stream is OK (test needed because several SETUP needs
3170 to be done for a given file) */
3171 if (rtp_c->stream != stream) {
3172 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3176 /* test if stream is already set up */
3177 if (rtp_c->rtp_ctx[stream_index]) {
3178 rtsp_reply_error(c, RTSP_STATUS_STATE);
3182 /* check transport */
3183 th = find_transport(h, rtp_c->rtp_protocol);
3184 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3185 th->client_port_min <= 0)) {
3186 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3190 /* setup default options */
3191 setup.transport_option[0] = '\0';
3192 dest_addr = rtp_c->from_addr;
3193 dest_addr.sin_port = htons(th->client_port_min);
3196 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3197 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3201 /* now everything is OK, so we can send the connection parameters */
3202 rtsp_reply_header(c, RTSP_STATUS_OK);
3204 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3206 switch(rtp_c->rtp_protocol) {
3207 case RTSP_LOWER_TRANSPORT_UDP:
3208 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3209 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3210 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3211 "client_port=%d-%d;server_port=%d-%d",
3212 th->client_port_min, th->client_port_max,
3213 rtp_port, rtcp_port);
3215 case RTSP_LOWER_TRANSPORT_TCP:
3216 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3217 stream_index * 2, stream_index * 2 + 1);
3222 if (setup.transport_option[0] != '\0')
3223 avio_printf(c->pb, ";%s", setup.transport_option);
3224 avio_printf(c->pb, "\r\n");
3227 avio_printf(c->pb, "\r\n");
3231 /* find an rtp connection by using the session ID. Check consistency
3233 static HTTPContext *find_rtp_session_with_url(const char *url,
3234 const char *session_id)
3242 rtp_c = find_rtp_session(session_id);
3246 /* find which url is asked */
3247 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3251 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3252 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3253 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3254 rtp_c->stream->filename, s);
3255 if(!strncmp(path, buf, sizeof(buf))) {
3256 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3261 if (len > 0 && path[len - 1] == '/' &&
3262 !strncmp(path, rtp_c->stream->filename, len - 1))
3267 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3271 rtp_c = find_rtp_session_with_url(url, h->session_id);
3273 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3277 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3278 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3279 rtp_c->state != HTTPSTATE_READY) {
3280 rtsp_reply_error(c, RTSP_STATUS_STATE);
3284 rtp_c->state = HTTPSTATE_SEND_DATA;
3286 /* now everything is OK, so we can send the connection parameters */
3287 rtsp_reply_header(c, RTSP_STATUS_OK);
3289 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3290 avio_printf(c->pb, "\r\n");
3293 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3297 rtp_c = find_rtp_session_with_url(url, h->session_id);
3299 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3303 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3304 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3305 rtsp_reply_error(c, RTSP_STATUS_STATE);
3309 rtp_c->state = HTTPSTATE_READY;
3310 rtp_c->first_pts = AV_NOPTS_VALUE;
3311 /* now everything is OK, so we can send the connection parameters */
3312 rtsp_reply_header(c, RTSP_STATUS_OK);
3314 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3315 avio_printf(c->pb, "\r\n");
3318 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3322 rtp_c = find_rtp_session_with_url(url, h->session_id);
3324 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3328 /* now everything is OK, so we can send the connection parameters */
3329 rtsp_reply_header(c, RTSP_STATUS_OK);
3331 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3332 avio_printf(c->pb, "\r\n");
3334 /* abort the session */
3335 close_connection(rtp_c);
3339 /********************************************************************/
3342 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3343 FFStream *stream, const char *session_id,
3344 enum RTSPLowerTransport rtp_protocol)
3346 HTTPContext *c = NULL;
3347 const char *proto_str;
3349 /* XXX: should output a warning page when coming
3350 close to the connection limit */
3351 if (nb_connections >= nb_max_connections)
3354 /* add a new connection */
3355 c = av_mallocz(sizeof(HTTPContext));
3360 c->poll_entry = NULL;
3361 c->from_addr = *from_addr;
3362 c->buffer_size = IOBUFFER_INIT_SIZE;
3363 c->buffer = av_malloc(c->buffer_size);
3368 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3369 c->state = HTTPSTATE_READY;
3370 c->is_packetized = 1;
3371 c->rtp_protocol = rtp_protocol;
3373 /* protocol is shown in statistics */
3374 switch(c->rtp_protocol) {
3375 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3376 proto_str = "MCAST";
3378 case RTSP_LOWER_TRANSPORT_UDP:
3381 case RTSP_LOWER_TRANSPORT_TCP:
3388 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3389 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3391 current_bandwidth += stream->bandwidth;
3393 c->next = first_http_ctx;
3405 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3406 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3408 static int rtp_new_av_stream(HTTPContext *c,
3409 int stream_index, struct sockaddr_in *dest_addr,
3410 HTTPContext *rtsp_c)
3412 AVFormatContext *ctx;
3415 URLContext *h = NULL;
3417 int max_packet_size;
3419 /* now we can open the relevant output stream */
3420 ctx = avformat_alloc_context();
3423 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3425 st = av_mallocz(sizeof(AVStream));
3428 ctx->nb_streams = 1;
3429 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3432 ctx->streams[0] = st;
3434 if (!c->stream->feed ||
3435 c->stream->feed == c->stream)
3436 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3439 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3441 st->priv_data = NULL;
3443 /* build destination RTP address */
3444 ipaddr = inet_ntoa(dest_addr->sin_addr);
3446 switch(c->rtp_protocol) {
3447 case RTSP_LOWER_TRANSPORT_UDP:
3448 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3451 /* XXX: also pass as parameter to function ? */
3452 if (c->stream->is_multicast) {
3454 ttl = c->stream->multicast_ttl;
3457 snprintf(ctx->filename, sizeof(ctx->filename),
3458 "rtp://%s:%d?multicast=1&ttl=%d",
3459 ipaddr, ntohs(dest_addr->sin_port), ttl);
3461 snprintf(ctx->filename, sizeof(ctx->filename),
3462 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3465 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3467 c->rtp_handles[stream_index] = h;
3468 max_packet_size = h->max_packet_size;
3470 case RTSP_LOWER_TRANSPORT_TCP:
3473 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3479 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3480 ipaddr, ntohs(dest_addr->sin_port),
3481 c->stream->filename, stream_index, c->protocol);
3483 /* normally, no packets should be output here, but the packet size may be checked */
3484 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3485 /* XXX: close stream */
3488 if (avformat_write_header(ctx, NULL) < 0) {
3495 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3498 c->rtp_ctx[stream_index] = ctx;
3502 /********************************************************************/
3503 /* ffserver initialization */
3505 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3509 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3512 fst = av_mallocz(sizeof(AVStream));
3516 fst->codec = avcodec_alloc_context3(NULL);
3517 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3518 if (codec->extradata_size) {
3519 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3520 memcpy(fst->codec->extradata, codec->extradata,
3521 codec->extradata_size);
3524 /* live streams must use the actual feed's codec since it may be
3525 * updated later to carry extradata needed by the streams.
3529 fst->priv_data = av_mallocz(sizeof(FeedData));
3530 fst->index = stream->nb_streams;
3531 avpriv_set_pts_info(fst, 33, 1, 90000);
3532 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3533 stream->streams[stream->nb_streams++] = fst;
3537 /* return the stream number in the feed */
3538 static int add_av_stream(FFStream *feed, AVStream *st)
3541 AVCodecContext *av, *av1;
3545 for(i=0;i<feed->nb_streams;i++) {
3546 st = feed->streams[i];
3548 if (av1->codec_id == av->codec_id &&
3549 av1->codec_type == av->codec_type &&
3550 av1->bit_rate == av->bit_rate) {
3552 switch(av->codec_type) {
3553 case AVMEDIA_TYPE_AUDIO:
3554 if (av1->channels == av->channels &&
3555 av1->sample_rate == av->sample_rate)
3558 case AVMEDIA_TYPE_VIDEO:
3559 if (av1->width == av->width &&
3560 av1->height == av->height &&
3561 av1->time_base.den == av->time_base.den &&
3562 av1->time_base.num == av->time_base.num &&
3563 av1->gop_size == av->gop_size)
3572 fst = add_av_stream1(feed, av, 0);
3575 return feed->nb_streams - 1;
3578 static void remove_stream(FFStream *stream)
3582 while (*ps != NULL) {
3590 /* specific mpeg4 handling : we extract the raw parameters */
3591 static void extract_mpeg4_header(AVFormatContext *infile)
3593 int mpeg4_count, i, size;
3598 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3601 for(i=0;i<infile->nb_streams;i++) {
3602 st = infile->streams[i];
3603 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3604 st->codec->extradata_size == 0) {
3611 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3612 while (mpeg4_count > 0) {
3613 if (av_read_frame(infile, &pkt) < 0)
3615 st = infile->streams[pkt.stream_index];
3616 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3617 st->codec->extradata_size == 0) {
3618 av_freep(&st->codec->extradata);
3619 /* fill extradata with the header */
3620 /* XXX: we make hard suppositions here ! */
3622 while (p < pkt.data + pkt.size - 4) {
3623 /* stop when vop header is found */
3624 if (p[0] == 0x00 && p[1] == 0x00 &&
3625 p[2] == 0x01 && p[3] == 0xb6) {
3626 size = p - pkt.data;
3627 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3628 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3629 st->codec->extradata_size = size;
3630 memcpy(st->codec->extradata, pkt.data, size);
3637 av_free_packet(&pkt);
3641 /* compute the needed AVStream for each file */
3642 static void build_file_streams(void)
3644 FFStream *stream, *stream_next;
3647 /* gather all streams */
3648 for(stream = first_stream; stream != NULL; stream = stream_next) {
3649 AVFormatContext *infile = NULL;
3650 stream_next = stream->next;
3651 if (stream->stream_type == STREAM_TYPE_LIVE &&
3653 /* the stream comes from a file */
3654 /* try to open the file */
3656 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3657 /* specific case : if transport stream output to RTP,
3658 we use a raw transport stream reader */
3659 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3662 http_log("Opening file '%s'\n", stream->feed_filename);
3663 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3664 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3665 /* remove stream (no need to spend more time on it) */
3667 remove_stream(stream);
3669 /* find all the AVStreams inside and reference them in
3671 if (avformat_find_stream_info(infile, NULL) < 0) {
3672 http_log("Could not find codec parameters from '%s'\n",
3673 stream->feed_filename);
3674 avformat_close_input(&infile);
3677 extract_mpeg4_header(infile);
3679 for(i=0;i<infile->nb_streams;i++)
3680 add_av_stream1(stream, infile->streams[i]->codec, 1);
3682 avformat_close_input(&infile);
3688 /* compute the needed AVStream for each feed */
3689 static void build_feed_streams(void)
3691 FFStream *stream, *feed;
3694 /* gather all streams */
3695 for(stream = first_stream; stream != NULL; stream = stream->next) {
3696 feed = stream->feed;
3698 if (stream->is_feed) {
3699 for(i=0;i<stream->nb_streams;i++)
3700 stream->feed_streams[i] = i;
3702 /* we handle a stream coming from a feed */
3703 for(i=0;i<stream->nb_streams;i++)
3704 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3709 /* create feed files if needed */
3710 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3713 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3714 /* See if it matches */
3715 AVFormatContext *s = NULL;
3718 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3719 /* set buffer size */
3720 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3721 /* Now see if it matches */
3722 if (s->nb_streams == feed->nb_streams) {
3724 for(i=0;i<s->nb_streams;i++) {
3726 sf = feed->streams[i];
3729 if (sf->index != ss->index ||
3731 http_log("Index & Id do not match for stream %d (%s)\n",
3732 i, feed->feed_filename);
3735 AVCodecContext *ccf, *ccs;
3739 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3741 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3742 http_log("Codecs do not match for stream %d\n", i);
3744 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3745 http_log("Codec bitrates do not match for stream %d\n", i);
3747 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3748 if (CHECK_CODEC(time_base.den) ||
3749 CHECK_CODEC(time_base.num) ||
3750 CHECK_CODEC(width) ||
3751 CHECK_CODEC(height)) {
3752 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3755 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3756 if (CHECK_CODEC(sample_rate) ||
3757 CHECK_CODEC(channels) ||
3758 CHECK_CODEC(frame_size)) {
3759 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3763 http_log("Unknown codec type\n");
3771 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3772 feed->feed_filename, s->nb_streams, feed->nb_streams);
3774 avformat_close_input(&s);
3776 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3777 feed->feed_filename);
3780 if (feed->readonly) {
3781 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3782 feed->feed_filename);
3785 unlink(feed->feed_filename);
3788 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3789 AVFormatContext s1 = {0}, *s = &s1;
3791 if (feed->readonly) {
3792 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3793 feed->feed_filename);
3797 /* only write the header of the ffm file */
3798 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3799 http_log("Could not open output feed file '%s'\n",
3800 feed->feed_filename);
3803 s->oformat = feed->fmt;
3804 s->nb_streams = feed->nb_streams;
3805 s->streams = feed->streams;
3806 if (avformat_write_header(s, NULL) < 0) {
3807 http_log("Container doesn't support the required parameters\n");
3810 /* XXX: need better api */
3811 av_freep(&s->priv_data);
3814 /* get feed size and write index */
3815 fd = open(feed->feed_filename, O_RDONLY);
3817 http_log("Could not open output feed file '%s'\n",
3818 feed->feed_filename);
3822 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3823 feed->feed_size = lseek(fd, 0, SEEK_END);
3824 /* ensure that we do not wrap before the end of file */
3825 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3826 feed->feed_max_size = feed->feed_size;
3832 /* compute the bandwidth used by each stream */
3833 static void compute_bandwidth(void)
3839 for(stream = first_stream; stream != NULL; stream = stream->next) {
3841 for(i=0;i<stream->nb_streams;i++) {
3842 AVStream *st = stream->streams[i];
3843 switch(st->codec->codec_type) {
3844 case AVMEDIA_TYPE_AUDIO:
3845 case AVMEDIA_TYPE_VIDEO:
3846 bandwidth += st->codec->bit_rate;
3852 stream->bandwidth = (bandwidth + 999) / 1000;
3856 /* add a codec and set the default parameters */
3857 static void add_codec(FFStream *stream, AVCodecContext *av)
3861 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3864 /* compute default parameters */
3865 switch(av->codec_type) {
3866 case AVMEDIA_TYPE_AUDIO:
3867 if (av->bit_rate == 0)
3868 av->bit_rate = 64000;
3869 if (av->sample_rate == 0)
3870 av->sample_rate = 22050;
3871 if (av->channels == 0)
3874 case AVMEDIA_TYPE_VIDEO:
3875 if (av->bit_rate == 0)
3876 av->bit_rate = 64000;
3877 if (av->time_base.num == 0){
3878 av->time_base.den = 5;
3879 av->time_base.num = 1;
3881 if (av->width == 0 || av->height == 0) {
3885 /* Bitrate tolerance is less for streaming */
3886 if (av->bit_rate_tolerance == 0)
3887 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3888 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3893 if (av->max_qdiff == 0)
3895 av->qcompress = 0.5;
3898 if (!av->nsse_weight)
3899 av->nsse_weight = 8;
3901 av->frame_skip_cmp = FF_CMP_DCTMAX;
3903 av->me_method = ME_EPZS;
3904 av->rc_buffer_aggressivity = 1.0;
3907 av->rc_eq = av_strdup("tex^qComp");
3908 if (!av->i_quant_factor)
3909 av->i_quant_factor = -0.8;
3910 if (!av->b_quant_factor)
3911 av->b_quant_factor = 1.25;
3912 if (!av->b_quant_offset)
3913 av->b_quant_offset = 1.25;
3914 if (!av->rc_max_rate)
3915 av->rc_max_rate = av->bit_rate * 2;
3917 if (av->rc_max_rate && !av->rc_buffer_size) {
3918 av->rc_buffer_size = av->rc_max_rate;
3927 st = av_mallocz(sizeof(AVStream));
3930 st->codec = avcodec_alloc_context3(NULL);
3931 stream->streams[stream->nb_streams++] = st;
3932 memcpy(st->codec, av, sizeof(AVCodecContext));
3935 static enum AVCodecID opt_audio_codec(const char *arg)
3937 AVCodec *p= avcodec_find_encoder_by_name(arg);
3939 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3940 return AV_CODEC_ID_NONE;
3945 static enum AVCodecID opt_video_codec(const char *arg)
3947 AVCodec *p= avcodec_find_encoder_by_name(arg);
3949 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3950 return AV_CODEC_ID_NONE;
3955 static int ffserver_opt_default(const char *opt, const char *arg,
3956 AVCodecContext *avctx, int type)
3959 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3961 ret = av_opt_set(avctx, opt, arg, 0);
3965 static int ffserver_opt_preset(const char *arg,
3966 AVCodecContext *avctx, int type,
3967 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3970 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3972 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3974 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3975 codec ? codec->name : NULL))) {
3976 fprintf(stderr, "File for preset '%s' not found\n", arg);
3981 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3982 if(line[0] == '#' && !e)
3984 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3986 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3990 if(!strcmp(tmp, "acodec")){
3991 *audio_id = opt_audio_codec(tmp2);
3992 }else if(!strcmp(tmp, "vcodec")){
3993 *video_id = opt_video_codec(tmp2);
3994 }else if(!strcmp(tmp, "scodec")){
3995 /* opt_subtitle_codec(tmp2); */
3996 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3997 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4008 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4009 const char *mime_type)
4011 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4014 AVOutputFormat *stream_fmt;
4015 char stream_format_name[64];
4017 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4018 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4027 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4031 fprintf(stderr, "%s:%d: ", filename, line_num);
4032 vfprintf(stderr, fmt, vl);
4038 static int parse_ffconfig(const char *filename)
4045 int val, errors, line_num;
4046 FFStream **last_stream, *stream, *redirect;
4047 FFStream **last_feed, *feed, *s;
4048 AVCodecContext audio_enc, video_enc;
4049 enum AVCodecID audio_id, video_id;
4051 f = fopen(filename, "r");
4059 first_stream = NULL;
4060 last_stream = &first_stream;
4062 last_feed = &first_feed;
4066 audio_id = AV_CODEC_ID_NONE;
4067 video_id = AV_CODEC_ID_NONE;
4069 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4071 if (fgets(line, sizeof(line), f) == NULL)
4075 while (av_isspace(*p))
4077 if (*p == '\0' || *p == '#')
4080 get_arg(cmd, sizeof(cmd), &p);
4082 if (!av_strcasecmp(cmd, "Port")) {
4083 get_arg(arg, sizeof(arg), &p);
4085 if (val < 1 || val > 65536) {
4086 ERROR("Invalid_port: %s\n", arg);
4088 my_http_addr.sin_port = htons(val);
4089 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4090 get_arg(arg, sizeof(arg), &p);
4091 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4092 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4094 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4095 // do nothing here, its the default now
4096 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4097 get_arg(arg, sizeof(arg), &p);
4099 if (val < 1 || val > 65536) {
4100 ERROR("%s:%d: Invalid port: %s\n", arg);
4102 my_rtsp_addr.sin_port = htons(atoi(arg));
4103 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4104 get_arg(arg, sizeof(arg), &p);
4105 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4106 ERROR("Invalid host/IP address: %s\n", arg);
4108 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4109 get_arg(arg, sizeof(arg), &p);
4111 if (val < 1 || val > 65536) {
4112 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4114 nb_max_http_connections = val;
4115 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4116 get_arg(arg, sizeof(arg), &p);
4118 if (val < 1 || val > nb_max_http_connections) {
4119 ERROR("Invalid MaxClients: %s\n", arg);
4121 nb_max_connections = val;
4123 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4125 get_arg(arg, sizeof(arg), &p);
4126 llval = strtoll(arg, NULL, 10);
4127 if (llval < 10 || llval > 10000000) {
4128 ERROR("Invalid MaxBandwidth: %s\n", arg);
4130 max_bandwidth = llval;
4131 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4132 if (!ffserver_debug)
4133 get_arg(logfilename, sizeof(logfilename), &p);
4134 } else if (!av_strcasecmp(cmd, "<Feed")) {
4135 /*********************************************/
4136 /* Feed related options */
4138 if (stream || feed) {
4139 ERROR("Already in a tag\n");
4141 feed = av_mallocz(sizeof(FFStream));
4142 get_arg(feed->filename, sizeof(feed->filename), &p);
4143 q = strrchr(feed->filename, '>');
4147 for (s = first_feed; s; s = s->next) {
4148 if (!strcmp(feed->filename, s->filename)) {
4149 ERROR("Feed '%s' already registered\n", s->filename);
4153 feed->fmt = av_guess_format("ffm", NULL, NULL);
4154 /* defaut feed file */
4155 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4156 "/tmp/%s.ffm", feed->filename);
4157 feed->feed_max_size = 5 * 1024 * 1024;
4159 feed->feed = feed; /* self feeding :-) */
4161 /* add in stream list */
4162 *last_stream = feed;
4163 last_stream = &feed->next;
4164 /* add in feed list */
4166 last_feed = &feed->next_feed;
4168 } else if (!av_strcasecmp(cmd, "Launch")) {
4172 feed->child_argv = av_mallocz(64 * sizeof(char *));
4174 for (i = 0; i < 62; i++) {
4175 get_arg(arg, sizeof(arg), &p);
4179 feed->child_argv[i] = av_strdup(arg);
4182 feed->child_argv[i] = av_asprintf("http://%s:%d/%s",
4183 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4184 inet_ntoa(my_http_addr.sin_addr),
4185 ntohs(my_http_addr.sin_port), feed->filename);
4187 } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
4189 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4191 } else if (stream) {
4192 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4194 } else if (!av_strcasecmp(cmd, "File")) {
4196 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4198 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4199 } else if (!av_strcasecmp(cmd, "Truncate")) {
4201 get_arg(arg, sizeof(arg), &p);
4202 feed->truncate = strtod(arg, NULL);
4204 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4209 get_arg(arg, sizeof(arg), &p);
4211 fsize = strtod(p1, &p1);
4212 switch(av_toupper(*p1)) {
4217 fsize *= 1024 * 1024;
4220 fsize *= 1024 * 1024 * 1024;
4223 feed->feed_max_size = (int64_t)fsize;
4224 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4225 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4228 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4230 ERROR("No corresponding <Feed> for </Feed>\n");
4233 } else if (!av_strcasecmp(cmd, "<Stream")) {
4234 /*********************************************/
4235 /* Stream related options */
4237 if (stream || feed) {
4238 ERROR("Already in a tag\n");
4241 stream = av_mallocz(sizeof(FFStream));
4242 get_arg(stream->filename, sizeof(stream->filename), &p);
4243 q = strrchr(stream->filename, '>');
4247 for (s = first_stream; s; s = s->next) {
4248 if (!strcmp(stream->filename, s->filename)) {
4249 ERROR("Stream '%s' already registered\n", s->filename);
4253 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4254 avcodec_get_context_defaults3(&video_enc, NULL);
4255 avcodec_get_context_defaults3(&audio_enc, NULL);
4257 audio_id = AV_CODEC_ID_NONE;
4258 video_id = AV_CODEC_ID_NONE;
4260 audio_id = stream->fmt->audio_codec;
4261 video_id = stream->fmt->video_codec;
4264 *last_stream = stream;
4265 last_stream = &stream->next;
4267 } else if (!av_strcasecmp(cmd, "Feed")) {
4268 get_arg(arg, sizeof(arg), &p);
4273 while (sfeed != NULL) {
4274 if (!strcmp(sfeed->filename, arg))
4276 sfeed = sfeed->next_feed;
4279 ERROR("feed '%s' not defined\n", arg);
4281 stream->feed = sfeed;
4283 } else if (!av_strcasecmp(cmd, "Format")) {
4284 get_arg(arg, sizeof(arg), &p);
4286 if (!strcmp(arg, "status")) {
4287 stream->stream_type = STREAM_TYPE_STATUS;
4290 stream->stream_type = STREAM_TYPE_LIVE;
4291 /* jpeg cannot be used here, so use single frame jpeg */
4292 if (!strcmp(arg, "jpeg"))
4293 strcpy(arg, "mjpeg");
4294 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4296 ERROR("Unknown Format: %s\n", arg);
4300 audio_id = stream->fmt->audio_codec;
4301 video_id = stream->fmt->video_codec;
4304 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4305 get_arg(arg, sizeof(arg), &p);
4307 stream->ifmt = av_find_input_format(arg);
4308 if (!stream->ifmt) {
4309 ERROR("Unknown input format: %s\n", arg);
4312 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4313 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4314 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4316 ERROR("FaviconURL only permitted for status streams\n");
4318 } else if (!av_strcasecmp(cmd, "Author")) {
4320 get_arg(stream->author, sizeof(stream->author), &p);
4321 } else if (!av_strcasecmp(cmd, "Comment")) {
4323 get_arg(stream->comment, sizeof(stream->comment), &p);
4324 } else if (!av_strcasecmp(cmd, "Copyright")) {
4326 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4327 } else if (!av_strcasecmp(cmd, "Title")) {
4329 get_arg(stream->title, sizeof(stream->title), &p);
4330 } else if (!av_strcasecmp(cmd, "Preroll")) {
4331 get_arg(arg, sizeof(arg), &p);
4333 stream->prebuffer = atof(arg) * 1000;
4334 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4336 stream->send_on_key = 1;
4337 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4338 get_arg(arg, sizeof(arg), &p);
4339 audio_id = opt_audio_codec(arg);
4340 if (audio_id == AV_CODEC_ID_NONE) {
4341 ERROR("Unknown AudioCodec: %s\n", arg);
4343 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4344 get_arg(arg, sizeof(arg), &p);
4345 video_id = opt_video_codec(arg);
4346 if (video_id == AV_CODEC_ID_NONE) {
4347 ERROR("Unknown VideoCodec: %s\n", arg);
4349 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4350 get_arg(arg, sizeof(arg), &p);
4352 stream->max_time = atof(arg) * 1000;
4353 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4354 get_arg(arg, sizeof(arg), &p);
4356 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4357 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4358 get_arg(arg, sizeof(arg), &p);
4360 audio_enc.channels = atoi(arg);
4361 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4362 get_arg(arg, sizeof(arg), &p);
4364 audio_enc.sample_rate = atoi(arg);
4365 } else if (!av_strcasecmp(cmd, "AudioQuality")) {
4366 get_arg(arg, sizeof(arg), &p);
4368 // audio_enc.quality = atof(arg) * 1000;
4370 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4372 int minrate, maxrate;
4374 get_arg(arg, sizeof(arg), &p);
4376 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4377 video_enc.rc_min_rate = minrate * 1000;
4378 video_enc.rc_max_rate = maxrate * 1000;
4380 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4383 } else if (!av_strcasecmp(cmd, "Debug")) {
4385 get_arg(arg, sizeof(arg), &p);
4386 video_enc.debug = strtol(arg,0,0);
4388 } else if (!av_strcasecmp(cmd, "Strict")) {
4390 get_arg(arg, sizeof(arg), &p);
4391 video_enc.strict_std_compliance = atoi(arg);
4393 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4395 get_arg(arg, sizeof(arg), &p);
4396 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4398 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4400 get_arg(arg, sizeof(arg), &p);
4401 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4403 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4404 get_arg(arg, sizeof(arg), &p);
4406 video_enc.bit_rate = atoi(arg) * 1000;
4408 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4409 get_arg(arg, sizeof(arg), &p);
4411 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4412 if ((video_enc.width % 16) != 0 ||
4413 (video_enc.height % 16) != 0) {
4414 ERROR("Image size must be a multiple of 16\n");
4417 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4418 get_arg(arg, sizeof(arg), &p);
4420 AVRational frame_rate;
4421 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4422 ERROR("Incorrect frame rate: %s\n", arg);
4424 video_enc.time_base.num = frame_rate.den;
4425 video_enc.time_base.den = frame_rate.num;
4428 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4429 get_arg(arg, sizeof(arg), &p);
4431 video_enc.gop_size = atoi(arg);
4432 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4434 video_enc.gop_size = 1;
4435 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4437 video_enc.mb_decision = FF_MB_DECISION_BITS;
4438 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4440 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4441 video_enc.flags |= CODEC_FLAG_4MV;
4443 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4444 !av_strcasecmp(cmd, "AVOptionAudio")) {
4446 AVCodecContext *avctx;
4448 get_arg(arg, sizeof(arg), &p);
4449 get_arg(arg2, sizeof(arg2), &p);
4450 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4452 type = AV_OPT_FLAG_VIDEO_PARAM;
4455 type = AV_OPT_FLAG_AUDIO_PARAM;
4457 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4458 ERROR("AVOption error: %s %s\n", arg, arg2);
4460 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4461 !av_strcasecmp(cmd, "AVPresetAudio")) {
4462 AVCodecContext *avctx;
4464 get_arg(arg, sizeof(arg), &p);
4465 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4467 video_enc.codec_id = video_id;
4468 type = AV_OPT_FLAG_VIDEO_PARAM;
4471 audio_enc.codec_id = audio_id;
4472 type = AV_OPT_FLAG_AUDIO_PARAM;
4474 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4475 ERROR("AVPreset error: %s\n", arg);
4477 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4478 get_arg(arg, sizeof(arg), &p);
4479 if ((strlen(arg) == 4) && stream)
4480 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4481 } else if (!av_strcasecmp(cmd, "BitExact")) {
4483 video_enc.flags |= CODEC_FLAG_BITEXACT;
4484 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4486 video_enc.dct_algo = FF_DCT_FASTINT;
4487 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4489 video_enc.idct_algo = FF_IDCT_SIMPLE;
4490 } else if (!av_strcasecmp(cmd, "Qscale")) {
4491 get_arg(arg, sizeof(arg), &p);
4493 video_enc.flags |= CODEC_FLAG_QSCALE;
4494 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4496 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4497 get_arg(arg, sizeof(arg), &p);
4499 video_enc.max_qdiff = atoi(arg);
4500 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4501 ERROR("VideoQDiff out of range\n");
4504 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4505 get_arg(arg, sizeof(arg), &p);
4507 video_enc.qmax = atoi(arg);
4508 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4509 ERROR("VideoQMax out of range\n");
4512 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4513 get_arg(arg, sizeof(arg), &p);
4515 video_enc.qmin = atoi(arg);
4516 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4517 ERROR("VideoQMin out of range\n");
4520 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4521 get_arg(arg, sizeof(arg), &p);
4523 video_enc.lumi_masking = atof(arg);
4524 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4525 get_arg(arg, sizeof(arg), &p);
4527 video_enc.dark_masking = atof(arg);
4528 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4529 video_id = AV_CODEC_ID_NONE;
4530 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4531 audio_id = AV_CODEC_ID_NONE;
4532 } else if (!av_strcasecmp(cmd, "ACL")) {
4533 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4534 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4536 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4538 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4539 get_arg(arg, sizeof(arg), &p);
4541 av_freep(&stream->rtsp_option);
4542 stream->rtsp_option = av_strdup(arg);
4544 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4545 get_arg(arg, sizeof(arg), &p);
4547 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4548 ERROR("Invalid host/IP address: %s\n", arg);
4550 stream->is_multicast = 1;
4551 stream->loop = 1; /* default is looping */
4553 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4554 get_arg(arg, sizeof(arg), &p);
4556 stream->multicast_port = atoi(arg);
4557 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4558 get_arg(arg, sizeof(arg), &p);
4560 stream->multicast_ttl = atoi(arg);
4561 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4564 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4566 ERROR("No corresponding <Stream> for </Stream>\n");
4568 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4569 if (audio_id != AV_CODEC_ID_NONE) {
4570 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4571 audio_enc.codec_id = audio_id;
4572 add_codec(stream, &audio_enc);
4574 if (video_id != AV_CODEC_ID_NONE) {
4575 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4576 video_enc.codec_id = video_id;
4577 add_codec(stream, &video_enc);
4582 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4583 /*********************************************/
4585 if (stream || feed || redirect) {
4586 ERROR("Already in a tag\n");
4588 redirect = av_mallocz(sizeof(FFStream));
4589 *last_stream = redirect;
4590 last_stream = &redirect->next;
4592 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4593 q = strrchr(redirect->filename, '>');
4596 redirect->stream_type = STREAM_TYPE_REDIRECT;
4598 } else if (!av_strcasecmp(cmd, "URL")) {
4600 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4601 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4603 ERROR("No corresponding <Redirect> for </Redirect>\n");
4605 if (!redirect->feed_filename[0]) {
4606 ERROR("No URL found for <Redirect>\n");
4610 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4611 ERROR("Loadable modules no longer supported\n");
4613 ERROR("Incorrect keyword: '%s'\n", cmd);
4625 static void handle_child_exit(int sig)
4630 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4633 for (feed = first_feed; feed; feed = feed->next) {
4634 if (feed->pid == pid) {
4635 int uptime = time(0) - feed->pid_start;
4638 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4641 /* Turn off any more restarts */
4642 feed->child_argv = 0;
4647 need_to_start_children = 1;
4650 static void opt_debug(void)
4653 logfilename[0] = '-';
4656 void show_help_default(const char *opt, const char *arg)
4658 printf("usage: ffserver [options]\n"
4659 "Hyper fast multi format Audio/Video streaming server\n");
4661 show_help_options(options, "Main options:", 0, 0, 0);
4664 static const OptionDef options[] = {
4665 #include "cmdutils_common_opts.h"
4666 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4667 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4668 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4672 int main(int argc, char **argv)
4674 struct sigaction sigact = { { 0 } };
4676 config_filename = av_strdup("/etc/ffserver.conf");
4678 parse_loglevel(argc, argv, options);
4680 avformat_network_init();
4682 show_banner(argc, argv, options);
4684 my_program_name = argv[0];
4686 parse_options(NULL, argc, argv, options, NULL);
4688 unsetenv("http_proxy"); /* Kill the http_proxy */
4690 av_lfg_init(&random_state, av_get_random_seed());
4692 sigact.sa_handler = handle_child_exit;
4693 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4694 sigaction(SIGCHLD, &sigact, 0);
4696 if (parse_ffconfig(config_filename) < 0) {
4697 fprintf(stderr, "Incorrect config file - exiting.\n");
4700 av_freep(&config_filename);
4702 /* open log file if needed */
4703 if (logfilename[0] != '\0') {
4704 if (!strcmp(logfilename, "-"))
4707 logfile = fopen(logfilename, "a");
4708 av_log_set_callback(http_av_log);
4711 build_file_streams();
4713 build_feed_streams();
4715 compute_bandwidth();
4718 signal(SIGPIPE, SIG_IGN);
4720 if (http_server() < 0) {
4721 http_log("Could not start server\n");