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
32 #include "libavformat/avformat.h"
33 // FIXME those are internal headers, ffserver _really_ shouldn't use them
34 #include "libavformat/ffm.h"
35 #include "libavformat/network.h"
36 #include "libavformat/os_support.h"
37 #include "libavformat/rtpdec.h"
38 #include "libavformat/rtsp.h"
39 #include "libavformat/avio_internal.h"
40 #include "libavformat/internal.h"
41 #include "libavformat/url.h"
43 #include "libavutil/avassert.h"
44 #include "libavutil/avstring.h"
45 #include "libavutil/lfg.h"
46 #include "libavutil/dict.h"
47 #include "libavutil/intreadwrite.h"
48 #include "libavutil/mathematics.h"
49 #include "libavutil/random_seed.h"
50 #include "libavutil/parseutils.h"
51 #include "libavutil/opt.h"
52 #include "libavutil/time.h"
57 #include <sys/ioctl.h>
71 const char program_name[] = "ffserver";
72 const int program_birth_year = 2000;
74 static const OptionDef options[];
77 HTTPSTATE_WAIT_REQUEST,
78 HTTPSTATE_SEND_HEADER,
79 HTTPSTATE_SEND_DATA_HEADER,
80 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
81 HTTPSTATE_SEND_DATA_TRAILER,
82 HTTPSTATE_RECEIVE_DATA,
83 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
86 RTSPSTATE_WAIT_REQUEST,
88 RTSPSTATE_SEND_PACKET,
91 static const char *http_state[] = {
107 #define MAX_STREAMS 20
109 #define IOBUFFER_INIT_SIZE 8192
111 /* timeouts are in ms */
112 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
113 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
115 #define SYNC_TIMEOUT (10 * 1000)
117 typedef struct RTSPActionServerSetup {
119 char transport_option[512];
120 } RTSPActionServerSetup;
123 int64_t count1, count2;
124 int64_t time1, time2;
127 /* context associated with one connection */
128 typedef struct HTTPContext {
129 enum HTTPState state;
130 int fd; /* socket file descriptor */
131 struct sockaddr_in from_addr; /* origin */
132 struct pollfd *poll_entry; /* used when polling */
134 uint8_t *buffer_ptr, *buffer_end;
137 int chunked_encoding;
138 int chunk_size; /* 0 if it needs to be read */
139 struct HTTPContext *next;
140 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
144 /* input format handling */
145 AVFormatContext *fmt_in;
146 int64_t start_time; /* In milliseconds - this wraps fairly often */
147 int64_t first_pts; /* initial pts value */
148 int64_t cur_pts; /* current pts value from the stream in us */
149 int64_t cur_frame_duration; /* duration of the current frame in us */
150 int cur_frame_bytes; /* output frame size, needed to compute
151 the time at which we send each
153 int pts_stream_index; /* stream we choose as clock reference */
154 int64_t cur_clock; /* current clock reference value in us */
155 /* output format handling */
156 struct FFStream *stream;
157 /* -1 is invalid stream */
158 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
159 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
161 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
162 int last_packet_sent; /* true if last data packet was sent */
164 DataRateData datarate;
171 int is_packetized; /* if true, the stream is packetized */
172 int packet_stream_index; /* current stream for output in state machine */
174 /* RTSP state specific */
175 uint8_t *pb_buffer; /* XXX: use that in all the code */
177 int seq; /* RTSP sequence number */
179 /* RTP state specific */
180 enum RTSPLowerTransport rtp_protocol;
181 char session_id[32]; /* session id */
182 AVFormatContext *rtp_ctx[MAX_STREAMS];
184 /* RTP/UDP specific */
185 URLContext *rtp_handles[MAX_STREAMS];
187 /* RTP/TCP specific */
188 struct HTTPContext *rtsp_c;
189 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
192 /* each generated stream is described here */
196 STREAM_TYPE_REDIRECT,
199 enum IPAddressAction {
204 typedef struct IPAddressACL {
205 struct IPAddressACL *next;
206 enum IPAddressAction action;
207 /* These are in host order */
208 struct in_addr first;
212 /* description of each stream of the ffserver.conf file */
213 typedef struct FFStream {
214 enum StreamType stream_type;
215 char filename[1024]; /* stream filename */
216 struct FFStream *feed; /* feed we are using (can be null if
218 AVDictionary *in_opts; /* input parameters */
219 AVInputFormat *ifmt; /* if non NULL, force input format */
222 char dynamic_acl[1024];
224 int prebuffer; /* Number of millseconds early to start */
225 int64_t max_time; /* Number of milliseconds to run */
227 AVStream *streams[MAX_STREAMS];
228 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
229 char feed_filename[1024]; /* file name of the feed storage, or
230 input file name for a stream */
235 pid_t pid; /* Of ffmpeg process */
236 time_t pid_start; /* Of ffmpeg process */
238 struct FFStream *next;
239 unsigned bandwidth; /* bandwidth, in kbits/s */
242 /* multicast specific */
244 struct in_addr multicast_ip;
245 int multicast_port; /* first port used for multicast */
247 int loop; /* if true, send the stream in loops (only meaningful if file) */
250 int feed_opened; /* true if someone is writing to the feed */
251 int is_feed; /* true if it is a feed */
252 int readonly; /* True if writing is prohibited to the file */
253 int truncate; /* True if feeder connection truncate the feed file */
255 int64_t bytes_served;
256 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
257 int64_t feed_write_index; /* current write position in feed (it wraps around) */
258 int64_t feed_size; /* current size of feed */
259 struct FFStream *next_feed;
262 typedef struct FeedData {
263 long long data_count;
264 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
267 static struct sockaddr_in my_http_addr;
268 static struct sockaddr_in my_rtsp_addr;
270 static char logfilename[1024];
271 static HTTPContext *first_http_ctx;
272 static FFStream *first_feed; /* contains only feeds */
273 static FFStream *first_stream; /* contains all streams, including feeds */
275 static void new_connection(int server_fd, int is_rtsp);
276 static void close_connection(HTTPContext *c);
279 static int handle_connection(HTTPContext *c);
280 static int http_parse_request(HTTPContext *c);
281 static int http_send_data(HTTPContext *c);
282 static void compute_status(HTTPContext *c);
283 static int open_input_stream(HTTPContext *c, const char *info);
284 static int http_start_receive_data(HTTPContext *c);
285 static int http_receive_data(HTTPContext *c);
288 static int rtsp_parse_request(HTTPContext *c);
289 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
290 static void rtsp_cmd_options(HTTPContext *c, const char *url);
291 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
292 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
293 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
294 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
297 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
298 struct in_addr my_ip);
301 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
302 FFStream *stream, const char *session_id,
303 enum RTSPLowerTransport rtp_protocol);
304 static int rtp_new_av_stream(HTTPContext *c,
305 int stream_index, struct sockaddr_in *dest_addr,
306 HTTPContext *rtsp_c);
308 static const char *my_program_name;
309 static const char *my_program_dir;
311 static const char *config_filename = "/etc/ffserver.conf";
313 static int ffserver_debug;
314 static int ffserver_daemon;
315 static int no_launch;
316 static int need_to_start_children;
318 /* maximum number of simultaneous HTTP connections */
319 static unsigned int nb_max_http_connections = 2000;
320 static unsigned int nb_max_connections = 5;
321 static unsigned int nb_connections;
323 static uint64_t max_bandwidth = 1000;
324 static uint64_t current_bandwidth;
326 static int64_t cur_time; // Making this global saves on passing it around everywhere
328 static AVLFG random_state;
330 static FILE *logfile = NULL;
332 static int64_t ffm_read_write_index(int fd)
336 if (lseek(fd, 8, SEEK_SET) < 0)
338 if (read(fd, buf, 8) != 8)
343 static int ffm_write_write_index(int fd, int64_t pos)
349 buf[i] = (pos >> (56 - i * 8)) & 0xff;
350 if (lseek(fd, 8, SEEK_SET) < 0)
352 if (write(fd, buf, 8) != 8)
357 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
360 FFMContext *ffm = s->priv_data;
361 ffm->write_index = pos;
362 ffm->file_size = file_size;
365 /* FIXME: make ffserver work with IPv6 */
366 /* resolve host with also IP address parsing */
367 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
370 if (!ff_inet_aton(hostname, sin_addr)) {
372 struct addrinfo *ai, *cur;
373 struct addrinfo hints = { 0 };
374 hints.ai_family = AF_INET;
375 if (getaddrinfo(hostname, NULL, &hints, &ai))
377 /* getaddrinfo returns a linked list of addrinfo structs.
378 * Even if we set ai_family = AF_INET above, make sure
379 * that the returned one actually is of the correct type. */
380 for (cur = ai; cur; cur = cur->ai_next) {
381 if (cur->ai_family == AF_INET) {
382 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
391 hp = gethostbyname(hostname);
394 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
400 static char *ctime1(char *buf2)
408 p = buf2 + strlen(p) - 1;
414 static void http_vlog(const char *fmt, va_list vargs)
416 static int print_prefix = 1;
421 fprintf(logfile, "%s ", buf);
423 print_prefix = strstr(fmt, "\n") != NULL;
424 vfprintf(logfile, fmt, vargs);
430 __attribute__ ((format (printf, 1, 2)))
432 static void http_log(const char *fmt, ...)
435 va_start(vargs, fmt);
436 http_vlog(fmt, vargs);
440 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
442 static int print_prefix = 1;
443 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
444 if (level > av_log_get_level())
446 if (print_prefix && avc)
447 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
448 print_prefix = strstr(fmt, "\n") != NULL;
449 http_vlog(fmt, vargs);
452 static void log_connection(HTTPContext *c)
457 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
458 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
459 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
462 static void update_datarate(DataRateData *drd, int64_t count)
464 if (!drd->time1 && !drd->count1) {
465 drd->time1 = drd->time2 = cur_time;
466 drd->count1 = drd->count2 = count;
467 } else if (cur_time - drd->time2 > 5000) {
468 drd->time1 = drd->time2;
469 drd->count1 = drd->count2;
470 drd->time2 = cur_time;
475 /* In bytes per second */
476 static int compute_datarate(DataRateData *drd, int64_t count)
478 if (cur_time == drd->time1)
481 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
485 static void start_children(FFStream *feed)
490 for (; feed; feed = feed->next) {
491 if (feed->child_argv && !feed->pid) {
492 feed->pid_start = time(0);
497 http_log("Unable to create children\n");
506 av_strlcpy(pathname, my_program_name, sizeof(pathname));
508 slash = strrchr(pathname, '/');
513 strcpy(slash, "ffmpeg");
515 http_log("Launch command line: ");
516 http_log("%s ", pathname);
517 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
518 http_log("%s ", feed->child_argv[i]);
521 for (i = 3; i < 256; i++)
524 if (!ffserver_debug) {
525 i = open("/dev/null", O_RDWR);
534 /* This is needed to make relative pathnames work */
535 if (chdir(my_program_dir) < 0) {
536 http_log("chdir failed\n");
540 signal(SIGPIPE, SIG_DFL);
542 execvp(pathname, feed->child_argv);
550 /* open a listening socket */
551 static int socket_open_listen(struct sockaddr_in *my_addr)
555 server_fd = socket(AF_INET,SOCK_STREAM,0);
562 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
564 my_addr->sin_family = AF_INET;
565 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
567 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
569 closesocket(server_fd);
573 if (listen (server_fd, 5) < 0) {
575 closesocket(server_fd);
578 ff_socket_nonblock(server_fd, 1);
583 /* start all multicast streams */
584 static void start_multicast(void)
589 struct sockaddr_in dest_addr = {0};
590 int default_port, stream_index;
593 for(stream = first_stream; stream != NULL; stream = stream->next) {
594 if (stream->is_multicast) {
595 unsigned random0 = av_lfg_get(&random_state);
596 unsigned random1 = av_lfg_get(&random_state);
597 /* open the RTP connection */
598 snprintf(session_id, sizeof(session_id), "%08x%08x",
601 /* choose a port if none given */
602 if (stream->multicast_port == 0) {
603 stream->multicast_port = default_port;
607 dest_addr.sin_family = AF_INET;
608 dest_addr.sin_addr = stream->multicast_ip;
609 dest_addr.sin_port = htons(stream->multicast_port);
611 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
612 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
616 if (open_input_stream(rtp_c, "") < 0) {
617 http_log("Could not open input stream for stream '%s'\n",
622 /* open each RTP stream */
623 for(stream_index = 0; stream_index < stream->nb_streams;
625 dest_addr.sin_port = htons(stream->multicast_port +
627 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
628 http_log("Could not open output stream '%s/streamid=%d'\n",
629 stream->filename, stream_index);
634 /* change state to send data */
635 rtp_c->state = HTTPSTATE_SEND_DATA;
640 /* main loop of the http server */
641 static int http_server(void)
643 int server_fd = 0, rtsp_server_fd = 0;
644 int ret, delay, delay1;
645 struct pollfd *poll_table, *poll_entry;
646 HTTPContext *c, *c_next;
648 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
649 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
653 if (my_http_addr.sin_port) {
654 server_fd = socket_open_listen(&my_http_addr);
659 if (my_rtsp_addr.sin_port) {
660 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
661 if (rtsp_server_fd < 0)
665 if (!rtsp_server_fd && !server_fd) {
666 http_log("HTTP and RTSP disabled.\n");
670 http_log("FFserver started.\n");
672 start_children(first_feed);
677 poll_entry = poll_table;
679 poll_entry->fd = server_fd;
680 poll_entry->events = POLLIN;
683 if (rtsp_server_fd) {
684 poll_entry->fd = rtsp_server_fd;
685 poll_entry->events = POLLIN;
689 /* wait for events on each HTTP handle */
696 case HTTPSTATE_SEND_HEADER:
697 case RTSPSTATE_SEND_REPLY:
698 case RTSPSTATE_SEND_PACKET:
699 c->poll_entry = poll_entry;
701 poll_entry->events = POLLOUT;
704 case HTTPSTATE_SEND_DATA_HEADER:
705 case HTTPSTATE_SEND_DATA:
706 case HTTPSTATE_SEND_DATA_TRAILER:
707 if (!c->is_packetized) {
708 /* for TCP, we output as much as we can (may need to put a limit) */
709 c->poll_entry = poll_entry;
711 poll_entry->events = POLLOUT;
714 /* when ffserver is doing the timing, we work by
715 looking at which packet need to be sent every
717 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
722 case HTTPSTATE_WAIT_REQUEST:
723 case HTTPSTATE_RECEIVE_DATA:
724 case HTTPSTATE_WAIT_FEED:
725 case RTSPSTATE_WAIT_REQUEST:
726 /* need to catch errors */
727 c->poll_entry = poll_entry;
729 poll_entry->events = POLLIN;/* Maybe this will work */
733 c->poll_entry = NULL;
739 /* wait for an event on one connection. We poll at least every
740 second to handle timeouts */
742 ret = poll(poll_table, poll_entry - poll_table, delay);
743 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
744 ff_neterrno() != AVERROR(EINTR))
748 cur_time = av_gettime() / 1000;
750 if (need_to_start_children) {
751 need_to_start_children = 0;
752 start_children(first_feed);
755 /* now handle the events */
756 for(c = first_http_ctx; c != NULL; c = c_next) {
758 if (handle_connection(c) < 0) {
759 /* close and free the connection */
765 poll_entry = poll_table;
767 /* new HTTP connection request ? */
768 if (poll_entry->revents & POLLIN)
769 new_connection(server_fd, 0);
772 if (rtsp_server_fd) {
773 /* new RTSP connection request ? */
774 if (poll_entry->revents & POLLIN)
775 new_connection(rtsp_server_fd, 1);
780 /* start waiting for a new HTTP/RTSP request */
781 static void start_wait_request(HTTPContext *c, int is_rtsp)
783 c->buffer_ptr = c->buffer;
784 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
787 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
788 c->state = RTSPSTATE_WAIT_REQUEST;
790 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
791 c->state = HTTPSTATE_WAIT_REQUEST;
795 static void http_send_too_busy_reply(int fd)
798 int len = snprintf(buffer, sizeof(buffer),
799 "HTTP/1.0 503 Server too busy\r\n"
800 "Content-type: text/html\r\n"
802 "<html><head><title>Too busy</title></head><body>\r\n"
803 "<p>The server is too busy to serve your request at this time.</p>\r\n"
804 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
805 "</body></html>\r\n",
806 nb_connections, nb_max_connections);
807 av_assert0(len < sizeof(buffer));
808 send(fd, buffer, len, 0);
812 static void new_connection(int server_fd, int is_rtsp)
814 struct sockaddr_in from_addr;
817 HTTPContext *c = NULL;
819 len = sizeof(from_addr);
820 fd = accept(server_fd, (struct sockaddr *)&from_addr,
823 http_log("error during accept %s\n", strerror(errno));
826 ff_socket_nonblock(fd, 1);
828 if (nb_connections >= nb_max_connections) {
829 http_send_too_busy_reply(fd);
833 /* add a new connection */
834 c = av_mallocz(sizeof(HTTPContext));
839 c->poll_entry = NULL;
840 c->from_addr = from_addr;
841 c->buffer_size = IOBUFFER_INIT_SIZE;
842 c->buffer = av_malloc(c->buffer_size);
846 c->next = first_http_ctx;
850 start_wait_request(c, is_rtsp);
862 static void close_connection(HTTPContext *c)
864 HTTPContext **cp, *c1;
866 AVFormatContext *ctx;
870 /* remove connection from list */
871 cp = &first_http_ctx;
872 while ((*cp) != NULL) {
880 /* remove references, if any (XXX: do it faster) */
881 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
886 /* remove connection associated resources */
890 /* close each frame parser */
891 for(i=0;i<c->fmt_in->nb_streams;i++) {
892 st = c->fmt_in->streams[i];
893 if (st->codec->codec)
894 avcodec_close(st->codec);
896 avformat_close_input(&c->fmt_in);
899 /* free RTP output streams if any */
902 nb_streams = c->stream->nb_streams;
904 for(i=0;i<nb_streams;i++) {
907 av_write_trailer(ctx);
908 av_dict_free(&ctx->metadata);
909 av_free(ctx->streams[0]);
912 h = c->rtp_handles[i];
919 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
922 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
923 av_write_trailer(ctx);
924 av_freep(&c->pb_buffer);
925 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
930 for(i=0; i<ctx->nb_streams; i++)
931 av_free(ctx->streams[i]);
933 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
934 current_bandwidth -= c->stream->bandwidth;
936 /* signal that there is no feed if we are the feeder socket */
937 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
938 c->stream->feed_opened = 0;
942 av_freep(&c->pb_buffer);
943 av_freep(&c->packet_buffer);
949 static int handle_connection(HTTPContext *c)
954 case HTTPSTATE_WAIT_REQUEST:
955 case RTSPSTATE_WAIT_REQUEST:
957 if ((c->timeout - cur_time) < 0)
959 if (c->poll_entry->revents & (POLLERR | POLLHUP))
962 /* no need to read if no events */
963 if (!(c->poll_entry->revents & POLLIN))
967 len = recv(c->fd, c->buffer_ptr, 1, 0);
969 if (ff_neterrno() != AVERROR(EAGAIN) &&
970 ff_neterrno() != AVERROR(EINTR))
972 } else if (len == 0) {
975 /* search for end of request. */
977 c->buffer_ptr += len;
979 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
980 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
981 /* request found : parse it and reply */
982 if (c->state == HTTPSTATE_WAIT_REQUEST) {
983 ret = http_parse_request(c);
985 ret = rtsp_parse_request(c);
989 } else if (ptr >= c->buffer_end) {
990 /* request too long: cannot do anything */
992 } else goto read_loop;
996 case HTTPSTATE_SEND_HEADER:
997 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1000 /* no need to write if no events */
1001 if (!(c->poll_entry->revents & POLLOUT))
1003 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1005 if (ff_neterrno() != AVERROR(EAGAIN) &&
1006 ff_neterrno() != AVERROR(EINTR)) {
1007 /* error : close connection */
1008 av_freep(&c->pb_buffer);
1012 c->buffer_ptr += len;
1014 c->stream->bytes_served += len;
1015 c->data_count += len;
1016 if (c->buffer_ptr >= c->buffer_end) {
1017 av_freep(&c->pb_buffer);
1018 /* if error, exit */
1021 /* all the buffer was sent : synchronize to the incoming stream */
1022 c->state = HTTPSTATE_SEND_DATA_HEADER;
1023 c->buffer_ptr = c->buffer_end = c->buffer;
1028 case HTTPSTATE_SEND_DATA:
1029 case HTTPSTATE_SEND_DATA_HEADER:
1030 case HTTPSTATE_SEND_DATA_TRAILER:
1031 /* for packetized output, we consider we can always write (the
1032 input streams sets the speed). It may be better to verify
1033 that we do not rely too much on the kernel queues */
1034 if (!c->is_packetized) {
1035 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1038 /* no need to read if no events */
1039 if (!(c->poll_entry->revents & POLLOUT))
1042 if (http_send_data(c) < 0)
1044 /* close connection if trailer sent */
1045 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1048 case HTTPSTATE_RECEIVE_DATA:
1049 /* no need to read if no events */
1050 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1052 if (!(c->poll_entry->revents & POLLIN))
1054 if (http_receive_data(c) < 0)
1057 case HTTPSTATE_WAIT_FEED:
1058 /* no need to read if no events */
1059 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1062 /* nothing to do, we'll be waken up by incoming feed packets */
1065 case RTSPSTATE_SEND_REPLY:
1066 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1067 av_freep(&c->pb_buffer);
1070 /* no need to write if no events */
1071 if (!(c->poll_entry->revents & POLLOUT))
1073 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1075 if (ff_neterrno() != AVERROR(EAGAIN) &&
1076 ff_neterrno() != AVERROR(EINTR)) {
1077 /* error : close connection */
1078 av_freep(&c->pb_buffer);
1082 c->buffer_ptr += len;
1083 c->data_count += len;
1084 if (c->buffer_ptr >= c->buffer_end) {
1085 /* all the buffer was sent : wait for a new request */
1086 av_freep(&c->pb_buffer);
1087 start_wait_request(c, 1);
1091 case RTSPSTATE_SEND_PACKET:
1092 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1093 av_freep(&c->packet_buffer);
1096 /* no need to write if no events */
1097 if (!(c->poll_entry->revents & POLLOUT))
1099 len = send(c->fd, c->packet_buffer_ptr,
1100 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1102 if (ff_neterrno() != AVERROR(EAGAIN) &&
1103 ff_neterrno() != AVERROR(EINTR)) {
1104 /* error : close connection */
1105 av_freep(&c->packet_buffer);
1109 c->packet_buffer_ptr += len;
1110 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1111 /* all the buffer was sent : wait for a new request */
1112 av_freep(&c->packet_buffer);
1113 c->state = RTSPSTATE_WAIT_REQUEST;
1117 case HTTPSTATE_READY:
1126 static int extract_rates(char *rates, int ratelen, const char *request)
1130 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1131 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1132 const char *q = p + 7;
1134 while (*q && *q != '\n' && isspace(*q))
1137 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1143 memset(rates, 0xff, ratelen);
1146 while (*q && *q != '\n' && *q != ':')
1149 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1153 if (stream_no < ratelen && stream_no >= 0)
1154 rates[stream_no] = rate_no;
1156 while (*q && *q != '\n' && !isspace(*q))
1163 p = strchr(p, '\n');
1173 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1176 int best_bitrate = 100000000;
1179 for (i = 0; i < feed->nb_streams; i++) {
1180 AVCodecContext *feed_codec = feed->streams[i]->codec;
1182 if (feed_codec->codec_id != codec->codec_id ||
1183 feed_codec->sample_rate != codec->sample_rate ||
1184 feed_codec->width != codec->width ||
1185 feed_codec->height != codec->height)
1188 /* Potential stream */
1190 /* We want the fastest stream less than bit_rate, or the slowest
1191 * faster than bit_rate
1194 if (feed_codec->bit_rate <= bit_rate) {
1195 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1196 best_bitrate = feed_codec->bit_rate;
1200 if (feed_codec->bit_rate < best_bitrate) {
1201 best_bitrate = feed_codec->bit_rate;
1210 static int modify_current_stream(HTTPContext *c, char *rates)
1213 FFStream *req = c->stream;
1214 int action_required = 0;
1216 /* Not much we can do for a feed */
1220 for (i = 0; i < req->nb_streams; i++) {
1221 AVCodecContext *codec = req->streams[i]->codec;
1225 c->switch_feed_streams[i] = req->feed_streams[i];
1228 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1231 /* Wants off or slow */
1232 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1234 /* This doesn't work well when it turns off the only stream! */
1235 c->switch_feed_streams[i] = -2;
1236 c->feed_streams[i] = -2;
1241 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1242 action_required = 1;
1245 return action_required;
1248 /* XXX: factorize in utils.c ? */
1249 /* XXX: take care with different space meaning */
1250 static void skip_spaces(const char **pp)
1254 while (*p == ' ' || *p == '\t')
1259 static void get_word(char *buf, int buf_size, const char **pp)
1267 while (!isspace(*p) && *p != '\0') {
1268 if ((q - buf) < buf_size - 1)
1277 static void get_arg(char *buf, int buf_size, const char **pp)
1284 while (isspace(*p)) p++;
1287 if (*p == '\"' || *p == '\'')
1299 if ((q - buf) < buf_size - 1)
1304 if (quote && *p == quote)
1309 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1310 const char *p, const char *filename, int line_num)
1316 get_arg(arg, sizeof(arg), &p);
1317 if (av_strcasecmp(arg, "allow") == 0)
1318 acl.action = IP_ALLOW;
1319 else if (av_strcasecmp(arg, "deny") == 0)
1320 acl.action = IP_DENY;
1322 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1323 filename, line_num, arg);
1327 get_arg(arg, sizeof(arg), &p);
1329 if (resolve_host(&acl.first, arg) != 0) {
1330 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1331 filename, line_num, arg);
1334 acl.last = acl.first;
1336 get_arg(arg, sizeof(arg), &p);
1339 if (resolve_host(&acl.last, arg) != 0) {
1340 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1341 filename, line_num, arg);
1347 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1348 IPAddressACL **naclp = 0;
1354 naclp = &stream->acl;
1360 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1361 filename, line_num);
1367 naclp = &(*naclp)->next;
1375 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1380 IPAddressACL *acl = NULL;
1384 f = fopen(stream->dynamic_acl, "r");
1386 perror(stream->dynamic_acl);
1390 acl = av_mallocz(sizeof(IPAddressACL));
1394 if (fgets(line, sizeof(line), f) == NULL)
1400 if (*p == '\0' || *p == '#')
1402 get_arg(cmd, sizeof(cmd), &p);
1404 if (!av_strcasecmp(cmd, "ACL"))
1405 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1412 static void free_acl_list(IPAddressACL *in_acl)
1414 IPAddressACL *pacl,*pacl2;
1424 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1426 enum IPAddressAction last_action = IP_DENY;
1428 struct in_addr *src = &c->from_addr.sin_addr;
1429 unsigned long src_addr = src->s_addr;
1431 for (acl = in_acl; acl; acl = acl->next) {
1432 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1433 return (acl->action == IP_ALLOW) ? 1 : 0;
1434 last_action = acl->action;
1437 /* Nothing matched, so return not the last action */
1438 return (last_action == IP_DENY) ? 1 : 0;
1441 static int validate_acl(FFStream *stream, HTTPContext *c)
1447 /* if stream->acl is null validate_acl_list will return 1 */
1448 ret = validate_acl_list(stream->acl, c);
1450 if (stream->dynamic_acl[0]) {
1451 acl = parse_dynamic_acl(stream, c);
1453 ret = validate_acl_list(acl, c);
1461 /* compute the real filename of a file by matching it without its
1462 extensions to all the stream filenames */
1463 static void compute_real_filename(char *filename, int max_size)
1470 /* compute filename by matching without the file extensions */
1471 av_strlcpy(file1, filename, sizeof(file1));
1472 p = strrchr(file1, '.');
1475 for(stream = first_stream; stream != NULL; stream = stream->next) {
1476 av_strlcpy(file2, stream->filename, sizeof(file2));
1477 p = strrchr(file2, '.');
1480 if (!strcmp(file1, file2)) {
1481 av_strlcpy(filename, stream->filename, max_size);
1496 /* parse http request and prepare header */
1497 static int http_parse_request(HTTPContext *c)
1500 enum RedirType redir_type;
1502 char info[1024], filename[1024];
1506 const char *mime_type;
1510 char *useragent = 0;
1513 get_word(cmd, sizeof(cmd), (const char **)&p);
1514 av_strlcpy(c->method, cmd, sizeof(c->method));
1516 if (!strcmp(cmd, "GET"))
1518 else if (!strcmp(cmd, "POST"))
1523 get_word(url, sizeof(url), (const char **)&p);
1524 av_strlcpy(c->url, url, sizeof(c->url));
1526 get_word(protocol, sizeof(protocol), (const char **)&p);
1527 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1530 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1533 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1535 /* find the filename and the optional info string in the request */
1536 p = strchr(url, '?');
1538 av_strlcpy(info, p, sizeof(info));
1543 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1545 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1546 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1548 if (*useragent && *useragent != '\n' && isspace(*useragent))
1552 p = strchr(p, '\n');
1559 redir_type = REDIR_NONE;
1560 if (av_match_ext(filename, "asx")) {
1561 redir_type = REDIR_ASX;
1562 filename[strlen(filename)-1] = 'f';
1563 } else if (av_match_ext(filename, "asf") &&
1564 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1565 /* if this isn't WMP or lookalike, return the redirector file */
1566 redir_type = REDIR_ASF;
1567 } else if (av_match_ext(filename, "rpm,ram")) {
1568 redir_type = REDIR_RAM;
1569 strcpy(filename + strlen(filename)-2, "m");
1570 } else if (av_match_ext(filename, "rtsp")) {
1571 redir_type = REDIR_RTSP;
1572 compute_real_filename(filename, sizeof(filename) - 1);
1573 } else if (av_match_ext(filename, "sdp")) {
1574 redir_type = REDIR_SDP;
1575 compute_real_filename(filename, sizeof(filename) - 1);
1578 // "redirect" / request to index.html
1579 if (!strlen(filename))
1580 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1582 stream = first_stream;
1583 while (stream != NULL) {
1584 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1586 stream = stream->next;
1588 if (stream == NULL) {
1589 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1590 http_log("File '%s' not found\n", url);
1595 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1596 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1598 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1599 c->http_error = 301;
1601 snprintf(q, c->buffer_size,
1602 "HTTP/1.0 301 Moved\r\n"
1604 "Content-type: text/html\r\n"
1606 "<html><head><title>Moved</title></head><body>\r\n"
1607 "You should be <a href=\"%s\">redirected</a>.\r\n"
1608 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1610 /* prepare output buffer */
1611 c->buffer_ptr = c->buffer;
1613 c->state = HTTPSTATE_SEND_HEADER;
1617 /* If this is WMP, get the rate information */
1618 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1619 if (modify_current_stream(c, ratebuf)) {
1620 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1621 if (c->switch_feed_streams[i] >= 0)
1622 c->switch_feed_streams[i] = -1;
1627 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1628 current_bandwidth += stream->bandwidth;
1630 /* If already streaming this feed, do not let start another feeder. */
1631 if (stream->feed_opened) {
1632 snprintf(msg, sizeof(msg), "This feed is already being received.");
1633 http_log("Feed '%s' already being received\n", stream->feed_filename);
1637 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1638 c->http_error = 503;
1640 snprintf(q, c->buffer_size,
1641 "HTTP/1.0 503 Server too busy\r\n"
1642 "Content-type: text/html\r\n"
1644 "<html><head><title>Too busy</title></head><body>\r\n"
1645 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1646 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1647 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1648 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1650 /* prepare output buffer */
1651 c->buffer_ptr = c->buffer;
1653 c->state = HTTPSTATE_SEND_HEADER;
1657 if (redir_type != REDIR_NONE) {
1660 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1661 if (av_strncasecmp(p, "Host:", 5) == 0) {
1665 p = strchr(p, '\n');
1676 while (isspace(*hostinfo))
1679 eoh = strchr(hostinfo, '\n');
1681 if (eoh[-1] == '\r')
1684 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1685 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1686 hostbuf[eoh - hostinfo] = 0;
1688 c->http_error = 200;
1690 switch(redir_type) {
1692 snprintf(q, c->buffer_size,
1693 "HTTP/1.0 200 ASX Follows\r\n"
1694 "Content-type: video/x-ms-asf\r\n"
1696 "<ASX Version=\"3\">\r\n"
1697 //"<!-- Autogenerated by ffserver -->\r\n"
1698 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1699 "</ASX>\r\n", hostbuf, filename, info);
1703 snprintf(q, c->buffer_size,
1704 "HTTP/1.0 200 RAM Follows\r\n"
1705 "Content-type: audio/x-pn-realaudio\r\n"
1707 "# Autogenerated by ffserver\r\n"
1708 "http://%s/%s%s\r\n", hostbuf, filename, info);
1712 snprintf(q, c->buffer_size,
1713 "HTTP/1.0 200 ASF Redirect follows\r\n"
1714 "Content-type: video/x-ms-asf\r\n"
1717 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1722 char hostname[256], *p;
1723 /* extract only hostname */
1724 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1725 p = strrchr(hostname, ':');
1728 snprintf(q, c->buffer_size,
1729 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1730 /* XXX: incorrect mime type ? */
1731 "Content-type: application/x-rtsp\r\n"
1733 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1742 struct sockaddr_in my_addr;
1744 snprintf(q, c->buffer_size,
1745 "HTTP/1.0 200 OK\r\n"
1746 "Content-type: application/sdp\r\n"
1750 len = sizeof(my_addr);
1751 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1753 /* XXX: should use a dynamic buffer */
1754 sdp_data_size = prepare_sdp_description(stream,
1757 if (sdp_data_size > 0) {
1758 memcpy(q, sdp_data, sdp_data_size);
1770 /* prepare output buffer */
1771 c->buffer_ptr = c->buffer;
1773 c->state = HTTPSTATE_SEND_HEADER;
1779 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1783 stream->conns_served++;
1785 /* XXX: add there authenticate and IP match */
1788 /* if post, it means a feed is being sent */
1789 if (!stream->is_feed) {
1790 /* However it might be a status report from WMP! Let us log the
1791 * data as it might come in handy one day. */
1795 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1796 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1800 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1801 client_id = strtol(p + 18, 0, 10);
1802 p = strchr(p, '\n');
1810 char *eol = strchr(logline, '\n');
1815 if (eol[-1] == '\r')
1817 http_log("%.*s\n", (int) (eol - logline), logline);
1818 c->suppress_log = 1;
1823 http_log("\nGot request:\n%s\n", c->buffer);
1826 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1829 /* Now we have to find the client_id */
1830 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1831 if (wmpc->wmp_client_id == client_id)
1835 if (wmpc && modify_current_stream(wmpc, ratebuf))
1836 wmpc->switch_pending = 1;
1839 snprintf(msg, sizeof(msg), "POST command not handled");
1843 if (http_start_receive_data(c) < 0) {
1844 snprintf(msg, sizeof(msg), "could not open feed");
1848 c->state = HTTPSTATE_RECEIVE_DATA;
1853 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1854 http_log("\nGot request:\n%s\n", c->buffer);
1857 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1860 /* open input stream */
1861 if (open_input_stream(c, info) < 0) {
1862 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1866 /* prepare http header */
1868 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1869 mime_type = c->stream->fmt->mime_type;
1871 mime_type = "application/x-octet-stream";
1872 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1874 /* for asf, we need extra headers */
1875 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1876 /* Need to allocate a client id */
1878 c->wmp_client_id = av_lfg_get(&random_state);
1880 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);
1882 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1883 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1884 q = c->buffer + strlen(c->buffer);
1886 /* prepare output buffer */
1888 c->buffer_ptr = c->buffer;
1890 c->state = HTTPSTATE_SEND_HEADER;
1893 c->http_error = 404;
1895 snprintf(q, c->buffer_size,
1896 "HTTP/1.0 404 Not Found\r\n"
1897 "Content-type: text/html\r\n"
1900 "<head><title>404 Not Found</title></head>\n"
1904 /* prepare output buffer */
1905 c->buffer_ptr = c->buffer;
1907 c->state = HTTPSTATE_SEND_HEADER;
1911 c->http_error = 200; /* horrible : we use this value to avoid
1912 going to the send data state */
1913 c->state = HTTPSTATE_SEND_HEADER;
1917 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1919 static const char suffix[] = " kMGTP";
1922 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1924 avio_printf(pb, "%"PRId64"%c", count, *s);
1927 static void compute_status(HTTPContext *c)
1936 if (avio_open_dyn_buf(&pb) < 0) {
1937 /* XXX: return an error ? */
1938 c->buffer_ptr = c->buffer;
1939 c->buffer_end = c->buffer;
1943 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1944 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1945 avio_printf(pb, "Pragma: no-cache\r\n");
1946 avio_printf(pb, "\r\n");
1948 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1949 if (c->stream->feed_filename[0])
1950 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1951 avio_printf(pb, "</head>\n<body>");
1952 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1954 avio_printf(pb, "<h2>Available Streams</h2>\n");
1955 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1956 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");
1957 stream = first_stream;
1958 while (stream != NULL) {
1959 char sfilename[1024];
1962 if (stream->feed != stream) {
1963 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1964 eosf = sfilename + strlen(sfilename);
1965 if (eosf - sfilename >= 4) {
1966 if (strcmp(eosf - 4, ".asf") == 0)
1967 strcpy(eosf - 4, ".asx");
1968 else if (strcmp(eosf - 3, ".rm") == 0)
1969 strcpy(eosf - 3, ".ram");
1970 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1971 /* generate a sample RTSP director if
1972 unicast. Generate an SDP redirector if
1974 eosf = strrchr(sfilename, '.');
1976 eosf = sfilename + strlen(sfilename);
1977 if (stream->is_multicast)
1978 strcpy(eosf, ".sdp");
1980 strcpy(eosf, ".rtsp");
1984 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1985 sfilename, stream->filename);
1986 avio_printf(pb, "<td align=right> %d <td align=right> ",
1987 stream->conns_served);
1988 fmt_bytecount(pb, stream->bytes_served);
1989 switch(stream->stream_type) {
1990 case STREAM_TYPE_LIVE: {
1991 int audio_bit_rate = 0;
1992 int video_bit_rate = 0;
1993 const char *audio_codec_name = "";
1994 const char *video_codec_name = "";
1995 const char *audio_codec_name_extra = "";
1996 const char *video_codec_name_extra = "";
1998 for(i=0;i<stream->nb_streams;i++) {
1999 AVStream *st = stream->streams[i];
2000 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2001 switch(st->codec->codec_type) {
2002 case AVMEDIA_TYPE_AUDIO:
2003 audio_bit_rate += st->codec->bit_rate;
2005 if (*audio_codec_name)
2006 audio_codec_name_extra = "...";
2007 audio_codec_name = codec->name;
2010 case AVMEDIA_TYPE_VIDEO:
2011 video_bit_rate += st->codec->bit_rate;
2013 if (*video_codec_name)
2014 video_codec_name_extra = "...";
2015 video_codec_name = codec->name;
2018 case AVMEDIA_TYPE_DATA:
2019 video_bit_rate += st->codec->bit_rate;
2025 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",
2028 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2029 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2031 avio_printf(pb, "<td>%s", stream->feed->filename);
2033 avio_printf(pb, "<td>%s", stream->feed_filename);
2034 avio_printf(pb, "\n");
2038 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2042 stream = stream->next;
2044 avio_printf(pb, "</table>\n");
2046 stream = first_stream;
2047 while (stream != NULL) {
2048 if (stream->feed == stream) {
2049 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2051 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2053 #if defined(linux) && !defined(CONFIG_NOCUTILS)
2058 /* This is somewhat linux specific I guess */
2059 snprintf(ps_cmd, sizeof(ps_cmd),
2060 "ps -o \"%%cpu,cputime\" --no-headers %d",
2063 pid_stat = popen(ps_cmd, "r");
2068 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2070 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2078 avio_printf(pb, "<p>");
2080 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");
2082 for (i = 0; i < stream->nb_streams; i++) {
2083 AVStream *st = stream->streams[i];
2084 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2085 const char *type = "unknown";
2086 char parameters[64];
2090 switch(st->codec->codec_type) {
2091 case AVMEDIA_TYPE_AUDIO:
2093 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2095 case AVMEDIA_TYPE_VIDEO:
2097 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2098 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2103 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2104 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2106 avio_printf(pb, "</table>\n");
2109 stream = stream->next;
2112 /* connection status */
2113 avio_printf(pb, "<h2>Connection Status</h2>\n");
2115 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2116 nb_connections, nb_max_connections);
2118 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2119 current_bandwidth, max_bandwidth);
2121 avio_printf(pb, "<table>\n");
2122 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");
2123 c1 = first_http_ctx;
2125 while (c1 != NULL) {
2131 for (j = 0; j < c1->stream->nb_streams; j++) {
2132 if (!c1->stream->feed)
2133 bitrate += c1->stream->streams[j]->codec->bit_rate;
2134 else if (c1->feed_streams[j] >= 0)
2135 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2140 p = inet_ntoa(c1->from_addr.sin_addr);
2141 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2143 c1->stream ? c1->stream->filename : "",
2144 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2147 http_state[c1->state]);
2148 fmt_bytecount(pb, bitrate);
2149 avio_printf(pb, "<td align=right>");
2150 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2151 avio_printf(pb, "<td align=right>");
2152 fmt_bytecount(pb, c1->data_count);
2153 avio_printf(pb, "\n");
2156 avio_printf(pb, "</table>\n");
2161 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2162 avio_printf(pb, "</body>\n</html>\n");
2164 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2165 c->buffer_ptr = c->pb_buffer;
2166 c->buffer_end = c->pb_buffer + len;
2169 static int open_input_stream(HTTPContext *c, const char *info)
2172 char input_filename[1024];
2173 AVFormatContext *s = NULL;
2174 int buf_size, i, ret;
2177 /* find file name */
2178 if (c->stream->feed) {
2179 strcpy(input_filename, c->stream->feed->feed_filename);
2180 buf_size = FFM_PACKET_SIZE;
2181 /* compute position (absolute time) */
2182 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2183 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2185 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2186 int prebuffer = strtol(buf, 0, 10);
2187 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2189 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2191 strcpy(input_filename, c->stream->feed_filename);
2193 /* compute position (relative time) */
2194 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2195 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2200 if (input_filename[0] == '\0')
2204 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2205 http_log("could not open %s: %d\n", input_filename, ret);
2209 /* set buffer size */
2210 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2212 s->flags |= AVFMT_FLAG_GENPTS;
2214 if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
2215 http_log("Could not find stream info '%s'\n", input_filename);
2216 avformat_close_input(&s);
2220 /* choose stream as clock source (we favorize video stream if
2221 present) for packet sending */
2222 c->pts_stream_index = 0;
2223 for(i=0;i<c->stream->nb_streams;i++) {
2224 if (c->pts_stream_index == 0 &&
2225 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2226 c->pts_stream_index = i;
2230 if (c->fmt_in->iformat->read_seek)
2231 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2232 /* set the start time (needed for maxtime and RTP packet timing) */
2233 c->start_time = cur_time;
2234 c->first_pts = AV_NOPTS_VALUE;
2238 /* return the server clock (in us) */
2239 static int64_t get_server_clock(HTTPContext *c)
2241 /* compute current pts value from system time */
2242 return (cur_time - c->start_time) * 1000;
2245 /* return the estimated time at which the current packet must be sent
2247 static int64_t get_packet_send_clock(HTTPContext *c)
2249 int bytes_left, bytes_sent, frame_bytes;
2251 frame_bytes = c->cur_frame_bytes;
2252 if (frame_bytes <= 0)
2255 bytes_left = c->buffer_end - c->buffer_ptr;
2256 bytes_sent = frame_bytes - bytes_left;
2257 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2262 static int http_prepare_data(HTTPContext *c)
2265 AVFormatContext *ctx;
2267 av_freep(&c->pb_buffer);
2269 case HTTPSTATE_SEND_DATA_HEADER:
2270 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2271 av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2272 av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2273 av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2274 av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2276 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2278 for(i=0;i<c->stream->nb_streams;i++) {
2280 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2281 /* if file or feed, then just take streams from FFStream struct */
2282 if (!c->stream->feed ||
2283 c->stream->feed == c->stream)
2284 src = c->stream->streams[i];
2286 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2288 *(c->fmt_ctx.streams[i]) = *src;
2289 c->fmt_ctx.streams[i]->priv_data = 0;
2290 c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2291 AVStream, not in codec */
2293 /* set output format parameters */
2294 c->fmt_ctx.oformat = c->stream->fmt;
2295 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2297 c->got_key_frame = 0;
2299 /* prepare header and save header data in a stream */
2300 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2301 /* XXX: potential leak */
2304 c->fmt_ctx.pb->seekable = 0;
2307 * HACK to avoid mpeg ps muxer to spit many underflow errors
2308 * Default value from FFmpeg
2309 * Try to set it use configuration option
2311 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2313 if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2314 http_log("Error writing output header\n");
2317 av_dict_free(&c->fmt_ctx.metadata);
2319 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2320 c->buffer_ptr = c->pb_buffer;
2321 c->buffer_end = c->pb_buffer + len;
2323 c->state = HTTPSTATE_SEND_DATA;
2324 c->last_packet_sent = 0;
2326 case HTTPSTATE_SEND_DATA:
2327 /* find a new packet */
2328 /* read a packet from the input stream */
2329 if (c->stream->feed)
2330 ffm_set_write_index(c->fmt_in,
2331 c->stream->feed->feed_write_index,
2332 c->stream->feed->feed_size);
2334 if (c->stream->max_time &&
2335 c->stream->max_time + c->start_time - cur_time < 0)
2336 /* We have timed out */
2337 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2341 ret = av_read_frame(c->fmt_in, &pkt);
2343 if (c->stream->feed) {
2344 /* if coming from feed, it means we reached the end of the
2345 ffm file, so must wait for more data */
2346 c->state = HTTPSTATE_WAIT_FEED;
2347 return 1; /* state changed */
2348 } else if (ret == AVERROR(EAGAIN)) {
2349 /* input not ready, come back later */
2352 if (c->stream->loop) {
2353 avformat_close_input(&c->fmt_in);
2354 if (open_input_stream(c, "") < 0)
2359 /* must send trailer now because eof or error */
2360 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2364 int source_index = pkt.stream_index;
2365 /* update first pts if needed */
2366 if (c->first_pts == AV_NOPTS_VALUE) {
2367 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2368 c->start_time = cur_time;
2370 /* send it to the appropriate stream */
2371 if (c->stream->feed) {
2372 /* if coming from a feed, select the right stream */
2373 if (c->switch_pending) {
2374 c->switch_pending = 0;
2375 for(i=0;i<c->stream->nb_streams;i++) {
2376 if (c->switch_feed_streams[i] == pkt.stream_index)
2377 if (pkt.flags & AV_PKT_FLAG_KEY)
2378 c->switch_feed_streams[i] = -1;
2379 if (c->switch_feed_streams[i] >= 0)
2380 c->switch_pending = 1;
2383 for(i=0;i<c->stream->nb_streams;i++) {
2384 if (c->stream->feed_streams[i] == pkt.stream_index) {
2385 AVStream *st = c->fmt_in->streams[source_index];
2386 pkt.stream_index = i;
2387 if (pkt.flags & AV_PKT_FLAG_KEY &&
2388 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2389 c->stream->nb_streams == 1))
2390 c->got_key_frame = 1;
2391 if (!c->stream->send_on_key || c->got_key_frame)
2396 AVCodecContext *codec;
2397 AVStream *ist, *ost;
2399 ist = c->fmt_in->streams[source_index];
2400 /* specific handling for RTP: we use several
2401 output stream (one for each RTP
2402 connection). XXX: need more abstract handling */
2403 if (c->is_packetized) {
2404 /* compute send time and duration */
2405 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2406 c->cur_pts -= c->first_pts;
2407 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2408 /* find RTP context */
2409 c->packet_stream_index = pkt.stream_index;
2410 ctx = c->rtp_ctx[c->packet_stream_index];
2412 av_free_packet(&pkt);
2415 codec = ctx->streams[0]->codec;
2416 /* only one stream per RTP connection */
2417 pkt.stream_index = 0;
2421 codec = ctx->streams[pkt.stream_index]->codec;
2424 if (c->is_packetized) {
2425 int max_packet_size;
2426 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2427 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2429 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2430 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2432 ret = avio_open_dyn_buf(&ctx->pb);
2435 /* XXX: potential leak */
2438 ost = ctx->streams[pkt.stream_index];
2440 ctx->pb->seekable = 0;
2441 if (pkt.dts != AV_NOPTS_VALUE)
2442 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2443 if (pkt.pts != AV_NOPTS_VALUE)
2444 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2445 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2446 if (av_write_frame(ctx, &pkt) < 0) {
2447 http_log("Error writing frame to output\n");
2448 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2451 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2452 c->cur_frame_bytes = len;
2453 c->buffer_ptr = c->pb_buffer;
2454 c->buffer_end = c->pb_buffer + len;
2456 codec->frame_number++;
2458 av_free_packet(&pkt);
2462 av_free_packet(&pkt);
2467 case HTTPSTATE_SEND_DATA_TRAILER:
2468 /* last packet test ? */
2469 if (c->last_packet_sent || c->is_packetized)
2472 /* prepare header */
2473 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2474 /* XXX: potential leak */
2477 c->fmt_ctx.pb->seekable = 0;
2478 av_write_trailer(ctx);
2479 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2480 c->buffer_ptr = c->pb_buffer;
2481 c->buffer_end = c->pb_buffer + len;
2483 c->last_packet_sent = 1;
2489 /* should convert the format at the same time */
2490 /* send data starting at c->buffer_ptr to the output connection
2491 (either UDP or TCP connection) */
2492 static int http_send_data(HTTPContext *c)
2497 if (c->buffer_ptr >= c->buffer_end) {
2498 ret = http_prepare_data(c);
2502 /* state change requested */
2505 if (c->is_packetized) {
2506 /* RTP data output */
2507 len = c->buffer_end - c->buffer_ptr;
2509 /* fail safe - should never happen */
2511 c->buffer_ptr = c->buffer_end;
2514 len = (c->buffer_ptr[0] << 24) |
2515 (c->buffer_ptr[1] << 16) |
2516 (c->buffer_ptr[2] << 8) |
2518 if (len > (c->buffer_end - c->buffer_ptr))
2520 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2521 /* nothing to send yet: we can wait */
2525 c->data_count += len;
2526 update_datarate(&c->datarate, c->data_count);
2528 c->stream->bytes_served += len;
2530 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2531 /* RTP packets are sent inside the RTSP TCP connection */
2533 int interleaved_index, size;
2535 HTTPContext *rtsp_c;
2538 /* if no RTSP connection left, error */
2541 /* if already sending something, then wait. */
2542 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2544 if (avio_open_dyn_buf(&pb) < 0)
2546 interleaved_index = c->packet_stream_index * 2;
2547 /* RTCP packets are sent at odd indexes */
2548 if (c->buffer_ptr[1] == 200)
2549 interleaved_index++;
2550 /* write RTSP TCP header */
2552 header[1] = interleaved_index;
2553 header[2] = len >> 8;
2555 avio_write(pb, header, 4);
2556 /* write RTP packet data */
2558 avio_write(pb, c->buffer_ptr, len);
2559 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2560 /* prepare asynchronous TCP sending */
2561 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2562 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2563 c->buffer_ptr += len;
2565 /* send everything we can NOW */
2566 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2567 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2569 rtsp_c->packet_buffer_ptr += len;
2570 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2571 /* if we could not send all the data, we will
2572 send it later, so a new state is needed to
2573 "lock" the RTSP TCP connection */
2574 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2577 /* all data has been sent */
2578 av_freep(&c->packet_buffer);
2580 /* send RTP packet directly in UDP */
2582 ffurl_write(c->rtp_handles[c->packet_stream_index],
2583 c->buffer_ptr, len);
2584 c->buffer_ptr += len;
2585 /* here we continue as we can send several packets per 10 ms slot */
2588 /* TCP data output */
2589 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2591 if (ff_neterrno() != AVERROR(EAGAIN) &&
2592 ff_neterrno() != AVERROR(EINTR))
2593 /* error : close connection */
2598 c->buffer_ptr += len;
2600 c->data_count += len;
2601 update_datarate(&c->datarate, c->data_count);
2603 c->stream->bytes_served += len;
2611 static int http_start_receive_data(HTTPContext *c)
2615 if (c->stream->feed_opened)
2618 /* Don't permit writing to this one */
2619 if (c->stream->readonly)
2623 fd = open(c->stream->feed_filename, O_RDWR);
2625 http_log("Error opening feeder file: %s\n", strerror(errno));
2630 if (c->stream->truncate) {
2631 /* truncate feed file */
2632 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2633 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2634 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2635 http_log("Error truncating feed file: %s\n", strerror(errno));
2639 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2640 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2645 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2646 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2647 lseek(fd, 0, SEEK_SET);
2649 /* init buffer input */
2650 c->buffer_ptr = c->buffer;
2651 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2652 c->stream->feed_opened = 1;
2653 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2657 static int http_receive_data(HTTPContext *c)
2660 int len, loop_run = 0;
2662 while (c->chunked_encoding && !c->chunk_size &&
2663 c->buffer_end > c->buffer_ptr) {
2664 /* read chunk header, if present */
2665 len = recv(c->fd, c->buffer_ptr, 1, 0);
2668 if (ff_neterrno() != AVERROR(EAGAIN) &&
2669 ff_neterrno() != AVERROR(EINTR))
2670 /* error : close connection */
2673 } else if (len == 0) {
2674 /* end of connection : close it */
2676 } else if (c->buffer_ptr - c->buffer >= 2 &&
2677 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2678 c->chunk_size = strtol(c->buffer, 0, 16);
2679 if (c->chunk_size == 0) // end of stream
2681 c->buffer_ptr = c->buffer;
2683 } else if (++loop_run > 10) {
2684 /* no chunk header, abort */
2691 if (c->buffer_end > c->buffer_ptr) {
2692 len = recv(c->fd, c->buffer_ptr,
2693 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2695 if (ff_neterrno() != AVERROR(EAGAIN) &&
2696 ff_neterrno() != AVERROR(EINTR))
2697 /* error : close connection */
2699 } else if (len == 0)
2700 /* end of connection : close it */
2703 c->chunk_size -= len;
2704 c->buffer_ptr += len;
2705 c->data_count += len;
2706 update_datarate(&c->datarate, c->data_count);
2710 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2711 if (c->buffer[0] != 'f' ||
2712 c->buffer[1] != 'm') {
2713 http_log("Feed stream has become desynchronized -- disconnecting\n");
2718 if (c->buffer_ptr >= c->buffer_end) {
2719 FFStream *feed = c->stream;
2720 /* a packet has been received : write it in the store, except
2722 if (c->data_count > FFM_PACKET_SIZE) {
2723 /* XXX: use llseek or url_seek */
2724 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2725 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2726 http_log("Error writing to feed file: %s\n", strerror(errno));
2730 feed->feed_write_index += FFM_PACKET_SIZE;
2731 /* update file size */
2732 if (feed->feed_write_index > c->stream->feed_size)
2733 feed->feed_size = feed->feed_write_index;
2735 /* handle wrap around if max file size reached */
2736 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2737 feed->feed_write_index = FFM_PACKET_SIZE;
2740 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2741 http_log("Error writing index to feed file: %s\n", strerror(errno));
2745 /* wake up any waiting connections */
2746 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2747 if (c1->state == HTTPSTATE_WAIT_FEED &&
2748 c1->stream->feed == c->stream->feed)
2749 c1->state = HTTPSTATE_SEND_DATA;
2752 /* We have a header in our hands that contains useful data */
2753 AVFormatContext *s = avformat_alloc_context();
2755 AVInputFormat *fmt_in;
2761 /* use feed output format name to find corresponding input format */
2762 fmt_in = av_find_input_format(feed->fmt->name);
2766 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2767 0, NULL, NULL, NULL, NULL);
2771 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2776 /* Now we have the actual streams */
2777 if (s->nb_streams != feed->nb_streams) {
2778 avformat_close_input(&s);
2780 http_log("Feed '%s' stream number does not match registered feed\n",
2781 c->stream->feed_filename);
2785 for (i = 0; i < s->nb_streams; i++) {
2786 AVStream *fst = feed->streams[i];
2787 AVStream *st = s->streams[i];
2788 avcodec_copy_context(fst->codec, st->codec);
2791 avformat_close_input(&s);
2794 c->buffer_ptr = c->buffer;
2799 c->stream->feed_opened = 0;
2801 /* wake up any waiting connections to stop waiting for feed */
2802 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2803 if (c1->state == HTTPSTATE_WAIT_FEED &&
2804 c1->stream->feed == c->stream->feed)
2805 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2810 /********************************************************************/
2813 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2820 switch(error_number) {
2821 case RTSP_STATUS_OK:
2824 case RTSP_STATUS_METHOD:
2825 str = "Method Not Allowed";
2827 case RTSP_STATUS_BANDWIDTH:
2828 str = "Not Enough Bandwidth";
2830 case RTSP_STATUS_SESSION:
2831 str = "Session Not Found";
2833 case RTSP_STATUS_STATE:
2834 str = "Method Not Valid in This State";
2836 case RTSP_STATUS_AGGREGATE:
2837 str = "Aggregate operation not allowed";
2839 case RTSP_STATUS_ONLY_AGGREGATE:
2840 str = "Only aggregate operation allowed";
2842 case RTSP_STATUS_TRANSPORT:
2843 str = "Unsupported transport";
2845 case RTSP_STATUS_INTERNAL:
2846 str = "Internal Server Error";
2848 case RTSP_STATUS_SERVICE:
2849 str = "Service Unavailable";
2851 case RTSP_STATUS_VERSION:
2852 str = "RTSP Version not supported";
2855 str = "Unknown Error";
2859 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2860 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2862 /* output GMT time */
2865 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2866 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2869 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2871 rtsp_reply_header(c, error_number);
2872 avio_printf(c->pb, "\r\n");
2875 static int rtsp_parse_request(HTTPContext *c)
2877 const char *p, *p1, *p2;
2883 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2885 c->buffer_ptr[0] = '\0';
2888 get_word(cmd, sizeof(cmd), &p);
2889 get_word(url, sizeof(url), &p);
2890 get_word(protocol, sizeof(protocol), &p);
2892 av_strlcpy(c->method, cmd, sizeof(c->method));
2893 av_strlcpy(c->url, url, sizeof(c->url));
2894 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2896 if (avio_open_dyn_buf(&c->pb) < 0) {
2897 /* XXX: cannot do more */
2898 c->pb = NULL; /* safety */
2902 /* check version name */
2903 if (strcmp(protocol, "RTSP/1.0") != 0) {
2904 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2908 /* parse each header line */
2909 /* skip to next line */
2910 while (*p != '\n' && *p != '\0')
2914 while (*p != '\0') {
2915 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2919 if (p2 > p && p2[-1] == '\r')
2921 /* skip empty line */
2925 if (len > sizeof(line) - 1)
2926 len = sizeof(line) - 1;
2927 memcpy(line, p, len);
2929 ff_rtsp_parse_line(header, line, NULL, NULL);
2933 /* handle sequence number */
2934 c->seq = header->seq;
2936 if (!strcmp(cmd, "DESCRIBE"))
2937 rtsp_cmd_describe(c, url);
2938 else if (!strcmp(cmd, "OPTIONS"))
2939 rtsp_cmd_options(c, url);
2940 else if (!strcmp(cmd, "SETUP"))
2941 rtsp_cmd_setup(c, url, header);
2942 else if (!strcmp(cmd, "PLAY"))
2943 rtsp_cmd_play(c, url, header);
2944 else if (!strcmp(cmd, "PAUSE"))
2945 rtsp_cmd_pause(c, url, header);
2946 else if (!strcmp(cmd, "TEARDOWN"))
2947 rtsp_cmd_teardown(c, url, header);
2949 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2952 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2953 c->pb = NULL; /* safety */
2955 /* XXX: cannot do more */
2958 c->buffer_ptr = c->pb_buffer;
2959 c->buffer_end = c->pb_buffer + len;
2960 c->state = RTSPSTATE_SEND_REPLY;
2964 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2965 struct in_addr my_ip)
2967 AVFormatContext *avc;
2968 AVStream *avs = NULL;
2971 avc = avformat_alloc_context();
2975 av_dict_set(&avc->metadata, "title",
2976 stream->title[0] ? stream->title : "No Title", 0);
2977 avc->nb_streams = stream->nb_streams;
2978 if (stream->is_multicast) {
2979 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2980 inet_ntoa(stream->multicast_ip),
2981 stream->multicast_port, stream->multicast_ttl);
2983 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2986 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2987 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2989 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2990 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2993 for(i = 0; i < stream->nb_streams; i++) {
2994 avc->streams[i] = &avs[i];
2995 avc->streams[i]->codec = stream->streams[i]->codec;
2997 *pbuffer = av_mallocz(2048);
2998 av_sdp_create(&avc, 1, *pbuffer, 2048);
3001 av_free(avc->streams);
3002 av_dict_free(&avc->metadata);
3006 return strlen(*pbuffer);
3009 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3011 // rtsp_reply_header(c, RTSP_STATUS_OK);
3012 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3013 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3014 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3015 avio_printf(c->pb, "\r\n");
3018 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3026 struct sockaddr_in my_addr;
3028 /* find which url is asked */
3029 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3034 for(stream = first_stream; stream != NULL; stream = stream->next) {
3035 if (!stream->is_feed &&
3036 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3037 !strcmp(path, stream->filename)) {
3041 /* no stream found */
3042 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3046 /* prepare the media description in sdp format */
3048 /* get the host IP */
3049 len = sizeof(my_addr);
3050 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3051 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3052 if (content_length < 0) {
3053 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3056 rtsp_reply_header(c, RTSP_STATUS_OK);
3057 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3058 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3059 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3060 avio_printf(c->pb, "\r\n");
3061 avio_write(c->pb, content, content_length);
3065 static HTTPContext *find_rtp_session(const char *session_id)
3069 if (session_id[0] == '\0')
3072 for(c = first_http_ctx; c != NULL; c = c->next) {
3073 if (!strcmp(c->session_id, session_id))
3079 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3081 RTSPTransportField *th;
3084 for(i=0;i<h->nb_transports;i++) {
3085 th = &h->transports[i];
3086 if (th->lower_transport == lower_transport)
3092 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3093 RTSPMessageHeader *h)
3096 int stream_index, rtp_port, rtcp_port;
3101 RTSPTransportField *th;
3102 struct sockaddr_in dest_addr;
3103 RTSPActionServerSetup setup;
3105 /* find which url is asked */
3106 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3111 /* now check each stream */
3112 for(stream = first_stream; stream != NULL; stream = stream->next) {
3113 if (!stream->is_feed &&
3114 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3115 /* accept aggregate filenames only if single stream */
3116 if (!strcmp(path, stream->filename)) {
3117 if (stream->nb_streams != 1) {
3118 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3125 for(stream_index = 0; stream_index < stream->nb_streams;
3127 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3128 stream->filename, stream_index);
3129 if (!strcmp(path, buf))
3134 /* no stream found */
3135 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3139 /* generate session id if needed */
3140 if (h->session_id[0] == '\0') {
3141 unsigned random0 = av_lfg_get(&random_state);
3142 unsigned random1 = av_lfg_get(&random_state);
3143 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3147 /* find rtp session, and create it if none found */
3148 rtp_c = find_rtp_session(h->session_id);
3150 /* always prefer UDP */
3151 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3153 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3155 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3160 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3161 th->lower_transport);
3163 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3167 /* open input stream */
3168 if (open_input_stream(rtp_c, "") < 0) {
3169 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3174 /* test if stream is OK (test needed because several SETUP needs
3175 to be done for a given file) */
3176 if (rtp_c->stream != stream) {
3177 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3181 /* test if stream is already set up */
3182 if (rtp_c->rtp_ctx[stream_index]) {
3183 rtsp_reply_error(c, RTSP_STATUS_STATE);
3187 /* check transport */
3188 th = find_transport(h, rtp_c->rtp_protocol);
3189 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3190 th->client_port_min <= 0)) {
3191 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3195 /* setup default options */
3196 setup.transport_option[0] = '\0';
3197 dest_addr = rtp_c->from_addr;
3198 dest_addr.sin_port = htons(th->client_port_min);
3201 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3202 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3206 /* now everything is OK, so we can send the connection parameters */
3207 rtsp_reply_header(c, RTSP_STATUS_OK);
3209 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3211 switch(rtp_c->rtp_protocol) {
3212 case RTSP_LOWER_TRANSPORT_UDP:
3213 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3214 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3215 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3216 "client_port=%d-%d;server_port=%d-%d",
3217 th->client_port_min, th->client_port_max,
3218 rtp_port, rtcp_port);
3220 case RTSP_LOWER_TRANSPORT_TCP:
3221 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3222 stream_index * 2, stream_index * 2 + 1);
3227 if (setup.transport_option[0] != '\0')
3228 avio_printf(c->pb, ";%s", setup.transport_option);
3229 avio_printf(c->pb, "\r\n");
3232 avio_printf(c->pb, "\r\n");
3236 /* find an rtp connection by using the session ID. Check consistency
3238 static HTTPContext *find_rtp_session_with_url(const char *url,
3239 const char *session_id)
3247 rtp_c = find_rtp_session(session_id);
3251 /* find which url is asked */
3252 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3256 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3257 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3258 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3259 rtp_c->stream->filename, s);
3260 if(!strncmp(path, buf, sizeof(buf))) {
3261 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3266 if (len > 0 && path[len - 1] == '/' &&
3267 !strncmp(path, rtp_c->stream->filename, len - 1))
3272 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3276 rtp_c = find_rtp_session_with_url(url, h->session_id);
3278 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3282 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3283 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3284 rtp_c->state != HTTPSTATE_READY) {
3285 rtsp_reply_error(c, RTSP_STATUS_STATE);
3289 rtp_c->state = HTTPSTATE_SEND_DATA;
3291 /* now everything is OK, so we can send the connection parameters */
3292 rtsp_reply_header(c, RTSP_STATUS_OK);
3294 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3295 avio_printf(c->pb, "\r\n");
3298 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3302 rtp_c = find_rtp_session_with_url(url, h->session_id);
3304 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3308 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3309 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3310 rtsp_reply_error(c, RTSP_STATUS_STATE);
3314 rtp_c->state = HTTPSTATE_READY;
3315 rtp_c->first_pts = AV_NOPTS_VALUE;
3316 /* now everything is OK, so we can send the connection parameters */
3317 rtsp_reply_header(c, RTSP_STATUS_OK);
3319 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3320 avio_printf(c->pb, "\r\n");
3323 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3327 rtp_c = find_rtp_session_with_url(url, h->session_id);
3329 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3333 /* now everything is OK, so we can send the connection parameters */
3334 rtsp_reply_header(c, RTSP_STATUS_OK);
3336 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3337 avio_printf(c->pb, "\r\n");
3339 /* abort the session */
3340 close_connection(rtp_c);
3344 /********************************************************************/
3347 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3348 FFStream *stream, const char *session_id,
3349 enum RTSPLowerTransport rtp_protocol)
3351 HTTPContext *c = NULL;
3352 const char *proto_str;
3354 /* XXX: should output a warning page when coming
3355 close to the connection limit */
3356 if (nb_connections >= nb_max_connections)
3359 /* add a new connection */
3360 c = av_mallocz(sizeof(HTTPContext));
3365 c->poll_entry = NULL;
3366 c->from_addr = *from_addr;
3367 c->buffer_size = IOBUFFER_INIT_SIZE;
3368 c->buffer = av_malloc(c->buffer_size);
3373 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3374 c->state = HTTPSTATE_READY;
3375 c->is_packetized = 1;
3376 c->rtp_protocol = rtp_protocol;
3378 /* protocol is shown in statistics */
3379 switch(c->rtp_protocol) {
3380 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3381 proto_str = "MCAST";
3383 case RTSP_LOWER_TRANSPORT_UDP:
3386 case RTSP_LOWER_TRANSPORT_TCP:
3393 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3394 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3396 current_bandwidth += stream->bandwidth;
3398 c->next = first_http_ctx;
3410 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3411 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3413 static int rtp_new_av_stream(HTTPContext *c,
3414 int stream_index, struct sockaddr_in *dest_addr,
3415 HTTPContext *rtsp_c)
3417 AVFormatContext *ctx;
3420 URLContext *h = NULL;
3422 int max_packet_size;
3424 /* now we can open the relevant output stream */
3425 ctx = avformat_alloc_context();
3428 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3430 st = av_mallocz(sizeof(AVStream));
3433 ctx->nb_streams = 1;
3434 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3437 ctx->streams[0] = st;
3439 if (!c->stream->feed ||
3440 c->stream->feed == c->stream)
3441 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3444 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3446 st->priv_data = NULL;
3448 /* build destination RTP address */
3449 ipaddr = inet_ntoa(dest_addr->sin_addr);
3451 switch(c->rtp_protocol) {
3452 case RTSP_LOWER_TRANSPORT_UDP:
3453 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3456 /* XXX: also pass as parameter to function ? */
3457 if (c->stream->is_multicast) {
3459 ttl = c->stream->multicast_ttl;
3462 snprintf(ctx->filename, sizeof(ctx->filename),
3463 "rtp://%s:%d?multicast=1&ttl=%d",
3464 ipaddr, ntohs(dest_addr->sin_port), ttl);
3466 snprintf(ctx->filename, sizeof(ctx->filename),
3467 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3470 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3472 c->rtp_handles[stream_index] = h;
3473 max_packet_size = h->max_packet_size;
3475 case RTSP_LOWER_TRANSPORT_TCP:
3478 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3484 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3485 ipaddr, ntohs(dest_addr->sin_port),
3486 c->stream->filename, stream_index, c->protocol);
3488 /* normally, no packets should be output here, but the packet size may be checked */
3489 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3490 /* XXX: close stream */
3493 if (avformat_write_header(ctx, NULL) < 0) {
3500 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3503 c->rtp_ctx[stream_index] = ctx;
3507 /********************************************************************/
3508 /* ffserver initialization */
3510 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3514 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3517 fst = av_mallocz(sizeof(AVStream));
3521 fst->codec = avcodec_alloc_context3(NULL);
3522 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3523 if (codec->extradata_size) {
3524 fst->codec->extradata = av_malloc(codec->extradata_size);
3525 memcpy(fst->codec->extradata, codec->extradata,
3526 codec->extradata_size);
3529 /* live streams must use the actual feed's codec since it may be
3530 * updated later to carry extradata needed by the streams.
3534 fst->priv_data = av_mallocz(sizeof(FeedData));
3535 fst->index = stream->nb_streams;
3536 avpriv_set_pts_info(fst, 33, 1, 90000);
3537 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3538 stream->streams[stream->nb_streams++] = fst;
3542 /* return the stream number in the feed */
3543 static int add_av_stream(FFStream *feed, AVStream *st)
3546 AVCodecContext *av, *av1;
3550 for(i=0;i<feed->nb_streams;i++) {
3551 st = feed->streams[i];
3553 if (av1->codec_id == av->codec_id &&
3554 av1->codec_type == av->codec_type &&
3555 av1->bit_rate == av->bit_rate) {
3557 switch(av->codec_type) {
3558 case AVMEDIA_TYPE_AUDIO:
3559 if (av1->channels == av->channels &&
3560 av1->sample_rate == av->sample_rate)
3563 case AVMEDIA_TYPE_VIDEO:
3564 if (av1->width == av->width &&
3565 av1->height == av->height &&
3566 av1->time_base.den == av->time_base.den &&
3567 av1->time_base.num == av->time_base.num &&
3568 av1->gop_size == av->gop_size)
3577 fst = add_av_stream1(feed, av, 0);
3580 return feed->nb_streams - 1;
3583 static void remove_stream(FFStream *stream)
3587 while (*ps != NULL) {
3595 /* specific mpeg4 handling : we extract the raw parameters */
3596 static void extract_mpeg4_header(AVFormatContext *infile)
3598 int mpeg4_count, i, size;
3604 for(i=0;i<infile->nb_streams;i++) {
3605 st = infile->streams[i];
3606 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3607 st->codec->extradata_size == 0) {
3614 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3615 while (mpeg4_count > 0) {
3616 if (av_read_packet(infile, &pkt) < 0)
3618 st = infile->streams[pkt.stream_index];
3619 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3620 st->codec->extradata_size == 0) {
3621 av_freep(&st->codec->extradata);
3622 /* fill extradata with the header */
3623 /* XXX: we make hard suppositions here ! */
3625 while (p < pkt.data + pkt.size - 4) {
3626 /* stop when vop header is found */
3627 if (p[0] == 0x00 && p[1] == 0x00 &&
3628 p[2] == 0x01 && p[3] == 0xb6) {
3629 size = p - pkt.data;
3630 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3631 st->codec->extradata = av_malloc(size);
3632 st->codec->extradata_size = size;
3633 memcpy(st->codec->extradata, pkt.data, size);
3640 av_free_packet(&pkt);
3644 /* compute the needed AVStream for each file */
3645 static void build_file_streams(void)
3647 FFStream *stream, *stream_next;
3650 /* gather all streams */
3651 for(stream = first_stream; stream != NULL; stream = stream_next) {
3652 AVFormatContext *infile = NULL;
3653 stream_next = stream->next;
3654 if (stream->stream_type == STREAM_TYPE_LIVE &&
3656 /* the stream comes from a file */
3657 /* try to open the file */
3659 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3660 /* specific case : if transport stream output to RTP,
3661 we use a raw transport stream reader */
3662 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3665 http_log("Opening file '%s'\n", stream->feed_filename);
3666 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3667 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3668 /* remove stream (no need to spend more time on it) */
3670 remove_stream(stream);
3672 /* find all the AVStreams inside and reference them in
3674 if (avformat_find_stream_info(infile, NULL) < 0) {
3675 http_log("Could not find codec parameters from '%s'\n",
3676 stream->feed_filename);
3677 avformat_close_input(&infile);
3680 extract_mpeg4_header(infile);
3682 for(i=0;i<infile->nb_streams;i++)
3683 add_av_stream1(stream, infile->streams[i]->codec, 1);
3685 avformat_close_input(&infile);
3691 /* compute the needed AVStream for each feed */
3692 static void build_feed_streams(void)
3694 FFStream *stream, *feed;
3697 /* gather all streams */
3698 for(stream = first_stream; stream != NULL; stream = stream->next) {
3699 feed = stream->feed;
3701 if (stream->is_feed) {
3702 for(i=0;i<stream->nb_streams;i++)
3703 stream->feed_streams[i] = i;
3705 /* we handle a stream coming from a feed */
3706 for(i=0;i<stream->nb_streams;i++)
3707 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3712 /* create feed files if needed */
3713 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3716 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3717 /* See if it matches */
3718 AVFormatContext *s = NULL;
3721 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3722 /* set buffer size */
3723 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3724 /* Now see if it matches */
3725 if (s->nb_streams == feed->nb_streams) {
3727 for(i=0;i<s->nb_streams;i++) {
3729 sf = feed->streams[i];
3732 if (sf->index != ss->index ||
3734 http_log("Index & Id do not match for stream %d (%s)\n",
3735 i, feed->feed_filename);
3738 AVCodecContext *ccf, *ccs;
3742 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3744 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3745 http_log("Codecs do not match for stream %d\n", i);
3747 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3748 http_log("Codec bitrates do not match for stream %d\n", i);
3750 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3751 if (CHECK_CODEC(time_base.den) ||
3752 CHECK_CODEC(time_base.num) ||
3753 CHECK_CODEC(width) ||
3754 CHECK_CODEC(height)) {
3755 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3758 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3759 if (CHECK_CODEC(sample_rate) ||
3760 CHECK_CODEC(channels) ||
3761 CHECK_CODEC(frame_size)) {
3762 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3766 http_log("Unknown codec type\n");
3774 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3775 feed->feed_filename, s->nb_streams, feed->nb_streams);
3777 avformat_close_input(&s);
3779 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3780 feed->feed_filename);
3783 if (feed->readonly) {
3784 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3785 feed->feed_filename);
3788 unlink(feed->feed_filename);
3791 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3792 AVFormatContext s1 = {0}, *s = &s1;
3794 if (feed->readonly) {
3795 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3796 feed->feed_filename);
3800 /* only write the header of the ffm file */
3801 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3802 http_log("Could not open output feed file '%s'\n",
3803 feed->feed_filename);
3806 s->oformat = feed->fmt;
3807 s->nb_streams = feed->nb_streams;
3808 s->streams = feed->streams;
3809 if (avformat_write_header(s, NULL) < 0) {
3810 http_log("Container doesn't support the required parameters\n");
3813 /* XXX: need better api */
3814 av_freep(&s->priv_data);
3817 /* get feed size and write index */
3818 fd = open(feed->feed_filename, O_RDONLY);
3820 http_log("Could not open output feed file '%s'\n",
3821 feed->feed_filename);
3825 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3826 feed->feed_size = lseek(fd, 0, SEEK_END);
3827 /* ensure that we do not wrap before the end of file */
3828 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3829 feed->feed_max_size = feed->feed_size;
3835 /* compute the bandwidth used by each stream */
3836 static void compute_bandwidth(void)
3842 for(stream = first_stream; stream != NULL; stream = stream->next) {
3844 for(i=0;i<stream->nb_streams;i++) {
3845 AVStream *st = stream->streams[i];
3846 switch(st->codec->codec_type) {
3847 case AVMEDIA_TYPE_AUDIO:
3848 case AVMEDIA_TYPE_VIDEO:
3849 bandwidth += st->codec->bit_rate;
3855 stream->bandwidth = (bandwidth + 999) / 1000;
3859 /* add a codec and set the default parameters */
3860 static void add_codec(FFStream *stream, AVCodecContext *av)
3864 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3867 /* compute default parameters */
3868 switch(av->codec_type) {
3869 case AVMEDIA_TYPE_AUDIO:
3870 if (av->bit_rate == 0)
3871 av->bit_rate = 64000;
3872 if (av->sample_rate == 0)
3873 av->sample_rate = 22050;
3874 if (av->channels == 0)
3877 case AVMEDIA_TYPE_VIDEO:
3878 if (av->bit_rate == 0)
3879 av->bit_rate = 64000;
3880 if (av->time_base.num == 0){
3881 av->time_base.den = 5;
3882 av->time_base.num = 1;
3884 if (av->width == 0 || av->height == 0) {
3888 /* Bitrate tolerance is less for streaming */
3889 if (av->bit_rate_tolerance == 0)
3890 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3891 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3896 if (av->max_qdiff == 0)
3898 av->qcompress = 0.5;
3901 if (!av->nsse_weight)
3902 av->nsse_weight = 8;
3904 av->frame_skip_cmp = FF_CMP_DCTMAX;
3906 av->me_method = ME_EPZS;
3907 av->rc_buffer_aggressivity = 1.0;
3910 av->rc_eq = "tex^qComp";
3911 if (!av->i_quant_factor)
3912 av->i_quant_factor = -0.8;
3913 if (!av->b_quant_factor)
3914 av->b_quant_factor = 1.25;
3915 if (!av->b_quant_offset)
3916 av->b_quant_offset = 1.25;
3917 if (!av->rc_max_rate)
3918 av->rc_max_rate = av->bit_rate * 2;
3920 if (av->rc_max_rate && !av->rc_buffer_size) {
3921 av->rc_buffer_size = av->rc_max_rate;
3930 st = av_mallocz(sizeof(AVStream));
3933 st->codec = avcodec_alloc_context3(NULL);
3934 stream->streams[stream->nb_streams++] = st;
3935 memcpy(st->codec, av, sizeof(AVCodecContext));
3938 static enum AVCodecID opt_audio_codec(const char *arg)
3940 AVCodec *p= avcodec_find_encoder_by_name(arg);
3942 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3943 return AV_CODEC_ID_NONE;
3948 static enum AVCodecID opt_video_codec(const char *arg)
3950 AVCodec *p= avcodec_find_encoder_by_name(arg);
3952 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3953 return AV_CODEC_ID_NONE;
3958 /* simplistic plugin support */
3961 static void load_module(const char *filename)
3964 void (*init_func)(void);
3965 dll = dlopen(filename, RTLD_NOW);
3967 fprintf(stderr, "Could not load module '%s' - %s\n",
3968 filename, dlerror());
3972 init_func = dlsym(dll, "ffserver_module_init");
3975 "%s: init function 'ffserver_module_init()' not found\n",
3984 static int ffserver_opt_default(const char *opt, const char *arg,
3985 AVCodecContext *avctx, int type)
3988 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3990 ret = av_opt_set(avctx, opt, arg, 0);
3994 static int ffserver_opt_preset(const char *arg,
3995 AVCodecContext *avctx, int type,
3996 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3999 char filename[1000], tmp[1000], tmp2[1000], line[1000];
4001 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
4003 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
4004 codec ? codec->name : NULL))) {
4005 fprintf(stderr, "File for preset '%s' not found\n", arg);
4010 int e= fscanf(f, "%999[^\n]\n", line) - 1;
4011 if(line[0] == '#' && !e)
4013 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
4015 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
4019 if(!strcmp(tmp, "acodec")){
4020 *audio_id = opt_audio_codec(tmp2);
4021 }else if(!strcmp(tmp, "vcodec")){
4022 *video_id = opt_video_codec(tmp2);
4023 }else if(!strcmp(tmp, "scodec")){
4024 /* opt_subtitle_codec(tmp2); */
4025 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
4026 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4037 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4038 const char *mime_type)
4040 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4043 AVOutputFormat *stream_fmt;
4044 char stream_format_name[64];
4046 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4047 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4056 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4060 fprintf(stderr, "%s:%d: ", filename, line_num);
4061 vfprintf(stderr, fmt, vl);
4067 static int parse_ffconfig(const char *filename)
4074 int val, errors, line_num;
4075 FFStream **last_stream, *stream, *redirect;
4076 FFStream **last_feed, *feed, *s;
4077 AVCodecContext audio_enc, video_enc;
4078 enum AVCodecID audio_id, video_id;
4080 f = fopen(filename, "r");
4088 first_stream = NULL;
4089 last_stream = &first_stream;
4091 last_feed = &first_feed;
4095 audio_id = AV_CODEC_ID_NONE;
4096 video_id = AV_CODEC_ID_NONE;
4098 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4100 if (fgets(line, sizeof(line), f) == NULL)
4106 if (*p == '\0' || *p == '#')
4109 get_arg(cmd, sizeof(cmd), &p);
4111 if (!av_strcasecmp(cmd, "Port")) {
4112 get_arg(arg, sizeof(arg), &p);
4114 if (val < 1 || val > 65536) {
4115 ERROR("Invalid_port: %s\n", arg);
4117 my_http_addr.sin_port = htons(val);
4118 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4119 get_arg(arg, sizeof(arg), &p);
4120 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4121 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4123 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4124 ffserver_daemon = 0;
4125 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4126 get_arg(arg, sizeof(arg), &p);
4128 if (val < 1 || val > 65536) {
4129 ERROR("%s:%d: Invalid port: %s\n", arg);
4131 my_rtsp_addr.sin_port = htons(atoi(arg));
4132 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4133 get_arg(arg, sizeof(arg), &p);
4134 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4135 ERROR("Invalid host/IP address: %s\n", arg);
4137 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4138 get_arg(arg, sizeof(arg), &p);
4140 if (val < 1 || val > 65536) {
4141 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4143 nb_max_http_connections = val;
4144 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4145 get_arg(arg, sizeof(arg), &p);
4147 if (val < 1 || val > nb_max_http_connections) {
4148 ERROR("Invalid MaxClients: %s\n", arg);
4150 nb_max_connections = val;
4152 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4154 get_arg(arg, sizeof(arg), &p);
4156 if (llval < 10 || llval > 10000000) {
4157 ERROR("Invalid MaxBandwidth: %s\n", arg);
4159 max_bandwidth = llval;
4160 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4161 if (!ffserver_debug)
4162 get_arg(logfilename, sizeof(logfilename), &p);
4163 } else if (!av_strcasecmp(cmd, "<Feed")) {
4164 /*********************************************/
4165 /* Feed related options */
4167 if (stream || feed) {
4168 ERROR("Already in a tag\n");
4170 feed = av_mallocz(sizeof(FFStream));
4171 get_arg(feed->filename, sizeof(feed->filename), &p);
4172 q = strrchr(feed->filename, '>');
4176 for (s = first_feed; s; s = s->next) {
4177 if (!strcmp(feed->filename, s->filename)) {
4178 ERROR("Feed '%s' already registered\n", s->filename);
4182 feed->fmt = av_guess_format("ffm", NULL, NULL);
4183 /* defaut feed file */
4184 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4185 "/tmp/%s.ffm", feed->filename);
4186 feed->feed_max_size = 5 * 1024 * 1024;
4188 feed->feed = feed; /* self feeding :-) */
4190 /* add in stream list */
4191 *last_stream = feed;
4192 last_stream = &feed->next;
4193 /* add in feed list */
4195 last_feed = &feed->next_feed;
4197 } else if (!av_strcasecmp(cmd, "Launch")) {
4201 feed->child_argv = av_mallocz(64 * sizeof(char *));
4203 for (i = 0; i < 62; i++) {
4204 get_arg(arg, sizeof(arg), &p);
4208 feed->child_argv[i] = av_strdup(arg);
4211 feed->child_argv[i] = av_asprintf("http://%s:%d/%s",
4212 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4213 inet_ntoa(my_http_addr.sin_addr),
4214 ntohs(my_http_addr.sin_port), feed->filename);
4216 } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
4218 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4220 } else if (stream) {
4221 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4223 } else if (!av_strcasecmp(cmd, "File")) {
4225 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4227 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4228 } else if (!av_strcasecmp(cmd, "Truncate")) {
4230 get_arg(arg, sizeof(arg), &p);
4231 feed->truncate = strtod(arg, NULL);
4233 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4238 get_arg(arg, sizeof(arg), &p);
4240 fsize = strtod(p1, &p1);
4241 switch(toupper(*p1)) {
4246 fsize *= 1024 * 1024;
4249 fsize *= 1024 * 1024 * 1024;
4252 feed->feed_max_size = (int64_t)fsize;
4253 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4254 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4257 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4259 ERROR("No corresponding <Feed> for </Feed>\n");
4262 } else if (!av_strcasecmp(cmd, "<Stream")) {
4263 /*********************************************/
4264 /* Stream related options */
4266 if (stream || feed) {
4267 ERROR("Already in a tag\n");
4270 stream = av_mallocz(sizeof(FFStream));
4271 get_arg(stream->filename, sizeof(stream->filename), &p);
4272 q = strrchr(stream->filename, '>');
4276 for (s = first_stream; s; s = s->next) {
4277 if (!strcmp(stream->filename, s->filename)) {
4278 ERROR("Stream '%s' already registered\n", s->filename);
4282 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4283 avcodec_get_context_defaults3(&video_enc, NULL);
4284 avcodec_get_context_defaults3(&audio_enc, NULL);
4286 audio_id = AV_CODEC_ID_NONE;
4287 video_id = AV_CODEC_ID_NONE;
4289 audio_id = stream->fmt->audio_codec;
4290 video_id = stream->fmt->video_codec;
4293 *last_stream = stream;
4294 last_stream = &stream->next;
4296 } else if (!av_strcasecmp(cmd, "Feed")) {
4297 get_arg(arg, sizeof(arg), &p);
4302 while (sfeed != NULL) {
4303 if (!strcmp(sfeed->filename, arg))
4305 sfeed = sfeed->next_feed;
4308 ERROR("feed '%s' not defined\n", arg);
4310 stream->feed = sfeed;
4312 } else if (!av_strcasecmp(cmd, "Format")) {
4313 get_arg(arg, sizeof(arg), &p);
4315 if (!strcmp(arg, "status")) {
4316 stream->stream_type = STREAM_TYPE_STATUS;
4319 stream->stream_type = STREAM_TYPE_LIVE;
4320 /* jpeg cannot be used here, so use single frame jpeg */
4321 if (!strcmp(arg, "jpeg"))
4322 strcpy(arg, "mjpeg");
4323 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4325 ERROR("Unknown Format: %s\n", arg);
4329 audio_id = stream->fmt->audio_codec;
4330 video_id = stream->fmt->video_codec;
4333 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4334 get_arg(arg, sizeof(arg), &p);
4336 stream->ifmt = av_find_input_format(arg);
4337 if (!stream->ifmt) {
4338 ERROR("Unknown input format: %s\n", arg);
4341 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4342 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4343 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4345 ERROR("FaviconURL only permitted for status streams\n");
4347 } else if (!av_strcasecmp(cmd, "Author")) {
4349 get_arg(stream->author, sizeof(stream->author), &p);
4350 } else if (!av_strcasecmp(cmd, "Comment")) {
4352 get_arg(stream->comment, sizeof(stream->comment), &p);
4353 } else if (!av_strcasecmp(cmd, "Copyright")) {
4355 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4356 } else if (!av_strcasecmp(cmd, "Title")) {
4358 get_arg(stream->title, sizeof(stream->title), &p);
4359 } else if (!av_strcasecmp(cmd, "Preroll")) {
4360 get_arg(arg, sizeof(arg), &p);
4362 stream->prebuffer = atof(arg) * 1000;
4363 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4365 stream->send_on_key = 1;
4366 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4367 get_arg(arg, sizeof(arg), &p);
4368 audio_id = opt_audio_codec(arg);
4369 if (audio_id == AV_CODEC_ID_NONE) {
4370 ERROR("Unknown AudioCodec: %s\n", arg);
4372 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4373 get_arg(arg, sizeof(arg), &p);
4374 video_id = opt_video_codec(arg);
4375 if (video_id == AV_CODEC_ID_NONE) {
4376 ERROR("Unknown VideoCodec: %s\n", arg);
4378 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4379 get_arg(arg, sizeof(arg), &p);
4381 stream->max_time = atof(arg) * 1000;
4382 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4383 get_arg(arg, sizeof(arg), &p);
4385 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4386 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4387 get_arg(arg, sizeof(arg), &p);
4389 audio_enc.channels = atoi(arg);
4390 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4391 get_arg(arg, sizeof(arg), &p);
4393 audio_enc.sample_rate = atoi(arg);
4394 } else if (!av_strcasecmp(cmd, "AudioQuality")) {
4395 get_arg(arg, sizeof(arg), &p);
4397 // audio_enc.quality = atof(arg) * 1000;
4399 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4401 int minrate, maxrate;
4403 get_arg(arg, sizeof(arg), &p);
4405 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4406 video_enc.rc_min_rate = minrate * 1000;
4407 video_enc.rc_max_rate = maxrate * 1000;
4409 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4412 } else if (!av_strcasecmp(cmd, "Debug")) {
4414 get_arg(arg, sizeof(arg), &p);
4415 video_enc.debug = strtol(arg,0,0);
4417 } else if (!av_strcasecmp(cmd, "Strict")) {
4419 get_arg(arg, sizeof(arg), &p);
4420 video_enc.strict_std_compliance = atoi(arg);
4422 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4424 get_arg(arg, sizeof(arg), &p);
4425 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4427 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4429 get_arg(arg, sizeof(arg), &p);
4430 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4432 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4433 get_arg(arg, sizeof(arg), &p);
4435 video_enc.bit_rate = atoi(arg) * 1000;
4437 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4438 get_arg(arg, sizeof(arg), &p);
4440 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4441 if ((video_enc.width % 16) != 0 ||
4442 (video_enc.height % 16) != 0) {
4443 ERROR("Image size must be a multiple of 16\n");
4446 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4447 get_arg(arg, sizeof(arg), &p);
4449 AVRational frame_rate;
4450 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4451 ERROR("Incorrect frame rate: %s\n", arg);
4453 video_enc.time_base.num = frame_rate.den;
4454 video_enc.time_base.den = frame_rate.num;
4457 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4458 get_arg(arg, sizeof(arg), &p);
4460 video_enc.gop_size = atoi(arg);
4461 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4463 video_enc.gop_size = 1;
4464 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4466 video_enc.mb_decision = FF_MB_DECISION_BITS;
4467 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4469 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4470 video_enc.flags |= CODEC_FLAG_4MV;
4472 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4473 !av_strcasecmp(cmd, "AVOptionAudio")) {
4475 AVCodecContext *avctx;
4477 get_arg(arg, sizeof(arg), &p);
4478 get_arg(arg2, sizeof(arg2), &p);
4479 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4481 type = AV_OPT_FLAG_VIDEO_PARAM;
4484 type = AV_OPT_FLAG_AUDIO_PARAM;
4486 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4487 ERROR("AVOption error: %s %s\n", arg, arg2);
4489 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4490 !av_strcasecmp(cmd, "AVPresetAudio")) {
4491 AVCodecContext *avctx;
4493 get_arg(arg, sizeof(arg), &p);
4494 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4496 video_enc.codec_id = video_id;
4497 type = AV_OPT_FLAG_VIDEO_PARAM;
4500 audio_enc.codec_id = audio_id;
4501 type = AV_OPT_FLAG_AUDIO_PARAM;
4503 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4504 ERROR("AVPreset error: %s\n", arg);
4506 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4507 get_arg(arg, sizeof(arg), &p);
4508 if ((strlen(arg) == 4) && stream)
4509 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4510 } else if (!av_strcasecmp(cmd, "BitExact")) {
4512 video_enc.flags |= CODEC_FLAG_BITEXACT;
4513 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4515 video_enc.dct_algo = FF_DCT_FASTINT;
4516 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4518 video_enc.idct_algo = FF_IDCT_SIMPLE;
4519 } else if (!av_strcasecmp(cmd, "Qscale")) {
4520 get_arg(arg, sizeof(arg), &p);
4522 video_enc.flags |= CODEC_FLAG_QSCALE;
4523 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4525 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4526 get_arg(arg, sizeof(arg), &p);
4528 video_enc.max_qdiff = atoi(arg);
4529 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4530 ERROR("VideoQDiff out of range\n");
4533 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4534 get_arg(arg, sizeof(arg), &p);
4536 video_enc.qmax = atoi(arg);
4537 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4538 ERROR("VideoQMax out of range\n");
4541 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4542 get_arg(arg, sizeof(arg), &p);
4544 video_enc.qmin = atoi(arg);
4545 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4546 ERROR("VideoQMin out of range\n");
4549 } else if (!av_strcasecmp(cmd, "LumaElim")) {
4550 get_arg(arg, sizeof(arg), &p);
4552 video_enc.luma_elim_threshold = atoi(arg);
4553 } else if (!av_strcasecmp(cmd, "ChromaElim")) {
4554 get_arg(arg, sizeof(arg), &p);
4556 video_enc.chroma_elim_threshold = atoi(arg);
4557 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4558 get_arg(arg, sizeof(arg), &p);
4560 video_enc.lumi_masking = atof(arg);
4561 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4562 get_arg(arg, sizeof(arg), &p);
4564 video_enc.dark_masking = atof(arg);
4565 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4566 video_id = AV_CODEC_ID_NONE;
4567 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4568 audio_id = AV_CODEC_ID_NONE;
4569 } else if (!av_strcasecmp(cmd, "ACL")) {
4570 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4571 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4573 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4575 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4576 get_arg(arg, sizeof(arg), &p);
4578 av_freep(&stream->rtsp_option);
4579 stream->rtsp_option = av_strdup(arg);
4581 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4582 get_arg(arg, sizeof(arg), &p);
4584 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4585 ERROR("Invalid host/IP address: %s\n", arg);
4587 stream->is_multicast = 1;
4588 stream->loop = 1; /* default is looping */
4590 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4591 get_arg(arg, sizeof(arg), &p);
4593 stream->multicast_port = atoi(arg);
4594 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4595 get_arg(arg, sizeof(arg), &p);
4597 stream->multicast_ttl = atoi(arg);
4598 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4601 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4603 ERROR("No corresponding <Stream> for </Stream>\n");
4605 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4606 if (audio_id != AV_CODEC_ID_NONE) {
4607 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4608 audio_enc.codec_id = audio_id;
4609 add_codec(stream, &audio_enc);
4611 if (video_id != AV_CODEC_ID_NONE) {
4612 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4613 video_enc.codec_id = video_id;
4614 add_codec(stream, &video_enc);
4619 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4620 /*********************************************/
4622 if (stream || feed || redirect) {
4623 ERROR("Already in a tag\n");
4625 redirect = av_mallocz(sizeof(FFStream));
4626 *last_stream = redirect;
4627 last_stream = &redirect->next;
4629 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4630 q = strrchr(redirect->filename, '>');
4633 redirect->stream_type = STREAM_TYPE_REDIRECT;
4635 } else if (!av_strcasecmp(cmd, "URL")) {
4637 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4638 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4640 ERROR("No corresponding <Redirect> for </Redirect>\n");
4642 if (!redirect->feed_filename[0]) {
4643 ERROR("No URL found for <Redirect>\n");
4647 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4648 get_arg(arg, sizeof(arg), &p);
4652 ERROR("Module support not compiled into this version: '%s'\n", arg);
4655 ERROR("Incorrect keyword: '%s'\n", cmd);
4667 static void handle_child_exit(int sig)
4672 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4675 for (feed = first_feed; feed; feed = feed->next) {
4676 if (feed->pid == pid) {
4677 int uptime = time(0) - feed->pid_start;
4680 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4683 /* Turn off any more restarts */
4684 feed->child_argv = 0;
4689 need_to_start_children = 1;
4692 static void opt_debug(void)
4695 ffserver_daemon = 0;
4696 logfilename[0] = '-';
4699 void show_help_default(const char *opt, const char *arg)
4701 printf("usage: ffserver [options]\n"
4702 "Hyper fast multi format Audio/Video streaming server\n");
4704 show_help_options(options, "Main options:", 0, 0, 0);
4707 static const OptionDef options[] = {
4708 #include "cmdutils_common_opts.h"
4709 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4710 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4711 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4715 int main(int argc, char **argv)
4717 struct sigaction sigact = { { 0 } };
4719 parse_loglevel(argc, argv, options);
4721 avformat_network_init();
4723 show_banner(argc, argv, options);
4725 my_program_name = argv[0];
4726 my_program_dir = getcwd(0, 0);
4727 ffserver_daemon = 1;
4729 parse_options(NULL, argc, argv, options, NULL);
4731 unsetenv("http_proxy"); /* Kill the http_proxy */
4733 av_lfg_init(&random_state, av_get_random_seed());
4735 sigact.sa_handler = handle_child_exit;
4736 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4737 sigaction(SIGCHLD, &sigact, 0);
4739 if (parse_ffconfig(config_filename) < 0) {
4740 fprintf(stderr, "Incorrect config file - exiting.\n");
4744 /* open log file if needed */
4745 if (logfilename[0] != '\0') {
4746 if (!strcmp(logfilename, "-"))
4749 logfile = fopen(logfilename, "a");
4750 av_log_set_callback(http_av_log);
4753 build_file_streams();
4755 build_feed_streams();
4757 compute_bandwidth();
4759 /* put the process in background and detach it from its TTY */
4760 if (ffserver_daemon) {
4767 } else if (pid > 0) {
4774 open("/dev/null", O_RDWR);
4775 if (strcmp(logfilename, "-") != 0) {
4785 signal(SIGPIPE, SIG_IGN);
4787 if (ffserver_daemon)
4790 if (http_server() < 0) {
4791 http_log("Could not start server\n");