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)
970 /* Check if it is a single jpeg frame 123 */
971 if (c->stream->single_frame && c->data_count > c->cur_frame_bytes && c->cur_frame_bytes > 0) {
975 case HTTPSTATE_RECEIVE_DATA:
976 /* no need to read if no events */
977 if (c->poll_entry->revents & (POLLERR | POLLHUP))
979 if (!(c->poll_entry->revents & POLLIN))
981 if (http_receive_data(c) < 0)
984 case HTTPSTATE_WAIT_FEED:
985 /* no need to read if no events */
986 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
989 /* nothing to do, we'll be waken up by incoming feed packets */
992 case RTSPSTATE_SEND_REPLY:
993 if (c->poll_entry->revents & (POLLERR | POLLHUP))
994 goto close_connection;
995 /* no need to write if no events */
996 if (!(c->poll_entry->revents & POLLOUT))
998 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1000 if (ff_neterrno() != AVERROR(EAGAIN) &&
1001 ff_neterrno() != AVERROR(EINTR)) {
1002 goto close_connection;
1006 c->buffer_ptr += len;
1007 c->data_count += len;
1008 if (c->buffer_ptr >= c->buffer_end) {
1009 /* all the buffer was sent : wait for a new request */
1010 av_freep(&c->pb_buffer);
1011 start_wait_request(c, 1);
1014 case RTSPSTATE_SEND_PACKET:
1015 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1016 av_freep(&c->packet_buffer);
1019 /* no need to write if no events */
1020 if (!(c->poll_entry->revents & POLLOUT))
1022 len = send(c->fd, c->packet_buffer_ptr,
1023 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1025 if (ff_neterrno() != AVERROR(EAGAIN) &&
1026 ff_neterrno() != AVERROR(EINTR)) {
1027 /* error : close connection */
1028 av_freep(&c->packet_buffer);
1033 c->packet_buffer_ptr += len;
1034 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1035 /* all the buffer was sent : wait for a new request */
1036 av_freep(&c->packet_buffer);
1037 c->state = RTSPSTATE_WAIT_REQUEST;
1040 case HTTPSTATE_READY:
1049 av_freep(&c->pb_buffer);
1053 static int extract_rates(char *rates, int ratelen, const char *request)
1057 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1058 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1059 const char *q = p + 7;
1061 while (*q && *q != '\n' && av_isspace(*q))
1064 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1070 memset(rates, 0xff, ratelen);
1073 while (*q && *q != '\n' && *q != ':')
1076 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1080 if (stream_no < ratelen && stream_no >= 0)
1081 rates[stream_no] = rate_no;
1083 while (*q && *q != '\n' && !av_isspace(*q))
1090 p = strchr(p, '\n');
1100 static int find_stream_in_feed(FFServerStream *feed, AVCodecContext *codec,
1104 int best_bitrate = 100000000;
1107 for (i = 0; i < feed->nb_streams; i++) {
1108 AVCodecContext *feed_codec = feed->streams[i]->codec;
1110 if (feed_codec->codec_id != codec->codec_id ||
1111 feed_codec->sample_rate != codec->sample_rate ||
1112 feed_codec->width != codec->width ||
1113 feed_codec->height != codec->height)
1116 /* Potential stream */
1118 /* We want the fastest stream less than bit_rate, or the slowest
1119 * faster than bit_rate
1122 if (feed_codec->bit_rate <= bit_rate) {
1123 if (best_bitrate > bit_rate ||
1124 feed_codec->bit_rate > best_bitrate) {
1125 best_bitrate = feed_codec->bit_rate;
1130 if (feed_codec->bit_rate < best_bitrate) {
1131 best_bitrate = feed_codec->bit_rate;
1138 static int modify_current_stream(HTTPContext *c, char *rates)
1141 FFServerStream *req = c->stream;
1142 int action_required = 0;
1144 /* Not much we can do for a feed */
1148 for (i = 0; i < req->nb_streams; i++) {
1149 AVCodecContext *codec = req->streams[i]->codec;
1153 c->switch_feed_streams[i] = req->feed_streams[i];
1156 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1159 /* Wants off or slow */
1160 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1162 /* This doesn't work well when it turns off the only stream! */
1163 c->switch_feed_streams[i] = -2;
1164 c->feed_streams[i] = -2;
1169 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1170 action_required = 1;
1173 return action_required;
1176 static void get_word(char *buf, int buf_size, const char **pp)
1182 p += strspn(p, SPACE_CHARS);
1184 while (!av_isspace(*p) && *p != '\0') {
1185 if ((q - buf) < buf_size - 1)
1194 static FFServerIPAddressACL* parse_dynamic_acl(FFServerStream *stream,
1200 FFServerIPAddressACL *acl = NULL;
1204 f = fopen(stream->dynamic_acl, "r");
1206 perror(stream->dynamic_acl);
1210 acl = av_mallocz(sizeof(FFServerIPAddressACL));
1217 while (fgets(line, sizeof(line), f)) {
1220 while (av_isspace(*p))
1222 if (*p == '\0' || *p == '#')
1224 ffserver_get_arg(cmd, sizeof(cmd), &p);
1226 if (!av_strcasecmp(cmd, "ACL"))
1227 ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl,
1235 static void free_acl_list(FFServerIPAddressACL *in_acl)
1237 FFServerIPAddressACL *pacl, *pacl2;
1247 static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c)
1249 enum FFServerIPAddressAction last_action = IP_DENY;
1250 FFServerIPAddressACL *acl;
1251 struct in_addr *src = &c->from_addr.sin_addr;
1252 unsigned long src_addr = src->s_addr;
1254 for (acl = in_acl; acl; acl = acl->next) {
1255 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1256 return (acl->action == IP_ALLOW) ? 1 : 0;
1257 last_action = acl->action;
1260 /* Nothing matched, so return not the last action */
1261 return (last_action == IP_DENY) ? 1 : 0;
1264 static int validate_acl(FFServerStream *stream, HTTPContext *c)
1267 FFServerIPAddressACL *acl;
1269 /* if stream->acl is null validate_acl_list will return 1 */
1270 ret = validate_acl_list(stream->acl, c);
1272 if (stream->dynamic_acl[0]) {
1273 acl = parse_dynamic_acl(stream, c);
1275 ret = validate_acl_list(acl, c);
1283 /* compute the real filename of a file by matching it without its
1284 extensions to all the stream's filenames */
1285 static void compute_real_filename(char *filename, int max_size)
1290 FFServerStream *stream;
1292 /* compute filename by matching without the file extensions */
1293 av_strlcpy(file1, filename, sizeof(file1));
1294 p = strrchr(file1, '.');
1297 for(stream = config.first_stream; stream; stream = stream->next) {
1298 av_strlcpy(file2, stream->filename, sizeof(file2));
1299 p = strrchr(file2, '.');
1302 if (!strcmp(file1, file2)) {
1303 av_strlcpy(filename, stream->filename, max_size);
1318 /* parse HTTP request and prepare header */
1319 static int http_parse_request(HTTPContext *c)
1323 enum RedirType redir_type;
1325 char info[1024], filename[1024];
1329 const char *mime_type;
1330 FFServerStream *stream;
1333 const char *useragent = 0;
1336 get_word(cmd, sizeof(cmd), &p);
1337 av_strlcpy(c->method, cmd, sizeof(c->method));
1339 if (!strcmp(cmd, "GET"))
1341 else if (!strcmp(cmd, "POST"))
1346 get_word(url, sizeof(url), &p);
1347 av_strlcpy(c->url, url, sizeof(c->url));
1349 get_word(protocol, sizeof(protocol), (const char **)&p);
1350 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1353 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1356 http_log("%s - - New connection: %s %s\n",
1357 inet_ntoa(c->from_addr.sin_addr), cmd, url);
1359 /* find the filename and the optional info string in the request */
1360 p1 = strchr(url, '?');
1362 av_strlcpy(info, p1, sizeof(info));
1367 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1369 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1370 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1372 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1376 p = strchr(p, '\n');
1383 redir_type = REDIR_NONE;
1384 if (av_match_ext(filename, "asx")) {
1385 redir_type = REDIR_ASX;
1386 filename[strlen(filename)-1] = 'f';
1387 } else if (av_match_ext(filename, "asf") &&
1388 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) {
1389 /* if this isn't WMP or lookalike, return the redirector file */
1390 redir_type = REDIR_ASF;
1391 } else if (av_match_ext(filename, "rpm,ram")) {
1392 redir_type = REDIR_RAM;
1393 strcpy(filename + strlen(filename)-2, "m");
1394 } else if (av_match_ext(filename, "rtsp")) {
1395 redir_type = REDIR_RTSP;
1396 compute_real_filename(filename, sizeof(filename) - 1);
1397 } else if (av_match_ext(filename, "sdp")) {
1398 redir_type = REDIR_SDP;
1399 compute_real_filename(filename, sizeof(filename) - 1);
1402 // "redirect" / request to index.html
1403 if (!strlen(filename))
1404 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1406 stream = config.first_stream;
1408 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1410 stream = stream->next;
1413 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1414 http_log("File '%s' not found\n", url);
1419 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1420 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1422 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1423 c->http_error = 301;
1425 snprintf(q, c->buffer_size,
1426 "HTTP/1.0 301 Moved\r\n"
1428 "Content-type: text/html\r\n"
1430 "<html><head><title>Moved</title></head><body>\r\n"
1431 "You should be <a href=\"%s\">redirected</a>.\r\n"
1432 "</body></html>\r\n",
1433 stream->feed_filename, stream->feed_filename);
1435 /* prepare output buffer */
1436 c->buffer_ptr = c->buffer;
1438 c->state = HTTPSTATE_SEND_HEADER;
1442 /* If this is WMP, get the rate information */
1443 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1444 if (modify_current_stream(c, ratebuf)) {
1445 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1446 if (c->switch_feed_streams[i] >= 0)
1447 c->switch_feed_streams[i] = -1;
1452 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1453 current_bandwidth += stream->bandwidth;
1455 /* If already streaming this feed, do not let start another feeder. */
1456 if (stream->feed_opened) {
1457 snprintf(msg, sizeof(msg), "This feed is already being received.");
1458 http_log("Feed '%s' already being received\n", stream->feed_filename);
1462 if (c->post == 0 && config.max_bandwidth < current_bandwidth) {
1463 c->http_error = 503;
1465 snprintf(q, c->buffer_size,
1466 "HTTP/1.0 503 Server too busy\r\n"
1467 "Content-type: text/html\r\n"
1469 "<html><head><title>Too busy</title></head><body>\r\n"
1470 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1471 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1472 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1473 "</body></html>\r\n",
1474 current_bandwidth, config.max_bandwidth);
1476 /* prepare output buffer */
1477 c->buffer_ptr = c->buffer;
1479 c->state = HTTPSTATE_SEND_HEADER;
1483 if (redir_type != REDIR_NONE) {
1484 const char *hostinfo = 0;
1486 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1487 if (av_strncasecmp(p, "Host:", 5) == 0) {
1491 p = strchr(p, '\n');
1502 while (av_isspace(*hostinfo))
1505 eoh = strchr(hostinfo, '\n');
1507 if (eoh[-1] == '\r')
1510 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1511 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1512 hostbuf[eoh - hostinfo] = 0;
1514 c->http_error = 200;
1516 switch(redir_type) {
1518 snprintf(q, c->buffer_size,
1519 "HTTP/1.0 200 ASX Follows\r\n"
1520 "Content-type: video/x-ms-asf\r\n"
1522 "<ASX Version=\"3\">\r\n"
1523 //"<!-- Autogenerated by ffserver -->\r\n"
1524 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1525 "</ASX>\r\n", hostbuf, filename, info);
1529 snprintf(q, c->buffer_size,
1530 "HTTP/1.0 200 RAM Follows\r\n"
1531 "Content-type: audio/x-pn-realaudio\r\n"
1533 "# Autogenerated by ffserver\r\n"
1534 "http://%s/%s%s\r\n", hostbuf, filename, info);
1538 snprintf(q, c->buffer_size,
1539 "HTTP/1.0 200 ASF Redirect follows\r\n"
1540 "Content-type: video/x-ms-asf\r\n"
1543 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1548 char hostname[256], *p;
1549 /* extract only hostname */
1550 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1551 p = strrchr(hostname, ':');
1554 snprintf(q, c->buffer_size,
1555 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1556 /* XXX: incorrect MIME type ? */
1557 "Content-type: application/x-rtsp\r\n"
1559 "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
1568 struct sockaddr_in my_addr;
1570 snprintf(q, c->buffer_size,
1571 "HTTP/1.0 200 OK\r\n"
1572 "Content-type: application/sdp\r\n"
1576 len = sizeof(my_addr);
1578 /* XXX: Should probably fail? */
1579 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1580 http_log("getsockname() failed\n");
1582 /* XXX: should use a dynamic buffer */
1583 sdp_data_size = prepare_sdp_description(stream,
1586 if (sdp_data_size > 0) {
1587 memcpy(q, sdp_data, sdp_data_size);
1599 /* prepare output buffer */
1600 c->buffer_ptr = c->buffer;
1602 c->state = HTTPSTATE_SEND_HEADER;
1608 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1612 stream->conns_served++;
1614 /* XXX: add there authenticate and IP match */
1617 /* if post, it means a feed is being sent */
1618 if (!stream->is_feed) {
1619 /* However it might be a status report from WMP! Let us log the
1620 * data as it might come handy one day. */
1621 const char *logline = 0;
1624 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1625 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1629 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1630 client_id = strtol(p + 18, 0, 10);
1631 p = strchr(p, '\n');
1639 char *eol = strchr(logline, '\n');
1644 if (eol[-1] == '\r')
1646 http_log("%.*s\n", (int) (eol - logline), logline);
1647 c->suppress_log = 1;
1652 http_log("\nGot request:\n%s\n", c->buffer);
1655 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1658 /* Now we have to find the client_id */
1659 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1660 if (wmpc->wmp_client_id == client_id)
1664 if (wmpc && modify_current_stream(wmpc, ratebuf))
1665 wmpc->switch_pending = 1;
1668 snprintf(msg, sizeof(msg), "POST command not handled");
1672 if (http_start_receive_data(c) < 0) {
1673 snprintf(msg, sizeof(msg), "could not open feed");
1677 c->state = HTTPSTATE_RECEIVE_DATA;
1682 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1683 http_log("\nGot request:\n%s\n", c->buffer);
1686 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1689 /* open input stream */
1690 if (open_input_stream(c, info) < 0) {
1691 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1695 /* prepare HTTP header */
1697 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1698 mime_type = c->stream->fmt->mime_type;
1700 mime_type = "application/x-octet-stream";
1701 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1703 /* for asf, we need extra headers */
1704 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1705 /* Need to allocate a client id */
1707 c->wmp_client_id = av_lfg_get(&random_state);
1709 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);
1711 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1712 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1713 q = c->buffer + strlen(c->buffer);
1715 /* prepare output buffer */
1717 c->buffer_ptr = c->buffer;
1719 c->state = HTTPSTATE_SEND_HEADER;
1722 c->http_error = 404;
1725 snprintf(q, c->buffer_size,
1726 "HTTP/1.0 404 Not Found\r\n"
1727 "Content-type: text/html\r\n"
1730 "<head><title>404 Not Found</title></head>\n"
1734 /* prepare output buffer */
1735 c->buffer_ptr = c->buffer;
1737 c->state = HTTPSTATE_SEND_HEADER;
1741 c->http_error = 200; /* horrible : we use this value to avoid
1742 going to the send data state */
1743 c->state = HTTPSTATE_SEND_HEADER;
1747 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1749 static const char suffix[] = " kMGTP";
1752 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1754 avio_printf(pb, "%"PRId64"%c", count, *s);
1757 static void compute_status(HTTPContext *c)
1760 FFServerStream *stream;
1766 if (avio_open_dyn_buf(&pb) < 0) {
1767 /* XXX: return an error ? */
1768 c->buffer_ptr = c->buffer;
1769 c->buffer_end = c->buffer;
1773 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1774 avio_printf(pb, "Content-type: text/html\r\n");
1775 avio_printf(pb, "Pragma: no-cache\r\n");
1776 avio_printf(pb, "\r\n");
1778 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1779 if (c->stream->feed_filename[0])
1780 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n",
1781 c->stream->feed_filename);
1782 avio_printf(pb, "</head>\n<body>");
1783 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1785 avio_printf(pb, "<h2>Available Streams</h2>\n");
1786 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1787 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");
1788 stream = config.first_stream;
1790 char sfilename[1024];
1793 if (stream->feed == stream) {
1794 stream = stream->next;
1798 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1799 eosf = sfilename + strlen(sfilename);
1800 if (eosf - sfilename >= 4) {
1801 if (strcmp(eosf - 4, ".asf") == 0)
1802 strcpy(eosf - 4, ".asx");
1803 else if (strcmp(eosf - 3, ".rm") == 0)
1804 strcpy(eosf - 3, ".ram");
1805 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1806 /* generate a sample RTSP director if
1807 unicast. Generate an SDP redirector if
1809 eosf = strrchr(sfilename, '.');
1811 eosf = sfilename + strlen(sfilename);
1812 if (stream->is_multicast)
1813 strcpy(eosf, ".sdp");
1815 strcpy(eosf, ".rtsp");
1819 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1820 sfilename, stream->filename);
1821 avio_printf(pb, "<td align=right> %d <td align=right> ",
1822 stream->conns_served);
1823 fmt_bytecount(pb, stream->bytes_served);
1825 switch(stream->stream_type) {
1826 case STREAM_TYPE_LIVE: {
1827 int audio_bit_rate = 0;
1828 int video_bit_rate = 0;
1829 const char *audio_codec_name = "";
1830 const char *video_codec_name = "";
1831 const char *audio_codec_name_extra = "";
1832 const char *video_codec_name_extra = "";
1834 for(i=0;i<stream->nb_streams;i++) {
1835 AVStream *st = stream->streams[i];
1836 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1838 switch(st->codec->codec_type) {
1839 case AVMEDIA_TYPE_AUDIO:
1840 audio_bit_rate += st->codec->bit_rate;
1842 if (*audio_codec_name)
1843 audio_codec_name_extra = "...";
1844 audio_codec_name = codec->name;
1847 case AVMEDIA_TYPE_VIDEO:
1848 video_bit_rate += st->codec->bit_rate;
1850 if (*video_codec_name)
1851 video_codec_name_extra = "...";
1852 video_codec_name = codec->name;
1855 case AVMEDIA_TYPE_DATA:
1856 video_bit_rate += st->codec->bit_rate;
1863 avio_printf(pb, "<td align=center> %s <td align=right> %d "
1864 "<td align=right> %d <td> %s %s <td align=right> "
1866 stream->fmt->name, stream->bandwidth,
1867 video_bit_rate / 1000, video_codec_name,
1868 video_codec_name_extra, audio_bit_rate / 1000,
1869 audio_codec_name, audio_codec_name_extra);
1872 avio_printf(pb, "<td>%s", stream->feed->filename);
1874 avio_printf(pb, "<td>%s", stream->feed_filename);
1875 avio_printf(pb, "\n");
1879 avio_printf(pb, "<td align=center> - <td align=right> - "
1880 "<td align=right> - <td><td align=right> - <td>\n");
1883 stream = stream->next;
1885 avio_printf(pb, "</table>\n");
1887 stream = config.first_stream;
1890 if (stream->feed != stream) {
1891 stream = stream->next;
1895 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1897 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1904 /* This is somewhat linux specific I guess */
1905 snprintf(ps_cmd, sizeof(ps_cmd),
1906 "ps -o \"%%cpu,cputime\" --no-headers %d",
1909 pid_stat = popen(ps_cmd, "r");
1914 if (fscanf(pid_stat, "%9s %63s", cpuperc, cpuused) == 2) {
1915 avio_printf(pb, "Currently using %s%% of the cpu. "
1916 "Total time used %s.\n",
1924 avio_printf(pb, "<p>");
1927 avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>"
1928 "type<th>kbits/s<th align=left>codec<th align=left>"
1931 for (i = 0; i < stream->nb_streams; i++) {
1932 AVStream *st = stream->streams[i];
1933 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1934 const char *type = "unknown";
1935 char parameters[64];
1939 switch(st->codec->codec_type) {
1940 case AVMEDIA_TYPE_AUDIO:
1942 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz",
1943 st->codec->channels, st->codec->sample_rate);
1945 case AVMEDIA_TYPE_VIDEO:
1947 snprintf(parameters, sizeof(parameters),
1948 "%dx%d, q=%d-%d, fps=%d", st->codec->width,
1949 st->codec->height, st->codec->qmin, st->codec->qmax,
1950 st->codec->time_base.den / st->codec->time_base.num);
1956 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d"
1958 i, type, st->codec->bit_rate/1000,
1959 codec ? codec->name : "", parameters);
1962 avio_printf(pb, "</table>\n");
1963 stream = stream->next;
1966 /* connection status */
1967 avio_printf(pb, "<h2>Connection Status</h2>\n");
1969 avio_printf(pb, "Number of connections: %d / %d<br>\n",
1970 nb_connections, config.nb_max_connections);
1972 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1973 current_bandwidth, config.max_bandwidth);
1975 avio_printf(pb, "<table>\n");
1976 avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target "
1977 "bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1978 c1 = first_http_ctx;
1986 for (j = 0; j < c1->stream->nb_streams; j++) {
1987 if (!c1->stream->feed)
1988 bitrate += c1->stream->streams[j]->codec->bit_rate;
1989 else if (c1->feed_streams[j] >= 0)
1990 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1995 p = inet_ntoa(c1->from_addr.sin_addr);
1996 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s"
1998 i, c1->stream ? c1->stream->filename : "",
1999 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", p,
2000 c1->protocol, http_state[c1->state]);
2001 fmt_bytecount(pb, bitrate);
2002 avio_printf(pb, "<td align=right>");
2003 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2004 avio_printf(pb, "<td align=right>");
2005 fmt_bytecount(pb, c1->data_count);
2006 avio_printf(pb, "\n");
2009 avio_printf(pb, "</table>\n");
2014 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2015 avio_printf(pb, "</body>\n</html>\n");
2017 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2018 c->buffer_ptr = c->pb_buffer;
2019 c->buffer_end = c->pb_buffer + len;
2022 static int open_input_stream(HTTPContext *c, const char *info)
2025 char input_filename[1024];
2026 AVFormatContext *s = NULL;
2027 int buf_size, i, ret;
2030 /* find file name */
2031 if (c->stream->feed) {
2032 strcpy(input_filename, c->stream->feed->feed_filename);
2033 buf_size = FFM_PACKET_SIZE;
2034 /* compute position (absolute time) */
2035 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2036 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2037 http_log("Invalid date specification '%s' for stream\n", buf);
2040 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2041 int prebuffer = strtol(buf, 0, 10);
2042 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2044 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2046 strcpy(input_filename, c->stream->feed_filename);
2048 /* compute position (relative time) */
2049 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2050 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2051 http_log("Invalid date specification '%s' for stream\n", buf);
2057 if (!input_filename[0]) {
2058 http_log("No filename was specified for stream\n");
2059 return AVERROR(EINVAL);
2063 ret = avformat_open_input(&s, input_filename, c->stream->ifmt,
2064 &c->stream->in_opts);
2066 http_log("Could not open input '%s': %s\n",
2067 input_filename, av_err2str(ret));
2071 /* set buffer size */
2073 ret = ffio_set_buf_size(s->pb, buf_size);
2075 http_log("Failed to set buffer size\n");
2080 s->flags |= AVFMT_FLAG_GENPTS;
2082 if (strcmp(s->iformat->name, "ffm") &&
2083 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2084 http_log("Could not find stream info for input '%s'\n", input_filename);
2085 avformat_close_input(&s);
2089 /* choose stream as clock source (we favor the video stream if
2090 * present) for packet sending */
2091 c->pts_stream_index = 0;
2092 for(i=0;i<c->stream->nb_streams;i++) {
2093 if (c->pts_stream_index == 0 &&
2094 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2095 c->pts_stream_index = i;
2099 if (c->fmt_in->iformat->read_seek)
2100 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2101 /* set the start time (needed for maxtime and RTP packet timing) */
2102 c->start_time = cur_time;
2103 c->first_pts = AV_NOPTS_VALUE;
2107 /* return the server clock (in us) */
2108 static int64_t get_server_clock(HTTPContext *c)
2110 /* compute current pts value from system time */
2111 return (cur_time - c->start_time) * 1000;
2114 /* return the estimated time at which the current packet must be sent
2116 static int64_t get_packet_send_clock(HTTPContext *c)
2118 int bytes_left, bytes_sent, frame_bytes;
2120 frame_bytes = c->cur_frame_bytes;
2121 if (frame_bytes <= 0)
2124 bytes_left = c->buffer_end - c->buffer_ptr;
2125 bytes_sent = frame_bytes - bytes_left;
2126 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2131 static int http_prepare_data(HTTPContext *c)
2134 AVFormatContext *ctx;
2136 av_freep(&c->pb_buffer);
2138 case HTTPSTATE_SEND_DATA_HEADER:
2139 ctx = avformat_alloc_context();
2141 return AVERROR(ENOMEM);
2144 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2145 c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams,
2146 sizeof(AVStream *));
2147 if (!c->fmt_ctx.streams)
2148 return AVERROR(ENOMEM);
2150 for(i=0;i<c->stream->nb_streams;i++) {
2152 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2154 /* if file or feed, then just take streams from FFServerStream struct */
2155 if (!c->stream->feed ||
2156 c->stream->feed == c->stream)
2157 src = c->stream->streams[i];
2159 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2161 *(c->fmt_ctx.streams[i]) = *src;
2162 c->fmt_ctx.streams[i]->priv_data = 0;
2163 /* XXX: should be done in AVStream, not in codec */
2164 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2166 /* set output format parameters */
2167 c->fmt_ctx.oformat = c->stream->fmt;
2168 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2170 c->got_key_frame = 0;
2172 /* prepare header and save header data in a stream */
2173 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2174 /* XXX: potential leak */
2177 c->fmt_ctx.pb->seekable = 0;
2180 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2181 * Default value from FFmpeg
2182 * Try to set it using configuration option
2184 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2186 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2187 http_log("Error writing output header for stream '%s': %s\n",
2188 c->stream->filename, av_err2str(ret));
2191 av_dict_free(&c->fmt_ctx.metadata);
2193 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2194 c->buffer_ptr = c->pb_buffer;
2195 c->buffer_end = c->pb_buffer + len;
2197 c->state = HTTPSTATE_SEND_DATA;
2198 c->last_packet_sent = 0;
2200 case HTTPSTATE_SEND_DATA:
2201 /* find a new packet */
2202 /* read a packet from the input stream */
2203 if (c->stream->feed)
2204 ffm_set_write_index(c->fmt_in,
2205 c->stream->feed->feed_write_index,
2206 c->stream->feed->feed_size);
2208 if (c->stream->max_time &&
2209 c->stream->max_time + c->start_time - cur_time < 0)
2210 /* We have timed out */
2211 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2215 ret = av_read_frame(c->fmt_in, &pkt);
2217 if (c->stream->feed) {
2218 /* if coming from feed, it means we reached the end of the
2219 ffm file, so must wait for more data */
2220 c->state = HTTPSTATE_WAIT_FEED;
2221 return 1; /* state changed */
2222 } else if (ret == AVERROR(EAGAIN)) {
2223 /* input not ready, come back later */
2226 if (c->stream->loop) {
2227 avformat_close_input(&c->fmt_in);
2228 if (open_input_stream(c, "") < 0)
2233 /* must send trailer now because EOF or error */
2234 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2238 int source_index = pkt.stream_index;
2239 /* update first pts if needed */
2240 if (c->first_pts == AV_NOPTS_VALUE) {
2241 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2242 c->start_time = cur_time;
2244 /* send it to the appropriate stream */
2245 if (c->stream->feed) {
2246 /* if coming from a feed, select the right stream */
2247 if (c->switch_pending) {
2248 c->switch_pending = 0;
2249 for(i=0;i<c->stream->nb_streams;i++) {
2250 if (c->switch_feed_streams[i] == pkt.stream_index)
2251 if (pkt.flags & AV_PKT_FLAG_KEY)
2252 c->switch_feed_streams[i] = -1;
2253 if (c->switch_feed_streams[i] >= 0)
2254 c->switch_pending = 1;
2257 for(i=0;i<c->stream->nb_streams;i++) {
2258 if (c->stream->feed_streams[i] == pkt.stream_index) {
2259 AVStream *st = c->fmt_in->streams[source_index];
2260 pkt.stream_index = i;
2261 if (pkt.flags & AV_PKT_FLAG_KEY &&
2262 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2263 c->stream->nb_streams == 1))
2264 c->got_key_frame = 1;
2265 if (!c->stream->send_on_key || c->got_key_frame)
2270 AVCodecContext *codec;
2271 AVStream *ist, *ost;
2273 ist = c->fmt_in->streams[source_index];
2274 /* specific handling for RTP: we use several
2275 * output streams (one for each RTP connection).
2276 * XXX: need more abstract handling */
2277 if (c->is_packetized) {
2278 /* compute send time and duration */
2279 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2280 c->cur_pts -= c->first_pts;
2281 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2282 /* find RTP context */
2283 c->packet_stream_index = pkt.stream_index;
2284 ctx = c->rtp_ctx[c->packet_stream_index];
2286 av_free_packet(&pkt);
2289 codec = ctx->streams[0]->codec;
2290 /* only one stream per RTP connection */
2291 pkt.stream_index = 0;
2295 codec = ctx->streams[pkt.stream_index]->codec;
2298 if (c->is_packetized) {
2299 int max_packet_size;
2300 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2301 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2303 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2304 ret = ffio_open_dyn_packet_buf(&ctx->pb,
2307 ret = avio_open_dyn_buf(&ctx->pb);
2310 /* XXX: potential leak */
2313 ost = ctx->streams[pkt.stream_index];
2315 ctx->pb->seekable = 0;
2316 if (pkt.dts != AV_NOPTS_VALUE)
2317 pkt.dts = av_rescale_q(pkt.dts, ist->time_base,
2319 if (pkt.pts != AV_NOPTS_VALUE)
2320 pkt.pts = av_rescale_q(pkt.pts, ist->time_base,
2322 pkt.duration = av_rescale_q(pkt.duration, ist->time_base,
2324 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2325 http_log("Error writing frame to output for stream '%s': %s\n",
2326 c->stream->filename, av_err2str(ret));
2327 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2330 av_freep(&c->pb_buffer);
2331 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2332 c->cur_frame_bytes = len;
2333 c->buffer_ptr = c->pb_buffer;
2334 c->buffer_end = c->pb_buffer + len;
2336 codec->frame_number++;
2338 av_free_packet(&pkt);
2342 av_free_packet(&pkt);
2347 case HTTPSTATE_SEND_DATA_TRAILER:
2348 /* last packet test ? */
2349 if (c->last_packet_sent || c->is_packetized)
2352 /* prepare header */
2353 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2354 /* XXX: potential leak */
2357 c->fmt_ctx.pb->seekable = 0;
2358 av_write_trailer(ctx);
2359 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2360 c->buffer_ptr = c->pb_buffer;
2361 c->buffer_end = c->pb_buffer + len;
2363 c->last_packet_sent = 1;
2369 /* should convert the format at the same time */
2370 /* send data starting at c->buffer_ptr to the output connection
2371 * (either UDP or TCP) */
2372 static int http_send_data(HTTPContext *c)
2377 if (c->buffer_ptr >= c->buffer_end) {
2378 ret = http_prepare_data(c);
2382 /* state change requested */
2385 if (c->is_packetized) {
2386 /* RTP data output */
2387 len = c->buffer_end - c->buffer_ptr;
2389 /* fail safe - should never happen */
2391 c->buffer_ptr = c->buffer_end;
2394 len = (c->buffer_ptr[0] << 24) |
2395 (c->buffer_ptr[1] << 16) |
2396 (c->buffer_ptr[2] << 8) |
2398 if (len > (c->buffer_end - c->buffer_ptr))
2400 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2401 /* nothing to send yet: we can wait */
2405 c->data_count += len;
2406 update_datarate(&c->datarate, c->data_count);
2408 c->stream->bytes_served += len;
2410 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2411 /* RTP packets are sent inside the RTSP TCP connection */
2413 int interleaved_index, size;
2415 HTTPContext *rtsp_c;
2418 /* if no RTSP connection left, error */
2421 /* if already sending something, then wait. */
2422 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2424 if (avio_open_dyn_buf(&pb) < 0)
2426 interleaved_index = c->packet_stream_index * 2;
2427 /* RTCP packets are sent at odd indexes */
2428 if (c->buffer_ptr[1] == 200)
2429 interleaved_index++;
2430 /* write RTSP TCP header */
2432 header[1] = interleaved_index;
2433 header[2] = len >> 8;
2435 avio_write(pb, header, 4);
2436 /* write RTP packet data */
2438 avio_write(pb, c->buffer_ptr, len);
2439 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2440 /* prepare asynchronous TCP sending */
2441 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2442 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2443 c->buffer_ptr += len;
2445 /* send everything we can NOW */
2446 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2447 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2449 rtsp_c->packet_buffer_ptr += len;
2450 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2451 /* if we could not send all the data, we will
2452 send it later, so a new state is needed to
2453 "lock" the RTSP TCP connection */
2454 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2457 /* all data has been sent */
2458 av_freep(&c->packet_buffer);
2460 /* send RTP packet directly in UDP */
2462 ffurl_write(c->rtp_handles[c->packet_stream_index],
2463 c->buffer_ptr, len);
2464 c->buffer_ptr += len;
2465 /* here we continue as we can send several packets
2469 /* TCP data output */
2470 len = send(c->fd, c->buffer_ptr,
2471 c->buffer_end - c->buffer_ptr, 0);
2473 if (ff_neterrno() != AVERROR(EAGAIN) &&
2474 ff_neterrno() != AVERROR(EINTR))
2475 /* error : close connection */
2480 c->buffer_ptr += len;
2482 c->data_count += len;
2483 update_datarate(&c->datarate, c->data_count);
2485 c->stream->bytes_served += len;
2493 static int http_start_receive_data(HTTPContext *c)
2498 if (c->stream->feed_opened) {
2499 http_log("Stream feed '%s' was not opened\n",
2500 c->stream->feed_filename);
2501 return AVERROR(EINVAL);
2504 /* Don't permit writing to this one */
2505 if (c->stream->readonly) {
2506 http_log("Cannot write to read-only file '%s'\n",
2507 c->stream->feed_filename);
2508 return AVERROR(EINVAL);
2512 fd = open(c->stream->feed_filename, O_RDWR);
2514 ret = AVERROR(errno);
2515 http_log("Could not open feed file '%s': %s\n",
2516 c->stream->feed_filename, strerror(errno));
2521 if (c->stream->truncate) {
2522 /* truncate feed file */
2523 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2524 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2525 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2526 ret = AVERROR(errno);
2527 http_log("Error truncating feed file '%s': %s\n",
2528 c->stream->feed_filename, strerror(errno));
2532 ret = ffm_read_write_index(fd);
2534 http_log("Error reading write index from feed file '%s': %s\n",
2535 c->stream->feed_filename, strerror(errno));
2538 c->stream->feed_write_index = ret;
2542 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd),
2544 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2545 lseek(fd, 0, SEEK_SET);
2547 /* init buffer input */
2548 c->buffer_ptr = c->buffer;
2549 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2550 c->stream->feed_opened = 1;
2551 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2555 static int http_receive_data(HTTPContext *c)
2558 int len, loop_run = 0;
2560 while (c->chunked_encoding && !c->chunk_size &&
2561 c->buffer_end > c->buffer_ptr) {
2562 /* read chunk header, if present */
2563 len = recv(c->fd, c->buffer_ptr, 1, 0);
2566 if (ff_neterrno() != AVERROR(EAGAIN) &&
2567 ff_neterrno() != AVERROR(EINTR))
2568 /* error : close connection */
2571 } else if (len == 0) {
2572 /* end of connection : close it */
2574 } else if (c->buffer_ptr - c->buffer >= 2 &&
2575 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2576 c->chunk_size = strtol(c->buffer, 0, 16);
2577 if (c->chunk_size == 0) // end of stream
2579 c->buffer_ptr = c->buffer;
2581 } else if (++loop_run > 10) {
2582 /* no chunk header, abort */
2589 if (c->buffer_end > c->buffer_ptr) {
2590 len = recv(c->fd, c->buffer_ptr,
2591 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2593 if (ff_neterrno() != AVERROR(EAGAIN) &&
2594 ff_neterrno() != AVERROR(EINTR))
2595 /* error : close connection */
2597 } else if (len == 0)
2598 /* end of connection : close it */
2601 c->chunk_size -= len;
2602 c->buffer_ptr += len;
2603 c->data_count += len;
2604 update_datarate(&c->datarate, c->data_count);
2608 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2609 if (c->buffer[0] != 'f' ||
2610 c->buffer[1] != 'm') {
2611 http_log("Feed stream has become desynchronized -- disconnecting\n");
2616 if (c->buffer_ptr >= c->buffer_end) {
2617 FFServerStream *feed = c->stream;
2618 /* a packet has been received : write it in the store, except
2620 if (c->data_count > FFM_PACKET_SIZE) {
2621 /* XXX: use llseek or url_seek
2622 * XXX: Should probably fail? */
2623 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2624 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2626 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2627 http_log("Error writing to feed file: %s\n", strerror(errno));
2631 feed->feed_write_index += FFM_PACKET_SIZE;
2632 /* update file size */
2633 if (feed->feed_write_index > c->stream->feed_size)
2634 feed->feed_size = feed->feed_write_index;
2636 /* handle wrap around if max file size reached */
2637 if (c->stream->feed_max_size &&
2638 feed->feed_write_index >= c->stream->feed_max_size)
2639 feed->feed_write_index = FFM_PACKET_SIZE;
2642 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2643 http_log("Error writing index to feed file: %s\n",
2648 /* wake up any waiting connections */
2649 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2650 if (c1->state == HTTPSTATE_WAIT_FEED &&
2651 c1->stream->feed == c->stream->feed)
2652 c1->state = HTTPSTATE_SEND_DATA;
2655 /* We have a header in our hands that contains useful data */
2656 AVFormatContext *s = avformat_alloc_context();
2658 AVInputFormat *fmt_in;
2664 /* use feed output format name to find corresponding input format */
2665 fmt_in = av_find_input_format(feed->fmt->name);
2669 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2670 0, NULL, NULL, NULL, NULL);
2677 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2682 /* Now we have the actual streams */
2683 if (s->nb_streams != feed->nb_streams) {
2684 avformat_close_input(&s);
2686 http_log("Feed '%s' stream number does not match registered feed\n",
2687 c->stream->feed_filename);
2691 for (i = 0; i < s->nb_streams; i++) {
2692 AVStream *fst = feed->streams[i];
2693 AVStream *st = s->streams[i];
2694 avcodec_copy_context(fst->codec, st->codec);
2697 avformat_close_input(&s);
2700 c->buffer_ptr = c->buffer;
2705 c->stream->feed_opened = 0;
2707 /* wake up any waiting connections to stop waiting for feed */
2708 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2709 if (c1->state == HTTPSTATE_WAIT_FEED &&
2710 c1->stream->feed == c->stream->feed)
2711 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2716 /********************************************************************/
2719 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2726 str = RTSP_STATUS_CODE2STRING(error_number);
2728 str = "Unknown Error";
2730 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2731 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2733 /* output GMT time */
2736 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2737 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2740 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2742 rtsp_reply_header(c, error_number);
2743 avio_printf(c->pb, "\r\n");
2746 static int rtsp_parse_request(HTTPContext *c)
2748 const char *p, *p1, *p2;
2754 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2756 c->buffer_ptr[0] = '\0';
2759 get_word(cmd, sizeof(cmd), &p);
2760 get_word(url, sizeof(url), &p);
2761 get_word(protocol, sizeof(protocol), &p);
2763 av_strlcpy(c->method, cmd, sizeof(c->method));
2764 av_strlcpy(c->url, url, sizeof(c->url));
2765 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2767 if (avio_open_dyn_buf(&c->pb) < 0) {
2768 /* XXX: cannot do more */
2769 c->pb = NULL; /* safety */
2773 /* check version name */
2774 if (strcmp(protocol, "RTSP/1.0")) {
2775 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2779 /* parse each header line */
2780 /* skip to next line */
2781 while (*p != '\n' && *p != '\0')
2785 while (*p != '\0') {
2786 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2790 if (p2 > p && p2[-1] == '\r')
2792 /* skip empty line */
2796 if (len > sizeof(line) - 1)
2797 len = sizeof(line) - 1;
2798 memcpy(line, p, len);
2800 ff_rtsp_parse_line(header, line, NULL, NULL);
2804 /* handle sequence number */
2805 c->seq = header->seq;
2807 if (!strcmp(cmd, "DESCRIBE"))
2808 rtsp_cmd_describe(c, url);
2809 else if (!strcmp(cmd, "OPTIONS"))
2810 rtsp_cmd_options(c, url);
2811 else if (!strcmp(cmd, "SETUP"))
2812 rtsp_cmd_setup(c, url, header);
2813 else if (!strcmp(cmd, "PLAY"))
2814 rtsp_cmd_play(c, url, header);
2815 else if (!strcmp(cmd, "PAUSE"))
2816 rtsp_cmd_interrupt(c, url, header, 1);
2817 else if (!strcmp(cmd, "TEARDOWN"))
2818 rtsp_cmd_interrupt(c, url, header, 0);
2820 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2823 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2824 c->pb = NULL; /* safety */
2826 /* XXX: cannot do more */
2829 c->buffer_ptr = c->pb_buffer;
2830 c->buffer_end = c->pb_buffer + len;
2831 c->state = RTSPSTATE_SEND_REPLY;
2835 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2836 struct in_addr my_ip)
2838 AVFormatContext *avc;
2839 AVStream *avs = NULL;
2840 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2841 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2846 avc = avformat_alloc_context();
2847 if (!avc || !rtp_format) {
2850 avc->oformat = rtp_format;
2851 av_dict_set(&avc->metadata, "title",
2852 entry ? entry->value : "No Title", 0);
2853 avc->nb_streams = stream->nb_streams;
2854 if (stream->is_multicast) {
2855 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2856 inet_ntoa(stream->multicast_ip),
2857 stream->multicast_port, stream->multicast_ttl);
2859 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2862 avc->streams = av_malloc_array(avc->nb_streams, sizeof(*avc->streams));
2866 avs = av_malloc_array(avc->nb_streams, sizeof(*avs));
2870 for(i = 0; i < stream->nb_streams; i++) {
2871 avc->streams[i] = &avs[i];
2872 avc->streams[i]->codec = stream->streams[i]->codec;
2874 *pbuffer = av_mallocz(2048);
2877 av_sdp_create(&avc, 1, *pbuffer, 2048);
2880 av_freep(&avc->streams);
2881 av_dict_free(&avc->metadata);
2885 return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2888 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2890 // rtsp_reply_header(c, RTSP_STATUS_OK);
2891 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2892 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2893 avio_printf(c->pb, "Public: %s\r\n",
2894 "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2895 avio_printf(c->pb, "\r\n");
2898 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2900 FFServerStream *stream;
2906 struct sockaddr_in my_addr;
2908 /* find which URL is asked */
2909 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2914 for(stream = config.first_stream; stream; stream = stream->next) {
2915 if (!stream->is_feed &&
2916 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2917 !strcmp(path, stream->filename)) {
2921 /* no stream found */
2922 rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
2926 /* prepare the media description in SDP format */
2928 /* get the host IP */
2929 len = sizeof(my_addr);
2930 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2931 content_length = prepare_sdp_description(stream, &content,
2933 if (content_length < 0) {
2934 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2937 rtsp_reply_header(c, RTSP_STATUS_OK);
2938 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2939 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2940 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2941 avio_printf(c->pb, "\r\n");
2942 avio_write(c->pb, content, content_length);
2946 static HTTPContext *find_rtp_session(const char *session_id)
2950 if (session_id[0] == '\0')
2953 for(c = first_http_ctx; c; c = c->next) {
2954 if (!strcmp(c->session_id, session_id))
2960 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2962 RTSPTransportField *th;
2965 for(i=0;i<h->nb_transports;i++) {
2966 th = &h->transports[i];
2967 if (th->lower_transport == lower_transport)
2973 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2974 RTSPMessageHeader *h)
2976 FFServerStream *stream;
2977 int stream_index, rtp_port, rtcp_port;
2982 RTSPTransportField *th;
2983 struct sockaddr_in dest_addr;
2984 RTSPActionServerSetup setup;
2986 /* find which URL is asked */
2987 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2992 /* now check each stream */
2993 for(stream = config.first_stream; stream; stream = stream->next) {
2994 if (stream->is_feed || !stream->fmt ||
2995 strcmp(stream->fmt->name, "rtp")) {
2998 /* accept aggregate filenames only if single stream */
2999 if (!strcmp(path, stream->filename)) {
3000 if (stream->nb_streams != 1) {
3001 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3008 for(stream_index = 0; stream_index < stream->nb_streams;
3010 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3011 stream->filename, stream_index);
3012 if (!strcmp(path, buf))
3016 /* no stream found */
3017 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3021 /* generate session id if needed */
3022 if (h->session_id[0] == '\0') {
3023 unsigned random0 = av_lfg_get(&random_state);
3024 unsigned random1 = av_lfg_get(&random_state);
3025 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3029 /* find RTP session, and create it if none found */
3030 rtp_c = find_rtp_session(h->session_id);
3032 /* always prefer UDP */
3033 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3035 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3037 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3042 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3043 th->lower_transport);
3045 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3049 /* open input stream */
3050 if (open_input_stream(rtp_c, "") < 0) {
3051 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3056 /* test if stream is OK (test needed because several SETUP needs
3057 to be done for a given file) */
3058 if (rtp_c->stream != stream) {
3059 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3063 /* test if stream is already set up */
3064 if (rtp_c->rtp_ctx[stream_index]) {
3065 rtsp_reply_error(c, RTSP_STATUS_STATE);
3069 /* check transport */
3070 th = find_transport(h, rtp_c->rtp_protocol);
3071 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3072 th->client_port_min <= 0)) {
3073 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3077 /* setup default options */
3078 setup.transport_option[0] = '\0';
3079 dest_addr = rtp_c->from_addr;
3080 dest_addr.sin_port = htons(th->client_port_min);
3083 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3084 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3088 /* now everything is OK, so we can send the connection parameters */
3089 rtsp_reply_header(c, RTSP_STATUS_OK);
3091 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3093 switch(rtp_c->rtp_protocol) {
3094 case RTSP_LOWER_TRANSPORT_UDP:
3095 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3096 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3097 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3098 "client_port=%d-%d;server_port=%d-%d",
3099 th->client_port_min, th->client_port_max,
3100 rtp_port, rtcp_port);
3102 case RTSP_LOWER_TRANSPORT_TCP:
3103 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3104 stream_index * 2, stream_index * 2 + 1);
3109 if (setup.transport_option[0] != '\0')
3110 avio_printf(c->pb, ";%s", setup.transport_option);
3111 avio_printf(c->pb, "\r\n");
3114 avio_printf(c->pb, "\r\n");
3118 /* find an RTP connection by using the session ID. Check consistency
3120 static HTTPContext *find_rtp_session_with_url(const char *url,
3121 const char *session_id)
3129 rtp_c = find_rtp_session(session_id);
3133 /* find which URL is asked */
3134 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3138 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3139 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3140 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3141 rtp_c->stream->filename, s);
3142 if(!strncmp(path, buf, sizeof(buf))) {
3143 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3148 if (len > 0 && path[len - 1] == '/' &&
3149 !strncmp(path, rtp_c->stream->filename, len - 1))
3154 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3158 rtp_c = find_rtp_session_with_url(url, h->session_id);
3160 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3164 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3165 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3166 rtp_c->state != HTTPSTATE_READY) {
3167 rtsp_reply_error(c, RTSP_STATUS_STATE);
3171 rtp_c->state = HTTPSTATE_SEND_DATA;
3173 /* now everything is OK, so we can send the connection parameters */
3174 rtsp_reply_header(c, RTSP_STATUS_OK);
3176 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3177 avio_printf(c->pb, "\r\n");
3180 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
3181 RTSPMessageHeader *h, int pause_only)
3185 rtp_c = find_rtp_session_with_url(url, h->session_id);
3187 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3192 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3193 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3194 rtsp_reply_error(c, RTSP_STATUS_STATE);
3197 rtp_c->state = HTTPSTATE_READY;
3198 rtp_c->first_pts = AV_NOPTS_VALUE;
3201 /* now everything is OK, so we can send the connection parameters */
3202 rtsp_reply_header(c, RTSP_STATUS_OK);
3204 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3205 avio_printf(c->pb, "\r\n");
3208 close_connection(rtp_c);
3211 /********************************************************************/
3214 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3215 FFServerStream *stream,
3216 const char *session_id,
3217 enum RTSPLowerTransport rtp_protocol)
3219 HTTPContext *c = NULL;
3220 const char *proto_str;
3222 /* XXX: should output a warning page when coming
3223 close to the connection limit */
3224 if (nb_connections >= config.nb_max_connections)
3227 /* add a new connection */
3228 c = av_mallocz(sizeof(HTTPContext));
3233 c->poll_entry = NULL;
3234 c->from_addr = *from_addr;
3235 c->buffer_size = IOBUFFER_INIT_SIZE;
3236 c->buffer = av_malloc(c->buffer_size);
3241 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3242 c->state = HTTPSTATE_READY;
3243 c->is_packetized = 1;
3244 c->rtp_protocol = rtp_protocol;
3246 /* protocol is shown in statistics */
3247 switch(c->rtp_protocol) {
3248 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3249 proto_str = "MCAST";
3251 case RTSP_LOWER_TRANSPORT_UDP:
3254 case RTSP_LOWER_TRANSPORT_TCP:
3261 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3262 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3264 current_bandwidth += stream->bandwidth;
3266 c->next = first_http_ctx;
3272 av_freep(&c->buffer);
3278 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3279 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3281 static int rtp_new_av_stream(HTTPContext *c,
3282 int stream_index, struct sockaddr_in *dest_addr,
3283 HTTPContext *rtsp_c)
3285 AVFormatContext *ctx;
3288 URLContext *h = NULL;
3290 int max_packet_size;
3292 /* now we can open the relevant output stream */
3293 ctx = avformat_alloc_context();
3296 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3298 st = av_mallocz(sizeof(AVStream));
3301 ctx->nb_streams = 1;
3302 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3305 ctx->streams[0] = st;
3307 if (!c->stream->feed ||
3308 c->stream->feed == c->stream)
3309 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3312 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3314 st->priv_data = NULL;
3316 /* build destination RTP address */
3317 ipaddr = inet_ntoa(dest_addr->sin_addr);
3319 switch(c->rtp_protocol) {
3320 case RTSP_LOWER_TRANSPORT_UDP:
3321 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3324 /* XXX: also pass as parameter to function ? */
3325 if (c->stream->is_multicast) {
3327 ttl = c->stream->multicast_ttl;
3330 snprintf(ctx->filename, sizeof(ctx->filename),
3331 "rtp://%s:%d?multicast=1&ttl=%d",
3332 ipaddr, ntohs(dest_addr->sin_port), ttl);
3334 snprintf(ctx->filename, sizeof(ctx->filename),
3335 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3338 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3340 c->rtp_handles[stream_index] = h;
3341 max_packet_size = h->max_packet_size;
3343 case RTSP_LOWER_TRANSPORT_TCP:
3346 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3352 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3353 ipaddr, ntohs(dest_addr->sin_port),
3354 c->stream->filename, stream_index, c->protocol);
3356 /* normally, no packets should be output here, but the packet size may
3358 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3359 /* XXX: close stream */
3362 if (avformat_write_header(ctx, NULL) < 0) {
3370 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3373 c->rtp_ctx[stream_index] = ctx;
3377 /********************************************************************/
3378 /* ffserver initialization */
3380 static AVStream *add_av_stream1(FFServerStream *stream,
3381 AVCodecContext *codec, int copy)
3385 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3388 fst = av_mallocz(sizeof(AVStream));
3392 fst->codec = avcodec_alloc_context3(codec->codec);
3397 avcodec_copy_context(fst->codec, codec);
3399 /* live streams must use the actual feed's codec since it may be
3400 * updated later to carry extradata needed by them.
3404 fst->priv_data = av_mallocz(sizeof(FeedData));
3405 fst->index = stream->nb_streams;
3406 avpriv_set_pts_info(fst, 33, 1, 90000);
3407 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3408 stream->streams[stream->nb_streams++] = fst;
3412 /* return the stream number in the feed */
3413 static int add_av_stream(FFServerStream *feed, AVStream *st)
3416 AVCodecContext *av, *av1;
3420 for(i=0;i<feed->nb_streams;i++) {
3421 av1 = feed->streams[i]->codec;
3422 if (av1->codec_id == av->codec_id &&
3423 av1->codec_type == av->codec_type &&
3424 av1->bit_rate == av->bit_rate) {
3426 switch(av->codec_type) {
3427 case AVMEDIA_TYPE_AUDIO:
3428 if (av1->channels == av->channels &&
3429 av1->sample_rate == av->sample_rate)
3432 case AVMEDIA_TYPE_VIDEO:
3433 if (av1->width == av->width &&
3434 av1->height == av->height &&
3435 av1->time_base.den == av->time_base.den &&
3436 av1->time_base.num == av->time_base.num &&
3437 av1->gop_size == av->gop_size)
3446 fst = add_av_stream1(feed, av, 0);
3449 if (av_stream_get_recommended_encoder_configuration(st))
3450 av_stream_set_recommended_encoder_configuration(fst,
3451 av_strdup(av_stream_get_recommended_encoder_configuration(st)));
3452 return feed->nb_streams - 1;
3455 static void remove_stream(FFServerStream *stream)
3457 FFServerStream **ps;
3458 ps = &config.first_stream;
3467 /* specific MPEG4 handling : we extract the raw parameters */
3468 static void extract_mpeg4_header(AVFormatContext *infile)
3470 int mpeg4_count, i, size;
3475 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3478 for(i=0;i<infile->nb_streams;i++) {
3479 st = infile->streams[i];
3480 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3481 st->codec->extradata_size == 0) {
3488 printf("MPEG4 without extra data: trying to find header in %s\n",
3490 while (mpeg4_count > 0) {
3491 if (av_read_frame(infile, &pkt) < 0)
3493 st = infile->streams[pkt.stream_index];
3494 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3495 st->codec->extradata_size == 0) {
3496 av_freep(&st->codec->extradata);
3497 /* fill extradata with the header */
3498 /* XXX: we make hard suppositions here ! */
3500 while (p < pkt.data + pkt.size - 4) {
3501 /* stop when vop header is found */
3502 if (p[0] == 0x00 && p[1] == 0x00 &&
3503 p[2] == 0x01 && p[3] == 0xb6) {
3504 size = p - pkt.data;
3505 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3506 st->codec->extradata_size = size;
3507 memcpy(st->codec->extradata, pkt.data, size);
3514 av_free_packet(&pkt);
3518 /* compute the needed AVStream for each file */
3519 static void build_file_streams(void)
3521 FFServerStream *stream, *stream_next;
3524 /* gather all streams */
3525 for(stream = config.first_stream; stream; stream = stream_next) {
3526 AVFormatContext *infile = NULL;
3527 stream_next = stream->next;
3528 if (stream->stream_type == STREAM_TYPE_LIVE &&
3530 /* the stream comes from a file */
3531 /* try to open the file */
3533 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3534 /* specific case : if transport stream output to RTP,
3535 we use a raw transport stream reader */
3536 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3539 if (!stream->feed_filename[0]) {
3540 http_log("Unspecified feed file for stream '%s'\n",
3545 http_log("Opening feed file '%s' for stream '%s'\n",
3546 stream->feed_filename, stream->filename);
3547 ret = avformat_open_input(&infile, stream->feed_filename,
3548 stream->ifmt, &stream->in_opts);
3550 http_log("Could not open '%s': %s\n", stream->feed_filename,
3552 /* remove stream (no need to spend more time on it) */
3554 remove_stream(stream);
3556 /* find all the AVStreams inside and reference them in
3558 if (avformat_find_stream_info(infile, NULL) < 0) {
3559 http_log("Could not find codec parameters from '%s'\n",
3560 stream->feed_filename);
3561 avformat_close_input(&infile);
3564 extract_mpeg4_header(infile);
3566 for(i=0;i<infile->nb_streams;i++)
3567 add_av_stream1(stream, infile->streams[i]->codec, 1);
3569 avformat_close_input(&infile);
3575 /* compute the needed AVStream for each feed */
3576 static void build_feed_streams(void)
3578 FFServerStream *stream, *feed;
3581 /* gather all streams */
3582 for(stream = config.first_stream; stream; stream = stream->next) {
3583 feed = stream->feed;
3585 if (stream->is_feed) {
3586 for(i=0;i<stream->nb_streams;i++)
3587 stream->feed_streams[i] = i;
3589 /* we handle a stream coming from a feed */
3590 for(i=0;i<stream->nb_streams;i++)
3591 stream->feed_streams[i] = add_av_stream(feed,
3592 stream->streams[i]);
3597 /* create feed files if needed */
3598 for(feed = config.first_feed; feed; feed = feed->next_feed) {
3601 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3602 /* See if it matches */
3603 AVFormatContext *s = NULL;
3606 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3607 /* set buffer size */
3608 int ret = ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3610 http_log("Failed to set buffer size\n");
3614 /* Now see if it matches */
3615 if (s->nb_streams == feed->nb_streams) {
3617 for(i=0;i<s->nb_streams;i++) {
3619 sf = feed->streams[i];
3622 if (sf->index != ss->index ||
3624 http_log("Index & Id do not match for stream %d (%s)\n",
3625 i, feed->feed_filename);
3628 AVCodecContext *ccf, *ccs;
3632 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3634 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3635 http_log("Codecs do not match for stream %d\n", i);
3637 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3638 http_log("Codec bitrates do not match for stream %d\n", i);
3640 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3641 if (CHECK_CODEC(time_base.den) ||
3642 CHECK_CODEC(time_base.num) ||
3643 CHECK_CODEC(width) ||
3644 CHECK_CODEC(height)) {
3645 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3648 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3649 if (CHECK_CODEC(sample_rate) ||
3650 CHECK_CODEC(channels) ||
3651 CHECK_CODEC(frame_size)) {
3652 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3656 http_log("Unknown codec type\n");
3664 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3665 feed->feed_filename, s->nb_streams, feed->nb_streams);
3667 avformat_close_input(&s);
3669 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3670 feed->feed_filename);
3673 if (feed->readonly) {
3674 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3675 feed->feed_filename);
3678 unlink(feed->feed_filename);
3681 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3682 AVFormatContext *s = avformat_alloc_context();
3685 http_log("Failed to allocate context\n");
3689 if (feed->readonly) {
3690 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3691 feed->feed_filename);
3695 /* only write the header of the ffm file */
3696 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3697 http_log("Could not open output feed file '%s'\n",
3698 feed->feed_filename);
3701 s->oformat = feed->fmt;
3702 s->nb_streams = feed->nb_streams;
3703 s->streams = feed->streams;
3704 if (avformat_write_header(s, NULL) < 0) {
3705 http_log("Container doesn't support the required parameters\n");
3708 /* XXX: need better API */
3709 av_freep(&s->priv_data);
3710 avio_closep(&s->pb);
3713 avformat_free_context(s);
3715 /* get feed size and write index */
3716 fd = open(feed->feed_filename, O_RDONLY);
3718 http_log("Could not open output feed file '%s'\n",
3719 feed->feed_filename);
3723 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3724 feed->feed_size = lseek(fd, 0, SEEK_END);
3725 /* ensure that we do not wrap before the end of file */
3726 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3727 feed->feed_max_size = feed->feed_size;
3733 /* compute the bandwidth used by each stream */
3734 static void compute_bandwidth(void)
3738 FFServerStream *stream;
3740 for(stream = config.first_stream; stream; stream = stream->next) {
3742 for(i=0;i<stream->nb_streams;i++) {
3743 AVStream *st = stream->streams[i];
3744 switch(st->codec->codec_type) {
3745 case AVMEDIA_TYPE_AUDIO:
3746 case AVMEDIA_TYPE_VIDEO:
3747 bandwidth += st->codec->bit_rate;
3753 stream->bandwidth = (bandwidth + 999) / 1000;
3757 static void handle_child_exit(int sig)
3762 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3763 FFServerStream *feed;
3765 for (feed = config.first_feed; feed; feed = feed->next) {
3766 if (feed->pid == pid) {
3767 int uptime = time(0) - feed->pid_start;
3771 "%s: Pid %d exited with status %d after %d seconds\n",
3772 feed->filename, pid, status, uptime);
3775 /* Turn off any more restarts */
3776 ffserver_free_child_args(&feed->child_argv);
3781 need_to_start_children = 1;
3784 static void opt_debug(void)
3787 snprintf(config.logfilename, sizeof(config.logfilename), "-");
3790 void show_help_default(const char *opt, const char *arg)
3792 printf("usage: ffserver [options]\n"
3793 "Hyper fast multi format Audio/Video streaming server\n");
3795 show_help_options(options, "Main options:", 0, 0, 0);
3798 static const OptionDef options[] = {
3799 #include "cmdutils_common_opts.h"
3800 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3801 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3802 { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3806 int main(int argc, char **argv)
3808 struct sigaction sigact = { { 0 } };
3811 config.filename = av_strdup("/etc/ffserver.conf");
3813 parse_loglevel(argc, argv, options);
3815 avformat_network_init();
3817 show_banner(argc, argv, options);
3819 my_program_name = argv[0];
3821 parse_options(NULL, argc, argv, options, NULL);
3823 unsetenv("http_proxy"); /* Kill the http_proxy */
3825 av_lfg_init(&random_state, av_get_random_seed());
3827 sigact.sa_handler = handle_child_exit;
3828 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3829 sigaction(SIGCHLD, &sigact, 0);
3831 if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3832 fprintf(stderr, "Error reading configuration file '%s': %s\n",
3833 config.filename, av_err2str(ret));
3836 av_freep(&config.filename);
3838 /* open log file if needed */
3839 if (config.logfilename[0] != '\0') {
3840 if (!strcmp(config.logfilename, "-"))
3843 logfile = fopen(config.logfilename, "a");
3844 av_log_set_callback(http_av_log);
3847 build_file_streams();
3849 build_feed_streams();
3851 compute_bandwidth();
3854 signal(SIGPIPE, SIG_IGN);
3856 if (http_server() < 0) {
3857 http_log("Could not start server\n");