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/random_seed.h"
53 #include "libavutil/parseutils.h"
54 #include "libavutil/opt.h"
55 #include "libavutil/time.h"
62 #include <sys/ioctl.h>
72 #include "ffserver_config.h"
74 const char program_name[] = "ffserver";
75 const int program_birth_year = 2000;
77 static const OptionDef options[];
80 HTTPSTATE_WAIT_REQUEST,
81 HTTPSTATE_SEND_HEADER,
82 HTTPSTATE_SEND_DATA_HEADER,
83 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
84 HTTPSTATE_SEND_DATA_TRAILER,
85 HTTPSTATE_RECEIVE_DATA,
86 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
89 RTSPSTATE_WAIT_REQUEST,
91 RTSPSTATE_SEND_PACKET,
94 static const char * const http_state[] = {
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 FFServerStream *stream;
158 /* -1 is invalid stream */
159 int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
160 int switch_feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
162 AVFormatContext fmt_ctx; /* instance of FFServerStream 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[FFSERVER_MAX_STREAMS];
185 /* RTP/UDP specific */
186 URLContext *rtp_handles[FFSERVER_MAX_STREAMS];
188 /* RTP/TCP specific */
189 struct HTTPContext *rtsp_c;
190 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
193 typedef struct FeedData {
194 long long data_count;
195 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
198 static HTTPContext *first_http_ctx;
200 static FFServerConfig config = {
201 .nb_max_http_connections = 2000,
202 .nb_max_connections = 5,
203 .max_bandwidth = 1000,
207 static void new_connection(int server_fd, int is_rtsp);
208 static void close_connection(HTTPContext *c);
211 static int handle_connection(HTTPContext *c);
212 static int http_parse_request(HTTPContext *c);
213 static int http_send_data(HTTPContext *c);
214 static void compute_status(HTTPContext *c);
215 static int open_input_stream(HTTPContext *c, const char *info);
216 static int http_start_receive_data(HTTPContext *c);
217 static int http_receive_data(HTTPContext *c);
220 static int rtsp_parse_request(HTTPContext *c);
221 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
222 static void rtsp_cmd_options(HTTPContext *c, const char *url);
223 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
224 RTSPMessageHeader *h);
225 static void rtsp_cmd_play(HTTPContext *c, const char *url,
226 RTSPMessageHeader *h);
227 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
228 RTSPMessageHeader *h, int pause_only);
231 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
232 struct in_addr my_ip);
235 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
236 FFServerStream *stream,
237 const char *session_id,
238 enum RTSPLowerTransport rtp_protocol);
239 static int rtp_new_av_stream(HTTPContext *c,
240 int stream_index, struct sockaddr_in *dest_addr,
241 HTTPContext *rtsp_c);
243 static const char *my_program_name;
245 static int no_launch;
246 static int need_to_start_children;
248 /* maximum number of simultaneous HTTP connections */
249 static unsigned int nb_connections;
251 static uint64_t current_bandwidth;
253 static int64_t cur_time; // Making this global saves on passing it around everywhere
255 static AVLFG random_state;
257 static FILE *logfile = NULL;
259 static void htmlstrip(char *s) {
261 s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
267 static int64_t ffm_read_write_index(int fd)
271 if (lseek(fd, 8, SEEK_SET) < 0)
273 if (read(fd, buf, 8) != 8)
278 static int ffm_write_write_index(int fd, int64_t pos)
284 buf[i] = (pos >> (56 - i * 8)) & 0xff;
285 if (lseek(fd, 8, SEEK_SET) < 0)
287 if (write(fd, buf, 8) != 8)
292 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
295 FFMContext *ffm = s->priv_data;
296 ffm->write_index = pos;
297 ffm->file_size = file_size;
300 static char *ctime1(char *buf2, int buf_size)
307 av_strlcpy(buf2, p, buf_size);
308 p = buf2 + strlen(p) - 1;
314 static void http_vlog(const char *fmt, va_list vargs)
316 static int print_prefix = 1;
323 ctime1(buf, sizeof(buf));
324 fprintf(logfile, "%s ", buf);
326 print_prefix = strstr(fmt, "\n") != NULL;
327 vfprintf(logfile, fmt, vargs);
332 __attribute__ ((format (printf, 1, 2)))
334 static void http_log(const char *fmt, ...)
337 va_start(vargs, fmt);
338 http_vlog(fmt, vargs);
342 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
344 static int print_prefix = 1;
345 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
346 if (level > av_log_get_level())
348 if (print_prefix && avc)
349 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
350 print_prefix = strstr(fmt, "\n") != NULL;
351 http_vlog(fmt, vargs);
354 static void log_connection(HTTPContext *c)
359 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
360 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
361 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
364 static void update_datarate(DataRateData *drd, int64_t count)
366 if (!drd->time1 && !drd->count1) {
367 drd->time1 = drd->time2 = cur_time;
368 drd->count1 = drd->count2 = count;
369 } else if (cur_time - drd->time2 > 5000) {
370 drd->time1 = drd->time2;
371 drd->count1 = drd->count2;
372 drd->time2 = cur_time;
377 /* In bytes per second */
378 static int compute_datarate(DataRateData *drd, int64_t count)
380 if (cur_time == drd->time1)
383 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
387 static void start_children(FFServerStream *feed)
396 /* replace "ffserver" with "ffmpeg" in the path of current
397 * program. Ignore user provided path */
398 av_strlcpy(pathname, my_program_name, sizeof(pathname));
400 slash = strrchr(pathname, '/');
405 strcpy(slash, "ffmpeg");
407 for (; feed; feed = feed->next) {
409 if (!feed->child_argv || feed->pid)
412 feed->pid_start = time(0);
416 http_log("Unable to create children\n");
425 http_log("Launch command line: ");
426 http_log("%s ", pathname);
428 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
429 http_log("%s ", feed->child_argv[i]);
432 for (i = 3; i < 256; i++)
436 if (!freopen("/dev/null", "r", stdin))
437 http_log("failed to redirect STDIN to /dev/null\n;");
438 if (!freopen("/dev/null", "w", stdout))
439 http_log("failed to redirect STDOUT to /dev/null\n;");
440 if (!freopen("/dev/null", "w", stderr))
441 http_log("failed to redirect STDERR to /dev/null\n;");
444 signal(SIGPIPE, SIG_DFL);
445 execvp(pathname, feed->child_argv);
450 /* open a listening socket */
451 static int socket_open_listen(struct sockaddr_in *my_addr)
455 server_fd = socket(AF_INET,SOCK_STREAM,0);
462 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)))
463 av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n");
465 my_addr->sin_family = AF_INET;
466 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
468 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
470 closesocket(server_fd);
474 if (listen (server_fd, 5) < 0) {
476 closesocket(server_fd);
480 if (ff_socket_nonblock(server_fd, 1) < 0)
481 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
486 /* start all multicast streams */
487 static void start_multicast(void)
489 FFServerStream *stream;
492 struct sockaddr_in dest_addr = {0};
493 int default_port, stream_index;
494 unsigned int random0, random1;
497 for(stream = config.first_stream; stream; stream = stream->next) {
499 if (!stream->is_multicast)
502 random0 = av_lfg_get(&random_state);
503 random1 = av_lfg_get(&random_state);
505 /* open the RTP connection */
506 snprintf(session_id, sizeof(session_id), "%08x%08x",
509 /* choose a port if none given */
510 if (stream->multicast_port == 0) {
511 stream->multicast_port = default_port;
515 dest_addr.sin_family = AF_INET;
516 dest_addr.sin_addr = stream->multicast_ip;
517 dest_addr.sin_port = htons(stream->multicast_port);
519 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
520 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
524 if (open_input_stream(rtp_c, "") < 0) {
525 http_log("Could not open input stream for stream '%s'\n",
530 /* open each RTP stream */
531 for(stream_index = 0; stream_index < stream->nb_streams;
533 dest_addr.sin_port = htons(stream->multicast_port +
535 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) >= 0)
538 http_log("Could not open output stream '%s/streamid=%d'\n",
539 stream->filename, stream_index);
543 rtp_c->state = HTTPSTATE_SEND_DATA;
547 /* main loop of the HTTP server */
548 static int http_server(void)
550 int server_fd = 0, rtsp_server_fd = 0;
552 struct pollfd *poll_table, *poll_entry;
553 HTTPContext *c, *c_next;
555 poll_table = av_mallocz_array(config.nb_max_http_connections + 2,
556 sizeof(*poll_table));
558 http_log("Impossible to allocate a poll table handling %d "
559 "connections.\n", config.nb_max_http_connections);
563 if (config.http_addr.sin_port) {
564 server_fd = socket_open_listen(&config.http_addr);
571 if (config.rtsp_addr.sin_port) {
572 rtsp_server_fd = socket_open_listen(&config.rtsp_addr);
573 if (rtsp_server_fd < 0) {
575 closesocket(server_fd);
580 if (!rtsp_server_fd && !server_fd) {
581 http_log("HTTP and RTSP disabled.\n");
586 http_log("FFserver started.\n");
588 start_children(config.first_feed);
593 poll_entry = poll_table;
595 poll_entry->fd = server_fd;
596 poll_entry->events = POLLIN;
599 if (rtsp_server_fd) {
600 poll_entry->fd = rtsp_server_fd;
601 poll_entry->events = POLLIN;
605 /* wait for events on each HTTP handle */
612 case HTTPSTATE_SEND_HEADER:
613 case RTSPSTATE_SEND_REPLY:
614 case RTSPSTATE_SEND_PACKET:
615 c->poll_entry = poll_entry;
617 poll_entry->events = POLLOUT;
620 case HTTPSTATE_SEND_DATA_HEADER:
621 case HTTPSTATE_SEND_DATA:
622 case HTTPSTATE_SEND_DATA_TRAILER:
623 if (!c->is_packetized) {
624 /* for TCP, we output as much as we can
625 * (may need to put a limit) */
626 c->poll_entry = poll_entry;
628 poll_entry->events = POLLOUT;
631 /* when ffserver is doing the timing, we work by
632 looking at which packet needs to be sent every
634 /* one tick wait XXX: 10 ms assumed */
639 case HTTPSTATE_WAIT_REQUEST:
640 case HTTPSTATE_RECEIVE_DATA:
641 case HTTPSTATE_WAIT_FEED:
642 case RTSPSTATE_WAIT_REQUEST:
643 /* need to catch errors */
644 c->poll_entry = poll_entry;
646 poll_entry->events = POLLIN;/* Maybe this will work */
650 c->poll_entry = NULL;
656 /* wait for an event on one connection. We poll at least every
657 second to handle timeouts */
659 ret = poll(poll_table, poll_entry - poll_table, delay);
660 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
661 ff_neterrno() != AVERROR(EINTR)) {
667 cur_time = av_gettime() / 1000;
669 if (need_to_start_children) {
670 need_to_start_children = 0;
671 start_children(config.first_feed);
674 /* now handle the events */
675 for(c = first_http_ctx; c; c = c_next) {
677 if (handle_connection(c) < 0) {
679 /* close and free the connection */
684 poll_entry = poll_table;
686 /* new HTTP connection request ? */
687 if (poll_entry->revents & POLLIN)
688 new_connection(server_fd, 0);
691 if (rtsp_server_fd) {
692 /* new RTSP connection request ? */
693 if (poll_entry->revents & POLLIN)
694 new_connection(rtsp_server_fd, 1);
699 /* start waiting for a new HTTP/RTSP request */
700 static void start_wait_request(HTTPContext *c, int is_rtsp)
702 c->buffer_ptr = c->buffer;
703 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
706 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
707 c->state = RTSPSTATE_WAIT_REQUEST;
709 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
710 c->state = HTTPSTATE_WAIT_REQUEST;
714 static void http_send_too_busy_reply(int fd)
717 int len = snprintf(buffer, sizeof(buffer),
718 "HTTP/1.0 503 Server too busy\r\n"
719 "Content-type: text/html\r\n"
721 "<html><head><title>Too busy</title></head><body>\r\n"
722 "<p>The server is too busy to serve your request at this time.</p>\r\n"
723 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
724 "</body></html>\r\n",
725 nb_connections, config.nb_max_connections);
726 av_assert0(len < sizeof(buffer));
727 if (send(fd, buffer, len, 0) < len)
728 av_log(NULL, AV_LOG_WARNING, "Could not send too-busy reply, send() failed\n");
732 static void new_connection(int server_fd, int is_rtsp)
734 struct sockaddr_in from_addr;
737 HTTPContext *c = NULL;
739 len = sizeof(from_addr);
740 fd = accept(server_fd, (struct sockaddr *)&from_addr,
743 http_log("error during accept %s\n", strerror(errno));
746 if (ff_socket_nonblock(fd, 1) < 0)
747 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
749 if (nb_connections >= config.nb_max_connections) {
750 http_send_too_busy_reply(fd);
754 /* add a new connection */
755 c = av_mallocz(sizeof(HTTPContext));
760 c->poll_entry = NULL;
761 c->from_addr = from_addr;
762 c->buffer_size = IOBUFFER_INIT_SIZE;
763 c->buffer = av_malloc(c->buffer_size);
767 c->next = first_http_ctx;
771 start_wait_request(c, is_rtsp);
777 av_freep(&c->buffer);
783 static void close_connection(HTTPContext *c)
785 HTTPContext **cp, *c1;
787 AVFormatContext *ctx;
791 /* remove connection from list */
792 cp = &first_http_ctx;
801 /* remove references, if any (XXX: do it faster) */
802 for(c1 = first_http_ctx; c1; c1 = c1->next) {
807 /* remove connection associated resources */
811 /* close each frame parser */
812 for(i=0;i<c->fmt_in->nb_streams;i++) {
813 st = c->fmt_in->streams[i];
814 if (st->codec->codec)
815 avcodec_close(st->codec);
817 avformat_close_input(&c->fmt_in);
820 /* free RTP output streams if any */
823 nb_streams = c->stream->nb_streams;
825 for(i=0;i<nb_streams;i++) {
828 av_write_trailer(ctx);
829 av_dict_free(&ctx->metadata);
830 av_freep(&ctx->streams[0]);
833 h = c->rtp_handles[i];
840 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
842 if (ctx->oformat && avio_open_dyn_buf(&ctx->pb) >= 0) {
843 av_write_trailer(ctx);
844 av_freep(&c->pb_buffer);
845 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
849 for(i=0; i<ctx->nb_streams; i++)
850 av_freep(&ctx->streams[i]);
851 av_freep(&ctx->streams);
852 av_freep(&ctx->priv_data);
854 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
855 current_bandwidth -= c->stream->bandwidth;
857 /* signal that there is no feed if we are the feeder socket */
858 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
859 c->stream->feed_opened = 0;
863 av_freep(&c->pb_buffer);
864 av_freep(&c->packet_buffer);
865 av_freep(&c->buffer);
870 static int handle_connection(HTTPContext *c)
876 case HTTPSTATE_WAIT_REQUEST:
877 case RTSPSTATE_WAIT_REQUEST:
879 if ((c->timeout - cur_time) < 0)
881 if (c->poll_entry->revents & (POLLERR | POLLHUP))
884 /* no need to read if no events */
885 if (!(c->poll_entry->revents & POLLIN))
889 if (!(len = recv(c->fd, c->buffer_ptr, 1, 0)))
893 if (ff_neterrno() != AVERROR(EAGAIN) &&
894 ff_neterrno() != AVERROR(EINTR))
898 /* search for end of request. */
899 c->buffer_ptr += len;
901 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
902 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
903 /* request found : parse it and reply */
904 if (c->state == HTTPSTATE_WAIT_REQUEST) {
905 ret = http_parse_request(c);
907 ret = rtsp_parse_request(c);
911 } else if (ptr >= c->buffer_end) {
912 /* request too long: cannot do anything */
914 } else goto read_loop;
918 case HTTPSTATE_SEND_HEADER:
919 if (c->poll_entry->revents & (POLLERR | POLLHUP))
922 /* no need to write if no events */
923 if (!(c->poll_entry->revents & POLLOUT))
925 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
927 if (ff_neterrno() != AVERROR(EAGAIN) &&
928 ff_neterrno() != AVERROR(EINTR)) {
929 goto close_connection;
933 c->buffer_ptr += len;
935 c->stream->bytes_served += len;
936 c->data_count += len;
937 if (c->buffer_ptr >= c->buffer_end) {
938 av_freep(&c->pb_buffer);
942 /* all the buffer was sent : synchronize to the incoming
944 c->state = HTTPSTATE_SEND_DATA_HEADER;
945 c->buffer_ptr = c->buffer_end = c->buffer;
949 case HTTPSTATE_SEND_DATA:
950 case HTTPSTATE_SEND_DATA_HEADER:
951 case HTTPSTATE_SEND_DATA_TRAILER:
952 /* for packetized output, we consider we can always write (the
953 input streams set the speed). It may be better to verify
954 that we do not rely too much on the kernel queues */
955 if (!c->is_packetized) {
956 if (c->poll_entry->revents & (POLLERR | POLLHUP))
959 /* no need to read if no events */
960 if (!(c->poll_entry->revents & POLLOUT))
963 if (http_send_data(c) < 0)
965 /* close connection if trailer sent */
966 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
969 case HTTPSTATE_RECEIVE_DATA:
970 /* no need to read if no events */
971 if (c->poll_entry->revents & (POLLERR | POLLHUP))
973 if (!(c->poll_entry->revents & POLLIN))
975 if (http_receive_data(c) < 0)
978 case HTTPSTATE_WAIT_FEED:
979 /* no need to read if no events */
980 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
983 /* nothing to do, we'll be waken up by incoming feed packets */
986 case RTSPSTATE_SEND_REPLY:
987 if (c->poll_entry->revents & (POLLERR | POLLHUP))
988 goto close_connection;
989 /* no need to write if no events */
990 if (!(c->poll_entry->revents & POLLOUT))
992 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
994 if (ff_neterrno() != AVERROR(EAGAIN) &&
995 ff_neterrno() != AVERROR(EINTR)) {
996 goto close_connection;
1000 c->buffer_ptr += len;
1001 c->data_count += len;
1002 if (c->buffer_ptr >= c->buffer_end) {
1003 /* all the buffer was sent : wait for a new request */
1004 av_freep(&c->pb_buffer);
1005 start_wait_request(c, 1);
1008 case RTSPSTATE_SEND_PACKET:
1009 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1010 av_freep(&c->packet_buffer);
1013 /* no need to write if no events */
1014 if (!(c->poll_entry->revents & POLLOUT))
1016 len = send(c->fd, c->packet_buffer_ptr,
1017 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1019 if (ff_neterrno() != AVERROR(EAGAIN) &&
1020 ff_neterrno() != AVERROR(EINTR)) {
1021 /* error : close connection */
1022 av_freep(&c->packet_buffer);
1027 c->packet_buffer_ptr += len;
1028 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1029 /* all the buffer was sent : wait for a new request */
1030 av_freep(&c->packet_buffer);
1031 c->state = RTSPSTATE_WAIT_REQUEST;
1034 case HTTPSTATE_READY:
1043 av_freep(&c->pb_buffer);
1047 static int extract_rates(char *rates, int ratelen, const char *request)
1051 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1052 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1053 const char *q = p + 7;
1055 while (*q && *q != '\n' && av_isspace(*q))
1058 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1064 memset(rates, 0xff, ratelen);
1067 while (*q && *q != '\n' && *q != ':')
1070 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1074 if (stream_no < ratelen && stream_no >= 0)
1075 rates[stream_no] = rate_no;
1077 while (*q && *q != '\n' && !av_isspace(*q))
1084 p = strchr(p, '\n');
1094 static int find_stream_in_feed(FFServerStream *feed, AVCodecContext *codec, int bit_rate)
1097 int best_bitrate = 100000000;
1100 for (i = 0; i < feed->nb_streams; i++) {
1101 AVCodecContext *feed_codec = feed->streams[i]->codec;
1103 if (feed_codec->codec_id != codec->codec_id ||
1104 feed_codec->sample_rate != codec->sample_rate ||
1105 feed_codec->width != codec->width ||
1106 feed_codec->height != codec->height)
1109 /* Potential stream */
1111 /* We want the fastest stream less than bit_rate, or the slowest
1112 * faster than bit_rate
1115 if (feed_codec->bit_rate <= bit_rate) {
1116 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1117 best_bitrate = feed_codec->bit_rate;
1122 if (feed_codec->bit_rate < best_bitrate) {
1123 best_bitrate = feed_codec->bit_rate;
1130 static int modify_current_stream(HTTPContext *c, char *rates)
1133 FFServerStream *req = c->stream;
1134 int action_required = 0;
1136 /* Not much we can do for a feed */
1140 for (i = 0; i < req->nb_streams; i++) {
1141 AVCodecContext *codec = req->streams[i]->codec;
1145 c->switch_feed_streams[i] = req->feed_streams[i];
1148 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1151 /* Wants off or slow */
1152 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1154 /* This doesn't work well when it turns off the only stream! */
1155 c->switch_feed_streams[i] = -2;
1156 c->feed_streams[i] = -2;
1161 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1162 action_required = 1;
1165 return action_required;
1168 static void get_word(char *buf, int buf_size, const char **pp)
1174 p += strspn(p, SPACE_CHARS);
1176 while (!av_isspace(*p) && *p != '\0') {
1177 if ((q - buf) < buf_size - 1)
1186 static FFServerIPAddressACL* parse_dynamic_acl(FFServerStream *stream, HTTPContext *c)
1191 FFServerIPAddressACL *acl = NULL;
1195 f = fopen(stream->dynamic_acl, "r");
1197 perror(stream->dynamic_acl);
1201 acl = av_mallocz(sizeof(FFServerIPAddressACL));
1204 while (fgets(line, sizeof(line), f)) {
1207 while (av_isspace(*p))
1209 if (*p == '\0' || *p == '#')
1211 ffserver_get_arg(cmd, sizeof(cmd), &p);
1213 if (!av_strcasecmp(cmd, "ACL"))
1214 ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1221 static void free_acl_list(FFServerIPAddressACL *in_acl)
1223 FFServerIPAddressACL *pacl, *pacl2;
1233 static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c)
1235 enum FFServerIPAddressAction last_action = IP_DENY;
1236 FFServerIPAddressACL *acl;
1237 struct in_addr *src = &c->from_addr.sin_addr;
1238 unsigned long src_addr = src->s_addr;
1240 for (acl = in_acl; acl; acl = acl->next) {
1241 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1242 return (acl->action == IP_ALLOW) ? 1 : 0;
1243 last_action = acl->action;
1246 /* Nothing matched, so return not the last action */
1247 return (last_action == IP_DENY) ? 1 : 0;
1250 static int validate_acl(FFServerStream *stream, HTTPContext *c)
1253 FFServerIPAddressACL *acl;
1255 /* if stream->acl is null validate_acl_list will return 1 */
1256 ret = validate_acl_list(stream->acl, c);
1258 if (stream->dynamic_acl[0]) {
1259 acl = parse_dynamic_acl(stream, c);
1261 ret = validate_acl_list(acl, c);
1269 /* compute the real filename of a file by matching it without its
1270 extensions to all the stream's filenames */
1271 static void compute_real_filename(char *filename, int max_size)
1276 FFServerStream *stream;
1278 /* compute filename by matching without the file extensions */
1279 av_strlcpy(file1, filename, sizeof(file1));
1280 p = strrchr(file1, '.');
1283 for(stream = config.first_stream; stream; stream = stream->next) {
1284 av_strlcpy(file2, stream->filename, sizeof(file2));
1285 p = strrchr(file2, '.');
1288 if (!strcmp(file1, file2)) {
1289 av_strlcpy(filename, stream->filename, max_size);
1304 /* parse HTTP request and prepare header */
1305 static int http_parse_request(HTTPContext *c)
1309 enum RedirType redir_type;
1311 char info[1024], filename[1024];
1315 const char *mime_type;
1316 FFServerStream *stream;
1319 const char *useragent = 0;
1322 get_word(cmd, sizeof(cmd), &p);
1323 av_strlcpy(c->method, cmd, sizeof(c->method));
1325 if (!strcmp(cmd, "GET"))
1327 else if (!strcmp(cmd, "POST"))
1332 get_word(url, sizeof(url), &p);
1333 av_strlcpy(c->url, url, sizeof(c->url));
1335 get_word(protocol, sizeof(protocol), (const char **)&p);
1336 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1339 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1342 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1344 /* find the filename and the optional info string in the request */
1345 p1 = strchr(url, '?');
1347 av_strlcpy(info, p1, sizeof(info));
1352 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1354 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1355 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1357 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1361 p = strchr(p, '\n');
1368 redir_type = REDIR_NONE;
1369 if (av_match_ext(filename, "asx")) {
1370 redir_type = REDIR_ASX;
1371 filename[strlen(filename)-1] = 'f';
1372 } else if (av_match_ext(filename, "asf") &&
1373 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) {
1374 /* if this isn't WMP or lookalike, return the redirector file */
1375 redir_type = REDIR_ASF;
1376 } else if (av_match_ext(filename, "rpm,ram")) {
1377 redir_type = REDIR_RAM;
1378 strcpy(filename + strlen(filename)-2, "m");
1379 } else if (av_match_ext(filename, "rtsp")) {
1380 redir_type = REDIR_RTSP;
1381 compute_real_filename(filename, sizeof(filename) - 1);
1382 } else if (av_match_ext(filename, "sdp")) {
1383 redir_type = REDIR_SDP;
1384 compute_real_filename(filename, sizeof(filename) - 1);
1387 // "redirect" / request to index.html
1388 if (!strlen(filename))
1389 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1391 stream = config.first_stream;
1393 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1395 stream = stream->next;
1398 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1399 http_log("File '%s' not found\n", url);
1404 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1405 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1407 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1408 c->http_error = 301;
1410 snprintf(q, c->buffer_size,
1411 "HTTP/1.0 301 Moved\r\n"
1413 "Content-type: text/html\r\n"
1415 "<html><head><title>Moved</title></head><body>\r\n"
1416 "You should be <a href=\"%s\">redirected</a>.\r\n"
1417 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1419 /* prepare output buffer */
1420 c->buffer_ptr = c->buffer;
1422 c->state = HTTPSTATE_SEND_HEADER;
1426 /* If this is WMP, get the rate information */
1427 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1428 if (modify_current_stream(c, ratebuf)) {
1429 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1430 if (c->switch_feed_streams[i] >= 0)
1431 c->switch_feed_streams[i] = -1;
1436 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1437 current_bandwidth += stream->bandwidth;
1439 /* If already streaming this feed, do not let start another feeder. */
1440 if (stream->feed_opened) {
1441 snprintf(msg, sizeof(msg), "This feed is already being received.");
1442 http_log("Feed '%s' already being received\n", stream->feed_filename);
1446 if (c->post == 0 && config.max_bandwidth < current_bandwidth) {
1447 c->http_error = 503;
1449 snprintf(q, c->buffer_size,
1450 "HTTP/1.0 503 Server too busy\r\n"
1451 "Content-type: text/html\r\n"
1453 "<html><head><title>Too busy</title></head><body>\r\n"
1454 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1455 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1456 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1457 "</body></html>\r\n", current_bandwidth, config.max_bandwidth);
1459 /* prepare output buffer */
1460 c->buffer_ptr = c->buffer;
1462 c->state = HTTPSTATE_SEND_HEADER;
1466 if (redir_type != REDIR_NONE) {
1467 const char *hostinfo = 0;
1469 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1470 if (av_strncasecmp(p, "Host:", 5) == 0) {
1474 p = strchr(p, '\n');
1485 while (av_isspace(*hostinfo))
1488 eoh = strchr(hostinfo, '\n');
1490 if (eoh[-1] == '\r')
1493 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1494 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1495 hostbuf[eoh - hostinfo] = 0;
1497 c->http_error = 200;
1499 switch(redir_type) {
1501 snprintf(q, c->buffer_size,
1502 "HTTP/1.0 200 ASX Follows\r\n"
1503 "Content-type: video/x-ms-asf\r\n"
1505 "<ASX Version=\"3\">\r\n"
1506 //"<!-- Autogenerated by ffserver -->\r\n"
1507 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1508 "</ASX>\r\n", hostbuf, filename, info);
1512 snprintf(q, c->buffer_size,
1513 "HTTP/1.0 200 RAM Follows\r\n"
1514 "Content-type: audio/x-pn-realaudio\r\n"
1516 "# Autogenerated by ffserver\r\n"
1517 "http://%s/%s%s\r\n", hostbuf, filename, info);
1521 snprintf(q, c->buffer_size,
1522 "HTTP/1.0 200 ASF Redirect follows\r\n"
1523 "Content-type: video/x-ms-asf\r\n"
1526 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1531 char hostname[256], *p;
1532 /* extract only hostname */
1533 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1534 p = strrchr(hostname, ':');
1537 snprintf(q, c->buffer_size,
1538 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1539 /* XXX: incorrect MIME type ? */
1540 "Content-type: application/x-rtsp\r\n"
1542 "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
1551 struct sockaddr_in my_addr;
1553 snprintf(q, c->buffer_size,
1554 "HTTP/1.0 200 OK\r\n"
1555 "Content-type: application/sdp\r\n"
1559 len = sizeof(my_addr);
1561 /* XXX: Should probably fail? */
1562 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1563 http_log("getsockname() failed\n");
1565 /* XXX: should use a dynamic buffer */
1566 sdp_data_size = prepare_sdp_description(stream,
1569 if (sdp_data_size > 0) {
1570 memcpy(q, sdp_data, sdp_data_size);
1582 /* prepare output buffer */
1583 c->buffer_ptr = c->buffer;
1585 c->state = HTTPSTATE_SEND_HEADER;
1591 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1595 stream->conns_served++;
1597 /* XXX: add there authenticate and IP match */
1600 /* if post, it means a feed is being sent */
1601 if (!stream->is_feed) {
1602 /* However it might be a status report from WMP! Let us log the
1603 * data as it might come handy one day. */
1604 const char *logline = 0;
1607 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1608 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1612 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1613 client_id = strtol(p + 18, 0, 10);
1614 p = strchr(p, '\n');
1622 char *eol = strchr(logline, '\n');
1627 if (eol[-1] == '\r')
1629 http_log("%.*s\n", (int) (eol - logline), logline);
1630 c->suppress_log = 1;
1635 http_log("\nGot request:\n%s\n", c->buffer);
1638 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1641 /* Now we have to find the client_id */
1642 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1643 if (wmpc->wmp_client_id == client_id)
1647 if (wmpc && modify_current_stream(wmpc, ratebuf))
1648 wmpc->switch_pending = 1;
1651 snprintf(msg, sizeof(msg), "POST command not handled");
1655 if (http_start_receive_data(c) < 0) {
1656 snprintf(msg, sizeof(msg), "could not open feed");
1660 c->state = HTTPSTATE_RECEIVE_DATA;
1665 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1666 http_log("\nGot request:\n%s\n", c->buffer);
1669 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1672 /* open input stream */
1673 if (open_input_stream(c, info) < 0) {
1674 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1678 /* prepare HTTP header */
1680 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1681 mime_type = c->stream->fmt->mime_type;
1683 mime_type = "application/x-octet-stream";
1684 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1686 /* for asf, we need extra headers */
1687 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1688 /* Need to allocate a client id */
1690 c->wmp_client_id = av_lfg_get(&random_state);
1692 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);
1694 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1695 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1696 q = c->buffer + strlen(c->buffer);
1698 /* prepare output buffer */
1700 c->buffer_ptr = c->buffer;
1702 c->state = HTTPSTATE_SEND_HEADER;
1705 c->http_error = 404;
1708 snprintf(q, c->buffer_size,
1709 "HTTP/1.0 404 Not Found\r\n"
1710 "Content-type: text/html\r\n"
1713 "<head><title>404 Not Found</title></head>\n"
1717 /* prepare output buffer */
1718 c->buffer_ptr = c->buffer;
1720 c->state = HTTPSTATE_SEND_HEADER;
1724 c->http_error = 200; /* horrible : we use this value to avoid
1725 going to the send data state */
1726 c->state = HTTPSTATE_SEND_HEADER;
1730 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1732 static const char suffix[] = " kMGTP";
1735 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1737 avio_printf(pb, "%"PRId64"%c", count, *s);
1740 static void compute_status(HTTPContext *c)
1743 FFServerStream *stream;
1749 if (avio_open_dyn_buf(&pb) < 0) {
1750 /* XXX: return an error ? */
1751 c->buffer_ptr = c->buffer;
1752 c->buffer_end = c->buffer;
1756 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1757 avio_printf(pb, "Content-type: text/html\r\n");
1758 avio_printf(pb, "Pragma: no-cache\r\n");
1759 avio_printf(pb, "\r\n");
1761 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1762 if (c->stream->feed_filename[0])
1763 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1764 avio_printf(pb, "</head>\n<body>");
1765 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1767 avio_printf(pb, "<h2>Available Streams</h2>\n");
1768 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1769 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");
1770 stream = config.first_stream;
1772 char sfilename[1024];
1775 if (stream->feed == stream) {
1776 stream = stream->next;
1780 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1781 eosf = sfilename + strlen(sfilename);
1782 if (eosf - sfilename >= 4) {
1783 if (strcmp(eosf - 4, ".asf") == 0)
1784 strcpy(eosf - 4, ".asx");
1785 else if (strcmp(eosf - 3, ".rm") == 0)
1786 strcpy(eosf - 3, ".ram");
1787 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1788 /* generate a sample RTSP director if
1789 unicast. Generate an SDP redirector if
1791 eosf = strrchr(sfilename, '.');
1793 eosf = sfilename + strlen(sfilename);
1794 if (stream->is_multicast)
1795 strcpy(eosf, ".sdp");
1797 strcpy(eosf, ".rtsp");
1801 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1802 sfilename, stream->filename);
1803 avio_printf(pb, "<td align=right> %d <td align=right> ",
1804 stream->conns_served);
1805 fmt_bytecount(pb, stream->bytes_served);
1807 switch(stream->stream_type) {
1808 case STREAM_TYPE_LIVE: {
1809 int audio_bit_rate = 0;
1810 int video_bit_rate = 0;
1811 const char *audio_codec_name = "";
1812 const char *video_codec_name = "";
1813 const char *audio_codec_name_extra = "";
1814 const char *video_codec_name_extra = "";
1816 for(i=0;i<stream->nb_streams;i++) {
1817 AVStream *st = stream->streams[i];
1818 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1820 switch(st->codec->codec_type) {
1821 case AVMEDIA_TYPE_AUDIO:
1822 audio_bit_rate += st->codec->bit_rate;
1824 if (*audio_codec_name)
1825 audio_codec_name_extra = "...";
1826 audio_codec_name = codec->name;
1829 case AVMEDIA_TYPE_VIDEO:
1830 video_bit_rate += st->codec->bit_rate;
1832 if (*video_codec_name)
1833 video_codec_name_extra = "...";
1834 video_codec_name = codec->name;
1837 case AVMEDIA_TYPE_DATA:
1838 video_bit_rate += st->codec->bit_rate;
1845 avio_printf(pb, "<td align=center> %s <td align=right> %d "
1846 "<td align=right> %d <td> %s %s <td align=right> "
1848 stream->fmt->name, stream->bandwidth,
1849 video_bit_rate / 1000, video_codec_name,
1850 video_codec_name_extra, audio_bit_rate / 1000,
1851 audio_codec_name, audio_codec_name_extra);
1854 avio_printf(pb, "<td>%s", stream->feed->filename);
1856 avio_printf(pb, "<td>%s", stream->feed_filename);
1857 avio_printf(pb, "\n");
1861 avio_printf(pb, "<td align=center> - <td align=right> - "
1862 "<td align=right> - <td><td align=right> - <td>\n");
1865 stream = stream->next;
1867 avio_printf(pb, "</table>\n");
1869 stream = config.first_stream;
1872 if (stream->feed != stream) {
1873 stream = stream->next;
1877 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1879 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1886 /* This is somewhat linux specific I guess */
1887 snprintf(ps_cmd, sizeof(ps_cmd),
1888 "ps -o \"%%cpu,cputime\" --no-headers %d",
1891 pid_stat = popen(ps_cmd, "r");
1896 if (fscanf(pid_stat, "%9s %63s", cpuperc, cpuused) == 2) {
1897 avio_printf(pb, "Currently using %s%% of the cpu. "
1898 "Total time used %s.\n",
1906 avio_printf(pb, "<p>");
1909 avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>"
1910 "type<th>kbits/s<th align=left>codec<th align=left>"
1913 for (i = 0; i < stream->nb_streams; i++) {
1914 AVStream *st = stream->streams[i];
1915 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1916 const char *type = "unknown";
1917 char parameters[64];
1921 switch(st->codec->codec_type) {
1922 case AVMEDIA_TYPE_AUDIO:
1924 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz",
1925 st->codec->channels, st->codec->sample_rate);
1927 case AVMEDIA_TYPE_VIDEO:
1929 snprintf(parameters, sizeof(parameters),
1930 "%dx%d, q=%d-%d, fps=%d", st->codec->width,
1931 st->codec->height, st->codec->qmin, st->codec->qmax,
1932 st->codec->time_base.den / st->codec->time_base.num);
1938 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d"
1940 i, type, st->codec->bit_rate/1000,
1941 codec ? codec->name : "", parameters);
1944 avio_printf(pb, "</table>\n");
1945 stream = stream->next;
1948 /* connection status */
1949 avio_printf(pb, "<h2>Connection Status</h2>\n");
1951 avio_printf(pb, "Number of connections: %d / %d<br>\n",
1952 nb_connections, config.nb_max_connections);
1954 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1955 current_bandwidth, config.max_bandwidth);
1957 avio_printf(pb, "<table>\n");
1958 avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target "
1959 "bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1960 c1 = first_http_ctx;
1968 for (j = 0; j < c1->stream->nb_streams; j++) {
1969 if (!c1->stream->feed)
1970 bitrate += c1->stream->streams[j]->codec->bit_rate;
1971 else if (c1->feed_streams[j] >= 0)
1972 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1977 p = inet_ntoa(c1->from_addr.sin_addr);
1978 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s"
1980 i, c1->stream ? c1->stream->filename : "",
1981 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", p,
1982 c1->protocol, http_state[c1->state]);
1983 fmt_bytecount(pb, bitrate);
1984 avio_printf(pb, "<td align=right>");
1985 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1986 avio_printf(pb, "<td align=right>");
1987 fmt_bytecount(pb, c1->data_count);
1988 avio_printf(pb, "\n");
1991 avio_printf(pb, "</table>\n");
1996 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
1997 avio_printf(pb, "</body>\n</html>\n");
1999 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2000 c->buffer_ptr = c->pb_buffer;
2001 c->buffer_end = c->pb_buffer + len;
2004 static int open_input_stream(HTTPContext *c, const char *info)
2007 char input_filename[1024];
2008 AVFormatContext *s = NULL;
2009 int buf_size, i, ret;
2012 /* find file name */
2013 if (c->stream->feed) {
2014 strcpy(input_filename, c->stream->feed->feed_filename);
2015 buf_size = FFM_PACKET_SIZE;
2016 /* compute position (absolute time) */
2017 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2018 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2019 http_log("Invalid date specification '%s' for stream\n", buf);
2022 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2023 int prebuffer = strtol(buf, 0, 10);
2024 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2026 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2028 strcpy(input_filename, c->stream->feed_filename);
2030 /* compute position (relative time) */
2031 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2032 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2033 http_log("Invalid date specification '%s' for stream\n", buf);
2039 if (!input_filename[0]) {
2040 http_log("No filename was specified for stream\n");
2041 return AVERROR(EINVAL);
2045 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2046 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2050 /* set buffer size */
2051 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2053 s->flags |= AVFMT_FLAG_GENPTS;
2055 if (strcmp(s->iformat->name, "ffm") &&
2056 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2057 http_log("Could not find stream info for input '%s'\n", input_filename);
2058 avformat_close_input(&s);
2062 /* choose stream as clock source (we favor the video stream if
2063 * present) for packet sending */
2064 c->pts_stream_index = 0;
2065 for(i=0;i<c->stream->nb_streams;i++) {
2066 if (c->pts_stream_index == 0 &&
2067 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2068 c->pts_stream_index = i;
2072 if (c->fmt_in->iformat->read_seek)
2073 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2074 /* set the start time (needed for maxtime and RTP packet timing) */
2075 c->start_time = cur_time;
2076 c->first_pts = AV_NOPTS_VALUE;
2080 /* return the server clock (in us) */
2081 static int64_t get_server_clock(HTTPContext *c)
2083 /* compute current pts value from system time */
2084 return (cur_time - c->start_time) * 1000;
2087 /* return the estimated time at which the current packet must be sent
2089 static int64_t get_packet_send_clock(HTTPContext *c)
2091 int bytes_left, bytes_sent, frame_bytes;
2093 frame_bytes = c->cur_frame_bytes;
2094 if (frame_bytes <= 0)
2097 bytes_left = c->buffer_end - c->buffer_ptr;
2098 bytes_sent = frame_bytes - bytes_left;
2099 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2104 static int http_prepare_data(HTTPContext *c)
2107 AVFormatContext *ctx;
2109 av_freep(&c->pb_buffer);
2111 case HTTPSTATE_SEND_DATA_HEADER:
2112 ctx = avformat_alloc_context();
2115 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2116 c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams, sizeof(AVStream *));
2118 for(i=0;i<c->stream->nb_streams;i++) {
2120 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2121 /* if file or feed, then just take streams from FFServerStream struct */
2122 if (!c->stream->feed ||
2123 c->stream->feed == c->stream)
2124 src = c->stream->streams[i];
2126 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2128 *(c->fmt_ctx.streams[i]) = *src;
2129 c->fmt_ctx.streams[i]->priv_data = 0;
2130 /* XXX: should be done in AVStream, not in codec */
2131 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2133 /* set output format parameters */
2134 c->fmt_ctx.oformat = c->stream->fmt;
2135 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2137 c->got_key_frame = 0;
2139 /* prepare header and save header data in a stream */
2140 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2141 /* XXX: potential leak */
2144 c->fmt_ctx.pb->seekable = 0;
2147 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2148 * Default value from FFmpeg
2149 * Try to set it using configuration option
2151 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2153 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2154 http_log("Error writing output header for stream '%s': %s\n",
2155 c->stream->filename, av_err2str(ret));
2158 av_dict_free(&c->fmt_ctx.metadata);
2160 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2161 c->buffer_ptr = c->pb_buffer;
2162 c->buffer_end = c->pb_buffer + len;
2164 c->state = HTTPSTATE_SEND_DATA;
2165 c->last_packet_sent = 0;
2167 case HTTPSTATE_SEND_DATA:
2168 /* find a new packet */
2169 /* read a packet from the input stream */
2170 if (c->stream->feed)
2171 ffm_set_write_index(c->fmt_in,
2172 c->stream->feed->feed_write_index,
2173 c->stream->feed->feed_size);
2175 if (c->stream->max_time &&
2176 c->stream->max_time + c->start_time - cur_time < 0)
2177 /* We have timed out */
2178 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2182 ret = av_read_frame(c->fmt_in, &pkt);
2184 if (c->stream->feed) {
2185 /* if coming from feed, it means we reached the end of the
2186 ffm file, so must wait for more data */
2187 c->state = HTTPSTATE_WAIT_FEED;
2188 return 1; /* state changed */
2189 } else if (ret == AVERROR(EAGAIN)) {
2190 /* input not ready, come back later */
2193 if (c->stream->loop) {
2194 avformat_close_input(&c->fmt_in);
2195 if (open_input_stream(c, "") < 0)
2200 /* must send trailer now because EOF or error */
2201 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2205 int source_index = pkt.stream_index;
2206 /* update first pts if needed */
2207 if (c->first_pts == AV_NOPTS_VALUE) {
2208 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2209 c->start_time = cur_time;
2211 /* send it to the appropriate stream */
2212 if (c->stream->feed) {
2213 /* if coming from a feed, select the right stream */
2214 if (c->switch_pending) {
2215 c->switch_pending = 0;
2216 for(i=0;i<c->stream->nb_streams;i++) {
2217 if (c->switch_feed_streams[i] == pkt.stream_index)
2218 if (pkt.flags & AV_PKT_FLAG_KEY)
2219 c->switch_feed_streams[i] = -1;
2220 if (c->switch_feed_streams[i] >= 0)
2221 c->switch_pending = 1;
2224 for(i=0;i<c->stream->nb_streams;i++) {
2225 if (c->stream->feed_streams[i] == pkt.stream_index) {
2226 AVStream *st = c->fmt_in->streams[source_index];
2227 pkt.stream_index = i;
2228 if (pkt.flags & AV_PKT_FLAG_KEY &&
2229 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2230 c->stream->nb_streams == 1))
2231 c->got_key_frame = 1;
2232 if (!c->stream->send_on_key || c->got_key_frame)
2237 AVCodecContext *codec;
2238 AVStream *ist, *ost;
2240 ist = c->fmt_in->streams[source_index];
2241 /* specific handling for RTP: we use several
2242 * output streams (one for each RTP connection).
2243 * XXX: need more abstract handling */
2244 if (c->is_packetized) {
2245 /* compute send time and duration */
2246 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2247 c->cur_pts -= c->first_pts;
2248 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2249 /* find RTP context */
2250 c->packet_stream_index = pkt.stream_index;
2251 ctx = c->rtp_ctx[c->packet_stream_index];
2253 av_free_packet(&pkt);
2256 codec = ctx->streams[0]->codec;
2257 /* only one stream per RTP connection */
2258 pkt.stream_index = 0;
2262 codec = ctx->streams[pkt.stream_index]->codec;
2265 if (c->is_packetized) {
2266 int max_packet_size;
2267 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2268 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2270 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2271 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2273 ret = avio_open_dyn_buf(&ctx->pb);
2276 /* XXX: potential leak */
2279 ost = ctx->streams[pkt.stream_index];
2281 ctx->pb->seekable = 0;
2282 if (pkt.dts != AV_NOPTS_VALUE)
2283 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2284 if (pkt.pts != AV_NOPTS_VALUE)
2285 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2286 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2287 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2288 http_log("Error writing frame to output for stream '%s': %s\n",
2289 c->stream->filename, av_err2str(ret));
2290 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2293 av_freep(&c->pb_buffer);
2294 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2295 c->cur_frame_bytes = len;
2296 c->buffer_ptr = c->pb_buffer;
2297 c->buffer_end = c->pb_buffer + len;
2299 codec->frame_number++;
2301 av_free_packet(&pkt);
2305 av_free_packet(&pkt);
2310 case HTTPSTATE_SEND_DATA_TRAILER:
2311 /* last packet test ? */
2312 if (c->last_packet_sent || c->is_packetized)
2315 /* prepare header */
2316 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2317 /* XXX: potential leak */
2320 c->fmt_ctx.pb->seekable = 0;
2321 av_write_trailer(ctx);
2322 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2323 c->buffer_ptr = c->pb_buffer;
2324 c->buffer_end = c->pb_buffer + len;
2326 c->last_packet_sent = 1;
2332 /* should convert the format at the same time */
2333 /* send data starting at c->buffer_ptr to the output connection
2334 * (either UDP or TCP) */
2335 static int http_send_data(HTTPContext *c)
2340 if (c->buffer_ptr >= c->buffer_end) {
2341 ret = http_prepare_data(c);
2345 /* state change requested */
2348 if (c->is_packetized) {
2349 /* RTP data output */
2350 len = c->buffer_end - c->buffer_ptr;
2352 /* fail safe - should never happen */
2354 c->buffer_ptr = c->buffer_end;
2357 len = (c->buffer_ptr[0] << 24) |
2358 (c->buffer_ptr[1] << 16) |
2359 (c->buffer_ptr[2] << 8) |
2361 if (len > (c->buffer_end - c->buffer_ptr))
2363 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2364 /* nothing to send yet: we can wait */
2368 c->data_count += len;
2369 update_datarate(&c->datarate, c->data_count);
2371 c->stream->bytes_served += len;
2373 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2374 /* RTP packets are sent inside the RTSP TCP connection */
2376 int interleaved_index, size;
2378 HTTPContext *rtsp_c;
2381 /* if no RTSP connection left, error */
2384 /* if already sending something, then wait. */
2385 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2387 if (avio_open_dyn_buf(&pb) < 0)
2389 interleaved_index = c->packet_stream_index * 2;
2390 /* RTCP packets are sent at odd indexes */
2391 if (c->buffer_ptr[1] == 200)
2392 interleaved_index++;
2393 /* write RTSP TCP header */
2395 header[1] = interleaved_index;
2396 header[2] = len >> 8;
2398 avio_write(pb, header, 4);
2399 /* write RTP packet data */
2401 avio_write(pb, c->buffer_ptr, len);
2402 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2403 /* prepare asynchronous TCP sending */
2404 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2405 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2406 c->buffer_ptr += len;
2408 /* send everything we can NOW */
2409 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2410 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2412 rtsp_c->packet_buffer_ptr += len;
2413 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2414 /* if we could not send all the data, we will
2415 send it later, so a new state is needed to
2416 "lock" the RTSP TCP connection */
2417 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2420 /* all data has been sent */
2421 av_freep(&c->packet_buffer);
2423 /* send RTP packet directly in UDP */
2425 ffurl_write(c->rtp_handles[c->packet_stream_index],
2426 c->buffer_ptr, len);
2427 c->buffer_ptr += len;
2428 /* here we continue as we can send several packets per 10 ms slot */
2431 /* TCP data output */
2432 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2434 if (ff_neterrno() != AVERROR(EAGAIN) &&
2435 ff_neterrno() != AVERROR(EINTR))
2436 /* error : close connection */
2441 c->buffer_ptr += len;
2443 c->data_count += len;
2444 update_datarate(&c->datarate, c->data_count);
2446 c->stream->bytes_served += len;
2454 static int http_start_receive_data(HTTPContext *c)
2459 if (c->stream->feed_opened) {
2460 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2461 return AVERROR(EINVAL);
2464 /* Don't permit writing to this one */
2465 if (c->stream->readonly) {
2466 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2467 return AVERROR(EINVAL);
2471 fd = open(c->stream->feed_filename, O_RDWR);
2473 ret = AVERROR(errno);
2474 http_log("Could not open feed file '%s': %s\n",
2475 c->stream->feed_filename, strerror(errno));
2480 if (c->stream->truncate) {
2481 /* truncate feed file */
2482 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2483 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2484 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2485 ret = AVERROR(errno);
2486 http_log("Error truncating feed file '%s': %s\n",
2487 c->stream->feed_filename, strerror(errno));
2491 ret = ffm_read_write_index(fd);
2493 http_log("Error reading write index from feed file '%s': %s\n",
2494 c->stream->feed_filename, strerror(errno));
2497 c->stream->feed_write_index = ret;
2501 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2502 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2503 lseek(fd, 0, SEEK_SET);
2505 /* init buffer input */
2506 c->buffer_ptr = c->buffer;
2507 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2508 c->stream->feed_opened = 1;
2509 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2513 static int http_receive_data(HTTPContext *c)
2516 int len, loop_run = 0;
2518 while (c->chunked_encoding && !c->chunk_size &&
2519 c->buffer_end > c->buffer_ptr) {
2520 /* read chunk header, if present */
2521 len = recv(c->fd, c->buffer_ptr, 1, 0);
2524 if (ff_neterrno() != AVERROR(EAGAIN) &&
2525 ff_neterrno() != AVERROR(EINTR))
2526 /* error : close connection */
2529 } else if (len == 0) {
2530 /* end of connection : close it */
2532 } else if (c->buffer_ptr - c->buffer >= 2 &&
2533 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2534 c->chunk_size = strtol(c->buffer, 0, 16);
2535 if (c->chunk_size == 0) // end of stream
2537 c->buffer_ptr = c->buffer;
2539 } else if (++loop_run > 10) {
2540 /* no chunk header, abort */
2547 if (c->buffer_end > c->buffer_ptr) {
2548 len = recv(c->fd, c->buffer_ptr,
2549 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2551 if (ff_neterrno() != AVERROR(EAGAIN) &&
2552 ff_neterrno() != AVERROR(EINTR))
2553 /* error : close connection */
2555 } else if (len == 0)
2556 /* end of connection : close it */
2559 c->chunk_size -= len;
2560 c->buffer_ptr += len;
2561 c->data_count += len;
2562 update_datarate(&c->datarate, c->data_count);
2566 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2567 if (c->buffer[0] != 'f' ||
2568 c->buffer[1] != 'm') {
2569 http_log("Feed stream has become desynchronized -- disconnecting\n");
2574 if (c->buffer_ptr >= c->buffer_end) {
2575 FFServerStream *feed = c->stream;
2576 /* a packet has been received : write it in the store, except
2578 if (c->data_count > FFM_PACKET_SIZE) {
2579 /* XXX: use llseek or url_seek
2580 * XXX: Should probably fail? */
2581 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2582 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2584 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2585 http_log("Error writing to feed file: %s\n", strerror(errno));
2589 feed->feed_write_index += FFM_PACKET_SIZE;
2590 /* update file size */
2591 if (feed->feed_write_index > c->stream->feed_size)
2592 feed->feed_size = feed->feed_write_index;
2594 /* handle wrap around if max file size reached */
2595 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2596 feed->feed_write_index = FFM_PACKET_SIZE;
2599 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2600 http_log("Error writing index to feed file: %s\n", strerror(errno));
2604 /* wake up any waiting connections */
2605 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2606 if (c1->state == HTTPSTATE_WAIT_FEED &&
2607 c1->stream->feed == c->stream->feed)
2608 c1->state = HTTPSTATE_SEND_DATA;
2611 /* We have a header in our hands that contains useful data */
2612 AVFormatContext *s = avformat_alloc_context();
2614 AVInputFormat *fmt_in;
2620 /* use feed output format name to find corresponding input format */
2621 fmt_in = av_find_input_format(feed->fmt->name);
2625 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2626 0, NULL, NULL, NULL, NULL);
2630 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2635 /* Now we have the actual streams */
2636 if (s->nb_streams != feed->nb_streams) {
2637 avformat_close_input(&s);
2639 http_log("Feed '%s' stream number does not match registered feed\n",
2640 c->stream->feed_filename);
2644 for (i = 0; i < s->nb_streams; i++) {
2645 AVStream *fst = feed->streams[i];
2646 AVStream *st = s->streams[i];
2647 avcodec_copy_context(fst->codec, st->codec);
2650 avformat_close_input(&s);
2653 c->buffer_ptr = c->buffer;
2658 c->stream->feed_opened = 0;
2660 /* wake up any waiting connections to stop waiting for feed */
2661 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2662 if (c1->state == HTTPSTATE_WAIT_FEED &&
2663 c1->stream->feed == c->stream->feed)
2664 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2669 /********************************************************************/
2672 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2679 str = RTSP_STATUS_CODE2STRING(error_number);
2681 str = "Unknown Error";
2683 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2684 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2686 /* output GMT time */
2689 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2690 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2693 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2695 rtsp_reply_header(c, error_number);
2696 avio_printf(c->pb, "\r\n");
2699 static int rtsp_parse_request(HTTPContext *c)
2701 const char *p, *p1, *p2;
2707 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2709 c->buffer_ptr[0] = '\0';
2712 get_word(cmd, sizeof(cmd), &p);
2713 get_word(url, sizeof(url), &p);
2714 get_word(protocol, sizeof(protocol), &p);
2716 av_strlcpy(c->method, cmd, sizeof(c->method));
2717 av_strlcpy(c->url, url, sizeof(c->url));
2718 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2720 if (avio_open_dyn_buf(&c->pb) < 0) {
2721 /* XXX: cannot do more */
2722 c->pb = NULL; /* safety */
2726 /* check version name */
2727 if (strcmp(protocol, "RTSP/1.0")) {
2728 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2732 /* parse each header line */
2733 /* skip to next line */
2734 while (*p != '\n' && *p != '\0')
2738 while (*p != '\0') {
2739 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2743 if (p2 > p && p2[-1] == '\r')
2745 /* skip empty line */
2749 if (len > sizeof(line) - 1)
2750 len = sizeof(line) - 1;
2751 memcpy(line, p, len);
2753 ff_rtsp_parse_line(header, line, NULL, NULL);
2757 /* handle sequence number */
2758 c->seq = header->seq;
2760 if (!strcmp(cmd, "DESCRIBE"))
2761 rtsp_cmd_describe(c, url);
2762 else if (!strcmp(cmd, "OPTIONS"))
2763 rtsp_cmd_options(c, url);
2764 else if (!strcmp(cmd, "SETUP"))
2765 rtsp_cmd_setup(c, url, header);
2766 else if (!strcmp(cmd, "PLAY"))
2767 rtsp_cmd_play(c, url, header);
2768 else if (!strcmp(cmd, "PAUSE"))
2769 rtsp_cmd_interrupt(c, url, header, 1);
2770 else if (!strcmp(cmd, "TEARDOWN"))
2771 rtsp_cmd_interrupt(c, url, header, 0);
2773 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2776 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2777 c->pb = NULL; /* safety */
2779 /* XXX: cannot do more */
2782 c->buffer_ptr = c->pb_buffer;
2783 c->buffer_end = c->pb_buffer + len;
2784 c->state = RTSPSTATE_SEND_REPLY;
2788 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2789 struct in_addr my_ip)
2791 AVFormatContext *avc;
2792 AVStream *avs = NULL;
2793 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2794 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2799 avc = avformat_alloc_context();
2800 if (!avc || !rtp_format) {
2803 avc->oformat = rtp_format;
2804 av_dict_set(&avc->metadata, "title",
2805 entry ? entry->value : "No Title", 0);
2806 avc->nb_streams = stream->nb_streams;
2807 if (stream->is_multicast) {
2808 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2809 inet_ntoa(stream->multicast_ip),
2810 stream->multicast_port, stream->multicast_ttl);
2812 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2815 if (!(avc->streams = av_malloc_array(avc->nb_streams, sizeof(*avc->streams))))
2817 if (!(avs = av_malloc_array(avc->nb_streams, sizeof(*avs))))
2820 for(i = 0; i < stream->nb_streams; i++) {
2821 avc->streams[i] = &avs[i];
2822 avc->streams[i]->codec = stream->streams[i]->codec;
2824 *pbuffer = av_mallocz(2048);
2825 av_sdp_create(&avc, 1, *pbuffer, 2048);
2828 av_freep(&avc->streams);
2829 av_dict_free(&avc->metadata);
2833 return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2836 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2838 // rtsp_reply_header(c, RTSP_STATUS_OK);
2839 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2840 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2841 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2842 avio_printf(c->pb, "\r\n");
2845 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2847 FFServerStream *stream;
2853 struct sockaddr_in my_addr;
2855 /* find which URL is asked */
2856 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2861 for(stream = config.first_stream; stream; stream = stream->next) {
2862 if (!stream->is_feed &&
2863 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2864 !strcmp(path, stream->filename)) {
2868 /* no stream found */
2869 rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
2873 /* prepare the media description in SDP format */
2875 /* get the host IP */
2876 len = sizeof(my_addr);
2877 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2878 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2879 if (content_length < 0) {
2880 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2883 rtsp_reply_header(c, RTSP_STATUS_OK);
2884 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2885 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2886 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2887 avio_printf(c->pb, "\r\n");
2888 avio_write(c->pb, content, content_length);
2892 static HTTPContext *find_rtp_session(const char *session_id)
2896 if (session_id[0] == '\0')
2899 for(c = first_http_ctx; c; c = c->next) {
2900 if (!strcmp(c->session_id, session_id))
2906 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2908 RTSPTransportField *th;
2911 for(i=0;i<h->nb_transports;i++) {
2912 th = &h->transports[i];
2913 if (th->lower_transport == lower_transport)
2919 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2920 RTSPMessageHeader *h)
2922 FFServerStream *stream;
2923 int stream_index, rtp_port, rtcp_port;
2928 RTSPTransportField *th;
2929 struct sockaddr_in dest_addr;
2930 RTSPActionServerSetup setup;
2932 /* find which URL is asked */
2933 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2938 /* now check each stream */
2939 for(stream = config.first_stream; stream; stream = stream->next) {
2940 if (stream->is_feed || !stream->fmt ||
2941 strcmp(stream->fmt->name, "rtp")) {
2944 /* accept aggregate filenames only if single stream */
2945 if (!strcmp(path, stream->filename)) {
2946 if (stream->nb_streams != 1) {
2947 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2954 for(stream_index = 0; stream_index < stream->nb_streams;
2956 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2957 stream->filename, stream_index);
2958 if (!strcmp(path, buf))
2962 /* no stream found */
2963 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2967 /* generate session id if needed */
2968 if (h->session_id[0] == '\0') {
2969 unsigned random0 = av_lfg_get(&random_state);
2970 unsigned random1 = av_lfg_get(&random_state);
2971 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2975 /* find RTP session, and create it if none found */
2976 rtp_c = find_rtp_session(h->session_id);
2978 /* always prefer UDP */
2979 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2981 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2983 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2988 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2989 th->lower_transport);
2991 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2995 /* open input stream */
2996 if (open_input_stream(rtp_c, "") < 0) {
2997 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3002 /* test if stream is OK (test needed because several SETUP needs
3003 to be done for a given file) */
3004 if (rtp_c->stream != stream) {
3005 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3009 /* test if stream is already set up */
3010 if (rtp_c->rtp_ctx[stream_index]) {
3011 rtsp_reply_error(c, RTSP_STATUS_STATE);
3015 /* check transport */
3016 th = find_transport(h, rtp_c->rtp_protocol);
3017 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3018 th->client_port_min <= 0)) {
3019 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3023 /* setup default options */
3024 setup.transport_option[0] = '\0';
3025 dest_addr = rtp_c->from_addr;
3026 dest_addr.sin_port = htons(th->client_port_min);
3029 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3030 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3034 /* now everything is OK, so we can send the connection parameters */
3035 rtsp_reply_header(c, RTSP_STATUS_OK);
3037 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3039 switch(rtp_c->rtp_protocol) {
3040 case RTSP_LOWER_TRANSPORT_UDP:
3041 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3042 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3043 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3044 "client_port=%d-%d;server_port=%d-%d",
3045 th->client_port_min, th->client_port_max,
3046 rtp_port, rtcp_port);
3048 case RTSP_LOWER_TRANSPORT_TCP:
3049 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3050 stream_index * 2, stream_index * 2 + 1);
3055 if (setup.transport_option[0] != '\0')
3056 avio_printf(c->pb, ";%s", setup.transport_option);
3057 avio_printf(c->pb, "\r\n");
3060 avio_printf(c->pb, "\r\n");
3064 /* find an RTP connection by using the session ID. Check consistency
3066 static HTTPContext *find_rtp_session_with_url(const char *url,
3067 const char *session_id)
3075 rtp_c = find_rtp_session(session_id);
3079 /* find which URL is asked */
3080 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3084 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3085 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3086 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3087 rtp_c->stream->filename, s);
3088 if(!strncmp(path, buf, sizeof(buf))) {
3089 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3094 if (len > 0 && path[len - 1] == '/' &&
3095 !strncmp(path, rtp_c->stream->filename, len - 1))
3100 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3104 rtp_c = find_rtp_session_with_url(url, h->session_id);
3106 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3110 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3111 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3112 rtp_c->state != HTTPSTATE_READY) {
3113 rtsp_reply_error(c, RTSP_STATUS_STATE);
3117 rtp_c->state = HTTPSTATE_SEND_DATA;
3119 /* now everything is OK, so we can send the connection parameters */
3120 rtsp_reply_header(c, RTSP_STATUS_OK);
3122 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3123 avio_printf(c->pb, "\r\n");
3126 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3130 rtp_c = find_rtp_session_with_url(url, h->session_id);
3132 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3137 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3138 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3139 rtsp_reply_error(c, RTSP_STATUS_STATE);
3142 rtp_c->state = HTTPSTATE_READY;
3143 rtp_c->first_pts = AV_NOPTS_VALUE;
3146 /* now everything is OK, so we can send the connection parameters */
3147 rtsp_reply_header(c, RTSP_STATUS_OK);
3149 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3150 avio_printf(c->pb, "\r\n");
3153 close_connection(rtp_c);
3156 /********************************************************************/
3159 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3160 FFServerStream *stream, const char *session_id,
3161 enum RTSPLowerTransport rtp_protocol)
3163 HTTPContext *c = NULL;
3164 const char *proto_str;
3166 /* XXX: should output a warning page when coming
3167 close to the connection limit */
3168 if (nb_connections >= config.nb_max_connections)
3171 /* add a new connection */
3172 c = av_mallocz(sizeof(HTTPContext));
3177 c->poll_entry = NULL;
3178 c->from_addr = *from_addr;
3179 c->buffer_size = IOBUFFER_INIT_SIZE;
3180 c->buffer = av_malloc(c->buffer_size);
3185 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3186 c->state = HTTPSTATE_READY;
3187 c->is_packetized = 1;
3188 c->rtp_protocol = rtp_protocol;
3190 /* protocol is shown in statistics */
3191 switch(c->rtp_protocol) {
3192 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3193 proto_str = "MCAST";
3195 case RTSP_LOWER_TRANSPORT_UDP:
3198 case RTSP_LOWER_TRANSPORT_TCP:
3205 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3206 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3208 current_bandwidth += stream->bandwidth;
3210 c->next = first_http_ctx;
3216 av_freep(&c->buffer);
3222 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3223 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3225 static int rtp_new_av_stream(HTTPContext *c,
3226 int stream_index, struct sockaddr_in *dest_addr,
3227 HTTPContext *rtsp_c)
3229 AVFormatContext *ctx;
3232 URLContext *h = NULL;
3234 int max_packet_size;
3236 /* now we can open the relevant output stream */
3237 ctx = avformat_alloc_context();
3240 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3242 st = av_mallocz(sizeof(AVStream));
3245 ctx->nb_streams = 1;
3246 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3249 ctx->streams[0] = st;
3251 if (!c->stream->feed ||
3252 c->stream->feed == c->stream)
3253 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3256 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3258 st->priv_data = NULL;
3260 /* build destination RTP address */
3261 ipaddr = inet_ntoa(dest_addr->sin_addr);
3263 switch(c->rtp_protocol) {
3264 case RTSP_LOWER_TRANSPORT_UDP:
3265 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3268 /* XXX: also pass as parameter to function ? */
3269 if (c->stream->is_multicast) {
3271 ttl = c->stream->multicast_ttl;
3274 snprintf(ctx->filename, sizeof(ctx->filename),
3275 "rtp://%s:%d?multicast=1&ttl=%d",
3276 ipaddr, ntohs(dest_addr->sin_port), ttl);
3278 snprintf(ctx->filename, sizeof(ctx->filename),
3279 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3282 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3284 c->rtp_handles[stream_index] = h;
3285 max_packet_size = h->max_packet_size;
3287 case RTSP_LOWER_TRANSPORT_TCP:
3290 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3296 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3297 ipaddr, ntohs(dest_addr->sin_port),
3298 c->stream->filename, stream_index, c->protocol);
3300 /* normally, no packets should be output here, but the packet size may
3302 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3303 /* XXX: close stream */
3306 if (avformat_write_header(ctx, NULL) < 0) {
3314 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3317 c->rtp_ctx[stream_index] = ctx;
3321 /********************************************************************/
3322 /* ffserver initialization */
3324 static AVStream *add_av_stream1(FFServerStream *stream, AVCodecContext *codec, int copy)
3328 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3331 fst = av_mallocz(sizeof(AVStream));
3335 fst->codec = avcodec_alloc_context3(codec->codec);
3336 avcodec_copy_context(fst->codec, codec);
3338 /* live streams must use the actual feed's codec since it may be
3339 * updated later to carry extradata needed by them.
3343 fst->priv_data = av_mallocz(sizeof(FeedData));
3344 fst->index = stream->nb_streams;
3345 avpriv_set_pts_info(fst, 33, 1, 90000);
3346 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3347 stream->streams[stream->nb_streams++] = fst;
3351 /* return the stream number in the feed */
3352 static int add_av_stream(FFServerStream *feed, AVStream *st)
3355 AVCodecContext *av, *av1;
3359 for(i=0;i<feed->nb_streams;i++) {
3360 av1 = feed->streams[i]->codec;
3361 if (av1->codec_id == av->codec_id &&
3362 av1->codec_type == av->codec_type &&
3363 av1->bit_rate == av->bit_rate) {
3365 switch(av->codec_type) {
3366 case AVMEDIA_TYPE_AUDIO:
3367 if (av1->channels == av->channels &&
3368 av1->sample_rate == av->sample_rate)
3371 case AVMEDIA_TYPE_VIDEO:
3372 if (av1->width == av->width &&
3373 av1->height == av->height &&
3374 av1->time_base.den == av->time_base.den &&
3375 av1->time_base.num == av->time_base.num &&
3376 av1->gop_size == av->gop_size)
3385 fst = add_av_stream1(feed, av, 0);
3388 if (av_stream_get_recommended_encoder_configuration(st))
3389 av_stream_set_recommended_encoder_configuration(fst,
3390 av_strdup(av_stream_get_recommended_encoder_configuration(st)));
3391 return feed->nb_streams - 1;
3394 static void remove_stream(FFServerStream *stream)
3396 FFServerStream **ps;
3397 ps = &config.first_stream;
3406 /* specific MPEG4 handling : we extract the raw parameters */
3407 static void extract_mpeg4_header(AVFormatContext *infile)
3409 int mpeg4_count, i, size;
3414 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3417 for(i=0;i<infile->nb_streams;i++) {
3418 st = infile->streams[i];
3419 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3420 st->codec->extradata_size == 0) {
3427 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3428 while (mpeg4_count > 0) {
3429 if (av_read_frame(infile, &pkt) < 0)
3431 st = infile->streams[pkt.stream_index];
3432 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3433 st->codec->extradata_size == 0) {
3434 av_freep(&st->codec->extradata);
3435 /* fill extradata with the header */
3436 /* XXX: we make hard suppositions here ! */
3438 while (p < pkt.data + pkt.size - 4) {
3439 /* stop when vop header is found */
3440 if (p[0] == 0x00 && p[1] == 0x00 &&
3441 p[2] == 0x01 && p[3] == 0xb6) {
3442 size = p - pkt.data;
3443 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3444 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3445 st->codec->extradata_size = size;
3446 memcpy(st->codec->extradata, pkt.data, size);
3453 av_free_packet(&pkt);
3457 /* compute the needed AVStream for each file */
3458 static void build_file_streams(void)
3460 FFServerStream *stream, *stream_next;
3463 /* gather all streams */
3464 for(stream = config.first_stream; stream; stream = stream_next) {
3465 AVFormatContext *infile = NULL;
3466 stream_next = stream->next;
3467 if (stream->stream_type == STREAM_TYPE_LIVE &&
3469 /* the stream comes from a file */
3470 /* try to open the file */
3472 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3473 /* specific case : if transport stream output to RTP,
3474 we use a raw transport stream reader */
3475 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3478 if (!stream->feed_filename[0]) {
3479 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3483 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3484 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3485 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3486 /* remove stream (no need to spend more time on it) */
3488 remove_stream(stream);
3490 /* find all the AVStreams inside and reference them in
3492 if (avformat_find_stream_info(infile, NULL) < 0) {
3493 http_log("Could not find codec parameters from '%s'\n",
3494 stream->feed_filename);
3495 avformat_close_input(&infile);
3498 extract_mpeg4_header(infile);
3500 for(i=0;i<infile->nb_streams;i++)
3501 add_av_stream1(stream, infile->streams[i]->codec, 1);
3503 avformat_close_input(&infile);
3509 /* compute the needed AVStream for each feed */
3510 static void build_feed_streams(void)
3512 FFServerStream *stream, *feed;
3515 /* gather all streams */
3516 for(stream = config.first_stream; stream; stream = stream->next) {
3517 feed = stream->feed;
3519 if (stream->is_feed) {
3520 for(i=0;i<stream->nb_streams;i++)
3521 stream->feed_streams[i] = i;
3523 /* we handle a stream coming from a feed */
3524 for(i=0;i<stream->nb_streams;i++)
3525 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3530 /* create feed files if needed */
3531 for(feed = config.first_feed; feed; feed = feed->next_feed) {
3534 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3535 /* See if it matches */
3536 AVFormatContext *s = NULL;
3539 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3540 /* set buffer size */
3541 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3542 /* Now see if it matches */
3543 if (s->nb_streams == feed->nb_streams) {
3545 for(i=0;i<s->nb_streams;i++) {
3547 sf = feed->streams[i];
3550 if (sf->index != ss->index ||
3552 http_log("Index & Id do not match for stream %d (%s)\n",
3553 i, feed->feed_filename);
3556 AVCodecContext *ccf, *ccs;
3560 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3562 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3563 http_log("Codecs do not match for stream %d\n", i);
3565 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3566 http_log("Codec bitrates do not match for stream %d\n", i);
3568 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3569 if (CHECK_CODEC(time_base.den) ||
3570 CHECK_CODEC(time_base.num) ||
3571 CHECK_CODEC(width) ||
3572 CHECK_CODEC(height)) {
3573 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3576 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3577 if (CHECK_CODEC(sample_rate) ||
3578 CHECK_CODEC(channels) ||
3579 CHECK_CODEC(frame_size)) {
3580 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3584 http_log("Unknown codec type\n");
3592 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3593 feed->feed_filename, s->nb_streams, feed->nb_streams);
3595 avformat_close_input(&s);
3597 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3598 feed->feed_filename);
3601 if (feed->readonly) {
3602 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3603 feed->feed_filename);
3606 unlink(feed->feed_filename);
3609 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3610 AVFormatContext *s = avformat_alloc_context();
3612 if (feed->readonly) {
3613 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3614 feed->feed_filename);
3618 /* only write the header of the ffm file */
3619 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3620 http_log("Could not open output feed file '%s'\n",
3621 feed->feed_filename);
3624 s->oformat = feed->fmt;
3625 s->nb_streams = feed->nb_streams;
3626 s->streams = feed->streams;
3627 if (avformat_write_header(s, NULL) < 0) {
3628 http_log("Container doesn't support the required parameters\n");
3631 /* XXX: need better API */
3632 av_freep(&s->priv_data);
3633 avio_closep(&s->pb);
3636 avformat_free_context(s);
3638 /* get feed size and write index */
3639 fd = open(feed->feed_filename, O_RDONLY);
3641 http_log("Could not open output feed file '%s'\n",
3642 feed->feed_filename);
3646 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3647 feed->feed_size = lseek(fd, 0, SEEK_END);
3648 /* ensure that we do not wrap before the end of file */
3649 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3650 feed->feed_max_size = feed->feed_size;
3656 /* compute the bandwidth used by each stream */
3657 static void compute_bandwidth(void)
3661 FFServerStream *stream;
3663 for(stream = config.first_stream; stream; stream = stream->next) {
3665 for(i=0;i<stream->nb_streams;i++) {
3666 AVStream *st = stream->streams[i];
3667 switch(st->codec->codec_type) {
3668 case AVMEDIA_TYPE_AUDIO:
3669 case AVMEDIA_TYPE_VIDEO:
3670 bandwidth += st->codec->bit_rate;
3676 stream->bandwidth = (bandwidth + 999) / 1000;
3680 static void handle_child_exit(int sig)
3685 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3686 FFServerStream *feed;
3688 for (feed = config.first_feed; feed; feed = feed->next) {
3689 if (feed->pid == pid) {
3690 int uptime = time(0) - feed->pid_start;
3693 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
3696 /* Turn off any more restarts */
3697 ffserver_free_child_args(&feed->child_argv);
3702 need_to_start_children = 1;
3705 static void opt_debug(void)
3708 snprintf(config.logfilename, sizeof(config.logfilename), "-");
3711 void show_help_default(const char *opt, const char *arg)
3713 printf("usage: ffserver [options]\n"
3714 "Hyper fast multi format Audio/Video streaming server\n");
3716 show_help_options(options, "Main options:", 0, 0, 0);
3719 static const OptionDef options[] = {
3720 #include "cmdutils_common_opts.h"
3721 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3722 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3723 { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3727 int main(int argc, char **argv)
3729 struct sigaction sigact = { { 0 } };
3732 config.filename = av_strdup("/etc/ffserver.conf");
3734 parse_loglevel(argc, argv, options);
3736 avformat_network_init();
3738 show_banner(argc, argv, options);
3740 my_program_name = argv[0];
3742 parse_options(NULL, argc, argv, options, NULL);
3744 unsetenv("http_proxy"); /* Kill the http_proxy */
3746 av_lfg_init(&random_state, av_get_random_seed());
3748 sigact.sa_handler = handle_child_exit;
3749 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3750 sigaction(SIGCHLD, &sigact, 0);
3752 if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3753 fprintf(stderr, "Error reading configuration file '%s': %s\n",
3754 config.filename, av_err2str(ret));
3757 av_freep(&config.filename);
3759 /* open log file if needed */
3760 if (config.logfilename[0] != '\0') {
3761 if (!strcmp(config.logfilename, "-"))
3764 logfile = fopen(config.logfilename, "a");
3765 av_log_set_callback(http_av_log);
3768 build_file_streams();
3770 build_feed_streams();
3772 compute_bandwidth();
3775 signal(SIGPIPE, SIG_IGN);
3777 if (http_server() < 0) {
3778 http_log("Could not start server\n");