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 void compute_status(HTTPContext *c);
213 static int open_input_stream(HTTPContext *c, const char *info);
214 static int http_parse_request(HTTPContext *c);
215 static int http_send_data(HTTPContext *c);
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)",
469 ntohs(my_addr->sin_port));
471 closesocket(server_fd);
475 if (listen (server_fd, 5) < 0) {
477 closesocket(server_fd);
481 if (ff_socket_nonblock(server_fd, 1) < 0)
482 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
487 /* start all multicast streams */
488 static void start_multicast(void)
490 FFServerStream *stream;
493 struct sockaddr_in dest_addr = {0};
494 int default_port, stream_index;
495 unsigned int random0, random1;
498 for(stream = config.first_stream; stream; stream = stream->next) {
500 if (!stream->is_multicast)
503 random0 = av_lfg_get(&random_state);
504 random1 = av_lfg_get(&random_state);
506 /* open the RTP connection */
507 snprintf(session_id, sizeof(session_id), "%08x%08x",
510 /* choose a port if none given */
511 if (stream->multicast_port == 0) {
512 stream->multicast_port = default_port;
516 dest_addr.sin_family = AF_INET;
517 dest_addr.sin_addr = stream->multicast_ip;
518 dest_addr.sin_port = htons(stream->multicast_port);
520 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
521 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
525 if (open_input_stream(rtp_c, "") < 0) {
526 http_log("Could not open input stream for stream '%s'\n",
531 /* open each RTP stream */
532 for(stream_index = 0; stream_index < stream->nb_streams;
534 dest_addr.sin_port = htons(stream->multicast_port +
536 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) >= 0)
539 http_log("Could not open output stream '%s/streamid=%d'\n",
540 stream->filename, stream_index);
544 rtp_c->state = HTTPSTATE_SEND_DATA;
548 /* main loop of the HTTP server */
549 static int http_server(void)
551 int server_fd = 0, rtsp_server_fd = 0;
553 struct pollfd *poll_table, *poll_entry;
554 HTTPContext *c, *c_next;
556 poll_table = av_mallocz_array(config.nb_max_http_connections + 2,
557 sizeof(*poll_table));
559 http_log("Impossible to allocate a poll table handling %d "
560 "connections.\n", config.nb_max_http_connections);
564 if (config.http_addr.sin_port) {
565 server_fd = socket_open_listen(&config.http_addr);
572 if (config.rtsp_addr.sin_port) {
573 rtsp_server_fd = socket_open_listen(&config.rtsp_addr);
574 if (rtsp_server_fd < 0) {
576 closesocket(server_fd);
581 if (!rtsp_server_fd && !server_fd) {
582 http_log("HTTP and RTSP disabled.\n");
587 http_log("FFserver started.\n");
589 start_children(config.first_feed);
594 poll_entry = poll_table;
596 poll_entry->fd = server_fd;
597 poll_entry->events = POLLIN;
600 if (rtsp_server_fd) {
601 poll_entry->fd = rtsp_server_fd;
602 poll_entry->events = POLLIN;
606 /* wait for events on each HTTP handle */
613 case HTTPSTATE_SEND_HEADER:
614 case RTSPSTATE_SEND_REPLY:
615 case RTSPSTATE_SEND_PACKET:
616 c->poll_entry = poll_entry;
618 poll_entry->events = POLLOUT;
621 case HTTPSTATE_SEND_DATA_HEADER:
622 case HTTPSTATE_SEND_DATA:
623 case HTTPSTATE_SEND_DATA_TRAILER:
624 if (!c->is_packetized) {
625 /* for TCP, we output as much as we can
626 * (may need to put a limit) */
627 c->poll_entry = poll_entry;
629 poll_entry->events = POLLOUT;
632 /* when ffserver is doing the timing, we work by
633 looking at which packet needs to be sent every
635 /* one tick wait XXX: 10 ms assumed */
640 case HTTPSTATE_WAIT_REQUEST:
641 case HTTPSTATE_RECEIVE_DATA:
642 case HTTPSTATE_WAIT_FEED:
643 case RTSPSTATE_WAIT_REQUEST:
644 /* need to catch errors */
645 c->poll_entry = poll_entry;
647 poll_entry->events = POLLIN;/* Maybe this will work */
651 c->poll_entry = NULL;
657 /* wait for an event on one connection. We poll at least every
658 second to handle timeouts */
660 ret = poll(poll_table, poll_entry - poll_table, delay);
661 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
662 ff_neterrno() != AVERROR(EINTR)) {
668 cur_time = av_gettime() / 1000;
670 if (need_to_start_children) {
671 need_to_start_children = 0;
672 start_children(config.first_feed);
675 /* now handle the events */
676 for(c = first_http_ctx; c; c = c_next) {
678 if (handle_connection(c) < 0) {
680 /* close and free the connection */
685 poll_entry = poll_table;
687 /* new HTTP connection request ? */
688 if (poll_entry->revents & POLLIN)
689 new_connection(server_fd, 0);
692 if (rtsp_server_fd) {
693 /* new RTSP connection request ? */
694 if (poll_entry->revents & POLLIN)
695 new_connection(rtsp_server_fd, 1);
700 /* start waiting for a new HTTP/RTSP request */
701 static void start_wait_request(HTTPContext *c, int is_rtsp)
703 c->buffer_ptr = c->buffer;
704 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
707 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
708 c->state = RTSPSTATE_WAIT_REQUEST;
710 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
711 c->state = HTTPSTATE_WAIT_REQUEST;
715 static void http_send_too_busy_reply(int fd)
718 int len = snprintf(buffer, sizeof(buffer),
719 "HTTP/1.0 503 Server too busy\r\n"
720 "Content-type: text/html\r\n"
722 "<html><head><title>Too busy</title></head><body>\r\n"
723 "<p>The server is too busy to serve your request at this time.</p>\r\n"
724 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
725 "</body></html>\r\n",
726 nb_connections, config.nb_max_connections);
727 av_assert0(len < sizeof(buffer));
728 if (send(fd, buffer, len, 0) < len)
729 av_log(NULL, AV_LOG_WARNING,
730 "Could not send too-busy reply, send() failed\n");
734 static void new_connection(int server_fd, int is_rtsp)
736 struct sockaddr_in from_addr;
739 HTTPContext *c = NULL;
741 len = sizeof(from_addr);
742 fd = accept(server_fd, (struct sockaddr *)&from_addr,
745 http_log("error during accept %s\n", strerror(errno));
748 if (ff_socket_nonblock(fd, 1) < 0)
749 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
751 if (nb_connections >= config.nb_max_connections) {
752 http_send_too_busy_reply(fd);
756 /* add a new connection */
757 c = av_mallocz(sizeof(HTTPContext));
762 c->poll_entry = NULL;
763 c->from_addr = from_addr;
764 c->buffer_size = IOBUFFER_INIT_SIZE;
765 c->buffer = av_malloc(c->buffer_size);
769 c->next = first_http_ctx;
773 start_wait_request(c, is_rtsp);
779 av_freep(&c->buffer);
785 static void close_connection(HTTPContext *c)
787 HTTPContext **cp, *c1;
789 AVFormatContext *ctx;
793 /* remove connection from list */
794 cp = &first_http_ctx;
803 /* remove references, if any (XXX: do it faster) */
804 for(c1 = first_http_ctx; c1; c1 = c1->next) {
809 /* remove connection associated resources */
813 /* close each frame parser */
814 for(i=0;i<c->fmt_in->nb_streams;i++) {
815 st = c->fmt_in->streams[i];
816 if (st->codec->codec)
817 avcodec_close(st->codec);
819 avformat_close_input(&c->fmt_in);
822 /* free RTP output streams if any */
825 nb_streams = c->stream->nb_streams;
827 for(i=0;i<nb_streams;i++) {
830 av_write_trailer(ctx);
831 av_dict_free(&ctx->metadata);
832 av_freep(&ctx->streams[0]);
835 h = c->rtp_handles[i];
842 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
844 if (ctx->oformat && avio_open_dyn_buf(&ctx->pb) >= 0) {
845 av_write_trailer(ctx);
846 av_freep(&c->pb_buffer);
847 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
851 for(i=0; i<ctx->nb_streams; i++)
852 av_freep(&ctx->streams[i]);
853 av_freep(&ctx->streams);
854 av_freep(&ctx->priv_data);
856 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
857 current_bandwidth -= c->stream->bandwidth;
859 /* signal that there is no feed if we are the feeder socket */
860 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
861 c->stream->feed_opened = 0;
865 av_freep(&c->pb_buffer);
866 av_freep(&c->packet_buffer);
867 av_freep(&c->buffer);
872 static int handle_connection(HTTPContext *c)
878 case HTTPSTATE_WAIT_REQUEST:
879 case RTSPSTATE_WAIT_REQUEST:
881 if ((c->timeout - cur_time) < 0)
883 if (c->poll_entry->revents & (POLLERR | POLLHUP))
886 /* no need to read if no events */
887 if (!(c->poll_entry->revents & POLLIN))
891 if (!(len = recv(c->fd, c->buffer_ptr, 1, 0)))
895 if (ff_neterrno() != AVERROR(EAGAIN) &&
896 ff_neterrno() != AVERROR(EINTR))
900 /* search for end of request. */
901 c->buffer_ptr += len;
903 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
904 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
905 /* request found : parse it and reply */
906 if (c->state == HTTPSTATE_WAIT_REQUEST) {
907 ret = http_parse_request(c);
909 ret = rtsp_parse_request(c);
913 } else if (ptr >= c->buffer_end) {
914 /* request too long: cannot do anything */
916 } else goto read_loop;
920 case HTTPSTATE_SEND_HEADER:
921 if (c->poll_entry->revents & (POLLERR | POLLHUP))
924 /* no need to write if no events */
925 if (!(c->poll_entry->revents & POLLOUT))
927 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
929 if (ff_neterrno() != AVERROR(EAGAIN) &&
930 ff_neterrno() != AVERROR(EINTR)) {
931 goto close_connection;
935 c->buffer_ptr += len;
937 c->stream->bytes_served += len;
938 c->data_count += len;
939 if (c->buffer_ptr >= c->buffer_end) {
940 av_freep(&c->pb_buffer);
944 /* all the buffer was sent : synchronize to the incoming
946 c->state = HTTPSTATE_SEND_DATA_HEADER;
947 c->buffer_ptr = c->buffer_end = c->buffer;
951 case HTTPSTATE_SEND_DATA:
952 case HTTPSTATE_SEND_DATA_HEADER:
953 case HTTPSTATE_SEND_DATA_TRAILER:
954 /* for packetized output, we consider we can always write (the
955 input streams set the speed). It may be better to verify
956 that we do not rely too much on the kernel queues */
957 if (!c->is_packetized) {
958 if (c->poll_entry->revents & (POLLERR | POLLHUP))
961 /* no need to read if no events */
962 if (!(c->poll_entry->revents & POLLOUT))
965 if (http_send_data(c) < 0)
967 /* close connection if trailer sent */
968 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
971 case HTTPSTATE_RECEIVE_DATA:
972 /* no need to read if no events */
973 if (c->poll_entry->revents & (POLLERR | POLLHUP))
975 if (!(c->poll_entry->revents & POLLIN))
977 if (http_receive_data(c) < 0)
980 case HTTPSTATE_WAIT_FEED:
981 /* no need to read if no events */
982 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
985 /* nothing to do, we'll be waken up by incoming feed packets */
988 case RTSPSTATE_SEND_REPLY:
989 if (c->poll_entry->revents & (POLLERR | POLLHUP))
990 goto close_connection;
991 /* no need to write if no events */
992 if (!(c->poll_entry->revents & POLLOUT))
994 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
996 if (ff_neterrno() != AVERROR(EAGAIN) &&
997 ff_neterrno() != AVERROR(EINTR)) {
998 goto close_connection;
1002 c->buffer_ptr += len;
1003 c->data_count += len;
1004 if (c->buffer_ptr >= c->buffer_end) {
1005 /* all the buffer was sent : wait for a new request */
1006 av_freep(&c->pb_buffer);
1007 start_wait_request(c, 1);
1010 case RTSPSTATE_SEND_PACKET:
1011 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1012 av_freep(&c->packet_buffer);
1015 /* no need to write if no events */
1016 if (!(c->poll_entry->revents & POLLOUT))
1018 len = send(c->fd, c->packet_buffer_ptr,
1019 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1021 if (ff_neterrno() != AVERROR(EAGAIN) &&
1022 ff_neterrno() != AVERROR(EINTR)) {
1023 /* error : close connection */
1024 av_freep(&c->packet_buffer);
1029 c->packet_buffer_ptr += len;
1030 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1031 /* all the buffer was sent : wait for a new request */
1032 av_freep(&c->packet_buffer);
1033 c->state = RTSPSTATE_WAIT_REQUEST;
1036 case HTTPSTATE_READY:
1045 av_freep(&c->pb_buffer);
1049 static int extract_rates(char *rates, int ratelen, const char *request)
1053 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1054 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1055 const char *q = p + 7;
1057 while (*q && *q != '\n' && av_isspace(*q))
1060 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1066 memset(rates, 0xff, ratelen);
1069 while (*q && *q != '\n' && *q != ':')
1072 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1076 if (stream_no < ratelen && stream_no >= 0)
1077 rates[stream_no] = rate_no;
1079 while (*q && *q != '\n' && !av_isspace(*q))
1086 p = strchr(p, '\n');
1096 static int find_stream_in_feed(FFServerStream *feed, AVCodecContext *codec,
1100 int best_bitrate = 100000000;
1103 for (i = 0; i < feed->nb_streams; i++) {
1104 AVCodecContext *feed_codec = feed->streams[i]->codec;
1106 if (feed_codec->codec_id != codec->codec_id ||
1107 feed_codec->sample_rate != codec->sample_rate ||
1108 feed_codec->width != codec->width ||
1109 feed_codec->height != codec->height)
1112 /* Potential stream */
1114 /* We want the fastest stream less than bit_rate, or the slowest
1115 * faster than bit_rate
1118 if (feed_codec->bit_rate <= bit_rate) {
1119 if (best_bitrate > bit_rate ||
1120 feed_codec->bit_rate > best_bitrate) {
1121 best_bitrate = feed_codec->bit_rate;
1126 if (feed_codec->bit_rate < best_bitrate) {
1127 best_bitrate = feed_codec->bit_rate;
1134 static int modify_current_stream(HTTPContext *c, char *rates)
1137 FFServerStream *req = c->stream;
1138 int action_required = 0;
1140 /* Not much we can do for a feed */
1144 for (i = 0; i < req->nb_streams; i++) {
1145 AVCodecContext *codec = req->streams[i]->codec;
1149 c->switch_feed_streams[i] = req->feed_streams[i];
1152 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1155 /* Wants off or slow */
1156 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1158 /* This doesn't work well when it turns off the only stream! */
1159 c->switch_feed_streams[i] = -2;
1160 c->feed_streams[i] = -2;
1165 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1166 action_required = 1;
1169 return action_required;
1172 static void get_word(char *buf, int buf_size, const char **pp)
1178 p += strspn(p, SPACE_CHARS);
1180 while (!av_isspace(*p) && *p != '\0') {
1181 if ((q - buf) < buf_size - 1)
1190 static FFServerIPAddressACL* parse_dynamic_acl(FFServerStream *stream,
1196 FFServerIPAddressACL *acl = NULL;
1200 f = fopen(stream->dynamic_acl, "r");
1202 perror(stream->dynamic_acl);
1206 acl = av_mallocz(sizeof(FFServerIPAddressACL));
1209 while (fgets(line, sizeof(line), f)) {
1212 while (av_isspace(*p))
1214 if (*p == '\0' || *p == '#')
1216 ffserver_get_arg(cmd, sizeof(cmd), &p);
1218 if (!av_strcasecmp(cmd, "ACL"))
1219 ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl,
1227 static void free_acl_list(FFServerIPAddressACL *in_acl)
1229 FFServerIPAddressACL *pacl, *pacl2;
1239 static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c)
1241 enum FFServerIPAddressAction last_action = IP_DENY;
1242 FFServerIPAddressACL *acl;
1243 struct in_addr *src = &c->from_addr.sin_addr;
1244 unsigned long src_addr = src->s_addr;
1246 for (acl = in_acl; acl; acl = acl->next) {
1247 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1248 return (acl->action == IP_ALLOW) ? 1 : 0;
1249 last_action = acl->action;
1252 /* Nothing matched, so return not the last action */
1253 return (last_action == IP_DENY) ? 1 : 0;
1256 static int validate_acl(FFServerStream *stream, HTTPContext *c)
1259 FFServerIPAddressACL *acl;
1261 /* if stream->acl is null validate_acl_list will return 1 */
1262 ret = validate_acl_list(stream->acl, c);
1264 if (stream->dynamic_acl[0]) {
1265 acl = parse_dynamic_acl(stream, c);
1267 ret = validate_acl_list(acl, c);
1275 /* compute the real filename of a file by matching it without its
1276 extensions to all the stream's filenames */
1277 static void compute_real_filename(char *filename, int max_size)
1282 FFServerStream *stream;
1284 /* compute filename by matching without the file extensions */
1285 av_strlcpy(file1, filename, sizeof(file1));
1286 p = strrchr(file1, '.');
1289 for(stream = config.first_stream; stream; stream = stream->next) {
1290 av_strlcpy(file2, stream->filename, sizeof(file2));
1291 p = strrchr(file2, '.');
1294 if (!strcmp(file1, file2)) {
1295 av_strlcpy(filename, stream->filename, max_size);
1310 /* parse HTTP request and prepare header */
1311 static int http_parse_request(HTTPContext *c)
1315 enum RedirType redir_type;
1317 char info[1024], filename[1024];
1321 const char *mime_type;
1322 FFServerStream *stream;
1325 const char *useragent = 0;
1328 get_word(cmd, sizeof(cmd), &p);
1329 av_strlcpy(c->method, cmd, sizeof(c->method));
1331 if (!strcmp(cmd, "GET"))
1333 else if (!strcmp(cmd, "POST"))
1338 get_word(url, sizeof(url), &p);
1339 av_strlcpy(c->url, url, sizeof(c->url));
1341 get_word(protocol, sizeof(protocol), (const char **)&p);
1342 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1345 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1348 http_log("%s - - New connection: %s %s\n",
1349 inet_ntoa(c->from_addr.sin_addr), cmd, url);
1351 /* find the filename and the optional info string in the request */
1352 p1 = strchr(url, '?');
1354 av_strlcpy(info, p1, sizeof(info));
1359 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1361 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1362 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1364 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1368 p = strchr(p, '\n');
1375 redir_type = REDIR_NONE;
1376 if (av_match_ext(filename, "asx")) {
1377 redir_type = REDIR_ASX;
1378 filename[strlen(filename)-1] = 'f';
1379 } else if (av_match_ext(filename, "asf") &&
1380 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) {
1381 /* if this isn't WMP or lookalike, return the redirector file */
1382 redir_type = REDIR_ASF;
1383 } else if (av_match_ext(filename, "rpm,ram")) {
1384 redir_type = REDIR_RAM;
1385 strcpy(filename + strlen(filename)-2, "m");
1386 } else if (av_match_ext(filename, "rtsp")) {
1387 redir_type = REDIR_RTSP;
1388 compute_real_filename(filename, sizeof(filename) - 1);
1389 } else if (av_match_ext(filename, "sdp")) {
1390 redir_type = REDIR_SDP;
1391 compute_real_filename(filename, sizeof(filename) - 1);
1394 // "redirect" / request to index.html
1395 if (!strlen(filename))
1396 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1398 stream = config.first_stream;
1400 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1402 stream = stream->next;
1405 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1406 http_log("File '%s' not found\n", url);
1411 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1412 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1414 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1415 c->http_error = 301;
1417 snprintf(q, c->buffer_size,
1418 "HTTP/1.0 301 Moved\r\n"
1420 "Content-type: text/html\r\n"
1422 "<html><head><title>Moved</title></head><body>\r\n"
1423 "You should be <a href=\"%s\">redirected</a>.\r\n"
1424 "</body></html>\r\n",
1425 stream->feed_filename, stream->feed_filename);
1427 /* prepare output buffer */
1428 c->buffer_ptr = c->buffer;
1430 c->state = HTTPSTATE_SEND_HEADER;
1434 /* If this is WMP, get the rate information */
1435 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1436 if (modify_current_stream(c, ratebuf)) {
1437 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1438 if (c->switch_feed_streams[i] >= 0)
1439 c->switch_feed_streams[i] = -1;
1444 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1445 current_bandwidth += stream->bandwidth;
1447 /* If already streaming this feed, do not let start another feeder. */
1448 if (stream->feed_opened) {
1449 snprintf(msg, sizeof(msg), "This feed is already being received.");
1450 http_log("Feed '%s' already being received\n", stream->feed_filename);
1454 if (c->post == 0 && config.max_bandwidth < current_bandwidth) {
1455 c->http_error = 503;
1457 snprintf(q, c->buffer_size,
1458 "HTTP/1.0 503 Server too busy\r\n"
1459 "Content-type: text/html\r\n"
1461 "<html><head><title>Too busy</title></head><body>\r\n"
1462 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1463 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1464 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1465 "</body></html>\r\n",
1466 current_bandwidth, config.max_bandwidth);
1468 /* prepare output buffer */
1469 c->buffer_ptr = c->buffer;
1471 c->state = HTTPSTATE_SEND_HEADER;
1475 if (redir_type != REDIR_NONE) {
1476 const char *hostinfo = 0;
1478 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1479 if (av_strncasecmp(p, "Host:", 5) == 0) {
1483 p = strchr(p, '\n');
1494 while (av_isspace(*hostinfo))
1497 eoh = strchr(hostinfo, '\n');
1499 if (eoh[-1] == '\r')
1502 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1503 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1504 hostbuf[eoh - hostinfo] = 0;
1506 c->http_error = 200;
1508 switch(redir_type) {
1510 snprintf(q, c->buffer_size,
1511 "HTTP/1.0 200 ASX Follows\r\n"
1512 "Content-type: video/x-ms-asf\r\n"
1514 "<ASX Version=\"3\">\r\n"
1515 //"<!-- Autogenerated by ffserver -->\r\n"
1516 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1517 "</ASX>\r\n", hostbuf, filename, info);
1521 snprintf(q, c->buffer_size,
1522 "HTTP/1.0 200 RAM Follows\r\n"
1523 "Content-type: audio/x-pn-realaudio\r\n"
1525 "# Autogenerated by ffserver\r\n"
1526 "http://%s/%s%s\r\n", hostbuf, filename, info);
1530 snprintf(q, c->buffer_size,
1531 "HTTP/1.0 200 ASF Redirect follows\r\n"
1532 "Content-type: video/x-ms-asf\r\n"
1535 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1540 char hostname[256], *p;
1541 /* extract only hostname */
1542 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1543 p = strrchr(hostname, ':');
1546 snprintf(q, c->buffer_size,
1547 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1548 /* XXX: incorrect MIME type ? */
1549 "Content-type: application/x-rtsp\r\n"
1551 "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
1560 struct sockaddr_in my_addr;
1562 snprintf(q, c->buffer_size,
1563 "HTTP/1.0 200 OK\r\n"
1564 "Content-type: application/sdp\r\n"
1568 len = sizeof(my_addr);
1570 /* XXX: Should probably fail? */
1571 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1572 http_log("getsockname() failed\n");
1574 /* XXX: should use a dynamic buffer */
1575 sdp_data_size = prepare_sdp_description(stream,
1578 if (sdp_data_size > 0) {
1579 memcpy(q, sdp_data, sdp_data_size);
1591 /* prepare output buffer */
1592 c->buffer_ptr = c->buffer;
1594 c->state = HTTPSTATE_SEND_HEADER;
1600 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1604 stream->conns_served++;
1606 /* XXX: add there authenticate and IP match */
1609 /* if post, it means a feed is being sent */
1610 if (!stream->is_feed) {
1611 /* However it might be a status report from WMP! Let us log the
1612 * data as it might come handy one day. */
1613 const char *logline = 0;
1616 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1617 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1621 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1622 client_id = strtol(p + 18, 0, 10);
1623 p = strchr(p, '\n');
1631 char *eol = strchr(logline, '\n');
1636 if (eol[-1] == '\r')
1638 http_log("%.*s\n", (int) (eol - logline), logline);
1639 c->suppress_log = 1;
1644 http_log("\nGot request:\n%s\n", c->buffer);
1647 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1650 /* Now we have to find the client_id */
1651 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1652 if (wmpc->wmp_client_id == client_id)
1656 if (wmpc && modify_current_stream(wmpc, ratebuf))
1657 wmpc->switch_pending = 1;
1660 snprintf(msg, sizeof(msg), "POST command not handled");
1664 if (http_start_receive_data(c) < 0) {
1665 snprintf(msg, sizeof(msg), "could not open feed");
1669 c->state = HTTPSTATE_RECEIVE_DATA;
1674 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1675 http_log("\nGot request:\n%s\n", c->buffer);
1678 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1681 /* open input stream */
1682 if (open_input_stream(c, info) < 0) {
1683 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1687 /* prepare HTTP header */
1689 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1690 mime_type = c->stream->fmt->mime_type;
1692 mime_type = "application/x-octet-stream";
1693 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1695 /* for asf, we need extra headers */
1696 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1697 /* Need to allocate a client id */
1699 c->wmp_client_id = av_lfg_get(&random_state);
1701 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);
1703 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1704 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1705 q = c->buffer + strlen(c->buffer);
1707 /* prepare output buffer */
1709 c->buffer_ptr = c->buffer;
1711 c->state = HTTPSTATE_SEND_HEADER;
1714 c->http_error = 404;
1717 snprintf(q, c->buffer_size,
1718 "HTTP/1.0 404 Not Found\r\n"
1719 "Content-type: text/html\r\n"
1722 "<head><title>404 Not Found</title></head>\n"
1726 /* prepare output buffer */
1727 c->buffer_ptr = c->buffer;
1729 c->state = HTTPSTATE_SEND_HEADER;
1733 c->http_error = 200; /* horrible : we use this value to avoid
1734 going to the send data state */
1735 c->state = HTTPSTATE_SEND_HEADER;
1739 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1741 static const char suffix[] = " kMGTP";
1744 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1746 avio_printf(pb, "%"PRId64"%c", count, *s);
1749 static void compute_status(HTTPContext *c)
1752 FFServerStream *stream;
1758 if (avio_open_dyn_buf(&pb) < 0) {
1759 /* XXX: return an error ? */
1760 c->buffer_ptr = c->buffer;
1761 c->buffer_end = c->buffer;
1765 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1766 avio_printf(pb, "Content-type: text/html\r\n");
1767 avio_printf(pb, "Pragma: no-cache\r\n");
1768 avio_printf(pb, "\r\n");
1770 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1771 if (c->stream->feed_filename[0])
1772 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n",
1773 c->stream->feed_filename);
1774 avio_printf(pb, "</head>\n<body>");
1775 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1777 avio_printf(pb, "<h2>Available Streams</h2>\n");
1778 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1779 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");
1780 stream = config.first_stream;
1782 char sfilename[1024];
1785 if (stream->feed == stream) {
1786 stream = stream->next;
1790 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1791 eosf = sfilename + strlen(sfilename);
1792 if (eosf - sfilename >= 4) {
1793 if (strcmp(eosf - 4, ".asf") == 0)
1794 strcpy(eosf - 4, ".asx");
1795 else if (strcmp(eosf - 3, ".rm") == 0)
1796 strcpy(eosf - 3, ".ram");
1797 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1798 /* generate a sample RTSP director if
1799 unicast. Generate an SDP redirector if
1801 eosf = strrchr(sfilename, '.');
1803 eosf = sfilename + strlen(sfilename);
1804 if (stream->is_multicast)
1805 strcpy(eosf, ".sdp");
1807 strcpy(eosf, ".rtsp");
1811 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1812 sfilename, stream->filename);
1813 avio_printf(pb, "<td align=right> %d <td align=right> ",
1814 stream->conns_served);
1815 fmt_bytecount(pb, stream->bytes_served);
1817 switch(stream->stream_type) {
1818 case STREAM_TYPE_LIVE: {
1819 int audio_bit_rate = 0;
1820 int video_bit_rate = 0;
1821 const char *audio_codec_name = "";
1822 const char *video_codec_name = "";
1823 const char *audio_codec_name_extra = "";
1824 const char *video_codec_name_extra = "";
1826 for(i=0;i<stream->nb_streams;i++) {
1827 AVStream *st = stream->streams[i];
1828 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1830 switch(st->codec->codec_type) {
1831 case AVMEDIA_TYPE_AUDIO:
1832 audio_bit_rate += st->codec->bit_rate;
1834 if (*audio_codec_name)
1835 audio_codec_name_extra = "...";
1836 audio_codec_name = codec->name;
1839 case AVMEDIA_TYPE_VIDEO:
1840 video_bit_rate += st->codec->bit_rate;
1842 if (*video_codec_name)
1843 video_codec_name_extra = "...";
1844 video_codec_name = codec->name;
1847 case AVMEDIA_TYPE_DATA:
1848 video_bit_rate += st->codec->bit_rate;
1855 avio_printf(pb, "<td align=center> %s <td align=right> %d "
1856 "<td align=right> %d <td> %s %s <td align=right> "
1858 stream->fmt->name, stream->bandwidth,
1859 video_bit_rate / 1000, video_codec_name,
1860 video_codec_name_extra, audio_bit_rate / 1000,
1861 audio_codec_name, audio_codec_name_extra);
1864 avio_printf(pb, "<td>%s", stream->feed->filename);
1866 avio_printf(pb, "<td>%s", stream->feed_filename);
1867 avio_printf(pb, "\n");
1871 avio_printf(pb, "<td align=center> - <td align=right> - "
1872 "<td align=right> - <td><td align=right> - <td>\n");
1875 stream = stream->next;
1877 avio_printf(pb, "</table>\n");
1879 stream = config.first_stream;
1882 if (stream->feed != stream) {
1883 stream = stream->next;
1887 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1889 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1896 /* This is somewhat linux specific I guess */
1897 snprintf(ps_cmd, sizeof(ps_cmd),
1898 "ps -o \"%%cpu,cputime\" --no-headers %d",
1901 pid_stat = popen(ps_cmd, "r");
1906 if (fscanf(pid_stat, "%9s %63s", cpuperc, cpuused) == 2) {
1907 avio_printf(pb, "Currently using %s%% of the cpu. "
1908 "Total time used %s.\n",
1916 avio_printf(pb, "<p>");
1919 avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>"
1920 "type<th>kbits/s<th align=left>codec<th align=left>"
1923 for (i = 0; i < stream->nb_streams; i++) {
1924 AVStream *st = stream->streams[i];
1925 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1926 const char *type = "unknown";
1927 char parameters[64];
1931 switch(st->codec->codec_type) {
1932 case AVMEDIA_TYPE_AUDIO:
1934 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz",
1935 st->codec->channels, st->codec->sample_rate);
1937 case AVMEDIA_TYPE_VIDEO:
1939 snprintf(parameters, sizeof(parameters),
1940 "%dx%d, q=%d-%d, fps=%d", st->codec->width,
1941 st->codec->height, st->codec->qmin, st->codec->qmax,
1942 st->codec->time_base.den / st->codec->time_base.num);
1948 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d"
1950 i, type, st->codec->bit_rate/1000,
1951 codec ? codec->name : "", parameters);
1954 avio_printf(pb, "</table>\n");
1955 stream = stream->next;
1958 /* connection status */
1959 avio_printf(pb, "<h2>Connection Status</h2>\n");
1961 avio_printf(pb, "Number of connections: %d / %d<br>\n",
1962 nb_connections, config.nb_max_connections);
1964 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1965 current_bandwidth, config.max_bandwidth);
1967 avio_printf(pb, "<table>\n");
1968 avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target "
1969 "bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1970 c1 = first_http_ctx;
1978 for (j = 0; j < c1->stream->nb_streams; j++) {
1979 if (!c1->stream->feed)
1980 bitrate += c1->stream->streams[j]->codec->bit_rate;
1981 else if (c1->feed_streams[j] >= 0)
1982 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1987 p = inet_ntoa(c1->from_addr.sin_addr);
1988 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s"
1990 i, c1->stream ? c1->stream->filename : "",
1991 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", p,
1992 c1->protocol, http_state[c1->state]);
1993 fmt_bytecount(pb, bitrate);
1994 avio_printf(pb, "<td align=right>");
1995 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1996 avio_printf(pb, "<td align=right>");
1997 fmt_bytecount(pb, c1->data_count);
1998 avio_printf(pb, "\n");
2001 avio_printf(pb, "</table>\n");
2006 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2007 avio_printf(pb, "</body>\n</html>\n");
2009 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2010 c->buffer_ptr = c->pb_buffer;
2011 c->buffer_end = c->pb_buffer + len;
2014 static int open_input_stream(HTTPContext *c, const char *info)
2017 char input_filename[1024];
2018 AVFormatContext *s = NULL;
2019 int buf_size, i, ret;
2022 /* find file name */
2023 if (c->stream->feed) {
2024 strcpy(input_filename, c->stream->feed->feed_filename);
2025 buf_size = FFM_PACKET_SIZE;
2026 /* compute position (absolute time) */
2027 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2028 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2029 http_log("Invalid date specification '%s' for stream\n", buf);
2032 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2033 int prebuffer = strtol(buf, 0, 10);
2034 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2036 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2038 strcpy(input_filename, c->stream->feed_filename);
2040 /* compute position (relative time) */
2041 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2042 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2043 http_log("Invalid date specification '%s' for stream\n", buf);
2049 if (!input_filename[0]) {
2050 http_log("No filename was specified for stream\n");
2051 return AVERROR(EINVAL);
2055 ret = avformat_open_input(&s, input_filename, c->stream->ifmt,
2056 &c->stream->in_opts);
2058 http_log("Could not open input '%s': %s\n",
2059 input_filename, av_err2str(ret));
2063 /* set buffer size */
2064 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2066 s->flags |= AVFMT_FLAG_GENPTS;
2068 if (strcmp(s->iformat->name, "ffm") &&
2069 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2070 http_log("Could not find stream info for input '%s'\n", input_filename);
2071 avformat_close_input(&s);
2075 /* choose stream as clock source (we favor the video stream if
2076 * present) for packet sending */
2077 c->pts_stream_index = 0;
2078 for(i=0;i<c->stream->nb_streams;i++) {
2079 if (c->pts_stream_index == 0 &&
2080 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2081 c->pts_stream_index = i;
2085 if (c->fmt_in->iformat->read_seek)
2086 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2087 /* set the start time (needed for maxtime and RTP packet timing) */
2088 c->start_time = cur_time;
2089 c->first_pts = AV_NOPTS_VALUE;
2093 /* return the server clock (in us) */
2094 static int64_t get_server_clock(HTTPContext *c)
2096 /* compute current pts value from system time */
2097 return (cur_time - c->start_time) * 1000;
2100 /* return the estimated time at which the current packet must be sent
2102 static int64_t get_packet_send_clock(HTTPContext *c)
2104 int bytes_left, bytes_sent, frame_bytes;
2106 frame_bytes = c->cur_frame_bytes;
2107 if (frame_bytes <= 0)
2110 bytes_left = c->buffer_end - c->buffer_ptr;
2111 bytes_sent = frame_bytes - bytes_left;
2112 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2117 static int http_prepare_data(HTTPContext *c)
2120 AVFormatContext *ctx;
2122 av_freep(&c->pb_buffer);
2124 case HTTPSTATE_SEND_DATA_HEADER:
2125 ctx = avformat_alloc_context();
2128 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2129 c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams,
2130 sizeof(AVStream *));
2132 for(i=0;i<c->stream->nb_streams;i++) {
2134 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2135 /* if file or feed, then just take streams from FFServerStream struct */
2136 if (!c->stream->feed ||
2137 c->stream->feed == c->stream)
2138 src = c->stream->streams[i];
2140 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2142 *(c->fmt_ctx.streams[i]) = *src;
2143 c->fmt_ctx.streams[i]->priv_data = 0;
2144 /* XXX: should be done in AVStream, not in codec */
2145 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2147 /* set output format parameters */
2148 c->fmt_ctx.oformat = c->stream->fmt;
2149 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2151 c->got_key_frame = 0;
2153 /* prepare header and save header data in a stream */
2154 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2155 /* XXX: potential leak */
2158 c->fmt_ctx.pb->seekable = 0;
2161 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2162 * Default value from FFmpeg
2163 * Try to set it using configuration option
2165 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2167 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2168 http_log("Error writing output header for stream '%s': %s\n",
2169 c->stream->filename, av_err2str(ret));
2172 av_dict_free(&c->fmt_ctx.metadata);
2174 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2175 c->buffer_ptr = c->pb_buffer;
2176 c->buffer_end = c->pb_buffer + len;
2178 c->state = HTTPSTATE_SEND_DATA;
2179 c->last_packet_sent = 0;
2181 case HTTPSTATE_SEND_DATA:
2182 /* find a new packet */
2183 /* read a packet from the input stream */
2184 if (c->stream->feed)
2185 ffm_set_write_index(c->fmt_in,
2186 c->stream->feed->feed_write_index,
2187 c->stream->feed->feed_size);
2189 if (c->stream->max_time &&
2190 c->stream->max_time + c->start_time - cur_time < 0)
2191 /* We have timed out */
2192 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2196 ret = av_read_frame(c->fmt_in, &pkt);
2198 if (c->stream->feed) {
2199 /* if coming from feed, it means we reached the end of the
2200 ffm file, so must wait for more data */
2201 c->state = HTTPSTATE_WAIT_FEED;
2202 return 1; /* state changed */
2203 } else if (ret == AVERROR(EAGAIN)) {
2204 /* input not ready, come back later */
2207 if (c->stream->loop) {
2208 avformat_close_input(&c->fmt_in);
2209 if (open_input_stream(c, "") < 0)
2214 /* must send trailer now because EOF or error */
2215 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2219 int source_index = pkt.stream_index;
2220 /* update first pts if needed */
2221 if (c->first_pts == AV_NOPTS_VALUE) {
2222 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2223 c->start_time = cur_time;
2225 /* send it to the appropriate stream */
2226 if (c->stream->feed) {
2227 /* if coming from a feed, select the right stream */
2228 if (c->switch_pending) {
2229 c->switch_pending = 0;
2230 for(i=0;i<c->stream->nb_streams;i++) {
2231 if (c->switch_feed_streams[i] == pkt.stream_index)
2232 if (pkt.flags & AV_PKT_FLAG_KEY)
2233 c->switch_feed_streams[i] = -1;
2234 if (c->switch_feed_streams[i] >= 0)
2235 c->switch_pending = 1;
2238 for(i=0;i<c->stream->nb_streams;i++) {
2239 if (c->stream->feed_streams[i] == pkt.stream_index) {
2240 AVStream *st = c->fmt_in->streams[source_index];
2241 pkt.stream_index = i;
2242 if (pkt.flags & AV_PKT_FLAG_KEY &&
2243 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2244 c->stream->nb_streams == 1))
2245 c->got_key_frame = 1;
2246 if (!c->stream->send_on_key || c->got_key_frame)
2251 AVCodecContext *codec;
2252 AVStream *ist, *ost;
2254 ist = c->fmt_in->streams[source_index];
2255 /* specific handling for RTP: we use several
2256 * output streams (one for each RTP connection).
2257 * XXX: need more abstract handling */
2258 if (c->is_packetized) {
2259 /* compute send time and duration */
2260 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2261 c->cur_pts -= c->first_pts;
2262 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2263 /* find RTP context */
2264 c->packet_stream_index = pkt.stream_index;
2265 ctx = c->rtp_ctx[c->packet_stream_index];
2267 av_free_packet(&pkt);
2270 codec = ctx->streams[0]->codec;
2271 /* only one stream per RTP connection */
2272 pkt.stream_index = 0;
2276 codec = ctx->streams[pkt.stream_index]->codec;
2279 if (c->is_packetized) {
2280 int max_packet_size;
2281 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2282 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2284 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2285 ret = ffio_open_dyn_packet_buf(&ctx->pb,
2288 ret = avio_open_dyn_buf(&ctx->pb);
2291 /* XXX: potential leak */
2294 ost = ctx->streams[pkt.stream_index];
2296 ctx->pb->seekable = 0;
2297 if (pkt.dts != AV_NOPTS_VALUE)
2298 pkt.dts = av_rescale_q(pkt.dts, ist->time_base,
2300 if (pkt.pts != AV_NOPTS_VALUE)
2301 pkt.pts = av_rescale_q(pkt.pts, ist->time_base,
2303 pkt.duration = av_rescale_q(pkt.duration, ist->time_base,
2305 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2306 http_log("Error writing frame to output for stream '%s': %s\n",
2307 c->stream->filename, av_err2str(ret));
2308 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2311 av_freep(&c->pb_buffer);
2312 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2313 c->cur_frame_bytes = len;
2314 c->buffer_ptr = c->pb_buffer;
2315 c->buffer_end = c->pb_buffer + len;
2317 codec->frame_number++;
2319 av_free_packet(&pkt);
2323 av_free_packet(&pkt);
2328 case HTTPSTATE_SEND_DATA_TRAILER:
2329 /* last packet test ? */
2330 if (c->last_packet_sent || c->is_packetized)
2333 /* prepare header */
2334 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2335 /* XXX: potential leak */
2338 c->fmt_ctx.pb->seekable = 0;
2339 av_write_trailer(ctx);
2340 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2341 c->buffer_ptr = c->pb_buffer;
2342 c->buffer_end = c->pb_buffer + len;
2344 c->last_packet_sent = 1;
2350 /* should convert the format at the same time */
2351 /* send data starting at c->buffer_ptr to the output connection
2352 * (either UDP or TCP) */
2353 static int http_send_data(HTTPContext *c)
2358 if (c->buffer_ptr >= c->buffer_end) {
2359 ret = http_prepare_data(c);
2363 /* state change requested */
2366 if (c->is_packetized) {
2367 /* RTP data output */
2368 len = c->buffer_end - c->buffer_ptr;
2370 /* fail safe - should never happen */
2372 c->buffer_ptr = c->buffer_end;
2375 len = (c->buffer_ptr[0] << 24) |
2376 (c->buffer_ptr[1] << 16) |
2377 (c->buffer_ptr[2] << 8) |
2379 if (len > (c->buffer_end - c->buffer_ptr))
2381 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2382 /* nothing to send yet: we can wait */
2386 c->data_count += len;
2387 update_datarate(&c->datarate, c->data_count);
2389 c->stream->bytes_served += len;
2391 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2392 /* RTP packets are sent inside the RTSP TCP connection */
2394 int interleaved_index, size;
2396 HTTPContext *rtsp_c;
2399 /* if no RTSP connection left, error */
2402 /* if already sending something, then wait. */
2403 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2405 if (avio_open_dyn_buf(&pb) < 0)
2407 interleaved_index = c->packet_stream_index * 2;
2408 /* RTCP packets are sent at odd indexes */
2409 if (c->buffer_ptr[1] == 200)
2410 interleaved_index++;
2411 /* write RTSP TCP header */
2413 header[1] = interleaved_index;
2414 header[2] = len >> 8;
2416 avio_write(pb, header, 4);
2417 /* write RTP packet data */
2419 avio_write(pb, c->buffer_ptr, len);
2420 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2421 /* prepare asynchronous TCP sending */
2422 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2423 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2424 c->buffer_ptr += len;
2426 /* send everything we can NOW */
2427 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2428 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2430 rtsp_c->packet_buffer_ptr += len;
2431 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2432 /* if we could not send all the data, we will
2433 send it later, so a new state is needed to
2434 "lock" the RTSP TCP connection */
2435 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2438 /* all data has been sent */
2439 av_freep(&c->packet_buffer);
2441 /* send RTP packet directly in UDP */
2443 ffurl_write(c->rtp_handles[c->packet_stream_index],
2444 c->buffer_ptr, len);
2445 c->buffer_ptr += len;
2446 /* here we continue as we can send several packets
2450 /* TCP data output */
2451 len = send(c->fd, c->buffer_ptr,
2452 c->buffer_end - c->buffer_ptr, 0);
2454 if (ff_neterrno() != AVERROR(EAGAIN) &&
2455 ff_neterrno() != AVERROR(EINTR))
2456 /* error : close connection */
2461 c->buffer_ptr += len;
2463 c->data_count += len;
2464 update_datarate(&c->datarate, c->data_count);
2466 c->stream->bytes_served += len;
2474 static int http_start_receive_data(HTTPContext *c)
2479 if (c->stream->feed_opened) {
2480 http_log("Stream feed '%s' was not opened\n",
2481 c->stream->feed_filename);
2482 return AVERROR(EINVAL);
2485 /* Don't permit writing to this one */
2486 if (c->stream->readonly) {
2487 http_log("Cannot write to read-only file '%s'\n",
2488 c->stream->feed_filename);
2489 return AVERROR(EINVAL);
2493 fd = open(c->stream->feed_filename, O_RDWR);
2495 ret = AVERROR(errno);
2496 http_log("Could not open feed file '%s': %s\n",
2497 c->stream->feed_filename, strerror(errno));
2502 if (c->stream->truncate) {
2503 /* truncate feed file */
2504 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2505 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2506 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2507 ret = AVERROR(errno);
2508 http_log("Error truncating feed file '%s': %s\n",
2509 c->stream->feed_filename, strerror(errno));
2513 ret = ffm_read_write_index(fd);
2515 http_log("Error reading write index from feed file '%s': %s\n",
2516 c->stream->feed_filename, strerror(errno));
2519 c->stream->feed_write_index = ret;
2523 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd),
2525 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2526 lseek(fd, 0, SEEK_SET);
2528 /* init buffer input */
2529 c->buffer_ptr = c->buffer;
2530 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2531 c->stream->feed_opened = 1;
2532 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2536 static int http_receive_data(HTTPContext *c)
2539 int len, loop_run = 0;
2541 while (c->chunked_encoding && !c->chunk_size &&
2542 c->buffer_end > c->buffer_ptr) {
2543 /* read chunk header, if present */
2544 len = recv(c->fd, c->buffer_ptr, 1, 0);
2547 if (ff_neterrno() != AVERROR(EAGAIN) &&
2548 ff_neterrno() != AVERROR(EINTR))
2549 /* error : close connection */
2552 } else if (len == 0) {
2553 /* end of connection : close it */
2555 } else if (c->buffer_ptr - c->buffer >= 2 &&
2556 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2557 c->chunk_size = strtol(c->buffer, 0, 16);
2558 if (c->chunk_size == 0) // end of stream
2560 c->buffer_ptr = c->buffer;
2562 } else if (++loop_run > 10) {
2563 /* no chunk header, abort */
2570 if (c->buffer_end > c->buffer_ptr) {
2571 len = recv(c->fd, c->buffer_ptr,
2572 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2574 if (ff_neterrno() != AVERROR(EAGAIN) &&
2575 ff_neterrno() != AVERROR(EINTR))
2576 /* error : close connection */
2578 } else if (len == 0)
2579 /* end of connection : close it */
2582 c->chunk_size -= len;
2583 c->buffer_ptr += len;
2584 c->data_count += len;
2585 update_datarate(&c->datarate, c->data_count);
2589 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2590 if (c->buffer[0] != 'f' ||
2591 c->buffer[1] != 'm') {
2592 http_log("Feed stream has become desynchronized -- disconnecting\n");
2597 if (c->buffer_ptr >= c->buffer_end) {
2598 FFServerStream *feed = c->stream;
2599 /* a packet has been received : write it in the store, except
2601 if (c->data_count > FFM_PACKET_SIZE) {
2602 /* XXX: use llseek or url_seek
2603 * XXX: Should probably fail? */
2604 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2605 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2607 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2608 http_log("Error writing to feed file: %s\n", strerror(errno));
2612 feed->feed_write_index += FFM_PACKET_SIZE;
2613 /* update file size */
2614 if (feed->feed_write_index > c->stream->feed_size)
2615 feed->feed_size = feed->feed_write_index;
2617 /* handle wrap around if max file size reached */
2618 if (c->stream->feed_max_size &&
2619 feed->feed_write_index >= c->stream->feed_max_size)
2620 feed->feed_write_index = FFM_PACKET_SIZE;
2623 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2624 http_log("Error writing index to feed file: %s\n",
2629 /* wake up any waiting connections */
2630 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2631 if (c1->state == HTTPSTATE_WAIT_FEED &&
2632 c1->stream->feed == c->stream->feed)
2633 c1->state = HTTPSTATE_SEND_DATA;
2636 /* We have a header in our hands that contains useful data */
2637 AVFormatContext *s = avformat_alloc_context();
2639 AVInputFormat *fmt_in;
2645 /* use feed output format name to find corresponding input format */
2646 fmt_in = av_find_input_format(feed->fmt->name);
2650 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2651 0, NULL, NULL, NULL, NULL);
2655 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2660 /* Now we have the actual streams */
2661 if (s->nb_streams != feed->nb_streams) {
2662 avformat_close_input(&s);
2664 http_log("Feed '%s' stream number does not match registered feed\n",
2665 c->stream->feed_filename);
2669 for (i = 0; i < s->nb_streams; i++) {
2670 AVStream *fst = feed->streams[i];
2671 AVStream *st = s->streams[i];
2672 avcodec_copy_context(fst->codec, st->codec);
2675 avformat_close_input(&s);
2678 c->buffer_ptr = c->buffer;
2683 c->stream->feed_opened = 0;
2685 /* wake up any waiting connections to stop waiting for feed */
2686 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2687 if (c1->state == HTTPSTATE_WAIT_FEED &&
2688 c1->stream->feed == c->stream->feed)
2689 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2694 /********************************************************************/
2697 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2704 str = RTSP_STATUS_CODE2STRING(error_number);
2706 str = "Unknown Error";
2708 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2709 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2711 /* output GMT time */
2714 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2715 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2718 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2720 rtsp_reply_header(c, error_number);
2721 avio_printf(c->pb, "\r\n");
2724 static int rtsp_parse_request(HTTPContext *c)
2726 const char *p, *p1, *p2;
2732 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2734 c->buffer_ptr[0] = '\0';
2737 get_word(cmd, sizeof(cmd), &p);
2738 get_word(url, sizeof(url), &p);
2739 get_word(protocol, sizeof(protocol), &p);
2741 av_strlcpy(c->method, cmd, sizeof(c->method));
2742 av_strlcpy(c->url, url, sizeof(c->url));
2743 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2745 if (avio_open_dyn_buf(&c->pb) < 0) {
2746 /* XXX: cannot do more */
2747 c->pb = NULL; /* safety */
2751 /* check version name */
2752 if (strcmp(protocol, "RTSP/1.0")) {
2753 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2757 /* parse each header line */
2758 /* skip to next line */
2759 while (*p != '\n' && *p != '\0')
2763 while (*p != '\0') {
2764 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2768 if (p2 > p && p2[-1] == '\r')
2770 /* skip empty line */
2774 if (len > sizeof(line) - 1)
2775 len = sizeof(line) - 1;
2776 memcpy(line, p, len);
2778 ff_rtsp_parse_line(header, line, NULL, NULL);
2782 /* handle sequence number */
2783 c->seq = header->seq;
2785 if (!strcmp(cmd, "DESCRIBE"))
2786 rtsp_cmd_describe(c, url);
2787 else if (!strcmp(cmd, "OPTIONS"))
2788 rtsp_cmd_options(c, url);
2789 else if (!strcmp(cmd, "SETUP"))
2790 rtsp_cmd_setup(c, url, header);
2791 else if (!strcmp(cmd, "PLAY"))
2792 rtsp_cmd_play(c, url, header);
2793 else if (!strcmp(cmd, "PAUSE"))
2794 rtsp_cmd_interrupt(c, url, header, 1);
2795 else if (!strcmp(cmd, "TEARDOWN"))
2796 rtsp_cmd_interrupt(c, url, header, 0);
2798 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2801 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2802 c->pb = NULL; /* safety */
2804 /* XXX: cannot do more */
2807 c->buffer_ptr = c->pb_buffer;
2808 c->buffer_end = c->pb_buffer + len;
2809 c->state = RTSPSTATE_SEND_REPLY;
2813 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2814 struct in_addr my_ip)
2816 AVFormatContext *avc;
2817 AVStream *avs = NULL;
2818 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2819 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2824 avc = avformat_alloc_context();
2825 if (!avc || !rtp_format) {
2828 avc->oformat = rtp_format;
2829 av_dict_set(&avc->metadata, "title",
2830 entry ? entry->value : "No Title", 0);
2831 avc->nb_streams = stream->nb_streams;
2832 if (stream->is_multicast) {
2833 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2834 inet_ntoa(stream->multicast_ip),
2835 stream->multicast_port, stream->multicast_ttl);
2837 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2840 avc->streams = av_malloc_array(avc->nb_streams, sizeof(*avc->streams));
2844 avs = av_malloc_array(avc->nb_streams, sizeof(*avs));
2848 for(i = 0; i < stream->nb_streams; i++) {
2849 avc->streams[i] = &avs[i];
2850 avc->streams[i]->codec = stream->streams[i]->codec;
2852 *pbuffer = av_mallocz(2048);
2853 av_sdp_create(&avc, 1, *pbuffer, 2048);
2856 av_freep(&avc->streams);
2857 av_dict_free(&avc->metadata);
2861 return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2864 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2866 // rtsp_reply_header(c, RTSP_STATUS_OK);
2867 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2868 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2869 avio_printf(c->pb, "Public: %s\r\n",
2870 "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2871 avio_printf(c->pb, "\r\n");
2874 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2876 FFServerStream *stream;
2882 struct sockaddr_in my_addr;
2884 /* find which URL is asked */
2885 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2890 for(stream = config.first_stream; stream; stream = stream->next) {
2891 if (!stream->is_feed &&
2892 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2893 !strcmp(path, stream->filename)) {
2897 /* no stream found */
2898 rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
2902 /* prepare the media description in SDP format */
2904 /* get the host IP */
2905 len = sizeof(my_addr);
2906 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2907 content_length = prepare_sdp_description(stream, &content,
2909 if (content_length < 0) {
2910 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2913 rtsp_reply_header(c, RTSP_STATUS_OK);
2914 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2915 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2916 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2917 avio_printf(c->pb, "\r\n");
2918 avio_write(c->pb, content, content_length);
2922 static HTTPContext *find_rtp_session(const char *session_id)
2926 if (session_id[0] == '\0')
2929 for(c = first_http_ctx; c; c = c->next) {
2930 if (!strcmp(c->session_id, session_id))
2936 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2938 RTSPTransportField *th;
2941 for(i=0;i<h->nb_transports;i++) {
2942 th = &h->transports[i];
2943 if (th->lower_transport == lower_transport)
2949 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2950 RTSPMessageHeader *h)
2952 FFServerStream *stream;
2953 int stream_index, rtp_port, rtcp_port;
2958 RTSPTransportField *th;
2959 struct sockaddr_in dest_addr;
2960 RTSPActionServerSetup setup;
2962 /* find which URL is asked */
2963 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2968 /* now check each stream */
2969 for(stream = config.first_stream; stream; stream = stream->next) {
2970 if (stream->is_feed || !stream->fmt ||
2971 strcmp(stream->fmt->name, "rtp")) {
2974 /* accept aggregate filenames only if single stream */
2975 if (!strcmp(path, stream->filename)) {
2976 if (stream->nb_streams != 1) {
2977 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2984 for(stream_index = 0; stream_index < stream->nb_streams;
2986 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2987 stream->filename, stream_index);
2988 if (!strcmp(path, buf))
2992 /* no stream found */
2993 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2997 /* generate session id if needed */
2998 if (h->session_id[0] == '\0') {
2999 unsigned random0 = av_lfg_get(&random_state);
3000 unsigned random1 = av_lfg_get(&random_state);
3001 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3005 /* find RTP session, and create it if none found */
3006 rtp_c = find_rtp_session(h->session_id);
3008 /* always prefer UDP */
3009 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3011 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3013 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3018 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3019 th->lower_transport);
3021 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3025 /* open input stream */
3026 if (open_input_stream(rtp_c, "") < 0) {
3027 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3032 /* test if stream is OK (test needed because several SETUP needs
3033 to be done for a given file) */
3034 if (rtp_c->stream != stream) {
3035 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3039 /* test if stream is already set up */
3040 if (rtp_c->rtp_ctx[stream_index]) {
3041 rtsp_reply_error(c, RTSP_STATUS_STATE);
3045 /* check transport */
3046 th = find_transport(h, rtp_c->rtp_protocol);
3047 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3048 th->client_port_min <= 0)) {
3049 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3053 /* setup default options */
3054 setup.transport_option[0] = '\0';
3055 dest_addr = rtp_c->from_addr;
3056 dest_addr.sin_port = htons(th->client_port_min);
3059 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3060 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3064 /* now everything is OK, so we can send the connection parameters */
3065 rtsp_reply_header(c, RTSP_STATUS_OK);
3067 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3069 switch(rtp_c->rtp_protocol) {
3070 case RTSP_LOWER_TRANSPORT_UDP:
3071 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3072 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3073 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3074 "client_port=%d-%d;server_port=%d-%d",
3075 th->client_port_min, th->client_port_max,
3076 rtp_port, rtcp_port);
3078 case RTSP_LOWER_TRANSPORT_TCP:
3079 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3080 stream_index * 2, stream_index * 2 + 1);
3085 if (setup.transport_option[0] != '\0')
3086 avio_printf(c->pb, ";%s", setup.transport_option);
3087 avio_printf(c->pb, "\r\n");
3090 avio_printf(c->pb, "\r\n");
3094 /* find an RTP connection by using the session ID. Check consistency
3096 static HTTPContext *find_rtp_session_with_url(const char *url,
3097 const char *session_id)
3105 rtp_c = find_rtp_session(session_id);
3109 /* find which URL is asked */
3110 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3114 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3115 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3116 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3117 rtp_c->stream->filename, s);
3118 if(!strncmp(path, buf, sizeof(buf))) {
3119 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3124 if (len > 0 && path[len - 1] == '/' &&
3125 !strncmp(path, rtp_c->stream->filename, len - 1))
3130 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3134 rtp_c = find_rtp_session_with_url(url, h->session_id);
3136 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3140 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3141 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3142 rtp_c->state != HTTPSTATE_READY) {
3143 rtsp_reply_error(c, RTSP_STATUS_STATE);
3147 rtp_c->state = HTTPSTATE_SEND_DATA;
3149 /* now everything is OK, so we can send the connection parameters */
3150 rtsp_reply_header(c, RTSP_STATUS_OK);
3152 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3153 avio_printf(c->pb, "\r\n");
3156 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
3157 RTSPMessageHeader *h, int pause_only)
3161 rtp_c = find_rtp_session_with_url(url, h->session_id);
3163 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3168 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3169 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3170 rtsp_reply_error(c, RTSP_STATUS_STATE);
3173 rtp_c->state = HTTPSTATE_READY;
3174 rtp_c->first_pts = AV_NOPTS_VALUE;
3177 /* now everything is OK, so we can send the connection parameters */
3178 rtsp_reply_header(c, RTSP_STATUS_OK);
3180 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3181 avio_printf(c->pb, "\r\n");
3184 close_connection(rtp_c);
3187 /********************************************************************/
3190 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3191 FFServerStream *stream,
3192 const char *session_id,
3193 enum RTSPLowerTransport rtp_protocol)
3195 HTTPContext *c = NULL;
3196 const char *proto_str;
3198 /* XXX: should output a warning page when coming
3199 close to the connection limit */
3200 if (nb_connections >= config.nb_max_connections)
3203 /* add a new connection */
3204 c = av_mallocz(sizeof(HTTPContext));
3209 c->poll_entry = NULL;
3210 c->from_addr = *from_addr;
3211 c->buffer_size = IOBUFFER_INIT_SIZE;
3212 c->buffer = av_malloc(c->buffer_size);
3217 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3218 c->state = HTTPSTATE_READY;
3219 c->is_packetized = 1;
3220 c->rtp_protocol = rtp_protocol;
3222 /* protocol is shown in statistics */
3223 switch(c->rtp_protocol) {
3224 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3225 proto_str = "MCAST";
3227 case RTSP_LOWER_TRANSPORT_UDP:
3230 case RTSP_LOWER_TRANSPORT_TCP:
3237 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3238 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3240 current_bandwidth += stream->bandwidth;
3242 c->next = first_http_ctx;
3248 av_freep(&c->buffer);
3254 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3255 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3257 static int rtp_new_av_stream(HTTPContext *c,
3258 int stream_index, struct sockaddr_in *dest_addr,
3259 HTTPContext *rtsp_c)
3261 AVFormatContext *ctx;
3264 URLContext *h = NULL;
3266 int max_packet_size;
3268 /* now we can open the relevant output stream */
3269 ctx = avformat_alloc_context();
3272 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3274 st = av_mallocz(sizeof(AVStream));
3277 ctx->nb_streams = 1;
3278 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3281 ctx->streams[0] = st;
3283 if (!c->stream->feed ||
3284 c->stream->feed == c->stream)
3285 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3288 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3290 st->priv_data = NULL;
3292 /* build destination RTP address */
3293 ipaddr = inet_ntoa(dest_addr->sin_addr);
3295 switch(c->rtp_protocol) {
3296 case RTSP_LOWER_TRANSPORT_UDP:
3297 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3300 /* XXX: also pass as parameter to function ? */
3301 if (c->stream->is_multicast) {
3303 ttl = c->stream->multicast_ttl;
3306 snprintf(ctx->filename, sizeof(ctx->filename),
3307 "rtp://%s:%d?multicast=1&ttl=%d",
3308 ipaddr, ntohs(dest_addr->sin_port), ttl);
3310 snprintf(ctx->filename, sizeof(ctx->filename),
3311 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3314 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3316 c->rtp_handles[stream_index] = h;
3317 max_packet_size = h->max_packet_size;
3319 case RTSP_LOWER_TRANSPORT_TCP:
3322 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3328 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3329 ipaddr, ntohs(dest_addr->sin_port),
3330 c->stream->filename, stream_index, c->protocol);
3332 /* normally, no packets should be output here, but the packet size may
3334 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3335 /* XXX: close stream */
3338 if (avformat_write_header(ctx, NULL) < 0) {
3346 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3349 c->rtp_ctx[stream_index] = ctx;
3353 /********************************************************************/
3354 /* ffserver initialization */
3356 static AVStream *add_av_stream1(FFServerStream *stream,
3357 AVCodecContext *codec, int copy)
3361 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3364 fst = av_mallocz(sizeof(AVStream));
3368 fst->codec = avcodec_alloc_context3(codec->codec);
3369 avcodec_copy_context(fst->codec, codec);
3371 /* live streams must use the actual feed's codec since it may be
3372 * updated later to carry extradata needed by them.
3376 fst->priv_data = av_mallocz(sizeof(FeedData));
3377 fst->index = stream->nb_streams;
3378 avpriv_set_pts_info(fst, 33, 1, 90000);
3379 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3380 stream->streams[stream->nb_streams++] = fst;
3384 /* return the stream number in the feed */
3385 static int add_av_stream(FFServerStream *feed, AVStream *st)
3388 AVCodecContext *av, *av1;
3392 for(i=0;i<feed->nb_streams;i++) {
3393 av1 = feed->streams[i]->codec;
3394 if (av1->codec_id == av->codec_id &&
3395 av1->codec_type == av->codec_type &&
3396 av1->bit_rate == av->bit_rate) {
3398 switch(av->codec_type) {
3399 case AVMEDIA_TYPE_AUDIO:
3400 if (av1->channels == av->channels &&
3401 av1->sample_rate == av->sample_rate)
3404 case AVMEDIA_TYPE_VIDEO:
3405 if (av1->width == av->width &&
3406 av1->height == av->height &&
3407 av1->time_base.den == av->time_base.den &&
3408 av1->time_base.num == av->time_base.num &&
3409 av1->gop_size == av->gop_size)
3418 fst = add_av_stream1(feed, av, 0);
3421 if (av_stream_get_recommended_encoder_configuration(st))
3422 av_stream_set_recommended_encoder_configuration(fst,
3423 av_strdup(av_stream_get_recommended_encoder_configuration(st)));
3424 return feed->nb_streams - 1;
3427 static void remove_stream(FFServerStream *stream)
3429 FFServerStream **ps;
3430 ps = &config.first_stream;
3439 /* specific MPEG4 handling : we extract the raw parameters */
3440 static void extract_mpeg4_header(AVFormatContext *infile)
3442 int mpeg4_count, i, size;
3447 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3450 for(i=0;i<infile->nb_streams;i++) {
3451 st = infile->streams[i];
3452 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3453 st->codec->extradata_size == 0) {
3460 printf("MPEG4 without extra data: trying to find header in %s\n",
3462 while (mpeg4_count > 0) {
3463 if (av_read_frame(infile, &pkt) < 0)
3465 st = infile->streams[pkt.stream_index];
3466 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3467 st->codec->extradata_size == 0) {
3468 av_freep(&st->codec->extradata);
3469 /* fill extradata with the header */
3470 /* XXX: we make hard suppositions here ! */
3472 while (p < pkt.data + pkt.size - 4) {
3473 /* stop when vop header is found */
3474 if (p[0] == 0x00 && p[1] == 0x00 &&
3475 p[2] == 0x01 && p[3] == 0xb6) {
3476 size = p - pkt.data;
3477 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3478 st->codec->extradata_size = size;
3479 memcpy(st->codec->extradata, pkt.data, size);
3486 av_free_packet(&pkt);
3490 /* compute the needed AVStream for each file */
3491 static void build_file_streams(void)
3493 FFServerStream *stream, *stream_next;
3496 /* gather all streams */
3497 for(stream = config.first_stream; stream; stream = stream_next) {
3498 AVFormatContext *infile = NULL;
3499 stream_next = stream->next;
3500 if (stream->stream_type == STREAM_TYPE_LIVE &&
3502 /* the stream comes from a file */
3503 /* try to open the file */
3505 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3506 /* specific case : if transport stream output to RTP,
3507 we use a raw transport stream reader */
3508 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3511 if (!stream->feed_filename[0]) {
3512 http_log("Unspecified feed file for stream '%s'\n",
3517 http_log("Opening feed file '%s' for stream '%s'\n",
3518 stream->feed_filename, stream->filename);
3519 ret = avformat_open_input(&infile, stream->feed_filename,
3520 stream->ifmt, &stream->in_opts);
3522 http_log("Could not open '%s': %s\n", stream->feed_filename,
3524 /* remove stream (no need to spend more time on it) */
3526 remove_stream(stream);
3528 /* find all the AVStreams inside and reference them in
3530 if (avformat_find_stream_info(infile, NULL) < 0) {
3531 http_log("Could not find codec parameters from '%s'\n",
3532 stream->feed_filename);
3533 avformat_close_input(&infile);
3536 extract_mpeg4_header(infile);
3538 for(i=0;i<infile->nb_streams;i++)
3539 add_av_stream1(stream, infile->streams[i]->codec, 1);
3541 avformat_close_input(&infile);
3547 /* compute the needed AVStream for each feed */
3548 static void build_feed_streams(void)
3550 FFServerStream *stream, *feed;
3553 /* gather all streams */
3554 for(stream = config.first_stream; stream; stream = stream->next) {
3555 feed = stream->feed;
3557 if (stream->is_feed) {
3558 for(i=0;i<stream->nb_streams;i++)
3559 stream->feed_streams[i] = i;
3561 /* we handle a stream coming from a feed */
3562 for(i=0;i<stream->nb_streams;i++)
3563 stream->feed_streams[i] = add_av_stream(feed,
3564 stream->streams[i]);
3569 /* create feed files if needed */
3570 for(feed = config.first_feed; feed; feed = feed->next_feed) {
3573 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3574 /* See if it matches */
3575 AVFormatContext *s = NULL;
3578 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3579 /* set buffer size */
3580 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3581 /* Now see if it matches */
3582 if (s->nb_streams == feed->nb_streams) {
3584 for(i=0;i<s->nb_streams;i++) {
3586 sf = feed->streams[i];
3589 if (sf->index != ss->index ||
3591 http_log("Index & Id do not match for stream %d (%s)\n",
3592 i, feed->feed_filename);
3595 AVCodecContext *ccf, *ccs;
3599 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3601 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3602 http_log("Codecs do not match for stream %d\n", i);
3604 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3605 http_log("Codec bitrates do not match for stream %d\n", i);
3607 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3608 if (CHECK_CODEC(time_base.den) ||
3609 CHECK_CODEC(time_base.num) ||
3610 CHECK_CODEC(width) ||
3611 CHECK_CODEC(height)) {
3612 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3615 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3616 if (CHECK_CODEC(sample_rate) ||
3617 CHECK_CODEC(channels) ||
3618 CHECK_CODEC(frame_size)) {
3619 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3623 http_log("Unknown codec type\n");
3631 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3632 feed->feed_filename, s->nb_streams, feed->nb_streams);
3634 avformat_close_input(&s);
3636 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3637 feed->feed_filename);
3640 if (feed->readonly) {
3641 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3642 feed->feed_filename);
3645 unlink(feed->feed_filename);
3648 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3649 AVFormatContext *s = avformat_alloc_context();
3651 if (feed->readonly) {
3652 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3653 feed->feed_filename);
3657 /* only write the header of the ffm file */
3658 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3659 http_log("Could not open output feed file '%s'\n",
3660 feed->feed_filename);
3663 s->oformat = feed->fmt;
3664 s->nb_streams = feed->nb_streams;
3665 s->streams = feed->streams;
3666 if (avformat_write_header(s, NULL) < 0) {
3667 http_log("Container doesn't support the required parameters\n");
3670 /* XXX: need better API */
3671 av_freep(&s->priv_data);
3672 avio_closep(&s->pb);
3675 avformat_free_context(s);
3677 /* get feed size and write index */
3678 fd = open(feed->feed_filename, O_RDONLY);
3680 http_log("Could not open output feed file '%s'\n",
3681 feed->feed_filename);
3685 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3686 feed->feed_size = lseek(fd, 0, SEEK_END);
3687 /* ensure that we do not wrap before the end of file */
3688 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3689 feed->feed_max_size = feed->feed_size;
3695 /* compute the bandwidth used by each stream */
3696 static void compute_bandwidth(void)
3700 FFServerStream *stream;
3702 for(stream = config.first_stream; stream; stream = stream->next) {
3704 for(i=0;i<stream->nb_streams;i++) {
3705 AVStream *st = stream->streams[i];
3706 switch(st->codec->codec_type) {
3707 case AVMEDIA_TYPE_AUDIO:
3708 case AVMEDIA_TYPE_VIDEO:
3709 bandwidth += st->codec->bit_rate;
3715 stream->bandwidth = (bandwidth + 999) / 1000;
3719 static void handle_child_exit(int sig)
3724 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3725 FFServerStream *feed;
3727 for (feed = config.first_feed; feed; feed = feed->next) {
3728 if (feed->pid == pid) {
3729 int uptime = time(0) - feed->pid_start;
3733 "%s: Pid %d exited with status %d after %d seconds\n",
3734 feed->filename, pid, status, uptime);
3737 /* Turn off any more restarts */
3738 ffserver_free_child_args(&feed->child_argv);
3743 need_to_start_children = 1;
3746 static void opt_debug(void)
3749 snprintf(config.logfilename, sizeof(config.logfilename), "-");
3752 void show_help_default(const char *opt, const char *arg)
3754 printf("usage: ffserver [options]\n"
3755 "Hyper fast multi format Audio/Video streaming server\n");
3757 show_help_options(options, "Main options:", 0, 0, 0);
3760 static const OptionDef options[] = {
3761 #include "cmdutils_common_opts.h"
3762 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3763 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3764 { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3768 int main(int argc, char **argv)
3770 struct sigaction sigact = { { 0 } };
3773 config.filename = av_strdup("/etc/ffserver.conf");
3775 parse_loglevel(argc, argv, options);
3777 avformat_network_init();
3779 show_banner(argc, argv, options);
3781 my_program_name = argv[0];
3783 parse_options(NULL, argc, argv, options, NULL);
3785 unsetenv("http_proxy"); /* Kill the http_proxy */
3787 av_lfg_init(&random_state, av_get_random_seed());
3789 sigact.sa_handler = handle_child_exit;
3790 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3791 sigaction(SIGCHLD, &sigact, 0);
3793 if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3794 fprintf(stderr, "Error reading configuration file '%s': %s\n",
3795 config.filename, av_err2str(ret));
3798 av_freep(&config.filename);
3800 /* open log file if needed */
3801 if (config.logfilename[0] != '\0') {
3802 if (!strcmp(config.logfilename, "-"))
3805 logfile = fopen(config.logfilename, "a");
3806 av_log_set_callback(http_av_log);
3809 build_file_streams();
3811 build_feed_streams();
3813 compute_bandwidth();
3816 signal(SIGPIPE, SIG_IGN);
3818 if (http_server() < 0) {
3819 http_log("Could not start server\n");