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", random0, random1);
509 /* choose a port if none given */
510 if (stream->multicast_port == 0) {
511 stream->multicast_port = default_port;
515 dest_addr.sin_family = AF_INET;
516 dest_addr.sin_addr = stream->multicast_ip;
517 dest_addr.sin_port = htons(stream->multicast_port);
519 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
520 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
524 if (open_input_stream(rtp_c, "") < 0) {
525 http_log("Could not open input stream for stream '%s'\n",
530 /* open each RTP stream */
531 for(stream_index = 0; stream_index < stream->nb_streams;
533 dest_addr.sin_port = htons(stream->multicast_port +
535 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) >= 0)
538 http_log("Could not open output stream '%s/streamid=%d'\n",
539 stream->filename, stream_index);
543 rtp_c->state = HTTPSTATE_SEND_DATA;
547 /* main loop of the HTTP server */
548 static int http_server(void)
550 int server_fd = 0, rtsp_server_fd = 0;
552 struct pollfd *poll_table, *poll_entry;
553 HTTPContext *c, *c_next;
555 poll_table = av_mallocz_array(config.nb_max_http_connections + 2,
556 sizeof(*poll_table));
558 http_log("Impossible to allocate a poll table handling %d "
559 "connections.\n", config.nb_max_http_connections);
563 if (config.http_addr.sin_port) {
564 server_fd = socket_open_listen(&config.http_addr);
571 if (config.rtsp_addr.sin_port) {
572 rtsp_server_fd = socket_open_listen(&config.rtsp_addr);
573 if (rtsp_server_fd < 0) {
575 closesocket(server_fd);
580 if (!rtsp_server_fd && !server_fd) {
581 http_log("HTTP and RTSP disabled.\n");
586 http_log("FFserver started.\n");
588 start_children(config.first_feed);
593 poll_entry = poll_table;
595 poll_entry->fd = server_fd;
596 poll_entry->events = POLLIN;
599 if (rtsp_server_fd) {
600 poll_entry->fd = rtsp_server_fd;
601 poll_entry->events = POLLIN;
605 /* wait for events on each HTTP handle */
612 case HTTPSTATE_SEND_HEADER:
613 case RTSPSTATE_SEND_REPLY:
614 case RTSPSTATE_SEND_PACKET:
615 c->poll_entry = poll_entry;
617 poll_entry->events = POLLOUT;
620 case HTTPSTATE_SEND_DATA_HEADER:
621 case HTTPSTATE_SEND_DATA:
622 case HTTPSTATE_SEND_DATA_TRAILER:
623 if (!c->is_packetized) {
624 /* for TCP, we output as much as we can
625 * (may need to put a limit) */
626 c->poll_entry = poll_entry;
628 poll_entry->events = POLLOUT;
631 /* when ffserver is doing the timing, we work by
632 looking at which packet needs to be sent every
634 /* one tick wait XXX: 10 ms assumed */
639 case HTTPSTATE_WAIT_REQUEST:
640 case HTTPSTATE_RECEIVE_DATA:
641 case HTTPSTATE_WAIT_FEED:
642 case RTSPSTATE_WAIT_REQUEST:
643 /* need to catch errors */
644 c->poll_entry = poll_entry;
646 poll_entry->events = POLLIN;/* Maybe this will work */
650 c->poll_entry = NULL;
656 /* wait for an event on one connection. We poll at least every
657 second to handle timeouts */
659 ret = poll(poll_table, poll_entry - poll_table, delay);
660 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
661 ff_neterrno() != AVERROR(EINTR)) {
667 cur_time = av_gettime() / 1000;
669 if (need_to_start_children) {
670 need_to_start_children = 0;
671 start_children(config.first_feed);
674 /* now handle the events */
675 for(c = first_http_ctx; c; c = c_next) {
677 if (handle_connection(c) < 0) {
679 /* close and free the connection */
684 poll_entry = poll_table;
686 /* new HTTP connection request ? */
687 if (poll_entry->revents & POLLIN)
688 new_connection(server_fd, 0);
691 if (rtsp_server_fd) {
692 /* new RTSP connection request ? */
693 if (poll_entry->revents & POLLIN)
694 new_connection(rtsp_server_fd, 1);
699 /* start waiting for a new HTTP/RTSP request */
700 static void start_wait_request(HTTPContext *c, int is_rtsp)
702 c->buffer_ptr = c->buffer;
703 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
706 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
707 c->state = RTSPSTATE_WAIT_REQUEST;
709 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
710 c->state = HTTPSTATE_WAIT_REQUEST;
714 static void http_send_too_busy_reply(int fd)
717 int len = snprintf(buffer, sizeof(buffer),
718 "HTTP/1.0 503 Server too busy\r\n"
719 "Content-type: text/html\r\n"
721 "<html><head><title>Too busy</title></head><body>\r\n"
722 "<p>The server is too busy to serve your request at this time.</p>\r\n"
723 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
724 "</body></html>\r\n",
725 nb_connections, config.nb_max_connections);
726 av_assert0(len < sizeof(buffer));
727 if (send(fd, buffer, len, 0) < len)
728 av_log(NULL, AV_LOG_WARNING,
729 "Could not send too-busy reply, send() failed\n");
733 static void new_connection(int server_fd, int is_rtsp)
735 struct sockaddr_in from_addr;
738 HTTPContext *c = NULL;
740 len = sizeof(from_addr);
741 fd = accept(server_fd, (struct sockaddr *)&from_addr,
744 http_log("error during accept %s\n", strerror(errno));
747 if (ff_socket_nonblock(fd, 1) < 0)
748 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
750 if (nb_connections >= config.nb_max_connections) {
751 http_send_too_busy_reply(fd);
755 /* add a new connection */
756 c = av_mallocz(sizeof(HTTPContext));
761 c->poll_entry = NULL;
762 c->from_addr = from_addr;
763 c->buffer_size = IOBUFFER_INIT_SIZE;
764 c->buffer = av_malloc(c->buffer_size);
768 c->next = first_http_ctx;
772 start_wait_request(c, is_rtsp);
778 av_freep(&c->buffer);
784 static void close_connection(HTTPContext *c)
786 HTTPContext **cp, *c1;
788 AVFormatContext *ctx;
792 /* remove connection from list */
793 cp = &first_http_ctx;
802 /* remove references, if any (XXX: do it faster) */
803 for(c1 = first_http_ctx; c1; c1 = c1->next) {
808 /* remove connection associated resources */
812 /* close each frame parser */
813 for(i=0;i<c->fmt_in->nb_streams;i++) {
814 st = c->fmt_in->streams[i];
815 if (st->codec->codec)
816 avcodec_close(st->codec);
818 avformat_close_input(&c->fmt_in);
821 /* free RTP output streams if any */
824 nb_streams = c->stream->nb_streams;
826 for(i=0;i<nb_streams;i++) {
829 av_write_trailer(ctx);
830 av_dict_free(&ctx->metadata);
831 av_freep(&ctx->streams[0]);
834 h = c->rtp_handles[i];
841 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
843 if (ctx->oformat && avio_open_dyn_buf(&ctx->pb) >= 0) {
844 av_write_trailer(ctx);
845 av_freep(&c->pb_buffer);
846 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
850 for(i=0; i<ctx->nb_streams; i++)
851 av_freep(&ctx->streams[i]);
852 av_freep(&ctx->streams);
853 av_freep(&ctx->priv_data);
855 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
856 current_bandwidth -= c->stream->bandwidth;
858 /* signal that there is no feed if we are the feeder socket */
859 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
860 c->stream->feed_opened = 0;
864 av_freep(&c->pb_buffer);
865 av_freep(&c->packet_buffer);
866 av_freep(&c->buffer);
871 static int handle_connection(HTTPContext *c)
877 case HTTPSTATE_WAIT_REQUEST:
878 case RTSPSTATE_WAIT_REQUEST:
880 if ((c->timeout - cur_time) < 0)
882 if (c->poll_entry->revents & (POLLERR | POLLHUP))
885 /* no need to read if no events */
886 if (!(c->poll_entry->revents & POLLIN))
890 if (!(len = recv(c->fd, c->buffer_ptr, 1, 0)))
894 if (ff_neterrno() != AVERROR(EAGAIN) &&
895 ff_neterrno() != AVERROR(EINTR))
899 /* search for end of request. */
900 c->buffer_ptr += len;
902 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
903 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
904 /* request found : parse it and reply */
905 if (c->state == HTTPSTATE_WAIT_REQUEST) {
906 ret = http_parse_request(c);
908 ret = rtsp_parse_request(c);
912 } else if (ptr >= c->buffer_end) {
913 /* request too long: cannot do anything */
915 } else goto read_loop;
919 case HTTPSTATE_SEND_HEADER:
920 if (c->poll_entry->revents & (POLLERR | POLLHUP))
923 /* no need to write if no events */
924 if (!(c->poll_entry->revents & POLLOUT))
926 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
928 if (ff_neterrno() != AVERROR(EAGAIN) &&
929 ff_neterrno() != AVERROR(EINTR)) {
930 goto close_connection;
934 c->buffer_ptr += len;
936 c->stream->bytes_served += len;
937 c->data_count += len;
938 if (c->buffer_ptr >= c->buffer_end) {
939 av_freep(&c->pb_buffer);
943 /* all the buffer was sent : synchronize to the incoming
945 c->state = HTTPSTATE_SEND_DATA_HEADER;
946 c->buffer_ptr = c->buffer_end = c->buffer;
950 case HTTPSTATE_SEND_DATA:
951 case HTTPSTATE_SEND_DATA_HEADER:
952 case HTTPSTATE_SEND_DATA_TRAILER:
953 /* for packetized output, we consider we can always write (the
954 input streams set the speed). It may be better to verify
955 that we do not rely too much on the kernel queues */
956 if (!c->is_packetized) {
957 if (c->poll_entry->revents & (POLLERR | POLLHUP))
960 /* no need to read if no events */
961 if (!(c->poll_entry->revents & POLLOUT))
964 if (http_send_data(c) < 0)
966 /* close connection if trailer sent */
967 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
969 /* Check if it is a single jpeg frame 123 */
970 if (c->stream->single_frame && c->data_count > c->cur_frame_bytes && c->cur_frame_bytes > 0) {
974 case HTTPSTATE_RECEIVE_DATA:
975 /* no need to read if no events */
976 if (c->poll_entry->revents & (POLLERR | POLLHUP))
978 if (!(c->poll_entry->revents & POLLIN))
980 if (http_receive_data(c) < 0)
983 case HTTPSTATE_WAIT_FEED:
984 /* no need to read if no events */
985 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
988 /* nothing to do, we'll be waken up by incoming feed packets */
991 case RTSPSTATE_SEND_REPLY:
992 if (c->poll_entry->revents & (POLLERR | POLLHUP))
993 goto close_connection;
994 /* no need to write if no events */
995 if (!(c->poll_entry->revents & POLLOUT))
997 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
999 if (ff_neterrno() != AVERROR(EAGAIN) &&
1000 ff_neterrno() != AVERROR(EINTR)) {
1001 goto close_connection;
1005 c->buffer_ptr += len;
1006 c->data_count += len;
1007 if (c->buffer_ptr >= c->buffer_end) {
1008 /* all the buffer was sent : wait for a new request */
1009 av_freep(&c->pb_buffer);
1010 start_wait_request(c, 1);
1013 case RTSPSTATE_SEND_PACKET:
1014 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1015 av_freep(&c->packet_buffer);
1018 /* no need to write if no events */
1019 if (!(c->poll_entry->revents & POLLOUT))
1021 len = send(c->fd, c->packet_buffer_ptr,
1022 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1024 if (ff_neterrno() != AVERROR(EAGAIN) &&
1025 ff_neterrno() != AVERROR(EINTR)) {
1026 /* error : close connection */
1027 av_freep(&c->packet_buffer);
1032 c->packet_buffer_ptr += len;
1033 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1034 /* all the buffer was sent : wait for a new request */
1035 av_freep(&c->packet_buffer);
1036 c->state = RTSPSTATE_WAIT_REQUEST;
1039 case HTTPSTATE_READY:
1048 av_freep(&c->pb_buffer);
1052 static int extract_rates(char *rates, int ratelen, const char *request)
1056 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1057 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1058 const char *q = p + 7;
1060 while (*q && *q != '\n' && av_isspace(*q))
1063 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1069 memset(rates, 0xff, ratelen);
1072 while (*q && *q != '\n' && *q != ':')
1075 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1079 if (stream_no < ratelen && stream_no >= 0)
1080 rates[stream_no] = rate_no;
1082 while (*q && *q != '\n' && !av_isspace(*q))
1089 p = strchr(p, '\n');
1099 static int find_stream_in_feed(FFServerStream *feed, AVCodecContext *codec,
1103 int best_bitrate = 100000000;
1106 for (i = 0; i < feed->nb_streams; i++) {
1107 AVCodecContext *feed_codec = feed->streams[i]->codec;
1109 if (feed_codec->codec_id != codec->codec_id ||
1110 feed_codec->sample_rate != codec->sample_rate ||
1111 feed_codec->width != codec->width ||
1112 feed_codec->height != codec->height)
1115 /* Potential stream */
1117 /* We want the fastest stream less than bit_rate, or the slowest
1118 * faster than bit_rate
1121 if (feed_codec->bit_rate <= bit_rate) {
1122 if (best_bitrate > bit_rate ||
1123 feed_codec->bit_rate > best_bitrate) {
1124 best_bitrate = feed_codec->bit_rate;
1129 if (feed_codec->bit_rate < best_bitrate) {
1130 best_bitrate = feed_codec->bit_rate;
1137 static int modify_current_stream(HTTPContext *c, char *rates)
1140 FFServerStream *req = c->stream;
1141 int action_required = 0;
1143 /* Not much we can do for a feed */
1147 for (i = 0; i < req->nb_streams; i++) {
1148 AVCodecContext *codec = req->streams[i]->codec;
1152 c->switch_feed_streams[i] = req->feed_streams[i];
1155 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1158 /* Wants off or slow */
1159 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1161 /* This doesn't work well when it turns off the only stream! */
1162 c->switch_feed_streams[i] = -2;
1163 c->feed_streams[i] = -2;
1168 if (c->switch_feed_streams[i] >= 0 &&
1169 c->switch_feed_streams[i] != c->feed_streams[i]) {
1170 action_required = 1;
1174 return action_required;
1177 static void get_word(char *buf, int buf_size, const char **pp)
1183 p += strspn(p, SPACE_CHARS);
1185 while (!av_isspace(*p) && *p != '\0') {
1186 if ((q - buf) < buf_size - 1)
1195 static FFServerIPAddressACL* parse_dynamic_acl(FFServerStream *stream,
1201 FFServerIPAddressACL *acl = NULL;
1205 f = fopen(stream->dynamic_acl, "r");
1207 perror(stream->dynamic_acl);
1211 acl = av_mallocz(sizeof(FFServerIPAddressACL));
1218 while (fgets(line, sizeof(line), f)) {
1221 while (av_isspace(*p))
1223 if (*p == '\0' || *p == '#')
1225 ffserver_get_arg(cmd, sizeof(cmd), &p);
1227 if (!av_strcasecmp(cmd, "ACL"))
1228 ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl,
1236 static void free_acl_list(FFServerIPAddressACL *in_acl)
1238 FFServerIPAddressACL *pacl, *pacl2;
1248 static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c)
1250 enum FFServerIPAddressAction last_action = IP_DENY;
1251 FFServerIPAddressACL *acl;
1252 struct in_addr *src = &c->from_addr.sin_addr;
1253 unsigned long src_addr = src->s_addr;
1255 for (acl = in_acl; acl; acl = acl->next) {
1256 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1257 return (acl->action == IP_ALLOW) ? 1 : 0;
1258 last_action = acl->action;
1261 /* Nothing matched, so return not the last action */
1262 return (last_action == IP_DENY) ? 1 : 0;
1265 static int validate_acl(FFServerStream *stream, HTTPContext *c)
1268 FFServerIPAddressACL *acl;
1270 /* if stream->acl is null validate_acl_list will return 1 */
1271 ret = validate_acl_list(stream->acl, c);
1273 if (stream->dynamic_acl[0]) {
1274 acl = parse_dynamic_acl(stream, c);
1275 ret = validate_acl_list(acl, c);
1282 /* compute the real filename of a file by matching it without its
1283 extensions to all the stream's filenames */
1284 static void compute_real_filename(char *filename, int max_size)
1289 FFServerStream *stream;
1291 /* compute filename by matching without the file extensions */
1292 av_strlcpy(file1, filename, sizeof(file1));
1293 p = strrchr(file1, '.');
1296 for(stream = config.first_stream; stream; stream = stream->next) {
1297 av_strlcpy(file2, stream->filename, sizeof(file2));
1298 p = strrchr(file2, '.');
1301 if (!strcmp(file1, file2)) {
1302 av_strlcpy(filename, stream->filename, max_size);
1317 /* parse HTTP request and prepare header */
1318 static int http_parse_request(HTTPContext *c)
1322 enum RedirType redir_type;
1324 char info[1024], filename[1024];
1328 const char *mime_type;
1329 FFServerStream *stream;
1332 const char *useragent = 0;
1335 get_word(cmd, sizeof(cmd), &p);
1336 av_strlcpy(c->method, cmd, sizeof(c->method));
1338 if (!strcmp(cmd, "GET"))
1340 else if (!strcmp(cmd, "POST"))
1345 get_word(url, sizeof(url), &p);
1346 av_strlcpy(c->url, url, sizeof(c->url));
1348 get_word(protocol, sizeof(protocol), (const char **)&p);
1349 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1352 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1355 http_log("%s - - New connection: %s %s\n",
1356 inet_ntoa(c->from_addr.sin_addr), cmd, url);
1358 /* find the filename and the optional info string in the request */
1359 p1 = strchr(url, '?');
1361 av_strlcpy(info, p1, sizeof(info));
1366 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1368 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1369 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1371 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1375 p = strchr(p, '\n');
1382 redir_type = REDIR_NONE;
1383 if (av_match_ext(filename, "asx")) {
1384 redir_type = REDIR_ASX;
1385 filename[strlen(filename)-1] = 'f';
1386 } else if (av_match_ext(filename, "asf") &&
1387 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) {
1388 /* if this isn't WMP or lookalike, return the redirector file */
1389 redir_type = REDIR_ASF;
1390 } else if (av_match_ext(filename, "rpm,ram")) {
1391 redir_type = REDIR_RAM;
1392 strcpy(filename + strlen(filename)-2, "m");
1393 } else if (av_match_ext(filename, "rtsp")) {
1394 redir_type = REDIR_RTSP;
1395 compute_real_filename(filename, sizeof(filename) - 1);
1396 } else if (av_match_ext(filename, "sdp")) {
1397 redir_type = REDIR_SDP;
1398 compute_real_filename(filename, sizeof(filename) - 1);
1401 // "redirect" / request to index.html
1402 if (!strlen(filename))
1403 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1405 stream = config.first_stream;
1407 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1409 stream = stream->next;
1412 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1413 http_log("File '%s' not found\n", url);
1418 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1419 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1421 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1422 c->http_error = 301;
1424 snprintf(q, c->buffer_size,
1425 "HTTP/1.0 301 Moved\r\n"
1427 "Content-type: text/html\r\n"
1429 "<html><head><title>Moved</title></head><body>\r\n"
1430 "You should be <a href=\"%s\">redirected</a>.\r\n"
1431 "</body></html>\r\n",
1432 stream->feed_filename, stream->feed_filename);
1434 /* prepare output buffer */
1435 c->buffer_ptr = c->buffer;
1437 c->state = HTTPSTATE_SEND_HEADER;
1441 /* If this is WMP, get the rate information */
1442 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1443 if (modify_current_stream(c, ratebuf)) {
1444 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1445 if (c->switch_feed_streams[i] >= 0)
1446 c->switch_feed_streams[i] = -1;
1451 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1452 current_bandwidth += stream->bandwidth;
1454 /* If already streaming this feed, do not let start another feeder. */
1455 if (stream->feed_opened) {
1456 snprintf(msg, sizeof(msg), "This feed is already being received.");
1457 http_log("Feed '%s' already being received\n", stream->feed_filename);
1461 if (c->post == 0 && config.max_bandwidth < current_bandwidth) {
1462 c->http_error = 503;
1464 snprintf(q, c->buffer_size,
1465 "HTTP/1.0 503 Server too busy\r\n"
1466 "Content-type: text/html\r\n"
1468 "<html><head><title>Too busy</title></head><body>\r\n"
1469 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1470 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1471 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1472 "</body></html>\r\n",
1473 current_bandwidth, config.max_bandwidth);
1475 /* prepare output buffer */
1476 c->buffer_ptr = c->buffer;
1478 c->state = HTTPSTATE_SEND_HEADER;
1482 if (redir_type != REDIR_NONE) {
1483 const char *hostinfo = 0;
1485 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1486 if (av_strncasecmp(p, "Host:", 5) == 0) {
1490 p = strchr(p, '\n');
1501 while (av_isspace(*hostinfo))
1504 eoh = strchr(hostinfo, '\n');
1506 if (eoh[-1] == '\r')
1509 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1510 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1511 hostbuf[eoh - hostinfo] = 0;
1513 c->http_error = 200;
1515 switch(redir_type) {
1517 snprintf(q, c->buffer_size,
1518 "HTTP/1.0 200 ASX Follows\r\n"
1519 "Content-type: video/x-ms-asf\r\n"
1521 "<ASX Version=\"3\">\r\n"
1522 //"<!-- Autogenerated by ffserver -->\r\n"
1523 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1524 "</ASX>\r\n", hostbuf, filename, info);
1528 snprintf(q, c->buffer_size,
1529 "HTTP/1.0 200 RAM Follows\r\n"
1530 "Content-type: audio/x-pn-realaudio\r\n"
1532 "# Autogenerated by ffserver\r\n"
1533 "http://%s/%s%s\r\n", hostbuf, filename, info);
1537 snprintf(q, c->buffer_size,
1538 "HTTP/1.0 200 ASF Redirect follows\r\n"
1539 "Content-type: video/x-ms-asf\r\n"
1542 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1547 char hostname[256], *p;
1548 /* extract only hostname */
1549 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1550 p = strrchr(hostname, ':');
1553 snprintf(q, c->buffer_size,
1554 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1555 /* XXX: incorrect MIME type ? */
1556 "Content-type: application/x-rtsp\r\n"
1558 "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
1567 struct sockaddr_in my_addr;
1569 snprintf(q, c->buffer_size,
1570 "HTTP/1.0 200 OK\r\n"
1571 "Content-type: application/sdp\r\n"
1575 len = sizeof(my_addr);
1577 /* XXX: Should probably fail? */
1578 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1579 http_log("getsockname() failed\n");
1581 /* XXX: should use a dynamic buffer */
1582 sdp_data_size = prepare_sdp_description(stream,
1585 if (sdp_data_size > 0) {
1586 memcpy(q, sdp_data, sdp_data_size);
1598 /* prepare output buffer */
1599 c->buffer_ptr = c->buffer;
1601 c->state = HTTPSTATE_SEND_HEADER;
1607 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1611 stream->conns_served++;
1613 /* XXX: add there authenticate and IP match */
1616 /* if post, it means a feed is being sent */
1617 if (!stream->is_feed) {
1618 /* However it might be a status report from WMP! Let us log the
1619 * data as it might come handy one day. */
1620 const char *logline = 0;
1623 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1624 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1628 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1629 client_id = strtol(p + 18, 0, 10);
1630 p = strchr(p, '\n');
1638 char *eol = strchr(logline, '\n');
1643 if (eol[-1] == '\r')
1645 http_log("%.*s\n", (int) (eol - logline), logline);
1646 c->suppress_log = 1;
1651 http_log("\nGot request:\n%s\n", c->buffer);
1654 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1657 /* Now we have to find the client_id */
1658 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1659 if (wmpc->wmp_client_id == client_id)
1663 if (wmpc && modify_current_stream(wmpc, ratebuf))
1664 wmpc->switch_pending = 1;
1667 snprintf(msg, sizeof(msg), "POST command not handled");
1671 if (http_start_receive_data(c) < 0) {
1672 snprintf(msg, sizeof(msg), "could not open feed");
1676 c->state = HTTPSTATE_RECEIVE_DATA;
1681 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1682 http_log("\nGot request:\n%s\n", c->buffer);
1685 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1688 /* open input stream */
1689 if (open_input_stream(c, info) < 0) {
1690 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1694 /* prepare HTTP header */
1696 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1697 mime_type = c->stream->fmt->mime_type;
1699 mime_type = "application/x-octet-stream";
1700 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1702 /* for asf, we need extra headers */
1703 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1704 /* Need to allocate a client id */
1706 c->wmp_client_id = av_lfg_get(&random_state);
1708 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);
1710 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1711 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1712 q = c->buffer + strlen(c->buffer);
1714 /* prepare output buffer */
1716 c->buffer_ptr = c->buffer;
1718 c->state = HTTPSTATE_SEND_HEADER;
1721 c->http_error = 404;
1724 snprintf(q, c->buffer_size,
1725 "HTTP/1.0 404 Not Found\r\n"
1726 "Content-type: text/html\r\n"
1729 "<head><title>404 Not Found</title></head>\n"
1733 /* prepare output buffer */
1734 c->buffer_ptr = c->buffer;
1736 c->state = HTTPSTATE_SEND_HEADER;
1740 c->http_error = 200; /* horrible : we use this value to avoid
1741 going to the send data state */
1742 c->state = HTTPSTATE_SEND_HEADER;
1746 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1748 static const char suffix[] = " kMGTP";
1751 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1753 avio_printf(pb, "%"PRId64"%c", count, *s);
1756 static void compute_status(HTTPContext *c)
1759 FFServerStream *stream;
1765 if (avio_open_dyn_buf(&pb) < 0) {
1766 /* XXX: return an error ? */
1767 c->buffer_ptr = c->buffer;
1768 c->buffer_end = c->buffer;
1772 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1773 avio_printf(pb, "Content-type: text/html\r\n");
1774 avio_printf(pb, "Pragma: no-cache\r\n");
1775 avio_printf(pb, "\r\n");
1777 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1778 if (c->stream->feed_filename[0])
1779 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n",
1780 c->stream->feed_filename);
1781 avio_printf(pb, "</head>\n<body>");
1782 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1784 avio_printf(pb, "<h2>Available Streams</h2>\n");
1785 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1786 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");
1787 stream = config.first_stream;
1789 char sfilename[1024];
1792 if (stream->feed == stream) {
1793 stream = stream->next;
1797 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1798 eosf = sfilename + strlen(sfilename);
1799 if (eosf - sfilename >= 4) {
1800 if (strcmp(eosf - 4, ".asf") == 0)
1801 strcpy(eosf - 4, ".asx");
1802 else if (strcmp(eosf - 3, ".rm") == 0)
1803 strcpy(eosf - 3, ".ram");
1804 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1805 /* generate a sample RTSP director if
1806 unicast. Generate an SDP redirector if
1808 eosf = strrchr(sfilename, '.');
1810 eosf = sfilename + strlen(sfilename);
1811 if (stream->is_multicast)
1812 strcpy(eosf, ".sdp");
1814 strcpy(eosf, ".rtsp");
1818 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1819 sfilename, stream->filename);
1820 avio_printf(pb, "<td align=right> %d <td align=right> ",
1821 stream->conns_served);
1822 fmt_bytecount(pb, stream->bytes_served);
1824 switch(stream->stream_type) {
1825 case STREAM_TYPE_LIVE: {
1826 int audio_bit_rate = 0;
1827 int video_bit_rate = 0;
1828 const char *audio_codec_name = "";
1829 const char *video_codec_name = "";
1830 const char *audio_codec_name_extra = "";
1831 const char *video_codec_name_extra = "";
1833 for(i=0;i<stream->nb_streams;i++) {
1834 AVStream *st = stream->streams[i];
1835 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1837 switch(st->codec->codec_type) {
1838 case AVMEDIA_TYPE_AUDIO:
1839 audio_bit_rate += st->codec->bit_rate;
1841 if (*audio_codec_name)
1842 audio_codec_name_extra = "...";
1843 audio_codec_name = codec->name;
1846 case AVMEDIA_TYPE_VIDEO:
1847 video_bit_rate += st->codec->bit_rate;
1849 if (*video_codec_name)
1850 video_codec_name_extra = "...";
1851 video_codec_name = codec->name;
1854 case AVMEDIA_TYPE_DATA:
1855 video_bit_rate += st->codec->bit_rate;
1862 avio_printf(pb, "<td align=center> %s <td align=right> %d "
1863 "<td align=right> %d <td> %s %s <td align=right> "
1865 stream->fmt->name, stream->bandwidth,
1866 video_bit_rate / 1000, video_codec_name,
1867 video_codec_name_extra, audio_bit_rate / 1000,
1868 audio_codec_name, audio_codec_name_extra);
1871 avio_printf(pb, "<td>%s", stream->feed->filename);
1873 avio_printf(pb, "<td>%s", stream->feed_filename);
1874 avio_printf(pb, "\n");
1878 avio_printf(pb, "<td align=center> - <td align=right> - "
1879 "<td align=right> - <td><td align=right> - <td>\n");
1882 stream = stream->next;
1884 avio_printf(pb, "</table>\n");
1886 stream = config.first_stream;
1889 if (stream->feed != stream) {
1890 stream = stream->next;
1894 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1896 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1903 /* This is somewhat linux specific I guess */
1904 snprintf(ps_cmd, sizeof(ps_cmd),
1905 "ps -o \"%%cpu,cputime\" --no-headers %d",
1908 pid_stat = popen(ps_cmd, "r");
1913 if (fscanf(pid_stat, "%9s %63s", cpuperc, cpuused) == 2) {
1914 avio_printf(pb, "Currently using %s%% of the cpu. "
1915 "Total time used %s.\n",
1923 avio_printf(pb, "<p>");
1926 avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>"
1927 "type<th>kbits/s<th align=left>codec<th align=left>"
1930 for (i = 0; i < stream->nb_streams; i++) {
1931 AVStream *st = stream->streams[i];
1932 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1933 const char *type = "unknown";
1934 char parameters[64];
1938 switch(st->codec->codec_type) {
1939 case AVMEDIA_TYPE_AUDIO:
1941 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz",
1942 st->codec->channels, st->codec->sample_rate);
1944 case AVMEDIA_TYPE_VIDEO:
1946 snprintf(parameters, sizeof(parameters),
1947 "%dx%d, q=%d-%d, fps=%d", st->codec->width,
1948 st->codec->height, st->codec->qmin, st->codec->qmax,
1949 st->codec->time_base.den / st->codec->time_base.num);
1955 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d"
1957 i, type, st->codec->bit_rate/1000,
1958 codec ? codec->name : "", parameters);
1961 avio_printf(pb, "</table>\n");
1962 stream = stream->next;
1965 /* connection status */
1966 avio_printf(pb, "<h2>Connection Status</h2>\n");
1968 avio_printf(pb, "Number of connections: %d / %d<br>\n",
1969 nb_connections, config.nb_max_connections);
1971 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1972 current_bandwidth, config.max_bandwidth);
1974 avio_printf(pb, "<table>\n");
1975 avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target "
1976 "bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1977 c1 = first_http_ctx;
1985 for (j = 0; j < c1->stream->nb_streams; j++) {
1986 if (!c1->stream->feed)
1987 bitrate += c1->stream->streams[j]->codec->bit_rate;
1988 else if (c1->feed_streams[j] >= 0)
1989 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1994 p = inet_ntoa(c1->from_addr.sin_addr);
1995 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s"
1997 i, c1->stream ? c1->stream->filename : "",
1998 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", p,
1999 c1->protocol, http_state[c1->state]);
2000 fmt_bytecount(pb, bitrate);
2001 avio_printf(pb, "<td align=right>");
2002 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2003 avio_printf(pb, "<td align=right>");
2004 fmt_bytecount(pb, c1->data_count);
2005 avio_printf(pb, "\n");
2008 avio_printf(pb, "</table>\n");
2013 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2014 avio_printf(pb, "</body>\n</html>\n");
2016 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2017 c->buffer_ptr = c->pb_buffer;
2018 c->buffer_end = c->pb_buffer + len;
2021 static int open_input_stream(HTTPContext *c, const char *info)
2024 char input_filename[1024];
2025 AVFormatContext *s = NULL;
2026 int buf_size, i, ret;
2029 /* find file name */
2030 if (c->stream->feed) {
2031 strcpy(input_filename, c->stream->feed->feed_filename);
2032 buf_size = FFM_PACKET_SIZE;
2033 /* compute position (absolute time) */
2034 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2035 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2036 http_log("Invalid date specification '%s' for stream\n", buf);
2039 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2040 int prebuffer = strtol(buf, 0, 10);
2041 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2043 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2045 strcpy(input_filename, c->stream->feed_filename);
2047 /* compute position (relative time) */
2048 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2049 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2050 http_log("Invalid date specification '%s' for stream\n", buf);
2056 if (!input_filename[0]) {
2057 http_log("No filename was specified for stream\n");
2058 return AVERROR(EINVAL);
2062 ret = avformat_open_input(&s, input_filename, c->stream->ifmt,
2063 &c->stream->in_opts);
2065 http_log("Could not open input '%s': %s\n",
2066 input_filename, av_err2str(ret));
2070 /* set buffer size */
2072 ret = ffio_set_buf_size(s->pb, buf_size);
2074 http_log("Failed to set buffer size\n");
2079 s->flags |= AVFMT_FLAG_GENPTS;
2081 if (strcmp(s->iformat->name, "ffm") &&
2082 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2083 http_log("Could not find stream info for input '%s'\n", input_filename);
2084 avformat_close_input(&s);
2088 /* choose stream as clock source (we favor the video stream if
2089 * present) for packet sending */
2090 c->pts_stream_index = 0;
2091 for(i=0;i<c->stream->nb_streams;i++) {
2092 if (c->pts_stream_index == 0 &&
2093 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2094 c->pts_stream_index = i;
2098 if (c->fmt_in->iformat->read_seek)
2099 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2100 /* set the start time (needed for maxtime and RTP packet timing) */
2101 c->start_time = cur_time;
2102 c->first_pts = AV_NOPTS_VALUE;
2106 /* return the server clock (in us) */
2107 static int64_t get_server_clock(HTTPContext *c)
2109 /* compute current pts value from system time */
2110 return (cur_time - c->start_time) * 1000;
2113 /* return the estimated time at which the current packet must be sent
2115 static int64_t get_packet_send_clock(HTTPContext *c)
2117 int bytes_left, bytes_sent, frame_bytes;
2119 frame_bytes = c->cur_frame_bytes;
2120 if (frame_bytes <= 0)
2123 bytes_left = c->buffer_end - c->buffer_ptr;
2124 bytes_sent = frame_bytes - bytes_left;
2125 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2129 static int http_prepare_data(HTTPContext *c)
2132 AVFormatContext *ctx;
2134 av_freep(&c->pb_buffer);
2136 case HTTPSTATE_SEND_DATA_HEADER:
2137 ctx = avformat_alloc_context();
2139 return AVERROR(ENOMEM);
2142 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2143 c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams,
2144 sizeof(AVStream *));
2145 if (!c->fmt_ctx.streams)
2146 return AVERROR(ENOMEM);
2148 for(i=0;i<c->stream->nb_streams;i++) {
2150 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2152 /* if file or feed, then just take streams from FFServerStream struct */
2153 if (!c->stream->feed ||
2154 c->stream->feed == c->stream)
2155 src = c->stream->streams[i];
2157 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2159 *(c->fmt_ctx.streams[i]) = *src;
2160 c->fmt_ctx.streams[i]->priv_data = 0;
2161 /* XXX: should be done in AVStream, not in codec */
2162 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2164 /* set output format parameters */
2165 c->fmt_ctx.oformat = c->stream->fmt;
2166 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2168 c->got_key_frame = 0;
2170 /* prepare header and save header data in a stream */
2171 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2172 /* XXX: potential leak */
2175 c->fmt_ctx.pb->seekable = 0;
2178 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2179 * Default value from FFmpeg
2180 * Try to set it using configuration option
2182 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2184 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2185 http_log("Error writing output header for stream '%s': %s\n",
2186 c->stream->filename, av_err2str(ret));
2189 av_dict_free(&c->fmt_ctx.metadata);
2191 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2192 c->buffer_ptr = c->pb_buffer;
2193 c->buffer_end = c->pb_buffer + len;
2195 c->state = HTTPSTATE_SEND_DATA;
2196 c->last_packet_sent = 0;
2198 case HTTPSTATE_SEND_DATA:
2199 /* find a new packet */
2200 /* read a packet from the input stream */
2201 if (c->stream->feed)
2202 ffm_set_write_index(c->fmt_in,
2203 c->stream->feed->feed_write_index,
2204 c->stream->feed->feed_size);
2206 if (c->stream->max_time &&
2207 c->stream->max_time + c->start_time - cur_time < 0)
2208 /* We have timed out */
2209 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2213 ret = av_read_frame(c->fmt_in, &pkt);
2215 if (c->stream->feed) {
2216 /* if coming from feed, it means we reached the end of the
2217 ffm file, so must wait for more data */
2218 c->state = HTTPSTATE_WAIT_FEED;
2219 return 1; /* state changed */
2221 if (ret == AVERROR(EAGAIN)) {
2222 /* input not ready, come back later */
2225 if (c->stream->loop) {
2226 avformat_close_input(&c->fmt_in);
2227 if (open_input_stream(c, "") < 0)
2232 /* must send trailer now because EOF or error */
2233 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2236 int source_index = pkt.stream_index;
2237 /* update first pts if needed */
2238 if (c->first_pts == AV_NOPTS_VALUE) {
2239 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2240 c->start_time = cur_time;
2242 /* send it to the appropriate stream */
2243 if (c->stream->feed) {
2244 /* if coming from a feed, select the right stream */
2245 if (c->switch_pending) {
2246 c->switch_pending = 0;
2247 for(i=0;i<c->stream->nb_streams;i++) {
2248 if (c->switch_feed_streams[i] == pkt.stream_index)
2249 if (pkt.flags & AV_PKT_FLAG_KEY)
2250 c->switch_feed_streams[i] = -1;
2251 if (c->switch_feed_streams[i] >= 0)
2252 c->switch_pending = 1;
2255 for(i=0;i<c->stream->nb_streams;i++) {
2256 if (c->stream->feed_streams[i] == pkt.stream_index) {
2257 AVStream *st = c->fmt_in->streams[source_index];
2258 pkt.stream_index = i;
2259 if (pkt.flags & AV_PKT_FLAG_KEY &&
2260 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2261 c->stream->nb_streams == 1))
2262 c->got_key_frame = 1;
2263 if (!c->stream->send_on_key || c->got_key_frame)
2268 AVCodecContext *codec;
2269 AVStream *ist, *ost;
2271 ist = c->fmt_in->streams[source_index];
2272 /* specific handling for RTP: we use several
2273 * output streams (one for each RTP connection).
2274 * XXX: need more abstract handling */
2275 if (c->is_packetized) {
2276 /* compute send time and duration */
2277 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2278 c->cur_pts -= c->first_pts;
2279 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2280 /* find RTP context */
2281 c->packet_stream_index = pkt.stream_index;
2282 ctx = c->rtp_ctx[c->packet_stream_index];
2284 av_free_packet(&pkt);
2287 codec = ctx->streams[0]->codec;
2288 /* only one stream per RTP connection */
2289 pkt.stream_index = 0;
2293 codec = ctx->streams[pkt.stream_index]->codec;
2296 if (c->is_packetized) {
2297 int max_packet_size;
2298 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2299 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2301 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2302 ret = ffio_open_dyn_packet_buf(&ctx->pb,
2305 ret = avio_open_dyn_buf(&ctx->pb);
2308 /* XXX: potential leak */
2311 ost = ctx->streams[pkt.stream_index];
2313 ctx->pb->seekable = 0;
2314 if (pkt.dts != AV_NOPTS_VALUE)
2315 pkt.dts = av_rescale_q(pkt.dts, ist->time_base,
2317 if (pkt.pts != AV_NOPTS_VALUE)
2318 pkt.pts = av_rescale_q(pkt.pts, ist->time_base,
2320 pkt.duration = av_rescale_q(pkt.duration, ist->time_base,
2322 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2323 http_log("Error writing frame to output for stream '%s': %s\n",
2324 c->stream->filename, av_err2str(ret));
2325 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2328 av_freep(&c->pb_buffer);
2329 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2330 c->cur_frame_bytes = len;
2331 c->buffer_ptr = c->pb_buffer;
2332 c->buffer_end = c->pb_buffer + len;
2334 codec->frame_number++;
2336 av_free_packet(&pkt);
2340 av_free_packet(&pkt);
2345 case HTTPSTATE_SEND_DATA_TRAILER:
2346 /* last packet test ? */
2347 if (c->last_packet_sent || c->is_packetized)
2350 /* prepare header */
2351 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2352 /* XXX: potential leak */
2355 c->fmt_ctx.pb->seekable = 0;
2356 av_write_trailer(ctx);
2357 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2358 c->buffer_ptr = c->pb_buffer;
2359 c->buffer_end = c->pb_buffer + len;
2361 c->last_packet_sent = 1;
2367 /* should convert the format at the same time */
2368 /* send data starting at c->buffer_ptr to the output connection
2369 * (either UDP or TCP) */
2370 static int http_send_data(HTTPContext *c)
2375 if (c->buffer_ptr >= c->buffer_end) {
2376 ret = http_prepare_data(c);
2380 /* state change requested */
2383 if (c->is_packetized) {
2384 /* RTP data output */
2385 len = c->buffer_end - c->buffer_ptr;
2387 /* fail safe - should never happen */
2389 c->buffer_ptr = c->buffer_end;
2392 len = (c->buffer_ptr[0] << 24) |
2393 (c->buffer_ptr[1] << 16) |
2394 (c->buffer_ptr[2] << 8) |
2396 if (len > (c->buffer_end - c->buffer_ptr))
2398 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2399 /* nothing to send yet: we can wait */
2403 c->data_count += len;
2404 update_datarate(&c->datarate, c->data_count);
2406 c->stream->bytes_served += len;
2408 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2409 /* RTP packets are sent inside the RTSP TCP connection */
2411 int interleaved_index, size;
2413 HTTPContext *rtsp_c;
2416 /* if no RTSP connection left, error */
2419 /* if already sending something, then wait. */
2420 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2422 if (avio_open_dyn_buf(&pb) < 0)
2424 interleaved_index = c->packet_stream_index * 2;
2425 /* RTCP packets are sent at odd indexes */
2426 if (c->buffer_ptr[1] == 200)
2427 interleaved_index++;
2428 /* write RTSP TCP header */
2430 header[1] = interleaved_index;
2431 header[2] = len >> 8;
2433 avio_write(pb, header, 4);
2434 /* write RTP packet data */
2436 avio_write(pb, c->buffer_ptr, len);
2437 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2438 /* prepare asynchronous TCP sending */
2439 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2440 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2441 c->buffer_ptr += len;
2443 /* send everything we can NOW */
2444 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2445 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2447 rtsp_c->packet_buffer_ptr += len;
2448 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2449 /* if we could not send all the data, we will
2450 send it later, so a new state is needed to
2451 "lock" the RTSP TCP connection */
2452 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2455 /* all data has been sent */
2456 av_freep(&c->packet_buffer);
2458 /* send RTP packet directly in UDP */
2460 ffurl_write(c->rtp_handles[c->packet_stream_index],
2461 c->buffer_ptr, len);
2462 c->buffer_ptr += len;
2463 /* here we continue as we can send several packets
2467 /* TCP data output */
2468 len = send(c->fd, c->buffer_ptr,
2469 c->buffer_end - c->buffer_ptr, 0);
2471 if (ff_neterrno() != AVERROR(EAGAIN) &&
2472 ff_neterrno() != AVERROR(EINTR))
2473 /* error : close connection */
2478 c->buffer_ptr += len;
2480 c->data_count += len;
2481 update_datarate(&c->datarate, c->data_count);
2483 c->stream->bytes_served += len;
2491 static int http_start_receive_data(HTTPContext *c)
2496 if (c->stream->feed_opened) {
2497 http_log("Stream feed '%s' was not opened\n",
2498 c->stream->feed_filename);
2499 return AVERROR(EINVAL);
2502 /* Don't permit writing to this one */
2503 if (c->stream->readonly) {
2504 http_log("Cannot write to read-only file '%s'\n",
2505 c->stream->feed_filename);
2506 return AVERROR(EINVAL);
2510 fd = open(c->stream->feed_filename, O_RDWR);
2512 ret = AVERROR(errno);
2513 http_log("Could not open feed file '%s': %s\n",
2514 c->stream->feed_filename, strerror(errno));
2519 if (c->stream->truncate) {
2520 /* truncate feed file */
2521 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2522 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2523 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2524 ret = AVERROR(errno);
2525 http_log("Error truncating feed file '%s': %s\n",
2526 c->stream->feed_filename, strerror(errno));
2530 ret = ffm_read_write_index(fd);
2532 http_log("Error reading write index from feed file '%s': %s\n",
2533 c->stream->feed_filename, strerror(errno));
2536 c->stream->feed_write_index = ret;
2540 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd),
2542 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2543 lseek(fd, 0, SEEK_SET);
2545 /* init buffer input */
2546 c->buffer_ptr = c->buffer;
2547 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2548 c->stream->feed_opened = 1;
2549 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2553 static int http_receive_data(HTTPContext *c)
2556 int len, loop_run = 0;
2558 while (c->chunked_encoding && !c->chunk_size &&
2559 c->buffer_end > c->buffer_ptr) {
2560 /* read chunk header, if present */
2561 len = recv(c->fd, c->buffer_ptr, 1, 0);
2564 if (ff_neterrno() != AVERROR(EAGAIN) &&
2565 ff_neterrno() != AVERROR(EINTR))
2566 /* error : close connection */
2569 } else if (len == 0) {
2570 /* end of connection : close it */
2572 } else if (c->buffer_ptr - c->buffer >= 2 &&
2573 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2574 c->chunk_size = strtol(c->buffer, 0, 16);
2575 if (c->chunk_size == 0) // end of stream
2577 c->buffer_ptr = c->buffer;
2579 } else if (++loop_run > 10) {
2580 /* no chunk header, abort */
2587 if (c->buffer_end > c->buffer_ptr) {
2588 len = recv(c->fd, c->buffer_ptr,
2589 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2591 if (ff_neterrno() != AVERROR(EAGAIN) &&
2592 ff_neterrno() != AVERROR(EINTR))
2593 /* error : close connection */
2595 } else if (len == 0)
2596 /* end of connection : close it */
2599 c->chunk_size -= len;
2600 c->buffer_ptr += len;
2601 c->data_count += len;
2602 update_datarate(&c->datarate, c->data_count);
2606 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2607 if (c->buffer[0] != 'f' ||
2608 c->buffer[1] != 'm') {
2609 http_log("Feed stream has become desynchronized -- disconnecting\n");
2614 if (c->buffer_ptr >= c->buffer_end) {
2615 FFServerStream *feed = c->stream;
2616 /* a packet has been received : write it in the store, except
2618 if (c->data_count > FFM_PACKET_SIZE) {
2619 /* XXX: use llseek or url_seek
2620 * XXX: Should probably fail? */
2621 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2622 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2624 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2625 http_log("Error writing to feed file: %s\n", strerror(errno));
2629 feed->feed_write_index += FFM_PACKET_SIZE;
2630 /* update file size */
2631 if (feed->feed_write_index > c->stream->feed_size)
2632 feed->feed_size = feed->feed_write_index;
2634 /* handle wrap around if max file size reached */
2635 if (c->stream->feed_max_size &&
2636 feed->feed_write_index >= c->stream->feed_max_size)
2637 feed->feed_write_index = FFM_PACKET_SIZE;
2640 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2641 http_log("Error writing index to feed file: %s\n",
2646 /* wake up any waiting connections */
2647 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2648 if (c1->state == HTTPSTATE_WAIT_FEED &&
2649 c1->stream->feed == c->stream->feed)
2650 c1->state = HTTPSTATE_SEND_DATA;
2653 /* We have a header in our hands that contains useful data */
2654 AVFormatContext *s = avformat_alloc_context();
2656 AVInputFormat *fmt_in;
2662 /* use feed output format name to find corresponding input format */
2663 fmt_in = av_find_input_format(feed->fmt->name);
2667 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2668 0, NULL, NULL, NULL, NULL);
2675 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2680 /* Now we have the actual streams */
2681 if (s->nb_streams != feed->nb_streams) {
2682 avformat_close_input(&s);
2684 http_log("Feed '%s' stream number does not match registered feed\n",
2685 c->stream->feed_filename);
2689 for (i = 0; i < s->nb_streams; i++) {
2690 AVStream *fst = feed->streams[i];
2691 AVStream *st = s->streams[i];
2692 avcodec_copy_context(fst->codec, st->codec);
2695 avformat_close_input(&s);
2698 c->buffer_ptr = c->buffer;
2703 c->stream->feed_opened = 0;
2705 /* wake up any waiting connections to stop waiting for feed */
2706 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2707 if (c1->state == HTTPSTATE_WAIT_FEED &&
2708 c1->stream->feed == c->stream->feed)
2709 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2714 /********************************************************************/
2717 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2724 str = RTSP_STATUS_CODE2STRING(error_number);
2726 str = "Unknown Error";
2728 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2729 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2731 /* output GMT time */
2734 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2735 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2738 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2740 rtsp_reply_header(c, error_number);
2741 avio_printf(c->pb, "\r\n");
2744 static int rtsp_parse_request(HTTPContext *c)
2746 const char *p, *p1, *p2;
2752 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2754 c->buffer_ptr[0] = '\0';
2757 get_word(cmd, sizeof(cmd), &p);
2758 get_word(url, sizeof(url), &p);
2759 get_word(protocol, sizeof(protocol), &p);
2761 av_strlcpy(c->method, cmd, sizeof(c->method));
2762 av_strlcpy(c->url, url, sizeof(c->url));
2763 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2765 if (avio_open_dyn_buf(&c->pb) < 0) {
2766 /* XXX: cannot do more */
2767 c->pb = NULL; /* safety */
2771 /* check version name */
2772 if (strcmp(protocol, "RTSP/1.0")) {
2773 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2777 /* parse each header line */
2778 /* skip to next line */
2779 while (*p != '\n' && *p != '\0')
2783 while (*p != '\0') {
2784 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2788 if (p2 > p && p2[-1] == '\r')
2790 /* skip empty line */
2794 if (len > sizeof(line) - 1)
2795 len = sizeof(line) - 1;
2796 memcpy(line, p, len);
2798 ff_rtsp_parse_line(header, line, NULL, NULL);
2802 /* handle sequence number */
2803 c->seq = header->seq;
2805 if (!strcmp(cmd, "DESCRIBE"))
2806 rtsp_cmd_describe(c, url);
2807 else if (!strcmp(cmd, "OPTIONS"))
2808 rtsp_cmd_options(c, url);
2809 else if (!strcmp(cmd, "SETUP"))
2810 rtsp_cmd_setup(c, url, header);
2811 else if (!strcmp(cmd, "PLAY"))
2812 rtsp_cmd_play(c, url, header);
2813 else if (!strcmp(cmd, "PAUSE"))
2814 rtsp_cmd_interrupt(c, url, header, 1);
2815 else if (!strcmp(cmd, "TEARDOWN"))
2816 rtsp_cmd_interrupt(c, url, header, 0);
2818 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2821 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2822 c->pb = NULL; /* safety */
2824 /* XXX: cannot do more */
2827 c->buffer_ptr = c->pb_buffer;
2828 c->buffer_end = c->pb_buffer + len;
2829 c->state = RTSPSTATE_SEND_REPLY;
2833 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2834 struct in_addr my_ip)
2836 AVFormatContext *avc;
2837 AVStream *avs = NULL;
2838 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2839 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2844 avc = avformat_alloc_context();
2845 if (!avc || !rtp_format) {
2848 avc->oformat = rtp_format;
2849 av_dict_set(&avc->metadata, "title",
2850 entry ? entry->value : "No Title", 0);
2851 avc->nb_streams = stream->nb_streams;
2852 if (stream->is_multicast) {
2853 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2854 inet_ntoa(stream->multicast_ip),
2855 stream->multicast_port, stream->multicast_ttl);
2857 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2860 avc->streams = av_malloc_array(avc->nb_streams, sizeof(*avc->streams));
2864 avs = av_malloc_array(avc->nb_streams, sizeof(*avs));
2868 for(i = 0; i < stream->nb_streams; i++) {
2869 avc->streams[i] = &avs[i];
2870 avc->streams[i]->codec = stream->streams[i]->codec;
2872 *pbuffer = av_mallocz(2048);
2875 av_sdp_create(&avc, 1, *pbuffer, 2048);
2878 av_freep(&avc->streams);
2879 av_dict_free(&avc->metadata);
2883 return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2886 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2888 // rtsp_reply_header(c, RTSP_STATUS_OK);
2889 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2890 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2891 avio_printf(c->pb, "Public: %s\r\n",
2892 "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2893 avio_printf(c->pb, "\r\n");
2896 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2898 FFServerStream *stream;
2904 struct sockaddr_in my_addr;
2906 /* find which URL is asked */
2907 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2912 for(stream = config.first_stream; stream; stream = stream->next) {
2913 if (!stream->is_feed &&
2914 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2915 !strcmp(path, stream->filename)) {
2919 /* no stream found */
2920 rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
2924 /* prepare the media description in SDP format */
2926 /* get the host IP */
2927 len = sizeof(my_addr);
2928 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2929 content_length = prepare_sdp_description(stream, &content,
2931 if (content_length < 0) {
2932 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2935 rtsp_reply_header(c, RTSP_STATUS_OK);
2936 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2937 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2938 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2939 avio_printf(c->pb, "\r\n");
2940 avio_write(c->pb, content, content_length);
2944 static HTTPContext *find_rtp_session(const char *session_id)
2948 if (session_id[0] == '\0')
2951 for(c = first_http_ctx; c; c = c->next) {
2952 if (!strcmp(c->session_id, session_id))
2958 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2960 RTSPTransportField *th;
2963 for(i=0;i<h->nb_transports;i++) {
2964 th = &h->transports[i];
2965 if (th->lower_transport == lower_transport)
2971 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2972 RTSPMessageHeader *h)
2974 FFServerStream *stream;
2975 int stream_index, rtp_port, rtcp_port;
2980 RTSPTransportField *th;
2981 struct sockaddr_in dest_addr;
2982 RTSPActionServerSetup setup;
2984 /* find which URL is asked */
2985 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2990 /* now check each stream */
2991 for(stream = config.first_stream; stream; stream = stream->next) {
2992 if (stream->is_feed || !stream->fmt ||
2993 strcmp(stream->fmt->name, "rtp")) {
2996 /* accept aggregate filenames only if single stream */
2997 if (!strcmp(path, stream->filename)) {
2998 if (stream->nb_streams != 1) {
2999 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3006 for(stream_index = 0; stream_index < stream->nb_streams;
3008 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3009 stream->filename, stream_index);
3010 if (!strcmp(path, buf))
3014 /* no stream found */
3015 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3019 /* generate session id if needed */
3020 if (h->session_id[0] == '\0') {
3021 unsigned random0 = av_lfg_get(&random_state);
3022 unsigned random1 = av_lfg_get(&random_state);
3023 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3027 /* find RTP session, and create it if none found */
3028 rtp_c = find_rtp_session(h->session_id);
3030 /* always prefer UDP */
3031 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3033 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3035 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3040 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3041 th->lower_transport);
3043 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3047 /* open input stream */
3048 if (open_input_stream(rtp_c, "") < 0) {
3049 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3054 /* test if stream is OK (test needed because several SETUP needs
3055 to be done for a given file) */
3056 if (rtp_c->stream != stream) {
3057 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3061 /* test if stream is already set up */
3062 if (rtp_c->rtp_ctx[stream_index]) {
3063 rtsp_reply_error(c, RTSP_STATUS_STATE);
3067 /* check transport */
3068 th = find_transport(h, rtp_c->rtp_protocol);
3069 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3070 th->client_port_min <= 0)) {
3071 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3075 /* setup default options */
3076 setup.transport_option[0] = '\0';
3077 dest_addr = rtp_c->from_addr;
3078 dest_addr.sin_port = htons(th->client_port_min);
3081 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3082 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3086 /* now everything is OK, so we can send the connection parameters */
3087 rtsp_reply_header(c, RTSP_STATUS_OK);
3089 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3091 switch(rtp_c->rtp_protocol) {
3092 case RTSP_LOWER_TRANSPORT_UDP:
3093 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3094 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3095 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3096 "client_port=%d-%d;server_port=%d-%d",
3097 th->client_port_min, th->client_port_max,
3098 rtp_port, rtcp_port);
3100 case RTSP_LOWER_TRANSPORT_TCP:
3101 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3102 stream_index * 2, stream_index * 2 + 1);
3107 if (setup.transport_option[0] != '\0')
3108 avio_printf(c->pb, ";%s", setup.transport_option);
3109 avio_printf(c->pb, "\r\n");
3112 avio_printf(c->pb, "\r\n");
3116 /* find an RTP connection by using the session ID. Check consistency
3118 static HTTPContext *find_rtp_session_with_url(const char *url,
3119 const char *session_id)
3127 rtp_c = find_rtp_session(session_id);
3131 /* find which URL is asked */
3132 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3136 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3137 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3138 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3139 rtp_c->stream->filename, s);
3140 if(!strncmp(path, buf, sizeof(buf))) {
3141 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3146 if (len > 0 && path[len - 1] == '/' &&
3147 !strncmp(path, rtp_c->stream->filename, len - 1))
3152 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3156 rtp_c = find_rtp_session_with_url(url, h->session_id);
3158 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3162 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3163 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3164 rtp_c->state != HTTPSTATE_READY) {
3165 rtsp_reply_error(c, RTSP_STATUS_STATE);
3169 rtp_c->state = HTTPSTATE_SEND_DATA;
3171 /* now everything is OK, so we can send the connection parameters */
3172 rtsp_reply_header(c, RTSP_STATUS_OK);
3174 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3175 avio_printf(c->pb, "\r\n");
3178 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
3179 RTSPMessageHeader *h, int pause_only)
3183 rtp_c = find_rtp_session_with_url(url, h->session_id);
3185 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3190 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3191 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3192 rtsp_reply_error(c, RTSP_STATUS_STATE);
3195 rtp_c->state = HTTPSTATE_READY;
3196 rtp_c->first_pts = AV_NOPTS_VALUE;
3199 /* now everything is OK, so we can send the connection parameters */
3200 rtsp_reply_header(c, RTSP_STATUS_OK);
3202 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3203 avio_printf(c->pb, "\r\n");
3206 close_connection(rtp_c);
3209 /********************************************************************/
3212 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3213 FFServerStream *stream,
3214 const char *session_id,
3215 enum RTSPLowerTransport rtp_protocol)
3217 HTTPContext *c = NULL;
3218 const char *proto_str;
3220 /* XXX: should output a warning page when coming
3221 close to the connection limit */
3222 if (nb_connections >= config.nb_max_connections)
3225 /* add a new connection */
3226 c = av_mallocz(sizeof(HTTPContext));
3231 c->poll_entry = NULL;
3232 c->from_addr = *from_addr;
3233 c->buffer_size = IOBUFFER_INIT_SIZE;
3234 c->buffer = av_malloc(c->buffer_size);
3239 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3240 c->state = HTTPSTATE_READY;
3241 c->is_packetized = 1;
3242 c->rtp_protocol = rtp_protocol;
3244 /* protocol is shown in statistics */
3245 switch(c->rtp_protocol) {
3246 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3247 proto_str = "MCAST";
3249 case RTSP_LOWER_TRANSPORT_UDP:
3252 case RTSP_LOWER_TRANSPORT_TCP:
3259 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3260 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3262 current_bandwidth += stream->bandwidth;
3264 c->next = first_http_ctx;
3270 av_freep(&c->buffer);
3276 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3277 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3279 static int rtp_new_av_stream(HTTPContext *c,
3280 int stream_index, struct sockaddr_in *dest_addr,
3281 HTTPContext *rtsp_c)
3283 AVFormatContext *ctx;
3286 URLContext *h = NULL;
3288 int max_packet_size;
3290 /* now we can open the relevant output stream */
3291 ctx = avformat_alloc_context();
3294 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3296 st = av_mallocz(sizeof(AVStream));
3299 ctx->nb_streams = 1;
3300 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3303 ctx->streams[0] = st;
3305 if (!c->stream->feed ||
3306 c->stream->feed == c->stream)
3307 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3310 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3312 st->priv_data = NULL;
3314 /* build destination RTP address */
3315 ipaddr = inet_ntoa(dest_addr->sin_addr);
3317 switch(c->rtp_protocol) {
3318 case RTSP_LOWER_TRANSPORT_UDP:
3319 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3322 /* XXX: also pass as parameter to function ? */
3323 if (c->stream->is_multicast) {
3325 ttl = c->stream->multicast_ttl;
3328 snprintf(ctx->filename, sizeof(ctx->filename),
3329 "rtp://%s:%d?multicast=1&ttl=%d",
3330 ipaddr, ntohs(dest_addr->sin_port), ttl);
3332 snprintf(ctx->filename, sizeof(ctx->filename),
3333 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3336 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3338 c->rtp_handles[stream_index] = h;
3339 max_packet_size = h->max_packet_size;
3341 case RTSP_LOWER_TRANSPORT_TCP:
3344 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3350 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3351 ipaddr, ntohs(dest_addr->sin_port),
3352 c->stream->filename, stream_index, c->protocol);
3354 /* normally, no packets should be output here, but the packet size may
3356 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3357 /* XXX: close stream */
3360 if (avformat_write_header(ctx, NULL) < 0) {
3368 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3371 c->rtp_ctx[stream_index] = ctx;
3375 /********************************************************************/
3376 /* ffserver initialization */
3378 static AVStream *add_av_stream1(FFServerStream *stream,
3379 AVCodecContext *codec, int copy)
3383 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3386 fst = av_mallocz(sizeof(AVStream));
3390 fst->codec = avcodec_alloc_context3(codec->codec);
3395 avcodec_copy_context(fst->codec, codec);
3397 /* live streams must use the actual feed's codec since it may be
3398 * updated later to carry extradata needed by them.
3402 fst->priv_data = av_mallocz(sizeof(FeedData));
3403 fst->index = stream->nb_streams;
3404 avpriv_set_pts_info(fst, 33, 1, 90000);
3405 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3406 stream->streams[stream->nb_streams++] = fst;
3410 /* return the stream number in the feed */
3411 static int add_av_stream(FFServerStream *feed, AVStream *st)
3414 AVCodecContext *av, *av1;
3418 for(i=0;i<feed->nb_streams;i++) {
3419 av1 = feed->streams[i]->codec;
3420 if (av1->codec_id == av->codec_id &&
3421 av1->codec_type == av->codec_type &&
3422 av1->bit_rate == av->bit_rate) {
3424 switch(av->codec_type) {
3425 case AVMEDIA_TYPE_AUDIO:
3426 if (av1->channels == av->channels &&
3427 av1->sample_rate == av->sample_rate)
3430 case AVMEDIA_TYPE_VIDEO:
3431 if (av1->width == av->width &&
3432 av1->height == av->height &&
3433 av1->time_base.den == av->time_base.den &&
3434 av1->time_base.num == av->time_base.num &&
3435 av1->gop_size == av->gop_size)
3444 fst = add_av_stream1(feed, av, 0);
3447 if (av_stream_get_recommended_encoder_configuration(st))
3448 av_stream_set_recommended_encoder_configuration(fst,
3449 av_strdup(av_stream_get_recommended_encoder_configuration(st)));
3450 return feed->nb_streams - 1;
3453 static void remove_stream(FFServerStream *stream)
3455 FFServerStream **ps;
3456 ps = &config.first_stream;
3465 /* specific MPEG4 handling : we extract the raw parameters */
3466 static void extract_mpeg4_header(AVFormatContext *infile)
3468 int mpeg4_count, i, size;
3473 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3476 for(i=0;i<infile->nb_streams;i++) {
3477 st = infile->streams[i];
3478 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3479 st->codec->extradata_size == 0) {
3486 printf("MPEG4 without extra data: trying to find header in %s\n",
3488 while (mpeg4_count > 0) {
3489 if (av_read_frame(infile, &pkt) < 0)
3491 st = infile->streams[pkt.stream_index];
3492 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3493 st->codec->extradata_size == 0) {
3494 av_freep(&st->codec->extradata);
3495 /* fill extradata with the header */
3496 /* XXX: we make hard suppositions here ! */
3498 while (p < pkt.data + pkt.size - 4) {
3499 /* stop when vop header is found */
3500 if (p[0] == 0x00 && p[1] == 0x00 &&
3501 p[2] == 0x01 && p[3] == 0xb6) {
3502 size = p - pkt.data;
3503 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3504 st->codec->extradata_size = size;
3505 memcpy(st->codec->extradata, pkt.data, size);
3512 av_free_packet(&pkt);
3516 /* compute the needed AVStream for each file */
3517 static void build_file_streams(void)
3519 FFServerStream *stream, *stream_next;
3522 /* gather all streams */
3523 for(stream = config.first_stream; stream; stream = stream_next) {
3524 AVFormatContext *infile = NULL;
3525 stream_next = stream->next;
3526 if (stream->stream_type == STREAM_TYPE_LIVE &&
3528 /* the stream comes from a file */
3529 /* try to open the file */
3531 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3532 /* specific case : if transport stream output to RTP,
3533 we use a raw transport stream reader */
3534 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3537 if (!stream->feed_filename[0]) {
3538 http_log("Unspecified feed file for stream '%s'\n",
3543 http_log("Opening feed file '%s' for stream '%s'\n",
3544 stream->feed_filename, stream->filename);
3545 ret = avformat_open_input(&infile, stream->feed_filename,
3546 stream->ifmt, &stream->in_opts);
3548 http_log("Could not open '%s': %s\n", stream->feed_filename,
3550 /* remove stream (no need to spend more time on it) */
3552 remove_stream(stream);
3554 /* find all the AVStreams inside and reference them in
3556 if (avformat_find_stream_info(infile, NULL) < 0) {
3557 http_log("Could not find codec parameters from '%s'\n",
3558 stream->feed_filename);
3559 avformat_close_input(&infile);
3562 extract_mpeg4_header(infile);
3564 for(i=0;i<infile->nb_streams;i++)
3565 add_av_stream1(stream, infile->streams[i]->codec, 1);
3567 avformat_close_input(&infile);
3573 /* compute the needed AVStream for each feed */
3574 static void build_feed_streams(void)
3576 FFServerStream *stream, *feed;
3579 /* gather all streams */
3580 for(stream = config.first_stream; stream; stream = stream->next) {
3581 feed = stream->feed;
3583 if (stream->is_feed) {
3584 for(i=0;i<stream->nb_streams;i++)
3585 stream->feed_streams[i] = i;
3587 /* we handle a stream coming from a feed */
3588 for(i=0;i<stream->nb_streams;i++)
3589 stream->feed_streams[i] = add_av_stream(feed,
3590 stream->streams[i]);
3595 /* create feed files if needed */
3596 for(feed = config.first_feed; feed; feed = feed->next_feed) {
3599 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3600 /* See if it matches */
3601 AVFormatContext *s = NULL;
3604 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3605 /* set buffer size */
3606 int ret = ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3608 http_log("Failed to set buffer size\n");
3612 /* Now see if it matches */
3613 if (s->nb_streams == feed->nb_streams) {
3615 for(i=0;i<s->nb_streams;i++) {
3617 sf = feed->streams[i];
3620 if (sf->index != ss->index ||
3622 http_log("Index & Id do not match for stream %d (%s)\n",
3623 i, feed->feed_filename);
3626 AVCodecContext *ccf, *ccs;
3630 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3632 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3633 http_log("Codecs do not match for stream %d\n", i);
3635 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3636 http_log("Codec bitrates do not match for stream %d\n", i);
3638 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3639 if (CHECK_CODEC(time_base.den) ||
3640 CHECK_CODEC(time_base.num) ||
3641 CHECK_CODEC(width) ||
3642 CHECK_CODEC(height)) {
3643 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3646 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3647 if (CHECK_CODEC(sample_rate) ||
3648 CHECK_CODEC(channels) ||
3649 CHECK_CODEC(frame_size)) {
3650 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3654 http_log("Unknown codec type\n");
3662 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3663 feed->feed_filename, s->nb_streams, feed->nb_streams);
3665 avformat_close_input(&s);
3667 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3668 feed->feed_filename);
3671 if (feed->readonly) {
3672 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3673 feed->feed_filename);
3676 unlink(feed->feed_filename);
3679 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3680 AVFormatContext *s = avformat_alloc_context();
3683 http_log("Failed to allocate context\n");
3687 if (feed->readonly) {
3688 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3689 feed->feed_filename);
3693 /* only write the header of the ffm file */
3694 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3695 http_log("Could not open output feed file '%s'\n",
3696 feed->feed_filename);
3699 s->oformat = feed->fmt;
3700 s->nb_streams = feed->nb_streams;
3701 s->streams = feed->streams;
3702 if (avformat_write_header(s, NULL) < 0) {
3703 http_log("Container doesn't support the required parameters\n");
3706 /* XXX: need better API */
3707 av_freep(&s->priv_data);
3708 avio_closep(&s->pb);
3711 avformat_free_context(s);
3713 /* get feed size and write index */
3714 fd = open(feed->feed_filename, O_RDONLY);
3716 http_log("Could not open output feed file '%s'\n",
3717 feed->feed_filename);
3721 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3722 feed->feed_size = lseek(fd, 0, SEEK_END);
3723 /* ensure that we do not wrap before the end of file */
3724 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3725 feed->feed_max_size = feed->feed_size;
3731 /* compute the bandwidth used by each stream */
3732 static void compute_bandwidth(void)
3736 FFServerStream *stream;
3738 for(stream = config.first_stream; stream; stream = stream->next) {
3740 for(i=0;i<stream->nb_streams;i++) {
3741 AVStream *st = stream->streams[i];
3742 switch(st->codec->codec_type) {
3743 case AVMEDIA_TYPE_AUDIO:
3744 case AVMEDIA_TYPE_VIDEO:
3745 bandwidth += st->codec->bit_rate;
3751 stream->bandwidth = (bandwidth + 999) / 1000;
3755 static void handle_child_exit(int sig)
3760 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3761 FFServerStream *feed;
3763 for (feed = config.first_feed; feed; feed = feed->next) {
3764 if (feed->pid == pid) {
3765 int uptime = time(0) - feed->pid_start;
3769 "%s: Pid %d exited with status %d after %d seconds\n",
3770 feed->filename, pid, status, uptime);
3773 /* Turn off any more restarts */
3774 ffserver_free_child_args(&feed->child_argv);
3779 need_to_start_children = 1;
3782 static void opt_debug(void)
3785 snprintf(config.logfilename, sizeof(config.logfilename), "-");
3788 void show_help_default(const char *opt, const char *arg)
3790 printf("usage: ffserver [options]\n"
3791 "Hyper fast multi format Audio/Video streaming server\n");
3793 show_help_options(options, "Main options:", 0, 0, 0);
3796 static const OptionDef options[] = {
3797 #include "cmdutils_common_opts.h"
3798 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3799 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3800 { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3804 int main(int argc, char **argv)
3806 struct sigaction sigact = { { 0 } };
3809 config.filename = av_strdup("/etc/ffserver.conf");
3811 parse_loglevel(argc, argv, options);
3813 avformat_network_init();
3815 show_banner(argc, argv, options);
3817 my_program_name = argv[0];
3819 parse_options(NULL, argc, argv, options, NULL);
3821 unsetenv("http_proxy"); /* Kill the http_proxy */
3823 av_lfg_init(&random_state, av_get_random_seed());
3825 sigact.sa_handler = handle_child_exit;
3826 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3827 sigaction(SIGCHLD, &sigact, 0);
3829 if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3830 fprintf(stderr, "Error reading configuration file '%s': %s\n",
3831 config.filename, av_err2str(ret));
3834 av_freep(&config.filename);
3836 /* open log file if needed */
3837 if (config.logfilename[0] != '\0') {
3838 if (!strcmp(config.logfilename, "-"))
3841 logfile = fopen(config.logfilename, "a");
3842 av_log_set_callback(http_av_log);
3845 build_file_streams();
3847 build_feed_streams();
3849 compute_bandwidth();
3852 signal(SIGPIPE, SIG_IGN);
3854 if (http_server() < 0) {
3855 http_log("Could not start server\n");