2 * Multiple format streaming server
3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
5 * This file is part of Libav.
7 * Libav is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * Libav is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #define closesocket close
29 #include "libavformat/avformat.h"
30 // FIXME those are internal headers, avserver _really_ shouldn't use them
31 #include "libavformat/ffm.h"
32 #include "libavformat/network.h"
33 #include "libavformat/os_support.h"
34 #include "libavformat/rtpdec.h"
35 #include "libavformat/rtpproto.h"
36 #include "libavformat/rtsp.h"
37 #include "libavformat/avio_internal.h"
38 #include "libavformat/internal.h"
39 #include "libavformat/url.h"
41 #include "libavutil/avstring.h"
42 #include "libavutil/lfg.h"
43 #include "libavutil/dict.h"
44 #include "libavutil/intreadwrite.h"
45 #include "libavutil/mathematics.h"
46 #include "libavutil/random_seed.h"
47 #include "libavutil/parseutils.h"
48 #include "libavutil/opt.h"
49 #include "libavutil/time.h"
54 #include <sys/ioctl.h>
65 const char program_name[] = "avserver";
66 const int program_birth_year = 2000;
68 static const OptionDef options[];
71 HTTPSTATE_WAIT_REQUEST,
72 HTTPSTATE_SEND_HEADER,
73 HTTPSTATE_SEND_DATA_HEADER,
74 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
75 HTTPSTATE_SEND_DATA_TRAILER,
76 HTTPSTATE_RECEIVE_DATA,
77 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
80 RTSPSTATE_WAIT_REQUEST,
82 RTSPSTATE_SEND_PACKET,
85 static const char *http_state[] = {
101 #define MAX_STREAMS 20
103 #define IOBUFFER_INIT_SIZE 8192
105 /* timeouts are in ms */
106 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
107 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
109 #define SYNC_TIMEOUT (10 * 1000)
111 typedef struct RTSPActionServerSetup {
113 char transport_option[512];
114 } RTSPActionServerSetup;
117 int64_t count1, count2;
118 int64_t time1, time2;
121 /* context associated with one connection */
122 typedef struct HTTPContext {
123 enum HTTPState state;
124 int fd; /* socket file descriptor */
125 struct sockaddr_in from_addr; /* origin */
126 struct pollfd *poll_entry; /* used when polling */
128 uint8_t *buffer_ptr, *buffer_end;
131 int chunked_encoding;
132 int chunk_size; /* 0 if it needs to be read */
133 struct HTTPContext *next;
134 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
138 /* input format handling */
139 AVFormatContext *fmt_in;
140 int64_t start_time; /* In milliseconds - this wraps fairly often */
141 int64_t first_pts; /* initial pts value */
142 int64_t cur_pts; /* current pts value from the stream in us */
143 int64_t cur_frame_duration; /* duration of the current frame in us */
144 int cur_frame_bytes; /* output frame size, needed to compute
145 the time at which we send each
147 int pts_stream_index; /* stream we choose as clock reference */
148 int64_t cur_clock; /* current clock reference value in us */
149 /* output format handling */
150 struct FFStream *stream;
151 /* -1 is invalid stream */
152 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
153 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
155 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
156 int last_packet_sent; /* true if last data packet was sent */
158 DataRateData datarate;
165 int is_packetized; /* if true, the stream is packetized */
166 int packet_stream_index; /* current stream for output in state machine */
168 /* RTSP state specific */
169 uint8_t *pb_buffer; /* XXX: use that in all the code */
171 int seq; /* RTSP sequence number */
173 /* RTP state specific */
174 enum RTSPLowerTransport rtp_protocol;
175 char session_id[32]; /* session id */
176 AVFormatContext *rtp_ctx[MAX_STREAMS];
178 /* RTP/UDP specific */
179 URLContext *rtp_handles[MAX_STREAMS];
181 /* RTP/TCP specific */
182 struct HTTPContext *rtsp_c;
183 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
186 /* each generated stream is described here */
190 STREAM_TYPE_REDIRECT,
193 enum IPAddressAction {
198 typedef struct IPAddressACL {
199 struct IPAddressACL *next;
200 enum IPAddressAction action;
201 /* These are in host order */
202 struct in_addr first;
206 /* description of each stream of the avserver.conf file */
207 typedef struct FFStream {
208 enum StreamType stream_type;
209 char filename[1024]; /* stream filename */
210 struct FFStream *feed; /* feed we are using (can be null if
212 AVDictionary *in_opts; /* input parameters */
213 AVInputFormat *ifmt; /* if non NULL, force input format */
216 char dynamic_acl[1024];
218 int prebuffer; /* Number of millseconds early to start */
219 int64_t max_time; /* Number of milliseconds to run */
221 AVStream *streams[MAX_STREAMS];
222 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
223 char feed_filename[1024]; /* file name of the feed storage, or
224 input file name for a stream */
229 pid_t pid; /* of avconv process */
230 time_t pid_start; /* of avconv process */
232 struct FFStream *next;
233 unsigned bandwidth; /* bandwidth, in kbits/s */
236 /* multicast specific */
238 struct in_addr multicast_ip;
239 int multicast_port; /* first port used for multicast */
241 int loop; /* if true, send the stream in loops (only meaningful if file) */
244 int feed_opened; /* true if someone is writing to the feed */
245 int is_feed; /* true if it is a feed */
246 int readonly; /* True if writing is prohibited to the file */
247 int truncate; /* True if feeder connection truncate the feed file */
249 int64_t bytes_served;
250 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
251 int64_t feed_write_index; /* current write position in feed (it wraps around) */
252 int64_t feed_size; /* current size of feed */
253 struct FFStream *next_feed;
256 typedef struct FeedData {
257 long long data_count;
258 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
261 static struct sockaddr_in my_http_addr;
262 static struct sockaddr_in my_rtsp_addr;
264 static char logfilename[1024];
265 static HTTPContext *first_http_ctx;
266 static FFStream *first_feed; /* contains only feeds */
267 static FFStream *first_stream; /* contains all streams, including feeds */
269 static void new_connection(int server_fd, int is_rtsp);
270 static void close_connection(HTTPContext *c);
273 static int handle_connection(HTTPContext *c);
274 static int http_parse_request(HTTPContext *c);
275 static int http_send_data(HTTPContext *c);
276 static void compute_status(HTTPContext *c);
277 static int open_input_stream(HTTPContext *c, const char *info);
278 static int http_start_receive_data(HTTPContext *c);
279 static int http_receive_data(HTTPContext *c);
282 static int rtsp_parse_request(HTTPContext *c);
283 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
284 static void rtsp_cmd_options(HTTPContext *c, const char *url);
285 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
286 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
287 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
288 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
291 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
292 struct in_addr my_ip);
295 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
296 FFStream *stream, const char *session_id,
297 enum RTSPLowerTransport rtp_protocol);
298 static int rtp_new_av_stream(HTTPContext *c,
299 int stream_index, struct sockaddr_in *dest_addr,
300 HTTPContext *rtsp_c);
302 static const char *my_program_name;
304 static const char *config_filename;
306 static int avserver_debug;
307 static int no_launch;
308 static int need_to_start_children;
310 /* maximum number of simultaneous HTTP connections */
311 static unsigned int nb_max_http_connections = 2000;
312 static unsigned int nb_max_connections = 5;
313 static unsigned int nb_connections;
315 static uint64_t max_bandwidth = 1000;
316 static uint64_t current_bandwidth;
318 static int64_t cur_time; // Making this global saves on passing it around everywhere
320 static AVLFG random_state;
322 static FILE *logfile = NULL;
324 static int64_t ffm_read_write_index(int fd)
328 lseek(fd, 8, SEEK_SET);
329 if (read(fd, buf, 8) != 8)
334 static int ffm_write_write_index(int fd, int64_t pos)
340 buf[i] = (pos >> (56 - i * 8)) & 0xff;
341 lseek(fd, 8, SEEK_SET);
342 if (write(fd, buf, 8) != 8)
347 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
350 FFMContext *ffm = s->priv_data;
351 ffm->write_index = pos;
352 ffm->file_size = file_size;
355 /* FIXME: make avserver work with IPv6 */
356 /* resolve host with also IP address parsing */
357 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
360 if (!ff_inet_aton(hostname, sin_addr)) {
362 struct addrinfo *ai, *cur;
363 struct addrinfo hints = { 0 };
364 hints.ai_family = AF_INET;
365 if (getaddrinfo(hostname, NULL, &hints, &ai))
367 /* getaddrinfo returns a linked list of addrinfo structs.
368 * Even if we set ai_family = AF_INET above, make sure
369 * that the returned one actually is of the correct type. */
370 for (cur = ai; cur; cur = cur->ai_next) {
371 if (cur->ai_family == AF_INET) {
372 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
381 hp = gethostbyname(hostname);
384 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
390 static char *ctime1(char *buf2)
398 p = buf2 + strlen(p) - 1;
404 static void http_vlog(const char *fmt, va_list vargs)
406 static int print_prefix = 1;
411 fprintf(logfile, "%s ", buf);
413 print_prefix = strstr(fmt, "\n") != NULL;
414 vfprintf(logfile, fmt, vargs);
420 __attribute__ ((format (printf, 1, 2)))
422 static void http_log(const char *fmt, ...)
425 va_start(vargs, fmt);
426 http_vlog(fmt, vargs);
430 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
432 static int print_prefix = 1;
433 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
434 if (level > av_log_get_level())
436 if (print_prefix && avc)
437 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
438 print_prefix = strstr(fmt, "\n") != NULL;
439 http_vlog(fmt, vargs);
442 static void log_connection(HTTPContext *c)
447 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
448 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
449 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
452 static void update_datarate(DataRateData *drd, int64_t count)
454 if (!drd->time1 && !drd->count1) {
455 drd->time1 = drd->time2 = cur_time;
456 drd->count1 = drd->count2 = count;
457 } else if (cur_time - drd->time2 > 5000) {
458 drd->time1 = drd->time2;
459 drd->count1 = drd->count2;
460 drd->time2 = cur_time;
465 /* In bytes per second */
466 static int compute_datarate(DataRateData *drd, int64_t count)
468 if (cur_time == drd->time1)
471 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
475 static void start_children(FFStream *feed)
480 for (; feed; feed = feed->next) {
481 if (feed->child_argv && !feed->pid) {
482 feed->pid_start = time(0);
487 http_log("Unable to create children\n");
496 av_strlcpy(pathname, my_program_name, sizeof(pathname));
498 slash = strrchr(pathname, '/');
503 strcpy(slash, "avconv");
505 http_log("Launch command line: ");
506 http_log("%s ", pathname);
507 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
508 http_log("%s ", feed->child_argv[i]);
511 for (i = 3; i < 256; i++)
514 if (!avserver_debug) {
515 if (!freopen("/dev/null", "r", stdin))
516 http_log("failed to redirect STDIN to /dev/null\n;");
517 if (!freopen("/dev/null", "w", stdout))
518 http_log("failed to redirect STDOUT to /dev/null\n;");
519 if (!freopen("/dev/null", "w", stderr))
520 http_log("failed to redirect STDERR to /dev/null\n;");
523 signal(SIGPIPE, SIG_DFL);
525 execvp(pathname, feed->child_argv);
533 /* open a listening socket */
534 static int socket_open_listen(struct sockaddr_in *my_addr)
538 server_fd = socket(AF_INET,SOCK_STREAM,0);
545 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
547 my_addr->sin_family = AF_INET;
548 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
550 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
552 closesocket(server_fd);
556 if (listen (server_fd, 5) < 0) {
558 closesocket(server_fd);
561 ff_socket_nonblock(server_fd, 1);
566 /* start all multicast streams */
567 static void start_multicast(void)
572 struct sockaddr_in dest_addr;
573 int default_port, stream_index;
576 for(stream = first_stream; stream != NULL; stream = stream->next) {
577 if (stream->is_multicast) {
578 /* open the RTP connection */
579 snprintf(session_id, sizeof(session_id), "%08x%08x",
580 av_lfg_get(&random_state), av_lfg_get(&random_state));
582 /* choose a port if none given */
583 if (stream->multicast_port == 0) {
584 stream->multicast_port = default_port;
588 dest_addr.sin_family = AF_INET;
589 dest_addr.sin_addr = stream->multicast_ip;
590 dest_addr.sin_port = htons(stream->multicast_port);
592 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
593 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
597 if (open_input_stream(rtp_c, "") < 0) {
598 http_log("Could not open input stream for stream '%s'\n",
603 /* open each RTP stream */
604 for(stream_index = 0; stream_index < stream->nb_streams;
606 dest_addr.sin_port = htons(stream->multicast_port +
608 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
609 http_log("Could not open output stream '%s/streamid=%d'\n",
610 stream->filename, stream_index);
615 /* change state to send data */
616 rtp_c->state = HTTPSTATE_SEND_DATA;
621 /* main loop of the http server */
622 static int http_server(void)
624 int server_fd = 0, rtsp_server_fd = 0;
625 int ret, delay, delay1;
626 struct pollfd *poll_table, *poll_entry;
627 HTTPContext *c, *c_next;
629 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
630 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
634 if (my_http_addr.sin_port) {
635 server_fd = socket_open_listen(&my_http_addr);
640 if (my_rtsp_addr.sin_port) {
641 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
642 if (rtsp_server_fd < 0)
646 if (!rtsp_server_fd && !server_fd) {
647 http_log("HTTP and RTSP disabled.\n");
651 http_log("AVserver started.\n");
653 start_children(first_feed);
658 poll_entry = poll_table;
660 poll_entry->fd = server_fd;
661 poll_entry->events = POLLIN;
664 if (rtsp_server_fd) {
665 poll_entry->fd = rtsp_server_fd;
666 poll_entry->events = POLLIN;
670 /* wait for events on each HTTP handle */
677 case HTTPSTATE_SEND_HEADER:
678 case RTSPSTATE_SEND_REPLY:
679 case RTSPSTATE_SEND_PACKET:
680 c->poll_entry = poll_entry;
682 poll_entry->events = POLLOUT;
685 case HTTPSTATE_SEND_DATA_HEADER:
686 case HTTPSTATE_SEND_DATA:
687 case HTTPSTATE_SEND_DATA_TRAILER:
688 if (!c->is_packetized) {
689 /* for TCP, we output as much as we can (may need to put a limit) */
690 c->poll_entry = poll_entry;
692 poll_entry->events = POLLOUT;
695 /* when avserver is doing the timing, we work by
696 looking at which packet need to be sent every
698 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
703 case HTTPSTATE_WAIT_REQUEST:
704 case HTTPSTATE_RECEIVE_DATA:
705 case HTTPSTATE_WAIT_FEED:
706 case RTSPSTATE_WAIT_REQUEST:
707 /* need to catch errors */
708 c->poll_entry = poll_entry;
710 poll_entry->events = POLLIN;/* Maybe this will work */
714 c->poll_entry = NULL;
720 /* wait for an event on one connection. We poll at least every
721 second to handle timeouts */
723 ret = poll(poll_table, poll_entry - poll_table, delay);
724 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
725 ff_neterrno() != AVERROR(EINTR))
729 cur_time = av_gettime() / 1000;
731 if (need_to_start_children) {
732 need_to_start_children = 0;
733 start_children(first_feed);
736 /* now handle the events */
737 for(c = first_http_ctx; c != NULL; c = c_next) {
739 if (handle_connection(c) < 0) {
740 /* close and free the connection */
746 poll_entry = poll_table;
748 /* new HTTP connection request ? */
749 if (poll_entry->revents & POLLIN)
750 new_connection(server_fd, 0);
753 if (rtsp_server_fd) {
754 /* new RTSP connection request ? */
755 if (poll_entry->revents & POLLIN)
756 new_connection(rtsp_server_fd, 1);
761 /* start waiting for a new HTTP/RTSP request */
762 static void start_wait_request(HTTPContext *c, int is_rtsp)
764 c->buffer_ptr = c->buffer;
765 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
768 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
769 c->state = RTSPSTATE_WAIT_REQUEST;
771 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
772 c->state = HTTPSTATE_WAIT_REQUEST;
776 static void http_send_too_busy_reply(int fd)
779 int len = snprintf(buffer, sizeof(buffer),
780 "HTTP/1.0 503 Server too busy\r\n"
781 "Content-type: text/html\r\n"
783 "<html><head><title>Too busy</title></head><body>\r\n"
784 "<p>The server is too busy to serve your request at this time.</p>\r\n"
785 "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
786 "</body></html>\r\n",
787 nb_connections, nb_max_connections);
788 send(fd, buffer, len, 0);
792 static void new_connection(int server_fd, int is_rtsp)
794 struct sockaddr_in from_addr;
797 HTTPContext *c = NULL;
799 len = sizeof(from_addr);
800 fd = accept(server_fd, (struct sockaddr *)&from_addr,
803 http_log("error during accept %s\n", strerror(errno));
806 ff_socket_nonblock(fd, 1);
808 if (nb_connections >= nb_max_connections) {
809 http_send_too_busy_reply(fd);
813 /* add a new connection */
814 c = av_mallocz(sizeof(HTTPContext));
819 c->poll_entry = NULL;
820 c->from_addr = from_addr;
821 c->buffer_size = IOBUFFER_INIT_SIZE;
822 c->buffer = av_malloc(c->buffer_size);
826 c->next = first_http_ctx;
830 start_wait_request(c, is_rtsp);
842 static void close_connection(HTTPContext *c)
844 HTTPContext **cp, *c1;
846 AVFormatContext *ctx;
850 /* remove connection from list */
851 cp = &first_http_ctx;
852 while ((*cp) != NULL) {
860 /* remove references, if any (XXX: do it faster) */
861 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
866 /* remove connection associated resources */
870 /* close each frame parser */
871 for(i=0;i<c->fmt_in->nb_streams;i++) {
872 st = c->fmt_in->streams[i];
873 if (st->codec->codec)
874 avcodec_close(st->codec);
876 avformat_close_input(&c->fmt_in);
879 /* free RTP output streams if any */
882 nb_streams = c->stream->nb_streams;
884 for(i=0;i<nb_streams;i++) {
887 av_write_trailer(ctx);
888 av_dict_free(&ctx->metadata);
889 av_free(ctx->streams[0]);
892 h = c->rtp_handles[i];
899 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
902 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
903 av_write_trailer(ctx);
904 av_freep(&c->pb_buffer);
905 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
910 for(i=0; i<ctx->nb_streams; i++)
911 av_free(ctx->streams[i]);
913 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
914 current_bandwidth -= c->stream->bandwidth;
916 /* signal that there is no feed if we are the feeder socket */
917 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
918 c->stream->feed_opened = 0;
922 av_freep(&c->pb_buffer);
923 av_freep(&c->packet_buffer);
929 static int handle_connection(HTTPContext *c)
934 case HTTPSTATE_WAIT_REQUEST:
935 case RTSPSTATE_WAIT_REQUEST:
937 if ((c->timeout - cur_time) < 0)
939 if (c->poll_entry->revents & (POLLERR | POLLHUP))
942 /* no need to read if no events */
943 if (!(c->poll_entry->revents & POLLIN))
947 len = recv(c->fd, c->buffer_ptr, 1, 0);
949 if (ff_neterrno() != AVERROR(EAGAIN) &&
950 ff_neterrno() != AVERROR(EINTR))
952 } else if (len == 0) {
955 /* search for end of request. */
957 c->buffer_ptr += len;
959 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
960 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
961 /* request found : parse it and reply */
962 if (c->state == HTTPSTATE_WAIT_REQUEST) {
963 ret = http_parse_request(c);
965 ret = rtsp_parse_request(c);
969 } else if (ptr >= c->buffer_end) {
970 /* request too long: cannot do anything */
972 } else goto read_loop;
976 case HTTPSTATE_SEND_HEADER:
977 if (c->poll_entry->revents & (POLLERR | POLLHUP))
980 /* no need to write if no events */
981 if (!(c->poll_entry->revents & POLLOUT))
983 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
985 if (ff_neterrno() != AVERROR(EAGAIN) &&
986 ff_neterrno() != AVERROR(EINTR)) {
987 /* error : close connection */
988 av_freep(&c->pb_buffer);
992 c->buffer_ptr += len;
994 c->stream->bytes_served += len;
995 c->data_count += len;
996 if (c->buffer_ptr >= c->buffer_end) {
997 av_freep(&c->pb_buffer);
1001 /* all the buffer was sent : synchronize to the incoming stream */
1002 c->state = HTTPSTATE_SEND_DATA_HEADER;
1003 c->buffer_ptr = c->buffer_end = c->buffer;
1008 case HTTPSTATE_SEND_DATA:
1009 case HTTPSTATE_SEND_DATA_HEADER:
1010 case HTTPSTATE_SEND_DATA_TRAILER:
1011 /* for packetized output, we consider we can always write (the
1012 input streams sets the speed). It may be better to verify
1013 that we do not rely too much on the kernel queues */
1014 if (!c->is_packetized) {
1015 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1018 /* no need to read if no events */
1019 if (!(c->poll_entry->revents & POLLOUT))
1022 if (http_send_data(c) < 0)
1024 /* close connection if trailer sent */
1025 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1028 case HTTPSTATE_RECEIVE_DATA:
1029 /* no need to read if no events */
1030 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1032 if (!(c->poll_entry->revents & POLLIN))
1034 if (http_receive_data(c) < 0)
1037 case HTTPSTATE_WAIT_FEED:
1038 /* no need to read if no events */
1039 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1042 /* nothing to do, we'll be waken up by incoming feed packets */
1045 case RTSPSTATE_SEND_REPLY:
1046 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1047 av_freep(&c->pb_buffer);
1050 /* no need to write if no events */
1051 if (!(c->poll_entry->revents & POLLOUT))
1053 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1055 if (ff_neterrno() != AVERROR(EAGAIN) &&
1056 ff_neterrno() != AVERROR(EINTR)) {
1057 /* error : close connection */
1058 av_freep(&c->pb_buffer);
1062 c->buffer_ptr += len;
1063 c->data_count += len;
1064 if (c->buffer_ptr >= c->buffer_end) {
1065 /* all the buffer was sent : wait for a new request */
1066 av_freep(&c->pb_buffer);
1067 start_wait_request(c, 1);
1071 case RTSPSTATE_SEND_PACKET:
1072 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1073 av_freep(&c->packet_buffer);
1076 /* no need to write if no events */
1077 if (!(c->poll_entry->revents & POLLOUT))
1079 len = send(c->fd, c->packet_buffer_ptr,
1080 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1082 if (ff_neterrno() != AVERROR(EAGAIN) &&
1083 ff_neterrno() != AVERROR(EINTR)) {
1084 /* error : close connection */
1085 av_freep(&c->packet_buffer);
1089 c->packet_buffer_ptr += len;
1090 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1091 /* all the buffer was sent : wait for a new request */
1092 av_freep(&c->packet_buffer);
1093 c->state = RTSPSTATE_WAIT_REQUEST;
1097 case HTTPSTATE_READY:
1106 static int extract_rates(char *rates, int ratelen, const char *request)
1110 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1111 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1112 const char *q = p + 7;
1114 while (*q && *q != '\n' && av_isspace(*q))
1117 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1123 memset(rates, 0xff, ratelen);
1126 while (*q && *q != '\n' && *q != ':')
1129 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1133 if (stream_no < ratelen && stream_no >= 0)
1134 rates[stream_no] = rate_no;
1136 while (*q && *q != '\n' && !av_isspace(*q))
1143 p = strchr(p, '\n');
1153 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1156 int best_bitrate = 100000000;
1159 for (i = 0; i < feed->nb_streams; i++) {
1160 AVCodecContext *feed_codec = feed->streams[i]->codec;
1162 if (feed_codec->codec_id != codec->codec_id ||
1163 feed_codec->sample_rate != codec->sample_rate ||
1164 feed_codec->width != codec->width ||
1165 feed_codec->height != codec->height)
1168 /* Potential stream */
1170 /* We want the fastest stream less than bit_rate, or the slowest
1171 * faster than bit_rate
1174 if (feed_codec->bit_rate <= bit_rate) {
1175 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1176 best_bitrate = feed_codec->bit_rate;
1180 if (feed_codec->bit_rate < best_bitrate) {
1181 best_bitrate = feed_codec->bit_rate;
1190 static int modify_current_stream(HTTPContext *c, char *rates)
1193 FFStream *req = c->stream;
1194 int action_required = 0;
1196 /* Not much we can do for a feed */
1200 for (i = 0; i < req->nb_streams; i++) {
1201 AVCodecContext *codec = req->streams[i]->codec;
1205 c->switch_feed_streams[i] = req->feed_streams[i];
1208 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1211 /* Wants off or slow */
1212 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1214 /* This doesn't work well when it turns off the only stream! */
1215 c->switch_feed_streams[i] = -2;
1216 c->feed_streams[i] = -2;
1221 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1222 action_required = 1;
1225 return action_required;
1228 /* XXX: factorize in utils.c ? */
1229 /* XXX: take care with different space meaning */
1230 static void skip_spaces(const char **pp)
1234 while (*p == ' ' || *p == '\t')
1239 static void get_word(char *buf, int buf_size, const char **pp)
1247 while (!av_isspace(*p) && *p != '\0') {
1248 if ((q - buf) < buf_size - 1)
1257 static void get_arg(char *buf, int buf_size, const char **pp)
1264 while (av_isspace(*p)) p++;
1267 if (*p == '\"' || *p == '\'')
1279 if ((q - buf) < buf_size - 1)
1284 if (quote && *p == quote)
1289 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1290 const char *p, const char *filename, int line_num)
1296 get_arg(arg, sizeof(arg), &p);
1297 if (av_strcasecmp(arg, "allow") == 0)
1298 acl.action = IP_ALLOW;
1299 else if (av_strcasecmp(arg, "deny") == 0)
1300 acl.action = IP_DENY;
1302 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1303 filename, line_num, arg);
1307 get_arg(arg, sizeof(arg), &p);
1309 if (resolve_host(&acl.first, arg) != 0) {
1310 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1311 filename, line_num, arg);
1314 acl.last = acl.first;
1316 get_arg(arg, sizeof(arg), &p);
1319 if (resolve_host(&acl.last, arg) != 0) {
1320 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1321 filename, line_num, arg);
1327 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1328 IPAddressACL **naclp = 0;
1334 naclp = &stream->acl;
1340 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1341 filename, line_num);
1347 naclp = &(*naclp)->next;
1355 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1360 IPAddressACL *acl = NULL;
1364 f = fopen(stream->dynamic_acl, "r");
1366 perror(stream->dynamic_acl);
1370 acl = av_mallocz(sizeof(IPAddressACL));
1374 if (fgets(line, sizeof(line), f) == NULL)
1378 while (av_isspace(*p))
1380 if (*p == '\0' || *p == '#')
1382 get_arg(cmd, sizeof(cmd), &p);
1384 if (!av_strcasecmp(cmd, "ACL"))
1385 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1392 static void free_acl_list(IPAddressACL *in_acl)
1394 IPAddressACL *pacl,*pacl2;
1404 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1406 enum IPAddressAction last_action = IP_DENY;
1408 struct in_addr *src = &c->from_addr.sin_addr;
1409 unsigned long src_addr = src->s_addr;
1411 for (acl = in_acl; acl; acl = acl->next) {
1412 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1413 return (acl->action == IP_ALLOW) ? 1 : 0;
1414 last_action = acl->action;
1417 /* Nothing matched, so return not the last action */
1418 return (last_action == IP_DENY) ? 1 : 0;
1421 static int validate_acl(FFStream *stream, HTTPContext *c)
1427 /* if stream->acl is null validate_acl_list will return 1 */
1428 ret = validate_acl_list(stream->acl, c);
1430 if (stream->dynamic_acl[0]) {
1431 acl = parse_dynamic_acl(stream, c);
1433 ret = validate_acl_list(acl, c);
1441 /* compute the real filename of a file by matching it without its
1442 extensions to all the stream filenames */
1443 static void compute_real_filename(char *filename, int max_size)
1450 /* compute filename by matching without the file extensions */
1451 av_strlcpy(file1, filename, sizeof(file1));
1452 p = strrchr(file1, '.');
1455 for(stream = first_stream; stream != NULL; stream = stream->next) {
1456 av_strlcpy(file2, stream->filename, sizeof(file2));
1457 p = strrchr(file2, '.');
1460 if (!strcmp(file1, file2)) {
1461 av_strlcpy(filename, stream->filename, max_size);
1476 /* parse http request and prepare header */
1477 static int http_parse_request(HTTPContext *c)
1481 enum RedirType redir_type;
1483 char info[1024], filename[1024];
1487 const char *mime_type;
1491 const char *useragent = 0;
1494 get_word(cmd, sizeof(cmd), &p);
1495 av_strlcpy(c->method, cmd, sizeof(c->method));
1497 if (!strcmp(cmd, "GET"))
1499 else if (!strcmp(cmd, "POST"))
1504 get_word(url, sizeof(url), &p);
1505 av_strlcpy(c->url, url, sizeof(c->url));
1507 get_word(protocol, sizeof(protocol), (const char **)&p);
1508 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1511 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1514 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1516 /* find the filename and the optional info string in the request */
1517 p1 = strchr(url, '?');
1519 av_strlcpy(info, p1, sizeof(info));
1524 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1526 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1527 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1529 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1533 p = strchr(p, '\n');
1540 redir_type = REDIR_NONE;
1541 if (av_match_ext(filename, "asx")) {
1542 redir_type = REDIR_ASX;
1543 filename[strlen(filename)-1] = 'f';
1544 } else if (av_match_ext(filename, "asf") &&
1545 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1546 /* if this isn't WMP or lookalike, return the redirector file */
1547 redir_type = REDIR_ASF;
1548 } else if (av_match_ext(filename, "rpm,ram")) {
1549 redir_type = REDIR_RAM;
1550 strcpy(filename + strlen(filename)-2, "m");
1551 } else if (av_match_ext(filename, "rtsp")) {
1552 redir_type = REDIR_RTSP;
1553 compute_real_filename(filename, sizeof(filename) - 1);
1554 } else if (av_match_ext(filename, "sdp")) {
1555 redir_type = REDIR_SDP;
1556 compute_real_filename(filename, sizeof(filename) - 1);
1559 // "redirect" / request to index.html
1560 if (!strlen(filename))
1561 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1563 stream = first_stream;
1564 while (stream != NULL) {
1565 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1567 stream = stream->next;
1569 if (stream == NULL) {
1570 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1571 http_log("File '%s' not found\n", url);
1576 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1577 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1579 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1580 c->http_error = 301;
1582 q += snprintf(q, c->buffer_size,
1583 "HTTP/1.0 301 Moved\r\n"
1585 "Content-type: text/html\r\n"
1587 "<html><head><title>Moved</title></head><body>\r\n"
1588 "You should be <a href=\"%s\">redirected</a>.\r\n"
1589 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1590 /* prepare output buffer */
1591 c->buffer_ptr = c->buffer;
1593 c->state = HTTPSTATE_SEND_HEADER;
1597 /* If this is WMP, get the rate information */
1598 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1599 if (modify_current_stream(c, ratebuf)) {
1600 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1601 if (c->switch_feed_streams[i] >= 0)
1602 c->switch_feed_streams[i] = -1;
1607 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1608 current_bandwidth += stream->bandwidth;
1610 /* If already streaming this feed, do not let start another feeder. */
1611 if (stream->feed_opened) {
1612 snprintf(msg, sizeof(msg), "This feed is already being received.");
1613 http_log("Feed '%s' already being received\n", stream->feed_filename);
1617 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1618 c->http_error = 503;
1620 q += snprintf(q, c->buffer_size,
1621 "HTTP/1.0 503 Server too busy\r\n"
1622 "Content-type: text/html\r\n"
1624 "<html><head><title>Too busy</title></head><body>\r\n"
1625 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1626 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1627 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1628 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1629 /* prepare output buffer */
1630 c->buffer_ptr = c->buffer;
1632 c->state = HTTPSTATE_SEND_HEADER;
1636 if (redir_type != REDIR_NONE) {
1637 const char *hostinfo = 0;
1639 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1640 if (av_strncasecmp(p, "Host:", 5) == 0) {
1644 p = strchr(p, '\n');
1655 while (av_isspace(*hostinfo))
1658 eoh = strchr(hostinfo, '\n');
1660 if (eoh[-1] == '\r')
1663 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1664 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1665 hostbuf[eoh - hostinfo] = 0;
1667 c->http_error = 200;
1669 switch(redir_type) {
1671 q += snprintf(q, c->buffer_size,
1672 "HTTP/1.0 200 ASX Follows\r\n"
1673 "Content-type: video/x-ms-asf\r\n"
1675 "<ASX Version=\"3\">\r\n"
1676 //"<!-- Autogenerated by avserver -->\r\n"
1677 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1678 "</ASX>\r\n", hostbuf, filename, info);
1681 q += snprintf(q, c->buffer_size,
1682 "HTTP/1.0 200 RAM Follows\r\n"
1683 "Content-type: audio/x-pn-realaudio\r\n"
1685 "# Autogenerated by avserver\r\n"
1686 "http://%s/%s%s\r\n", hostbuf, filename, info);
1689 q += snprintf(q, c->buffer_size,
1690 "HTTP/1.0 200 ASF Redirect follows\r\n"
1691 "Content-type: video/x-ms-asf\r\n"
1694 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1698 char hostname[256], *p;
1699 /* extract only hostname */
1700 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1701 p = strrchr(hostname, ':');
1704 q += snprintf(q, c->buffer_size,
1705 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1706 /* XXX: incorrect mime type ? */
1707 "Content-type: application/x-rtsp\r\n"
1709 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1717 struct sockaddr_in my_addr;
1719 q += snprintf(q, c->buffer_size,
1720 "HTTP/1.0 200 OK\r\n"
1721 "Content-type: application/sdp\r\n"
1724 len = sizeof(my_addr);
1725 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1727 /* XXX: should use a dynamic buffer */
1728 sdp_data_size = prepare_sdp_description(stream,
1731 if (sdp_data_size > 0) {
1732 memcpy(q, sdp_data, sdp_data_size);
1744 /* prepare output buffer */
1745 c->buffer_ptr = c->buffer;
1747 c->state = HTTPSTATE_SEND_HEADER;
1753 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1757 stream->conns_served++;
1759 /* XXX: add there authenticate and IP match */
1762 /* if post, it means a feed is being sent */
1763 if (!stream->is_feed) {
1764 /* However it might be a status report from WMP! Let us log the
1765 * data as it might come in handy one day. */
1766 const char *logline = 0;
1769 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1770 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1774 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1775 client_id = strtol(p + 18, 0, 10);
1776 p = strchr(p, '\n');
1784 char *eol = strchr(logline, '\n');
1789 if (eol[-1] == '\r')
1791 http_log("%.*s\n", (int) (eol - logline), logline);
1792 c->suppress_log = 1;
1797 http_log("\nGot request:\n%s\n", c->buffer);
1800 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1803 /* Now we have to find the client_id */
1804 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1805 if (wmpc->wmp_client_id == client_id)
1809 if (wmpc && modify_current_stream(wmpc, ratebuf))
1810 wmpc->switch_pending = 1;
1813 snprintf(msg, sizeof(msg), "POST command not handled");
1817 if (http_start_receive_data(c) < 0) {
1818 snprintf(msg, sizeof(msg), "could not open feed");
1822 c->state = HTTPSTATE_RECEIVE_DATA;
1827 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1828 http_log("\nGot request:\n%s\n", c->buffer);
1831 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1834 /* open input stream */
1835 if (open_input_stream(c, info) < 0) {
1836 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1840 /* prepare http header */
1842 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1843 mime_type = c->stream->fmt->mime_type;
1845 mime_type = "application/x-octet-stream";
1846 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1848 /* for asf, we need extra headers */
1849 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1850 /* Need to allocate a client id */
1852 c->wmp_client_id = av_lfg_get(&random_state);
1854 q += snprintf(q, q - (char *) 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);
1856 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1857 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1859 /* prepare output buffer */
1861 c->buffer_ptr = c->buffer;
1863 c->state = HTTPSTATE_SEND_HEADER;
1866 c->http_error = 404;
1868 q += snprintf(q, c->buffer_size,
1869 "HTTP/1.0 404 Not Found\r\n"
1870 "Content-type: text/html\r\n"
1873 "<head><title>404 Not Found</title></head>\n"
1876 /* prepare output buffer */
1877 c->buffer_ptr = c->buffer;
1879 c->state = HTTPSTATE_SEND_HEADER;
1883 c->http_error = 200; /* horrible : we use this value to avoid
1884 going to the send data state */
1885 c->state = HTTPSTATE_SEND_HEADER;
1889 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1891 static const char suffix[] = " kMGTP";
1894 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1896 avio_printf(pb, "%"PRId64"%c", count, *s);
1899 static void compute_status(HTTPContext *c)
1908 if (avio_open_dyn_buf(&pb) < 0) {
1909 /* XXX: return an error ? */
1910 c->buffer_ptr = c->buffer;
1911 c->buffer_end = c->buffer;
1915 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1916 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1917 avio_printf(pb, "Pragma: no-cache\r\n");
1918 avio_printf(pb, "\r\n");
1920 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1921 if (c->stream->feed_filename[0])
1922 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1923 avio_printf(pb, "</head>\n<body>");
1924 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1926 avio_printf(pb, "<h2>Available Streams</h2>\n");
1927 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1928 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");
1929 stream = first_stream;
1930 while (stream != NULL) {
1931 char sfilename[1024];
1934 if (stream->feed != stream) {
1935 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1936 eosf = sfilename + strlen(sfilename);
1937 if (eosf - sfilename >= 4) {
1938 if (strcmp(eosf - 4, ".asf") == 0)
1939 strcpy(eosf - 4, ".asx");
1940 else if (strcmp(eosf - 3, ".rm") == 0)
1941 strcpy(eosf - 3, ".ram");
1942 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1943 /* generate a sample RTSP director if
1944 unicast. Generate an SDP redirector if
1946 eosf = strrchr(sfilename, '.');
1948 eosf = sfilename + strlen(sfilename);
1949 if (stream->is_multicast)
1950 strcpy(eosf, ".sdp");
1952 strcpy(eosf, ".rtsp");
1956 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1957 sfilename, stream->filename);
1958 avio_printf(pb, "<td align=right> %d <td align=right> ",
1959 stream->conns_served);
1960 fmt_bytecount(pb, stream->bytes_served);
1961 switch(stream->stream_type) {
1962 case STREAM_TYPE_LIVE: {
1963 int audio_bit_rate = 0;
1964 int video_bit_rate = 0;
1965 const char *audio_codec_name = "";
1966 const char *video_codec_name = "";
1967 const char *audio_codec_name_extra = "";
1968 const char *video_codec_name_extra = "";
1970 for(i=0;i<stream->nb_streams;i++) {
1971 AVStream *st = stream->streams[i];
1972 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1973 switch(st->codec->codec_type) {
1974 case AVMEDIA_TYPE_AUDIO:
1975 audio_bit_rate += st->codec->bit_rate;
1977 if (*audio_codec_name)
1978 audio_codec_name_extra = "...";
1979 audio_codec_name = codec->name;
1982 case AVMEDIA_TYPE_VIDEO:
1983 video_bit_rate += st->codec->bit_rate;
1985 if (*video_codec_name)
1986 video_codec_name_extra = "...";
1987 video_codec_name = codec->name;
1990 case AVMEDIA_TYPE_DATA:
1991 video_bit_rate += st->codec->bit_rate;
1997 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",
2000 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2001 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2003 avio_printf(pb, "<td>%s", stream->feed->filename);
2005 avio_printf(pb, "<td>%s", stream->feed_filename);
2006 avio_printf(pb, "\n");
2010 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2014 stream = stream->next;
2016 avio_printf(pb, "</table>\n");
2018 stream = first_stream;
2019 while (stream != NULL) {
2020 if (stream->feed == stream) {
2021 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2023 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2025 #if defined(linux) && !defined(CONFIG_NOCUTILS)
2030 /* This is somewhat linux specific I guess */
2031 snprintf(ps_cmd, sizeof(ps_cmd),
2032 "ps -o \"%%cpu,cputime\" --no-headers %d",
2035 pid_stat = popen(ps_cmd, "r");
2040 if (fscanf(pid_stat, "%10s %64s", cpuperc,
2042 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2050 avio_printf(pb, "<p>");
2052 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");
2054 for (i = 0; i < stream->nb_streams; i++) {
2055 AVStream *st = stream->streams[i];
2056 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2057 const char *type = "unknown";
2058 char parameters[64];
2062 switch(st->codec->codec_type) {
2063 case AVMEDIA_TYPE_AUDIO:
2065 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2067 case AVMEDIA_TYPE_VIDEO:
2069 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2070 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2075 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2076 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2078 avio_printf(pb, "</table>\n");
2081 stream = stream->next;
2084 /* connection status */
2085 avio_printf(pb, "<h2>Connection Status</h2>\n");
2087 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2088 nb_connections, nb_max_connections);
2090 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2091 current_bandwidth, max_bandwidth);
2093 avio_printf(pb, "<table>\n");
2094 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");
2095 c1 = first_http_ctx;
2097 while (c1 != NULL) {
2103 for (j = 0; j < c1->stream->nb_streams; j++) {
2104 if (!c1->stream->feed)
2105 bitrate += c1->stream->streams[j]->codec->bit_rate;
2106 else if (c1->feed_streams[j] >= 0)
2107 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2112 p = inet_ntoa(c1->from_addr.sin_addr);
2113 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2115 c1->stream ? c1->stream->filename : "",
2116 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2119 http_state[c1->state]);
2120 fmt_bytecount(pb, bitrate);
2121 avio_printf(pb, "<td align=right>");
2122 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2123 avio_printf(pb, "<td align=right>");
2124 fmt_bytecount(pb, c1->data_count);
2125 avio_printf(pb, "\n");
2128 avio_printf(pb, "</table>\n");
2133 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2134 avio_printf(pb, "</body>\n</html>\n");
2136 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2137 c->buffer_ptr = c->pb_buffer;
2138 c->buffer_end = c->pb_buffer + len;
2141 static int open_input_stream(HTTPContext *c, const char *info)
2144 char input_filename[1024];
2145 AVFormatContext *s = NULL;
2149 /* find file name */
2150 if (c->stream->feed) {
2151 strcpy(input_filename, c->stream->feed->feed_filename);
2152 /* compute position (absolute time) */
2153 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2154 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2156 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2157 int prebuffer = strtol(buf, 0, 10);
2158 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2160 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2162 strcpy(input_filename, c->stream->feed_filename);
2163 /* compute position (relative time) */
2164 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2165 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2170 if (input_filename[0] == '\0')
2174 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2175 http_log("could not open %s: %d\n", input_filename, ret);
2178 s->flags |= AVFMT_FLAG_GENPTS;
2180 if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
2181 http_log("Could not find stream info '%s'\n", input_filename);
2182 avformat_close_input(&s);
2186 /* choose stream as clock source (we favorize video stream if
2187 present) for packet sending */
2188 c->pts_stream_index = 0;
2189 for(i=0;i<c->stream->nb_streams;i++) {
2190 if (c->pts_stream_index == 0 &&
2191 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2192 c->pts_stream_index = i;
2196 if (c->fmt_in->iformat->read_seek)
2197 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2198 /* set the start time (needed for maxtime and RTP packet timing) */
2199 c->start_time = cur_time;
2200 c->first_pts = AV_NOPTS_VALUE;
2204 /* return the server clock (in us) */
2205 static int64_t get_server_clock(HTTPContext *c)
2207 /* compute current pts value from system time */
2208 return (cur_time - c->start_time) * 1000;
2211 /* return the estimated time at which the current packet must be sent
2213 static int64_t get_packet_send_clock(HTTPContext *c)
2215 int bytes_left, bytes_sent, frame_bytes;
2217 frame_bytes = c->cur_frame_bytes;
2218 if (frame_bytes <= 0)
2221 bytes_left = c->buffer_end - c->buffer_ptr;
2222 bytes_sent = frame_bytes - bytes_left;
2223 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2228 static int http_prepare_data(HTTPContext *c)
2231 AVFormatContext *ctx;
2233 av_freep(&c->pb_buffer);
2235 case HTTPSTATE_SEND_DATA_HEADER:
2236 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2237 av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2238 av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2239 av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2240 av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2242 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2244 for(i=0;i<c->stream->nb_streams;i++) {
2246 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2247 /* if file or feed, then just take streams from FFStream struct */
2248 if (!c->stream->feed ||
2249 c->stream->feed == c->stream)
2250 src = c->stream->streams[i];
2252 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2254 *(c->fmt_ctx.streams[i]) = *src;
2255 c->fmt_ctx.streams[i]->priv_data = 0;
2256 c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2257 AVStream, not in codec */
2259 /* set output format parameters */
2260 c->fmt_ctx.oformat = c->stream->fmt;
2261 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2263 c->got_key_frame = 0;
2265 /* prepare header and save header data in a stream */
2266 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2267 /* XXX: potential leak */
2270 c->fmt_ctx.pb->seekable = 0;
2273 * HACK to avoid mpeg ps muxer to spit many underflow errors
2274 * Default value from Libav
2275 * Try to set it use configuration option
2277 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2279 if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2280 http_log("Error writing output header\n");
2283 av_dict_free(&c->fmt_ctx.metadata);
2285 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2286 c->buffer_ptr = c->pb_buffer;
2287 c->buffer_end = c->pb_buffer + len;
2289 c->state = HTTPSTATE_SEND_DATA;
2290 c->last_packet_sent = 0;
2292 case HTTPSTATE_SEND_DATA:
2293 /* find a new packet */
2294 /* read a packet from the input stream */
2295 if (c->stream->feed)
2296 ffm_set_write_index(c->fmt_in,
2297 c->stream->feed->feed_write_index,
2298 c->stream->feed->feed_size);
2300 if (c->stream->max_time &&
2301 c->stream->max_time + c->start_time - cur_time < 0)
2302 /* We have timed out */
2303 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2307 ret = av_read_frame(c->fmt_in, &pkt);
2309 if (c->stream->feed) {
2310 /* if coming from feed, it means we reached the end of the
2311 ffm file, so must wait for more data */
2312 c->state = HTTPSTATE_WAIT_FEED;
2313 return 1; /* state changed */
2314 } else if (ret == AVERROR(EAGAIN)) {
2315 /* input not ready, come back later */
2318 if (c->stream->loop) {
2319 avformat_close_input(&c->fmt_in);
2320 if (open_input_stream(c, "") < 0)
2325 /* must send trailer now because eof or error */
2326 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2330 int source_index = pkt.stream_index;
2331 /* update first pts if needed */
2332 if (c->first_pts == AV_NOPTS_VALUE) {
2333 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2334 c->start_time = cur_time;
2336 /* send it to the appropriate stream */
2337 if (c->stream->feed) {
2338 /* if coming from a feed, select the right stream */
2339 if (c->switch_pending) {
2340 c->switch_pending = 0;
2341 for(i=0;i<c->stream->nb_streams;i++) {
2342 if (c->switch_feed_streams[i] == pkt.stream_index)
2343 if (pkt.flags & AV_PKT_FLAG_KEY)
2344 c->switch_feed_streams[i] = -1;
2345 if (c->switch_feed_streams[i] >= 0)
2346 c->switch_pending = 1;
2349 for(i=0;i<c->stream->nb_streams;i++) {
2350 if (c->stream->feed_streams[i] == pkt.stream_index) {
2351 AVStream *st = c->fmt_in->streams[source_index];
2352 pkt.stream_index = i;
2353 if (pkt.flags & AV_PKT_FLAG_KEY &&
2354 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2355 c->stream->nb_streams == 1))
2356 c->got_key_frame = 1;
2357 if (!c->stream->send_on_key || c->got_key_frame)
2362 AVCodecContext *codec;
2363 AVStream *ist, *ost;
2365 ist = c->fmt_in->streams[source_index];
2366 /* specific handling for RTP: we use several
2367 output stream (one for each RTP
2368 connection). XXX: need more abstract handling */
2369 if (c->is_packetized) {
2370 /* compute send time and duration */
2371 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2372 c->cur_pts -= c->first_pts;
2373 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2374 /* find RTP context */
2375 c->packet_stream_index = pkt.stream_index;
2376 ctx = c->rtp_ctx[c->packet_stream_index];
2378 av_free_packet(&pkt);
2381 codec = ctx->streams[0]->codec;
2382 /* only one stream per RTP connection */
2383 pkt.stream_index = 0;
2387 codec = ctx->streams[pkt.stream_index]->codec;
2390 if (c->is_packetized) {
2391 int max_packet_size;
2392 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2393 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2395 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2396 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2398 ret = avio_open_dyn_buf(&ctx->pb);
2401 /* XXX: potential leak */
2404 ost = ctx->streams[pkt.stream_index];
2406 ctx->pb->seekable = 0;
2407 if (pkt.dts != AV_NOPTS_VALUE)
2408 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2409 if (pkt.pts != AV_NOPTS_VALUE)
2410 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2411 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2412 if (av_write_frame(ctx, &pkt) < 0) {
2413 http_log("Error writing frame to output\n");
2414 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2417 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2418 c->cur_frame_bytes = len;
2419 c->buffer_ptr = c->pb_buffer;
2420 c->buffer_end = c->pb_buffer + len;
2422 codec->frame_number++;
2424 av_free_packet(&pkt);
2428 av_free_packet(&pkt);
2433 case HTTPSTATE_SEND_DATA_TRAILER:
2434 /* last packet test ? */
2435 if (c->last_packet_sent || c->is_packetized)
2438 /* prepare header */
2439 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2440 /* XXX: potential leak */
2443 c->fmt_ctx.pb->seekable = 0;
2444 av_write_trailer(ctx);
2445 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2446 c->buffer_ptr = c->pb_buffer;
2447 c->buffer_end = c->pb_buffer + len;
2449 c->last_packet_sent = 1;
2455 /* should convert the format at the same time */
2456 /* send data starting at c->buffer_ptr to the output connection
2457 (either UDP or TCP connection) */
2458 static int http_send_data(HTTPContext *c)
2463 if (c->buffer_ptr >= c->buffer_end) {
2464 ret = http_prepare_data(c);
2468 /* state change requested */
2471 if (c->is_packetized) {
2472 /* RTP data output */
2473 len = c->buffer_end - c->buffer_ptr;
2475 /* fail safe - should never happen */
2477 c->buffer_ptr = c->buffer_end;
2480 len = (c->buffer_ptr[0] << 24) |
2481 (c->buffer_ptr[1] << 16) |
2482 (c->buffer_ptr[2] << 8) |
2484 if (len > (c->buffer_end - c->buffer_ptr))
2486 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2487 /* nothing to send yet: we can wait */
2491 c->data_count += len;
2492 update_datarate(&c->datarate, c->data_count);
2494 c->stream->bytes_served += len;
2496 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2497 /* RTP packets are sent inside the RTSP TCP connection */
2499 int interleaved_index, size;
2501 HTTPContext *rtsp_c;
2504 /* if no RTSP connection left, error */
2507 /* if already sending something, then wait. */
2508 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2510 if (avio_open_dyn_buf(&pb) < 0)
2512 interleaved_index = c->packet_stream_index * 2;
2513 /* RTCP packets are sent at odd indexes */
2514 if (c->buffer_ptr[1] == 200)
2515 interleaved_index++;
2516 /* write RTSP TCP header */
2518 header[1] = interleaved_index;
2519 header[2] = len >> 8;
2521 avio_write(pb, header, 4);
2522 /* write RTP packet data */
2524 avio_write(pb, c->buffer_ptr, len);
2525 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2526 /* prepare asynchronous TCP sending */
2527 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2528 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2529 c->buffer_ptr += len;
2531 /* send everything we can NOW */
2532 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2533 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2535 rtsp_c->packet_buffer_ptr += len;
2536 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2537 /* if we could not send all the data, we will
2538 send it later, so a new state is needed to
2539 "lock" the RTSP TCP connection */
2540 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2543 /* all data has been sent */
2544 av_freep(&c->packet_buffer);
2546 /* send RTP packet directly in UDP */
2548 ffurl_write(c->rtp_handles[c->packet_stream_index],
2549 c->buffer_ptr, len);
2550 c->buffer_ptr += len;
2551 /* here we continue as we can send several packets per 10 ms slot */
2554 /* TCP data output */
2555 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2557 if (ff_neterrno() != AVERROR(EAGAIN) &&
2558 ff_neterrno() != AVERROR(EINTR))
2559 /* error : close connection */
2564 c->buffer_ptr += len;
2566 c->data_count += len;
2567 update_datarate(&c->datarate, c->data_count);
2569 c->stream->bytes_served += len;
2577 static int http_start_receive_data(HTTPContext *c)
2581 if (c->stream->feed_opened)
2584 /* Don't permit writing to this one */
2585 if (c->stream->readonly)
2589 fd = open(c->stream->feed_filename, O_RDWR);
2591 http_log("Error opening feeder file: %s\n", strerror(errno));
2596 if (c->stream->truncate) {
2597 /* truncate feed file */
2598 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2599 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2600 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2601 http_log("Error truncating feed file: %s\n", strerror(errno));
2605 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2606 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2611 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2612 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2613 lseek(fd, 0, SEEK_SET);
2615 /* init buffer input */
2616 c->buffer_ptr = c->buffer;
2617 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2618 c->stream->feed_opened = 1;
2619 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2623 static int http_receive_data(HTTPContext *c)
2626 int len, loop_run = 0;
2628 while (c->chunked_encoding && !c->chunk_size &&
2629 c->buffer_end > c->buffer_ptr) {
2630 /* read chunk header, if present */
2631 len = recv(c->fd, c->buffer_ptr, 1, 0);
2634 if (ff_neterrno() != AVERROR(EAGAIN) &&
2635 ff_neterrno() != AVERROR(EINTR))
2636 /* error : close connection */
2639 } else if (len == 0) {
2640 /* end of connection : close it */
2642 } else if (c->buffer_ptr - c->buffer >= 2 &&
2643 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2644 c->chunk_size = strtol(c->buffer, 0, 16);
2645 if (c->chunk_size == 0) // end of stream
2647 c->buffer_ptr = c->buffer;
2649 } else if (++loop_run > 10) {
2650 /* no chunk header, abort */
2657 if (c->buffer_end > c->buffer_ptr) {
2658 len = recv(c->fd, c->buffer_ptr,
2659 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2661 if (ff_neterrno() != AVERROR(EAGAIN) &&
2662 ff_neterrno() != AVERROR(EINTR))
2663 /* error : close connection */
2665 } else if (len == 0)
2666 /* end of connection : close it */
2669 c->chunk_size -= len;
2670 c->buffer_ptr += len;
2671 c->data_count += len;
2672 update_datarate(&c->datarate, c->data_count);
2676 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2677 if (c->buffer[0] != 'f' ||
2678 c->buffer[1] != 'm') {
2679 http_log("Feed stream has become desynchronized -- disconnecting\n");
2684 if (c->buffer_ptr >= c->buffer_end) {
2685 FFStream *feed = c->stream;
2686 /* a packet has been received : write it in the store, except
2688 if (c->data_count > FFM_PACKET_SIZE) {
2689 /* XXX: use llseek or url_seek */
2690 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2691 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2692 http_log("Error writing to feed file: %s\n", strerror(errno));
2696 feed->feed_write_index += FFM_PACKET_SIZE;
2697 /* update file size */
2698 if (feed->feed_write_index > c->stream->feed_size)
2699 feed->feed_size = feed->feed_write_index;
2701 /* handle wrap around if max file size reached */
2702 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2703 feed->feed_write_index = FFM_PACKET_SIZE;
2706 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2707 http_log("Error writing index to feed file: %s\n", strerror(errno));
2711 /* wake up any waiting connections */
2712 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2713 if (c1->state == HTTPSTATE_WAIT_FEED &&
2714 c1->stream->feed == c->stream->feed)
2715 c1->state = HTTPSTATE_SEND_DATA;
2718 /* We have a header in our hands that contains useful data */
2719 AVFormatContext *s = avformat_alloc_context();
2721 AVInputFormat *fmt_in;
2727 /* use feed output format name to find corresponding input format */
2728 fmt_in = av_find_input_format(feed->fmt->name);
2732 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2733 0, NULL, NULL, NULL, NULL);
2737 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2742 /* Now we have the actual streams */
2743 if (s->nb_streams != feed->nb_streams) {
2744 avformat_close_input(&s);
2746 http_log("Feed '%s' stream number does not match registered feed\n",
2747 c->stream->feed_filename);
2751 for (i = 0; i < s->nb_streams; i++) {
2752 AVStream *fst = feed->streams[i];
2753 AVStream *st = s->streams[i];
2754 avcodec_copy_context(fst->codec, st->codec);
2757 avformat_close_input(&s);
2760 c->buffer_ptr = c->buffer;
2765 c->stream->feed_opened = 0;
2767 /* wake up any waiting connections to stop waiting for feed */
2768 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2769 if (c1->state == HTTPSTATE_WAIT_FEED &&
2770 c1->stream->feed == c->stream->feed)
2771 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2776 /********************************************************************/
2779 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2786 switch(error_number) {
2787 case RTSP_STATUS_OK:
2790 case RTSP_STATUS_METHOD:
2791 str = "Method Not Allowed";
2793 case RTSP_STATUS_BANDWIDTH:
2794 str = "Not Enough Bandwidth";
2796 case RTSP_STATUS_SESSION:
2797 str = "Session Not Found";
2799 case RTSP_STATUS_STATE:
2800 str = "Method Not Valid in This State";
2802 case RTSP_STATUS_AGGREGATE:
2803 str = "Aggregate operation not allowed";
2805 case RTSP_STATUS_ONLY_AGGREGATE:
2806 str = "Only aggregate operation allowed";
2808 case RTSP_STATUS_TRANSPORT:
2809 str = "Unsupported transport";
2811 case RTSP_STATUS_INTERNAL:
2812 str = "Internal Server Error";
2814 case RTSP_STATUS_SERVICE:
2815 str = "Service Unavailable";
2817 case RTSP_STATUS_VERSION:
2818 str = "RTSP Version not supported";
2821 str = "Unknown Error";
2825 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2826 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2828 /* output GMT time */
2831 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2832 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2835 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2837 rtsp_reply_header(c, error_number);
2838 avio_printf(c->pb, "\r\n");
2841 static int rtsp_parse_request(HTTPContext *c)
2843 const char *p, *p1, *p2;
2849 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2851 c->buffer_ptr[0] = '\0';
2854 get_word(cmd, sizeof(cmd), &p);
2855 get_word(url, sizeof(url), &p);
2856 get_word(protocol, sizeof(protocol), &p);
2858 av_strlcpy(c->method, cmd, sizeof(c->method));
2859 av_strlcpy(c->url, url, sizeof(c->url));
2860 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2862 if (avio_open_dyn_buf(&c->pb) < 0) {
2863 /* XXX: cannot do more */
2864 c->pb = NULL; /* safety */
2868 /* check version name */
2869 if (strcmp(protocol, "RTSP/1.0") != 0) {
2870 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2874 /* parse each header line */
2875 /* skip to next line */
2876 while (*p != '\n' && *p != '\0')
2880 while (*p != '\0') {
2881 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2885 if (p2 > p && p2[-1] == '\r')
2887 /* skip empty line */
2891 if (len > sizeof(line) - 1)
2892 len = sizeof(line) - 1;
2893 memcpy(line, p, len);
2895 ff_rtsp_parse_line(header, line, NULL, NULL);
2899 /* handle sequence number */
2900 c->seq = header->seq;
2902 if (!strcmp(cmd, "DESCRIBE"))
2903 rtsp_cmd_describe(c, url);
2904 else if (!strcmp(cmd, "OPTIONS"))
2905 rtsp_cmd_options(c, url);
2906 else if (!strcmp(cmd, "SETUP"))
2907 rtsp_cmd_setup(c, url, header);
2908 else if (!strcmp(cmd, "PLAY"))
2909 rtsp_cmd_play(c, url, header);
2910 else if (!strcmp(cmd, "PAUSE"))
2911 rtsp_cmd_pause(c, url, header);
2912 else if (!strcmp(cmd, "TEARDOWN"))
2913 rtsp_cmd_teardown(c, url, header);
2915 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2918 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2919 c->pb = NULL; /* safety */
2921 /* XXX: cannot do more */
2924 c->buffer_ptr = c->pb_buffer;
2925 c->buffer_end = c->pb_buffer + len;
2926 c->state = RTSPSTATE_SEND_REPLY;
2930 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2931 struct in_addr my_ip)
2933 AVFormatContext *avc;
2934 AVStream *avs = NULL;
2937 avc = avformat_alloc_context();
2941 av_dict_set(&avc->metadata, "title",
2942 stream->title[0] ? stream->title : "No Title", 0);
2943 avc->nb_streams = stream->nb_streams;
2944 if (stream->is_multicast) {
2945 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2946 inet_ntoa(stream->multicast_ip),
2947 stream->multicast_port, stream->multicast_ttl);
2949 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2952 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2953 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2955 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2956 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2959 for(i = 0; i < stream->nb_streams; i++) {
2960 avc->streams[i] = &avs[i];
2961 avc->streams[i]->codec = stream->streams[i]->codec;
2963 *pbuffer = av_mallocz(2048);
2964 av_sdp_create(&avc, 1, *pbuffer, 2048);
2967 av_free(avc->streams);
2968 av_dict_free(&avc->metadata);
2972 return strlen(*pbuffer);
2975 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2977 // rtsp_reply_header(c, RTSP_STATUS_OK);
2978 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2979 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2980 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2981 avio_printf(c->pb, "\r\n");
2984 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2992 struct sockaddr_in my_addr;
2994 /* find which url is asked */
2995 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3000 for(stream = first_stream; stream != NULL; stream = stream->next) {
3001 if (!stream->is_feed &&
3002 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3003 !strcmp(path, stream->filename)) {
3007 /* no stream found */
3008 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3012 /* prepare the media description in sdp format */
3014 /* get the host IP */
3015 len = sizeof(my_addr);
3016 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3017 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3018 if (content_length < 0) {
3019 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3022 rtsp_reply_header(c, RTSP_STATUS_OK);
3023 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3024 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3025 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3026 avio_printf(c->pb, "\r\n");
3027 avio_write(c->pb, content, content_length);
3031 static HTTPContext *find_rtp_session(const char *session_id)
3035 if (session_id[0] == '\0')
3038 for(c = first_http_ctx; c != NULL; c = c->next) {
3039 if (!strcmp(c->session_id, session_id))
3045 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3047 RTSPTransportField *th;
3050 for(i=0;i<h->nb_transports;i++) {
3051 th = &h->transports[i];
3052 if (th->lower_transport == lower_transport)
3058 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3059 RTSPMessageHeader *h)
3062 int stream_index, rtp_port, rtcp_port;
3067 RTSPTransportField *th;
3068 struct sockaddr_in dest_addr;
3069 RTSPActionServerSetup setup;
3071 /* find which url is asked */
3072 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3077 /* now check each stream */
3078 for(stream = first_stream; stream != NULL; stream = stream->next) {
3079 if (!stream->is_feed &&
3080 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3081 /* accept aggregate filenames only if single stream */
3082 if (!strcmp(path, stream->filename)) {
3083 if (stream->nb_streams != 1) {
3084 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3091 for(stream_index = 0; stream_index < stream->nb_streams;
3093 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3094 stream->filename, stream_index);
3095 if (!strcmp(path, buf))
3100 /* no stream found */
3101 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3105 /* generate session id if needed */
3106 if (h->session_id[0] == '\0')
3107 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3108 av_lfg_get(&random_state), av_lfg_get(&random_state));
3110 /* find rtp session, and create it if none found */
3111 rtp_c = find_rtp_session(h->session_id);
3113 /* always prefer UDP */
3114 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3116 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3118 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3123 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3124 th->lower_transport);
3126 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3130 /* open input stream */
3131 if (open_input_stream(rtp_c, "") < 0) {
3132 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3137 /* test if stream is OK (test needed because several SETUP needs
3138 to be done for a given file) */
3139 if (rtp_c->stream != stream) {
3140 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3144 /* test if stream is already set up */
3145 if (rtp_c->rtp_ctx[stream_index]) {
3146 rtsp_reply_error(c, RTSP_STATUS_STATE);
3150 /* check transport */
3151 th = find_transport(h, rtp_c->rtp_protocol);
3152 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3153 th->client_port_min <= 0)) {
3154 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3158 /* setup default options */
3159 setup.transport_option[0] = '\0';
3160 dest_addr = rtp_c->from_addr;
3161 dest_addr.sin_port = htons(th->client_port_min);
3164 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3165 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3169 /* now everything is OK, so we can send the connection parameters */
3170 rtsp_reply_header(c, RTSP_STATUS_OK);
3172 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3174 switch(rtp_c->rtp_protocol) {
3175 case RTSP_LOWER_TRANSPORT_UDP:
3176 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3177 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3178 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3179 "client_port=%d-%d;server_port=%d-%d",
3180 th->client_port_min, th->client_port_max,
3181 rtp_port, rtcp_port);
3183 case RTSP_LOWER_TRANSPORT_TCP:
3184 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3185 stream_index * 2, stream_index * 2 + 1);
3190 if (setup.transport_option[0] != '\0')
3191 avio_printf(c->pb, ";%s", setup.transport_option);
3192 avio_printf(c->pb, "\r\n");
3195 avio_printf(c->pb, "\r\n");
3199 /* find an rtp connection by using the session ID. Check consistency
3201 static HTTPContext *find_rtp_session_with_url(const char *url,
3202 const char *session_id)
3210 rtp_c = find_rtp_session(session_id);
3214 /* find which url is asked */
3215 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3219 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3220 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3221 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3222 rtp_c->stream->filename, s);
3223 if(!strncmp(path, buf, sizeof(buf))) {
3224 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3229 if (len > 0 && path[len - 1] == '/' &&
3230 !strncmp(path, rtp_c->stream->filename, len - 1))
3235 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3239 rtp_c = find_rtp_session_with_url(url, h->session_id);
3241 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3245 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3246 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3247 rtp_c->state != HTTPSTATE_READY) {
3248 rtsp_reply_error(c, RTSP_STATUS_STATE);
3252 rtp_c->state = HTTPSTATE_SEND_DATA;
3254 /* now everything is OK, so we can send the connection parameters */
3255 rtsp_reply_header(c, RTSP_STATUS_OK);
3257 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3258 avio_printf(c->pb, "\r\n");
3261 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3265 rtp_c = find_rtp_session_with_url(url, h->session_id);
3267 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3271 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3272 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3273 rtsp_reply_error(c, RTSP_STATUS_STATE);
3277 rtp_c->state = HTTPSTATE_READY;
3278 rtp_c->first_pts = AV_NOPTS_VALUE;
3279 /* now everything is OK, so we can send the connection parameters */
3280 rtsp_reply_header(c, RTSP_STATUS_OK);
3282 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3283 avio_printf(c->pb, "\r\n");
3286 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3290 rtp_c = find_rtp_session_with_url(url, h->session_id);
3292 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3296 /* now everything is OK, so we can send the connection parameters */
3297 rtsp_reply_header(c, RTSP_STATUS_OK);
3299 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3300 avio_printf(c->pb, "\r\n");
3302 /* abort the session */
3303 close_connection(rtp_c);
3307 /********************************************************************/
3310 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3311 FFStream *stream, const char *session_id,
3312 enum RTSPLowerTransport rtp_protocol)
3314 HTTPContext *c = NULL;
3315 const char *proto_str;
3317 /* XXX: should output a warning page when coming
3318 close to the connection limit */
3319 if (nb_connections >= nb_max_connections)
3322 /* add a new connection */
3323 c = av_mallocz(sizeof(HTTPContext));
3328 c->poll_entry = NULL;
3329 c->from_addr = *from_addr;
3330 c->buffer_size = IOBUFFER_INIT_SIZE;
3331 c->buffer = av_malloc(c->buffer_size);
3336 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3337 c->state = HTTPSTATE_READY;
3338 c->is_packetized = 1;
3339 c->rtp_protocol = rtp_protocol;
3341 /* protocol is shown in statistics */
3342 switch(c->rtp_protocol) {
3343 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3344 proto_str = "MCAST";
3346 case RTSP_LOWER_TRANSPORT_UDP:
3349 case RTSP_LOWER_TRANSPORT_TCP:
3356 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3357 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3359 current_bandwidth += stream->bandwidth;
3361 c->next = first_http_ctx;
3373 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3374 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3376 static int rtp_new_av_stream(HTTPContext *c,
3377 int stream_index, struct sockaddr_in *dest_addr,
3378 HTTPContext *rtsp_c)
3380 AVFormatContext *ctx;
3383 URLContext *h = NULL;
3385 int max_packet_size;
3387 /* now we can open the relevant output stream */
3388 ctx = avformat_alloc_context();
3391 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3393 st = av_mallocz(sizeof(AVStream));
3396 ctx->nb_streams = 1;
3397 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3400 ctx->streams[0] = st;
3402 if (!c->stream->feed ||
3403 c->stream->feed == c->stream)
3404 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3407 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3409 st->priv_data = NULL;
3411 /* build destination RTP address */
3412 ipaddr = inet_ntoa(dest_addr->sin_addr);
3414 switch(c->rtp_protocol) {
3415 case RTSP_LOWER_TRANSPORT_UDP:
3416 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3419 /* XXX: also pass as parameter to function ? */
3420 if (c->stream->is_multicast) {
3422 ttl = c->stream->multicast_ttl;
3425 snprintf(ctx->filename, sizeof(ctx->filename),
3426 "rtp://%s:%d?multicast=1&ttl=%d",
3427 ipaddr, ntohs(dest_addr->sin_port), ttl);
3429 snprintf(ctx->filename, sizeof(ctx->filename),
3430 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3433 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3435 c->rtp_handles[stream_index] = h;
3436 max_packet_size = h->max_packet_size;
3438 case RTSP_LOWER_TRANSPORT_TCP:
3441 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3447 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3448 ipaddr, ntohs(dest_addr->sin_port),
3449 c->stream->filename, stream_index, c->protocol);
3451 /* normally, no packets should be output here, but the packet size may be checked */
3452 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3453 /* XXX: close stream */
3456 if (avformat_write_header(ctx, NULL) < 0) {
3463 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3466 c->rtp_ctx[stream_index] = ctx;
3470 /********************************************************************/
3471 /* avserver initialization */
3473 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3477 fst = av_mallocz(sizeof(AVStream));
3481 fst->codec = avcodec_alloc_context3(NULL);
3482 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3483 if (codec->extradata_size) {
3484 fst->codec->extradata = av_malloc(codec->extradata_size);
3485 memcpy(fst->codec->extradata, codec->extradata,
3486 codec->extradata_size);
3489 /* live streams must use the actual feed's codec since it may be
3490 * updated later to carry extradata needed by the streams.
3494 fst->priv_data = av_mallocz(sizeof(FeedData));
3495 fst->index = stream->nb_streams;
3496 avpriv_set_pts_info(fst, 33, 1, 90000);
3497 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3498 stream->streams[stream->nb_streams++] = fst;
3502 /* return the stream number in the feed */
3503 static int add_av_stream(FFStream *feed, AVStream *st)
3506 AVCodecContext *av, *av1;
3510 for(i=0;i<feed->nb_streams;i++) {
3511 st = feed->streams[i];
3513 if (av1->codec_id == av->codec_id &&
3514 av1->codec_type == av->codec_type &&
3515 av1->bit_rate == av->bit_rate) {
3517 switch(av->codec_type) {
3518 case AVMEDIA_TYPE_AUDIO:
3519 if (av1->channels == av->channels &&
3520 av1->sample_rate == av->sample_rate)
3523 case AVMEDIA_TYPE_VIDEO:
3524 if (av1->width == av->width &&
3525 av1->height == av->height &&
3526 av1->time_base.den == av->time_base.den &&
3527 av1->time_base.num == av->time_base.num &&
3528 av1->gop_size == av->gop_size)
3537 fst = add_av_stream1(feed, av, 0);
3540 return feed->nb_streams - 1;
3543 static void remove_stream(FFStream *stream)
3547 while (*ps != NULL) {
3555 /* specific mpeg4 handling : we extract the raw parameters */
3556 static void extract_mpeg4_header(AVFormatContext *infile)
3558 int mpeg4_count, i, size;
3563 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3566 for(i=0;i<infile->nb_streams;i++) {
3567 st = infile->streams[i];
3568 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3569 st->codec->extradata_size == 0) {
3576 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3577 while (mpeg4_count > 0) {
3578 if (av_read_frame(infile, &pkt) < 0)
3580 st = infile->streams[pkt.stream_index];
3581 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3582 st->codec->extradata_size == 0) {
3583 av_freep(&st->codec->extradata);
3584 /* fill extradata with the header */
3585 /* XXX: we make hard suppositions here ! */
3587 while (p < pkt.data + pkt.size - 4) {
3588 /* stop when vop header is found */
3589 if (p[0] == 0x00 && p[1] == 0x00 &&
3590 p[2] == 0x01 && p[3] == 0xb6) {
3591 size = p - pkt.data;
3592 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3593 st->codec->extradata = av_malloc(size);
3594 st->codec->extradata_size = size;
3595 memcpy(st->codec->extradata, pkt.data, size);
3602 av_free_packet(&pkt);
3606 /* compute the needed AVStream for each file */
3607 static void build_file_streams(void)
3609 FFStream *stream, *stream_next;
3612 /* gather all streams */
3613 for(stream = first_stream; stream != NULL; stream = stream_next) {
3614 AVFormatContext *infile = NULL;
3615 stream_next = stream->next;
3616 if (stream->stream_type == STREAM_TYPE_LIVE &&
3618 /* the stream comes from a file */
3619 /* try to open the file */
3621 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3622 /* specific case : if transport stream output to RTP,
3623 we use a raw transport stream reader */
3624 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3627 http_log("Opening file '%s'\n", stream->feed_filename);
3628 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3629 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3630 /* remove stream (no need to spend more time on it) */
3632 remove_stream(stream);
3634 /* find all the AVStreams inside and reference them in
3636 if (avformat_find_stream_info(infile, NULL) < 0) {
3637 http_log("Could not find codec parameters from '%s'\n",
3638 stream->feed_filename);
3639 avformat_close_input(&infile);
3642 extract_mpeg4_header(infile);
3644 for(i=0;i<infile->nb_streams;i++)
3645 add_av_stream1(stream, infile->streams[i]->codec, 1);
3647 avformat_close_input(&infile);
3653 /* compute the needed AVStream for each feed */
3654 static void build_feed_streams(void)
3656 FFStream *stream, *feed;
3659 /* gather all streams */
3660 for(stream = first_stream; stream != NULL; stream = stream->next) {
3661 feed = stream->feed;
3663 if (stream->is_feed) {
3664 for(i=0;i<stream->nb_streams;i++)
3665 stream->feed_streams[i] = i;
3667 /* we handle a stream coming from a feed */
3668 for(i=0;i<stream->nb_streams;i++)
3669 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3674 /* create feed files if needed */
3675 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3678 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3679 /* See if it matches */
3680 AVFormatContext *s = NULL;
3683 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3684 /* Now see if it matches */
3685 if (s->nb_streams == feed->nb_streams) {
3687 for(i=0;i<s->nb_streams;i++) {
3689 sf = feed->streams[i];
3692 if (sf->index != ss->index ||
3694 http_log("Index & Id do not match for stream %d (%s)\n",
3695 i, feed->feed_filename);
3698 AVCodecContext *ccf, *ccs;
3702 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3704 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3705 http_log("Codecs do not match for stream %d\n", i);
3707 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3708 http_log("Codec bitrates do not match for stream %d\n", i);
3710 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3711 if (CHECK_CODEC(time_base.den) ||
3712 CHECK_CODEC(time_base.num) ||
3713 CHECK_CODEC(width) ||
3714 CHECK_CODEC(height)) {
3715 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3718 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3719 if (CHECK_CODEC(sample_rate) ||
3720 CHECK_CODEC(channels) ||
3721 CHECK_CODEC(frame_size)) {
3722 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3726 http_log("Unknown codec type\n");
3734 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3735 feed->feed_filename, s->nb_streams, feed->nb_streams);
3737 avformat_close_input(&s);
3739 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3740 feed->feed_filename);
3743 if (feed->readonly) {
3744 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3745 feed->feed_filename);
3748 unlink(feed->feed_filename);
3751 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3752 AVFormatContext s1 = {0}, *s = &s1;
3754 if (feed->readonly) {
3755 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3756 feed->feed_filename);
3760 /* only write the header of the ffm file */
3761 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3762 http_log("Could not open output feed file '%s'\n",
3763 feed->feed_filename);
3766 s->oformat = feed->fmt;
3767 s->nb_streams = feed->nb_streams;
3768 s->streams = feed->streams;
3769 if (avformat_write_header(s, NULL) < 0) {
3770 http_log("Container doesn't supports the required parameters\n");
3773 /* XXX: need better api */
3774 av_freep(&s->priv_data);
3777 /* get feed size and write index */
3778 fd = open(feed->feed_filename, O_RDONLY);
3780 http_log("Could not open output feed file '%s'\n",
3781 feed->feed_filename);
3785 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3786 feed->feed_size = lseek(fd, 0, SEEK_END);
3787 /* ensure that we do not wrap before the end of file */
3788 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3789 feed->feed_max_size = feed->feed_size;
3795 /* compute the bandwidth used by each stream */
3796 static void compute_bandwidth(void)
3802 for(stream = first_stream; stream != NULL; stream = stream->next) {
3804 for(i=0;i<stream->nb_streams;i++) {
3805 AVStream *st = stream->streams[i];
3806 switch(st->codec->codec_type) {
3807 case AVMEDIA_TYPE_AUDIO:
3808 case AVMEDIA_TYPE_VIDEO:
3809 bandwidth += st->codec->bit_rate;
3815 stream->bandwidth = (bandwidth + 999) / 1000;
3819 /* add a codec and set the default parameters */
3820 static void add_codec(FFStream *stream, AVCodecContext *av)
3824 /* compute default parameters */
3825 switch(av->codec_type) {
3826 case AVMEDIA_TYPE_AUDIO:
3827 if (av->bit_rate == 0)
3828 av->bit_rate = 64000;
3829 if (av->sample_rate == 0)
3830 av->sample_rate = 22050;
3831 if (av->channels == 0)
3834 case AVMEDIA_TYPE_VIDEO:
3835 if (av->bit_rate == 0)
3836 av->bit_rate = 64000;
3837 if (av->time_base.num == 0){
3838 av->time_base.den = 5;
3839 av->time_base.num = 1;
3841 if (av->width == 0 || av->height == 0) {
3845 /* Bitrate tolerance is less for streaming */
3846 if (av->bit_rate_tolerance == 0)
3847 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3848 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3853 if (av->max_qdiff == 0)
3855 av->qcompress = 0.5;
3858 if (!av->nsse_weight)
3859 av->nsse_weight = 8;
3861 av->frame_skip_cmp = FF_CMP_DCTMAX;
3863 av->me_method = ME_EPZS;
3864 av->rc_buffer_aggressivity = 1.0;
3867 av->rc_eq = "tex^qComp";
3868 if (!av->i_quant_factor)
3869 av->i_quant_factor = -0.8;
3870 if (!av->b_quant_factor)
3871 av->b_quant_factor = 1.25;
3872 if (!av->b_quant_offset)
3873 av->b_quant_offset = 1.25;
3874 if (!av->rc_max_rate)
3875 av->rc_max_rate = av->bit_rate * 2;
3877 if (av->rc_max_rate && !av->rc_buffer_size) {
3878 av->rc_buffer_size = av->rc_max_rate;
3887 st = av_mallocz(sizeof(AVStream));
3890 st->codec = avcodec_alloc_context3(NULL);
3891 stream->streams[stream->nb_streams++] = st;
3892 memcpy(st->codec, av, sizeof(AVCodecContext));
3895 static enum AVCodecID opt_audio_codec(const char *arg)
3897 AVCodec *p= avcodec_find_encoder_by_name(arg);
3899 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3900 return AV_CODEC_ID_NONE;
3905 static enum AVCodecID opt_video_codec(const char *arg)
3907 AVCodec *p= avcodec_find_encoder_by_name(arg);
3909 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3910 return AV_CODEC_ID_NONE;
3915 static int avserver_opt_default(const char *opt, const char *arg,
3916 AVCodecContext *avctx, int type)
3919 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3921 ret = av_opt_set(avctx, opt, arg, 0);
3925 static int avserver_opt_preset(const char *arg,
3926 AVCodecContext *avctx, int type,
3927 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3930 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3932 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3934 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3935 codec ? codec->name : NULL))) {
3936 fprintf(stderr, "File for preset '%s' not found\n", arg);
3941 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3942 if(line[0] == '#' && !e)
3944 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3946 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3950 if(!strcmp(tmp, "acodec")){
3951 *audio_id = opt_audio_codec(tmp2);
3952 }else if(!strcmp(tmp, "vcodec")){
3953 *video_id = opt_video_codec(tmp2);
3954 }else if(!strcmp(tmp, "scodec")){
3955 /* opt_subtitle_codec(tmp2); */
3956 }else if(avserver_opt_default(tmp, tmp2, avctx, type) < 0){
3957 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3968 static AVOutputFormat *avserver_guess_format(const char *short_name, const char *filename,
3969 const char *mime_type)
3971 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3974 AVOutputFormat *stream_fmt;
3975 char stream_format_name[64];
3977 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3978 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
3987 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
3991 fprintf(stderr, "%s:%d: ", filename, line_num);
3992 vfprintf(stderr, fmt, vl);
3998 static int parse_ffconfig(const char *filename)
4005 int val, errors, line_num;
4006 FFStream **last_stream, *stream, *redirect;
4007 FFStream **last_feed, *feed, *s;
4008 AVCodecContext audio_enc, video_enc;
4009 enum AVCodecID audio_id, video_id;
4011 f = fopen(filename, "r");
4019 first_stream = NULL;
4020 last_stream = &first_stream;
4022 last_feed = &first_feed;
4026 audio_id = AV_CODEC_ID_NONE;
4027 video_id = AV_CODEC_ID_NONE;
4029 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4031 if (fgets(line, sizeof(line), f) == NULL)
4035 while (av_isspace(*p))
4037 if (*p == '\0' || *p == '#')
4040 get_arg(cmd, sizeof(cmd), &p);
4042 if (!av_strcasecmp(cmd, "Port")) {
4043 get_arg(arg, sizeof(arg), &p);
4045 if (val < 1 || val > 65536) {
4046 ERROR("Invalid_port: %s\n", arg);
4048 my_http_addr.sin_port = htons(val);
4049 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4050 get_arg(arg, sizeof(arg), &p);
4051 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4052 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4054 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4055 get_arg(arg, sizeof(arg), &p);
4057 if (val < 1 || val > 65536) {
4058 ERROR("%s:%d: Invalid port: %s\n", arg);
4060 my_rtsp_addr.sin_port = htons(atoi(arg));
4061 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4062 get_arg(arg, sizeof(arg), &p);
4063 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4064 ERROR("Invalid host/IP address: %s\n", arg);
4066 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4067 get_arg(arg, sizeof(arg), &p);
4069 if (val < 1 || val > 65536) {
4070 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4072 nb_max_http_connections = val;
4073 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4074 get_arg(arg, sizeof(arg), &p);
4076 if (val < 1 || val > nb_max_http_connections) {
4077 ERROR("Invalid MaxClients: %s\n", arg);
4079 nb_max_connections = val;
4081 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4083 get_arg(arg, sizeof(arg), &p);
4085 if (llval < 10 || llval > 10000000) {
4086 ERROR("Invalid MaxBandwidth: %s\n", arg);
4088 max_bandwidth = llval;
4089 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4090 if (!avserver_debug)
4091 get_arg(logfilename, sizeof(logfilename), &p);
4092 } else if (!av_strcasecmp(cmd, "<Feed")) {
4093 /*********************************************/
4094 /* Feed related options */
4096 if (stream || feed) {
4097 ERROR("Already in a tag\n");
4099 feed = av_mallocz(sizeof(FFStream));
4100 get_arg(feed->filename, sizeof(feed->filename), &p);
4101 q = strrchr(feed->filename, '>');
4105 for (s = first_feed; s; s = s->next) {
4106 if (!strcmp(feed->filename, s->filename)) {
4107 ERROR("Feed '%s' already registered\n", s->filename);
4111 feed->fmt = av_guess_format("ffm", NULL, NULL);
4112 /* defaut feed file */
4113 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4114 "/tmp/%s.ffm", feed->filename);
4115 feed->feed_max_size = 5 * 1024 * 1024;
4117 feed->feed = feed; /* self feeding :-) */
4119 /* add in stream list */
4120 *last_stream = feed;
4121 last_stream = &feed->next;
4122 /* add in feed list */
4124 last_feed = &feed->next_feed;
4126 } else if (!av_strcasecmp(cmd, "Launch")) {
4130 feed->child_argv = av_mallocz(64 * sizeof(char *));
4132 for (i = 0; i < 62; i++) {
4133 get_arg(arg, sizeof(arg), &p);
4137 feed->child_argv[i] = av_strdup(arg);
4140 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4142 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4144 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4145 inet_ntoa(my_http_addr.sin_addr),
4146 ntohs(my_http_addr.sin_port), feed->filename);
4148 } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
4150 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4152 } else if (stream) {
4153 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4155 } else if (!av_strcasecmp(cmd, "File")) {
4157 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4159 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4160 } else if (!av_strcasecmp(cmd, "Truncate")) {
4162 get_arg(arg, sizeof(arg), &p);
4163 feed->truncate = strtod(arg, NULL);
4165 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4170 get_arg(arg, sizeof(arg), &p);
4172 fsize = strtod(p1, &p1);
4173 switch(av_toupper(*p1)) {
4178 fsize *= 1024 * 1024;
4181 fsize *= 1024 * 1024 * 1024;
4184 feed->feed_max_size = (int64_t)fsize;
4185 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4186 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4189 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4191 ERROR("No corresponding <Feed> for </Feed>\n");
4194 } else if (!av_strcasecmp(cmd, "<Stream")) {
4195 /*********************************************/
4196 /* Stream related options */
4198 if (stream || feed) {
4199 ERROR("Already in a tag\n");
4202 stream = av_mallocz(sizeof(FFStream));
4203 get_arg(stream->filename, sizeof(stream->filename), &p);
4204 q = strrchr(stream->filename, '>');
4208 for (s = first_stream; s; s = s->next) {
4209 if (!strcmp(stream->filename, s->filename)) {
4210 ERROR("Stream '%s' already registered\n", s->filename);
4214 stream->fmt = avserver_guess_format(NULL, stream->filename, NULL);
4215 avcodec_get_context_defaults3(&video_enc, NULL);
4216 avcodec_get_context_defaults3(&audio_enc, NULL);
4217 audio_id = AV_CODEC_ID_NONE;
4218 video_id = AV_CODEC_ID_NONE;
4220 audio_id = stream->fmt->audio_codec;
4221 video_id = stream->fmt->video_codec;
4224 *last_stream = stream;
4225 last_stream = &stream->next;
4227 } else if (!av_strcasecmp(cmd, "Feed")) {
4228 get_arg(arg, sizeof(arg), &p);
4233 while (sfeed != NULL) {
4234 if (!strcmp(sfeed->filename, arg))
4236 sfeed = sfeed->next_feed;
4239 ERROR("feed '%s' not defined\n", arg);
4241 stream->feed = sfeed;
4243 } else if (!av_strcasecmp(cmd, "Format")) {
4244 get_arg(arg, sizeof(arg), &p);
4246 if (!strcmp(arg, "status")) {
4247 stream->stream_type = STREAM_TYPE_STATUS;
4250 stream->stream_type = STREAM_TYPE_LIVE;
4251 /* jpeg cannot be used here, so use single frame jpeg */
4252 if (!strcmp(arg, "jpeg"))
4253 strcpy(arg, "mjpeg");
4254 stream->fmt = avserver_guess_format(arg, NULL, NULL);
4256 ERROR("Unknown Format: %s\n", arg);
4260 audio_id = stream->fmt->audio_codec;
4261 video_id = stream->fmt->video_codec;
4264 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4265 get_arg(arg, sizeof(arg), &p);
4267 stream->ifmt = av_find_input_format(arg);
4268 if (!stream->ifmt) {
4269 ERROR("Unknown input format: %s\n", arg);
4272 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4273 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4274 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4276 ERROR("FaviconURL only permitted for status streams\n");
4278 } else if (!av_strcasecmp(cmd, "Author")) {
4280 get_arg(stream->author, sizeof(stream->author), &p);
4281 } else if (!av_strcasecmp(cmd, "Comment")) {
4283 get_arg(stream->comment, sizeof(stream->comment), &p);
4284 } else if (!av_strcasecmp(cmd, "Copyright")) {
4286 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4287 } else if (!av_strcasecmp(cmd, "Title")) {
4289 get_arg(stream->title, sizeof(stream->title), &p);
4290 } else if (!av_strcasecmp(cmd, "Preroll")) {
4291 get_arg(arg, sizeof(arg), &p);
4293 stream->prebuffer = atof(arg) * 1000;
4294 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4296 stream->send_on_key = 1;
4297 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4298 get_arg(arg, sizeof(arg), &p);
4299 audio_id = opt_audio_codec(arg);
4300 if (audio_id == AV_CODEC_ID_NONE) {
4301 ERROR("Unknown AudioCodec: %s\n", arg);
4303 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4304 get_arg(arg, sizeof(arg), &p);
4305 video_id = opt_video_codec(arg);
4306 if (video_id == AV_CODEC_ID_NONE) {
4307 ERROR("Unknown VideoCodec: %s\n", arg);
4309 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4310 get_arg(arg, sizeof(arg), &p);
4312 stream->max_time = atof(arg) * 1000;
4313 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4314 get_arg(arg, sizeof(arg), &p);
4316 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4317 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4318 get_arg(arg, sizeof(arg), &p);
4320 audio_enc.channels = atoi(arg);
4321 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4322 get_arg(arg, sizeof(arg), &p);
4324 audio_enc.sample_rate = atoi(arg);
4325 } else if (!av_strcasecmp(cmd, "AudioQuality")) {
4326 get_arg(arg, sizeof(arg), &p);
4328 // audio_enc.quality = atof(arg) * 1000;
4330 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4332 int minrate, maxrate;
4334 get_arg(arg, sizeof(arg), &p);
4336 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4337 video_enc.rc_min_rate = minrate * 1000;
4338 video_enc.rc_max_rate = maxrate * 1000;
4340 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4343 } else if (!av_strcasecmp(cmd, "Debug")) {
4345 get_arg(arg, sizeof(arg), &p);
4346 video_enc.debug = strtol(arg,0,0);
4348 } else if (!av_strcasecmp(cmd, "Strict")) {
4350 get_arg(arg, sizeof(arg), &p);
4351 video_enc.strict_std_compliance = atoi(arg);
4353 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4355 get_arg(arg, sizeof(arg), &p);
4356 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4358 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4360 get_arg(arg, sizeof(arg), &p);
4361 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4363 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4364 get_arg(arg, sizeof(arg), &p);
4366 video_enc.bit_rate = atoi(arg) * 1000;
4368 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4369 get_arg(arg, sizeof(arg), &p);
4371 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4372 if ((video_enc.width % 16) != 0 ||
4373 (video_enc.height % 16) != 0) {
4374 ERROR("Image size must be a multiple of 16\n");
4377 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4378 get_arg(arg, sizeof(arg), &p);
4380 AVRational frame_rate;
4381 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4382 ERROR("Incorrect frame rate: %s\n", arg);
4384 video_enc.time_base.num = frame_rate.den;
4385 video_enc.time_base.den = frame_rate.num;
4388 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4389 get_arg(arg, sizeof(arg), &p);
4391 video_enc.gop_size = atoi(arg);
4392 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4394 video_enc.gop_size = 1;
4395 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4397 video_enc.mb_decision = FF_MB_DECISION_BITS;
4398 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4400 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4401 video_enc.flags |= CODEC_FLAG_4MV;
4403 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4404 !av_strcasecmp(cmd, "AVOptionAudio")) {
4406 AVCodecContext *avctx;
4408 get_arg(arg, sizeof(arg), &p);
4409 get_arg(arg2, sizeof(arg2), &p);
4410 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4412 type = AV_OPT_FLAG_VIDEO_PARAM;
4415 type = AV_OPT_FLAG_AUDIO_PARAM;
4417 if (avserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4418 ERROR("AVOption error: %s %s\n", arg, arg2);
4420 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4421 !av_strcasecmp(cmd, "AVPresetAudio")) {
4422 AVCodecContext *avctx;
4424 get_arg(arg, sizeof(arg), &p);
4425 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4427 video_enc.codec_id = video_id;
4428 type = AV_OPT_FLAG_VIDEO_PARAM;
4431 audio_enc.codec_id = audio_id;
4432 type = AV_OPT_FLAG_AUDIO_PARAM;
4434 if (avserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4435 ERROR("AVPreset error: %s\n", arg);
4437 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4438 get_arg(arg, sizeof(arg), &p);
4439 if ((strlen(arg) == 4) && stream)
4440 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4441 } else if (!av_strcasecmp(cmd, "BitExact")) {
4443 video_enc.flags |= CODEC_FLAG_BITEXACT;
4444 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4446 video_enc.dct_algo = FF_DCT_FASTINT;
4447 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4449 video_enc.idct_algo = FF_IDCT_SIMPLE;
4450 } else if (!av_strcasecmp(cmd, "Qscale")) {
4451 get_arg(arg, sizeof(arg), &p);
4453 video_enc.flags |= CODEC_FLAG_QSCALE;
4454 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4456 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4457 get_arg(arg, sizeof(arg), &p);
4459 video_enc.max_qdiff = atoi(arg);
4460 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4461 ERROR("VideoQDiff out of range\n");
4464 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4465 get_arg(arg, sizeof(arg), &p);
4467 video_enc.qmax = atoi(arg);
4468 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4469 ERROR("VideoQMax out of range\n");
4472 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4473 get_arg(arg, sizeof(arg), &p);
4475 video_enc.qmin = atoi(arg);
4476 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4477 ERROR("VideoQMin out of range\n");
4480 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4481 get_arg(arg, sizeof(arg), &p);
4483 video_enc.lumi_masking = atof(arg);
4484 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4485 get_arg(arg, sizeof(arg), &p);
4487 video_enc.dark_masking = atof(arg);
4488 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4489 video_id = AV_CODEC_ID_NONE;
4490 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4491 audio_id = AV_CODEC_ID_NONE;
4492 } else if (!av_strcasecmp(cmd, "ACL")) {
4493 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4494 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4496 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4498 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4499 get_arg(arg, sizeof(arg), &p);
4501 av_freep(&stream->rtsp_option);
4502 stream->rtsp_option = av_strdup(arg);
4504 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4505 get_arg(arg, sizeof(arg), &p);
4507 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4508 ERROR("Invalid host/IP address: %s\n", arg);
4510 stream->is_multicast = 1;
4511 stream->loop = 1; /* default is looping */
4513 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4514 get_arg(arg, sizeof(arg), &p);
4516 stream->multicast_port = atoi(arg);
4517 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4518 get_arg(arg, sizeof(arg), &p);
4520 stream->multicast_ttl = atoi(arg);
4521 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4524 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4526 ERROR("No corresponding <Stream> for </Stream>\n");
4528 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4529 if (audio_id != AV_CODEC_ID_NONE) {
4530 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4531 audio_enc.codec_id = audio_id;
4532 add_codec(stream, &audio_enc);
4534 if (video_id != AV_CODEC_ID_NONE) {
4535 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4536 video_enc.codec_id = video_id;
4537 add_codec(stream, &video_enc);
4542 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4543 /*********************************************/
4545 if (stream || feed || redirect) {
4546 ERROR("Already in a tag\n");
4548 redirect = av_mallocz(sizeof(FFStream));
4549 *last_stream = redirect;
4550 last_stream = &redirect->next;
4552 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4553 q = strrchr(redirect->filename, '>');
4556 redirect->stream_type = STREAM_TYPE_REDIRECT;
4558 } else if (!av_strcasecmp(cmd, "URL")) {
4560 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4561 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4563 ERROR("No corresponding <Redirect> for </Redirect>\n");
4565 if (!redirect->feed_filename[0]) {
4566 ERROR("No URL found for <Redirect>\n");
4570 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4571 ERROR("Loadable modules no longer supported\n");
4573 ERROR("Incorrect keyword: '%s'\n", cmd);
4585 static void handle_child_exit(int sig)
4590 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4593 for (feed = first_feed; feed; feed = feed->next) {
4594 if (feed->pid == pid) {
4595 int uptime = time(0) - feed->pid_start;
4598 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4601 /* Turn off any more restarts */
4602 feed->child_argv = 0;
4607 need_to_start_children = 1;
4610 static void opt_debug(void)
4613 logfilename[0] = '-';
4616 void show_help_default(const char *opt, const char *arg)
4618 printf("usage: avserver [options]\n"
4619 "Hyper fast multi format Audio/Video streaming server\n");
4621 show_help_options(options, "Main options:", 0, 0, 0);
4624 static const OptionDef options[] = {
4625 #include "cmdutils_common_opts.h"
4626 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4627 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4628 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/avserver.conf", "configfile" },
4632 int main(int argc, char **argv)
4634 struct sigaction sigact = { { 0 } };
4636 config_filename = av_strdup("/etc/avserver.conf");
4638 parse_loglevel(argc, argv, options);
4640 avformat_network_init();
4644 my_program_name = argv[0];
4646 parse_options(NULL, argc, argv, options, NULL);
4648 unsetenv("http_proxy"); /* Kill the http_proxy */
4650 av_lfg_init(&random_state, av_get_random_seed());
4652 sigact.sa_handler = handle_child_exit;
4653 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4654 sigaction(SIGCHLD, &sigact, 0);
4656 if (parse_ffconfig(config_filename) < 0) {
4657 fprintf(stderr, "Incorrect config file - exiting.\n");
4661 /* open log file if needed */
4662 if (logfilename[0] != '\0') {
4663 if (!strcmp(logfilename, "-"))
4666 logfile = fopen(logfilename, "a");
4667 av_log_set_callback(http_av_log);
4670 build_file_streams();
4672 build_feed_streams();
4674 compute_bandwidth();
4677 signal(SIGPIPE, SIG_IGN);
4679 if (http_server() < 0) {
4680 http_log("Could not start server\n");