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));
1213 while (fgets(line, sizeof(line), f)) {
1216 while (av_isspace(*p))
1218 if (*p == '\0' || *p == '#')
1220 ffserver_get_arg(cmd, sizeof(cmd), &p);
1222 if (!av_strcasecmp(cmd, "ACL"))
1223 ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl,
1231 static void free_acl_list(FFServerIPAddressACL *in_acl)
1233 FFServerIPAddressACL *pacl, *pacl2;
1243 static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c)
1245 enum FFServerIPAddressAction last_action = IP_DENY;
1246 FFServerIPAddressACL *acl;
1247 struct in_addr *src = &c->from_addr.sin_addr;
1248 unsigned long src_addr = src->s_addr;
1250 for (acl = in_acl; acl; acl = acl->next) {
1251 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1252 return (acl->action == IP_ALLOW) ? 1 : 0;
1253 last_action = acl->action;
1256 /* Nothing matched, so return not the last action */
1257 return (last_action == IP_DENY) ? 1 : 0;
1260 static int validate_acl(FFServerStream *stream, HTTPContext *c)
1263 FFServerIPAddressACL *acl;
1265 /* if stream->acl is null validate_acl_list will return 1 */
1266 ret = validate_acl_list(stream->acl, c);
1268 if (stream->dynamic_acl[0]) {
1269 acl = parse_dynamic_acl(stream, c);
1271 ret = validate_acl_list(acl, c);
1279 /* compute the real filename of a file by matching it without its
1280 extensions to all the stream's filenames */
1281 static void compute_real_filename(char *filename, int max_size)
1286 FFServerStream *stream;
1288 /* compute filename by matching without the file extensions */
1289 av_strlcpy(file1, filename, sizeof(file1));
1290 p = strrchr(file1, '.');
1293 for(stream = config.first_stream; stream; stream = stream->next) {
1294 av_strlcpy(file2, stream->filename, sizeof(file2));
1295 p = strrchr(file2, '.');
1298 if (!strcmp(file1, file2)) {
1299 av_strlcpy(filename, stream->filename, max_size);
1314 /* parse HTTP request and prepare header */
1315 static int http_parse_request(HTTPContext *c)
1319 enum RedirType redir_type;
1321 char info[1024], filename[1024];
1325 const char *mime_type;
1326 FFServerStream *stream;
1329 const char *useragent = 0;
1332 get_word(cmd, sizeof(cmd), &p);
1333 av_strlcpy(c->method, cmd, sizeof(c->method));
1335 if (!strcmp(cmd, "GET"))
1337 else if (!strcmp(cmd, "POST"))
1342 get_word(url, sizeof(url), &p);
1343 av_strlcpy(c->url, url, sizeof(c->url));
1345 get_word(protocol, sizeof(protocol), (const char **)&p);
1346 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1349 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1352 http_log("%s - - New connection: %s %s\n",
1353 inet_ntoa(c->from_addr.sin_addr), cmd, url);
1355 /* find the filename and the optional info string in the request */
1356 p1 = strchr(url, '?');
1358 av_strlcpy(info, p1, sizeof(info));
1363 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1365 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1366 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1368 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1372 p = strchr(p, '\n');
1379 redir_type = REDIR_NONE;
1380 if (av_match_ext(filename, "asx")) {
1381 redir_type = REDIR_ASX;
1382 filename[strlen(filename)-1] = 'f';
1383 } else if (av_match_ext(filename, "asf") &&
1384 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) {
1385 /* if this isn't WMP or lookalike, return the redirector file */
1386 redir_type = REDIR_ASF;
1387 } else if (av_match_ext(filename, "rpm,ram")) {
1388 redir_type = REDIR_RAM;
1389 strcpy(filename + strlen(filename)-2, "m");
1390 } else if (av_match_ext(filename, "rtsp")) {
1391 redir_type = REDIR_RTSP;
1392 compute_real_filename(filename, sizeof(filename) - 1);
1393 } else if (av_match_ext(filename, "sdp")) {
1394 redir_type = REDIR_SDP;
1395 compute_real_filename(filename, sizeof(filename) - 1);
1398 // "redirect" / request to index.html
1399 if (!strlen(filename))
1400 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1402 stream = config.first_stream;
1404 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1406 stream = stream->next;
1409 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1410 http_log("File '%s' not found\n", url);
1415 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1416 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1418 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1419 c->http_error = 301;
1421 snprintf(q, c->buffer_size,
1422 "HTTP/1.0 301 Moved\r\n"
1424 "Content-type: text/html\r\n"
1426 "<html><head><title>Moved</title></head><body>\r\n"
1427 "You should be <a href=\"%s\">redirected</a>.\r\n"
1428 "</body></html>\r\n",
1429 stream->feed_filename, stream->feed_filename);
1431 /* prepare output buffer */
1432 c->buffer_ptr = c->buffer;
1434 c->state = HTTPSTATE_SEND_HEADER;
1438 /* If this is WMP, get the rate information */
1439 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1440 if (modify_current_stream(c, ratebuf)) {
1441 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1442 if (c->switch_feed_streams[i] >= 0)
1443 c->switch_feed_streams[i] = -1;
1448 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1449 current_bandwidth += stream->bandwidth;
1451 /* If already streaming this feed, do not let start another feeder. */
1452 if (stream->feed_opened) {
1453 snprintf(msg, sizeof(msg), "This feed is already being received.");
1454 http_log("Feed '%s' already being received\n", stream->feed_filename);
1458 if (c->post == 0 && config.max_bandwidth < current_bandwidth) {
1459 c->http_error = 503;
1461 snprintf(q, c->buffer_size,
1462 "HTTP/1.0 503 Server too busy\r\n"
1463 "Content-type: text/html\r\n"
1465 "<html><head><title>Too busy</title></head><body>\r\n"
1466 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1467 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1468 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1469 "</body></html>\r\n",
1470 current_bandwidth, config.max_bandwidth);
1472 /* prepare output buffer */
1473 c->buffer_ptr = c->buffer;
1475 c->state = HTTPSTATE_SEND_HEADER;
1479 if (redir_type != REDIR_NONE) {
1480 const char *hostinfo = 0;
1482 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1483 if (av_strncasecmp(p, "Host:", 5) == 0) {
1487 p = strchr(p, '\n');
1498 while (av_isspace(*hostinfo))
1501 eoh = strchr(hostinfo, '\n');
1503 if (eoh[-1] == '\r')
1506 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1507 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1508 hostbuf[eoh - hostinfo] = 0;
1510 c->http_error = 200;
1512 switch(redir_type) {
1514 snprintf(q, c->buffer_size,
1515 "HTTP/1.0 200 ASX Follows\r\n"
1516 "Content-type: video/x-ms-asf\r\n"
1518 "<ASX Version=\"3\">\r\n"
1519 //"<!-- Autogenerated by ffserver -->\r\n"
1520 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1521 "</ASX>\r\n", hostbuf, filename, info);
1525 snprintf(q, c->buffer_size,
1526 "HTTP/1.0 200 RAM Follows\r\n"
1527 "Content-type: audio/x-pn-realaudio\r\n"
1529 "# Autogenerated by ffserver\r\n"
1530 "http://%s/%s%s\r\n", hostbuf, filename, info);
1534 snprintf(q, c->buffer_size,
1535 "HTTP/1.0 200 ASF Redirect follows\r\n"
1536 "Content-type: video/x-ms-asf\r\n"
1539 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1544 char hostname[256], *p;
1545 /* extract only hostname */
1546 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1547 p = strrchr(hostname, ':');
1550 snprintf(q, c->buffer_size,
1551 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1552 /* XXX: incorrect MIME type ? */
1553 "Content-type: application/x-rtsp\r\n"
1555 "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
1564 struct sockaddr_in my_addr;
1566 snprintf(q, c->buffer_size,
1567 "HTTP/1.0 200 OK\r\n"
1568 "Content-type: application/sdp\r\n"
1572 len = sizeof(my_addr);
1574 /* XXX: Should probably fail? */
1575 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1576 http_log("getsockname() failed\n");
1578 /* XXX: should use a dynamic buffer */
1579 sdp_data_size = prepare_sdp_description(stream,
1582 if (sdp_data_size > 0) {
1583 memcpy(q, sdp_data, sdp_data_size);
1595 /* prepare output buffer */
1596 c->buffer_ptr = c->buffer;
1598 c->state = HTTPSTATE_SEND_HEADER;
1604 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1608 stream->conns_served++;
1610 /* XXX: add there authenticate and IP match */
1613 /* if post, it means a feed is being sent */
1614 if (!stream->is_feed) {
1615 /* However it might be a status report from WMP! Let us log the
1616 * data as it might come handy one day. */
1617 const char *logline = 0;
1620 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1621 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1625 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1626 client_id = strtol(p + 18, 0, 10);
1627 p = strchr(p, '\n');
1635 char *eol = strchr(logline, '\n');
1640 if (eol[-1] == '\r')
1642 http_log("%.*s\n", (int) (eol - logline), logline);
1643 c->suppress_log = 1;
1648 http_log("\nGot request:\n%s\n", c->buffer);
1651 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1654 /* Now we have to find the client_id */
1655 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1656 if (wmpc->wmp_client_id == client_id)
1660 if (wmpc && modify_current_stream(wmpc, ratebuf))
1661 wmpc->switch_pending = 1;
1664 snprintf(msg, sizeof(msg), "POST command not handled");
1668 if (http_start_receive_data(c) < 0) {
1669 snprintf(msg, sizeof(msg), "could not open feed");
1673 c->state = HTTPSTATE_RECEIVE_DATA;
1678 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1679 http_log("\nGot request:\n%s\n", c->buffer);
1682 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1685 /* open input stream */
1686 if (open_input_stream(c, info) < 0) {
1687 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1691 /* prepare HTTP header */
1693 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1694 mime_type = c->stream->fmt->mime_type;
1696 mime_type = "application/x-octet-stream";
1697 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1699 /* for asf, we need extra headers */
1700 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1701 /* Need to allocate a client id */
1703 c->wmp_client_id = av_lfg_get(&random_state);
1705 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);
1707 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1708 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1709 q = c->buffer + strlen(c->buffer);
1711 /* prepare output buffer */
1713 c->buffer_ptr = c->buffer;
1715 c->state = HTTPSTATE_SEND_HEADER;
1718 c->http_error = 404;
1721 snprintf(q, c->buffer_size,
1722 "HTTP/1.0 404 Not Found\r\n"
1723 "Content-type: text/html\r\n"
1726 "<head><title>404 Not Found</title></head>\n"
1730 /* prepare output buffer */
1731 c->buffer_ptr = c->buffer;
1733 c->state = HTTPSTATE_SEND_HEADER;
1737 c->http_error = 200; /* horrible : we use this value to avoid
1738 going to the send data state */
1739 c->state = HTTPSTATE_SEND_HEADER;
1743 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1745 static const char suffix[] = " kMGTP";
1748 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1750 avio_printf(pb, "%"PRId64"%c", count, *s);
1753 static void compute_status(HTTPContext *c)
1756 FFServerStream *stream;
1762 if (avio_open_dyn_buf(&pb) < 0) {
1763 /* XXX: return an error ? */
1764 c->buffer_ptr = c->buffer;
1765 c->buffer_end = c->buffer;
1769 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1770 avio_printf(pb, "Content-type: text/html\r\n");
1771 avio_printf(pb, "Pragma: no-cache\r\n");
1772 avio_printf(pb, "\r\n");
1774 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1775 if (c->stream->feed_filename[0])
1776 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n",
1777 c->stream->feed_filename);
1778 avio_printf(pb, "</head>\n<body>");
1779 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1781 avio_printf(pb, "<h2>Available Streams</h2>\n");
1782 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1783 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");
1784 stream = config.first_stream;
1786 char sfilename[1024];
1789 if (stream->feed == stream) {
1790 stream = stream->next;
1794 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1795 eosf = sfilename + strlen(sfilename);
1796 if (eosf - sfilename >= 4) {
1797 if (strcmp(eosf - 4, ".asf") == 0)
1798 strcpy(eosf - 4, ".asx");
1799 else if (strcmp(eosf - 3, ".rm") == 0)
1800 strcpy(eosf - 3, ".ram");
1801 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1802 /* generate a sample RTSP director if
1803 unicast. Generate an SDP redirector if
1805 eosf = strrchr(sfilename, '.');
1807 eosf = sfilename + strlen(sfilename);
1808 if (stream->is_multicast)
1809 strcpy(eosf, ".sdp");
1811 strcpy(eosf, ".rtsp");
1815 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1816 sfilename, stream->filename);
1817 avio_printf(pb, "<td align=right> %d <td align=right> ",
1818 stream->conns_served);
1819 fmt_bytecount(pb, stream->bytes_served);
1821 switch(stream->stream_type) {
1822 case STREAM_TYPE_LIVE: {
1823 int audio_bit_rate = 0;
1824 int video_bit_rate = 0;
1825 const char *audio_codec_name = "";
1826 const char *video_codec_name = "";
1827 const char *audio_codec_name_extra = "";
1828 const char *video_codec_name_extra = "";
1830 for(i=0;i<stream->nb_streams;i++) {
1831 AVStream *st = stream->streams[i];
1832 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1834 switch(st->codec->codec_type) {
1835 case AVMEDIA_TYPE_AUDIO:
1836 audio_bit_rate += st->codec->bit_rate;
1838 if (*audio_codec_name)
1839 audio_codec_name_extra = "...";
1840 audio_codec_name = codec->name;
1843 case AVMEDIA_TYPE_VIDEO:
1844 video_bit_rate += st->codec->bit_rate;
1846 if (*video_codec_name)
1847 video_codec_name_extra = "...";
1848 video_codec_name = codec->name;
1851 case AVMEDIA_TYPE_DATA:
1852 video_bit_rate += st->codec->bit_rate;
1859 avio_printf(pb, "<td align=center> %s <td align=right> %d "
1860 "<td align=right> %d <td> %s %s <td align=right> "
1862 stream->fmt->name, stream->bandwidth,
1863 video_bit_rate / 1000, video_codec_name,
1864 video_codec_name_extra, audio_bit_rate / 1000,
1865 audio_codec_name, audio_codec_name_extra);
1868 avio_printf(pb, "<td>%s", stream->feed->filename);
1870 avio_printf(pb, "<td>%s", stream->feed_filename);
1871 avio_printf(pb, "\n");
1875 avio_printf(pb, "<td align=center> - <td align=right> - "
1876 "<td align=right> - <td><td align=right> - <td>\n");
1879 stream = stream->next;
1881 avio_printf(pb, "</table>\n");
1883 stream = config.first_stream;
1886 if (stream->feed != stream) {
1887 stream = stream->next;
1891 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1893 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1900 /* This is somewhat linux specific I guess */
1901 snprintf(ps_cmd, sizeof(ps_cmd),
1902 "ps -o \"%%cpu,cputime\" --no-headers %d",
1905 pid_stat = popen(ps_cmd, "r");
1910 if (fscanf(pid_stat, "%9s %63s", cpuperc, cpuused) == 2) {
1911 avio_printf(pb, "Currently using %s%% of the cpu. "
1912 "Total time used %s.\n",
1920 avio_printf(pb, "<p>");
1923 avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>"
1924 "type<th>kbits/s<th align=left>codec<th align=left>"
1927 for (i = 0; i < stream->nb_streams; i++) {
1928 AVStream *st = stream->streams[i];
1929 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1930 const char *type = "unknown";
1931 char parameters[64];
1935 switch(st->codec->codec_type) {
1936 case AVMEDIA_TYPE_AUDIO:
1938 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz",
1939 st->codec->channels, st->codec->sample_rate);
1941 case AVMEDIA_TYPE_VIDEO:
1943 snprintf(parameters, sizeof(parameters),
1944 "%dx%d, q=%d-%d, fps=%d", st->codec->width,
1945 st->codec->height, st->codec->qmin, st->codec->qmax,
1946 st->codec->time_base.den / st->codec->time_base.num);
1952 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d"
1954 i, type, st->codec->bit_rate/1000,
1955 codec ? codec->name : "", parameters);
1958 avio_printf(pb, "</table>\n");
1959 stream = stream->next;
1962 /* connection status */
1963 avio_printf(pb, "<h2>Connection Status</h2>\n");
1965 avio_printf(pb, "Number of connections: %d / %d<br>\n",
1966 nb_connections, config.nb_max_connections);
1968 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1969 current_bandwidth, config.max_bandwidth);
1971 avio_printf(pb, "<table>\n");
1972 avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target "
1973 "bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1974 c1 = first_http_ctx;
1982 for (j = 0; j < c1->stream->nb_streams; j++) {
1983 if (!c1->stream->feed)
1984 bitrate += c1->stream->streams[j]->codec->bit_rate;
1985 else if (c1->feed_streams[j] >= 0)
1986 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1991 p = inet_ntoa(c1->from_addr.sin_addr);
1992 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s"
1994 i, c1->stream ? c1->stream->filename : "",
1995 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", p,
1996 c1->protocol, http_state[c1->state]);
1997 fmt_bytecount(pb, bitrate);
1998 avio_printf(pb, "<td align=right>");
1999 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2000 avio_printf(pb, "<td align=right>");
2001 fmt_bytecount(pb, c1->data_count);
2002 avio_printf(pb, "\n");
2005 avio_printf(pb, "</table>\n");
2010 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2011 avio_printf(pb, "</body>\n</html>\n");
2013 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2014 c->buffer_ptr = c->pb_buffer;
2015 c->buffer_end = c->pb_buffer + len;
2018 static int open_input_stream(HTTPContext *c, const char *info)
2021 char input_filename[1024];
2022 AVFormatContext *s = NULL;
2023 int buf_size, i, ret;
2026 /* find file name */
2027 if (c->stream->feed) {
2028 strcpy(input_filename, c->stream->feed->feed_filename);
2029 buf_size = FFM_PACKET_SIZE;
2030 /* compute position (absolute time) */
2031 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2032 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2033 http_log("Invalid date specification '%s' for stream\n", buf);
2036 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2037 int prebuffer = strtol(buf, 0, 10);
2038 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2040 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2042 strcpy(input_filename, c->stream->feed_filename);
2044 /* compute position (relative time) */
2045 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2046 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2047 http_log("Invalid date specification '%s' for stream\n", buf);
2053 if (!input_filename[0]) {
2054 http_log("No filename was specified for stream\n");
2055 return AVERROR(EINVAL);
2059 ret = avformat_open_input(&s, input_filename, c->stream->ifmt,
2060 &c->stream->in_opts);
2062 http_log("Could not open input '%s': %s\n",
2063 input_filename, av_err2str(ret));
2067 /* set buffer size */
2069 ret = ffio_set_buf_size(s->pb, buf_size);
2071 http_log("Failed to set buffer size\n");
2076 s->flags |= AVFMT_FLAG_GENPTS;
2078 if (strcmp(s->iformat->name, "ffm") &&
2079 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2080 http_log("Could not find stream info for input '%s'\n", input_filename);
2081 avformat_close_input(&s);
2085 /* choose stream as clock source (we favor the video stream if
2086 * present) for packet sending */
2087 c->pts_stream_index = 0;
2088 for(i=0;i<c->stream->nb_streams;i++) {
2089 if (c->pts_stream_index == 0 &&
2090 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2091 c->pts_stream_index = i;
2095 if (c->fmt_in->iformat->read_seek)
2096 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2097 /* set the start time (needed for maxtime and RTP packet timing) */
2098 c->start_time = cur_time;
2099 c->first_pts = AV_NOPTS_VALUE;
2103 /* return the server clock (in us) */
2104 static int64_t get_server_clock(HTTPContext *c)
2106 /* compute current pts value from system time */
2107 return (cur_time - c->start_time) * 1000;
2110 /* return the estimated time at which the current packet must be sent
2112 static int64_t get_packet_send_clock(HTTPContext *c)
2114 int bytes_left, bytes_sent, frame_bytes;
2116 frame_bytes = c->cur_frame_bytes;
2117 if (frame_bytes <= 0)
2120 bytes_left = c->buffer_end - c->buffer_ptr;
2121 bytes_sent = frame_bytes - bytes_left;
2122 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2127 static int http_prepare_data(HTTPContext *c)
2130 AVFormatContext *ctx;
2132 av_freep(&c->pb_buffer);
2134 case HTTPSTATE_SEND_DATA_HEADER:
2135 ctx = avformat_alloc_context();
2137 return AVERROR(ENOMEM);
2140 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2141 c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams,
2142 sizeof(AVStream *));
2143 if (!c->fmt_ctx.streams)
2144 return AVERROR(ENOMEM);
2146 for(i=0;i<c->stream->nb_streams;i++) {
2148 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2150 /* if file or feed, then just take streams from FFServerStream struct */
2151 if (!c->stream->feed ||
2152 c->stream->feed == c->stream)
2153 src = c->stream->streams[i];
2155 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2157 *(c->fmt_ctx.streams[i]) = *src;
2158 c->fmt_ctx.streams[i]->priv_data = 0;
2159 /* XXX: should be done in AVStream, not in codec */
2160 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2162 /* set output format parameters */
2163 c->fmt_ctx.oformat = c->stream->fmt;
2164 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2166 c->got_key_frame = 0;
2168 /* prepare header and save header data in a stream */
2169 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2170 /* XXX: potential leak */
2173 c->fmt_ctx.pb->seekable = 0;
2176 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2177 * Default value from FFmpeg
2178 * Try to set it using configuration option
2180 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2182 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2183 http_log("Error writing output header for stream '%s': %s\n",
2184 c->stream->filename, av_err2str(ret));
2187 av_dict_free(&c->fmt_ctx.metadata);
2189 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2190 c->buffer_ptr = c->pb_buffer;
2191 c->buffer_end = c->pb_buffer + len;
2193 c->state = HTTPSTATE_SEND_DATA;
2194 c->last_packet_sent = 0;
2196 case HTTPSTATE_SEND_DATA:
2197 /* find a new packet */
2198 /* read a packet from the input stream */
2199 if (c->stream->feed)
2200 ffm_set_write_index(c->fmt_in,
2201 c->stream->feed->feed_write_index,
2202 c->stream->feed->feed_size);
2204 if (c->stream->max_time &&
2205 c->stream->max_time + c->start_time - cur_time < 0)
2206 /* We have timed out */
2207 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2211 ret = av_read_frame(c->fmt_in, &pkt);
2213 if (c->stream->feed) {
2214 /* if coming from feed, it means we reached the end of the
2215 ffm file, so must wait for more data */
2216 c->state = HTTPSTATE_WAIT_FEED;
2217 return 1; /* state changed */
2218 } else if (ret == AVERROR(EAGAIN)) {
2219 /* input not ready, come back later */
2222 if (c->stream->loop) {
2223 avformat_close_input(&c->fmt_in);
2224 if (open_input_stream(c, "") < 0)
2229 /* must send trailer now because EOF or error */
2230 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2234 int source_index = pkt.stream_index;
2235 /* update first pts if needed */
2236 if (c->first_pts == AV_NOPTS_VALUE) {
2237 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2238 c->start_time = cur_time;
2240 /* send it to the appropriate stream */
2241 if (c->stream->feed) {
2242 /* if coming from a feed, select the right stream */
2243 if (c->switch_pending) {
2244 c->switch_pending = 0;
2245 for(i=0;i<c->stream->nb_streams;i++) {
2246 if (c->switch_feed_streams[i] == pkt.stream_index)
2247 if (pkt.flags & AV_PKT_FLAG_KEY)
2248 c->switch_feed_streams[i] = -1;
2249 if (c->switch_feed_streams[i] >= 0)
2250 c->switch_pending = 1;
2253 for(i=0;i<c->stream->nb_streams;i++) {
2254 if (c->stream->feed_streams[i] == pkt.stream_index) {
2255 AVStream *st = c->fmt_in->streams[source_index];
2256 pkt.stream_index = i;
2257 if (pkt.flags & AV_PKT_FLAG_KEY &&
2258 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2259 c->stream->nb_streams == 1))
2260 c->got_key_frame = 1;
2261 if (!c->stream->send_on_key || c->got_key_frame)
2266 AVCodecContext *codec;
2267 AVStream *ist, *ost;
2269 ist = c->fmt_in->streams[source_index];
2270 /* specific handling for RTP: we use several
2271 * output streams (one for each RTP connection).
2272 * XXX: need more abstract handling */
2273 if (c->is_packetized) {
2274 /* compute send time and duration */
2275 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2276 c->cur_pts -= c->first_pts;
2277 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2278 /* find RTP context */
2279 c->packet_stream_index = pkt.stream_index;
2280 ctx = c->rtp_ctx[c->packet_stream_index];
2282 av_free_packet(&pkt);
2285 codec = ctx->streams[0]->codec;
2286 /* only one stream per RTP connection */
2287 pkt.stream_index = 0;
2291 codec = ctx->streams[pkt.stream_index]->codec;
2294 if (c->is_packetized) {
2295 int max_packet_size;
2296 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2297 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2299 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2300 ret = ffio_open_dyn_packet_buf(&ctx->pb,
2303 ret = avio_open_dyn_buf(&ctx->pb);
2306 /* XXX: potential leak */
2309 ost = ctx->streams[pkt.stream_index];
2311 ctx->pb->seekable = 0;
2312 if (pkt.dts != AV_NOPTS_VALUE)
2313 pkt.dts = av_rescale_q(pkt.dts, ist->time_base,
2315 if (pkt.pts != AV_NOPTS_VALUE)
2316 pkt.pts = av_rescale_q(pkt.pts, ist->time_base,
2318 pkt.duration = av_rescale_q(pkt.duration, ist->time_base,
2320 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2321 http_log("Error writing frame to output for stream '%s': %s\n",
2322 c->stream->filename, av_err2str(ret));
2323 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2326 av_freep(&c->pb_buffer);
2327 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2328 c->cur_frame_bytes = len;
2329 c->buffer_ptr = c->pb_buffer;
2330 c->buffer_end = c->pb_buffer + len;
2332 codec->frame_number++;
2334 av_free_packet(&pkt);
2338 av_free_packet(&pkt);
2343 case HTTPSTATE_SEND_DATA_TRAILER:
2344 /* last packet test ? */
2345 if (c->last_packet_sent || c->is_packetized)
2348 /* prepare header */
2349 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2350 /* XXX: potential leak */
2353 c->fmt_ctx.pb->seekable = 0;
2354 av_write_trailer(ctx);
2355 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2356 c->buffer_ptr = c->pb_buffer;
2357 c->buffer_end = c->pb_buffer + len;
2359 c->last_packet_sent = 1;
2365 /* should convert the format at the same time */
2366 /* send data starting at c->buffer_ptr to the output connection
2367 * (either UDP or TCP) */
2368 static int http_send_data(HTTPContext *c)
2373 if (c->buffer_ptr >= c->buffer_end) {
2374 ret = http_prepare_data(c);
2378 /* state change requested */
2381 if (c->is_packetized) {
2382 /* RTP data output */
2383 len = c->buffer_end - c->buffer_ptr;
2385 /* fail safe - should never happen */
2387 c->buffer_ptr = c->buffer_end;
2390 len = (c->buffer_ptr[0] << 24) |
2391 (c->buffer_ptr[1] << 16) |
2392 (c->buffer_ptr[2] << 8) |
2394 if (len > (c->buffer_end - c->buffer_ptr))
2396 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2397 /* nothing to send yet: we can wait */
2401 c->data_count += len;
2402 update_datarate(&c->datarate, c->data_count);
2404 c->stream->bytes_served += len;
2406 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2407 /* RTP packets are sent inside the RTSP TCP connection */
2409 int interleaved_index, size;
2411 HTTPContext *rtsp_c;
2414 /* if no RTSP connection left, error */
2417 /* if already sending something, then wait. */
2418 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2420 if (avio_open_dyn_buf(&pb) < 0)
2422 interleaved_index = c->packet_stream_index * 2;
2423 /* RTCP packets are sent at odd indexes */
2424 if (c->buffer_ptr[1] == 200)
2425 interleaved_index++;
2426 /* write RTSP TCP header */
2428 header[1] = interleaved_index;
2429 header[2] = len >> 8;
2431 avio_write(pb, header, 4);
2432 /* write RTP packet data */
2434 avio_write(pb, c->buffer_ptr, len);
2435 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2436 /* prepare asynchronous TCP sending */
2437 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2438 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2439 c->buffer_ptr += len;
2441 /* send everything we can NOW */
2442 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2443 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2445 rtsp_c->packet_buffer_ptr += len;
2446 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2447 /* if we could not send all the data, we will
2448 send it later, so a new state is needed to
2449 "lock" the RTSP TCP connection */
2450 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2453 /* all data has been sent */
2454 av_freep(&c->packet_buffer);
2456 /* send RTP packet directly in UDP */
2458 ffurl_write(c->rtp_handles[c->packet_stream_index],
2459 c->buffer_ptr, len);
2460 c->buffer_ptr += len;
2461 /* here we continue as we can send several packets
2465 /* TCP data output */
2466 len = send(c->fd, c->buffer_ptr,
2467 c->buffer_end - c->buffer_ptr, 0);
2469 if (ff_neterrno() != AVERROR(EAGAIN) &&
2470 ff_neterrno() != AVERROR(EINTR))
2471 /* error : close connection */
2476 c->buffer_ptr += len;
2478 c->data_count += len;
2479 update_datarate(&c->datarate, c->data_count);
2481 c->stream->bytes_served += len;
2489 static int http_start_receive_data(HTTPContext *c)
2494 if (c->stream->feed_opened) {
2495 http_log("Stream feed '%s' was not opened\n",
2496 c->stream->feed_filename);
2497 return AVERROR(EINVAL);
2500 /* Don't permit writing to this one */
2501 if (c->stream->readonly) {
2502 http_log("Cannot write to read-only file '%s'\n",
2503 c->stream->feed_filename);
2504 return AVERROR(EINVAL);
2508 fd = open(c->stream->feed_filename, O_RDWR);
2510 ret = AVERROR(errno);
2511 http_log("Could not open feed file '%s': %s\n",
2512 c->stream->feed_filename, strerror(errno));
2517 if (c->stream->truncate) {
2518 /* truncate feed file */
2519 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2520 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2521 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2522 ret = AVERROR(errno);
2523 http_log("Error truncating feed file '%s': %s\n",
2524 c->stream->feed_filename, strerror(errno));
2528 ret = ffm_read_write_index(fd);
2530 http_log("Error reading write index from feed file '%s': %s\n",
2531 c->stream->feed_filename, strerror(errno));
2534 c->stream->feed_write_index = ret;
2538 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd),
2540 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2541 lseek(fd, 0, SEEK_SET);
2543 /* init buffer input */
2544 c->buffer_ptr = c->buffer;
2545 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2546 c->stream->feed_opened = 1;
2547 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2551 static int http_receive_data(HTTPContext *c)
2554 int len, loop_run = 0;
2556 while (c->chunked_encoding && !c->chunk_size &&
2557 c->buffer_end > c->buffer_ptr) {
2558 /* read chunk header, if present */
2559 len = recv(c->fd, c->buffer_ptr, 1, 0);
2562 if (ff_neterrno() != AVERROR(EAGAIN) &&
2563 ff_neterrno() != AVERROR(EINTR))
2564 /* error : close connection */
2567 } else if (len == 0) {
2568 /* end of connection : close it */
2570 } else if (c->buffer_ptr - c->buffer >= 2 &&
2571 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2572 c->chunk_size = strtol(c->buffer, 0, 16);
2573 if (c->chunk_size == 0) // end of stream
2575 c->buffer_ptr = c->buffer;
2577 } else if (++loop_run > 10) {
2578 /* no chunk header, abort */
2585 if (c->buffer_end > c->buffer_ptr) {
2586 len = recv(c->fd, c->buffer_ptr,
2587 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2589 if (ff_neterrno() != AVERROR(EAGAIN) &&
2590 ff_neterrno() != AVERROR(EINTR))
2591 /* error : close connection */
2593 } else if (len == 0)
2594 /* end of connection : close it */
2597 c->chunk_size -= len;
2598 c->buffer_ptr += len;
2599 c->data_count += len;
2600 update_datarate(&c->datarate, c->data_count);
2604 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2605 if (c->buffer[0] != 'f' ||
2606 c->buffer[1] != 'm') {
2607 http_log("Feed stream has become desynchronized -- disconnecting\n");
2612 if (c->buffer_ptr >= c->buffer_end) {
2613 FFServerStream *feed = c->stream;
2614 /* a packet has been received : write it in the store, except
2616 if (c->data_count > FFM_PACKET_SIZE) {
2617 /* XXX: use llseek or url_seek
2618 * XXX: Should probably fail? */
2619 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2620 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2622 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2623 http_log("Error writing to feed file: %s\n", strerror(errno));
2627 feed->feed_write_index += FFM_PACKET_SIZE;
2628 /* update file size */
2629 if (feed->feed_write_index > c->stream->feed_size)
2630 feed->feed_size = feed->feed_write_index;
2632 /* handle wrap around if max file size reached */
2633 if (c->stream->feed_max_size &&
2634 feed->feed_write_index >= c->stream->feed_max_size)
2635 feed->feed_write_index = FFM_PACKET_SIZE;
2638 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2639 http_log("Error writing index to feed file: %s\n",
2644 /* wake up any waiting connections */
2645 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2646 if (c1->state == HTTPSTATE_WAIT_FEED &&
2647 c1->stream->feed == c->stream->feed)
2648 c1->state = HTTPSTATE_SEND_DATA;
2651 /* We have a header in our hands that contains useful data */
2652 AVFormatContext *s = avformat_alloc_context();
2654 AVInputFormat *fmt_in;
2660 /* use feed output format name to find corresponding input format */
2661 fmt_in = av_find_input_format(feed->fmt->name);
2665 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2666 0, NULL, NULL, NULL, NULL);
2673 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2678 /* Now we have the actual streams */
2679 if (s->nb_streams != feed->nb_streams) {
2680 avformat_close_input(&s);
2682 http_log("Feed '%s' stream number does not match registered feed\n",
2683 c->stream->feed_filename);
2687 for (i = 0; i < s->nb_streams; i++) {
2688 AVStream *fst = feed->streams[i];
2689 AVStream *st = s->streams[i];
2690 avcodec_copy_context(fst->codec, st->codec);
2693 avformat_close_input(&s);
2696 c->buffer_ptr = c->buffer;
2701 c->stream->feed_opened = 0;
2703 /* wake up any waiting connections to stop waiting for feed */
2704 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2705 if (c1->state == HTTPSTATE_WAIT_FEED &&
2706 c1->stream->feed == c->stream->feed)
2707 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2712 /********************************************************************/
2715 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2722 str = RTSP_STATUS_CODE2STRING(error_number);
2724 str = "Unknown Error";
2726 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2727 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2729 /* output GMT time */
2732 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2733 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2736 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2738 rtsp_reply_header(c, error_number);
2739 avio_printf(c->pb, "\r\n");
2742 static int rtsp_parse_request(HTTPContext *c)
2744 const char *p, *p1, *p2;
2750 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2752 c->buffer_ptr[0] = '\0';
2755 get_word(cmd, sizeof(cmd), &p);
2756 get_word(url, sizeof(url), &p);
2757 get_word(protocol, sizeof(protocol), &p);
2759 av_strlcpy(c->method, cmd, sizeof(c->method));
2760 av_strlcpy(c->url, url, sizeof(c->url));
2761 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2763 if (avio_open_dyn_buf(&c->pb) < 0) {
2764 /* XXX: cannot do more */
2765 c->pb = NULL; /* safety */
2769 /* check version name */
2770 if (strcmp(protocol, "RTSP/1.0")) {
2771 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2775 /* parse each header line */
2776 /* skip to next line */
2777 while (*p != '\n' && *p != '\0')
2781 while (*p != '\0') {
2782 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2786 if (p2 > p && p2[-1] == '\r')
2788 /* skip empty line */
2792 if (len > sizeof(line) - 1)
2793 len = sizeof(line) - 1;
2794 memcpy(line, p, len);
2796 ff_rtsp_parse_line(header, line, NULL, NULL);
2800 /* handle sequence number */
2801 c->seq = header->seq;
2803 if (!strcmp(cmd, "DESCRIBE"))
2804 rtsp_cmd_describe(c, url);
2805 else if (!strcmp(cmd, "OPTIONS"))
2806 rtsp_cmd_options(c, url);
2807 else if (!strcmp(cmd, "SETUP"))
2808 rtsp_cmd_setup(c, url, header);
2809 else if (!strcmp(cmd, "PLAY"))
2810 rtsp_cmd_play(c, url, header);
2811 else if (!strcmp(cmd, "PAUSE"))
2812 rtsp_cmd_interrupt(c, url, header, 1);
2813 else if (!strcmp(cmd, "TEARDOWN"))
2814 rtsp_cmd_interrupt(c, url, header, 0);
2816 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2819 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2820 c->pb = NULL; /* safety */
2822 /* XXX: cannot do more */
2825 c->buffer_ptr = c->pb_buffer;
2826 c->buffer_end = c->pb_buffer + len;
2827 c->state = RTSPSTATE_SEND_REPLY;
2831 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2832 struct in_addr my_ip)
2834 AVFormatContext *avc;
2835 AVStream *avs = NULL;
2836 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2837 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2842 avc = avformat_alloc_context();
2843 if (!avc || !rtp_format) {
2846 avc->oformat = rtp_format;
2847 av_dict_set(&avc->metadata, "title",
2848 entry ? entry->value : "No Title", 0);
2849 avc->nb_streams = stream->nb_streams;
2850 if (stream->is_multicast) {
2851 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2852 inet_ntoa(stream->multicast_ip),
2853 stream->multicast_port, stream->multicast_ttl);
2855 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2858 avc->streams = av_malloc_array(avc->nb_streams, sizeof(*avc->streams));
2862 avs = av_malloc_array(avc->nb_streams, sizeof(*avs));
2866 for(i = 0; i < stream->nb_streams; i++) {
2867 avc->streams[i] = &avs[i];
2868 avc->streams[i]->codec = stream->streams[i]->codec;
2870 *pbuffer = av_mallocz(2048);
2873 av_sdp_create(&avc, 1, *pbuffer, 2048);
2876 av_freep(&avc->streams);
2877 av_dict_free(&avc->metadata);
2881 return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2884 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2886 // rtsp_reply_header(c, RTSP_STATUS_OK);
2887 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2888 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2889 avio_printf(c->pb, "Public: %s\r\n",
2890 "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2891 avio_printf(c->pb, "\r\n");
2894 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2896 FFServerStream *stream;
2902 struct sockaddr_in my_addr;
2904 /* find which URL is asked */
2905 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2910 for(stream = config.first_stream; stream; stream = stream->next) {
2911 if (!stream->is_feed &&
2912 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2913 !strcmp(path, stream->filename)) {
2917 /* no stream found */
2918 rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
2922 /* prepare the media description in SDP format */
2924 /* get the host IP */
2925 len = sizeof(my_addr);
2926 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2927 content_length = prepare_sdp_description(stream, &content,
2929 if (content_length < 0) {
2930 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2933 rtsp_reply_header(c, RTSP_STATUS_OK);
2934 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2935 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2936 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2937 avio_printf(c->pb, "\r\n");
2938 avio_write(c->pb, content, content_length);
2942 static HTTPContext *find_rtp_session(const char *session_id)
2946 if (session_id[0] == '\0')
2949 for(c = first_http_ctx; c; c = c->next) {
2950 if (!strcmp(c->session_id, session_id))
2956 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2958 RTSPTransportField *th;
2961 for(i=0;i<h->nb_transports;i++) {
2962 th = &h->transports[i];
2963 if (th->lower_transport == lower_transport)
2969 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2970 RTSPMessageHeader *h)
2972 FFServerStream *stream;
2973 int stream_index, rtp_port, rtcp_port;
2978 RTSPTransportField *th;
2979 struct sockaddr_in dest_addr;
2980 RTSPActionServerSetup setup;
2982 /* find which URL is asked */
2983 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2988 /* now check each stream */
2989 for(stream = config.first_stream; stream; stream = stream->next) {
2990 if (stream->is_feed || !stream->fmt ||
2991 strcmp(stream->fmt->name, "rtp")) {
2994 /* accept aggregate filenames only if single stream */
2995 if (!strcmp(path, stream->filename)) {
2996 if (stream->nb_streams != 1) {
2997 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3004 for(stream_index = 0; stream_index < stream->nb_streams;
3006 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3007 stream->filename, stream_index);
3008 if (!strcmp(path, buf))
3012 /* no stream found */
3013 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3017 /* generate session id if needed */
3018 if (h->session_id[0] == '\0') {
3019 unsigned random0 = av_lfg_get(&random_state);
3020 unsigned random1 = av_lfg_get(&random_state);
3021 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3025 /* find RTP session, and create it if none found */
3026 rtp_c = find_rtp_session(h->session_id);
3028 /* always prefer UDP */
3029 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3031 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3033 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3038 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3039 th->lower_transport);
3041 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3045 /* open input stream */
3046 if (open_input_stream(rtp_c, "") < 0) {
3047 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3052 /* test if stream is OK (test needed because several SETUP needs
3053 to be done for a given file) */
3054 if (rtp_c->stream != stream) {
3055 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3059 /* test if stream is already set up */
3060 if (rtp_c->rtp_ctx[stream_index]) {
3061 rtsp_reply_error(c, RTSP_STATUS_STATE);
3065 /* check transport */
3066 th = find_transport(h, rtp_c->rtp_protocol);
3067 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3068 th->client_port_min <= 0)) {
3069 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3073 /* setup default options */
3074 setup.transport_option[0] = '\0';
3075 dest_addr = rtp_c->from_addr;
3076 dest_addr.sin_port = htons(th->client_port_min);
3079 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3080 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3084 /* now everything is OK, so we can send the connection parameters */
3085 rtsp_reply_header(c, RTSP_STATUS_OK);
3087 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3089 switch(rtp_c->rtp_protocol) {
3090 case RTSP_LOWER_TRANSPORT_UDP:
3091 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3092 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3093 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3094 "client_port=%d-%d;server_port=%d-%d",
3095 th->client_port_min, th->client_port_max,
3096 rtp_port, rtcp_port);
3098 case RTSP_LOWER_TRANSPORT_TCP:
3099 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3100 stream_index * 2, stream_index * 2 + 1);
3105 if (setup.transport_option[0] != '\0')
3106 avio_printf(c->pb, ";%s", setup.transport_option);
3107 avio_printf(c->pb, "\r\n");
3110 avio_printf(c->pb, "\r\n");
3114 /* find an RTP connection by using the session ID. Check consistency
3116 static HTTPContext *find_rtp_session_with_url(const char *url,
3117 const char *session_id)
3125 rtp_c = find_rtp_session(session_id);
3129 /* find which URL is asked */
3130 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3134 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3135 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3136 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3137 rtp_c->stream->filename, s);
3138 if(!strncmp(path, buf, sizeof(buf))) {
3139 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3144 if (len > 0 && path[len - 1] == '/' &&
3145 !strncmp(path, rtp_c->stream->filename, len - 1))
3150 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3154 rtp_c = find_rtp_session_with_url(url, h->session_id);
3156 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3160 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3161 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3162 rtp_c->state != HTTPSTATE_READY) {
3163 rtsp_reply_error(c, RTSP_STATUS_STATE);
3167 rtp_c->state = HTTPSTATE_SEND_DATA;
3169 /* now everything is OK, so we can send the connection parameters */
3170 rtsp_reply_header(c, RTSP_STATUS_OK);
3172 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3173 avio_printf(c->pb, "\r\n");
3176 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
3177 RTSPMessageHeader *h, int pause_only)
3181 rtp_c = find_rtp_session_with_url(url, h->session_id);
3183 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3188 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3189 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3190 rtsp_reply_error(c, RTSP_STATUS_STATE);
3193 rtp_c->state = HTTPSTATE_READY;
3194 rtp_c->first_pts = AV_NOPTS_VALUE;
3197 /* now everything is OK, so we can send the connection parameters */
3198 rtsp_reply_header(c, RTSP_STATUS_OK);
3200 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3201 avio_printf(c->pb, "\r\n");
3204 close_connection(rtp_c);
3207 /********************************************************************/
3210 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3211 FFServerStream *stream,
3212 const char *session_id,
3213 enum RTSPLowerTransport rtp_protocol)
3215 HTTPContext *c = NULL;
3216 const char *proto_str;
3218 /* XXX: should output a warning page when coming
3219 close to the connection limit */
3220 if (nb_connections >= config.nb_max_connections)
3223 /* add a new connection */
3224 c = av_mallocz(sizeof(HTTPContext));
3229 c->poll_entry = NULL;
3230 c->from_addr = *from_addr;
3231 c->buffer_size = IOBUFFER_INIT_SIZE;
3232 c->buffer = av_malloc(c->buffer_size);
3237 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3238 c->state = HTTPSTATE_READY;
3239 c->is_packetized = 1;
3240 c->rtp_protocol = rtp_protocol;
3242 /* protocol is shown in statistics */
3243 switch(c->rtp_protocol) {
3244 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3245 proto_str = "MCAST";
3247 case RTSP_LOWER_TRANSPORT_UDP:
3250 case RTSP_LOWER_TRANSPORT_TCP:
3257 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3258 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3260 current_bandwidth += stream->bandwidth;
3262 c->next = first_http_ctx;
3268 av_freep(&c->buffer);
3274 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3275 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3277 static int rtp_new_av_stream(HTTPContext *c,
3278 int stream_index, struct sockaddr_in *dest_addr,
3279 HTTPContext *rtsp_c)
3281 AVFormatContext *ctx;
3284 URLContext *h = NULL;
3286 int max_packet_size;
3288 /* now we can open the relevant output stream */
3289 ctx = avformat_alloc_context();
3292 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3294 st = av_mallocz(sizeof(AVStream));
3297 ctx->nb_streams = 1;
3298 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3301 ctx->streams[0] = st;
3303 if (!c->stream->feed ||
3304 c->stream->feed == c->stream)
3305 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3308 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3310 st->priv_data = NULL;
3312 /* build destination RTP address */
3313 ipaddr = inet_ntoa(dest_addr->sin_addr);
3315 switch(c->rtp_protocol) {
3316 case RTSP_LOWER_TRANSPORT_UDP:
3317 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3320 /* XXX: also pass as parameter to function ? */
3321 if (c->stream->is_multicast) {
3323 ttl = c->stream->multicast_ttl;
3326 snprintf(ctx->filename, sizeof(ctx->filename),
3327 "rtp://%s:%d?multicast=1&ttl=%d",
3328 ipaddr, ntohs(dest_addr->sin_port), ttl);
3330 snprintf(ctx->filename, sizeof(ctx->filename),
3331 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3334 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3336 c->rtp_handles[stream_index] = h;
3337 max_packet_size = h->max_packet_size;
3339 case RTSP_LOWER_TRANSPORT_TCP:
3342 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3348 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3349 ipaddr, ntohs(dest_addr->sin_port),
3350 c->stream->filename, stream_index, c->protocol);
3352 /* normally, no packets should be output here, but the packet size may
3354 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3355 /* XXX: close stream */
3358 if (avformat_write_header(ctx, NULL) < 0) {
3366 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3369 c->rtp_ctx[stream_index] = ctx;
3373 /********************************************************************/
3374 /* ffserver initialization */
3376 static AVStream *add_av_stream1(FFServerStream *stream,
3377 AVCodecContext *codec, int copy)
3381 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3384 fst = av_mallocz(sizeof(AVStream));
3388 fst->codec = avcodec_alloc_context3(codec->codec);
3393 avcodec_copy_context(fst->codec, codec);
3395 /* live streams must use the actual feed's codec since it may be
3396 * updated later to carry extradata needed by them.
3400 fst->priv_data = av_mallocz(sizeof(FeedData));
3401 fst->index = stream->nb_streams;
3402 avpriv_set_pts_info(fst, 33, 1, 90000);
3403 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3404 stream->streams[stream->nb_streams++] = fst;
3408 /* return the stream number in the feed */
3409 static int add_av_stream(FFServerStream *feed, AVStream *st)
3412 AVCodecContext *av, *av1;
3416 for(i=0;i<feed->nb_streams;i++) {
3417 av1 = feed->streams[i]->codec;
3418 if (av1->codec_id == av->codec_id &&
3419 av1->codec_type == av->codec_type &&
3420 av1->bit_rate == av->bit_rate) {
3422 switch(av->codec_type) {
3423 case AVMEDIA_TYPE_AUDIO:
3424 if (av1->channels == av->channels &&
3425 av1->sample_rate == av->sample_rate)
3428 case AVMEDIA_TYPE_VIDEO:
3429 if (av1->width == av->width &&
3430 av1->height == av->height &&
3431 av1->time_base.den == av->time_base.den &&
3432 av1->time_base.num == av->time_base.num &&
3433 av1->gop_size == av->gop_size)
3442 fst = add_av_stream1(feed, av, 0);
3445 if (av_stream_get_recommended_encoder_configuration(st))
3446 av_stream_set_recommended_encoder_configuration(fst,
3447 av_strdup(av_stream_get_recommended_encoder_configuration(st)));
3448 return feed->nb_streams - 1;
3451 static void remove_stream(FFServerStream *stream)
3453 FFServerStream **ps;
3454 ps = &config.first_stream;
3463 /* specific MPEG4 handling : we extract the raw parameters */
3464 static void extract_mpeg4_header(AVFormatContext *infile)
3466 int mpeg4_count, i, size;
3471 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3474 for(i=0;i<infile->nb_streams;i++) {
3475 st = infile->streams[i];
3476 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3477 st->codec->extradata_size == 0) {
3484 printf("MPEG4 without extra data: trying to find header in %s\n",
3486 while (mpeg4_count > 0) {
3487 if (av_read_frame(infile, &pkt) < 0)
3489 st = infile->streams[pkt.stream_index];
3490 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3491 st->codec->extradata_size == 0) {
3492 av_freep(&st->codec->extradata);
3493 /* fill extradata with the header */
3494 /* XXX: we make hard suppositions here ! */
3496 while (p < pkt.data + pkt.size - 4) {
3497 /* stop when vop header is found */
3498 if (p[0] == 0x00 && p[1] == 0x00 &&
3499 p[2] == 0x01 && p[3] == 0xb6) {
3500 size = p - pkt.data;
3501 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3502 st->codec->extradata_size = size;
3503 memcpy(st->codec->extradata, pkt.data, size);
3510 av_free_packet(&pkt);
3514 /* compute the needed AVStream for each file */
3515 static void build_file_streams(void)
3517 FFServerStream *stream, *stream_next;
3520 /* gather all streams */
3521 for(stream = config.first_stream; stream; stream = stream_next) {
3522 AVFormatContext *infile = NULL;
3523 stream_next = stream->next;
3524 if (stream->stream_type == STREAM_TYPE_LIVE &&
3526 /* the stream comes from a file */
3527 /* try to open the file */
3529 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3530 /* specific case : if transport stream output to RTP,
3531 we use a raw transport stream reader */
3532 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3535 if (!stream->feed_filename[0]) {
3536 http_log("Unspecified feed file for stream '%s'\n",
3541 http_log("Opening feed file '%s' for stream '%s'\n",
3542 stream->feed_filename, stream->filename);
3543 ret = avformat_open_input(&infile, stream->feed_filename,
3544 stream->ifmt, &stream->in_opts);
3546 http_log("Could not open '%s': %s\n", stream->feed_filename,
3548 /* remove stream (no need to spend more time on it) */
3550 remove_stream(stream);
3552 /* find all the AVStreams inside and reference them in
3554 if (avformat_find_stream_info(infile, NULL) < 0) {
3555 http_log("Could not find codec parameters from '%s'\n",
3556 stream->feed_filename);
3557 avformat_close_input(&infile);
3560 extract_mpeg4_header(infile);
3562 for(i=0;i<infile->nb_streams;i++)
3563 add_av_stream1(stream, infile->streams[i]->codec, 1);
3565 avformat_close_input(&infile);
3571 /* compute the needed AVStream for each feed */
3572 static void build_feed_streams(void)
3574 FFServerStream *stream, *feed;
3577 /* gather all streams */
3578 for(stream = config.first_stream; stream; stream = stream->next) {
3579 feed = stream->feed;
3581 if (stream->is_feed) {
3582 for(i=0;i<stream->nb_streams;i++)
3583 stream->feed_streams[i] = i;
3585 /* we handle a stream coming from a feed */
3586 for(i=0;i<stream->nb_streams;i++)
3587 stream->feed_streams[i] = add_av_stream(feed,
3588 stream->streams[i]);
3593 /* create feed files if needed */
3594 for(feed = config.first_feed; feed; feed = feed->next_feed) {
3597 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3598 /* See if it matches */
3599 AVFormatContext *s = NULL;
3602 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3603 /* set buffer size */
3604 int ret = ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3606 http_log("Failed to set buffer size\n");
3610 /* Now see if it matches */
3611 if (s->nb_streams == feed->nb_streams) {
3613 for(i=0;i<s->nb_streams;i++) {
3615 sf = feed->streams[i];
3618 if (sf->index != ss->index ||
3620 http_log("Index & Id do not match for stream %d (%s)\n",
3621 i, feed->feed_filename);
3624 AVCodecContext *ccf, *ccs;
3628 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3630 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3631 http_log("Codecs do not match for stream %d\n", i);
3633 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3634 http_log("Codec bitrates do not match for stream %d\n", i);
3636 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3637 if (CHECK_CODEC(time_base.den) ||
3638 CHECK_CODEC(time_base.num) ||
3639 CHECK_CODEC(width) ||
3640 CHECK_CODEC(height)) {
3641 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3644 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3645 if (CHECK_CODEC(sample_rate) ||
3646 CHECK_CODEC(channels) ||
3647 CHECK_CODEC(frame_size)) {
3648 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3652 http_log("Unknown codec type\n");
3660 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3661 feed->feed_filename, s->nb_streams, feed->nb_streams);
3663 avformat_close_input(&s);
3665 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3666 feed->feed_filename);
3669 if (feed->readonly) {
3670 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3671 feed->feed_filename);
3674 unlink(feed->feed_filename);
3677 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3678 AVFormatContext *s = avformat_alloc_context();
3681 http_log("Failed to allocate context\n");
3685 if (feed->readonly) {
3686 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3687 feed->feed_filename);
3691 /* only write the header of the ffm file */
3692 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3693 http_log("Could not open output feed file '%s'\n",
3694 feed->feed_filename);
3697 s->oformat = feed->fmt;
3698 s->nb_streams = feed->nb_streams;
3699 s->streams = feed->streams;
3700 if (avformat_write_header(s, NULL) < 0) {
3701 http_log("Container doesn't support the required parameters\n");
3704 /* XXX: need better API */
3705 av_freep(&s->priv_data);
3706 avio_closep(&s->pb);
3709 avformat_free_context(s);
3711 /* get feed size and write index */
3712 fd = open(feed->feed_filename, O_RDONLY);
3714 http_log("Could not open output feed file '%s'\n",
3715 feed->feed_filename);
3719 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3720 feed->feed_size = lseek(fd, 0, SEEK_END);
3721 /* ensure that we do not wrap before the end of file */
3722 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3723 feed->feed_max_size = feed->feed_size;
3729 /* compute the bandwidth used by each stream */
3730 static void compute_bandwidth(void)
3734 FFServerStream *stream;
3736 for(stream = config.first_stream; stream; stream = stream->next) {
3738 for(i=0;i<stream->nb_streams;i++) {
3739 AVStream *st = stream->streams[i];
3740 switch(st->codec->codec_type) {
3741 case AVMEDIA_TYPE_AUDIO:
3742 case AVMEDIA_TYPE_VIDEO:
3743 bandwidth += st->codec->bit_rate;
3749 stream->bandwidth = (bandwidth + 999) / 1000;
3753 static void handle_child_exit(int sig)
3758 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3759 FFServerStream *feed;
3761 for (feed = config.first_feed; feed; feed = feed->next) {
3762 if (feed->pid == pid) {
3763 int uptime = time(0) - feed->pid_start;
3767 "%s: Pid %d exited with status %d after %d seconds\n",
3768 feed->filename, pid, status, uptime);
3771 /* Turn off any more restarts */
3772 ffserver_free_child_args(&feed->child_argv);
3777 need_to_start_children = 1;
3780 static void opt_debug(void)
3783 snprintf(config.logfilename, sizeof(config.logfilename), "-");
3786 void show_help_default(const char *opt, const char *arg)
3788 printf("usage: ffserver [options]\n"
3789 "Hyper fast multi format Audio/Video streaming server\n");
3791 show_help_options(options, "Main options:", 0, 0, 0);
3794 static const OptionDef options[] = {
3795 #include "cmdutils_common_opts.h"
3796 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3797 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3798 { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3802 int main(int argc, char **argv)
3804 struct sigaction sigact = { { 0 } };
3807 config.filename = av_strdup("/etc/ffserver.conf");
3809 parse_loglevel(argc, argv, options);
3811 avformat_network_init();
3813 show_banner(argc, argv, options);
3815 my_program_name = argv[0];
3817 parse_options(NULL, argc, argv, options, NULL);
3819 unsetenv("http_proxy"); /* Kill the http_proxy */
3821 av_lfg_init(&random_state, av_get_random_seed());
3823 sigact.sa_handler = handle_child_exit;
3824 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3825 sigaction(SIGCHLD, &sigact, 0);
3827 if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3828 fprintf(stderr, "Error reading configuration file '%s': %s\n",
3829 config.filename, av_err2str(ret));
3832 av_freep(&config.filename);
3834 /* open log file if needed */
3835 if (config.logfilename[0] != '\0') {
3836 if (!strcmp(config.logfilename, "-"))
3839 logfile = fopen(config.logfilename, "a");
3840 av_log_set_callback(http_av_log);
3843 build_file_streams();
3845 build_feed_streams();
3847 compute_bandwidth();
3850 signal(SIGPIPE, SIG_IGN);
3852 if (http_server() < 0) {
3853 http_log("Could not start server\n");