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 int http_parse_request(HTTPContext *c);
213 static int http_send_data(HTTPContext *c);
214 static void compute_status(HTTPContext *c);
215 static int open_input_stream(HTTPContext *c, const char *info);
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;
320 ctime1(buf, sizeof(buf));
321 fprintf(logfile, "%s ", buf);
323 print_prefix = strstr(fmt, "\n") != NULL;
324 vfprintf(logfile, fmt, vargs);
330 __attribute__ ((format (printf, 1, 2)))
332 static void http_log(const char *fmt, ...)
335 va_start(vargs, fmt);
336 http_vlog(fmt, vargs);
340 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
342 static int print_prefix = 1;
343 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
344 if (level > av_log_get_level())
346 if (print_prefix && avc)
347 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
348 print_prefix = strstr(fmt, "\n") != NULL;
349 http_vlog(fmt, vargs);
352 static void log_connection(HTTPContext *c)
357 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
358 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
359 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
362 static void update_datarate(DataRateData *drd, int64_t count)
364 if (!drd->time1 && !drd->count1) {
365 drd->time1 = drd->time2 = cur_time;
366 drd->count1 = drd->count2 = count;
367 } else if (cur_time - drd->time2 > 5000) {
368 drd->time1 = drd->time2;
369 drd->count1 = drd->count2;
370 drd->time2 = cur_time;
375 /* In bytes per second */
376 static int compute_datarate(DataRateData *drd, int64_t count)
378 if (cur_time == drd->time1)
381 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
385 static void start_children(FFServerStream *feed)
394 /* replace "ffserver" with "ffmpeg" in the path of current
395 * program. Ignore user provided path */
396 av_strlcpy(pathname, my_program_name, sizeof(pathname));
398 slash = strrchr(pathname, '/');
403 strcpy(slash, "ffmpeg");
405 for (; feed; feed = feed->next) {
407 if (!feed->child_argv || feed->pid)
410 feed->pid_start = time(0);
414 http_log("Unable to create children\n");
423 http_log("Launch command line: ");
424 http_log("%s ", pathname);
426 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
427 http_log("%s ", feed->child_argv[i]);
430 for (i = 3; i < 256; i++)
434 if (!freopen("/dev/null", "r", stdin))
435 http_log("failed to redirect STDIN to /dev/null\n;");
436 if (!freopen("/dev/null", "w", stdout))
437 http_log("failed to redirect STDOUT to /dev/null\n;");
438 if (!freopen("/dev/null", "w", stderr))
439 http_log("failed to redirect STDERR to /dev/null\n;");
442 signal(SIGPIPE, SIG_DFL);
443 execvp(pathname, feed->child_argv);
448 /* open a listening socket */
449 static int socket_open_listen(struct sockaddr_in *my_addr)
453 server_fd = socket(AF_INET,SOCK_STREAM,0);
460 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)))
461 av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n");
463 my_addr->sin_family = AF_INET;
464 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
466 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
468 closesocket(server_fd);
472 if (listen (server_fd, 5) < 0) {
474 closesocket(server_fd);
478 if (ff_socket_nonblock(server_fd, 1) < 0)
479 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
484 /* start all multicast streams */
485 static void start_multicast(void)
487 FFServerStream *stream;
490 struct sockaddr_in dest_addr = {0};
491 int default_port, stream_index;
492 unsigned int random0, random1;
495 for(stream = config.first_stream; stream; stream = stream->next) {
497 if (!stream->is_multicast)
500 random0 = av_lfg_get(&random_state);
501 random1 = av_lfg_get(&random_state);
503 /* open the RTP connection */
504 snprintf(session_id, sizeof(session_id), "%08x%08x",
507 /* choose a port if none given */
508 if (stream->multicast_port == 0) {
509 stream->multicast_port = default_port;
513 dest_addr.sin_family = AF_INET;
514 dest_addr.sin_addr = stream->multicast_ip;
515 dest_addr.sin_port = htons(stream->multicast_port);
517 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
518 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
522 if (open_input_stream(rtp_c, "") < 0) {
523 http_log("Could not open input stream for stream '%s'\n",
528 /* open each RTP stream */
529 for(stream_index = 0; stream_index < stream->nb_streams;
531 dest_addr.sin_port = htons(stream->multicast_port +
533 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) >= 0)
536 http_log("Could not open output stream '%s/streamid=%d'\n",
537 stream->filename, stream_index);
541 rtp_c->state = HTTPSTATE_SEND_DATA;
545 /* main loop of the HTTP server */
546 static int http_server(void)
548 int server_fd = 0, rtsp_server_fd = 0;
550 struct pollfd *poll_table, *poll_entry;
551 HTTPContext *c, *c_next;
553 poll_table = av_mallocz_array(config.nb_max_http_connections + 2,
554 sizeof(*poll_table));
556 http_log("Impossible to allocate a poll table handling %d "
557 "connections.\n", config.nb_max_http_connections);
561 if (config.http_addr.sin_port) {
562 server_fd = socket_open_listen(&config.http_addr);
569 if (config.rtsp_addr.sin_port) {
570 rtsp_server_fd = socket_open_listen(&config.rtsp_addr);
571 if (rtsp_server_fd < 0) {
573 closesocket(server_fd);
578 if (!rtsp_server_fd && !server_fd) {
579 http_log("HTTP and RTSP disabled.\n");
584 http_log("FFserver started.\n");
586 start_children(config.first_feed);
591 poll_entry = poll_table;
593 poll_entry->fd = server_fd;
594 poll_entry->events = POLLIN;
597 if (rtsp_server_fd) {
598 poll_entry->fd = rtsp_server_fd;
599 poll_entry->events = POLLIN;
603 /* wait for events on each HTTP handle */
610 case HTTPSTATE_SEND_HEADER:
611 case RTSPSTATE_SEND_REPLY:
612 case RTSPSTATE_SEND_PACKET:
613 c->poll_entry = poll_entry;
615 poll_entry->events = POLLOUT;
618 case HTTPSTATE_SEND_DATA_HEADER:
619 case HTTPSTATE_SEND_DATA:
620 case HTTPSTATE_SEND_DATA_TRAILER:
621 if (!c->is_packetized) {
622 /* for TCP, we output as much as we can
623 * (may need to put a limit) */
624 c->poll_entry = poll_entry;
626 poll_entry->events = POLLOUT;
629 /* when ffserver is doing the timing, we work by
630 looking at which packet needs to be sent every
632 /* one tick wait XXX: 10 ms assumed */
637 case HTTPSTATE_WAIT_REQUEST:
638 case HTTPSTATE_RECEIVE_DATA:
639 case HTTPSTATE_WAIT_FEED:
640 case RTSPSTATE_WAIT_REQUEST:
641 /* need to catch errors */
642 c->poll_entry = poll_entry;
644 poll_entry->events = POLLIN;/* Maybe this will work */
648 c->poll_entry = NULL;
654 /* wait for an event on one connection. We poll at least every
655 second to handle timeouts */
657 ret = poll(poll_table, poll_entry - poll_table, delay);
658 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
659 ff_neterrno() != AVERROR(EINTR)) {
665 cur_time = av_gettime() / 1000;
667 if (need_to_start_children) {
668 need_to_start_children = 0;
669 start_children(config.first_feed);
672 /* now handle the events */
673 for(c = first_http_ctx; c; c = c_next) {
675 if (handle_connection(c) < 0) {
677 /* close and free the connection */
682 poll_entry = poll_table;
684 /* new HTTP connection request ? */
685 if (poll_entry->revents & POLLIN)
686 new_connection(server_fd, 0);
689 if (rtsp_server_fd) {
690 /* new RTSP connection request ? */
691 if (poll_entry->revents & POLLIN)
692 new_connection(rtsp_server_fd, 1);
697 /* start waiting for a new HTTP/RTSP request */
698 static void start_wait_request(HTTPContext *c, int is_rtsp)
700 c->buffer_ptr = c->buffer;
701 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
704 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
705 c->state = RTSPSTATE_WAIT_REQUEST;
707 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
708 c->state = HTTPSTATE_WAIT_REQUEST;
712 static void http_send_too_busy_reply(int fd)
715 int len = snprintf(buffer, sizeof(buffer),
716 "HTTP/1.0 503 Server too busy\r\n"
717 "Content-type: text/html\r\n"
719 "<html><head><title>Too busy</title></head><body>\r\n"
720 "<p>The server is too busy to serve your request at this time.</p>\r\n"
721 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
722 "</body></html>\r\n",
723 nb_connections, config.nb_max_connections);
724 av_assert0(len < sizeof(buffer));
725 if (send(fd, buffer, len, 0) < len)
726 av_log(NULL, AV_LOG_WARNING, "Could not send too-busy reply, send() failed\n");
730 static void new_connection(int server_fd, int is_rtsp)
732 struct sockaddr_in from_addr;
735 HTTPContext *c = NULL;
737 len = sizeof(from_addr);
738 fd = accept(server_fd, (struct sockaddr *)&from_addr,
741 http_log("error during accept %s\n", strerror(errno));
744 if (ff_socket_nonblock(fd, 1) < 0)
745 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
747 if (nb_connections >= config.nb_max_connections) {
748 http_send_too_busy_reply(fd);
752 /* add a new connection */
753 c = av_mallocz(sizeof(HTTPContext));
758 c->poll_entry = NULL;
759 c->from_addr = from_addr;
760 c->buffer_size = IOBUFFER_INIT_SIZE;
761 c->buffer = av_malloc(c->buffer_size);
765 c->next = first_http_ctx;
769 start_wait_request(c, is_rtsp);
775 av_freep(&c->buffer);
781 static void close_connection(HTTPContext *c)
783 HTTPContext **cp, *c1;
785 AVFormatContext *ctx;
789 /* remove connection from list */
790 cp = &first_http_ctx;
799 /* remove references, if any (XXX: do it faster) */
800 for(c1 = first_http_ctx; c1; c1 = c1->next) {
805 /* remove connection associated resources */
809 /* close each frame parser */
810 for(i=0;i<c->fmt_in->nb_streams;i++) {
811 st = c->fmt_in->streams[i];
812 if (st->codec->codec)
813 avcodec_close(st->codec);
815 avformat_close_input(&c->fmt_in);
818 /* free RTP output streams if any */
821 nb_streams = c->stream->nb_streams;
823 for(i=0;i<nb_streams;i++) {
826 av_write_trailer(ctx);
827 av_dict_free(&ctx->metadata);
828 av_freep(&ctx->streams[0]);
831 h = c->rtp_handles[i];
838 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
840 if (ctx->oformat && avio_open_dyn_buf(&ctx->pb) >= 0) {
841 av_write_trailer(ctx);
842 av_freep(&c->pb_buffer);
843 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
847 for(i=0; i<ctx->nb_streams; i++)
848 av_freep(&ctx->streams[i]);
849 av_freep(&ctx->streams);
850 av_freep(&ctx->priv_data);
852 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
853 current_bandwidth -= c->stream->bandwidth;
855 /* signal that there is no feed if we are the feeder socket */
856 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
857 c->stream->feed_opened = 0;
861 av_freep(&c->pb_buffer);
862 av_freep(&c->packet_buffer);
863 av_freep(&c->buffer);
868 static int handle_connection(HTTPContext *c)
873 case HTTPSTATE_WAIT_REQUEST:
874 case RTSPSTATE_WAIT_REQUEST:
876 if ((c->timeout - cur_time) < 0)
878 if (c->poll_entry->revents & (POLLERR | POLLHUP))
881 /* no need to read if no events */
882 if (!(c->poll_entry->revents & POLLIN))
886 len = recv(c->fd, c->buffer_ptr, 1, 0);
888 if (ff_neterrno() != AVERROR(EAGAIN) &&
889 ff_neterrno() != AVERROR(EINTR))
891 } else if (len == 0) {
894 /* search for end of request. */
896 c->buffer_ptr += len;
898 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
899 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
900 /* request found : parse it and reply */
901 if (c->state == HTTPSTATE_WAIT_REQUEST) {
902 ret = http_parse_request(c);
904 ret = rtsp_parse_request(c);
908 } else if (ptr >= c->buffer_end) {
909 /* request too long: cannot do anything */
911 } else goto read_loop;
915 case HTTPSTATE_SEND_HEADER:
916 if (c->poll_entry->revents & (POLLERR | POLLHUP))
919 /* no need to write if no events */
920 if (!(c->poll_entry->revents & POLLOUT))
922 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
924 if (ff_neterrno() != AVERROR(EAGAIN) &&
925 ff_neterrno() != AVERROR(EINTR)) {
926 goto close_connection;
929 c->buffer_ptr += len;
931 c->stream->bytes_served += len;
932 c->data_count += len;
933 if (c->buffer_ptr >= c->buffer_end) {
934 av_freep(&c->pb_buffer);
938 /* all the buffer was sent : synchronize to the incoming
940 c->state = HTTPSTATE_SEND_DATA_HEADER;
941 c->buffer_ptr = c->buffer_end = c->buffer;
946 case HTTPSTATE_SEND_DATA:
947 case HTTPSTATE_SEND_DATA_HEADER:
948 case HTTPSTATE_SEND_DATA_TRAILER:
949 /* for packetized output, we consider we can always write (the
950 input streams set the speed). It may be better to verify
951 that we do not rely too much on the kernel queues */
952 if (!c->is_packetized) {
953 if (c->poll_entry->revents & (POLLERR | POLLHUP))
956 /* no need to read if no events */
957 if (!(c->poll_entry->revents & POLLOUT))
960 if (http_send_data(c) < 0)
962 /* close connection if trailer sent */
963 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
966 case HTTPSTATE_RECEIVE_DATA:
967 /* no need to read if no events */
968 if (c->poll_entry->revents & (POLLERR | POLLHUP))
970 if (!(c->poll_entry->revents & POLLIN))
972 if (http_receive_data(c) < 0)
975 case HTTPSTATE_WAIT_FEED:
976 /* no need to read if no events */
977 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
980 /* nothing to do, we'll be waken up by incoming feed packets */
983 case RTSPSTATE_SEND_REPLY:
984 if (c->poll_entry->revents & (POLLERR | POLLHUP))
985 goto close_connection;
986 /* no need to write if no events */
987 if (!(c->poll_entry->revents & POLLOUT))
989 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
991 if (ff_neterrno() != AVERROR(EAGAIN) &&
992 ff_neterrno() != AVERROR(EINTR)) {
993 goto close_connection;
996 c->buffer_ptr += len;
997 c->data_count += len;
998 if (c->buffer_ptr >= c->buffer_end) {
999 /* all the buffer was sent : wait for a new request */
1000 av_freep(&c->pb_buffer);
1001 start_wait_request(c, 1);
1005 case RTSPSTATE_SEND_PACKET:
1006 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1007 av_freep(&c->packet_buffer);
1010 /* no need to write if no events */
1011 if (!(c->poll_entry->revents & POLLOUT))
1013 len = send(c->fd, c->packet_buffer_ptr,
1014 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1016 if (ff_neterrno() != AVERROR(EAGAIN) &&
1017 ff_neterrno() != AVERROR(EINTR)) {
1018 /* error : close connection */
1019 av_freep(&c->packet_buffer);
1023 c->packet_buffer_ptr += len;
1024 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1025 /* all the buffer was sent : wait for a new request */
1026 av_freep(&c->packet_buffer);
1027 c->state = RTSPSTATE_WAIT_REQUEST;
1031 case HTTPSTATE_READY:
1040 av_freep(&c->pb_buffer);
1044 static int extract_rates(char *rates, int ratelen, const char *request)
1048 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1049 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1050 const char *q = p + 7;
1052 while (*q && *q != '\n' && av_isspace(*q))
1055 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1061 memset(rates, 0xff, ratelen);
1064 while (*q && *q != '\n' && *q != ':')
1067 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1071 if (stream_no < ratelen && stream_no >= 0)
1072 rates[stream_no] = rate_no;
1074 while (*q && *q != '\n' && !av_isspace(*q))
1081 p = strchr(p, '\n');
1091 static int find_stream_in_feed(FFServerStream *feed, AVCodecContext *codec, int bit_rate)
1094 int best_bitrate = 100000000;
1097 for (i = 0; i < feed->nb_streams; i++) {
1098 AVCodecContext *feed_codec = feed->streams[i]->codec;
1100 if (feed_codec->codec_id != codec->codec_id ||
1101 feed_codec->sample_rate != codec->sample_rate ||
1102 feed_codec->width != codec->width ||
1103 feed_codec->height != codec->height)
1106 /* Potential stream */
1108 /* We want the fastest stream less than bit_rate, or the slowest
1109 * faster than bit_rate
1112 if (feed_codec->bit_rate <= bit_rate) {
1113 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1114 best_bitrate = feed_codec->bit_rate;
1118 if (feed_codec->bit_rate < best_bitrate) {
1119 best_bitrate = feed_codec->bit_rate;
1128 static int modify_current_stream(HTTPContext *c, char *rates)
1131 FFServerStream *req = c->stream;
1132 int action_required = 0;
1134 /* Not much we can do for a feed */
1138 for (i = 0; i < req->nb_streams; i++) {
1139 AVCodecContext *codec = req->streams[i]->codec;
1143 c->switch_feed_streams[i] = req->feed_streams[i];
1146 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1149 /* Wants off or slow */
1150 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1152 /* This doesn't work well when it turns off the only stream! */
1153 c->switch_feed_streams[i] = -2;
1154 c->feed_streams[i] = -2;
1159 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1160 action_required = 1;
1163 return action_required;
1166 static void get_word(char *buf, int buf_size, const char **pp)
1172 p += strspn(p, SPACE_CHARS);
1174 while (!av_isspace(*p) && *p != '\0') {
1175 if ((q - buf) < buf_size - 1)
1184 static FFServerIPAddressACL* parse_dynamic_acl(FFServerStream *stream, HTTPContext *c)
1189 FFServerIPAddressACL *acl = NULL;
1193 f = fopen(stream->dynamic_acl, "r");
1195 perror(stream->dynamic_acl);
1199 acl = av_mallocz(sizeof(FFServerIPAddressACL));
1202 while (fgets(line, sizeof(line), f)) {
1205 while (av_isspace(*p))
1207 if (*p == '\0' || *p == '#')
1209 ffserver_get_arg(cmd, sizeof(cmd), &p);
1211 if (!av_strcasecmp(cmd, "ACL"))
1212 ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1219 static void free_acl_list(FFServerIPAddressACL *in_acl)
1221 FFServerIPAddressACL *pacl, *pacl2;
1231 static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c)
1233 enum FFServerIPAddressAction last_action = IP_DENY;
1234 FFServerIPAddressACL *acl;
1235 struct in_addr *src = &c->from_addr.sin_addr;
1236 unsigned long src_addr = src->s_addr;
1238 for (acl = in_acl; acl; acl = acl->next) {
1239 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1240 return (acl->action == IP_ALLOW) ? 1 : 0;
1241 last_action = acl->action;
1244 /* Nothing matched, so return not the last action */
1245 return (last_action == IP_DENY) ? 1 : 0;
1248 static int validate_acl(FFServerStream *stream, HTTPContext *c)
1251 FFServerIPAddressACL *acl;
1253 /* if stream->acl is null validate_acl_list will return 1 */
1254 ret = validate_acl_list(stream->acl, c);
1256 if (stream->dynamic_acl[0]) {
1257 acl = parse_dynamic_acl(stream, c);
1259 ret = validate_acl_list(acl, c);
1267 /* compute the real filename of a file by matching it without its
1268 extensions to all the stream's filenames */
1269 static void compute_real_filename(char *filename, int max_size)
1274 FFServerStream *stream;
1276 /* compute filename by matching without the file extensions */
1277 av_strlcpy(file1, filename, sizeof(file1));
1278 p = strrchr(file1, '.');
1281 for(stream = config.first_stream; stream; stream = stream->next) {
1282 av_strlcpy(file2, stream->filename, sizeof(file2));
1283 p = strrchr(file2, '.');
1286 if (!strcmp(file1, file2)) {
1287 av_strlcpy(filename, stream->filename, max_size);
1302 /* parse HTTP request and prepare header */
1303 static int http_parse_request(HTTPContext *c)
1307 enum RedirType redir_type;
1309 char info[1024], filename[1024];
1313 const char *mime_type;
1314 FFServerStream *stream;
1317 const char *useragent = 0;
1320 get_word(cmd, sizeof(cmd), &p);
1321 av_strlcpy(c->method, cmd, sizeof(c->method));
1323 if (!strcmp(cmd, "GET"))
1325 else if (!strcmp(cmd, "POST"))
1330 get_word(url, sizeof(url), &p);
1331 av_strlcpy(c->url, url, sizeof(c->url));
1333 get_word(protocol, sizeof(protocol), (const char **)&p);
1334 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1337 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1340 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1342 /* find the filename and the optional info string in the request */
1343 p1 = strchr(url, '?');
1345 av_strlcpy(info, p1, sizeof(info));
1350 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1352 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1353 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1355 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1359 p = strchr(p, '\n');
1366 redir_type = REDIR_NONE;
1367 if (av_match_ext(filename, "asx")) {
1368 redir_type = REDIR_ASX;
1369 filename[strlen(filename)-1] = 'f';
1370 } else if (av_match_ext(filename, "asf") &&
1371 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) {
1372 /* if this isn't WMP or lookalike, return the redirector file */
1373 redir_type = REDIR_ASF;
1374 } else if (av_match_ext(filename, "rpm,ram")) {
1375 redir_type = REDIR_RAM;
1376 strcpy(filename + strlen(filename)-2, "m");
1377 } else if (av_match_ext(filename, "rtsp")) {
1378 redir_type = REDIR_RTSP;
1379 compute_real_filename(filename, sizeof(filename) - 1);
1380 } else if (av_match_ext(filename, "sdp")) {
1381 redir_type = REDIR_SDP;
1382 compute_real_filename(filename, sizeof(filename) - 1);
1385 // "redirect" / request to index.html
1386 if (!strlen(filename))
1387 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1389 stream = config.first_stream;
1391 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1393 stream = stream->next;
1396 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1397 http_log("File '%s' not found\n", url);
1402 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1403 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1405 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1406 c->http_error = 301;
1408 snprintf(q, c->buffer_size,
1409 "HTTP/1.0 301 Moved\r\n"
1411 "Content-type: text/html\r\n"
1413 "<html><head><title>Moved</title></head><body>\r\n"
1414 "You should be <a href=\"%s\">redirected</a>.\r\n"
1415 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1417 /* prepare output buffer */
1418 c->buffer_ptr = c->buffer;
1420 c->state = HTTPSTATE_SEND_HEADER;
1424 /* If this is WMP, get the rate information */
1425 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1426 if (modify_current_stream(c, ratebuf)) {
1427 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1428 if (c->switch_feed_streams[i] >= 0)
1429 c->switch_feed_streams[i] = -1;
1434 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1435 current_bandwidth += stream->bandwidth;
1437 /* If already streaming this feed, do not let start another feeder. */
1438 if (stream->feed_opened) {
1439 snprintf(msg, sizeof(msg), "This feed is already being received.");
1440 http_log("Feed '%s' already being received\n", stream->feed_filename);
1444 if (c->post == 0 && config.max_bandwidth < current_bandwidth) {
1445 c->http_error = 503;
1447 snprintf(q, c->buffer_size,
1448 "HTTP/1.0 503 Server too busy\r\n"
1449 "Content-type: text/html\r\n"
1451 "<html><head><title>Too busy</title></head><body>\r\n"
1452 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1453 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1454 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1455 "</body></html>\r\n", current_bandwidth, config.max_bandwidth);
1457 /* prepare output buffer */
1458 c->buffer_ptr = c->buffer;
1460 c->state = HTTPSTATE_SEND_HEADER;
1464 if (redir_type != REDIR_NONE) {
1465 const char *hostinfo = 0;
1467 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1468 if (av_strncasecmp(p, "Host:", 5) == 0) {
1472 p = strchr(p, '\n');
1483 while (av_isspace(*hostinfo))
1486 eoh = strchr(hostinfo, '\n');
1488 if (eoh[-1] == '\r')
1491 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1492 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1493 hostbuf[eoh - hostinfo] = 0;
1495 c->http_error = 200;
1497 switch(redir_type) {
1499 snprintf(q, c->buffer_size,
1500 "HTTP/1.0 200 ASX Follows\r\n"
1501 "Content-type: video/x-ms-asf\r\n"
1503 "<ASX Version=\"3\">\r\n"
1504 //"<!-- Autogenerated by ffserver -->\r\n"
1505 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1506 "</ASX>\r\n", hostbuf, filename, info);
1510 snprintf(q, c->buffer_size,
1511 "HTTP/1.0 200 RAM Follows\r\n"
1512 "Content-type: audio/x-pn-realaudio\r\n"
1514 "# Autogenerated by ffserver\r\n"
1515 "http://%s/%s%s\r\n", hostbuf, filename, info);
1519 snprintf(q, c->buffer_size,
1520 "HTTP/1.0 200 ASF Redirect follows\r\n"
1521 "Content-type: video/x-ms-asf\r\n"
1524 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1529 char hostname[256], *p;
1530 /* extract only hostname */
1531 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1532 p = strrchr(hostname, ':');
1535 snprintf(q, c->buffer_size,
1536 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1537 /* XXX: incorrect MIME type ? */
1538 "Content-type: application/x-rtsp\r\n"
1540 "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
1549 struct sockaddr_in my_addr;
1551 snprintf(q, c->buffer_size,
1552 "HTTP/1.0 200 OK\r\n"
1553 "Content-type: application/sdp\r\n"
1557 len = sizeof(my_addr);
1559 /* XXX: Should probably fail? */
1560 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1561 http_log("getsockname() failed\n");
1563 /* XXX: should use a dynamic buffer */
1564 sdp_data_size = prepare_sdp_description(stream,
1567 if (sdp_data_size > 0) {
1568 memcpy(q, sdp_data, sdp_data_size);
1580 /* prepare output buffer */
1581 c->buffer_ptr = c->buffer;
1583 c->state = HTTPSTATE_SEND_HEADER;
1589 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1593 stream->conns_served++;
1595 /* XXX: add there authenticate and IP match */
1598 /* if post, it means a feed is being sent */
1599 if (!stream->is_feed) {
1600 /* However it might be a status report from WMP! Let us log the
1601 * data as it might come handy one day. */
1602 const char *logline = 0;
1605 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1606 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1610 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1611 client_id = strtol(p + 18, 0, 10);
1612 p = strchr(p, '\n');
1620 char *eol = strchr(logline, '\n');
1625 if (eol[-1] == '\r')
1627 http_log("%.*s\n", (int) (eol - logline), logline);
1628 c->suppress_log = 1;
1633 http_log("\nGot request:\n%s\n", c->buffer);
1636 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1639 /* Now we have to find the client_id */
1640 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1641 if (wmpc->wmp_client_id == client_id)
1645 if (wmpc && modify_current_stream(wmpc, ratebuf))
1646 wmpc->switch_pending = 1;
1649 snprintf(msg, sizeof(msg), "POST command not handled");
1653 if (http_start_receive_data(c) < 0) {
1654 snprintf(msg, sizeof(msg), "could not open feed");
1658 c->state = HTTPSTATE_RECEIVE_DATA;
1663 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1664 http_log("\nGot request:\n%s\n", c->buffer);
1667 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1670 /* open input stream */
1671 if (open_input_stream(c, info) < 0) {
1672 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1676 /* prepare HTTP header */
1678 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1679 mime_type = c->stream->fmt->mime_type;
1681 mime_type = "application/x-octet-stream";
1682 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1684 /* for asf, we need extra headers */
1685 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1686 /* Need to allocate a client id */
1688 c->wmp_client_id = av_lfg_get(&random_state);
1690 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);
1692 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1693 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1694 q = c->buffer + strlen(c->buffer);
1696 /* prepare output buffer */
1698 c->buffer_ptr = c->buffer;
1700 c->state = HTTPSTATE_SEND_HEADER;
1703 c->http_error = 404;
1706 snprintf(q, c->buffer_size,
1707 "HTTP/1.0 404 Not Found\r\n"
1708 "Content-type: text/html\r\n"
1711 "<head><title>404 Not Found</title></head>\n"
1715 /* prepare output buffer */
1716 c->buffer_ptr = c->buffer;
1718 c->state = HTTPSTATE_SEND_HEADER;
1722 c->http_error = 200; /* horrible : we use this value to avoid
1723 going to the send data state */
1724 c->state = HTTPSTATE_SEND_HEADER;
1728 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1730 static const char suffix[] = " kMGTP";
1733 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1735 avio_printf(pb, "%"PRId64"%c", count, *s);
1738 static void compute_status(HTTPContext *c)
1741 FFServerStream *stream;
1747 if (avio_open_dyn_buf(&pb) < 0) {
1748 /* XXX: return an error ? */
1749 c->buffer_ptr = c->buffer;
1750 c->buffer_end = c->buffer;
1754 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1755 avio_printf(pb, "Content-type: text/html\r\n");
1756 avio_printf(pb, "Pragma: no-cache\r\n");
1757 avio_printf(pb, "\r\n");
1759 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1760 if (c->stream->feed_filename[0])
1761 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1762 avio_printf(pb, "</head>\n<body>");
1763 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1765 avio_printf(pb, "<h2>Available Streams</h2>\n");
1766 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1767 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");
1768 stream = config.first_stream;
1770 char sfilename[1024];
1773 if (stream->feed == stream) {
1774 stream = stream->next;
1778 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1779 eosf = sfilename + strlen(sfilename);
1780 if (eosf - sfilename >= 4) {
1781 if (strcmp(eosf - 4, ".asf") == 0)
1782 strcpy(eosf - 4, ".asx");
1783 else if (strcmp(eosf - 3, ".rm") == 0)
1784 strcpy(eosf - 3, ".ram");
1785 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1786 /* generate a sample RTSP director if
1787 unicast. Generate an SDP redirector if
1789 eosf = strrchr(sfilename, '.');
1791 eosf = sfilename + strlen(sfilename);
1792 if (stream->is_multicast)
1793 strcpy(eosf, ".sdp");
1795 strcpy(eosf, ".rtsp");
1799 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1800 sfilename, stream->filename);
1801 avio_printf(pb, "<td align=right> %d <td align=right> ",
1802 stream->conns_served);
1803 fmt_bytecount(pb, stream->bytes_served);
1805 switch(stream->stream_type) {
1806 case STREAM_TYPE_LIVE: {
1807 int audio_bit_rate = 0;
1808 int video_bit_rate = 0;
1809 const char *audio_codec_name = "";
1810 const char *video_codec_name = "";
1811 const char *audio_codec_name_extra = "";
1812 const char *video_codec_name_extra = "";
1814 for(i=0;i<stream->nb_streams;i++) {
1815 AVStream *st = stream->streams[i];
1816 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1818 switch(st->codec->codec_type) {
1819 case AVMEDIA_TYPE_AUDIO:
1820 audio_bit_rate += st->codec->bit_rate;
1822 if (*audio_codec_name)
1823 audio_codec_name_extra = "...";
1824 audio_codec_name = codec->name;
1827 case AVMEDIA_TYPE_VIDEO:
1828 video_bit_rate += st->codec->bit_rate;
1830 if (*video_codec_name)
1831 video_codec_name_extra = "...";
1832 video_codec_name = codec->name;
1835 case AVMEDIA_TYPE_DATA:
1836 video_bit_rate += st->codec->bit_rate;
1843 avio_printf(pb, "<td align=center> %s <td align=right> %d "
1844 "<td align=right> %d <td> %s %s <td align=right> "
1846 stream->fmt->name, stream->bandwidth,
1847 video_bit_rate / 1000, video_codec_name,
1848 video_codec_name_extra, audio_bit_rate / 1000,
1849 audio_codec_name, audio_codec_name_extra);
1852 avio_printf(pb, "<td>%s", stream->feed->filename);
1854 avio_printf(pb, "<td>%s", stream->feed_filename);
1855 avio_printf(pb, "\n");
1859 avio_printf(pb, "<td align=center> - <td align=right> - "
1860 "<td align=right> - <td><td align=right> - <td>\n");
1863 stream = stream->next;
1865 avio_printf(pb, "</table>\n");
1867 stream = config.first_stream;
1870 if (stream->feed != stream) {
1871 stream = stream->next;
1875 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1877 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1884 /* This is somewhat linux specific I guess */
1885 snprintf(ps_cmd, sizeof(ps_cmd),
1886 "ps -o \"%%cpu,cputime\" --no-headers %d",
1889 pid_stat = popen(ps_cmd, "r");
1894 if (fscanf(pid_stat, "%9s %63s", cpuperc, cpuused) == 2) {
1895 avio_printf(pb, "Currently using %s%% of the cpu. "
1896 "Total time used %s.\n",
1904 avio_printf(pb, "<p>");
1907 avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>"
1908 "type<th>kbits/s<th align=left>codec<th align=left>"
1911 for (i = 0; i < stream->nb_streams; i++) {
1912 AVStream *st = stream->streams[i];
1913 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1914 const char *type = "unknown";
1915 char parameters[64];
1919 switch(st->codec->codec_type) {
1920 case AVMEDIA_TYPE_AUDIO:
1922 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz",
1923 st->codec->channels, st->codec->sample_rate);
1925 case AVMEDIA_TYPE_VIDEO:
1927 snprintf(parameters, sizeof(parameters),
1928 "%dx%d, q=%d-%d, fps=%d", st->codec->width,
1929 st->codec->height, st->codec->qmin, st->codec->qmax,
1930 st->codec->time_base.den / st->codec->time_base.num);
1936 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d"
1938 i, type, st->codec->bit_rate/1000,
1939 codec ? codec->name : "", parameters);
1942 avio_printf(pb, "</table>\n");
1943 stream = stream->next;
1946 /* connection status */
1947 avio_printf(pb, "<h2>Connection Status</h2>\n");
1949 avio_printf(pb, "Number of connections: %d / %d<br>\n",
1950 nb_connections, config.nb_max_connections);
1952 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1953 current_bandwidth, config.max_bandwidth);
1955 avio_printf(pb, "<table>\n");
1956 avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target "
1957 "bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1958 c1 = first_http_ctx;
1966 for (j = 0; j < c1->stream->nb_streams; j++) {
1967 if (!c1->stream->feed)
1968 bitrate += c1->stream->streams[j]->codec->bit_rate;
1969 else if (c1->feed_streams[j] >= 0)
1970 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1975 p = inet_ntoa(c1->from_addr.sin_addr);
1976 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s"
1978 i, c1->stream ? c1->stream->filename : "",
1979 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", p,
1980 c1->protocol, http_state[c1->state]);
1981 fmt_bytecount(pb, bitrate);
1982 avio_printf(pb, "<td align=right>");
1983 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1984 avio_printf(pb, "<td align=right>");
1985 fmt_bytecount(pb, c1->data_count);
1986 avio_printf(pb, "\n");
1989 avio_printf(pb, "</table>\n");
1994 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
1995 avio_printf(pb, "</body>\n</html>\n");
1997 len = avio_close_dyn_buf(pb, &c->pb_buffer);
1998 c->buffer_ptr = c->pb_buffer;
1999 c->buffer_end = c->pb_buffer + len;
2002 static int open_input_stream(HTTPContext *c, const char *info)
2005 char input_filename[1024];
2006 AVFormatContext *s = NULL;
2007 int buf_size, i, ret;
2010 /* find file name */
2011 if (c->stream->feed) {
2012 strcpy(input_filename, c->stream->feed->feed_filename);
2013 buf_size = FFM_PACKET_SIZE;
2014 /* compute position (absolute time) */
2015 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2016 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2017 http_log("Invalid date specification '%s' for stream\n", buf);
2020 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2021 int prebuffer = strtol(buf, 0, 10);
2022 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2024 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2026 strcpy(input_filename, c->stream->feed_filename);
2028 /* compute position (relative time) */
2029 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2030 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2031 http_log("Invalid date specification '%s' for stream\n", buf);
2037 if (!input_filename[0]) {
2038 http_log("No filename was specified for stream\n");
2039 return AVERROR(EINVAL);
2043 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2044 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2048 /* set buffer size */
2049 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2051 s->flags |= AVFMT_FLAG_GENPTS;
2053 if (strcmp(s->iformat->name, "ffm") &&
2054 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2055 http_log("Could not find stream info for input '%s'\n", input_filename);
2056 avformat_close_input(&s);
2060 /* choose stream as clock source (we favor the video stream if
2061 * present) for packet sending */
2062 c->pts_stream_index = 0;
2063 for(i=0;i<c->stream->nb_streams;i++) {
2064 if (c->pts_stream_index == 0 &&
2065 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2066 c->pts_stream_index = i;
2070 if (c->fmt_in->iformat->read_seek)
2071 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2072 /* set the start time (needed for maxtime and RTP packet timing) */
2073 c->start_time = cur_time;
2074 c->first_pts = AV_NOPTS_VALUE;
2078 /* return the server clock (in us) */
2079 static int64_t get_server_clock(HTTPContext *c)
2081 /* compute current pts value from system time */
2082 return (cur_time - c->start_time) * 1000;
2085 /* return the estimated time at which the current packet must be sent
2087 static int64_t get_packet_send_clock(HTTPContext *c)
2089 int bytes_left, bytes_sent, frame_bytes;
2091 frame_bytes = c->cur_frame_bytes;
2092 if (frame_bytes <= 0)
2095 bytes_left = c->buffer_end - c->buffer_ptr;
2096 bytes_sent = frame_bytes - bytes_left;
2097 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2102 static int http_prepare_data(HTTPContext *c)
2105 AVFormatContext *ctx;
2107 av_freep(&c->pb_buffer);
2109 case HTTPSTATE_SEND_DATA_HEADER:
2110 ctx = avformat_alloc_context();
2113 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2114 c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams, sizeof(AVStream *));
2116 for(i=0;i<c->stream->nb_streams;i++) {
2118 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2119 /* if file or feed, then just take streams from FFServerStream struct */
2120 if (!c->stream->feed ||
2121 c->stream->feed == c->stream)
2122 src = c->stream->streams[i];
2124 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2126 *(c->fmt_ctx.streams[i]) = *src;
2127 c->fmt_ctx.streams[i]->priv_data = 0;
2128 /* XXX: should be done in AVStream, not in codec */
2129 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2131 /* set output format parameters */
2132 c->fmt_ctx.oformat = c->stream->fmt;
2133 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2135 c->got_key_frame = 0;
2137 /* prepare header and save header data in a stream */
2138 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2139 /* XXX: potential leak */
2142 c->fmt_ctx.pb->seekable = 0;
2145 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2146 * Default value from FFmpeg
2147 * Try to set it using configuration option
2149 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2151 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2152 http_log("Error writing output header for stream '%s': %s\n",
2153 c->stream->filename, av_err2str(ret));
2156 av_dict_free(&c->fmt_ctx.metadata);
2158 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2159 c->buffer_ptr = c->pb_buffer;
2160 c->buffer_end = c->pb_buffer + len;
2162 c->state = HTTPSTATE_SEND_DATA;
2163 c->last_packet_sent = 0;
2165 case HTTPSTATE_SEND_DATA:
2166 /* find a new packet */
2167 /* read a packet from the input stream */
2168 if (c->stream->feed)
2169 ffm_set_write_index(c->fmt_in,
2170 c->stream->feed->feed_write_index,
2171 c->stream->feed->feed_size);
2173 if (c->stream->max_time &&
2174 c->stream->max_time + c->start_time - cur_time < 0)
2175 /* We have timed out */
2176 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2180 ret = av_read_frame(c->fmt_in, &pkt);
2182 if (c->stream->feed) {
2183 /* if coming from feed, it means we reached the end of the
2184 ffm file, so must wait for more data */
2185 c->state = HTTPSTATE_WAIT_FEED;
2186 return 1; /* state changed */
2187 } else if (ret == AVERROR(EAGAIN)) {
2188 /* input not ready, come back later */
2191 if (c->stream->loop) {
2192 avformat_close_input(&c->fmt_in);
2193 if (open_input_stream(c, "") < 0)
2198 /* must send trailer now because EOF or error */
2199 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2203 int source_index = pkt.stream_index;
2204 /* update first pts if needed */
2205 if (c->first_pts == AV_NOPTS_VALUE) {
2206 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2207 c->start_time = cur_time;
2209 /* send it to the appropriate stream */
2210 if (c->stream->feed) {
2211 /* if coming from a feed, select the right stream */
2212 if (c->switch_pending) {
2213 c->switch_pending = 0;
2214 for(i=0;i<c->stream->nb_streams;i++) {
2215 if (c->switch_feed_streams[i] == pkt.stream_index)
2216 if (pkt.flags & AV_PKT_FLAG_KEY)
2217 c->switch_feed_streams[i] = -1;
2218 if (c->switch_feed_streams[i] >= 0)
2219 c->switch_pending = 1;
2222 for(i=0;i<c->stream->nb_streams;i++) {
2223 if (c->stream->feed_streams[i] == pkt.stream_index) {
2224 AVStream *st = c->fmt_in->streams[source_index];
2225 pkt.stream_index = i;
2226 if (pkt.flags & AV_PKT_FLAG_KEY &&
2227 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2228 c->stream->nb_streams == 1))
2229 c->got_key_frame = 1;
2230 if (!c->stream->send_on_key || c->got_key_frame)
2235 AVCodecContext *codec;
2236 AVStream *ist, *ost;
2238 ist = c->fmt_in->streams[source_index];
2239 /* specific handling for RTP: we use several
2240 * output streams (one for each RTP connection).
2241 * XXX: need more abstract handling */
2242 if (c->is_packetized) {
2243 /* compute send time and duration */
2244 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2245 c->cur_pts -= c->first_pts;
2246 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2247 /* find RTP context */
2248 c->packet_stream_index = pkt.stream_index;
2249 ctx = c->rtp_ctx[c->packet_stream_index];
2251 av_free_packet(&pkt);
2254 codec = ctx->streams[0]->codec;
2255 /* only one stream per RTP connection */
2256 pkt.stream_index = 0;
2260 codec = ctx->streams[pkt.stream_index]->codec;
2263 if (c->is_packetized) {
2264 int max_packet_size;
2265 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2266 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2268 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2269 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2271 ret = avio_open_dyn_buf(&ctx->pb);
2274 /* XXX: potential leak */
2277 ost = ctx->streams[pkt.stream_index];
2279 ctx->pb->seekable = 0;
2280 if (pkt.dts != AV_NOPTS_VALUE)
2281 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2282 if (pkt.pts != AV_NOPTS_VALUE)
2283 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2284 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2285 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2286 http_log("Error writing frame to output for stream '%s': %s\n",
2287 c->stream->filename, av_err2str(ret));
2288 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2291 av_freep(&c->pb_buffer);
2292 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2293 c->cur_frame_bytes = len;
2294 c->buffer_ptr = c->pb_buffer;
2295 c->buffer_end = c->pb_buffer + len;
2297 codec->frame_number++;
2299 av_free_packet(&pkt);
2303 av_free_packet(&pkt);
2308 case HTTPSTATE_SEND_DATA_TRAILER:
2309 /* last packet test ? */
2310 if (c->last_packet_sent || c->is_packetized)
2313 /* prepare header */
2314 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2315 /* XXX: potential leak */
2318 c->fmt_ctx.pb->seekable = 0;
2319 av_write_trailer(ctx);
2320 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2321 c->buffer_ptr = c->pb_buffer;
2322 c->buffer_end = c->pb_buffer + len;
2324 c->last_packet_sent = 1;
2330 /* should convert the format at the same time */
2331 /* send data starting at c->buffer_ptr to the output connection
2332 * (either UDP or TCP) */
2333 static int http_send_data(HTTPContext *c)
2338 if (c->buffer_ptr >= c->buffer_end) {
2339 ret = http_prepare_data(c);
2343 /* state change requested */
2346 if (c->is_packetized) {
2347 /* RTP data output */
2348 len = c->buffer_end - c->buffer_ptr;
2350 /* fail safe - should never happen */
2352 c->buffer_ptr = c->buffer_end;
2355 len = (c->buffer_ptr[0] << 24) |
2356 (c->buffer_ptr[1] << 16) |
2357 (c->buffer_ptr[2] << 8) |
2359 if (len > (c->buffer_end - c->buffer_ptr))
2361 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2362 /* nothing to send yet: we can wait */
2366 c->data_count += len;
2367 update_datarate(&c->datarate, c->data_count);
2369 c->stream->bytes_served += len;
2371 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2372 /* RTP packets are sent inside the RTSP TCP connection */
2374 int interleaved_index, size;
2376 HTTPContext *rtsp_c;
2379 /* if no RTSP connection left, error */
2382 /* if already sending something, then wait. */
2383 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2385 if (avio_open_dyn_buf(&pb) < 0)
2387 interleaved_index = c->packet_stream_index * 2;
2388 /* RTCP packets are sent at odd indexes */
2389 if (c->buffer_ptr[1] == 200)
2390 interleaved_index++;
2391 /* write RTSP TCP header */
2393 header[1] = interleaved_index;
2394 header[2] = len >> 8;
2396 avio_write(pb, header, 4);
2397 /* write RTP packet data */
2399 avio_write(pb, c->buffer_ptr, len);
2400 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2401 /* prepare asynchronous TCP sending */
2402 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2403 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2404 c->buffer_ptr += len;
2406 /* send everything we can NOW */
2407 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2408 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2410 rtsp_c->packet_buffer_ptr += len;
2411 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2412 /* if we could not send all the data, we will
2413 send it later, so a new state is needed to
2414 "lock" the RTSP TCP connection */
2415 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2418 /* all data has been sent */
2419 av_freep(&c->packet_buffer);
2421 /* send RTP packet directly in UDP */
2423 ffurl_write(c->rtp_handles[c->packet_stream_index],
2424 c->buffer_ptr, len);
2425 c->buffer_ptr += len;
2426 /* here we continue as we can send several packets per 10 ms slot */
2429 /* TCP data output */
2430 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2432 if (ff_neterrno() != AVERROR(EAGAIN) &&
2433 ff_neterrno() != AVERROR(EINTR))
2434 /* error : close connection */
2439 c->buffer_ptr += len;
2441 c->data_count += len;
2442 update_datarate(&c->datarate, c->data_count);
2444 c->stream->bytes_served += len;
2452 static int http_start_receive_data(HTTPContext *c)
2457 if (c->stream->feed_opened) {
2458 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2459 return AVERROR(EINVAL);
2462 /* Don't permit writing to this one */
2463 if (c->stream->readonly) {
2464 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2465 return AVERROR(EINVAL);
2469 fd = open(c->stream->feed_filename, O_RDWR);
2471 ret = AVERROR(errno);
2472 http_log("Could not open feed file '%s': %s\n",
2473 c->stream->feed_filename, strerror(errno));
2478 if (c->stream->truncate) {
2479 /* truncate feed file */
2480 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2481 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2482 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2483 ret = AVERROR(errno);
2484 http_log("Error truncating feed file '%s': %s\n",
2485 c->stream->feed_filename, strerror(errno));
2489 ret = ffm_read_write_index(fd);
2491 http_log("Error reading write index from feed file '%s': %s\n",
2492 c->stream->feed_filename, strerror(errno));
2495 c->stream->feed_write_index = ret;
2499 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2500 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2501 lseek(fd, 0, SEEK_SET);
2503 /* init buffer input */
2504 c->buffer_ptr = c->buffer;
2505 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2506 c->stream->feed_opened = 1;
2507 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2511 static int http_receive_data(HTTPContext *c)
2514 int len, loop_run = 0;
2516 while (c->chunked_encoding && !c->chunk_size &&
2517 c->buffer_end > c->buffer_ptr) {
2518 /* read chunk header, if present */
2519 len = recv(c->fd, c->buffer_ptr, 1, 0);
2522 if (ff_neterrno() != AVERROR(EAGAIN) &&
2523 ff_neterrno() != AVERROR(EINTR))
2524 /* error : close connection */
2527 } else if (len == 0) {
2528 /* end of connection : close it */
2530 } else if (c->buffer_ptr - c->buffer >= 2 &&
2531 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2532 c->chunk_size = strtol(c->buffer, 0, 16);
2533 if (c->chunk_size == 0) // end of stream
2535 c->buffer_ptr = c->buffer;
2537 } else if (++loop_run > 10) {
2538 /* no chunk header, abort */
2545 if (c->buffer_end > c->buffer_ptr) {
2546 len = recv(c->fd, c->buffer_ptr,
2547 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2549 if (ff_neterrno() != AVERROR(EAGAIN) &&
2550 ff_neterrno() != AVERROR(EINTR))
2551 /* error : close connection */
2553 } else if (len == 0)
2554 /* end of connection : close it */
2557 c->chunk_size -= len;
2558 c->buffer_ptr += len;
2559 c->data_count += len;
2560 update_datarate(&c->datarate, c->data_count);
2564 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2565 if (c->buffer[0] != 'f' ||
2566 c->buffer[1] != 'm') {
2567 http_log("Feed stream has become desynchronized -- disconnecting\n");
2572 if (c->buffer_ptr >= c->buffer_end) {
2573 FFServerStream *feed = c->stream;
2574 /* a packet has been received : write it in the store, except
2576 if (c->data_count > FFM_PACKET_SIZE) {
2577 /* XXX: use llseek or url_seek
2578 * XXX: Should probably fail? */
2579 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2580 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2582 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2583 http_log("Error writing to feed file: %s\n", strerror(errno));
2587 feed->feed_write_index += FFM_PACKET_SIZE;
2588 /* update file size */
2589 if (feed->feed_write_index > c->stream->feed_size)
2590 feed->feed_size = feed->feed_write_index;
2592 /* handle wrap around if max file size reached */
2593 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2594 feed->feed_write_index = FFM_PACKET_SIZE;
2597 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2598 http_log("Error writing index to feed file: %s\n", strerror(errno));
2602 /* wake up any waiting connections */
2603 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2604 if (c1->state == HTTPSTATE_WAIT_FEED &&
2605 c1->stream->feed == c->stream->feed)
2606 c1->state = HTTPSTATE_SEND_DATA;
2609 /* We have a header in our hands that contains useful data */
2610 AVFormatContext *s = avformat_alloc_context();
2612 AVInputFormat *fmt_in;
2618 /* use feed output format name to find corresponding input format */
2619 fmt_in = av_find_input_format(feed->fmt->name);
2623 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2624 0, NULL, NULL, NULL, NULL);
2628 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2633 /* Now we have the actual streams */
2634 if (s->nb_streams != feed->nb_streams) {
2635 avformat_close_input(&s);
2637 http_log("Feed '%s' stream number does not match registered feed\n",
2638 c->stream->feed_filename);
2642 for (i = 0; i < s->nb_streams; i++) {
2643 AVStream *fst = feed->streams[i];
2644 AVStream *st = s->streams[i];
2645 avcodec_copy_context(fst->codec, st->codec);
2648 avformat_close_input(&s);
2651 c->buffer_ptr = c->buffer;
2656 c->stream->feed_opened = 0;
2658 /* wake up any waiting connections to stop waiting for feed */
2659 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2660 if (c1->state == HTTPSTATE_WAIT_FEED &&
2661 c1->stream->feed == c->stream->feed)
2662 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2667 /********************************************************************/
2670 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2677 str = RTSP_STATUS_CODE2STRING(error_number);
2679 str = "Unknown Error";
2681 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2682 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2684 /* output GMT time */
2687 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2688 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2691 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2693 rtsp_reply_header(c, error_number);
2694 avio_printf(c->pb, "\r\n");
2697 static int rtsp_parse_request(HTTPContext *c)
2699 const char *p, *p1, *p2;
2705 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2707 c->buffer_ptr[0] = '\0';
2710 get_word(cmd, sizeof(cmd), &p);
2711 get_word(url, sizeof(url), &p);
2712 get_word(protocol, sizeof(protocol), &p);
2714 av_strlcpy(c->method, cmd, sizeof(c->method));
2715 av_strlcpy(c->url, url, sizeof(c->url));
2716 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2718 if (avio_open_dyn_buf(&c->pb) < 0) {
2719 /* XXX: cannot do more */
2720 c->pb = NULL; /* safety */
2724 /* check version name */
2725 if (strcmp(protocol, "RTSP/1.0")) {
2726 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2730 /* parse each header line */
2731 /* skip to next line */
2732 while (*p != '\n' && *p != '\0')
2736 while (*p != '\0') {
2737 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2741 if (p2 > p && p2[-1] == '\r')
2743 /* skip empty line */
2747 if (len > sizeof(line) - 1)
2748 len = sizeof(line) - 1;
2749 memcpy(line, p, len);
2751 ff_rtsp_parse_line(header, line, NULL, NULL);
2755 /* handle sequence number */
2756 c->seq = header->seq;
2758 if (!strcmp(cmd, "DESCRIBE"))
2759 rtsp_cmd_describe(c, url);
2760 else if (!strcmp(cmd, "OPTIONS"))
2761 rtsp_cmd_options(c, url);
2762 else if (!strcmp(cmd, "SETUP"))
2763 rtsp_cmd_setup(c, url, header);
2764 else if (!strcmp(cmd, "PLAY"))
2765 rtsp_cmd_play(c, url, header);
2766 else if (!strcmp(cmd, "PAUSE"))
2767 rtsp_cmd_interrupt(c, url, header, 1);
2768 else if (!strcmp(cmd, "TEARDOWN"))
2769 rtsp_cmd_interrupt(c, url, header, 0);
2771 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2774 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2775 c->pb = NULL; /* safety */
2777 /* XXX: cannot do more */
2780 c->buffer_ptr = c->pb_buffer;
2781 c->buffer_end = c->pb_buffer + len;
2782 c->state = RTSPSTATE_SEND_REPLY;
2786 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2787 struct in_addr my_ip)
2789 AVFormatContext *avc;
2790 AVStream *avs = NULL;
2791 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2792 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2797 avc = avformat_alloc_context();
2798 if (!avc || !rtp_format) {
2801 avc->oformat = rtp_format;
2802 av_dict_set(&avc->metadata, "title",
2803 entry ? entry->value : "No Title", 0);
2804 avc->nb_streams = stream->nb_streams;
2805 if (stream->is_multicast) {
2806 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2807 inet_ntoa(stream->multicast_ip),
2808 stream->multicast_port, stream->multicast_ttl);
2810 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2813 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2814 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2816 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2817 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2820 for(i = 0; i < stream->nb_streams; i++) {
2821 avc->streams[i] = &avs[i];
2822 avc->streams[i]->codec = stream->streams[i]->codec;
2824 *pbuffer = av_mallocz(2048);
2825 av_sdp_create(&avc, 1, *pbuffer, 2048);
2828 av_freep(&avc->streams);
2829 av_dict_free(&avc->metadata);
2833 return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2836 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2838 // rtsp_reply_header(c, RTSP_STATUS_OK);
2839 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2840 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2841 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2842 avio_printf(c->pb, "\r\n");
2845 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2847 FFServerStream *stream;
2853 struct sockaddr_in my_addr;
2855 /* find which URL is asked */
2856 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2861 for(stream = config.first_stream; stream; stream = stream->next) {
2862 if (!stream->is_feed &&
2863 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2864 !strcmp(path, stream->filename)) {
2868 /* no stream found */
2869 rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
2873 /* prepare the media description in SDP format */
2875 /* get the host IP */
2876 len = sizeof(my_addr);
2877 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2878 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2879 if (content_length < 0) {
2880 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2883 rtsp_reply_header(c, RTSP_STATUS_OK);
2884 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2885 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2886 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2887 avio_printf(c->pb, "\r\n");
2888 avio_write(c->pb, content, content_length);
2892 static HTTPContext *find_rtp_session(const char *session_id)
2896 if (session_id[0] == '\0')
2899 for(c = first_http_ctx; c; c = c->next) {
2900 if (!strcmp(c->session_id, session_id))
2906 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2908 RTSPTransportField *th;
2911 for(i=0;i<h->nb_transports;i++) {
2912 th = &h->transports[i];
2913 if (th->lower_transport == lower_transport)
2919 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2920 RTSPMessageHeader *h)
2922 FFServerStream *stream;
2923 int stream_index, rtp_port, rtcp_port;
2928 RTSPTransportField *th;
2929 struct sockaddr_in dest_addr;
2930 RTSPActionServerSetup setup;
2932 /* find which URL is asked */
2933 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2938 /* now check each stream */
2939 for(stream = config.first_stream; stream; stream = stream->next) {
2940 if (stream->is_feed || !stream->fmt ||
2941 strcmp(stream->fmt->name, "rtp")) {
2944 /* accept aggregate filenames only if single stream */
2945 if (!strcmp(path, stream->filename)) {
2946 if (stream->nb_streams != 1) {
2947 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2954 for(stream_index = 0; stream_index < stream->nb_streams;
2956 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2957 stream->filename, stream_index);
2958 if (!strcmp(path, buf))
2962 /* no stream found */
2963 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2967 /* generate session id if needed */
2968 if (h->session_id[0] == '\0') {
2969 unsigned random0 = av_lfg_get(&random_state);
2970 unsigned random1 = av_lfg_get(&random_state);
2971 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2975 /* find RTP session, and create it if none found */
2976 rtp_c = find_rtp_session(h->session_id);
2978 /* always prefer UDP */
2979 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2981 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2983 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2988 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2989 th->lower_transport);
2991 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2995 /* open input stream */
2996 if (open_input_stream(rtp_c, "") < 0) {
2997 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3002 /* test if stream is OK (test needed because several SETUP needs
3003 to be done for a given file) */
3004 if (rtp_c->stream != stream) {
3005 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3009 /* test if stream is already set up */
3010 if (rtp_c->rtp_ctx[stream_index]) {
3011 rtsp_reply_error(c, RTSP_STATUS_STATE);
3015 /* check transport */
3016 th = find_transport(h, rtp_c->rtp_protocol);
3017 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3018 th->client_port_min <= 0)) {
3019 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3023 /* setup default options */
3024 setup.transport_option[0] = '\0';
3025 dest_addr = rtp_c->from_addr;
3026 dest_addr.sin_port = htons(th->client_port_min);
3029 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3030 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3034 /* now everything is OK, so we can send the connection parameters */
3035 rtsp_reply_header(c, RTSP_STATUS_OK);
3037 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3039 switch(rtp_c->rtp_protocol) {
3040 case RTSP_LOWER_TRANSPORT_UDP:
3041 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3042 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3043 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3044 "client_port=%d-%d;server_port=%d-%d",
3045 th->client_port_min, th->client_port_max,
3046 rtp_port, rtcp_port);
3048 case RTSP_LOWER_TRANSPORT_TCP:
3049 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3050 stream_index * 2, stream_index * 2 + 1);
3055 if (setup.transport_option[0] != '\0')
3056 avio_printf(c->pb, ";%s", setup.transport_option);
3057 avio_printf(c->pb, "\r\n");
3060 avio_printf(c->pb, "\r\n");
3064 /* find an RTP connection by using the session ID. Check consistency
3066 static HTTPContext *find_rtp_session_with_url(const char *url,
3067 const char *session_id)
3075 rtp_c = find_rtp_session(session_id);
3079 /* find which URL is asked */
3080 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3084 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3085 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3086 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3087 rtp_c->stream->filename, s);
3088 if(!strncmp(path, buf, sizeof(buf))) {
3089 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3094 if (len > 0 && path[len - 1] == '/' &&
3095 !strncmp(path, rtp_c->stream->filename, len - 1))
3100 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3104 rtp_c = find_rtp_session_with_url(url, h->session_id);
3106 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3110 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3111 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3112 rtp_c->state != HTTPSTATE_READY) {
3113 rtsp_reply_error(c, RTSP_STATUS_STATE);
3117 rtp_c->state = HTTPSTATE_SEND_DATA;
3119 /* now everything is OK, so we can send the connection parameters */
3120 rtsp_reply_header(c, RTSP_STATUS_OK);
3122 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3123 avio_printf(c->pb, "\r\n");
3126 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3130 rtp_c = find_rtp_session_with_url(url, h->session_id);
3132 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3137 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3138 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3139 rtsp_reply_error(c, RTSP_STATUS_STATE);
3142 rtp_c->state = HTTPSTATE_READY;
3143 rtp_c->first_pts = AV_NOPTS_VALUE;
3146 /* now everything is OK, so we can send the connection parameters */
3147 rtsp_reply_header(c, RTSP_STATUS_OK);
3149 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3150 avio_printf(c->pb, "\r\n");
3153 close_connection(rtp_c);
3156 /********************************************************************/
3159 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3160 FFServerStream *stream, const char *session_id,
3161 enum RTSPLowerTransport rtp_protocol)
3163 HTTPContext *c = NULL;
3164 const char *proto_str;
3166 /* XXX: should output a warning page when coming
3167 close to the connection limit */
3168 if (nb_connections >= config.nb_max_connections)
3171 /* add a new connection */
3172 c = av_mallocz(sizeof(HTTPContext));
3177 c->poll_entry = NULL;
3178 c->from_addr = *from_addr;
3179 c->buffer_size = IOBUFFER_INIT_SIZE;
3180 c->buffer = av_malloc(c->buffer_size);
3185 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3186 c->state = HTTPSTATE_READY;
3187 c->is_packetized = 1;
3188 c->rtp_protocol = rtp_protocol;
3190 /* protocol is shown in statistics */
3191 switch(c->rtp_protocol) {
3192 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3193 proto_str = "MCAST";
3195 case RTSP_LOWER_TRANSPORT_UDP:
3198 case RTSP_LOWER_TRANSPORT_TCP:
3205 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3206 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3208 current_bandwidth += stream->bandwidth;
3210 c->next = first_http_ctx;
3216 av_freep(&c->buffer);
3222 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3223 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3225 static int rtp_new_av_stream(HTTPContext *c,
3226 int stream_index, struct sockaddr_in *dest_addr,
3227 HTTPContext *rtsp_c)
3229 AVFormatContext *ctx;
3232 URLContext *h = NULL;
3234 int max_packet_size;
3236 /* now we can open the relevant output stream */
3237 ctx = avformat_alloc_context();
3240 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3242 st = av_mallocz(sizeof(AVStream));
3245 ctx->nb_streams = 1;
3246 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3249 ctx->streams[0] = st;
3251 if (!c->stream->feed ||
3252 c->stream->feed == c->stream)
3253 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3256 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3258 st->priv_data = NULL;
3260 /* build destination RTP address */
3261 ipaddr = inet_ntoa(dest_addr->sin_addr);
3263 switch(c->rtp_protocol) {
3264 case RTSP_LOWER_TRANSPORT_UDP:
3265 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3268 /* XXX: also pass as parameter to function ? */
3269 if (c->stream->is_multicast) {
3271 ttl = c->stream->multicast_ttl;
3274 snprintf(ctx->filename, sizeof(ctx->filename),
3275 "rtp://%s:%d?multicast=1&ttl=%d",
3276 ipaddr, ntohs(dest_addr->sin_port), ttl);
3278 snprintf(ctx->filename, sizeof(ctx->filename),
3279 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3282 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3284 c->rtp_handles[stream_index] = h;
3285 max_packet_size = h->max_packet_size;
3287 case RTSP_LOWER_TRANSPORT_TCP:
3290 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3296 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3297 ipaddr, ntohs(dest_addr->sin_port),
3298 c->stream->filename, stream_index, c->protocol);
3300 /* normally, no packets should be output here, but the packet size may
3302 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3303 /* XXX: close stream */
3306 if (avformat_write_header(ctx, NULL) < 0) {
3314 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3317 c->rtp_ctx[stream_index] = ctx;
3321 /********************************************************************/
3322 /* ffserver initialization */
3324 static AVStream *add_av_stream1(FFServerStream *stream, AVCodecContext *codec, int copy)
3328 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3331 fst = av_mallocz(sizeof(AVStream));
3335 fst->codec = avcodec_alloc_context3(codec->codec);
3336 avcodec_copy_context(fst->codec, codec);
3338 /* live streams must use the actual feed's codec since it may be
3339 * updated later to carry extradata needed by them.
3343 fst->priv_data = av_mallocz(sizeof(FeedData));
3344 fst->index = stream->nb_streams;
3345 avpriv_set_pts_info(fst, 33, 1, 90000);
3346 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3347 stream->streams[stream->nb_streams++] = fst;
3351 /* return the stream number in the feed */
3352 static int add_av_stream(FFServerStream *feed, AVStream *st)
3355 AVCodecContext *av, *av1;
3359 for(i=0;i<feed->nb_streams;i++) {
3360 av1 = feed->streams[i]->codec;
3361 if (av1->codec_id == av->codec_id &&
3362 av1->codec_type == av->codec_type &&
3363 av1->bit_rate == av->bit_rate) {
3365 switch(av->codec_type) {
3366 case AVMEDIA_TYPE_AUDIO:
3367 if (av1->channels == av->channels &&
3368 av1->sample_rate == av->sample_rate)
3371 case AVMEDIA_TYPE_VIDEO:
3372 if (av1->width == av->width &&
3373 av1->height == av->height &&
3374 av1->time_base.den == av->time_base.den &&
3375 av1->time_base.num == av->time_base.num &&
3376 av1->gop_size == av->gop_size)
3385 fst = add_av_stream1(feed, av, 0);
3388 if (av_stream_get_recommended_encoder_configuration(st))
3389 av_stream_set_recommended_encoder_configuration(fst,
3390 av_strdup(av_stream_get_recommended_encoder_configuration(st)));
3391 return feed->nb_streams - 1;
3394 static void remove_stream(FFServerStream *stream)
3396 FFServerStream **ps;
3397 ps = &config.first_stream;
3406 /* specific MPEG4 handling : we extract the raw parameters */
3407 static void extract_mpeg4_header(AVFormatContext *infile)
3409 int mpeg4_count, i, size;
3414 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3417 for(i=0;i<infile->nb_streams;i++) {
3418 st = infile->streams[i];
3419 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3420 st->codec->extradata_size == 0) {
3427 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3428 while (mpeg4_count > 0) {
3429 if (av_read_frame(infile, &pkt) < 0)
3431 st = infile->streams[pkt.stream_index];
3432 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3433 st->codec->extradata_size == 0) {
3434 av_freep(&st->codec->extradata);
3435 /* fill extradata with the header */
3436 /* XXX: we make hard suppositions here ! */
3438 while (p < pkt.data + pkt.size - 4) {
3439 /* stop when vop header is found */
3440 if (p[0] == 0x00 && p[1] == 0x00 &&
3441 p[2] == 0x01 && p[3] == 0xb6) {
3442 size = p - pkt.data;
3443 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3444 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3445 st->codec->extradata_size = size;
3446 memcpy(st->codec->extradata, pkt.data, size);
3453 av_free_packet(&pkt);
3457 /* compute the needed AVStream for each file */
3458 static void build_file_streams(void)
3460 FFServerStream *stream, *stream_next;
3463 /* gather all streams */
3464 for(stream = config.first_stream; stream; stream = stream_next) {
3465 AVFormatContext *infile = NULL;
3466 stream_next = stream->next;
3467 if (stream->stream_type == STREAM_TYPE_LIVE &&
3469 /* the stream comes from a file */
3470 /* try to open the file */
3472 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3473 /* specific case : if transport stream output to RTP,
3474 we use a raw transport stream reader */
3475 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3478 if (!stream->feed_filename[0]) {
3479 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3483 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3484 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3485 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3486 /* remove stream (no need to spend more time on it) */
3488 remove_stream(stream);
3490 /* find all the AVStreams inside and reference them in
3492 if (avformat_find_stream_info(infile, NULL) < 0) {
3493 http_log("Could not find codec parameters from '%s'\n",
3494 stream->feed_filename);
3495 avformat_close_input(&infile);
3498 extract_mpeg4_header(infile);
3500 for(i=0;i<infile->nb_streams;i++)
3501 add_av_stream1(stream, infile->streams[i]->codec, 1);
3503 avformat_close_input(&infile);
3509 /* compute the needed AVStream for each feed */
3510 static void build_feed_streams(void)
3512 FFServerStream *stream, *feed;
3515 /* gather all streams */
3516 for(stream = config.first_stream; stream; stream = stream->next) {
3517 feed = stream->feed;
3519 if (stream->is_feed) {
3520 for(i=0;i<stream->nb_streams;i++)
3521 stream->feed_streams[i] = i;
3523 /* we handle a stream coming from a feed */
3524 for(i=0;i<stream->nb_streams;i++)
3525 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3530 /* create feed files if needed */
3531 for(feed = config.first_feed; feed; feed = feed->next_feed) {
3534 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3535 /* See if it matches */
3536 AVFormatContext *s = NULL;
3539 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3540 /* set buffer size */
3541 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3542 /* Now see if it matches */
3543 if (s->nb_streams == feed->nb_streams) {
3545 for(i=0;i<s->nb_streams;i++) {
3547 sf = feed->streams[i];
3550 if (sf->index != ss->index ||
3552 http_log("Index & Id do not match for stream %d (%s)\n",
3553 i, feed->feed_filename);
3556 AVCodecContext *ccf, *ccs;
3560 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3562 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3563 http_log("Codecs do not match for stream %d\n", i);
3565 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3566 http_log("Codec bitrates do not match for stream %d\n", i);
3568 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3569 if (CHECK_CODEC(time_base.den) ||
3570 CHECK_CODEC(time_base.num) ||
3571 CHECK_CODEC(width) ||
3572 CHECK_CODEC(height)) {
3573 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3576 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3577 if (CHECK_CODEC(sample_rate) ||
3578 CHECK_CODEC(channels) ||
3579 CHECK_CODEC(frame_size)) {
3580 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3584 http_log("Unknown codec type\n");
3592 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3593 feed->feed_filename, s->nb_streams, feed->nb_streams);
3595 avformat_close_input(&s);
3597 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3598 feed->feed_filename);
3601 if (feed->readonly) {
3602 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3603 feed->feed_filename);
3606 unlink(feed->feed_filename);
3609 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3610 AVFormatContext *s = avformat_alloc_context();
3612 if (feed->readonly) {
3613 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3614 feed->feed_filename);
3618 /* only write the header of the ffm file */
3619 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3620 http_log("Could not open output feed file '%s'\n",
3621 feed->feed_filename);
3624 s->oformat = feed->fmt;
3625 s->nb_streams = feed->nb_streams;
3626 s->streams = feed->streams;
3627 if (avformat_write_header(s, NULL) < 0) {
3628 http_log("Container doesn't support the required parameters\n");
3631 /* XXX: need better API */
3632 av_freep(&s->priv_data);
3633 avio_closep(&s->pb);
3636 avformat_free_context(s);
3638 /* get feed size and write index */
3639 fd = open(feed->feed_filename, O_RDONLY);
3641 http_log("Could not open output feed file '%s'\n",
3642 feed->feed_filename);
3646 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3647 feed->feed_size = lseek(fd, 0, SEEK_END);
3648 /* ensure that we do not wrap before the end of file */
3649 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3650 feed->feed_max_size = feed->feed_size;
3656 /* compute the bandwidth used by each stream */
3657 static void compute_bandwidth(void)
3661 FFServerStream *stream;
3663 for(stream = config.first_stream; stream; stream = stream->next) {
3665 for(i=0;i<stream->nb_streams;i++) {
3666 AVStream *st = stream->streams[i];
3667 switch(st->codec->codec_type) {
3668 case AVMEDIA_TYPE_AUDIO:
3669 case AVMEDIA_TYPE_VIDEO:
3670 bandwidth += st->codec->bit_rate;
3676 stream->bandwidth = (bandwidth + 999) / 1000;
3680 static void handle_child_exit(int sig)
3685 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3686 FFServerStream *feed;
3688 for (feed = config.first_feed; feed; feed = feed->next) {
3689 if (feed->pid == pid) {
3690 int uptime = time(0) - feed->pid_start;
3693 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
3696 /* Turn off any more restarts */
3697 ffserver_free_child_args(&feed->child_argv);
3702 need_to_start_children = 1;
3705 static void opt_debug(void)
3708 snprintf(config.logfilename, sizeof(config.logfilename), "-");
3711 void show_help_default(const char *opt, const char *arg)
3713 printf("usage: ffserver [options]\n"
3714 "Hyper fast multi format Audio/Video streaming server\n");
3716 show_help_options(options, "Main options:", 0, 0, 0);
3719 static const OptionDef options[] = {
3720 #include "cmdutils_common_opts.h"
3721 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3722 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3723 { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3727 int main(int argc, char **argv)
3729 struct sigaction sigact = { { 0 } };
3732 config.filename = av_strdup("/etc/ffserver.conf");
3734 parse_loglevel(argc, argv, options);
3736 avformat_network_init();
3738 show_banner(argc, argv, options);
3740 my_program_name = argv[0];
3742 parse_options(NULL, argc, argv, options, NULL);
3744 unsetenv("http_proxy"); /* Kill the http_proxy */
3746 av_lfg_init(&random_state, av_get_random_seed());
3748 sigact.sa_handler = handle_child_exit;
3749 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3750 sigaction(SIGCHLD, &sigact, 0);
3752 if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3753 fprintf(stderr, "Error reading configuration file '%s': %s\n",
3754 config.filename, av_err2str(ret));
3757 av_freep(&config.filename);
3759 /* open log file if needed */
3760 if (config.logfilename[0] != '\0') {
3761 if (!strcmp(config.logfilename, "-"))
3764 logfile = fopen(config.logfilename, "a");
3765 av_log_set_callback(http_av_log);
3768 build_file_streams();
3770 build_feed_streams();
3772 compute_bandwidth();
3775 signal(SIGPIPE, SIG_IGN);
3777 if (http_server() < 0) {
3778 http_log("Could not start server\n");