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->streams = av_malloc_array(avc->nb_streams, sizeof(*avc->streams))))
2815 if (!(avs = av_malloc_array(avc->nb_streams, sizeof(*avs))))
2818 for(i = 0; i < stream->nb_streams; i++) {
2819 avc->streams[i] = &avs[i];
2820 avc->streams[i]->codec = stream->streams[i]->codec;
2822 *pbuffer = av_mallocz(2048);
2823 av_sdp_create(&avc, 1, *pbuffer, 2048);
2826 av_freep(&avc->streams);
2827 av_dict_free(&avc->metadata);
2831 return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2834 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2836 // rtsp_reply_header(c, RTSP_STATUS_OK);
2837 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2838 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2839 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2840 avio_printf(c->pb, "\r\n");
2843 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2845 FFServerStream *stream;
2851 struct sockaddr_in my_addr;
2853 /* find which URL is asked */
2854 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2859 for(stream = config.first_stream; stream; stream = stream->next) {
2860 if (!stream->is_feed &&
2861 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2862 !strcmp(path, stream->filename)) {
2866 /* no stream found */
2867 rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
2871 /* prepare the media description in SDP format */
2873 /* get the host IP */
2874 len = sizeof(my_addr);
2875 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2876 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2877 if (content_length < 0) {
2878 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2881 rtsp_reply_header(c, RTSP_STATUS_OK);
2882 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2883 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2884 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2885 avio_printf(c->pb, "\r\n");
2886 avio_write(c->pb, content, content_length);
2890 static HTTPContext *find_rtp_session(const char *session_id)
2894 if (session_id[0] == '\0')
2897 for(c = first_http_ctx; c; c = c->next) {
2898 if (!strcmp(c->session_id, session_id))
2904 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2906 RTSPTransportField *th;
2909 for(i=0;i<h->nb_transports;i++) {
2910 th = &h->transports[i];
2911 if (th->lower_transport == lower_transport)
2917 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2918 RTSPMessageHeader *h)
2920 FFServerStream *stream;
2921 int stream_index, rtp_port, rtcp_port;
2926 RTSPTransportField *th;
2927 struct sockaddr_in dest_addr;
2928 RTSPActionServerSetup setup;
2930 /* find which URL is asked */
2931 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2936 /* now check each stream */
2937 for(stream = config.first_stream; stream; stream = stream->next) {
2938 if (stream->is_feed || !stream->fmt ||
2939 strcmp(stream->fmt->name, "rtp")) {
2942 /* accept aggregate filenames only if single stream */
2943 if (!strcmp(path, stream->filename)) {
2944 if (stream->nb_streams != 1) {
2945 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2952 for(stream_index = 0; stream_index < stream->nb_streams;
2954 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2955 stream->filename, stream_index);
2956 if (!strcmp(path, buf))
2960 /* no stream found */
2961 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2965 /* generate session id if needed */
2966 if (h->session_id[0] == '\0') {
2967 unsigned random0 = av_lfg_get(&random_state);
2968 unsigned random1 = av_lfg_get(&random_state);
2969 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2973 /* find RTP session, and create it if none found */
2974 rtp_c = find_rtp_session(h->session_id);
2976 /* always prefer UDP */
2977 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2979 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2981 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2986 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2987 th->lower_transport);
2989 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2993 /* open input stream */
2994 if (open_input_stream(rtp_c, "") < 0) {
2995 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3000 /* test if stream is OK (test needed because several SETUP needs
3001 to be done for a given file) */
3002 if (rtp_c->stream != stream) {
3003 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3007 /* test if stream is already set up */
3008 if (rtp_c->rtp_ctx[stream_index]) {
3009 rtsp_reply_error(c, RTSP_STATUS_STATE);
3013 /* check transport */
3014 th = find_transport(h, rtp_c->rtp_protocol);
3015 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3016 th->client_port_min <= 0)) {
3017 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3021 /* setup default options */
3022 setup.transport_option[0] = '\0';
3023 dest_addr = rtp_c->from_addr;
3024 dest_addr.sin_port = htons(th->client_port_min);
3027 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3028 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3032 /* now everything is OK, so we can send the connection parameters */
3033 rtsp_reply_header(c, RTSP_STATUS_OK);
3035 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3037 switch(rtp_c->rtp_protocol) {
3038 case RTSP_LOWER_TRANSPORT_UDP:
3039 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3040 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3041 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3042 "client_port=%d-%d;server_port=%d-%d",
3043 th->client_port_min, th->client_port_max,
3044 rtp_port, rtcp_port);
3046 case RTSP_LOWER_TRANSPORT_TCP:
3047 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3048 stream_index * 2, stream_index * 2 + 1);
3053 if (setup.transport_option[0] != '\0')
3054 avio_printf(c->pb, ";%s", setup.transport_option);
3055 avio_printf(c->pb, "\r\n");
3058 avio_printf(c->pb, "\r\n");
3062 /* find an RTP connection by using the session ID. Check consistency
3064 static HTTPContext *find_rtp_session_with_url(const char *url,
3065 const char *session_id)
3073 rtp_c = find_rtp_session(session_id);
3077 /* find which URL is asked */
3078 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3082 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3083 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3084 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3085 rtp_c->stream->filename, s);
3086 if(!strncmp(path, buf, sizeof(buf))) {
3087 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3092 if (len > 0 && path[len - 1] == '/' &&
3093 !strncmp(path, rtp_c->stream->filename, len - 1))
3098 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3102 rtp_c = find_rtp_session_with_url(url, h->session_id);
3104 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3108 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3109 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3110 rtp_c->state != HTTPSTATE_READY) {
3111 rtsp_reply_error(c, RTSP_STATUS_STATE);
3115 rtp_c->state = HTTPSTATE_SEND_DATA;
3117 /* now everything is OK, so we can send the connection parameters */
3118 rtsp_reply_header(c, RTSP_STATUS_OK);
3120 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3121 avio_printf(c->pb, "\r\n");
3124 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3128 rtp_c = find_rtp_session_with_url(url, h->session_id);
3130 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3135 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3136 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3137 rtsp_reply_error(c, RTSP_STATUS_STATE);
3140 rtp_c->state = HTTPSTATE_READY;
3141 rtp_c->first_pts = AV_NOPTS_VALUE;
3144 /* now everything is OK, so we can send the connection parameters */
3145 rtsp_reply_header(c, RTSP_STATUS_OK);
3147 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3148 avio_printf(c->pb, "\r\n");
3151 close_connection(rtp_c);
3154 /********************************************************************/
3157 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3158 FFServerStream *stream, const char *session_id,
3159 enum RTSPLowerTransport rtp_protocol)
3161 HTTPContext *c = NULL;
3162 const char *proto_str;
3164 /* XXX: should output a warning page when coming
3165 close to the connection limit */
3166 if (nb_connections >= config.nb_max_connections)
3169 /* add a new connection */
3170 c = av_mallocz(sizeof(HTTPContext));
3175 c->poll_entry = NULL;
3176 c->from_addr = *from_addr;
3177 c->buffer_size = IOBUFFER_INIT_SIZE;
3178 c->buffer = av_malloc(c->buffer_size);
3183 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3184 c->state = HTTPSTATE_READY;
3185 c->is_packetized = 1;
3186 c->rtp_protocol = rtp_protocol;
3188 /* protocol is shown in statistics */
3189 switch(c->rtp_protocol) {
3190 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3191 proto_str = "MCAST";
3193 case RTSP_LOWER_TRANSPORT_UDP:
3196 case RTSP_LOWER_TRANSPORT_TCP:
3203 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3204 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3206 current_bandwidth += stream->bandwidth;
3208 c->next = first_http_ctx;
3214 av_freep(&c->buffer);
3220 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3221 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3223 static int rtp_new_av_stream(HTTPContext *c,
3224 int stream_index, struct sockaddr_in *dest_addr,
3225 HTTPContext *rtsp_c)
3227 AVFormatContext *ctx;
3230 URLContext *h = NULL;
3232 int max_packet_size;
3234 /* now we can open the relevant output stream */
3235 ctx = avformat_alloc_context();
3238 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3240 st = av_mallocz(sizeof(AVStream));
3243 ctx->nb_streams = 1;
3244 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3247 ctx->streams[0] = st;
3249 if (!c->stream->feed ||
3250 c->stream->feed == c->stream)
3251 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3254 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3256 st->priv_data = NULL;
3258 /* build destination RTP address */
3259 ipaddr = inet_ntoa(dest_addr->sin_addr);
3261 switch(c->rtp_protocol) {
3262 case RTSP_LOWER_TRANSPORT_UDP:
3263 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3266 /* XXX: also pass as parameter to function ? */
3267 if (c->stream->is_multicast) {
3269 ttl = c->stream->multicast_ttl;
3272 snprintf(ctx->filename, sizeof(ctx->filename),
3273 "rtp://%s:%d?multicast=1&ttl=%d",
3274 ipaddr, ntohs(dest_addr->sin_port), ttl);
3276 snprintf(ctx->filename, sizeof(ctx->filename),
3277 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3280 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3282 c->rtp_handles[stream_index] = h;
3283 max_packet_size = h->max_packet_size;
3285 case RTSP_LOWER_TRANSPORT_TCP:
3288 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3294 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3295 ipaddr, ntohs(dest_addr->sin_port),
3296 c->stream->filename, stream_index, c->protocol);
3298 /* normally, no packets should be output here, but the packet size may
3300 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3301 /* XXX: close stream */
3304 if (avformat_write_header(ctx, NULL) < 0) {
3312 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3315 c->rtp_ctx[stream_index] = ctx;
3319 /********************************************************************/
3320 /* ffserver initialization */
3322 static AVStream *add_av_stream1(FFServerStream *stream, AVCodecContext *codec, int copy)
3326 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3329 fst = av_mallocz(sizeof(AVStream));
3333 fst->codec = avcodec_alloc_context3(codec->codec);
3334 avcodec_copy_context(fst->codec, codec);
3336 /* live streams must use the actual feed's codec since it may be
3337 * updated later to carry extradata needed by them.
3341 fst->priv_data = av_mallocz(sizeof(FeedData));
3342 fst->index = stream->nb_streams;
3343 avpriv_set_pts_info(fst, 33, 1, 90000);
3344 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3345 stream->streams[stream->nb_streams++] = fst;
3349 /* return the stream number in the feed */
3350 static int add_av_stream(FFServerStream *feed, AVStream *st)
3353 AVCodecContext *av, *av1;
3357 for(i=0;i<feed->nb_streams;i++) {
3358 av1 = feed->streams[i]->codec;
3359 if (av1->codec_id == av->codec_id &&
3360 av1->codec_type == av->codec_type &&
3361 av1->bit_rate == av->bit_rate) {
3363 switch(av->codec_type) {
3364 case AVMEDIA_TYPE_AUDIO:
3365 if (av1->channels == av->channels &&
3366 av1->sample_rate == av->sample_rate)
3369 case AVMEDIA_TYPE_VIDEO:
3370 if (av1->width == av->width &&
3371 av1->height == av->height &&
3372 av1->time_base.den == av->time_base.den &&
3373 av1->time_base.num == av->time_base.num &&
3374 av1->gop_size == av->gop_size)
3383 fst = add_av_stream1(feed, av, 0);
3386 if (av_stream_get_recommended_encoder_configuration(st))
3387 av_stream_set_recommended_encoder_configuration(fst,
3388 av_strdup(av_stream_get_recommended_encoder_configuration(st)));
3389 return feed->nb_streams - 1;
3392 static void remove_stream(FFServerStream *stream)
3394 FFServerStream **ps;
3395 ps = &config.first_stream;
3404 /* specific MPEG4 handling : we extract the raw parameters */
3405 static void extract_mpeg4_header(AVFormatContext *infile)
3407 int mpeg4_count, i, size;
3412 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3415 for(i=0;i<infile->nb_streams;i++) {
3416 st = infile->streams[i];
3417 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3418 st->codec->extradata_size == 0) {
3425 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3426 while (mpeg4_count > 0) {
3427 if (av_read_frame(infile, &pkt) < 0)
3429 st = infile->streams[pkt.stream_index];
3430 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3431 st->codec->extradata_size == 0) {
3432 av_freep(&st->codec->extradata);
3433 /* fill extradata with the header */
3434 /* XXX: we make hard suppositions here ! */
3436 while (p < pkt.data + pkt.size - 4) {
3437 /* stop when vop header is found */
3438 if (p[0] == 0x00 && p[1] == 0x00 &&
3439 p[2] == 0x01 && p[3] == 0xb6) {
3440 size = p - pkt.data;
3441 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3442 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3443 st->codec->extradata_size = size;
3444 memcpy(st->codec->extradata, pkt.data, size);
3451 av_free_packet(&pkt);
3455 /* compute the needed AVStream for each file */
3456 static void build_file_streams(void)
3458 FFServerStream *stream, *stream_next;
3461 /* gather all streams */
3462 for(stream = config.first_stream; stream; stream = stream_next) {
3463 AVFormatContext *infile = NULL;
3464 stream_next = stream->next;
3465 if (stream->stream_type == STREAM_TYPE_LIVE &&
3467 /* the stream comes from a file */
3468 /* try to open the file */
3470 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3471 /* specific case : if transport stream output to RTP,
3472 we use a raw transport stream reader */
3473 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3476 if (!stream->feed_filename[0]) {
3477 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3481 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3482 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3483 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3484 /* remove stream (no need to spend more time on it) */
3486 remove_stream(stream);
3488 /* find all the AVStreams inside and reference them in
3490 if (avformat_find_stream_info(infile, NULL) < 0) {
3491 http_log("Could not find codec parameters from '%s'\n",
3492 stream->feed_filename);
3493 avformat_close_input(&infile);
3496 extract_mpeg4_header(infile);
3498 for(i=0;i<infile->nb_streams;i++)
3499 add_av_stream1(stream, infile->streams[i]->codec, 1);
3501 avformat_close_input(&infile);
3507 /* compute the needed AVStream for each feed */
3508 static void build_feed_streams(void)
3510 FFServerStream *stream, *feed;
3513 /* gather all streams */
3514 for(stream = config.first_stream; stream; stream = stream->next) {
3515 feed = stream->feed;
3517 if (stream->is_feed) {
3518 for(i=0;i<stream->nb_streams;i++)
3519 stream->feed_streams[i] = i;
3521 /* we handle a stream coming from a feed */
3522 for(i=0;i<stream->nb_streams;i++)
3523 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3528 /* create feed files if needed */
3529 for(feed = config.first_feed; feed; feed = feed->next_feed) {
3532 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3533 /* See if it matches */
3534 AVFormatContext *s = NULL;
3537 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3538 /* set buffer size */
3539 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3540 /* Now see if it matches */
3541 if (s->nb_streams == feed->nb_streams) {
3543 for(i=0;i<s->nb_streams;i++) {
3545 sf = feed->streams[i];
3548 if (sf->index != ss->index ||
3550 http_log("Index & Id do not match for stream %d (%s)\n",
3551 i, feed->feed_filename);
3554 AVCodecContext *ccf, *ccs;
3558 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3560 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3561 http_log("Codecs do not match for stream %d\n", i);
3563 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3564 http_log("Codec bitrates do not match for stream %d\n", i);
3566 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3567 if (CHECK_CODEC(time_base.den) ||
3568 CHECK_CODEC(time_base.num) ||
3569 CHECK_CODEC(width) ||
3570 CHECK_CODEC(height)) {
3571 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3574 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3575 if (CHECK_CODEC(sample_rate) ||
3576 CHECK_CODEC(channels) ||
3577 CHECK_CODEC(frame_size)) {
3578 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3582 http_log("Unknown codec type\n");
3590 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3591 feed->feed_filename, s->nb_streams, feed->nb_streams);
3593 avformat_close_input(&s);
3595 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3596 feed->feed_filename);
3599 if (feed->readonly) {
3600 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3601 feed->feed_filename);
3604 unlink(feed->feed_filename);
3607 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3608 AVFormatContext *s = avformat_alloc_context();
3610 if (feed->readonly) {
3611 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3612 feed->feed_filename);
3616 /* only write the header of the ffm file */
3617 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3618 http_log("Could not open output feed file '%s'\n",
3619 feed->feed_filename);
3622 s->oformat = feed->fmt;
3623 s->nb_streams = feed->nb_streams;
3624 s->streams = feed->streams;
3625 if (avformat_write_header(s, NULL) < 0) {
3626 http_log("Container doesn't support the required parameters\n");
3629 /* XXX: need better API */
3630 av_freep(&s->priv_data);
3631 avio_closep(&s->pb);
3634 avformat_free_context(s);
3636 /* get feed size and write index */
3637 fd = open(feed->feed_filename, O_RDONLY);
3639 http_log("Could not open output feed file '%s'\n",
3640 feed->feed_filename);
3644 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3645 feed->feed_size = lseek(fd, 0, SEEK_END);
3646 /* ensure that we do not wrap before the end of file */
3647 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3648 feed->feed_max_size = feed->feed_size;
3654 /* compute the bandwidth used by each stream */
3655 static void compute_bandwidth(void)
3659 FFServerStream *stream;
3661 for(stream = config.first_stream; stream; stream = stream->next) {
3663 for(i=0;i<stream->nb_streams;i++) {
3664 AVStream *st = stream->streams[i];
3665 switch(st->codec->codec_type) {
3666 case AVMEDIA_TYPE_AUDIO:
3667 case AVMEDIA_TYPE_VIDEO:
3668 bandwidth += st->codec->bit_rate;
3674 stream->bandwidth = (bandwidth + 999) / 1000;
3678 static void handle_child_exit(int sig)
3683 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3684 FFServerStream *feed;
3686 for (feed = config.first_feed; feed; feed = feed->next) {
3687 if (feed->pid == pid) {
3688 int uptime = time(0) - feed->pid_start;
3691 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
3694 /* Turn off any more restarts */
3695 ffserver_free_child_args(&feed->child_argv);
3700 need_to_start_children = 1;
3703 static void opt_debug(void)
3706 snprintf(config.logfilename, sizeof(config.logfilename), "-");
3709 void show_help_default(const char *opt, const char *arg)
3711 printf("usage: ffserver [options]\n"
3712 "Hyper fast multi format Audio/Video streaming server\n");
3714 show_help_options(options, "Main options:", 0, 0, 0);
3717 static const OptionDef options[] = {
3718 #include "cmdutils_common_opts.h"
3719 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3720 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3721 { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3725 int main(int argc, char **argv)
3727 struct sigaction sigact = { { 0 } };
3730 config.filename = av_strdup("/etc/ffserver.conf");
3732 parse_loglevel(argc, argv, options);
3734 avformat_network_init();
3736 show_banner(argc, argv, options);
3738 my_program_name = argv[0];
3740 parse_options(NULL, argc, argv, options, NULL);
3742 unsetenv("http_proxy"); /* Kill the http_proxy */
3744 av_lfg_init(&random_state, av_get_random_seed());
3746 sigact.sa_handler = handle_child_exit;
3747 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3748 sigaction(SIGCHLD, &sigact, 0);
3750 if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3751 fprintf(stderr, "Error reading configuration file '%s': %s\n",
3752 config.filename, av_err2str(ret));
3755 av_freep(&config.filename);
3757 /* open log file if needed */
3758 if (config.logfilename[0] != '\0') {
3759 if (!strcmp(config.logfilename, "-"))
3762 logfile = fopen(config.logfilename, "a");
3763 av_log_set_callback(http_av_log);
3766 build_file_streams();
3768 build_feed_streams();
3770 compute_bandwidth();
3773 signal(SIGPIPE, SIG_IGN);
3775 if (http_server() < 0) {
3776 http_log("Could not start server\n");