2 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * multiple format streaming server based on the FFmpeg libraries
28 #define closesocket close
33 #include "libavformat/avformat.h"
34 // FIXME those are internal headers, ffserver _really_ shouldn't use them
35 #include "libavformat/ffm.h"
36 #include "libavformat/network.h"
37 #include "libavformat/os_support.h"
38 #include "libavformat/rtpdec.h"
39 #include "libavformat/rtpproto.h"
40 #include "libavformat/rtsp.h"
41 #include "libavformat/rtspcodes.h"
42 #include "libavformat/avio_internal.h"
43 #include "libavformat/internal.h"
44 #include "libavformat/url.h"
46 #include "libavutil/avassert.h"
47 #include "libavutil/avstring.h"
48 #include "libavutil/lfg.h"
49 #include "libavutil/dict.h"
50 #include "libavutil/intreadwrite.h"
51 #include "libavutil/mathematics.h"
52 #include "libavutil/pixdesc.h"
53 #include "libavutil/random_seed.h"
54 #include "libavutil/parseutils.h"
55 #include "libavutil/opt.h"
56 #include "libavutil/time.h"
61 #include <sys/ioctl.h>
72 const char program_name[] = "ffserver";
73 const int program_birth_year = 2000;
75 static const OptionDef options[];
78 HTTPSTATE_WAIT_REQUEST,
79 HTTPSTATE_SEND_HEADER,
80 HTTPSTATE_SEND_DATA_HEADER,
81 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
82 HTTPSTATE_SEND_DATA_TRAILER,
83 HTTPSTATE_RECEIVE_DATA,
84 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
87 RTSPSTATE_WAIT_REQUEST,
89 RTSPSTATE_SEND_PACKET,
92 static const char *http_state[] = {
108 #define MAX_STREAMS 20
110 #define IOBUFFER_INIT_SIZE 8192
112 /* timeouts are in ms */
113 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
114 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
116 #define SYNC_TIMEOUT (10 * 1000)
118 typedef struct RTSPActionServerSetup {
120 char transport_option[512];
121 } RTSPActionServerSetup;
124 int64_t count1, count2;
125 int64_t time1, time2;
128 /* context associated with one connection */
129 typedef struct HTTPContext {
130 enum HTTPState state;
131 int fd; /* socket file descriptor */
132 struct sockaddr_in from_addr; /* origin */
133 struct pollfd *poll_entry; /* used when polling */
135 uint8_t *buffer_ptr, *buffer_end;
138 int chunked_encoding;
139 int chunk_size; /* 0 if it needs to be read */
140 struct HTTPContext *next;
141 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
145 /* input format handling */
146 AVFormatContext *fmt_in;
147 int64_t start_time; /* In milliseconds - this wraps fairly often */
148 int64_t first_pts; /* initial pts value */
149 int64_t cur_pts; /* current pts value from the stream in us */
150 int64_t cur_frame_duration; /* duration of the current frame in us */
151 int cur_frame_bytes; /* output frame size, needed to compute
152 the time at which we send each
154 int pts_stream_index; /* stream we choose as clock reference */
155 int64_t cur_clock; /* current clock reference value in us */
156 /* output format handling */
157 struct FFStream *stream;
158 /* -1 is invalid stream */
159 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
160 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
162 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
163 int last_packet_sent; /* true if last data packet was sent */
165 DataRateData datarate;
172 int is_packetized; /* if true, the stream is packetized */
173 int packet_stream_index; /* current stream for output in state machine */
175 /* RTSP state specific */
176 uint8_t *pb_buffer; /* XXX: use that in all the code */
178 int seq; /* RTSP sequence number */
180 /* RTP state specific */
181 enum RTSPLowerTransport rtp_protocol;
182 char session_id[32]; /* session id */
183 AVFormatContext *rtp_ctx[MAX_STREAMS];
185 /* RTP/UDP specific */
186 URLContext *rtp_handles[MAX_STREAMS];
188 /* RTP/TCP specific */
189 struct HTTPContext *rtsp_c;
190 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
193 /* each generated stream is described here */
197 STREAM_TYPE_REDIRECT,
200 enum IPAddressAction {
205 typedef struct IPAddressACL {
206 struct IPAddressACL *next;
207 enum IPAddressAction action;
208 /* These are in host order */
209 struct in_addr first;
213 /* description of each stream of the ffserver.conf file */
214 typedef struct FFStream {
215 enum StreamType stream_type;
216 char filename[1024]; /* stream filename */
217 struct FFStream *feed; /* feed we are using (can be null if
219 AVDictionary *in_opts; /* input parameters */
220 AVDictionary *metadata; /* metadata to set on the stream */
221 AVInputFormat *ifmt; /* if non NULL, force input format */
224 char dynamic_acl[1024];
226 int prebuffer; /* Number of milliseconds early to start */
227 int64_t max_time; /* Number of milliseconds to run */
229 AVStream *streams[MAX_STREAMS];
230 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
231 char feed_filename[1024]; /* file name of the feed storage, or
232 input file name for a stream */
233 pid_t pid; /* Of ffmpeg process */
234 time_t pid_start; /* Of ffmpeg process */
236 struct FFStream *next;
237 unsigned bandwidth; /* bandwidth, in kbits/s */
240 /* multicast specific */
242 struct in_addr multicast_ip;
243 int multicast_port; /* first port used for multicast */
245 int loop; /* if true, send the stream in loops (only meaningful if file) */
248 int feed_opened; /* true if someone is writing to the feed */
249 int is_feed; /* true if it is a feed */
250 int readonly; /* True if writing is prohibited to the file */
251 int truncate; /* True if feeder connection truncate the feed file */
253 int64_t bytes_served;
254 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
255 int64_t feed_write_index; /* current write position in feed (it wraps around) */
256 int64_t feed_size; /* current size of feed */
257 struct FFStream *next_feed;
260 typedef struct FeedData {
261 long long data_count;
262 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
265 static struct sockaddr_in my_http_addr;
266 static struct sockaddr_in my_rtsp_addr;
268 static char logfilename[1024];
269 static HTTPContext *first_http_ctx;
270 static FFStream *first_feed; /* contains only feeds */
271 static FFStream *first_stream; /* contains all streams, including feeds */
273 static void new_connection(int server_fd, int is_rtsp);
274 static void close_connection(HTTPContext *c);
277 static int handle_connection(HTTPContext *c);
278 static int http_parse_request(HTTPContext *c);
279 static int http_send_data(HTTPContext *c);
280 static void compute_status(HTTPContext *c);
281 static int open_input_stream(HTTPContext *c, const char *info);
282 static int http_start_receive_data(HTTPContext *c);
283 static int http_receive_data(HTTPContext *c);
286 static int rtsp_parse_request(HTTPContext *c);
287 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
288 static void rtsp_cmd_options(HTTPContext *c, const char *url);
289 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
290 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
291 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only);
294 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
295 struct in_addr my_ip);
298 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
299 FFStream *stream, const char *session_id,
300 enum RTSPLowerTransport rtp_protocol);
301 static int rtp_new_av_stream(HTTPContext *c,
302 int stream_index, struct sockaddr_in *dest_addr,
303 HTTPContext *rtsp_c);
305 static const char *my_program_name;
307 static const char *config_filename;
309 static int ffserver_debug;
310 static int no_launch;
311 static int need_to_start_children;
313 /* maximum number of simultaneous HTTP connections */
314 static unsigned int nb_max_http_connections = 2000;
315 static unsigned int nb_max_connections = 5;
316 static unsigned int nb_connections;
318 static uint64_t max_bandwidth = 1000;
319 static uint64_t current_bandwidth;
321 static int64_t cur_time; // Making this global saves on passing it around everywhere
323 static AVLFG random_state;
325 static FILE *logfile = NULL;
327 static void htmlstrip(char *s) {
329 s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
335 static int64_t ffm_read_write_index(int fd)
339 if (lseek(fd, 8, SEEK_SET) < 0)
341 if (read(fd, buf, 8) != 8)
346 static int ffm_write_write_index(int fd, int64_t pos)
352 buf[i] = (pos >> (56 - i * 8)) & 0xff;
353 if (lseek(fd, 8, SEEK_SET) < 0)
355 if (write(fd, buf, 8) != 8)
360 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
363 FFMContext *ffm = s->priv_data;
364 ffm->write_index = pos;
365 ffm->file_size = file_size;
368 /* FIXME: make ffserver work with IPv6 */
369 /* resolve host with also IP address parsing */
370 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
373 if (!ff_inet_aton(hostname, sin_addr)) {
375 struct addrinfo *ai, *cur;
376 struct addrinfo hints = { 0 };
377 hints.ai_family = AF_INET;
378 if (getaddrinfo(hostname, NULL, &hints, &ai))
380 /* getaddrinfo returns a linked list of addrinfo structs.
381 * Even if we set ai_family = AF_INET above, make sure
382 * that the returned one actually is of the correct type. */
383 for (cur = ai; cur; cur = cur->ai_next) {
384 if (cur->ai_family == AF_INET) {
385 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
394 hp = gethostbyname(hostname);
397 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
403 static char *ctime1(char *buf2, int buf_size)
410 av_strlcpy(buf2, p, buf_size);
411 p = buf2 + strlen(p) - 1;
417 static void http_vlog(const char *fmt, va_list vargs)
419 static int print_prefix = 1;
423 ctime1(buf, sizeof(buf));
424 fprintf(logfile, "%s ", buf);
426 print_prefix = strstr(fmt, "\n") != NULL;
427 vfprintf(logfile, fmt, vargs);
433 __attribute__ ((format (printf, 1, 2)))
435 static void http_log(const char *fmt, ...)
438 va_start(vargs, fmt);
439 http_vlog(fmt, vargs);
443 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
445 static int print_prefix = 1;
446 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
447 if (level > av_log_get_level())
449 if (print_prefix && avc)
450 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
451 print_prefix = strstr(fmt, "\n") != NULL;
452 http_vlog(fmt, vargs);
455 static void log_connection(HTTPContext *c)
460 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
461 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
462 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
465 static void update_datarate(DataRateData *drd, int64_t count)
467 if (!drd->time1 && !drd->count1) {
468 drd->time1 = drd->time2 = cur_time;
469 drd->count1 = drd->count2 = count;
470 } else if (cur_time - drd->time2 > 5000) {
471 drd->time1 = drd->time2;
472 drd->count1 = drd->count2;
473 drd->time2 = cur_time;
478 /* In bytes per second */
479 static int compute_datarate(DataRateData *drd, int64_t count)
481 if (cur_time == drd->time1)
484 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
488 static void start_children(FFStream *feed)
493 for (; feed; feed = feed->next) {
494 if (feed->child_argv && !feed->pid) {
495 feed->pid_start = time(0);
500 http_log("Unable to create children\n");
509 /* replace "ffserver" with "ffmpeg" in the path of current
510 * program. Ignore user provided path */
511 av_strlcpy(pathname, my_program_name, sizeof(pathname));
512 slash = strrchr(pathname, '/');
517 strcpy(slash, "ffmpeg");
519 http_log("Launch command line: ");
520 http_log("%s ", pathname);
521 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
522 http_log("%s ", feed->child_argv[i]);
525 for (i = 3; i < 256; i++)
528 if (!ffserver_debug) {
529 if (!freopen("/dev/null", "r", stdin))
530 http_log("failed to redirect STDIN to /dev/null\n;");
531 if (!freopen("/dev/null", "w", stdout))
532 http_log("failed to redirect STDOUT to /dev/null\n;");
533 if (!freopen("/dev/null", "w", stderr))
534 http_log("failed to redirect STDERR to /dev/null\n;");
537 signal(SIGPIPE, SIG_DFL);
539 execvp(pathname, feed->child_argv);
547 /* open a listening socket */
548 static int socket_open_listen(struct sockaddr_in *my_addr)
552 server_fd = socket(AF_INET,SOCK_STREAM,0);
559 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
561 my_addr->sin_family = AF_INET;
562 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
564 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
566 closesocket(server_fd);
570 if (listen (server_fd, 5) < 0) {
572 closesocket(server_fd);
575 ff_socket_nonblock(server_fd, 1);
580 /* start all multicast streams */
581 static void start_multicast(void)
586 struct sockaddr_in dest_addr = {0};
587 int default_port, stream_index;
590 for(stream = first_stream; stream != NULL; stream = stream->next) {
591 if (stream->is_multicast) {
592 unsigned random0 = av_lfg_get(&random_state);
593 unsigned random1 = av_lfg_get(&random_state);
594 /* open the RTP connection */
595 snprintf(session_id, sizeof(session_id), "%08x%08x",
598 /* choose a port if none given */
599 if (stream->multicast_port == 0) {
600 stream->multicast_port = default_port;
604 dest_addr.sin_family = AF_INET;
605 dest_addr.sin_addr = stream->multicast_ip;
606 dest_addr.sin_port = htons(stream->multicast_port);
608 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
609 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
613 if (open_input_stream(rtp_c, "") < 0) {
614 http_log("Could not open input stream for stream '%s'\n",
619 /* open each RTP stream */
620 for(stream_index = 0; stream_index < stream->nb_streams;
622 dest_addr.sin_port = htons(stream->multicast_port +
624 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
625 http_log("Could not open output stream '%s/streamid=%d'\n",
626 stream->filename, stream_index);
631 rtp_c->state = HTTPSTATE_SEND_DATA;
636 /* main loop of the HTTP server */
637 static int http_server(void)
639 int server_fd = 0, rtsp_server_fd = 0;
641 struct pollfd *poll_table, *poll_entry;
642 HTTPContext *c, *c_next;
644 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
645 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
649 if (my_http_addr.sin_port) {
650 server_fd = socket_open_listen(&my_http_addr);
655 if (my_rtsp_addr.sin_port) {
656 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
657 if (rtsp_server_fd < 0)
661 if (!rtsp_server_fd && !server_fd) {
662 http_log("HTTP and RTSP disabled.\n");
666 http_log("FFserver started.\n");
668 start_children(first_feed);
673 poll_entry = poll_table;
675 poll_entry->fd = server_fd;
676 poll_entry->events = POLLIN;
679 if (rtsp_server_fd) {
680 poll_entry->fd = rtsp_server_fd;
681 poll_entry->events = POLLIN;
685 /* wait for events on each HTTP handle */
692 case HTTPSTATE_SEND_HEADER:
693 case RTSPSTATE_SEND_REPLY:
694 case RTSPSTATE_SEND_PACKET:
695 c->poll_entry = poll_entry;
697 poll_entry->events = POLLOUT;
700 case HTTPSTATE_SEND_DATA_HEADER:
701 case HTTPSTATE_SEND_DATA:
702 case HTTPSTATE_SEND_DATA_TRAILER:
703 if (!c->is_packetized) {
704 /* for TCP, we output as much as we can
705 * (may need to put a limit) */
706 c->poll_entry = poll_entry;
708 poll_entry->events = POLLOUT;
711 /* when ffserver is doing the timing, we work by
712 looking at which packet needs to be sent every
714 /* one tick wait XXX: 10 ms assumed */
719 case HTTPSTATE_WAIT_REQUEST:
720 case HTTPSTATE_RECEIVE_DATA:
721 case HTTPSTATE_WAIT_FEED:
722 case RTSPSTATE_WAIT_REQUEST:
723 /* need to catch errors */
724 c->poll_entry = poll_entry;
726 poll_entry->events = POLLIN;/* Maybe this will work */
730 c->poll_entry = NULL;
736 /* wait for an event on one connection. We poll at least every
737 second to handle timeouts */
739 ret = poll(poll_table, poll_entry - poll_table, delay);
740 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
741 ff_neterrno() != AVERROR(EINTR))
745 cur_time = av_gettime() / 1000;
747 if (need_to_start_children) {
748 need_to_start_children = 0;
749 start_children(first_feed);
752 /* now handle the events */
753 for(c = first_http_ctx; c != NULL; c = c_next) {
755 if (handle_connection(c) < 0) {
757 /* close and free the connection */
762 poll_entry = poll_table;
764 /* new HTTP connection request ? */
765 if (poll_entry->revents & POLLIN)
766 new_connection(server_fd, 0);
769 if (rtsp_server_fd) {
770 /* new RTSP connection request ? */
771 if (poll_entry->revents & POLLIN)
772 new_connection(rtsp_server_fd, 1);
777 /* start waiting for a new HTTP/RTSP request */
778 static void start_wait_request(HTTPContext *c, int is_rtsp)
780 c->buffer_ptr = c->buffer;
781 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
784 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
785 c->state = RTSPSTATE_WAIT_REQUEST;
787 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
788 c->state = HTTPSTATE_WAIT_REQUEST;
792 static void http_send_too_busy_reply(int fd)
795 int len = snprintf(buffer, sizeof(buffer),
796 "HTTP/1.0 503 Server too busy\r\n"
797 "Content-type: text/html\r\n"
799 "<html><head><title>Too busy</title></head><body>\r\n"
800 "<p>The server is too busy to serve your request at this time.</p>\r\n"
801 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
802 "</body></html>\r\n",
803 nb_connections, nb_max_connections);
804 av_assert0(len < sizeof(buffer));
805 send(fd, buffer, len, 0);
809 static void new_connection(int server_fd, int is_rtsp)
811 struct sockaddr_in from_addr;
814 HTTPContext *c = NULL;
816 len = sizeof(from_addr);
817 fd = accept(server_fd, (struct sockaddr *)&from_addr,
820 http_log("error during accept %s\n", strerror(errno));
823 ff_socket_nonblock(fd, 1);
825 if (nb_connections >= nb_max_connections) {
826 http_send_too_busy_reply(fd);
830 /* add a new connection */
831 c = av_mallocz(sizeof(HTTPContext));
836 c->poll_entry = NULL;
837 c->from_addr = from_addr;
838 c->buffer_size = IOBUFFER_INIT_SIZE;
839 c->buffer = av_malloc(c->buffer_size);
843 c->next = first_http_ctx;
847 start_wait_request(c, is_rtsp);
859 static void close_connection(HTTPContext *c)
861 HTTPContext **cp, *c1;
863 AVFormatContext *ctx;
867 /* remove connection from list */
868 cp = &first_http_ctx;
869 while ((*cp) != NULL) {
877 /* remove references, if any (XXX: do it faster) */
878 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
883 /* remove connection associated resources */
887 /* close each frame parser */
888 for(i=0;i<c->fmt_in->nb_streams;i++) {
889 st = c->fmt_in->streams[i];
890 if (st->codec->codec)
891 avcodec_close(st->codec);
893 avformat_close_input(&c->fmt_in);
896 /* free RTP output streams if any */
899 nb_streams = c->stream->nb_streams;
901 for(i=0;i<nb_streams;i++) {
904 av_write_trailer(ctx);
905 av_dict_free(&ctx->metadata);
906 av_free(ctx->streams[0]);
909 h = c->rtp_handles[i];
916 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
919 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
920 av_write_trailer(ctx);
921 av_freep(&c->pb_buffer);
922 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
927 for(i=0; i<ctx->nb_streams; i++)
928 av_free(ctx->streams[i]);
929 av_freep(&ctx->streams);
930 av_freep(&ctx->priv_data);
932 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
933 current_bandwidth -= c->stream->bandwidth;
935 /* signal that there is no feed if we are the feeder socket */
936 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
937 c->stream->feed_opened = 0;
941 av_freep(&c->pb_buffer);
942 av_freep(&c->packet_buffer);
948 static int handle_connection(HTTPContext *c)
953 case HTTPSTATE_WAIT_REQUEST:
954 case RTSPSTATE_WAIT_REQUEST:
956 if ((c->timeout - cur_time) < 0)
958 if (c->poll_entry->revents & (POLLERR | POLLHUP))
961 /* no need to read if no events */
962 if (!(c->poll_entry->revents & POLLIN))
966 len = recv(c->fd, c->buffer_ptr, 1, 0);
968 if (ff_neterrno() != AVERROR(EAGAIN) &&
969 ff_neterrno() != AVERROR(EINTR))
971 } else if (len == 0) {
974 /* search for end of request. */
976 c->buffer_ptr += len;
978 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
979 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
980 /* request found : parse it and reply */
981 if (c->state == HTTPSTATE_WAIT_REQUEST) {
982 ret = http_parse_request(c);
984 ret = rtsp_parse_request(c);
988 } else if (ptr >= c->buffer_end) {
989 /* request too long: cannot do anything */
991 } else goto read_loop;
995 case HTTPSTATE_SEND_HEADER:
996 if (c->poll_entry->revents & (POLLERR | POLLHUP))
999 /* no need to write if no events */
1000 if (!(c->poll_entry->revents & POLLOUT))
1002 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1004 if (ff_neterrno() != AVERROR(EAGAIN) &&
1005 ff_neterrno() != AVERROR(EINTR)) {
1006 goto close_connection;
1009 c->buffer_ptr += len;
1011 c->stream->bytes_served += len;
1012 c->data_count += len;
1013 if (c->buffer_ptr >= c->buffer_end) {
1014 av_freep(&c->pb_buffer);
1015 /* if error, exit */
1018 /* all the buffer was sent : synchronize to the incoming
1020 c->state = HTTPSTATE_SEND_DATA_HEADER;
1021 c->buffer_ptr = c->buffer_end = c->buffer;
1026 case HTTPSTATE_SEND_DATA:
1027 case HTTPSTATE_SEND_DATA_HEADER:
1028 case HTTPSTATE_SEND_DATA_TRAILER:
1029 /* for packetized output, we consider we can always write (the
1030 input streams set the speed). It may be better to verify
1031 that we do not rely too much on the kernel queues */
1032 if (!c->is_packetized) {
1033 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1036 /* no need to read if no events */
1037 if (!(c->poll_entry->revents & POLLOUT))
1040 if (http_send_data(c) < 0)
1042 /* close connection if trailer sent */
1043 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1046 case HTTPSTATE_RECEIVE_DATA:
1047 /* no need to read if no events */
1048 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1050 if (!(c->poll_entry->revents & POLLIN))
1052 if (http_receive_data(c) < 0)
1055 case HTTPSTATE_WAIT_FEED:
1056 /* no need to read if no events */
1057 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1060 /* nothing to do, we'll be waken up by incoming feed packets */
1063 case RTSPSTATE_SEND_REPLY:
1064 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1065 goto close_connection;
1066 /* no need to write if no events */
1067 if (!(c->poll_entry->revents & POLLOUT))
1069 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1071 if (ff_neterrno() != AVERROR(EAGAIN) &&
1072 ff_neterrno() != AVERROR(EINTR)) {
1073 goto close_connection;
1076 c->buffer_ptr += len;
1077 c->data_count += len;
1078 if (c->buffer_ptr >= c->buffer_end) {
1079 /* all the buffer was sent : wait for a new request */
1080 av_freep(&c->pb_buffer);
1081 start_wait_request(c, 1);
1085 case RTSPSTATE_SEND_PACKET:
1086 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1087 av_freep(&c->packet_buffer);
1090 /* no need to write if no events */
1091 if (!(c->poll_entry->revents & POLLOUT))
1093 len = send(c->fd, c->packet_buffer_ptr,
1094 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1096 if (ff_neterrno() != AVERROR(EAGAIN) &&
1097 ff_neterrno() != AVERROR(EINTR)) {
1098 /* error : close connection */
1099 av_freep(&c->packet_buffer);
1103 c->packet_buffer_ptr += len;
1104 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1105 /* all the buffer was sent : wait for a new request */
1106 av_freep(&c->packet_buffer);
1107 c->state = RTSPSTATE_WAIT_REQUEST;
1111 case HTTPSTATE_READY:
1120 av_freep(&c->pb_buffer);
1124 static int extract_rates(char *rates, int ratelen, const char *request)
1128 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1129 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1130 const char *q = p + 7;
1132 while (*q && *q != '\n' && av_isspace(*q))
1135 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1141 memset(rates, 0xff, ratelen);
1144 while (*q && *q != '\n' && *q != ':')
1147 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1151 if (stream_no < ratelen && stream_no >= 0)
1152 rates[stream_no] = rate_no;
1154 while (*q && *q != '\n' && !av_isspace(*q))
1161 p = strchr(p, '\n');
1171 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1174 int best_bitrate = 100000000;
1177 for (i = 0; i < feed->nb_streams; i++) {
1178 AVCodecContext *feed_codec = feed->streams[i]->codec;
1180 if (feed_codec->codec_id != codec->codec_id ||
1181 feed_codec->sample_rate != codec->sample_rate ||
1182 feed_codec->width != codec->width ||
1183 feed_codec->height != codec->height)
1186 /* Potential stream */
1188 /* We want the fastest stream less than bit_rate, or the slowest
1189 * faster than bit_rate
1192 if (feed_codec->bit_rate <= bit_rate) {
1193 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1194 best_bitrate = feed_codec->bit_rate;
1198 if (feed_codec->bit_rate < best_bitrate) {
1199 best_bitrate = feed_codec->bit_rate;
1208 static int modify_current_stream(HTTPContext *c, char *rates)
1211 FFStream *req = c->stream;
1212 int action_required = 0;
1214 /* Not much we can do for a feed */
1218 for (i = 0; i < req->nb_streams; i++) {
1219 AVCodecContext *codec = req->streams[i]->codec;
1223 c->switch_feed_streams[i] = req->feed_streams[i];
1226 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1229 /* Wants off or slow */
1230 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1232 /* This doesn't work well when it turns off the only stream! */
1233 c->switch_feed_streams[i] = -2;
1234 c->feed_streams[i] = -2;
1239 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1240 action_required = 1;
1243 return action_required;
1246 /* XXX: factorize in utils.c ? */
1247 /* XXX: take care with different space meaning */
1248 static void skip_spaces(const char **pp)
1252 while (*p == ' ' || *p == '\t')
1257 static void get_word(char *buf, int buf_size, const char **pp)
1265 while (!av_isspace(*p) && *p != '\0') {
1266 if ((q - buf) < buf_size - 1)
1275 static void get_arg(char *buf, int buf_size, const char **pp)
1282 while (av_isspace(*p)) p++;
1285 if (*p == '\"' || *p == '\'')
1297 if ((q - buf) < buf_size - 1)
1302 if (quote && *p == quote)
1307 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1308 const char *p, const char *filename, int line_num)
1314 get_arg(arg, sizeof(arg), &p);
1315 if (av_strcasecmp(arg, "allow") == 0)
1316 acl.action = IP_ALLOW;
1317 else if (av_strcasecmp(arg, "deny") == 0)
1318 acl.action = IP_DENY;
1320 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1321 filename, line_num, arg);
1325 get_arg(arg, sizeof(arg), &p);
1327 if (resolve_host(&acl.first, arg) != 0) {
1328 fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1329 filename, line_num, arg);
1332 acl.last = acl.first;
1334 get_arg(arg, sizeof(arg), &p);
1337 if (resolve_host(&acl.last, arg) != 0) {
1338 fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1339 filename, line_num, arg);
1345 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1346 IPAddressACL **naclp = 0;
1352 naclp = &stream->acl;
1358 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1359 filename, line_num);
1365 naclp = &(*naclp)->next;
1374 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1379 IPAddressACL *acl = NULL;
1383 f = fopen(stream->dynamic_acl, "r");
1385 perror(stream->dynamic_acl);
1389 acl = av_mallocz(sizeof(IPAddressACL));
1393 if (fgets(line, sizeof(line), f) == NULL)
1397 while (av_isspace(*p))
1399 if (*p == '\0' || *p == '#')
1401 get_arg(cmd, sizeof(cmd), &p);
1403 if (!av_strcasecmp(cmd, "ACL"))
1404 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1411 static void free_acl_list(IPAddressACL *in_acl)
1413 IPAddressACL *pacl,*pacl2;
1423 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1425 enum IPAddressAction last_action = IP_DENY;
1427 struct in_addr *src = &c->from_addr.sin_addr;
1428 unsigned long src_addr = src->s_addr;
1430 for (acl = in_acl; acl; acl = acl->next) {
1431 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1432 return (acl->action == IP_ALLOW) ? 1 : 0;
1433 last_action = acl->action;
1436 /* Nothing matched, so return not the last action */
1437 return (last_action == IP_DENY) ? 1 : 0;
1440 static int validate_acl(FFStream *stream, HTTPContext *c)
1446 /* if stream->acl is null validate_acl_list will return 1 */
1447 ret = validate_acl_list(stream->acl, c);
1449 if (stream->dynamic_acl[0]) {
1450 acl = parse_dynamic_acl(stream, c);
1452 ret = validate_acl_list(acl, c);
1460 /* compute the real filename of a file by matching it without its
1461 extensions to all the stream's filenames */
1462 static void compute_real_filename(char *filename, int max_size)
1469 /* compute filename by matching without the file extensions */
1470 av_strlcpy(file1, filename, sizeof(file1));
1471 p = strrchr(file1, '.');
1474 for(stream = first_stream; stream != NULL; stream = stream->next) {
1475 av_strlcpy(file2, stream->filename, sizeof(file2));
1476 p = strrchr(file2, '.');
1479 if (!strcmp(file1, file2)) {
1480 av_strlcpy(filename, stream->filename, max_size);
1495 /* parse HTTP request and prepare header */
1496 static int http_parse_request(HTTPContext *c)
1500 enum RedirType redir_type;
1502 char info[1024], filename[1024];
1506 const char *mime_type;
1510 const char *useragent = 0;
1513 get_word(cmd, sizeof(cmd), &p);
1514 av_strlcpy(c->method, cmd, sizeof(c->method));
1516 if (!strcmp(cmd, "GET"))
1518 else if (!strcmp(cmd, "POST"))
1523 get_word(url, sizeof(url), &p);
1524 av_strlcpy(c->url, url, sizeof(c->url));
1526 get_word(protocol, sizeof(protocol), (const char **)&p);
1527 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1530 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1533 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1535 /* find the filename and the optional info string in the request */
1536 p1 = strchr(url, '?');
1538 av_strlcpy(info, p1, sizeof(info));
1543 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1545 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1546 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1548 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1552 p = strchr(p, '\n');
1559 redir_type = REDIR_NONE;
1560 if (av_match_ext(filename, "asx")) {
1561 redir_type = REDIR_ASX;
1562 filename[strlen(filename)-1] = 'f';
1563 } else if (av_match_ext(filename, "asf") &&
1564 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1565 /* if this isn't WMP or lookalike, return the redirector file */
1566 redir_type = REDIR_ASF;
1567 } else if (av_match_ext(filename, "rpm,ram")) {
1568 redir_type = REDIR_RAM;
1569 strcpy(filename + strlen(filename)-2, "m");
1570 } else if (av_match_ext(filename, "rtsp")) {
1571 redir_type = REDIR_RTSP;
1572 compute_real_filename(filename, sizeof(filename) - 1);
1573 } else if (av_match_ext(filename, "sdp")) {
1574 redir_type = REDIR_SDP;
1575 compute_real_filename(filename, sizeof(filename) - 1);
1578 // "redirect" / request to index.html
1579 if (!strlen(filename))
1580 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1582 stream = first_stream;
1583 while (stream != NULL) {
1584 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1586 stream = stream->next;
1588 if (stream == NULL) {
1589 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1590 http_log("File '%s' not found\n", url);
1595 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1596 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1598 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1599 c->http_error = 301;
1601 snprintf(q, c->buffer_size,
1602 "HTTP/1.0 301 Moved\r\n"
1604 "Content-type: text/html\r\n"
1606 "<html><head><title>Moved</title></head><body>\r\n"
1607 "You should be <a href=\"%s\">redirected</a>.\r\n"
1608 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1610 /* prepare output buffer */
1611 c->buffer_ptr = c->buffer;
1613 c->state = HTTPSTATE_SEND_HEADER;
1617 /* If this is WMP, get the rate information */
1618 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1619 if (modify_current_stream(c, ratebuf)) {
1620 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1621 if (c->switch_feed_streams[i] >= 0)
1622 c->switch_feed_streams[i] = -1;
1627 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1628 current_bandwidth += stream->bandwidth;
1630 /* If already streaming this feed, do not let start another feeder. */
1631 if (stream->feed_opened) {
1632 snprintf(msg, sizeof(msg), "This feed is already being received.");
1633 http_log("Feed '%s' already being received\n", stream->feed_filename);
1637 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1638 c->http_error = 503;
1640 snprintf(q, c->buffer_size,
1641 "HTTP/1.0 503 Server too busy\r\n"
1642 "Content-type: text/html\r\n"
1644 "<html><head><title>Too busy</title></head><body>\r\n"
1645 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1646 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1647 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1648 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1650 /* prepare output buffer */
1651 c->buffer_ptr = c->buffer;
1653 c->state = HTTPSTATE_SEND_HEADER;
1657 if (redir_type != REDIR_NONE) {
1658 const char *hostinfo = 0;
1660 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1661 if (av_strncasecmp(p, "Host:", 5) == 0) {
1665 p = strchr(p, '\n');
1676 while (av_isspace(*hostinfo))
1679 eoh = strchr(hostinfo, '\n');
1681 if (eoh[-1] == '\r')
1684 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1685 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1686 hostbuf[eoh - hostinfo] = 0;
1688 c->http_error = 200;
1690 switch(redir_type) {
1692 snprintf(q, c->buffer_size,
1693 "HTTP/1.0 200 ASX Follows\r\n"
1694 "Content-type: video/x-ms-asf\r\n"
1696 "<ASX Version=\"3\">\r\n"
1697 //"<!-- Autogenerated by ffserver -->\r\n"
1698 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1699 "</ASX>\r\n", hostbuf, filename, info);
1703 snprintf(q, c->buffer_size,
1704 "HTTP/1.0 200 RAM Follows\r\n"
1705 "Content-type: audio/x-pn-realaudio\r\n"
1707 "# Autogenerated by ffserver\r\n"
1708 "http://%s/%s%s\r\n", hostbuf, filename, info);
1712 snprintf(q, c->buffer_size,
1713 "HTTP/1.0 200 ASF Redirect follows\r\n"
1714 "Content-type: video/x-ms-asf\r\n"
1717 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1722 char hostname[256], *p;
1723 /* extract only hostname */
1724 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1725 p = strrchr(hostname, ':');
1728 snprintf(q, c->buffer_size,
1729 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1730 /* XXX: incorrect MIME type ? */
1731 "Content-type: application/x-rtsp\r\n"
1733 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1742 struct sockaddr_in my_addr;
1744 snprintf(q, c->buffer_size,
1745 "HTTP/1.0 200 OK\r\n"
1746 "Content-type: application/sdp\r\n"
1750 len = sizeof(my_addr);
1751 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1753 /* XXX: should use a dynamic buffer */
1754 sdp_data_size = prepare_sdp_description(stream,
1757 if (sdp_data_size > 0) {
1758 memcpy(q, sdp_data, sdp_data_size);
1770 /* prepare output buffer */
1771 c->buffer_ptr = c->buffer;
1773 c->state = HTTPSTATE_SEND_HEADER;
1779 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1783 stream->conns_served++;
1785 /* XXX: add there authenticate and IP match */
1788 /* if post, it means a feed is being sent */
1789 if (!stream->is_feed) {
1790 /* However it might be a status report from WMP! Let us log the
1791 * data as it might come handy one day. */
1792 const char *logline = 0;
1795 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1796 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1800 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1801 client_id = strtol(p + 18, 0, 10);
1802 p = strchr(p, '\n');
1810 char *eol = strchr(logline, '\n');
1815 if (eol[-1] == '\r')
1817 http_log("%.*s\n", (int) (eol - logline), logline);
1818 c->suppress_log = 1;
1823 http_log("\nGot request:\n%s\n", c->buffer);
1826 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1829 /* Now we have to find the client_id */
1830 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1831 if (wmpc->wmp_client_id == client_id)
1835 if (wmpc && modify_current_stream(wmpc, ratebuf))
1836 wmpc->switch_pending = 1;
1839 snprintf(msg, sizeof(msg), "POST command not handled");
1843 if (http_start_receive_data(c) < 0) {
1844 snprintf(msg, sizeof(msg), "could not open feed");
1848 c->state = HTTPSTATE_RECEIVE_DATA;
1853 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1854 http_log("\nGot request:\n%s\n", c->buffer);
1857 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1860 /* open input stream */
1861 if (open_input_stream(c, info) < 0) {
1862 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1866 /* prepare HTTP header */
1868 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1869 mime_type = c->stream->fmt->mime_type;
1871 mime_type = "application/x-octet-stream";
1872 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1874 /* for asf, we need extra headers */
1875 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1876 /* Need to allocate a client id */
1878 c->wmp_client_id = av_lfg_get(&random_state);
1880 av_strlcatf(c->buffer, c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
1882 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1883 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1884 q = c->buffer + strlen(c->buffer);
1886 /* prepare output buffer */
1888 c->buffer_ptr = c->buffer;
1890 c->state = HTTPSTATE_SEND_HEADER;
1893 c->http_error = 404;
1896 snprintf(q, c->buffer_size,
1897 "HTTP/1.0 404 Not Found\r\n"
1898 "Content-type: text/html\r\n"
1901 "<head><title>404 Not Found</title></head>\n"
1905 /* prepare output buffer */
1906 c->buffer_ptr = c->buffer;
1908 c->state = HTTPSTATE_SEND_HEADER;
1912 c->http_error = 200; /* horrible : we use this value to avoid
1913 going to the send data state */
1914 c->state = HTTPSTATE_SEND_HEADER;
1918 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1920 static const char suffix[] = " kMGTP";
1923 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1925 avio_printf(pb, "%"PRId64"%c", count, *s);
1928 static void compute_status(HTTPContext *c)
1937 if (avio_open_dyn_buf(&pb) < 0) {
1938 /* XXX: return an error ? */
1939 c->buffer_ptr = c->buffer;
1940 c->buffer_end = c->buffer;
1944 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1945 avio_printf(pb, "Content-type: text/html\r\n");
1946 avio_printf(pb, "Pragma: no-cache\r\n");
1947 avio_printf(pb, "\r\n");
1949 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1950 if (c->stream->feed_filename[0])
1951 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1952 avio_printf(pb, "</head>\n<body>");
1953 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1955 avio_printf(pb, "<h2>Available Streams</h2>\n");
1956 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1957 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");
1958 stream = first_stream;
1959 while (stream != NULL) {
1960 char sfilename[1024];
1963 if (stream->feed != stream) {
1964 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1965 eosf = sfilename + strlen(sfilename);
1966 if (eosf - sfilename >= 4) {
1967 if (strcmp(eosf - 4, ".asf") == 0)
1968 strcpy(eosf - 4, ".asx");
1969 else if (strcmp(eosf - 3, ".rm") == 0)
1970 strcpy(eosf - 3, ".ram");
1971 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1972 /* generate a sample RTSP director if
1973 unicast. Generate an SDP redirector if
1975 eosf = strrchr(sfilename, '.');
1977 eosf = sfilename + strlen(sfilename);
1978 if (stream->is_multicast)
1979 strcpy(eosf, ".sdp");
1981 strcpy(eosf, ".rtsp");
1985 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1986 sfilename, stream->filename);
1987 avio_printf(pb, "<td align=right> %d <td align=right> ",
1988 stream->conns_served);
1989 fmt_bytecount(pb, stream->bytes_served);
1990 switch(stream->stream_type) {
1991 case STREAM_TYPE_LIVE: {
1992 int audio_bit_rate = 0;
1993 int video_bit_rate = 0;
1994 const char *audio_codec_name = "";
1995 const char *video_codec_name = "";
1996 const char *audio_codec_name_extra = "";
1997 const char *video_codec_name_extra = "";
1999 for(i=0;i<stream->nb_streams;i++) {
2000 AVStream *st = stream->streams[i];
2001 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2002 switch(st->codec->codec_type) {
2003 case AVMEDIA_TYPE_AUDIO:
2004 audio_bit_rate += st->codec->bit_rate;
2006 if (*audio_codec_name)
2007 audio_codec_name_extra = "...";
2008 audio_codec_name = codec->name;
2011 case AVMEDIA_TYPE_VIDEO:
2012 video_bit_rate += st->codec->bit_rate;
2014 if (*video_codec_name)
2015 video_codec_name_extra = "...";
2016 video_codec_name = codec->name;
2019 case AVMEDIA_TYPE_DATA:
2020 video_bit_rate += st->codec->bit_rate;
2026 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",
2029 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2030 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2032 avio_printf(pb, "<td>%s", stream->feed->filename);
2034 avio_printf(pb, "<td>%s", stream->feed_filename);
2035 avio_printf(pb, "\n");
2039 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2043 stream = stream->next;
2045 avio_printf(pb, "</table>\n");
2047 stream = first_stream;
2048 while (stream != NULL) {
2049 if (stream->feed == stream) {
2050 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2052 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2059 /* This is somewhat linux specific I guess */
2060 snprintf(ps_cmd, sizeof(ps_cmd),
2061 "ps -o \"%%cpu,cputime\" --no-headers %d",
2064 pid_stat = popen(ps_cmd, "r");
2069 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2071 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2079 avio_printf(pb, "<p>");
2081 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");
2083 for (i = 0; i < stream->nb_streams; i++) {
2084 AVStream *st = stream->streams[i];
2085 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2086 const char *type = "unknown";
2087 char parameters[64];
2091 switch(st->codec->codec_type) {
2092 case AVMEDIA_TYPE_AUDIO:
2094 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2096 case AVMEDIA_TYPE_VIDEO:
2098 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2099 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2104 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2105 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2107 avio_printf(pb, "</table>\n");
2110 stream = stream->next;
2113 /* connection status */
2114 avio_printf(pb, "<h2>Connection Status</h2>\n");
2116 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2117 nb_connections, nb_max_connections);
2119 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2120 current_bandwidth, max_bandwidth);
2122 avio_printf(pb, "<table>\n");
2123 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");
2124 c1 = first_http_ctx;
2126 while (c1 != NULL) {
2132 for (j = 0; j < c1->stream->nb_streams; j++) {
2133 if (!c1->stream->feed)
2134 bitrate += c1->stream->streams[j]->codec->bit_rate;
2135 else if (c1->feed_streams[j] >= 0)
2136 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2141 p = inet_ntoa(c1->from_addr.sin_addr);
2142 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2144 c1->stream ? c1->stream->filename : "",
2145 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2148 http_state[c1->state]);
2149 fmt_bytecount(pb, bitrate);
2150 avio_printf(pb, "<td align=right>");
2151 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2152 avio_printf(pb, "<td align=right>");
2153 fmt_bytecount(pb, c1->data_count);
2154 avio_printf(pb, "\n");
2157 avio_printf(pb, "</table>\n");
2162 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2163 avio_printf(pb, "</body>\n</html>\n");
2165 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2166 c->buffer_ptr = c->pb_buffer;
2167 c->buffer_end = c->pb_buffer + len;
2170 static int open_input_stream(HTTPContext *c, const char *info)
2173 char input_filename[1024];
2174 AVFormatContext *s = NULL;
2175 int buf_size, i, ret;
2178 /* find file name */
2179 if (c->stream->feed) {
2180 strcpy(input_filename, c->stream->feed->feed_filename);
2181 buf_size = FFM_PACKET_SIZE;
2182 /* compute position (absolute time) */
2183 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2184 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2185 http_log("Invalid date specification '%s' for stream\n", buf);
2188 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2189 int prebuffer = strtol(buf, 0, 10);
2190 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2192 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2194 strcpy(input_filename, c->stream->feed_filename);
2196 /* compute position (relative time) */
2197 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2198 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2199 http_log("Invalid date specification '%s' for stream\n", buf);
2205 if (!input_filename[0]) {
2206 http_log("No filename was specified for stream\n");
2207 return AVERROR(EINVAL);
2211 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2212 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2216 /* set buffer size */
2217 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2219 s->flags |= AVFMT_FLAG_GENPTS;
2221 if (strcmp(s->iformat->name, "ffm") &&
2222 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2223 http_log("Could not find stream info for input '%s'\n", input_filename);
2224 avformat_close_input(&s);
2228 /* choose stream as clock source (we favor the video stream if
2229 * present) for packet sending */
2230 c->pts_stream_index = 0;
2231 for(i=0;i<c->stream->nb_streams;i++) {
2232 if (c->pts_stream_index == 0 &&
2233 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2234 c->pts_stream_index = i;
2238 if (c->fmt_in->iformat->read_seek)
2239 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2240 /* set the start time (needed for maxtime and RTP packet timing) */
2241 c->start_time = cur_time;
2242 c->first_pts = AV_NOPTS_VALUE;
2246 /* return the server clock (in us) */
2247 static int64_t get_server_clock(HTTPContext *c)
2249 /* compute current pts value from system time */
2250 return (cur_time - c->start_time) * 1000;
2253 /* return the estimated time at which the current packet must be sent
2255 static int64_t get_packet_send_clock(HTTPContext *c)
2257 int bytes_left, bytes_sent, frame_bytes;
2259 frame_bytes = c->cur_frame_bytes;
2260 if (frame_bytes <= 0)
2263 bytes_left = c->buffer_end - c->buffer_ptr;
2264 bytes_sent = frame_bytes - bytes_left;
2265 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2270 static int http_prepare_data(HTTPContext *c)
2273 AVFormatContext *ctx;
2275 av_freep(&c->pb_buffer);
2277 case HTTPSTATE_SEND_DATA_HEADER:
2278 ctx = avformat_alloc_context();
2281 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2282 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2284 for(i=0;i<c->stream->nb_streams;i++) {
2286 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2287 /* if file or feed, then just take streams from FFStream struct */
2288 if (!c->stream->feed ||
2289 c->stream->feed == c->stream)
2290 src = c->stream->streams[i];
2292 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2294 *(c->fmt_ctx.streams[i]) = *src;
2295 c->fmt_ctx.streams[i]->priv_data = 0;
2296 /* XXX: should be done in AVStream, not in codec */
2297 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2299 /* set output format parameters */
2300 c->fmt_ctx.oformat = c->stream->fmt;
2301 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2303 c->got_key_frame = 0;
2305 /* prepare header and save header data in a stream */
2306 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2307 /* XXX: potential leak */
2310 c->fmt_ctx.pb->seekable = 0;
2313 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2314 * Default value from FFmpeg
2315 * Try to set it using configuration option
2317 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2319 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2320 http_log("Error writing output header for stream '%s': %s\n",
2321 c->stream->filename, av_err2str(ret));
2324 av_dict_free(&c->fmt_ctx.metadata);
2326 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2327 c->buffer_ptr = c->pb_buffer;
2328 c->buffer_end = c->pb_buffer + len;
2330 c->state = HTTPSTATE_SEND_DATA;
2331 c->last_packet_sent = 0;
2333 case HTTPSTATE_SEND_DATA:
2334 /* find a new packet */
2335 /* read a packet from the input stream */
2336 if (c->stream->feed)
2337 ffm_set_write_index(c->fmt_in,
2338 c->stream->feed->feed_write_index,
2339 c->stream->feed->feed_size);
2341 if (c->stream->max_time &&
2342 c->stream->max_time + c->start_time - cur_time < 0)
2343 /* We have timed out */
2344 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2348 ret = av_read_frame(c->fmt_in, &pkt);
2350 if (c->stream->feed) {
2351 /* if coming from feed, it means we reached the end of the
2352 ffm file, so must wait for more data */
2353 c->state = HTTPSTATE_WAIT_FEED;
2354 return 1; /* state changed */
2355 } else if (ret == AVERROR(EAGAIN)) {
2356 /* input not ready, come back later */
2359 if (c->stream->loop) {
2360 avformat_close_input(&c->fmt_in);
2361 if (open_input_stream(c, "") < 0)
2366 /* must send trailer now because EOF or error */
2367 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2371 int source_index = pkt.stream_index;
2372 /* update first pts if needed */
2373 if (c->first_pts == AV_NOPTS_VALUE) {
2374 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2375 c->start_time = cur_time;
2377 /* send it to the appropriate stream */
2378 if (c->stream->feed) {
2379 /* if coming from a feed, select the right stream */
2380 if (c->switch_pending) {
2381 c->switch_pending = 0;
2382 for(i=0;i<c->stream->nb_streams;i++) {
2383 if (c->switch_feed_streams[i] == pkt.stream_index)
2384 if (pkt.flags & AV_PKT_FLAG_KEY)
2385 c->switch_feed_streams[i] = -1;
2386 if (c->switch_feed_streams[i] >= 0)
2387 c->switch_pending = 1;
2390 for(i=0;i<c->stream->nb_streams;i++) {
2391 if (c->stream->feed_streams[i] == pkt.stream_index) {
2392 AVStream *st = c->fmt_in->streams[source_index];
2393 pkt.stream_index = i;
2394 if (pkt.flags & AV_PKT_FLAG_KEY &&
2395 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2396 c->stream->nb_streams == 1))
2397 c->got_key_frame = 1;
2398 if (!c->stream->send_on_key || c->got_key_frame)
2403 AVCodecContext *codec;
2404 AVStream *ist, *ost;
2406 ist = c->fmt_in->streams[source_index];
2407 /* specific handling for RTP: we use several
2408 * output streams (one for each RTP connection).
2409 * XXX: need more abstract handling */
2410 if (c->is_packetized) {
2411 /* compute send time and duration */
2412 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2413 c->cur_pts -= c->first_pts;
2414 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2415 /* find RTP context */
2416 c->packet_stream_index = pkt.stream_index;
2417 ctx = c->rtp_ctx[c->packet_stream_index];
2419 av_free_packet(&pkt);
2422 codec = ctx->streams[0]->codec;
2423 /* only one stream per RTP connection */
2424 pkt.stream_index = 0;
2428 codec = ctx->streams[pkt.stream_index]->codec;
2431 if (c->is_packetized) {
2432 int max_packet_size;
2433 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2434 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2436 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2437 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2439 ret = avio_open_dyn_buf(&ctx->pb);
2442 /* XXX: potential leak */
2445 ost = ctx->streams[pkt.stream_index];
2447 ctx->pb->seekable = 0;
2448 if (pkt.dts != AV_NOPTS_VALUE)
2449 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2450 if (pkt.pts != AV_NOPTS_VALUE)
2451 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2452 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2453 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2454 http_log("Error writing frame to output for stream '%s': %s\n",
2455 c->stream->filename, av_err2str(ret));
2456 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2459 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2460 c->cur_frame_bytes = len;
2461 c->buffer_ptr = c->pb_buffer;
2462 c->buffer_end = c->pb_buffer + len;
2464 codec->frame_number++;
2466 av_free_packet(&pkt);
2470 av_free_packet(&pkt);
2475 case HTTPSTATE_SEND_DATA_TRAILER:
2476 /* last packet test ? */
2477 if (c->last_packet_sent || c->is_packetized)
2480 /* prepare header */
2481 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2482 /* XXX: potential leak */
2485 c->fmt_ctx.pb->seekable = 0;
2486 av_write_trailer(ctx);
2487 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2488 c->buffer_ptr = c->pb_buffer;
2489 c->buffer_end = c->pb_buffer + len;
2491 c->last_packet_sent = 1;
2497 /* should convert the format at the same time */
2498 /* send data starting at c->buffer_ptr to the output connection
2499 * (either UDP or TCP) */
2500 static int http_send_data(HTTPContext *c)
2505 if (c->buffer_ptr >= c->buffer_end) {
2506 ret = http_prepare_data(c);
2510 /* state change requested */
2513 if (c->is_packetized) {
2514 /* RTP data output */
2515 len = c->buffer_end - c->buffer_ptr;
2517 /* fail safe - should never happen */
2519 c->buffer_ptr = c->buffer_end;
2522 len = (c->buffer_ptr[0] << 24) |
2523 (c->buffer_ptr[1] << 16) |
2524 (c->buffer_ptr[2] << 8) |
2526 if (len > (c->buffer_end - c->buffer_ptr))
2528 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2529 /* nothing to send yet: we can wait */
2533 c->data_count += len;
2534 update_datarate(&c->datarate, c->data_count);
2536 c->stream->bytes_served += len;
2538 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2539 /* RTP packets are sent inside the RTSP TCP connection */
2541 int interleaved_index, size;
2543 HTTPContext *rtsp_c;
2546 /* if no RTSP connection left, error */
2549 /* if already sending something, then wait. */
2550 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2552 if (avio_open_dyn_buf(&pb) < 0)
2554 interleaved_index = c->packet_stream_index * 2;
2555 /* RTCP packets are sent at odd indexes */
2556 if (c->buffer_ptr[1] == 200)
2557 interleaved_index++;
2558 /* write RTSP TCP header */
2560 header[1] = interleaved_index;
2561 header[2] = len >> 8;
2563 avio_write(pb, header, 4);
2564 /* write RTP packet data */
2566 avio_write(pb, c->buffer_ptr, len);
2567 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2568 /* prepare asynchronous TCP sending */
2569 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2570 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2571 c->buffer_ptr += len;
2573 /* send everything we can NOW */
2574 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2575 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2577 rtsp_c->packet_buffer_ptr += len;
2578 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2579 /* if we could not send all the data, we will
2580 send it later, so a new state is needed to
2581 "lock" the RTSP TCP connection */
2582 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2585 /* all data has been sent */
2586 av_freep(&c->packet_buffer);
2588 /* send RTP packet directly in UDP */
2590 ffurl_write(c->rtp_handles[c->packet_stream_index],
2591 c->buffer_ptr, len);
2592 c->buffer_ptr += len;
2593 /* here we continue as we can send several packets per 10 ms slot */
2596 /* TCP data output */
2597 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2599 if (ff_neterrno() != AVERROR(EAGAIN) &&
2600 ff_neterrno() != AVERROR(EINTR))
2601 /* error : close connection */
2606 c->buffer_ptr += len;
2608 c->data_count += len;
2609 update_datarate(&c->datarate, c->data_count);
2611 c->stream->bytes_served += len;
2619 static int http_start_receive_data(HTTPContext *c)
2624 if (c->stream->feed_opened) {
2625 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2626 return AVERROR(EINVAL);
2629 /* Don't permit writing to this one */
2630 if (c->stream->readonly) {
2631 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2632 return AVERROR(EINVAL);
2636 fd = open(c->stream->feed_filename, O_RDWR);
2638 ret = AVERROR(errno);
2639 http_log("Could not open feed file '%s': %s\n",
2640 c->stream->feed_filename, strerror(errno));
2645 if (c->stream->truncate) {
2646 /* truncate feed file */
2647 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2648 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2649 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2650 ret = AVERROR(errno);
2651 http_log("Error truncating feed file '%s': %s\n",
2652 c->stream->feed_filename, strerror(errno));
2656 ret = ffm_read_write_index(fd);
2658 http_log("Error reading write index from feed file '%s': %s\n",
2659 c->stream->feed_filename, strerror(errno));
2662 c->stream->feed_write_index = ret;
2666 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2667 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2668 lseek(fd, 0, SEEK_SET);
2670 /* init buffer input */
2671 c->buffer_ptr = c->buffer;
2672 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2673 c->stream->feed_opened = 1;
2674 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2678 static int http_receive_data(HTTPContext *c)
2681 int len, loop_run = 0;
2683 while (c->chunked_encoding && !c->chunk_size &&
2684 c->buffer_end > c->buffer_ptr) {
2685 /* read chunk header, if present */
2686 len = recv(c->fd, c->buffer_ptr, 1, 0);
2689 if (ff_neterrno() != AVERROR(EAGAIN) &&
2690 ff_neterrno() != AVERROR(EINTR))
2691 /* error : close connection */
2694 } else if (len == 0) {
2695 /* end of connection : close it */
2697 } else if (c->buffer_ptr - c->buffer >= 2 &&
2698 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2699 c->chunk_size = strtol(c->buffer, 0, 16);
2700 if (c->chunk_size == 0) // end of stream
2702 c->buffer_ptr = c->buffer;
2704 } else if (++loop_run > 10) {
2705 /* no chunk header, abort */
2712 if (c->buffer_end > c->buffer_ptr) {
2713 len = recv(c->fd, c->buffer_ptr,
2714 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2716 if (ff_neterrno() != AVERROR(EAGAIN) &&
2717 ff_neterrno() != AVERROR(EINTR))
2718 /* error : close connection */
2720 } else if (len == 0)
2721 /* end of connection : close it */
2724 c->chunk_size -= len;
2725 c->buffer_ptr += len;
2726 c->data_count += len;
2727 update_datarate(&c->datarate, c->data_count);
2731 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2732 if (c->buffer[0] != 'f' ||
2733 c->buffer[1] != 'm') {
2734 http_log("Feed stream has become desynchronized -- disconnecting\n");
2739 if (c->buffer_ptr >= c->buffer_end) {
2740 FFStream *feed = c->stream;
2741 /* a packet has been received : write it in the store, except
2743 if (c->data_count > FFM_PACKET_SIZE) {
2744 /* XXX: use llseek or url_seek */
2745 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2746 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2747 http_log("Error writing to feed file: %s\n", strerror(errno));
2751 feed->feed_write_index += FFM_PACKET_SIZE;
2752 /* update file size */
2753 if (feed->feed_write_index > c->stream->feed_size)
2754 feed->feed_size = feed->feed_write_index;
2756 /* handle wrap around if max file size reached */
2757 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2758 feed->feed_write_index = FFM_PACKET_SIZE;
2761 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2762 http_log("Error writing index to feed file: %s\n", strerror(errno));
2766 /* wake up any waiting connections */
2767 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2768 if (c1->state == HTTPSTATE_WAIT_FEED &&
2769 c1->stream->feed == c->stream->feed)
2770 c1->state = HTTPSTATE_SEND_DATA;
2773 /* We have a header in our hands that contains useful data */
2774 AVFormatContext *s = avformat_alloc_context();
2776 AVInputFormat *fmt_in;
2782 /* use feed output format name to find corresponding input format */
2783 fmt_in = av_find_input_format(feed->fmt->name);
2787 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2788 0, NULL, NULL, NULL, NULL);
2792 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2797 /* Now we have the actual streams */
2798 if (s->nb_streams != feed->nb_streams) {
2799 avformat_close_input(&s);
2801 http_log("Feed '%s' stream number does not match registered feed\n",
2802 c->stream->feed_filename);
2806 for (i = 0; i < s->nb_streams; i++) {
2807 AVStream *fst = feed->streams[i];
2808 AVStream *st = s->streams[i];
2809 avcodec_copy_context(fst->codec, st->codec);
2812 avformat_close_input(&s);
2815 c->buffer_ptr = c->buffer;
2820 c->stream->feed_opened = 0;
2822 /* wake up any waiting connections to stop waiting for feed */
2823 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2824 if (c1->state == HTTPSTATE_WAIT_FEED &&
2825 c1->stream->feed == c->stream->feed)
2826 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2831 /********************************************************************/
2834 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2841 str = RTSP_STATUS_CODE2STRING(error_number);
2843 str = "Unknown Error";
2845 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2846 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2848 /* output GMT time */
2851 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2852 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2855 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2857 rtsp_reply_header(c, error_number);
2858 avio_printf(c->pb, "\r\n");
2861 static int rtsp_parse_request(HTTPContext *c)
2863 const char *p, *p1, *p2;
2869 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2871 c->buffer_ptr[0] = '\0';
2874 get_word(cmd, sizeof(cmd), &p);
2875 get_word(url, sizeof(url), &p);
2876 get_word(protocol, sizeof(protocol), &p);
2878 av_strlcpy(c->method, cmd, sizeof(c->method));
2879 av_strlcpy(c->url, url, sizeof(c->url));
2880 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2882 if (avio_open_dyn_buf(&c->pb) < 0) {
2883 /* XXX: cannot do more */
2884 c->pb = NULL; /* safety */
2888 /* check version name */
2889 if (strcmp(protocol, "RTSP/1.0") != 0) {
2890 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2894 /* parse each header line */
2895 /* skip to next line */
2896 while (*p != '\n' && *p != '\0')
2900 while (*p != '\0') {
2901 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2905 if (p2 > p && p2[-1] == '\r')
2907 /* skip empty line */
2911 if (len > sizeof(line) - 1)
2912 len = sizeof(line) - 1;
2913 memcpy(line, p, len);
2915 ff_rtsp_parse_line(header, line, NULL, NULL);
2919 /* handle sequence number */
2920 c->seq = header->seq;
2922 if (!strcmp(cmd, "DESCRIBE"))
2923 rtsp_cmd_describe(c, url);
2924 else if (!strcmp(cmd, "OPTIONS"))
2925 rtsp_cmd_options(c, url);
2926 else if (!strcmp(cmd, "SETUP"))
2927 rtsp_cmd_setup(c, url, header);
2928 else if (!strcmp(cmd, "PLAY"))
2929 rtsp_cmd_play(c, url, header);
2930 else if (!strcmp(cmd, "PAUSE"))
2931 rtsp_cmd_interrupt(c, url, header, 1);
2932 else if (!strcmp(cmd, "TEARDOWN"))
2933 rtsp_cmd_interrupt(c, url, header, 0);
2935 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2938 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2939 c->pb = NULL; /* safety */
2941 /* XXX: cannot do more */
2944 c->buffer_ptr = c->pb_buffer;
2945 c->buffer_end = c->pb_buffer + len;
2946 c->state = RTSPSTATE_SEND_REPLY;
2950 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2951 struct in_addr my_ip)
2953 AVFormatContext *avc;
2954 AVStream *avs = NULL;
2955 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2956 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2959 avc = avformat_alloc_context();
2960 if (avc == NULL || !rtp_format) {
2963 avc->oformat = rtp_format;
2964 av_dict_set(&avc->metadata, "title",
2965 entry ? entry->value : "No Title", 0);
2966 avc->nb_streams = stream->nb_streams;
2967 if (stream->is_multicast) {
2968 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2969 inet_ntoa(stream->multicast_ip),
2970 stream->multicast_port, stream->multicast_ttl);
2972 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2975 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2976 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2978 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2979 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2982 for(i = 0; i < stream->nb_streams; i++) {
2983 avc->streams[i] = &avs[i];
2984 avc->streams[i]->codec = stream->streams[i]->codec;
2986 *pbuffer = av_mallocz(2048);
2987 av_sdp_create(&avc, 1, *pbuffer, 2048);
2990 av_free(avc->streams);
2991 av_dict_free(&avc->metadata);
2995 return strlen(*pbuffer);
2998 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3000 // rtsp_reply_header(c, RTSP_STATUS_OK);
3001 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3002 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3003 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3004 avio_printf(c->pb, "\r\n");
3007 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3015 struct sockaddr_in my_addr;
3017 /* find which URL is asked */
3018 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3023 for(stream = first_stream; stream != NULL; stream = stream->next) {
3024 if (!stream->is_feed &&
3025 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3026 !strcmp(path, stream->filename)) {
3030 /* no stream found */
3031 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3035 /* prepare the media description in SDP format */
3037 /* get the host IP */
3038 len = sizeof(my_addr);
3039 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3040 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3041 if (content_length < 0) {
3042 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3045 rtsp_reply_header(c, RTSP_STATUS_OK);
3046 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3047 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3048 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3049 avio_printf(c->pb, "\r\n");
3050 avio_write(c->pb, content, content_length);
3054 static HTTPContext *find_rtp_session(const char *session_id)
3058 if (session_id[0] == '\0')
3061 for(c = first_http_ctx; c != NULL; c = c->next) {
3062 if (!strcmp(c->session_id, session_id))
3068 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3070 RTSPTransportField *th;
3073 for(i=0;i<h->nb_transports;i++) {
3074 th = &h->transports[i];
3075 if (th->lower_transport == lower_transport)
3081 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3082 RTSPMessageHeader *h)
3085 int stream_index, rtp_port, rtcp_port;
3090 RTSPTransportField *th;
3091 struct sockaddr_in dest_addr;
3092 RTSPActionServerSetup setup;
3094 /* find which URL is asked */
3095 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3100 /* now check each stream */
3101 for(stream = first_stream; stream != NULL; stream = stream->next) {
3102 if (!stream->is_feed &&
3103 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3104 /* accept aggregate filenames only if single stream */
3105 if (!strcmp(path, stream->filename)) {
3106 if (stream->nb_streams != 1) {
3107 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3114 for(stream_index = 0; stream_index < stream->nb_streams;
3116 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3117 stream->filename, stream_index);
3118 if (!strcmp(path, buf))
3123 /* no stream found */
3124 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3128 /* generate session id if needed */
3129 if (h->session_id[0] == '\0') {
3130 unsigned random0 = av_lfg_get(&random_state);
3131 unsigned random1 = av_lfg_get(&random_state);
3132 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3136 /* find RTP session, and create it if none found */
3137 rtp_c = find_rtp_session(h->session_id);
3139 /* always prefer UDP */
3140 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3142 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3144 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3149 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3150 th->lower_transport);
3152 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3156 /* open input stream */
3157 if (open_input_stream(rtp_c, "") < 0) {
3158 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3163 /* test if stream is OK (test needed because several SETUP needs
3164 to be done for a given file) */
3165 if (rtp_c->stream != stream) {
3166 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3170 /* test if stream is already set up */
3171 if (rtp_c->rtp_ctx[stream_index]) {
3172 rtsp_reply_error(c, RTSP_STATUS_STATE);
3176 /* check transport */
3177 th = find_transport(h, rtp_c->rtp_protocol);
3178 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3179 th->client_port_min <= 0)) {
3180 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3184 /* setup default options */
3185 setup.transport_option[0] = '\0';
3186 dest_addr = rtp_c->from_addr;
3187 dest_addr.sin_port = htons(th->client_port_min);
3190 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3191 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3195 /* now everything is OK, so we can send the connection parameters */
3196 rtsp_reply_header(c, RTSP_STATUS_OK);
3198 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3200 switch(rtp_c->rtp_protocol) {
3201 case RTSP_LOWER_TRANSPORT_UDP:
3202 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3203 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3204 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3205 "client_port=%d-%d;server_port=%d-%d",
3206 th->client_port_min, th->client_port_max,
3207 rtp_port, rtcp_port);
3209 case RTSP_LOWER_TRANSPORT_TCP:
3210 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3211 stream_index * 2, stream_index * 2 + 1);
3216 if (setup.transport_option[0] != '\0')
3217 avio_printf(c->pb, ";%s", setup.transport_option);
3218 avio_printf(c->pb, "\r\n");
3221 avio_printf(c->pb, "\r\n");
3225 /* find an RTP connection by using the session ID. Check consistency
3227 static HTTPContext *find_rtp_session_with_url(const char *url,
3228 const char *session_id)
3236 rtp_c = find_rtp_session(session_id);
3240 /* find which URL is asked */
3241 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3245 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3246 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3247 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3248 rtp_c->stream->filename, s);
3249 if(!strncmp(path, buf, sizeof(buf))) {
3250 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3255 if (len > 0 && path[len - 1] == '/' &&
3256 !strncmp(path, rtp_c->stream->filename, len - 1))
3261 static void rtsp_cmd_play(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 rtp_c->state != HTTPSTATE_READY) {
3274 rtsp_reply_error(c, RTSP_STATUS_STATE);
3278 rtp_c->state = HTTPSTATE_SEND_DATA;
3280 /* now everything is OK, so we can send the connection parameters */
3281 rtsp_reply_header(c, RTSP_STATUS_OK);
3283 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3284 avio_printf(c->pb, "\r\n");
3287 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3291 rtp_c = find_rtp_session_with_url(url, h->session_id);
3293 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3298 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3299 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3300 rtsp_reply_error(c, RTSP_STATUS_STATE);
3303 rtp_c->state = HTTPSTATE_READY;
3304 rtp_c->first_pts = AV_NOPTS_VALUE;
3307 /* now everything is OK, so we can send the connection parameters */
3308 rtsp_reply_header(c, RTSP_STATUS_OK);
3310 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3311 avio_printf(c->pb, "\r\n");
3314 close_connection(rtp_c);
3317 /********************************************************************/
3320 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3321 FFStream *stream, const char *session_id,
3322 enum RTSPLowerTransport rtp_protocol)
3324 HTTPContext *c = NULL;
3325 const char *proto_str;
3327 /* XXX: should output a warning page when coming
3328 close to the connection limit */
3329 if (nb_connections >= nb_max_connections)
3332 /* add a new connection */
3333 c = av_mallocz(sizeof(HTTPContext));
3338 c->poll_entry = NULL;
3339 c->from_addr = *from_addr;
3340 c->buffer_size = IOBUFFER_INIT_SIZE;
3341 c->buffer = av_malloc(c->buffer_size);
3346 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3347 c->state = HTTPSTATE_READY;
3348 c->is_packetized = 1;
3349 c->rtp_protocol = rtp_protocol;
3351 /* protocol is shown in statistics */
3352 switch(c->rtp_protocol) {
3353 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3354 proto_str = "MCAST";
3356 case RTSP_LOWER_TRANSPORT_UDP:
3359 case RTSP_LOWER_TRANSPORT_TCP:
3366 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3367 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3369 current_bandwidth += stream->bandwidth;
3371 c->next = first_http_ctx;
3383 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3384 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3386 static int rtp_new_av_stream(HTTPContext *c,
3387 int stream_index, struct sockaddr_in *dest_addr,
3388 HTTPContext *rtsp_c)
3390 AVFormatContext *ctx;
3393 URLContext *h = NULL;
3395 int max_packet_size;
3397 /* now we can open the relevant output stream */
3398 ctx = avformat_alloc_context();
3401 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3403 st = av_mallocz(sizeof(AVStream));
3406 ctx->nb_streams = 1;
3407 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3410 ctx->streams[0] = st;
3412 if (!c->stream->feed ||
3413 c->stream->feed == c->stream)
3414 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3417 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3419 st->priv_data = NULL;
3421 /* build destination RTP address */
3422 ipaddr = inet_ntoa(dest_addr->sin_addr);
3424 switch(c->rtp_protocol) {
3425 case RTSP_LOWER_TRANSPORT_UDP:
3426 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3429 /* XXX: also pass as parameter to function ? */
3430 if (c->stream->is_multicast) {
3432 ttl = c->stream->multicast_ttl;
3435 snprintf(ctx->filename, sizeof(ctx->filename),
3436 "rtp://%s:%d?multicast=1&ttl=%d",
3437 ipaddr, ntohs(dest_addr->sin_port), ttl);
3439 snprintf(ctx->filename, sizeof(ctx->filename),
3440 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3443 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3445 c->rtp_handles[stream_index] = h;
3446 max_packet_size = h->max_packet_size;
3448 case RTSP_LOWER_TRANSPORT_TCP:
3451 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3457 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3458 ipaddr, ntohs(dest_addr->sin_port),
3459 c->stream->filename, stream_index, c->protocol);
3461 /* normally, no packets should be output here, but the packet size may
3463 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3464 /* XXX: close stream */
3467 if (avformat_write_header(ctx, NULL) < 0) {
3474 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3477 c->rtp_ctx[stream_index] = ctx;
3481 /********************************************************************/
3482 /* ffserver initialization */
3484 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3488 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3491 fst = av_mallocz(sizeof(AVStream));
3495 fst->codec = avcodec_alloc_context3(NULL);
3496 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3497 if (codec->extradata_size) {
3498 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3499 memcpy(fst->codec->extradata, codec->extradata,
3500 codec->extradata_size);
3503 /* live streams must use the actual feed's codec since it may be
3504 * updated later to carry extradata needed by them.
3508 fst->priv_data = av_mallocz(sizeof(FeedData));
3509 fst->index = stream->nb_streams;
3510 avpriv_set_pts_info(fst, 33, 1, 90000);
3511 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3512 stream->streams[stream->nb_streams++] = fst;
3516 /* return the stream number in the feed */
3517 static int add_av_stream(FFStream *feed, AVStream *st)
3520 AVCodecContext *av, *av1;
3524 for(i=0;i<feed->nb_streams;i++) {
3525 st = feed->streams[i];
3527 if (av1->codec_id == av->codec_id &&
3528 av1->codec_type == av->codec_type &&
3529 av1->bit_rate == av->bit_rate) {
3531 switch(av->codec_type) {
3532 case AVMEDIA_TYPE_AUDIO:
3533 if (av1->channels == av->channels &&
3534 av1->sample_rate == av->sample_rate)
3537 case AVMEDIA_TYPE_VIDEO:
3538 if (av1->width == av->width &&
3539 av1->height == av->height &&
3540 av1->time_base.den == av->time_base.den &&
3541 av1->time_base.num == av->time_base.num &&
3542 av1->gop_size == av->gop_size)
3551 fst = add_av_stream1(feed, av, 0);
3554 return feed->nb_streams - 1;
3557 static void remove_stream(FFStream *stream)
3561 while (*ps != NULL) {
3569 /* specific MPEG4 handling : we extract the raw parameters */
3570 static void extract_mpeg4_header(AVFormatContext *infile)
3572 int mpeg4_count, i, size;
3577 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3580 for(i=0;i<infile->nb_streams;i++) {
3581 st = infile->streams[i];
3582 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3583 st->codec->extradata_size == 0) {
3590 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3591 while (mpeg4_count > 0) {
3592 if (av_read_frame(infile, &pkt) < 0)
3594 st = infile->streams[pkt.stream_index];
3595 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3596 st->codec->extradata_size == 0) {
3597 av_freep(&st->codec->extradata);
3598 /* fill extradata with the header */
3599 /* XXX: we make hard suppositions here ! */
3601 while (p < pkt.data + pkt.size - 4) {
3602 /* stop when vop header is found */
3603 if (p[0] == 0x00 && p[1] == 0x00 &&
3604 p[2] == 0x01 && p[3] == 0xb6) {
3605 size = p - pkt.data;
3606 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3607 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3608 st->codec->extradata_size = size;
3609 memcpy(st->codec->extradata, pkt.data, size);
3616 av_free_packet(&pkt);
3620 /* compute the needed AVStream for each file */
3621 static void build_file_streams(void)
3623 FFStream *stream, *stream_next;
3626 /* gather all streams */
3627 for(stream = first_stream; stream != NULL; stream = stream_next) {
3628 AVFormatContext *infile = NULL;
3629 stream_next = stream->next;
3630 if (stream->stream_type == STREAM_TYPE_LIVE &&
3632 /* the stream comes from a file */
3633 /* try to open the file */
3635 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3636 /* specific case : if transport stream output to RTP,
3637 we use a raw transport stream reader */
3638 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3641 if (!stream->feed_filename[0]) {
3642 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3646 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3647 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3648 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3649 /* remove stream (no need to spend more time on it) */
3651 remove_stream(stream);
3653 /* find all the AVStreams inside and reference them in
3655 if (avformat_find_stream_info(infile, NULL) < 0) {
3656 http_log("Could not find codec parameters from '%s'\n",
3657 stream->feed_filename);
3658 avformat_close_input(&infile);
3661 extract_mpeg4_header(infile);
3663 for(i=0;i<infile->nb_streams;i++)
3664 add_av_stream1(stream, infile->streams[i]->codec, 1);
3666 avformat_close_input(&infile);
3672 /* compute the needed AVStream for each feed */
3673 static void build_feed_streams(void)