2 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * multiple format streaming server based on the FFmpeg libraries
28 #define closesocket close
33 #include "libavformat/avformat.h"
34 // FIXME those are internal headers, ffserver _really_ shouldn't use them
35 #include "libavformat/ffm.h"
36 #include "libavformat/network.h"
37 #include "libavformat/os_support.h"
38 #include "libavformat/rtpdec.h"
39 #include "libavformat/rtpproto.h"
40 #include "libavformat/rtsp.h"
41 #include "libavformat/rtspcodes.h"
42 #include "libavformat/avio_internal.h"
43 #include "libavformat/internal.h"
44 #include "libavformat/url.h"
46 #include "libavutil/avassert.h"
47 #include "libavutil/avstring.h"
48 #include "libavutil/lfg.h"
49 #include "libavutil/dict.h"
50 #include "libavutil/intreadwrite.h"
51 #include "libavutil/mathematics.h"
52 #include "libavutil/random_seed.h"
53 #include "libavutil/parseutils.h"
54 #include "libavutil/opt.h"
55 #include "libavutil/time.h"
62 #include <sys/ioctl.h>
72 #include "ffserver_config.h"
74 const char program_name[] = "ffserver";
75 const int program_birth_year = 2000;
77 static const OptionDef options[];
80 HTTPSTATE_WAIT_REQUEST,
81 HTTPSTATE_SEND_HEADER,
82 HTTPSTATE_SEND_DATA_HEADER,
83 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
84 HTTPSTATE_SEND_DATA_TRAILER,
85 HTTPSTATE_RECEIVE_DATA,
86 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
89 RTSPSTATE_WAIT_REQUEST,
91 RTSPSTATE_SEND_PACKET,
94 static const char * const http_state[] = {
110 #define IOBUFFER_INIT_SIZE 8192
112 /* timeouts are in ms */
113 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
114 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
116 #define SYNC_TIMEOUT (10 * 1000)
118 typedef struct RTSPActionServerSetup {
120 char transport_option[512];
121 } RTSPActionServerSetup;
124 int64_t count1, count2;
125 int64_t time1, time2;
128 /* context associated with one connection */
129 typedef struct HTTPContext {
130 enum HTTPState state;
131 int fd; /* socket file descriptor */
132 struct sockaddr_in from_addr; /* origin */
133 struct pollfd *poll_entry; /* used when polling */
135 uint8_t *buffer_ptr, *buffer_end;
138 int chunked_encoding;
139 int chunk_size; /* 0 if it needs to be read */
140 struct HTTPContext *next;
141 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
145 /* input format handling */
146 AVFormatContext *fmt_in;
147 int64_t start_time; /* In milliseconds - this wraps fairly often */
148 int64_t first_pts; /* initial pts value */
149 int64_t cur_pts; /* current pts value from the stream in us */
150 int64_t cur_frame_duration; /* duration of the current frame in us */
151 int cur_frame_bytes; /* output frame size, needed to compute
152 the time at which we send each
154 int pts_stream_index; /* stream we choose as clock reference */
155 int64_t cur_clock; /* current clock reference value in us */
156 /* output format handling */
157 struct FFServerStream *stream;
158 /* -1 is invalid stream */
159 int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
160 int switch_feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
162 AVFormatContext fmt_ctx; /* instance of FFServerStream for one user */
163 int last_packet_sent; /* true if last data packet was sent */
165 DataRateData datarate;
172 int is_packetized; /* if true, the stream is packetized */
173 int packet_stream_index; /* current stream for output in state machine */
175 /* RTSP state specific */
176 uint8_t *pb_buffer; /* XXX: use that in all the code */
178 int seq; /* RTSP sequence number */
180 /* RTP state specific */
181 enum RTSPLowerTransport rtp_protocol;
182 char session_id[32]; /* session id */
183 AVFormatContext *rtp_ctx[FFSERVER_MAX_STREAMS];
185 /* RTP/UDP specific */
186 URLContext *rtp_handles[FFSERVER_MAX_STREAMS];
188 /* RTP/TCP specific */
189 struct HTTPContext *rtsp_c;
190 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
193 typedef struct FeedData {
194 long long data_count;
195 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
198 static HTTPContext *first_http_ctx;
200 static FFServerConfig config = {
201 .nb_max_http_connections = 2000,
202 .nb_max_connections = 5,
203 .max_bandwidth = 1000,
207 static void new_connection(int server_fd, int is_rtsp);
208 static void close_connection(HTTPContext *c);
211 static int handle_connection(HTTPContext *c);
212 static void compute_status(HTTPContext *c);
213 static int open_input_stream(HTTPContext *c, const char *info);
214 static int http_parse_request(HTTPContext *c);
215 static int http_send_data(HTTPContext *c);
216 static int http_start_receive_data(HTTPContext *c);
217 static int http_receive_data(HTTPContext *c);
220 static int rtsp_parse_request(HTTPContext *c);
221 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
222 static void rtsp_cmd_options(HTTPContext *c, const char *url);
223 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
224 RTSPMessageHeader *h);
225 static void rtsp_cmd_play(HTTPContext *c, const char *url,
226 RTSPMessageHeader *h);
227 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
228 RTSPMessageHeader *h, int pause_only);
231 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
232 struct in_addr my_ip);
235 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
236 FFServerStream *stream,
237 const char *session_id,
238 enum RTSPLowerTransport rtp_protocol);
239 static int rtp_new_av_stream(HTTPContext *c,
240 int stream_index, struct sockaddr_in *dest_addr,
241 HTTPContext *rtsp_c);
243 static const char *my_program_name;
245 static int no_launch;
246 static int need_to_start_children;
248 /* maximum number of simultaneous HTTP connections */
249 static unsigned int nb_connections;
251 static uint64_t current_bandwidth;
253 static int64_t cur_time; // Making this global saves on passing it around everywhere
255 static AVLFG random_state;
257 static FILE *logfile = NULL;
259 static void htmlstrip(char *s) {
261 s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
267 static int64_t ffm_read_write_index(int fd)
271 if (lseek(fd, 8, SEEK_SET) < 0)
273 if (read(fd, buf, 8) != 8)
278 static int ffm_write_write_index(int fd, int64_t pos)
284 buf[i] = (pos >> (56 - i * 8)) & 0xff;
285 if (lseek(fd, 8, SEEK_SET) < 0)
287 if (write(fd, buf, 8) != 8)
292 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
295 FFMContext *ffm = s->priv_data;
296 ffm->write_index = pos;
297 ffm->file_size = file_size;
300 static char *ctime1(char *buf2, int buf_size)
307 av_strlcpy(buf2, p, buf_size);
308 p = buf2 + strlen(p) - 1;
314 static void http_vlog(const char *fmt, va_list vargs)
316 static int print_prefix = 1;
323 ctime1(buf, sizeof(buf));
324 fprintf(logfile, "%s ", buf);
326 print_prefix = strstr(fmt, "\n") != NULL;
327 vfprintf(logfile, fmt, vargs);
332 __attribute__ ((format (printf, 1, 2)))
334 static void http_log(const char *fmt, ...)
337 va_start(vargs, fmt);
338 http_vlog(fmt, vargs);
342 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
344 static int print_prefix = 1;
345 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
346 if (level > av_log_get_level())
348 if (print_prefix && avc)
349 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
350 print_prefix = strstr(fmt, "\n") != NULL;
351 http_vlog(fmt, vargs);
354 static void log_connection(HTTPContext *c)
359 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
360 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
361 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
364 static void update_datarate(DataRateData *drd, int64_t count)
366 if (!drd->time1 && !drd->count1) {
367 drd->time1 = drd->time2 = cur_time;
368 drd->count1 = drd->count2 = count;
369 } else if (cur_time - drd->time2 > 5000) {
370 drd->time1 = drd->time2;
371 drd->count1 = drd->count2;
372 drd->time2 = cur_time;
377 /* In bytes per second */
378 static int compute_datarate(DataRateData *drd, int64_t count)
380 if (cur_time == drd->time1)
383 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
387 static void start_children(FFServerStream *feed)
396 /* replace "ffserver" with "ffmpeg" in the path of current
397 * program. Ignore user provided path */
398 av_strlcpy(pathname, my_program_name, sizeof(pathname));
400 slash = strrchr(pathname, '/');
405 strcpy(slash, "ffmpeg");
407 for (; feed; feed = feed->next) {
409 if (!feed->child_argv || feed->pid)
412 feed->pid_start = time(0);
416 http_log("Unable to create children\n");
425 http_log("Launch command line: ");
426 http_log("%s ", pathname);
428 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
429 http_log("%s ", feed->child_argv[i]);
432 for (i = 3; i < 256; i++)
436 if (!freopen("/dev/null", "r", stdin))
437 http_log("failed to redirect STDIN to /dev/null\n;");
438 if (!freopen("/dev/null", "w", stdout))
439 http_log("failed to redirect STDOUT to /dev/null\n;");
440 if (!freopen("/dev/null", "w", stderr))
441 http_log("failed to redirect STDERR to /dev/null\n;");
444 signal(SIGPIPE, SIG_DFL);
445 execvp(pathname, feed->child_argv);
450 /* open a listening socket */
451 static int socket_open_listen(struct sockaddr_in *my_addr)
455 server_fd = socket(AF_INET,SOCK_STREAM,0);
462 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)))
463 av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n");
465 my_addr->sin_family = AF_INET;
466 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
468 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)",
469 ntohs(my_addr->sin_port));
471 closesocket(server_fd);
475 if (listen (server_fd, 5) < 0) {
477 closesocket(server_fd);
481 if (ff_socket_nonblock(server_fd, 1) < 0)
482 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
487 /* start all multicast streams */
488 static void start_multicast(void)
490 FFServerStream *stream;
493 struct sockaddr_in dest_addr = {0};
494 int default_port, stream_index;
495 unsigned int random0, random1;
498 for(stream = config.first_stream; stream; stream = stream->next) {
500 if (!stream->is_multicast)
503 random0 = av_lfg_get(&random_state);
504 random1 = av_lfg_get(&random_state);
506 /* open the RTP connection */
507 snprintf(session_id, sizeof(session_id), "%08x%08x",
510 /* choose a port if none given */
511 if (stream->multicast_port == 0) {
512 stream->multicast_port = default_port;
516 dest_addr.sin_family = AF_INET;
517 dest_addr.sin_addr = stream->multicast_ip;
518 dest_addr.sin_port = htons(stream->multicast_port);
520 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
521 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
525 if (open_input_stream(rtp_c, "") < 0) {
526 http_log("Could not open input stream for stream '%s'\n",
531 /* open each RTP stream */
532 for(stream_index = 0; stream_index < stream->nb_streams;
534 dest_addr.sin_port = htons(stream->multicast_port +
536 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) >= 0)
539 http_log("Could not open output stream '%s/streamid=%d'\n",
540 stream->filename, stream_index);
544 rtp_c->state = HTTPSTATE_SEND_DATA;
548 /* main loop of the HTTP server */
549 static int http_server(void)
551 int server_fd = 0, rtsp_server_fd = 0;
553 struct pollfd *poll_table, *poll_entry;
554 HTTPContext *c, *c_next;
556 poll_table = av_mallocz_array(config.nb_max_http_connections + 2,
557 sizeof(*poll_table));
559 http_log("Impossible to allocate a poll table handling %d "
560 "connections.\n", config.nb_max_http_connections);
564 if (config.http_addr.sin_port) {
565 server_fd = socket_open_listen(&config.http_addr);
572 if (config.rtsp_addr.sin_port) {
573 rtsp_server_fd = socket_open_listen(&config.rtsp_addr);
574 if (rtsp_server_fd < 0) {
576 closesocket(server_fd);
581 if (!rtsp_server_fd && !server_fd) {
582 http_log("HTTP and RTSP disabled.\n");
587 http_log("FFserver started.\n");
589 start_children(config.first_feed);
594 poll_entry = poll_table;
596 poll_entry->fd = server_fd;
597 poll_entry->events = POLLIN;
600 if (rtsp_server_fd) {
601 poll_entry->fd = rtsp_server_fd;
602 poll_entry->events = POLLIN;
606 /* wait for events on each HTTP handle */
613 case HTTPSTATE_SEND_HEADER:
614 case RTSPSTATE_SEND_REPLY:
615 case RTSPSTATE_SEND_PACKET:
616 c->poll_entry = poll_entry;
618 poll_entry->events = POLLOUT;
621 case HTTPSTATE_SEND_DATA_HEADER:
622 case HTTPSTATE_SEND_DATA:
623 case HTTPSTATE_SEND_DATA_TRAILER:
624 if (!c->is_packetized) {
625 /* for TCP, we output as much as we can
626 * (may need to put a limit) */
627 c->poll_entry = poll_entry;
629 poll_entry->events = POLLOUT;
632 /* when ffserver is doing the timing, we work by
633 looking at which packet needs to be sent every
635 /* one tick wait XXX: 10 ms assumed */
640 case HTTPSTATE_WAIT_REQUEST:
641 case HTTPSTATE_RECEIVE_DATA:
642 case HTTPSTATE_WAIT_FEED:
643 case RTSPSTATE_WAIT_REQUEST:
644 /* need to catch errors */
645 c->poll_entry = poll_entry;
647 poll_entry->events = POLLIN;/* Maybe this will work */
651 c->poll_entry = NULL;
657 /* wait for an event on one connection. We poll at least every
658 second to handle timeouts */
660 ret = poll(poll_table, poll_entry - poll_table, delay);
661 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
662 ff_neterrno() != AVERROR(EINTR)) {
668 cur_time = av_gettime() / 1000;
670 if (need_to_start_children) {
671 need_to_start_children = 0;
672 start_children(config.first_feed);
675 /* now handle the events */
676 for(c = first_http_ctx; c; c = c_next) {
678 if (handle_connection(c) < 0) {
680 /* close and free the connection */
685 poll_entry = poll_table;
687 /* new HTTP connection request ? */
688 if (poll_entry->revents & POLLIN)
689 new_connection(server_fd, 0);
692 if (rtsp_server_fd) {
693 /* new RTSP connection request ? */
694 if (poll_entry->revents & POLLIN)
695 new_connection(rtsp_server_fd, 1);
700 /* start waiting for a new HTTP/RTSP request */
701 static void start_wait_request(HTTPContext *c, int is_rtsp)
703 c->buffer_ptr = c->buffer;
704 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
707 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
708 c->state = RTSPSTATE_WAIT_REQUEST;
710 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
711 c->state = HTTPSTATE_WAIT_REQUEST;
715 static void http_send_too_busy_reply(int fd)
718 int len = snprintf(buffer, sizeof(buffer),
719 "HTTP/1.0 503 Server too busy\r\n"
720 "Content-type: text/html\r\n"
722 "<html><head><title>Too busy</title></head><body>\r\n"
723 "<p>The server is too busy to serve your request at this time.</p>\r\n"
724 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
725 "</body></html>\r\n",
726 nb_connections, config.nb_max_connections);
727 av_assert0(len < sizeof(buffer));
728 if (send(fd, buffer, len, 0) < len)
729 av_log(NULL, AV_LOG_WARNING,
730 "Could not send too-busy reply, send() failed\n");
734 static void new_connection(int server_fd, int is_rtsp)
736 struct sockaddr_in from_addr;
739 HTTPContext *c = NULL;
741 len = sizeof(from_addr);
742 fd = accept(server_fd, (struct sockaddr *)&from_addr,
745 http_log("error during accept %s\n", strerror(errno));
748 if (ff_socket_nonblock(fd, 1) < 0)
749 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
751 if (nb_connections >= config.nb_max_connections) {
752 http_send_too_busy_reply(fd);
756 /* add a new connection */
757 c = av_mallocz(sizeof(HTTPContext));
762 c->poll_entry = NULL;
763 c->from_addr = from_addr;
764 c->buffer_size = IOBUFFER_INIT_SIZE;
765 c->buffer = av_malloc(c->buffer_size);
769 c->next = first_http_ctx;
773 start_wait_request(c, is_rtsp);
779 av_freep(&c->buffer);
785 static void close_connection(HTTPContext *c)
787 HTTPContext **cp, *c1;
789 AVFormatContext *ctx;
793 /* remove connection from list */
794 cp = &first_http_ctx;
803 /* remove references, if any (XXX: do it faster) */
804 for(c1 = first_http_ctx; c1; c1 = c1->next) {
809 /* remove connection associated resources */
813 /* close each frame parser */
814 for(i=0;i<c->fmt_in->nb_streams;i++) {
815 st = c->fmt_in->streams[i];
816 if (st->codec->codec)
817 avcodec_close(st->codec);
819 avformat_close_input(&c->fmt_in);
822 /* free RTP output streams if any */
825 nb_streams = c->stream->nb_streams;
827 for(i=0;i<nb_streams;i++) {
830 av_write_trailer(ctx);
831 av_dict_free(&ctx->metadata);
832 av_freep(&ctx->streams[0]);
835 h = c->rtp_handles[i];
842 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
844 if (ctx->oformat && avio_open_dyn_buf(&ctx->pb) >= 0) {
845 av_write_trailer(ctx);
846 av_freep(&c->pb_buffer);
847 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
851 for(i=0; i<ctx->nb_streams; i++)
852 av_freep(&ctx->streams[i]);
853 av_freep(&ctx->streams);
854 av_freep(&ctx->priv_data);
856 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
857 current_bandwidth -= c->stream->bandwidth;
859 /* signal that there is no feed if we are the feeder socket */
860 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
861 c->stream->feed_opened = 0;
865 av_freep(&c->pb_buffer);
866 av_freep(&c->packet_buffer);
867 av_freep(&c->buffer);
872 static int handle_connection(HTTPContext *c)
878 case HTTPSTATE_WAIT_REQUEST:
879 case RTSPSTATE_WAIT_REQUEST:
881 if ((c->timeout - cur_time) < 0)
883 if (c->poll_entry->revents & (POLLERR | POLLHUP))
886 /* no need to read if no events */
887 if (!(c->poll_entry->revents & POLLIN))
891 if (!(len = recv(c->fd, c->buffer_ptr, 1, 0)))
895 if (ff_neterrno() != AVERROR(EAGAIN) &&
896 ff_neterrno() != AVERROR(EINTR))
900 /* search for end of request. */
901 c->buffer_ptr += len;
903 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
904 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
905 /* request found : parse it and reply */
906 if (c->state == HTTPSTATE_WAIT_REQUEST) {
907 ret = http_parse_request(c);
909 ret = rtsp_parse_request(c);
913 } else if (ptr >= c->buffer_end) {
914 /* request too long: cannot do anything */
916 } else goto read_loop;
920 case HTTPSTATE_SEND_HEADER:
921 if (c->poll_entry->revents & (POLLERR | POLLHUP))
924 /* no need to write if no events */
925 if (!(c->poll_entry->revents & POLLOUT))
927 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
929 if (ff_neterrno() != AVERROR(EAGAIN) &&
930 ff_neterrno() != AVERROR(EINTR)) {
931 goto close_connection;
935 c->buffer_ptr += len;
937 c->stream->bytes_served += len;
938 c->data_count += len;
939 if (c->buffer_ptr >= c->buffer_end) {
940 av_freep(&c->pb_buffer);
944 /* all the buffer was sent : synchronize to the incoming
946 c->state = HTTPSTATE_SEND_DATA_HEADER;
947 c->buffer_ptr = c->buffer_end = c->buffer;
951 case HTTPSTATE_SEND_DATA:
952 case HTTPSTATE_SEND_DATA_HEADER:
953 case HTTPSTATE_SEND_DATA_TRAILER:
954 /* for packetized output, we consider we can always write (the
955 input streams set the speed). It may be better to verify
956 that we do not rely too much on the kernel queues */
957 if (!c->is_packetized) {
958 if (c->poll_entry->revents & (POLLERR | POLLHUP))
961 /* no need to read if no events */
962 if (!(c->poll_entry->revents & POLLOUT))
965 if (http_send_data(c) < 0)
967 /* close connection if trailer sent */
968 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
971 case HTTPSTATE_RECEIVE_DATA:
972 /* no need to read if no events */
973 if (c->poll_entry->revents & (POLLERR | POLLHUP))
975 if (!(c->poll_entry->revents & POLLIN))
977 if (http_receive_data(c) < 0)
980 case HTTPSTATE_WAIT_FEED:
981 /* no need to read if no events */
982 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
985 /* nothing to do, we'll be waken up by incoming feed packets */
988 case RTSPSTATE_SEND_REPLY:
989 if (c->poll_entry->revents & (POLLERR | POLLHUP))
990 goto close_connection;
991 /* no need to write if no events */
992 if (!(c->poll_entry->revents & POLLOUT))
994 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
996 if (ff_neterrno() != AVERROR(EAGAIN) &&
997 ff_neterrno() != AVERROR(EINTR)) {
998 goto close_connection;
1002 c->buffer_ptr += len;
1003 c->data_count += len;
1004 if (c->buffer_ptr >= c->buffer_end) {
1005 /* all the buffer was sent : wait for a new request */
1006 av_freep(&c->pb_buffer);
1007 start_wait_request(c, 1);
1010 case RTSPSTATE_SEND_PACKET:
1011 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1012 av_freep(&c->packet_buffer);
1015 /* no need to write if no events */
1016 if (!(c->poll_entry->revents & POLLOUT))
1018 len = send(c->fd, c->packet_buffer_ptr,
1019 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1021 if (ff_neterrno() != AVERROR(EAGAIN) &&
1022 ff_neterrno() != AVERROR(EINTR)) {
1023 /* error : close connection */
1024 av_freep(&c->packet_buffer);
1029 c->packet_buffer_ptr += len;
1030 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1031 /* all the buffer was sent : wait for a new request */
1032 av_freep(&c->packet_buffer);
1033 c->state = RTSPSTATE_WAIT_REQUEST;
1036 case HTTPSTATE_READY:
1045 av_freep(&c->pb_buffer);
1049 static int extract_rates(char *rates, int ratelen, const char *request)
1053 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1054 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1055 const char *q = p + 7;
1057 while (*q && *q != '\n' && av_isspace(*q))
1060 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1066 memset(rates, 0xff, ratelen);
1069 while (*q && *q != '\n' && *q != ':')
1072 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1076 if (stream_no < ratelen && stream_no >= 0)
1077 rates[stream_no] = rate_no;
1079 while (*q && *q != '\n' && !av_isspace(*q))
1086 p = strchr(p, '\n');
1096 static int find_stream_in_feed(FFServerStream *feed, AVCodecContext *codec,
1100 int best_bitrate = 100000000;
1103 for (i = 0; i < feed->nb_streams; i++) {
1104 AVCodecContext *feed_codec = feed->streams[i]->codec;
1106 if (feed_codec->codec_id != codec->codec_id ||
1107 feed_codec->sample_rate != codec->sample_rate ||
1108 feed_codec->width != codec->width ||
1109 feed_codec->height != codec->height)
1112 /* Potential stream */
1114 /* We want the fastest stream less than bit_rate, or the slowest
1115 * faster than bit_rate
1118 if (feed_codec->bit_rate <= bit_rate) {
1119 if (best_bitrate > bit_rate ||
1120 feed_codec->bit_rate > best_bitrate) {
1121 best_bitrate = feed_codec->bit_rate;
1126 if (feed_codec->bit_rate < best_bitrate) {
1127 best_bitrate = feed_codec->bit_rate;
1134 static int modify_current_stream(HTTPContext *c, char *rates)
1137 FFServerStream *req = c->stream;
1138 int action_required = 0;
1140 /* Not much we can do for a feed */
1144 for (i = 0; i < req->nb_streams; i++) {
1145 AVCodecContext *codec = req->streams[i]->codec;
1149 c->switch_feed_streams[i] = req->feed_streams[i];
1152 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1155 /* Wants off or slow */
1156 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1158 /* This doesn't work well when it turns off the only stream! */
1159 c->switch_feed_streams[i] = -2;
1160 c->feed_streams[i] = -2;
1165 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1166 action_required = 1;
1169 return action_required;
1172 static void get_word(char *buf, int buf_size, const char **pp)
1178 p += strspn(p, SPACE_CHARS);
1180 while (!av_isspace(*p) && *p != '\0') {
1181 if ((q - buf) < buf_size - 1)
1190 static FFServerIPAddressACL* parse_dynamic_acl(FFServerStream *stream,
1196 FFServerIPAddressACL *acl = NULL;
1200 f = fopen(stream->dynamic_acl, "r");
1202 perror(stream->dynamic_acl);
1206 acl = av_mallocz(sizeof(FFServerIPAddressACL));
1209 while (fgets(line, sizeof(line), f)) {
1212 while (av_isspace(*p))
1214 if (*p == '\0' || *p == '#')
1216 ffserver_get_arg(cmd, sizeof(cmd), &p);
1218 if (!av_strcasecmp(cmd, "ACL"))
1219 ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl,
1227 static void free_acl_list(FFServerIPAddressACL *in_acl)
1229 FFServerIPAddressACL *pacl, *pacl2;
1239 static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c)
1241 enum FFServerIPAddressAction last_action = IP_DENY;
1242 FFServerIPAddressACL *acl;
1243 struct in_addr *src = &c->from_addr.sin_addr;
1244 unsigned long src_addr = src->s_addr;
1246 for (acl = in_acl; acl; acl = acl->next) {
1247 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1248 return (acl->action == IP_ALLOW) ? 1 : 0;
1249 last_action = acl->action;
1252 /* Nothing matched, so return not the last action */
1253 return (last_action == IP_DENY) ? 1 : 0;
1256 static int validate_acl(FFServerStream *stream, HTTPContext *c)
1259 FFServerIPAddressACL *acl;
1261 /* if stream->acl is null validate_acl_list will return 1 */
1262 ret = validate_acl_list(stream->acl, c);
1264 if (stream->dynamic_acl[0]) {
1265 acl = parse_dynamic_acl(stream, c);
1267 ret = validate_acl_list(acl, c);
1275 /* compute the real filename of a file by matching it without its
1276 extensions to all the stream's filenames */
1277 static void compute_real_filename(char *filename, int max_size)
1282 FFServerStream *stream;
1284 /* compute filename by matching without the file extensions */
1285 av_strlcpy(file1, filename, sizeof(file1));
1286 p = strrchr(file1, '.');
1289 for(stream = config.first_stream; stream; stream = stream->next) {
1290 av_strlcpy(file2, stream->filename, sizeof(file2));
1291 p = strrchr(file2, '.');
1294 if (!strcmp(file1, file2)) {
1295 av_strlcpy(filename, stream->filename, max_size);
1310 /* parse HTTP request and prepare header */
1311 static int http_parse_request(HTTPContext *c)
1315 enum RedirType redir_type;
1317 char info[1024], filename[1024];
1321 const char *mime_type;
1322 FFServerStream *stream;
1325 const char *useragent = 0;
1328 get_word(cmd, sizeof(cmd), &p);
1329 av_strlcpy(c->method, cmd, sizeof(c->method));
1331 if (!strcmp(cmd, "GET"))
1333 else if (!strcmp(cmd, "POST"))
1338 get_word(url, sizeof(url), &p);
1339 av_strlcpy(c->url, url, sizeof(c->url));
1341 get_word(protocol, sizeof(protocol), (const char **)&p);
1342 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1345 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1348 http_log("%s - - New connection: %s %s\n",
1349 inet_ntoa(c->from_addr.sin_addr), cmd, url);
1351 /* find the filename and the optional info string in the request */
1352 p1 = strchr(url, '?');
1354 av_strlcpy(info, p1, sizeof(info));
1359 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1361 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1362 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1364 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1368 p = strchr(p, '\n');
1375 redir_type = REDIR_NONE;
1376 if (av_match_ext(filename, "asx")) {
1377 redir_type = REDIR_ASX;
1378 filename[strlen(filename)-1] = 'f';
1379 } else if (av_match_ext(filename, "asf") &&
1380 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) {
1381 /* if this isn't WMP or lookalike, return the redirector file */
1382 redir_type = REDIR_ASF;
1383 } else if (av_match_ext(filename, "rpm,ram")) {
1384 redir_type = REDIR_RAM;
1385 strcpy(filename + strlen(filename)-2, "m");
1386 } else if (av_match_ext(filename, "rtsp")) {
1387 redir_type = REDIR_RTSP;
1388 compute_real_filename(filename, sizeof(filename) - 1);
1389 } else if (av_match_ext(filename, "sdp")) {
1390 redir_type = REDIR_SDP;
1391 compute_real_filename(filename, sizeof(filename) - 1);
1394 // "redirect" / request to index.html
1395 if (!strlen(filename))
1396 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1398 stream = config.first_stream;
1400 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1402 stream = stream->next;
1405 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1406 http_log("File '%s' not found\n", url);
1411 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1412 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1414 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1415 c->http_error = 301;
1417 snprintf(q, c->buffer_size,
1418 "HTTP/1.0 301 Moved\r\n"
1420 "Content-type: text/html\r\n"
1422 "<html><head><title>Moved</title></head><body>\r\n"
1423 "You should be <a href=\"%s\">redirected</a>.\r\n"
1424 "</body></html>\r\n",
1425 stream->feed_filename, stream->feed_filename);
1427 /* prepare output buffer */
1428 c->buffer_ptr = c->buffer;
1430 c->state = HTTPSTATE_SEND_HEADER;
1434 /* If this is WMP, get the rate information */
1435 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1436 if (modify_current_stream(c, ratebuf)) {
1437 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1438 if (c->switch_feed_streams[i] >= 0)
1439 c->switch_feed_streams[i] = -1;
1444 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1445 current_bandwidth += stream->bandwidth;
1447 /* If already streaming this feed, do not let start another feeder. */
1448 if (stream->feed_opened) {
1449 snprintf(msg, sizeof(msg), "This feed is already being received.");
1450 http_log("Feed '%s' already being received\n", stream->feed_filename);
1454 if (c->post == 0 && config.max_bandwidth < current_bandwidth) {
1455 c->http_error = 503;
1457 snprintf(q, c->buffer_size,
1458 "HTTP/1.0 503 Server too busy\r\n"
1459 "Content-type: text/html\r\n"
1461 "<html><head><title>Too busy</title></head><body>\r\n"
1462 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1463 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1464 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1465 "</body></html>\r\n",
1466 current_bandwidth, config.max_bandwidth);
1468 /* prepare output buffer */
1469 c->buffer_ptr = c->buffer;
1471 c->state = HTTPSTATE_SEND_HEADER;
1475 if (redir_type != REDIR_NONE) {
1476 const char *hostinfo = 0;
1478 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1479 if (av_strncasecmp(p, "Host:", 5) == 0) {
1483 p = strchr(p, '\n');
1494 while (av_isspace(*hostinfo))
1497 eoh = strchr(hostinfo, '\n');
1499 if (eoh[-1] == '\r')
1502 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1503 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1504 hostbuf[eoh - hostinfo] = 0;
1506 c->http_error = 200;
1508 switch(redir_type) {
1510 snprintf(q, c->buffer_size,
1511 "HTTP/1.0 200 ASX Follows\r\n"
1512 "Content-type: video/x-ms-asf\r\n"
1514 "<ASX Version=\"3\">\r\n"
1515 //"<!-- Autogenerated by ffserver -->\r\n"
1516 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1517 "</ASX>\r\n", hostbuf, filename, info);
1521 snprintf(q, c->buffer_size,
1522 "HTTP/1.0 200 RAM Follows\r\n"
1523 "Content-type: audio/x-pn-realaudio\r\n"
1525 "# Autogenerated by ffserver\r\n"
1526 "http://%s/%s%s\r\n", hostbuf, filename, info);
1530 snprintf(q, c->buffer_size,
1531 "HTTP/1.0 200 ASF Redirect follows\r\n"
1532 "Content-type: video/x-ms-asf\r\n"
1535 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1540 char hostname[256], *p;
1541 /* extract only hostname */
1542 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1543 p = strrchr(hostname, ':');
1546 snprintf(q, c->buffer_size,
1547 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1548 /* XXX: incorrect MIME type ? */
1549 "Content-type: application/x-rtsp\r\n"
1551 "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
1560 struct sockaddr_in my_addr;
1562 snprintf(q, c->buffer_size,
1563 "HTTP/1.0 200 OK\r\n"
1564 "Content-type: application/sdp\r\n"
1568 len = sizeof(my_addr);
1570 /* XXX: Should probably fail? */
1571 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1572 http_log("getsockname() failed\n");
1574 /* XXX: should use a dynamic buffer */
1575 sdp_data_size = prepare_sdp_description(stream,
1578 if (sdp_data_size > 0) {
1579 memcpy(q, sdp_data, sdp_data_size);
1591 /* prepare output buffer */
1592 c->buffer_ptr = c->buffer;
1594 c->state = HTTPSTATE_SEND_HEADER;
1600 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1604 stream->conns_served++;
1606 /* XXX: add there authenticate and IP match */
1609 /* if post, it means a feed is being sent */
1610 if (!stream->is_feed) {
1611 /* However it might be a status report from WMP! Let us log the
1612 * data as it might come handy one day. */
1613 const char *logline = 0;
1616 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1617 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1621 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1622 client_id = strtol(p + 18, 0, 10);
1623 p = strchr(p, '\n');
1631 char *eol = strchr(logline, '\n');
1636 if (eol[-1] == '\r')
1638 http_log("%.*s\n", (int) (eol - logline), logline);
1639 c->suppress_log = 1;
1644 http_log("\nGot request:\n%s\n", c->buffer);
1647 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1650 /* Now we have to find the client_id */
1651 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1652 if (wmpc->wmp_client_id == client_id)
1656 if (wmpc && modify_current_stream(wmpc, ratebuf))
1657 wmpc->switch_pending = 1;
1660 snprintf(msg, sizeof(msg), "POST command not handled");
1664 if (http_start_receive_data(c) < 0) {
1665 snprintf(msg, sizeof(msg), "could not open feed");
1669 c->state = HTTPSTATE_RECEIVE_DATA;
1674 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1675 http_log("\nGot request:\n%s\n", c->buffer);
1678 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1681 /* open input stream */
1682 if (open_input_stream(c, info) < 0) {
1683 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1687 /* prepare HTTP header */
1689 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1690 mime_type = c->stream->fmt->mime_type;
1692 mime_type = "application/x-octet-stream";
1693 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1695 /* for asf, we need extra headers */
1696 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1697 /* Need to allocate a client id */
1699 c->wmp_client_id = av_lfg_get(&random_state);
1701 av_strlcatf(c->buffer, c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
1703 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1704 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1705 q = c->buffer + strlen(c->buffer);
1707 /* prepare output buffer */
1709 c->buffer_ptr = c->buffer;
1711 c->state = HTTPSTATE_SEND_HEADER;
1714 c->http_error = 404;
1717 snprintf(q, c->buffer_size,
1718 "HTTP/1.0 404 Not Found\r\n"
1719 "Content-type: text/html\r\n"
1722 "<head><title>404 Not Found</title></head>\n"
1726 /* prepare output buffer */
1727 c->buffer_ptr = c->buffer;
1729 c->state = HTTPSTATE_SEND_HEADER;
1733 c->http_error = 200; /* horrible : we use this value to avoid
1734 going to the send data state */
1735 c->state = HTTPSTATE_SEND_HEADER;
1739 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1741 static const char suffix[] = " kMGTP";
1744 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1746 avio_printf(pb, "%"PRId64"%c", count, *s);
1749 static void compute_status(HTTPContext *c)
1752 FFServerStream *stream;
1758 if (avio_open_dyn_buf(&pb) < 0) {
1759 /* XXX: return an error ? */
1760 c->buffer_ptr = c->buffer;
1761 c->buffer_end = c->buffer;
1765 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1766 avio_printf(pb, "Content-type: text/html\r\n");
1767 avio_printf(pb, "Pragma: no-cache\r\n");
1768 avio_printf(pb, "\r\n");
1770 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1771 if (c->stream->feed_filename[0])
1772 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n",
1773 c->stream->feed_filename);
1774 avio_printf(pb, "</head>\n<body>");
1775 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1777 avio_printf(pb, "<h2>Available Streams</h2>\n");
1778 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1779 avio_printf(pb, "<tr><th valign=top>Path<th align=left>Served<br>Conns<th><br>bytes<th valign=top>Format<th>Bit rate<br>kbits/s<th align=left>Video<br>kbits/s<th><br>Codec<th align=left>Audio<br>kbits/s<th><br>Codec<th align=left valign=top>Feed\n");
1780 stream = config.first_stream;
1782 char sfilename[1024];
1785 if (stream->feed == stream) {
1786 stream = stream->next;
1790 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1791 eosf = sfilename + strlen(sfilename);
1792 if (eosf - sfilename >= 4) {
1793 if (strcmp(eosf - 4, ".asf") == 0)
1794 strcpy(eosf - 4, ".asx");
1795 else if (strcmp(eosf - 3, ".rm") == 0)
1796 strcpy(eosf - 3, ".ram");
1797 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1798 /* generate a sample RTSP director if
1799 unicast. Generate an SDP redirector if
1801 eosf = strrchr(sfilename, '.');
1803 eosf = sfilename + strlen(sfilename);
1804 if (stream->is_multicast)
1805 strcpy(eosf, ".sdp");
1807 strcpy(eosf, ".rtsp");
1811 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1812 sfilename, stream->filename);
1813 avio_printf(pb, "<td align=right> %d <td align=right> ",
1814 stream->conns_served);
1815 fmt_bytecount(pb, stream->bytes_served);
1817 switch(stream->stream_type) {
1818 case STREAM_TYPE_LIVE: {
1819 int audio_bit_rate = 0;
1820 int video_bit_rate = 0;
1821 const char *audio_codec_name = "";
1822 const char *video_codec_name = "";
1823 const char *audio_codec_name_extra = "";
1824 const char *video_codec_name_extra = "";
1826 for(i=0;i<stream->nb_streams;i++) {
1827 AVStream *st = stream->streams[i];
1828 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1830 switch(st->codec->codec_type) {
1831 case AVMEDIA_TYPE_AUDIO:
1832 audio_bit_rate += st->codec->bit_rate;
1834 if (*audio_codec_name)
1835 audio_codec_name_extra = "...";
1836 audio_codec_name = codec->name;
1839 case AVMEDIA_TYPE_VIDEO:
1840 video_bit_rate += st->codec->bit_rate;
1842 if (*video_codec_name)
1843 video_codec_name_extra = "...";
1844 video_codec_name = codec->name;
1847 case AVMEDIA_TYPE_DATA:
1848 video_bit_rate += st->codec->bit_rate;
1855 avio_printf(pb, "<td align=center> %s <td align=right> %d "
1856 "<td align=right> %d <td> %s %s <td align=right> "
1858 stream->fmt->name, stream->bandwidth,
1859 video_bit_rate / 1000, video_codec_name,
1860 video_codec_name_extra, audio_bit_rate / 1000,
1861 audio_codec_name, audio_codec_name_extra);
1864 avio_printf(pb, "<td>%s", stream->feed->filename);
1866 avio_printf(pb, "<td>%s", stream->feed_filename);
1867 avio_printf(pb, "\n");
1871 avio_printf(pb, "<td align=center> - <td align=right> - "
1872 "<td align=right> - <td><td align=right> - <td>\n");
1875 stream = stream->next;
1877 avio_printf(pb, "</table>\n");
1879 stream = config.first_stream;
1882 if (stream->feed != stream) {
1883 stream = stream->next;
1887 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1889 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1896 /* This is somewhat linux specific I guess */
1897 snprintf(ps_cmd, sizeof(ps_cmd),
1898 "ps -o \"%%cpu,cputime\" --no-headers %d",
1901 pid_stat = popen(ps_cmd, "r");
1906 if (fscanf(pid_stat, "%9s %63s", cpuperc, cpuused) == 2) {
1907 avio_printf(pb, "Currently using %s%% of the cpu. "
1908 "Total time used %s.\n",
1916 avio_printf(pb, "<p>");
1919 avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>"
1920 "type<th>kbits/s<th align=left>codec<th align=left>"
1923 for (i = 0; i < stream->nb_streams; i++) {
1924 AVStream *st = stream->streams[i];
1925 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1926 const char *type = "unknown";
1927 char parameters[64];
1931 switch(st->codec->codec_type) {
1932 case AVMEDIA_TYPE_AUDIO:
1934 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz",
1935 st->codec->channels, st->codec->sample_rate);
1937 case AVMEDIA_TYPE_VIDEO:
1939 snprintf(parameters, sizeof(parameters),
1940 "%dx%d, q=%d-%d, fps=%d", st->codec->width,
1941 st->codec->height, st->codec->qmin, st->codec->qmax,
1942 st->codec->time_base.den / st->codec->time_base.num);
1948 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d"
1950 i, type, st->codec->bit_rate/1000,
1951 codec ? codec->name : "", parameters);
1954 avio_printf(pb, "</table>\n");
1955 stream = stream->next;
1958 /* connection status */
1959 avio_printf(pb, "<h2>Connection Status</h2>\n");
1961 avio_printf(pb, "Number of connections: %d / %d<br>\n",
1962 nb_connections, config.nb_max_connections);
1964 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1965 current_bandwidth, config.max_bandwidth);
1967 avio_printf(pb, "<table>\n");
1968 avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target "
1969 "bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1970 c1 = first_http_ctx;
1978 for (j = 0; j < c1->stream->nb_streams; j++) {
1979 if (!c1->stream->feed)
1980 bitrate += c1->stream->streams[j]->codec->bit_rate;
1981 else if (c1->feed_streams[j] >= 0)
1982 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1987 p = inet_ntoa(c1->from_addr.sin_addr);
1988 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s"
1990 i, c1->stream ? c1->stream->filename : "",
1991 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", p,
1992 c1->protocol, http_state[c1->state]);
1993 fmt_bytecount(pb, bitrate);
1994 avio_printf(pb, "<td align=right>");
1995 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1996 avio_printf(pb, "<td align=right>");
1997 fmt_bytecount(pb, c1->data_count);
1998 avio_printf(pb, "\n");
2001 avio_printf(pb, "</table>\n");
2006 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2007 avio_printf(pb, "</body>\n</html>\n");
2009 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2010 c->buffer_ptr = c->pb_buffer;
2011 c->buffer_end = c->pb_buffer + len;
2014 static int open_input_stream(HTTPContext *c, const char *info)
2017 char input_filename[1024];
2018 AVFormatContext *s = NULL;
2019 int buf_size, i, ret;
2022 /* find file name */
2023 if (c->stream->feed) {
2024 strcpy(input_filename, c->stream->feed->feed_filename);
2025 buf_size = FFM_PACKET_SIZE;
2026 /* compute position (absolute time) */
2027 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2028 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2029 http_log("Invalid date specification '%s' for stream\n", buf);
2032 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2033 int prebuffer = strtol(buf, 0, 10);
2034 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2036 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2038 strcpy(input_filename, c->stream->feed_filename);
2040 /* compute position (relative time) */
2041 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2042 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2043 http_log("Invalid date specification '%s' for stream\n", buf);
2049 if (!input_filename[0]) {
2050 http_log("No filename was specified for stream\n");
2051 return AVERROR(EINVAL);
2055 ret = avformat_open_input(&s, input_filename, c->stream->ifmt,
2056 &c->stream->in_opts);
2058 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2062 /* set buffer size */
2063 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2065 s->flags |= AVFMT_FLAG_GENPTS;
2067 if (strcmp(s->iformat->name, "ffm") &&
2068 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2069 http_log("Could not find stream info for input '%s'\n", input_filename);
2070 avformat_close_input(&s);
2074 /* choose stream as clock source (we favor the video stream if
2075 * present) for packet sending */
2076 c->pts_stream_index = 0;
2077 for(i=0;i<c->stream->nb_streams;i++) {
2078 if (c->pts_stream_index == 0 &&
2079 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2080 c->pts_stream_index = i;
2084 if (c->fmt_in->iformat->read_seek)
2085 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2086 /* set the start time (needed for maxtime and RTP packet timing) */
2087 c->start_time = cur_time;
2088 c->first_pts = AV_NOPTS_VALUE;
2092 /* return the server clock (in us) */
2093 static int64_t get_server_clock(HTTPContext *c)
2095 /* compute current pts value from system time */
2096 return (cur_time - c->start_time) * 1000;
2099 /* return the estimated time at which the current packet must be sent
2101 static int64_t get_packet_send_clock(HTTPContext *c)
2103 int bytes_left, bytes_sent, frame_bytes;
2105 frame_bytes = c->cur_frame_bytes;
2106 if (frame_bytes <= 0)
2109 bytes_left = c->buffer_end - c->buffer_ptr;
2110 bytes_sent = frame_bytes - bytes_left;
2111 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2116 static int http_prepare_data(HTTPContext *c)
2119 AVFormatContext *ctx;
2121 av_freep(&c->pb_buffer);
2123 case HTTPSTATE_SEND_DATA_HEADER:
2124 ctx = avformat_alloc_context();
2127 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2128 c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams, sizeof(AVStream *));
2130 for(i=0;i<c->stream->nb_streams;i++) {
2132 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2133 /* if file or feed, then just take streams from FFServerStream struct */
2134 if (!c->stream->feed ||
2135 c->stream->feed == c->stream)
2136 src = c->stream->streams[i];
2138 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2140 *(c->fmt_ctx.streams[i]) = *src;
2141 c->fmt_ctx.streams[i]->priv_data = 0;
2142 /* XXX: should be done in AVStream, not in codec */
2143 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2145 /* set output format parameters */
2146 c->fmt_ctx.oformat = c->stream->fmt;
2147 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2149 c->got_key_frame = 0;
2151 /* prepare header and save header data in a stream */
2152 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2153 /* XXX: potential leak */
2156 c->fmt_ctx.pb->seekable = 0;
2159 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2160 * Default value from FFmpeg
2161 * Try to set it using configuration option
2163 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2165 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2166 http_log("Error writing output header for stream '%s': %s\n",
2167 c->stream->filename, av_err2str(ret));
2170 av_dict_free(&c->fmt_ctx.metadata);
2172 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2173 c->buffer_ptr = c->pb_buffer;
2174 c->buffer_end = c->pb_buffer + len;
2176 c->state = HTTPSTATE_SEND_DATA;
2177 c->last_packet_sent = 0;
2179 case HTTPSTATE_SEND_DATA:
2180 /* find a new packet */
2181 /* read a packet from the input stream */
2182 if (c->stream->feed)
2183 ffm_set_write_index(c->fmt_in,
2184 c->stream->feed->feed_write_index,
2185 c->stream->feed->feed_size);
2187 if (c->stream->max_time &&
2188 c->stream->max_time + c->start_time - cur_time < 0)
2189 /* We have timed out */
2190 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2194 ret = av_read_frame(c->fmt_in, &pkt);
2196 if (c->stream->feed) {
2197 /* if coming from feed, it means we reached the end of the
2198 ffm file, so must wait for more data */
2199 c->state = HTTPSTATE_WAIT_FEED;
2200 return 1; /* state changed */
2201 } else if (ret == AVERROR(EAGAIN)) {
2202 /* input not ready, come back later */
2205 if (c->stream->loop) {
2206 avformat_close_input(&c->fmt_in);
2207 if (open_input_stream(c, "") < 0)
2212 /* must send trailer now because EOF or error */
2213 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2217 int source_index = pkt.stream_index;
2218 /* update first pts if needed */
2219 if (c->first_pts == AV_NOPTS_VALUE) {
2220 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2221 c->start_time = cur_time;
2223 /* send it to the appropriate stream */
2224 if (c->stream->feed) {
2225 /* if coming from a feed, select the right stream */
2226 if (c->switch_pending) {
2227 c->switch_pending = 0;
2228 for(i=0;i<c->stream->nb_streams;i++) {
2229 if (c->switch_feed_streams[i] == pkt.stream_index)
2230 if (pkt.flags & AV_PKT_FLAG_KEY)
2231 c->switch_feed_streams[i] = -1;
2232 if (c->switch_feed_streams[i] >= 0)
2233 c->switch_pending = 1;
2236 for(i=0;i<c->stream->nb_streams;i++) {
2237 if (c->stream->feed_streams[i] == pkt.stream_index) {
2238 AVStream *st = c->fmt_in->streams[source_index];
2239 pkt.stream_index = i;
2240 if (pkt.flags & AV_PKT_FLAG_KEY &&
2241 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2242 c->stream->nb_streams == 1))
2243 c->got_key_frame = 1;
2244 if (!c->stream->send_on_key || c->got_key_frame)
2249 AVCodecContext *codec;
2250 AVStream *ist, *ost;
2252 ist = c->fmt_in->streams[source_index];
2253 /* specific handling for RTP: we use several
2254 * output streams (one for each RTP connection).
2255 * XXX: need more abstract handling */
2256 if (c->is_packetized) {
2257 /* compute send time and duration */
2258 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2259 c->cur_pts -= c->first_pts;
2260 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2261 /* find RTP context */
2262 c->packet_stream_index = pkt.stream_index;
2263 ctx = c->rtp_ctx[c->packet_stream_index];
2265 av_free_packet(&pkt);
2268 codec = ctx->streams[0]->codec;
2269 /* only one stream per RTP connection */
2270 pkt.stream_index = 0;
2274 codec = ctx->streams[pkt.stream_index]->codec;
2277 if (c->is_packetized) {
2278 int max_packet_size;
2279 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2280 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2282 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2283 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2285 ret = avio_open_dyn_buf(&ctx->pb);
2288 /* XXX: potential leak */
2291 ost = ctx->streams[pkt.stream_index];
2293 ctx->pb->seekable = 0;
2294 if (pkt.dts != AV_NOPTS_VALUE)
2295 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2296 if (pkt.pts != AV_NOPTS_VALUE)
2297 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2298 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2299 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2300 http_log("Error writing frame to output for stream '%s': %s\n",
2301 c->stream->filename, av_err2str(ret));
2302 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2305 av_freep(&c->pb_buffer);
2306 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2307 c->cur_frame_bytes = len;
2308 c->buffer_ptr = c->pb_buffer;
2309 c->buffer_end = c->pb_buffer + len;
2311 codec->frame_number++;
2313 av_free_packet(&pkt);
2317 av_free_packet(&pkt);
2322 case HTTPSTATE_SEND_DATA_TRAILER:
2323 /* last packet test ? */
2324 if (c->last_packet_sent || c->is_packetized)
2327 /* prepare header */
2328 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2329 /* XXX: potential leak */
2332 c->fmt_ctx.pb->seekable = 0;
2333 av_write_trailer(ctx);
2334 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2335 c->buffer_ptr = c->pb_buffer;
2336 c->buffer_end = c->pb_buffer + len;
2338 c->last_packet_sent = 1;
2344 /* should convert the format at the same time */
2345 /* send data starting at c->buffer_ptr to the output connection
2346 * (either UDP or TCP) */
2347 static int http_send_data(HTTPContext *c)
2352 if (c->buffer_ptr >= c->buffer_end) {
2353 ret = http_prepare_data(c);
2357 /* state change requested */
2360 if (c->is_packetized) {
2361 /* RTP data output */
2362 len = c->buffer_end - c->buffer_ptr;
2364 /* fail safe - should never happen */
2366 c->buffer_ptr = c->buffer_end;
2369 len = (c->buffer_ptr[0] << 24) |
2370 (c->buffer_ptr[1] << 16) |
2371 (c->buffer_ptr[2] << 8) |
2373 if (len > (c->buffer_end - c->buffer_ptr))
2375 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2376 /* nothing to send yet: we can wait */
2380 c->data_count += len;
2381 update_datarate(&c->datarate, c->data_count);
2383 c->stream->bytes_served += len;
2385 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2386 /* RTP packets are sent inside the RTSP TCP connection */
2388 int interleaved_index, size;
2390 HTTPContext *rtsp_c;
2393 /* if no RTSP connection left, error */
2396 /* if already sending something, then wait. */
2397 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2399 if (avio_open_dyn_buf(&pb) < 0)
2401 interleaved_index = c->packet_stream_index * 2;
2402 /* RTCP packets are sent at odd indexes */
2403 if (c->buffer_ptr[1] == 200)
2404 interleaved_index++;
2405 /* write RTSP TCP header */
2407 header[1] = interleaved_index;
2408 header[2] = len >> 8;
2410 avio_write(pb, header, 4);
2411 /* write RTP packet data */
2413 avio_write(pb, c->buffer_ptr, len);
2414 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2415 /* prepare asynchronous TCP sending */
2416 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2417 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2418 c->buffer_ptr += len;
2420 /* send everything we can NOW */
2421 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2422 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2424 rtsp_c->packet_buffer_ptr += len;
2425 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2426 /* if we could not send all the data, we will
2427 send it later, so a new state is needed to
2428 "lock" the RTSP TCP connection */
2429 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2432 /* all data has been sent */
2433 av_freep(&c->packet_buffer);
2435 /* send RTP packet directly in UDP */
2437 ffurl_write(c->rtp_handles[c->packet_stream_index],
2438 c->buffer_ptr, len);
2439 c->buffer_ptr += len;
2440 /* here we continue as we can send several packets per 10 ms slot */
2443 /* TCP data output */
2444 len = send(c->fd, c->buffer_ptr,
2445 c->buffer_end - c->buffer_ptr, 0);
2447 if (ff_neterrno() != AVERROR(EAGAIN) &&
2448 ff_neterrno() != AVERROR(EINTR))
2449 /* error : close connection */
2454 c->buffer_ptr += len;
2456 c->data_count += len;
2457 update_datarate(&c->datarate, c->data_count);
2459 c->stream->bytes_served += len;
2467 static int http_start_receive_data(HTTPContext *c)
2472 if (c->stream->feed_opened) {
2473 http_log("Stream feed '%s' was not opened\n",
2474 c->stream->feed_filename);
2475 return AVERROR(EINVAL);
2478 /* Don't permit writing to this one */
2479 if (c->stream->readonly) {
2480 http_log("Cannot write to read-only file '%s'\n",
2481 c->stream->feed_filename);
2482 return AVERROR(EINVAL);
2486 fd = open(c->stream->feed_filename, O_RDWR);
2488 ret = AVERROR(errno);
2489 http_log("Could not open feed file '%s': %s\n",
2490 c->stream->feed_filename, strerror(errno));
2495 if (c->stream->truncate) {
2496 /* truncate feed file */
2497 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2498 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2499 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2500 ret = AVERROR(errno);
2501 http_log("Error truncating feed file '%s': %s\n",
2502 c->stream->feed_filename, strerror(errno));
2506 ret = ffm_read_write_index(fd);
2508 http_log("Error reading write index from feed file '%s': %s\n",
2509 c->stream->feed_filename, strerror(errno));
2512 c->stream->feed_write_index = ret;
2516 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd),
2518 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2519 lseek(fd, 0, SEEK_SET);
2521 /* init buffer input */
2522 c->buffer_ptr = c->buffer;
2523 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2524 c->stream->feed_opened = 1;
2525 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2529 static int http_receive_data(HTTPContext *c)
2532 int len, loop_run = 0;
2534 while (c->chunked_encoding && !c->chunk_size &&
2535 c->buffer_end > c->buffer_ptr) {
2536 /* read chunk header, if present */
2537 len = recv(c->fd, c->buffer_ptr, 1, 0);
2540 if (ff_neterrno() != AVERROR(EAGAIN) &&
2541 ff_neterrno() != AVERROR(EINTR))
2542 /* error : close connection */
2545 } else if (len == 0) {
2546 /* end of connection : close it */
2548 } else if (c->buffer_ptr - c->buffer >= 2 &&
2549 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2550 c->chunk_size = strtol(c->buffer, 0, 16);
2551 if (c->chunk_size == 0) // end of stream
2553 c->buffer_ptr = c->buffer;
2555 } else if (++loop_run > 10) {
2556 /* no chunk header, abort */
2563 if (c->buffer_end > c->buffer_ptr) {
2564 len = recv(c->fd, c->buffer_ptr,
2565 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2567 if (ff_neterrno() != AVERROR(EAGAIN) &&
2568 ff_neterrno() != AVERROR(EINTR))
2569 /* error : close connection */
2571 } else if (len == 0)
2572 /* end of connection : close it */
2575 c->chunk_size -= len;
2576 c->buffer_ptr += len;
2577 c->data_count += len;
2578 update_datarate(&c->datarate, c->data_count);
2582 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2583 if (c->buffer[0] != 'f' ||
2584 c->buffer[1] != 'm') {
2585 http_log("Feed stream has become desynchronized -- disconnecting\n");
2590 if (c->buffer_ptr >= c->buffer_end) {
2591 FFServerStream *feed = c->stream;
2592 /* a packet has been received : write it in the store, except
2594 if (c->data_count > FFM_PACKET_SIZE) {
2595 /* XXX: use llseek or url_seek
2596 * XXX: Should probably fail? */
2597 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2598 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2600 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2601 http_log("Error writing to feed file: %s\n", strerror(errno));
2605 feed->feed_write_index += FFM_PACKET_SIZE;
2606 /* update file size */
2607 if (feed->feed_write_index > c->stream->feed_size)
2608 feed->feed_size = feed->feed_write_index;
2610 /* handle wrap around if max file size reached */
2611 if (c->stream->feed_max_size &&
2612 feed->feed_write_index >= c->stream->feed_max_size)
2613 feed->feed_write_index = FFM_PACKET_SIZE;
2616 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2617 http_log("Error writing index to feed file: %s\n",
2622 /* wake up any waiting connections */
2623 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2624 if (c1->state == HTTPSTATE_WAIT_FEED &&
2625 c1->stream->feed == c->stream->feed)
2626 c1->state = HTTPSTATE_SEND_DATA;
2629 /* We have a header in our hands that contains useful data */
2630 AVFormatContext *s = avformat_alloc_context();
2632 AVInputFormat *fmt_in;
2638 /* use feed output format name to find corresponding input format */
2639 fmt_in = av_find_input_format(feed->fmt->name);
2643 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2644 0, NULL, NULL, NULL, NULL);
2648 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2653 /* Now we have the actual streams */
2654 if (s->nb_streams != feed->nb_streams) {
2655 avformat_close_input(&s);
2657 http_log("Feed '%s' stream number does not match registered feed\n",
2658 c->stream->feed_filename);
2662 for (i = 0; i < s->nb_streams; i++) {
2663 AVStream *fst = feed->streams[i];
2664 AVStream *st = s->streams[i];
2665 avcodec_copy_context(fst->codec, st->codec);
2668 avformat_close_input(&s);
2671 c->buffer_ptr = c->buffer;
2676 c->stream->feed_opened = 0;
2678 /* wake up any waiting connections to stop waiting for feed */
2679 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2680 if (c1->state == HTTPSTATE_WAIT_FEED &&
2681 c1->stream->feed == c->stream->feed)
2682 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2687 /********************************************************************/
2690 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2697 str = RTSP_STATUS_CODE2STRING(error_number);
2699 str = "Unknown Error";
2701 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2702 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2704 /* output GMT time */
2707 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2708 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2711 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2713 rtsp_reply_header(c, error_number);
2714 avio_printf(c->pb, "\r\n");
2717 static int rtsp_parse_request(HTTPContext *c)
2719 const char *p, *p1, *p2;
2725 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2727 c->buffer_ptr[0] = '\0';
2730 get_word(cmd, sizeof(cmd), &p);
2731 get_word(url, sizeof(url), &p);
2732 get_word(protocol, sizeof(protocol), &p);
2734 av_strlcpy(c->method, cmd, sizeof(c->method));
2735 av_strlcpy(c->url, url, sizeof(c->url));
2736 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2738 if (avio_open_dyn_buf(&c->pb) < 0) {
2739 /* XXX: cannot do more */
2740 c->pb = NULL; /* safety */
2744 /* check version name */
2745 if (strcmp(protocol, "RTSP/1.0")) {
2746 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2750 /* parse each header line */
2751 /* skip to next line */
2752 while (*p != '\n' && *p != '\0')
2756 while (*p != '\0') {
2757 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2761 if (p2 > p && p2[-1] == '\r')
2763 /* skip empty line */
2767 if (len > sizeof(line) - 1)
2768 len = sizeof(line) - 1;
2769 memcpy(line, p, len);
2771 ff_rtsp_parse_line(header, line, NULL, NULL);
2775 /* handle sequence number */
2776 c->seq = header->seq;
2778 if (!strcmp(cmd, "DESCRIBE"))
2779 rtsp_cmd_describe(c, url);
2780 else if (!strcmp(cmd, "OPTIONS"))
2781 rtsp_cmd_options(c, url);
2782 else if (!strcmp(cmd, "SETUP"))
2783 rtsp_cmd_setup(c, url, header);
2784 else if (!strcmp(cmd, "PLAY"))
2785 rtsp_cmd_play(c, url, header);
2786 else if (!strcmp(cmd, "PAUSE"))
2787 rtsp_cmd_interrupt(c, url, header, 1);
2788 else if (!strcmp(cmd, "TEARDOWN"))
2789 rtsp_cmd_interrupt(c, url, header, 0);
2791 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2794 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2795 c->pb = NULL; /* safety */
2797 /* XXX: cannot do more */
2800 c->buffer_ptr = c->pb_buffer;
2801 c->buffer_end = c->pb_buffer + len;
2802 c->state = RTSPSTATE_SEND_REPLY;
2806 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2807 struct in_addr my_ip)
2809 AVFormatContext *avc;
2810 AVStream *avs = NULL;
2811 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2812 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2817 avc = avformat_alloc_context();
2818 if (!avc || !rtp_format) {
2821 avc->oformat = rtp_format;
2822 av_dict_set(&avc->metadata, "title",
2823 entry ? entry->value : "No Title", 0);
2824 avc->nb_streams = stream->nb_streams;
2825 if (stream->is_multicast) {
2826 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2827 inet_ntoa(stream->multicast_ip),
2828 stream->multicast_port, stream->multicast_ttl);
2830 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2833 if (!(avc->streams = av_malloc_array(avc->nb_streams, sizeof(*avc->streams))))
2835 if (!(avs = av_malloc_array(avc->nb_streams, sizeof(*avs))))
2838 for(i = 0; i < stream->nb_streams; i++) {
2839 avc->streams[i] = &avs[i];
2840 avc->streams[i]->codec = stream->streams[i]->codec;
2842 *pbuffer = av_mallocz(2048);
2843 av_sdp_create(&avc, 1, *pbuffer, 2048);
2846 av_freep(&avc->streams);
2847 av_dict_free(&avc->metadata);
2851 return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2854 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2856 // rtsp_reply_header(c, RTSP_STATUS_OK);
2857 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2858 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2859 avio_printf(c->pb, "Public: %s\r\n",
2860 "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2861 avio_printf(c->pb, "\r\n");
2864 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2866 FFServerStream *stream;
2872 struct sockaddr_in my_addr;
2874 /* find which URL is asked */
2875 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2880 for(stream = config.first_stream; stream; stream = stream->next) {
2881 if (!stream->is_feed &&
2882 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2883 !strcmp(path, stream->filename)) {
2887 /* no stream found */
2888 rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
2892 /* prepare the media description in SDP format */
2894 /* get the host IP */
2895 len = sizeof(my_addr);
2896 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2897 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2898 if (content_length < 0) {
2899 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2902 rtsp_reply_header(c, RTSP_STATUS_OK);
2903 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2904 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2905 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2906 avio_printf(c->pb, "\r\n");
2907 avio_write(c->pb, content, content_length);
2911 static HTTPContext *find_rtp_session(const char *session_id)
2915 if (session_id[0] == '\0')
2918 for(c = first_http_ctx; c; c = c->next) {
2919 if (!strcmp(c->session_id, session_id))
2925 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2927 RTSPTransportField *th;
2930 for(i=0;i<h->nb_transports;i++) {
2931 th = &h->transports[i];
2932 if (th->lower_transport == lower_transport)
2938 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2939 RTSPMessageHeader *h)
2941 FFServerStream *stream;
2942 int stream_index, rtp_port, rtcp_port;
2947 RTSPTransportField *th;
2948 struct sockaddr_in dest_addr;
2949 RTSPActionServerSetup setup;
2951 /* find which URL is asked */
2952 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2957 /* now check each stream */
2958 for(stream = config.first_stream; stream; stream = stream->next) {
2959 if (stream->is_feed || !stream->fmt ||
2960 strcmp(stream->fmt->name, "rtp")) {
2963 /* accept aggregate filenames only if single stream */
2964 if (!strcmp(path, stream->filename)) {
2965 if (stream->nb_streams != 1) {
2966 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2973 for(stream_index = 0; stream_index < stream->nb_streams;
2975 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2976 stream->filename, stream_index);
2977 if (!strcmp(path, buf))
2981 /* no stream found */
2982 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2986 /* generate session id if needed */
2987 if (h->session_id[0] == '\0') {
2988 unsigned random0 = av_lfg_get(&random_state);
2989 unsigned random1 = av_lfg_get(&random_state);
2990 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2994 /* find RTP session, and create it if none found */
2995 rtp_c = find_rtp_session(h->session_id);
2997 /* always prefer UDP */
2998 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3000 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3002 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3007 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3008 th->lower_transport);
3010 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3014 /* open input stream */
3015 if (open_input_stream(rtp_c, "") < 0) {
3016 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3021 /* test if stream is OK (test needed because several SETUP needs
3022 to be done for a given file) */
3023 if (rtp_c->stream != stream) {
3024 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3028 /* test if stream is already set up */
3029 if (rtp_c->rtp_ctx[stream_index]) {
3030 rtsp_reply_error(c, RTSP_STATUS_STATE);
3034 /* check transport */
3035 th = find_transport(h, rtp_c->rtp_protocol);
3036 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3037 th->client_port_min <= 0)) {
3038 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3042 /* setup default options */
3043 setup.transport_option[0] = '\0';
3044 dest_addr = rtp_c->from_addr;
3045 dest_addr.sin_port = htons(th->client_port_min);
3048 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3049 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3053 /* now everything is OK, so we can send the connection parameters */
3054 rtsp_reply_header(c, RTSP_STATUS_OK);
3056 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3058 switch(rtp_c->rtp_protocol) {
3059 case RTSP_LOWER_TRANSPORT_UDP:
3060 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3061 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3062 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3063 "client_port=%d-%d;server_port=%d-%d",
3064 th->client_port_min, th->client_port_max,
3065 rtp_port, rtcp_port);
3067 case RTSP_LOWER_TRANSPORT_TCP:
3068 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3069 stream_index * 2, stream_index * 2 + 1);
3074 if (setup.transport_option[0] != '\0')
3075 avio_printf(c->pb, ";%s", setup.transport_option);
3076 avio_printf(c->pb, "\r\n");
3079 avio_printf(c->pb, "\r\n");
3083 /* find an RTP connection by using the session ID. Check consistency
3085 static HTTPContext *find_rtp_session_with_url(const char *url,
3086 const char *session_id)
3094 rtp_c = find_rtp_session(session_id);
3098 /* find which URL is asked */
3099 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3103 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3104 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3105 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3106 rtp_c->stream->filename, s);
3107 if(!strncmp(path, buf, sizeof(buf))) {
3108 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3113 if (len > 0 && path[len - 1] == '/' &&
3114 !strncmp(path, rtp_c->stream->filename, len - 1))
3119 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3123 rtp_c = find_rtp_session_with_url(url, h->session_id);
3125 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3129 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3130 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3131 rtp_c->state != HTTPSTATE_READY) {
3132 rtsp_reply_error(c, RTSP_STATUS_STATE);
3136 rtp_c->state = HTTPSTATE_SEND_DATA;
3138 /* now everything is OK, so we can send the connection parameters */
3139 rtsp_reply_header(c, RTSP_STATUS_OK);
3141 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3142 avio_printf(c->pb, "\r\n");
3145 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
3146 RTSPMessageHeader *h, int pause_only)
3150 rtp_c = find_rtp_session_with_url(url, h->session_id);
3152 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3157 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3158 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3159 rtsp_reply_error(c, RTSP_STATUS_STATE);
3162 rtp_c->state = HTTPSTATE_READY;
3163 rtp_c->first_pts = AV_NOPTS_VALUE;
3166 /* now everything is OK, so we can send the connection parameters */
3167 rtsp_reply_header(c, RTSP_STATUS_OK);
3169 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3170 avio_printf(c->pb, "\r\n");
3173 close_connection(rtp_c);
3176 /********************************************************************/
3179 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3180 FFServerStream *stream,
3181 const char *session_id,
3182 enum RTSPLowerTransport rtp_protocol)
3184 HTTPContext *c = NULL;
3185 const char *proto_str;
3187 /* XXX: should output a warning page when coming
3188 close to the connection limit */
3189 if (nb_connections >= config.nb_max_connections)
3192 /* add a new connection */
3193 c = av_mallocz(sizeof(HTTPContext));
3198 c->poll_entry = NULL;
3199 c->from_addr = *from_addr;
3200 c->buffer_size = IOBUFFER_INIT_SIZE;
3201 c->buffer = av_malloc(c->buffer_size);
3206 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3207 c->state = HTTPSTATE_READY;
3208 c->is_packetized = 1;
3209 c->rtp_protocol = rtp_protocol;
3211 /* protocol is shown in statistics */
3212 switch(c->rtp_protocol) {
3213 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3214 proto_str = "MCAST";
3216 case RTSP_LOWER_TRANSPORT_UDP:
3219 case RTSP_LOWER_TRANSPORT_TCP:
3226 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3227 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3229 current_bandwidth += stream->bandwidth;
3231 c->next = first_http_ctx;
3237 av_freep(&c->buffer);
3243 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3244 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3246 static int rtp_new_av_stream(HTTPContext *c,
3247 int stream_index, struct sockaddr_in *dest_addr,
3248 HTTPContext *rtsp_c)
3250 AVFormatContext *ctx;
3253 URLContext *h = NULL;
3255 int max_packet_size;
3257 /* now we can open the relevant output stream */
3258 ctx = avformat_alloc_context();
3261 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3263 st = av_mallocz(sizeof(AVStream));
3266 ctx->nb_streams = 1;
3267 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3270 ctx->streams[0] = st;
3272 if (!c->stream->feed ||
3273 c->stream->feed == c->stream)
3274 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3277 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3279 st->priv_data = NULL;
3281 /* build destination RTP address */
3282 ipaddr = inet_ntoa(dest_addr->sin_addr);
3284 switch(c->rtp_protocol) {
3285 case RTSP_LOWER_TRANSPORT_UDP:
3286 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3289 /* XXX: also pass as parameter to function ? */
3290 if (c->stream->is_multicast) {
3292 ttl = c->stream->multicast_ttl;
3295 snprintf(ctx->filename, sizeof(ctx->filename),
3296 "rtp://%s:%d?multicast=1&ttl=%d",
3297 ipaddr, ntohs(dest_addr->sin_port), ttl);
3299 snprintf(ctx->filename, sizeof(ctx->filename),
3300 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3303 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3305 c->rtp_handles[stream_index] = h;
3306 max_packet_size = h->max_packet_size;
3308 case RTSP_LOWER_TRANSPORT_TCP:
3311 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3317 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3318 ipaddr, ntohs(dest_addr->sin_port),
3319 c->stream->filename, stream_index, c->protocol);
3321 /* normally, no packets should be output here, but the packet size may
3323 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3324 /* XXX: close stream */
3327 if (avformat_write_header(ctx, NULL) < 0) {
3335 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3338 c->rtp_ctx[stream_index] = ctx;
3342 /********************************************************************/
3343 /* ffserver initialization */
3345 static AVStream *add_av_stream1(FFServerStream *stream,
3346 AVCodecContext *codec, int copy)
3350 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3353 fst = av_mallocz(sizeof(AVStream));
3357 fst->codec = avcodec_alloc_context3(codec->codec);
3358 avcodec_copy_context(fst->codec, codec);
3360 /* live streams must use the actual feed's codec since it may be
3361 * updated later to carry extradata needed by them.
3365 fst->priv_data = av_mallocz(sizeof(FeedData));
3366 fst->index = stream->nb_streams;
3367 avpriv_set_pts_info(fst, 33, 1, 90000);
3368 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3369 stream->streams[stream->nb_streams++] = fst;
3373 /* return the stream number in the feed */
3374 static int add_av_stream(FFServerStream *feed, AVStream *st)
3377 AVCodecContext *av, *av1;
3381 for(i=0;i<feed->nb_streams;i++) {
3382 av1 = feed->streams[i]->codec;
3383 if (av1->codec_id == av->codec_id &&
3384 av1->codec_type == av->codec_type &&
3385 av1->bit_rate == av->bit_rate) {
3387 switch(av->codec_type) {
3388 case AVMEDIA_TYPE_AUDIO:
3389 if (av1->channels == av->channels &&
3390 av1->sample_rate == av->sample_rate)
3393 case AVMEDIA_TYPE_VIDEO:
3394 if (av1->width == av->width &&
3395 av1->height == av->height &&
3396 av1->time_base.den == av->time_base.den &&
3397 av1->time_base.num == av->time_base.num &&
3398 av1->gop_size == av->gop_size)
3407 fst = add_av_stream1(feed, av, 0);
3410 if (av_stream_get_recommended_encoder_configuration(st))
3411 av_stream_set_recommended_encoder_configuration(fst,
3412 av_strdup(av_stream_get_recommended_encoder_configuration(st)));
3413 return feed->nb_streams - 1;
3416 static void remove_stream(FFServerStream *stream)
3418 FFServerStream **ps;
3419 ps = &config.first_stream;
3428 /* specific MPEG4 handling : we extract the raw parameters */
3429 static void extract_mpeg4_header(AVFormatContext *infile)
3431 int mpeg4_count, i, size;
3436 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3439 for(i=0;i<infile->nb_streams;i++) {
3440 st = infile->streams[i];
3441 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3442 st->codec->extradata_size == 0) {
3449 printf("MPEG4 without extra data: trying to find header in %s\n",
3451 while (mpeg4_count > 0) {
3452 if (av_read_frame(infile, &pkt) < 0)
3454 st = infile->streams[pkt.stream_index];
3455 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3456 st->codec->extradata_size == 0) {
3457 av_freep(&st->codec->extradata);
3458 /* fill extradata with the header */
3459 /* XXX: we make hard suppositions here ! */
3461 while (p < pkt.data + pkt.size - 4) {
3462 /* stop when vop header is found */
3463 if (p[0] == 0x00 && p[1] == 0x00 &&
3464 p[2] == 0x01 && p[3] == 0xb6) {
3465 size = p - pkt.data;
3466 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3467 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3468 st->codec->extradata_size = size;
3469 memcpy(st->codec->extradata, pkt.data, size);
3476 av_free_packet(&pkt);
3480 /* compute the needed AVStream for each file */
3481 static void build_file_streams(void)
3483 FFServerStream *stream, *stream_next;
3486 /* gather all streams */
3487 for(stream = config.first_stream; stream; stream = stream_next) {
3488 AVFormatContext *infile = NULL;
3489 stream_next = stream->next;
3490 if (stream->stream_type == STREAM_TYPE_LIVE &&
3492 /* the stream comes from a file */
3493 /* try to open the file */
3495 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3496 /* specific case : if transport stream output to RTP,
3497 we use a raw transport stream reader */
3498 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3501 if (!stream->feed_filename[0]) {
3502 http_log("Unspecified feed file for stream '%s'\n",
3507 http_log("Opening feed file '%s' for stream '%s'\n",
3508 stream->feed_filename, stream->filename);
3509 ret = avformat_open_input(&infile, stream->feed_filename,
3510 stream->ifmt, &stream->in_opts);
3512 http_log("Could not open '%s': %s\n", stream->feed_filename,
3514 /* remove stream (no need to spend more time on it) */
3516 remove_stream(stream);
3518 /* find all the AVStreams inside and reference them in
3520 if (avformat_find_stream_info(infile, NULL) < 0) {
3521 http_log("Could not find codec parameters from '%s'\n",
3522 stream->feed_filename);
3523 avformat_close_input(&infile);
3526 extract_mpeg4_header(infile);
3528 for(i=0;i<infile->nb_streams;i++)
3529 add_av_stream1(stream, infile->streams[i]->codec, 1);
3531 avformat_close_input(&infile);
3537 /* compute the needed AVStream for each feed */
3538 static void build_feed_streams(void)
3540 FFServerStream *stream, *feed;
3543 /* gather all streams */
3544 for(stream = config.first_stream; stream; stream = stream->next) {
3545 feed = stream->feed;
3547 if (stream->is_feed) {
3548 for(i=0;i<stream->nb_streams;i++)
3549 stream->feed_streams[i] = i;
3551 /* we handle a stream coming from a feed */
3552 for(i=0;i<stream->nb_streams;i++)
3553 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3558 /* create feed files if needed */
3559 for(feed = config.first_feed; feed; feed = feed->next_feed) {
3562 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3563 /* See if it matches */
3564 AVFormatContext *s = NULL;
3567 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3568 /* set buffer size */
3569 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3570 /* Now see if it matches */
3571 if (s->nb_streams == feed->nb_streams) {
3573 for(i=0;i<s->nb_streams;i++) {
3575 sf = feed->streams[i];
3578 if (sf->index != ss->index ||
3580 http_log("Index & Id do not match for stream %d (%s)\n",
3581 i, feed->feed_filename);
3584 AVCodecContext *ccf, *ccs;
3588 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3590 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3591 http_log("Codecs do not match for stream %d\n", i);
3593 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3594 http_log("Codec bitrates do not match for stream %d\n", i);
3596 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3597 if (CHECK_CODEC(time_base.den) ||
3598 CHECK_CODEC(time_base.num) ||
3599 CHECK_CODEC(width) ||
3600 CHECK_CODEC(height)) {
3601 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3604 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3605 if (CHECK_CODEC(sample_rate) ||
3606 CHECK_CODEC(channels) ||
3607 CHECK_CODEC(frame_size)) {
3608 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3612 http_log("Unknown codec type\n");
3620 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3621 feed->feed_filename, s->nb_streams, feed->nb_streams);
3623 avformat_close_input(&s);
3625 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3626 feed->feed_filename);
3629 if (feed->readonly) {
3630 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3631 feed->feed_filename);
3634 unlink(feed->feed_filename);
3637 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3638 AVFormatContext *s = avformat_alloc_context();
3640 if (feed->readonly) {
3641 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3642 feed->feed_filename);
3646 /* only write the header of the ffm file */
3647 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3648 http_log("Could not open output feed file '%s'\n",
3649 feed->feed_filename);
3652 s->oformat = feed->fmt;
3653 s->nb_streams = feed->nb_streams;
3654 s->streams = feed->streams;
3655 if (avformat_write_header(s, NULL) < 0) {
3656 http_log("Container doesn't support the required parameters\n");
3659 /* XXX: need better API */
3660 av_freep(&s->priv_data);
3661 avio_closep(&s->pb);
3664 avformat_free_context(s);
3666 /* get feed size and write index */
3667 fd = open(feed->feed_filename, O_RDONLY);
3669 http_log("Could not open output feed file '%s'\n",
3670 feed->feed_filename);
3674 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3675 feed->feed_size = lseek(fd, 0, SEEK_END);
3676 /* ensure that we do not wrap before the end of file */
3677 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3678 feed->feed_max_size = feed->feed_size;
3684 /* compute the bandwidth used by each stream */
3685 static void compute_bandwidth(void)
3689 FFServerStream *stream;
3691 for(stream = config.first_stream; stream; stream = stream->next) {
3693 for(i=0;i<stream->nb_streams;i++) {
3694 AVStream *st = stream->streams[i];
3695 switch(st->codec->codec_type) {
3696 case AVMEDIA_TYPE_AUDIO:
3697 case AVMEDIA_TYPE_VIDEO:
3698 bandwidth += st->codec->bit_rate;
3704 stream->bandwidth = (bandwidth + 999) / 1000;
3708 static void handle_child_exit(int sig)
3713 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3714 FFServerStream *feed;
3716 for (feed = config.first_feed; feed; feed = feed->next) {
3717 if (feed->pid == pid) {
3718 int uptime = time(0) - feed->pid_start;
3722 "%s: Pid %d exited with status %d after %d seconds\n",
3723 feed->filename, pid, status, uptime);
3726 /* Turn off any more restarts */
3727 ffserver_free_child_args(&feed->child_argv);
3732 need_to_start_children = 1;
3735 static void opt_debug(void)
3738 snprintf(config.logfilename, sizeof(config.logfilename), "-");
3741 void show_help_default(const char *opt, const char *arg)
3743 printf("usage: ffserver [options]\n"
3744 "Hyper fast multi format Audio/Video streaming server\n");
3746 show_help_options(options, "Main options:", 0, 0, 0);
3749 static const OptionDef options[] = {
3750 #include "cmdutils_common_opts.h"
3751 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3752 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3753 { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3757 int main(int argc, char **argv)
3759 struct sigaction sigact = { { 0 } };
3762 config.filename = av_strdup("/etc/ffserver.conf");
3764 parse_loglevel(argc, argv, options);
3766 avformat_network_init();
3768 show_banner(argc, argv, options);
3770 my_program_name = argv[0];
3772 parse_options(NULL, argc, argv, options, NULL);
3774 unsetenv("http_proxy"); /* Kill the http_proxy */
3776 av_lfg_init(&random_state, av_get_random_seed());
3778 sigact.sa_handler = handle_child_exit;
3779 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3780 sigaction(SIGCHLD, &sigact, 0);
3782 if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3783 fprintf(stderr, "Error reading configuration file '%s': %s\n",
3784 config.filename, av_err2str(ret));
3787 av_freep(&config.filename);
3789 /* open log file if needed */
3790 if (config.logfilename[0] != '\0') {
3791 if (!strcmp(config.logfilename, "-"))
3794 logfile = fopen(config.logfilename, "a");
3795 av_log_set_callback(http_av_log);
3798 build_file_streams();
3800 build_feed_streams();
3802 compute_bandwidth();
3805 signal(SIGPIPE, SIG_IGN);
3807 if (http_server() < 0) {
3808 http_log("Could not start server\n");