2
* Multiple format streaming server
3
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
5
* This file is part of Libav.
7
* Libav is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
12
* Libav is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with Libav; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24
#define closesocket close
29
#include "libavformat/avformat.h"
30
#include "libavformat/ffm.h"
31
#include "libavformat/network.h"
32
#include "libavformat/os_support.h"
33
#include "libavformat/rtpdec.h"
34
#include "libavformat/rtsp.h"
35
// XXX for ffio_open_dyn_packet_buffer, to be removed
36
#include "libavformat/avio_internal.h"
37
#include "libavutil/avstring.h"
38
#include "libavutil/lfg.h"
39
#include "libavutil/dict.h"
40
#include "libavutil/random_seed.h"
41
#include "libavutil/parseutils.h"
42
#include "libavutil/opt.h"
46
#include <sys/ioctl.h>
61
const char program_name[] = "ffserver";
62
const int program_birth_year = 2000;
64
static const OptionDef options[];
67
HTTPSTATE_WAIT_REQUEST,
68
HTTPSTATE_SEND_HEADER,
69
HTTPSTATE_SEND_DATA_HEADER,
70
HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
71
HTTPSTATE_SEND_DATA_TRAILER,
72
HTTPSTATE_RECEIVE_DATA,
73
HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
76
RTSPSTATE_WAIT_REQUEST,
78
RTSPSTATE_SEND_PACKET,
81
static const char *http_state[] = {
97
#define MAX_STREAMS 20
99
#define IOBUFFER_INIT_SIZE 8192
101
/* timeouts are in ms */
102
#define HTTP_REQUEST_TIMEOUT (15 * 1000)
103
#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
105
#define SYNC_TIMEOUT (10 * 1000)
107
typedef struct RTSPActionServerSetup {
109
char transport_option[512];
110
} RTSPActionServerSetup;
113
int64_t count1, count2;
114
int64_t time1, time2;
117
/* context associated with one connection */
118
typedef struct HTTPContext {
119
enum HTTPState state;
120
int fd; /* socket file descriptor */
121
struct sockaddr_in from_addr; /* origin */
122
struct pollfd *poll_entry; /* used when polling */
124
uint8_t *buffer_ptr, *buffer_end;
127
int chunked_encoding;
128
int chunk_size; /* 0 if it needs to be read */
129
struct HTTPContext *next;
130
int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
134
/* input format handling */
135
AVFormatContext *fmt_in;
136
int64_t start_time; /* In milliseconds - this wraps fairly often */
137
int64_t first_pts; /* initial pts value */
138
int64_t cur_pts; /* current pts value from the stream in us */
139
int64_t cur_frame_duration; /* duration of the current frame in us */
140
int cur_frame_bytes; /* output frame size, needed to compute
141
the time at which we send each
143
int pts_stream_index; /* stream we choose as clock reference */
144
int64_t cur_clock; /* current clock reference value in us */
145
/* output format handling */
146
struct FFStream *stream;
147
/* -1 is invalid stream */
148
int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
149
int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
151
AVFormatContext fmt_ctx; /* instance of FFStream for one user */
152
int last_packet_sent; /* true if last data packet was sent */
154
DataRateData datarate;
161
int is_packetized; /* if true, the stream is packetized */
162
int packet_stream_index; /* current stream for output in state machine */
164
/* RTSP state specific */
165
uint8_t *pb_buffer; /* XXX: use that in all the code */
167
int seq; /* RTSP sequence number */
169
/* RTP state specific */
170
enum RTSPLowerTransport rtp_protocol;
171
char session_id[32]; /* session id */
172
AVFormatContext *rtp_ctx[MAX_STREAMS];
174
/* RTP/UDP specific */
175
URLContext *rtp_handles[MAX_STREAMS];
177
/* RTP/TCP specific */
178
struct HTTPContext *rtsp_c;
179
uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
182
/* each generated stream is described here */
186
STREAM_TYPE_REDIRECT,
189
enum IPAddressAction {
194
typedef struct IPAddressACL {
195
struct IPAddressACL *next;
196
enum IPAddressAction action;
197
/* These are in host order */
198
struct in_addr first;
202
/* description of each stream of the ffserver.conf file */
203
typedef struct FFStream {
204
enum StreamType stream_type;
205
char filename[1024]; /* stream filename */
206
struct FFStream *feed; /* feed we are using (can be null if
208
AVDictionary *in_opts; /* input parameters */
209
AVInputFormat *ifmt; /* if non NULL, force input format */
212
char dynamic_acl[1024];
214
int prebuffer; /* Number of millseconds early to start */
215
int64_t max_time; /* Number of milliseconds to run */
217
AVStream *streams[MAX_STREAMS];
218
int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
219
char feed_filename[1024]; /* file name of the feed storage, or
220
input file name for a stream */
225
pid_t pid; /* Of ffmpeg process */
226
time_t pid_start; /* Of ffmpeg process */
228
struct FFStream *next;
229
unsigned bandwidth; /* bandwidth, in kbits/s */
232
/* multicast specific */
234
struct in_addr multicast_ip;
235
int multicast_port; /* first port used for multicast */
237
int loop; /* if true, send the stream in loops (only meaningful if file) */
240
int feed_opened; /* true if someone is writing to the feed */
241
int is_feed; /* true if it is a feed */
242
int readonly; /* True if writing is prohibited to the file */
243
int truncate; /* True if feeder connection truncate the feed file */
245
int64_t bytes_served;
246
int64_t feed_max_size; /* maximum storage size, zero means unlimited */
247
int64_t feed_write_index; /* current write position in feed (it wraps around) */
248
int64_t feed_size; /* current size of feed */
249
struct FFStream *next_feed;
252
typedef struct FeedData {
253
long long data_count;
254
float avg_frame_size; /* frame size averaged over last frames with exponential mean */
257
static struct sockaddr_in my_http_addr;
258
static struct sockaddr_in my_rtsp_addr;
260
static char logfilename[1024];
261
static HTTPContext *first_http_ctx;
262
static FFStream *first_feed; /* contains only feeds */
263
static FFStream *first_stream; /* contains all streams, including feeds */
265
static void new_connection(int server_fd, int is_rtsp);
266
static void close_connection(HTTPContext *c);
269
static int handle_connection(HTTPContext *c);
270
static int http_parse_request(HTTPContext *c);
271
static int http_send_data(HTTPContext *c);
272
static void compute_status(HTTPContext *c);
273
static int open_input_stream(HTTPContext *c, const char *info);
274
static int http_start_receive_data(HTTPContext *c);
275
static int http_receive_data(HTTPContext *c);
278
static int rtsp_parse_request(HTTPContext *c);
279
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
280
static void rtsp_cmd_options(HTTPContext *c, const char *url);
281
static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
282
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
283
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
284
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
287
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
288
struct in_addr my_ip);
291
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
292
FFStream *stream, const char *session_id,
293
enum RTSPLowerTransport rtp_protocol);
294
static int rtp_new_av_stream(HTTPContext *c,
295
int stream_index, struct sockaddr_in *dest_addr,
296
HTTPContext *rtsp_c);
298
static const char *my_program_name;
299
static const char *my_program_dir;
301
static const char *config_filename = "/etc/ffserver.conf";
303
static int ffserver_debug;
304
static int ffserver_daemon;
305
static int no_launch;
306
static int need_to_start_children;
308
/* maximum number of simultaneous HTTP connections */
309
static unsigned int nb_max_http_connections = 2000;
310
static unsigned int nb_max_connections = 5;
311
static unsigned int nb_connections;
313
static uint64_t max_bandwidth = 1000;
314
static uint64_t current_bandwidth;
316
static int64_t cur_time; // Making this global saves on passing it around everywhere
318
static AVLFG random_state;
320
static FILE *logfile = NULL;
322
/* FIXME: make ffserver work with IPv6 */
323
/* resolve host with also IP address parsing */
324
static int resolve_host(struct in_addr *sin_addr, const char *hostname)
327
if (!ff_inet_aton(hostname, sin_addr)) {
329
struct addrinfo *ai, *cur;
330
struct addrinfo hints;
331
memset(&hints, 0, sizeof(hints));
332
hints.ai_family = AF_INET;
333
if (getaddrinfo(hostname, NULL, &hints, &ai))
335
/* getaddrinfo returns a linked list of addrinfo structs.
336
* Even if we set ai_family = AF_INET above, make sure
337
* that the returned one actually is of the correct type. */
338
for (cur = ai; cur; cur = cur->ai_next) {
339
if (cur->ai_family == AF_INET) {
340
*sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
349
hp = gethostbyname(hostname);
352
memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
358
static char *ctime1(char *buf2)
366
p = buf2 + strlen(p) - 1;
372
static void http_vlog(const char *fmt, va_list vargs)
374
static int print_prefix = 1;
379
fprintf(logfile, "%s ", buf);
381
print_prefix = strstr(fmt, "\n") != NULL;
382
vfprintf(logfile, fmt, vargs);
388
__attribute__ ((format (printf, 1, 2)))
390
static void http_log(const char *fmt, ...)
393
va_start(vargs, fmt);
394
http_vlog(fmt, vargs);
398
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
400
static int print_prefix = 1;
401
AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
402
if (level > av_log_get_level())
404
if (print_prefix && avc)
405
http_log("[%s @ %p]", avc->item_name(ptr), ptr);
406
print_prefix = strstr(fmt, "\n") != NULL;
407
http_vlog(fmt, vargs);
410
static void log_connection(HTTPContext *c)
415
http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
416
inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
417
c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
420
static void update_datarate(DataRateData *drd, int64_t count)
422
if (!drd->time1 && !drd->count1) {
423
drd->time1 = drd->time2 = cur_time;
424
drd->count1 = drd->count2 = count;
425
} else if (cur_time - drd->time2 > 5000) {
426
drd->time1 = drd->time2;
427
drd->count1 = drd->count2;
428
drd->time2 = cur_time;
433
/* In bytes per second */
434
static int compute_datarate(DataRateData *drd, int64_t count)
436
if (cur_time == drd->time1)
439
return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
443
static void start_children(FFStream *feed)
448
for (; feed; feed = feed->next) {
449
if (feed->child_argv && !feed->pid) {
450
feed->pid_start = time(0);
455
http_log("Unable to create children\n");
464
av_strlcpy(pathname, my_program_name, sizeof(pathname));
466
slash = strrchr(pathname, '/');
471
strcpy(slash, "ffmpeg");
473
http_log("Launch commandline: ");
474
http_log("%s ", pathname);
475
for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
476
http_log("%s ", feed->child_argv[i]);
479
for (i = 3; i < 256; i++)
482
if (!ffserver_debug) {
483
i = open("/dev/null", O_RDWR);
492
/* This is needed to make relative pathnames work */
493
chdir(my_program_dir);
495
signal(SIGPIPE, SIG_DFL);
497
execvp(pathname, feed->child_argv);
505
/* open a listening socket */
506
static int socket_open_listen(struct sockaddr_in *my_addr)
510
server_fd = socket(AF_INET,SOCK_STREAM,0);
517
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
519
if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
521
snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
523
closesocket(server_fd);
527
if (listen (server_fd, 5) < 0) {
529
closesocket(server_fd);
532
ff_socket_nonblock(server_fd, 1);
537
/* start all multicast streams */
538
static void start_multicast(void)
543
struct sockaddr_in dest_addr;
544
int default_port, stream_index;
547
for(stream = first_stream; stream != NULL; stream = stream->next) {
548
if (stream->is_multicast) {
549
/* open the RTP connection */
550
snprintf(session_id, sizeof(session_id), "%08x%08x",
551
av_lfg_get(&random_state), av_lfg_get(&random_state));
553
/* choose a port if none given */
554
if (stream->multicast_port == 0) {
555
stream->multicast_port = default_port;
559
dest_addr.sin_family = AF_INET;
560
dest_addr.sin_addr = stream->multicast_ip;
561
dest_addr.sin_port = htons(stream->multicast_port);
563
rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
564
RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
568
if (open_input_stream(rtp_c, "") < 0) {
569
http_log("Could not open input stream for stream '%s'\n",
574
/* open each RTP stream */
575
for(stream_index = 0; stream_index < stream->nb_streams;
577
dest_addr.sin_port = htons(stream->multicast_port +
579
if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
580
http_log("Could not open output stream '%s/streamid=%d'\n",
581
stream->filename, stream_index);
586
/* change state to send data */
587
rtp_c->state = HTTPSTATE_SEND_DATA;
592
/* main loop of the http server */
593
static int http_server(void)
595
int server_fd = 0, rtsp_server_fd = 0;
596
int ret, delay, delay1;
597
struct pollfd *poll_table, *poll_entry;
598
HTTPContext *c, *c_next;
600
if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
601
http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
605
if (my_http_addr.sin_port) {
606
server_fd = socket_open_listen(&my_http_addr);
611
if (my_rtsp_addr.sin_port) {
612
rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
613
if (rtsp_server_fd < 0)
617
if (!rtsp_server_fd && !server_fd) {
618
http_log("HTTP and RTSP disabled.\n");
622
http_log("FFserver started.\n");
624
start_children(first_feed);
629
poll_entry = poll_table;
631
poll_entry->fd = server_fd;
632
poll_entry->events = POLLIN;
635
if (rtsp_server_fd) {
636
poll_entry->fd = rtsp_server_fd;
637
poll_entry->events = POLLIN;
641
/* wait for events on each HTTP handle */
648
case HTTPSTATE_SEND_HEADER:
649
case RTSPSTATE_SEND_REPLY:
650
case RTSPSTATE_SEND_PACKET:
651
c->poll_entry = poll_entry;
653
poll_entry->events = POLLOUT;
656
case HTTPSTATE_SEND_DATA_HEADER:
657
case HTTPSTATE_SEND_DATA:
658
case HTTPSTATE_SEND_DATA_TRAILER:
659
if (!c->is_packetized) {
660
/* for TCP, we output as much as we can (may need to put a limit) */
661
c->poll_entry = poll_entry;
663
poll_entry->events = POLLOUT;
666
/* when ffserver is doing the timing, we work by
667
looking at which packet need to be sent every
669
delay1 = 10; /* one tick wait XXX: 10 ms assumed */
674
case HTTPSTATE_WAIT_REQUEST:
675
case HTTPSTATE_RECEIVE_DATA:
676
case HTTPSTATE_WAIT_FEED:
677
case RTSPSTATE_WAIT_REQUEST:
678
/* need to catch errors */
679
c->poll_entry = poll_entry;
681
poll_entry->events = POLLIN;/* Maybe this will work */
685
c->poll_entry = NULL;
691
/* wait for an event on one connection. We poll at least every
692
second to handle timeouts */
694
ret = poll(poll_table, poll_entry - poll_table, delay);
695
if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
696
ff_neterrno() != AVERROR(EINTR))
700
cur_time = av_gettime() / 1000;
702
if (need_to_start_children) {
703
need_to_start_children = 0;
704
start_children(first_feed);
707
/* now handle the events */
708
for(c = first_http_ctx; c != NULL; c = c_next) {
710
if (handle_connection(c) < 0) {
711
/* close and free the connection */
717
poll_entry = poll_table;
719
/* new HTTP connection request ? */
720
if (poll_entry->revents & POLLIN)
721
new_connection(server_fd, 0);
724
if (rtsp_server_fd) {
725
/* new RTSP connection request ? */
726
if (poll_entry->revents & POLLIN)
727
new_connection(rtsp_server_fd, 1);
732
/* start waiting for a new HTTP/RTSP request */
733
static void start_wait_request(HTTPContext *c, int is_rtsp)
735
c->buffer_ptr = c->buffer;
736
c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
739
c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
740
c->state = RTSPSTATE_WAIT_REQUEST;
742
c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
743
c->state = HTTPSTATE_WAIT_REQUEST;
747
static void http_send_too_busy_reply(int fd)
750
int len = snprintf(buffer, sizeof(buffer),
751
"HTTP/1.0 503 Server too busy\r\n"
752
"Content-type: text/html\r\n"
754
"<html><head><title>Too busy</title></head><body>\r\n"
755
"<p>The server is too busy to serve your request at this time.</p>\r\n"
756
"<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
757
"</body></html>\r\n",
758
nb_connections, nb_max_connections);
759
send(fd, buffer, len, 0);
763
static void new_connection(int server_fd, int is_rtsp)
765
struct sockaddr_in from_addr;
767
HTTPContext *c = NULL;
769
len = sizeof(from_addr);
770
fd = accept(server_fd, (struct sockaddr *)&from_addr,
773
http_log("error during accept %s\n", strerror(errno));
776
ff_socket_nonblock(fd, 1);
778
if (nb_connections >= nb_max_connections) {
779
http_send_too_busy_reply(fd);
783
/* add a new connection */
784
c = av_mallocz(sizeof(HTTPContext));
789
c->poll_entry = NULL;
790
c->from_addr = from_addr;
791
c->buffer_size = IOBUFFER_INIT_SIZE;
792
c->buffer = av_malloc(c->buffer_size);
796
c->next = first_http_ctx;
800
start_wait_request(c, is_rtsp);
812
static void close_connection(HTTPContext *c)
814
HTTPContext **cp, *c1;
816
AVFormatContext *ctx;
820
/* remove connection from list */
821
cp = &first_http_ctx;
822
while ((*cp) != NULL) {
830
/* remove references, if any (XXX: do it faster) */
831
for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
836
/* remove connection associated resources */
840
/* close each frame parser */
841
for(i=0;i<c->fmt_in->nb_streams;i++) {
842
st = c->fmt_in->streams[i];
843
if (st->codec->codec)
844
avcodec_close(st->codec);
846
av_close_input_file(c->fmt_in);
849
/* free RTP output streams if any */
852
nb_streams = c->stream->nb_streams;
854
for(i=0;i<nb_streams;i++) {
857
av_write_trailer(ctx);
858
av_dict_free(&ctx->metadata);
859
av_free(ctx->streams[0]);
862
h = c->rtp_handles[i];
869
if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
872
if (avio_open_dyn_buf(&ctx->pb) >= 0) {
873
av_write_trailer(ctx);
874
av_freep(&c->pb_buffer);
875
avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
880
for(i=0; i<ctx->nb_streams; i++)
881
av_free(ctx->streams[i]);
883
if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
884
current_bandwidth -= c->stream->bandwidth;
886
/* signal that there is no feed if we are the feeder socket */
887
if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
888
c->stream->feed_opened = 0;
892
av_freep(&c->pb_buffer);
893
av_freep(&c->packet_buffer);
899
static int handle_connection(HTTPContext *c)
904
case HTTPSTATE_WAIT_REQUEST:
905
case RTSPSTATE_WAIT_REQUEST:
907
if ((c->timeout - cur_time) < 0)
909
if (c->poll_entry->revents & (POLLERR | POLLHUP))
912
/* no need to read if no events */
913
if (!(c->poll_entry->revents & POLLIN))
917
len = recv(c->fd, c->buffer_ptr, 1, 0);
919
if (ff_neterrno() != AVERROR(EAGAIN) &&
920
ff_neterrno() != AVERROR(EINTR))
922
} else if (len == 0) {
925
/* search for end of request. */
927
c->buffer_ptr += len;
929
if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
930
(ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
931
/* request found : parse it and reply */
932
if (c->state == HTTPSTATE_WAIT_REQUEST) {
933
ret = http_parse_request(c);
935
ret = rtsp_parse_request(c);
939
} else if (ptr >= c->buffer_end) {
940
/* request too long: cannot do anything */
942
} else goto read_loop;
946
case HTTPSTATE_SEND_HEADER:
947
if (c->poll_entry->revents & (POLLERR | POLLHUP))
950
/* no need to write if no events */
951
if (!(c->poll_entry->revents & POLLOUT))
953
len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
955
if (ff_neterrno() != AVERROR(EAGAIN) &&
956
ff_neterrno() != AVERROR(EINTR)) {
957
/* error : close connection */
958
av_freep(&c->pb_buffer);
962
c->buffer_ptr += len;
964
c->stream->bytes_served += len;
965
c->data_count += len;
966
if (c->buffer_ptr >= c->buffer_end) {
967
av_freep(&c->pb_buffer);
971
/* all the buffer was sent : synchronize to the incoming stream */
972
c->state = HTTPSTATE_SEND_DATA_HEADER;
973
c->buffer_ptr = c->buffer_end = c->buffer;
978
case HTTPSTATE_SEND_DATA:
979
case HTTPSTATE_SEND_DATA_HEADER:
980
case HTTPSTATE_SEND_DATA_TRAILER:
981
/* for packetized output, we consider we can always write (the
982
input streams sets the speed). It may be better to verify
983
that we do not rely too much on the kernel queues */
984
if (!c->is_packetized) {
985
if (c->poll_entry->revents & (POLLERR | POLLHUP))
988
/* no need to read if no events */
989
if (!(c->poll_entry->revents & POLLOUT))
992
if (http_send_data(c) < 0)
994
/* close connection if trailer sent */
995
if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
998
case HTTPSTATE_RECEIVE_DATA:
999
/* no need to read if no events */
1000
if (c->poll_entry->revents & (POLLERR | POLLHUP))
1002
if (!(c->poll_entry->revents & POLLIN))
1004
if (http_receive_data(c) < 0)
1007
case HTTPSTATE_WAIT_FEED:
1008
/* no need to read if no events */
1009
if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1012
/* nothing to do, we'll be waken up by incoming feed packets */
1015
case RTSPSTATE_SEND_REPLY:
1016
if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1017
av_freep(&c->pb_buffer);
1020
/* no need to write if no events */
1021
if (!(c->poll_entry->revents & POLLOUT))
1023
len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1025
if (ff_neterrno() != AVERROR(EAGAIN) &&
1026
ff_neterrno() != AVERROR(EINTR)) {
1027
/* error : close connection */
1028
av_freep(&c->pb_buffer);
1032
c->buffer_ptr += len;
1033
c->data_count += len;
1034
if (c->buffer_ptr >= c->buffer_end) {
1035
/* all the buffer was sent : wait for a new request */
1036
av_freep(&c->pb_buffer);
1037
start_wait_request(c, 1);
1041
case RTSPSTATE_SEND_PACKET:
1042
if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1043
av_freep(&c->packet_buffer);
1046
/* no need to write if no events */
1047
if (!(c->poll_entry->revents & POLLOUT))
1049
len = send(c->fd, c->packet_buffer_ptr,
1050
c->packet_buffer_end - c->packet_buffer_ptr, 0);
1052
if (ff_neterrno() != AVERROR(EAGAIN) &&
1053
ff_neterrno() != AVERROR(EINTR)) {
1054
/* error : close connection */
1055
av_freep(&c->packet_buffer);
1059
c->packet_buffer_ptr += len;
1060
if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1061
/* all the buffer was sent : wait for a new request */
1062
av_freep(&c->packet_buffer);
1063
c->state = RTSPSTATE_WAIT_REQUEST;
1067
case HTTPSTATE_READY:
1076
static int extract_rates(char *rates, int ratelen, const char *request)
1080
for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1081
if (strncasecmp(p, "Pragma:", 7) == 0) {
1082
const char *q = p + 7;
1084
while (*q && *q != '\n' && isspace(*q))
1087
if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1093
memset(rates, 0xff, ratelen);
1096
while (*q && *q != '\n' && *q != ':')
1099
if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1103
if (stream_no < ratelen && stream_no >= 0)
1104
rates[stream_no] = rate_no;
1106
while (*q && *q != '\n' && !isspace(*q))
1113
p = strchr(p, '\n');
1123
static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1126
int best_bitrate = 100000000;
1129
for (i = 0; i < feed->nb_streams; i++) {
1130
AVCodecContext *feed_codec = feed->streams[i]->codec;
1132
if (feed_codec->codec_id != codec->codec_id ||
1133
feed_codec->sample_rate != codec->sample_rate ||
1134
feed_codec->width != codec->width ||
1135
feed_codec->height != codec->height)
1138
/* Potential stream */
1140
/* We want the fastest stream less than bit_rate, or the slowest
1141
* faster than bit_rate
1144
if (feed_codec->bit_rate <= bit_rate) {
1145
if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1146
best_bitrate = feed_codec->bit_rate;
1150
if (feed_codec->bit_rate < best_bitrate) {
1151
best_bitrate = feed_codec->bit_rate;
1160
static int modify_current_stream(HTTPContext *c, char *rates)
1163
FFStream *req = c->stream;
1164
int action_required = 0;
1166
/* Not much we can do for a feed */
1170
for (i = 0; i < req->nb_streams; i++) {
1171
AVCodecContext *codec = req->streams[i]->codec;
1175
c->switch_feed_streams[i] = req->feed_streams[i];
1178
c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1181
/* Wants off or slow */
1182
c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1184
/* This doesn't work well when it turns off the only stream! */
1185
c->switch_feed_streams[i] = -2;
1186
c->feed_streams[i] = -2;
1191
if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1192
action_required = 1;
1195
return action_required;
1198
/* XXX: factorize in utils.c ? */
1199
/* XXX: take care with different space meaning */
1200
static void skip_spaces(const char **pp)
1204
while (*p == ' ' || *p == '\t')
1209
static void get_word(char *buf, int buf_size, const char **pp)
1217
while (!isspace(*p) && *p != '\0') {
1218
if ((q - buf) < buf_size - 1)
1227
static void get_arg(char *buf, int buf_size, const char **pp)
1234
while (isspace(*p)) p++;
1237
if (*p == '\"' || *p == '\'')
1249
if ((q - buf) < buf_size - 1)
1254
if (quote && *p == quote)
1259
static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1260
const char *p, const char *filename, int line_num)
1266
get_arg(arg, sizeof(arg), &p);
1267
if (strcasecmp(arg, "allow") == 0)
1268
acl.action = IP_ALLOW;
1269
else if (strcasecmp(arg, "deny") == 0)
1270
acl.action = IP_DENY;
1272
fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1273
filename, line_num, arg);
1277
get_arg(arg, sizeof(arg), &p);
1279
if (resolve_host(&acl.first, arg) != 0) {
1280
fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1281
filename, line_num, arg);
1284
acl.last = acl.first;
1286
get_arg(arg, sizeof(arg), &p);
1289
if (resolve_host(&acl.last, arg) != 0) {
1290
fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1291
filename, line_num, arg);
1297
IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1298
IPAddressACL **naclp = 0;
1304
naclp = &stream->acl;
1310
fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1311
filename, line_num);
1317
naclp = &(*naclp)->next;
1325
static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1330
IPAddressACL *acl = NULL;
1334
f = fopen(stream->dynamic_acl, "r");
1336
perror(stream->dynamic_acl);
1340
acl = av_mallocz(sizeof(IPAddressACL));
1344
if (fgets(line, sizeof(line), f) == NULL)
1350
if (*p == '\0' || *p == '#')
1352
get_arg(cmd, sizeof(cmd), &p);
1354
if (!strcasecmp(cmd, "ACL"))
1355
parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1362
static void free_acl_list(IPAddressACL *in_acl)
1364
IPAddressACL *pacl,*pacl2;
1374
static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1376
enum IPAddressAction last_action = IP_DENY;
1378
struct in_addr *src = &c->from_addr.sin_addr;
1379
unsigned long src_addr = src->s_addr;
1381
for (acl = in_acl; acl; acl = acl->next) {
1382
if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1383
return (acl->action == IP_ALLOW) ? 1 : 0;
1384
last_action = acl->action;
1387
/* Nothing matched, so return not the last action */
1388
return (last_action == IP_DENY) ? 1 : 0;
1391
static int validate_acl(FFStream *stream, HTTPContext *c)
1397
/* if stream->acl is null validate_acl_list will return 1 */
1398
ret = validate_acl_list(stream->acl, c);
1400
if (stream->dynamic_acl[0]) {
1401
acl = parse_dynamic_acl(stream, c);
1403
ret = validate_acl_list(acl, c);
1411
/* compute the real filename of a file by matching it without its
1412
extensions to all the stream filenames */
1413
static void compute_real_filename(char *filename, int max_size)
1420
/* compute filename by matching without the file extensions */
1421
av_strlcpy(file1, filename, sizeof(file1));
1422
p = strrchr(file1, '.');
1425
for(stream = first_stream; stream != NULL; stream = stream->next) {
1426
av_strlcpy(file2, stream->filename, sizeof(file2));
1427
p = strrchr(file2, '.');
1430
if (!strcmp(file1, file2)) {
1431
av_strlcpy(filename, stream->filename, max_size);
1446
/* parse http request and prepare header */
1447
static int http_parse_request(HTTPContext *c)
1450
enum RedirType redir_type;
1452
char info[1024], filename[1024];
1456
const char *mime_type;
1460
char *useragent = 0;
1463
get_word(cmd, sizeof(cmd), (const char **)&p);
1464
av_strlcpy(c->method, cmd, sizeof(c->method));
1466
if (!strcmp(cmd, "GET"))
1468
else if (!strcmp(cmd, "POST"))
1473
get_word(url, sizeof(url), (const char **)&p);
1474
av_strlcpy(c->url, url, sizeof(c->url));
1476
get_word(protocol, sizeof(protocol), (const char **)&p);
1477
if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1480
av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1483
http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1485
/* find the filename and the optional info string in the request */
1486
p = strchr(url, '?');
1488
av_strlcpy(info, p, sizeof(info));
1493
av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1495
for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1496
if (strncasecmp(p, "User-Agent:", 11) == 0) {
1498
if (*useragent && *useragent != '\n' && isspace(*useragent))
1502
p = strchr(p, '\n');
1509
redir_type = REDIR_NONE;
1510
if (av_match_ext(filename, "asx")) {
1511
redir_type = REDIR_ASX;
1512
filename[strlen(filename)-1] = 'f';
1513
} else if (av_match_ext(filename, "asf") &&
1514
(!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1515
/* if this isn't WMP or lookalike, return the redirector file */
1516
redir_type = REDIR_ASF;
1517
} else if (av_match_ext(filename, "rpm,ram")) {
1518
redir_type = REDIR_RAM;
1519
strcpy(filename + strlen(filename)-2, "m");
1520
} else if (av_match_ext(filename, "rtsp")) {
1521
redir_type = REDIR_RTSP;
1522
compute_real_filename(filename, sizeof(filename) - 1);
1523
} else if (av_match_ext(filename, "sdp")) {
1524
redir_type = REDIR_SDP;
1525
compute_real_filename(filename, sizeof(filename) - 1);
1528
// "redirect" / request to index.html
1529
if (!strlen(filename))
1530
av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1532
stream = first_stream;
1533
while (stream != NULL) {
1534
if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1536
stream = stream->next;
1538
if (stream == NULL) {
1539
snprintf(msg, sizeof(msg), "File '%s' not found", url);
1540
http_log("File '%s' not found\n", url);
1545
memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1546
memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1548
if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1549
c->http_error = 301;
1551
q += snprintf(q, c->buffer_size,
1552
"HTTP/1.0 301 Moved\r\n"
1554
"Content-type: text/html\r\n"
1556
"<html><head><title>Moved</title></head><body>\r\n"
1557
"You should be <a href=\"%s\">redirected</a>.\r\n"
1558
"</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1559
/* prepare output buffer */
1560
c->buffer_ptr = c->buffer;
1562
c->state = HTTPSTATE_SEND_HEADER;
1566
/* If this is WMP, get the rate information */
1567
if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1568
if (modify_current_stream(c, ratebuf)) {
1569
for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1570
if (c->switch_feed_streams[i] >= 0)
1571
c->switch_feed_streams[i] = -1;
1576
if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1577
current_bandwidth += stream->bandwidth;
1579
/* If already streaming this feed, do not let start another feeder. */
1580
if (stream->feed_opened) {
1581
snprintf(msg, sizeof(msg), "This feed is already being received.");
1582
http_log("Feed '%s' already being received\n", stream->feed_filename);
1586
if (c->post == 0 && max_bandwidth < current_bandwidth) {
1587
c->http_error = 503;
1589
q += snprintf(q, c->buffer_size,
1590
"HTTP/1.0 503 Server too busy\r\n"
1591
"Content-type: text/html\r\n"
1593
"<html><head><title>Too busy</title></head><body>\r\n"
1594
"<p>The server is too busy to serve your request at this time.</p>\r\n"
1595
"<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1596
"and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1597
"</body></html>\r\n", current_bandwidth, max_bandwidth);
1598
/* prepare output buffer */
1599
c->buffer_ptr = c->buffer;
1601
c->state = HTTPSTATE_SEND_HEADER;
1605
if (redir_type != REDIR_NONE) {
1608
for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1609
if (strncasecmp(p, "Host:", 5) == 0) {
1613
p = strchr(p, '\n');
1624
while (isspace(*hostinfo))
1627
eoh = strchr(hostinfo, '\n');
1629
if (eoh[-1] == '\r')
1632
if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1633
memcpy(hostbuf, hostinfo, eoh - hostinfo);
1634
hostbuf[eoh - hostinfo] = 0;
1636
c->http_error = 200;
1638
switch(redir_type) {
1640
q += snprintf(q, c->buffer_size,
1641
"HTTP/1.0 200 ASX Follows\r\n"
1642
"Content-type: video/x-ms-asf\r\n"
1644
"<ASX Version=\"3\">\r\n"
1645
//"<!-- Autogenerated by ffserver -->\r\n"
1646
"<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1647
"</ASX>\r\n", hostbuf, filename, info);
1650
q += snprintf(q, c->buffer_size,
1651
"HTTP/1.0 200 RAM Follows\r\n"
1652
"Content-type: audio/x-pn-realaudio\r\n"
1654
"# Autogenerated by ffserver\r\n"
1655
"http://%s/%s%s\r\n", hostbuf, filename, info);
1658
q += snprintf(q, c->buffer_size,
1659
"HTTP/1.0 200 ASF Redirect follows\r\n"
1660
"Content-type: video/x-ms-asf\r\n"
1663
"Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1667
char hostname[256], *p;
1668
/* extract only hostname */
1669
av_strlcpy(hostname, hostbuf, sizeof(hostname));
1670
p = strrchr(hostname, ':');
1673
q += snprintf(q, c->buffer_size,
1674
"HTTP/1.0 200 RTSP Redirect follows\r\n"
1675
/* XXX: incorrect mime type ? */
1676
"Content-type: application/x-rtsp\r\n"
1678
"rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1684
int sdp_data_size, len;
1685
struct sockaddr_in my_addr;
1687
q += snprintf(q, c->buffer_size,
1688
"HTTP/1.0 200 OK\r\n"
1689
"Content-type: application/sdp\r\n"
1692
len = sizeof(my_addr);
1693
getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1695
/* XXX: should use a dynamic buffer */
1696
sdp_data_size = prepare_sdp_description(stream,
1699
if (sdp_data_size > 0) {
1700
memcpy(q, sdp_data, sdp_data_size);
1712
/* prepare output buffer */
1713
c->buffer_ptr = c->buffer;
1715
c->state = HTTPSTATE_SEND_HEADER;
1721
snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1725
stream->conns_served++;
1727
/* XXX: add there authenticate and IP match */
1730
/* if post, it means a feed is being sent */
1731
if (!stream->is_feed) {
1732
/* However it might be a status report from WMP! Let us log the
1733
* data as it might come in handy one day. */
1737
for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1738
if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1742
if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1743
client_id = strtol(p + 18, 0, 10);
1744
p = strchr(p, '\n');
1752
char *eol = strchr(logline, '\n');
1757
if (eol[-1] == '\r')
1759
http_log("%.*s\n", (int) (eol - logline), logline);
1760
c->suppress_log = 1;
1765
http_log("\nGot request:\n%s\n", c->buffer);
1768
if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1771
/* Now we have to find the client_id */
1772
for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1773
if (wmpc->wmp_client_id == client_id)
1777
if (wmpc && modify_current_stream(wmpc, ratebuf))
1778
wmpc->switch_pending = 1;
1781
snprintf(msg, sizeof(msg), "POST command not handled");
1785
if (http_start_receive_data(c) < 0) {
1786
snprintf(msg, sizeof(msg), "could not open feed");
1790
c->state = HTTPSTATE_RECEIVE_DATA;
1795
if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1796
http_log("\nGot request:\n%s\n", c->buffer);
1799
if (c->stream->stream_type == STREAM_TYPE_STATUS)
1802
/* open input stream */
1803
if (open_input_stream(c, info) < 0) {
1804
snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1808
/* prepare http header */
1810
q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1811
mime_type = c->stream->fmt->mime_type;
1813
mime_type = "application/x-octet-stream";
1814
q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1816
/* for asf, we need extra headers */
1817
if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1818
/* Need to allocate a client id */
1820
c->wmp_client_id = av_lfg_get(&random_state);
1822
q += snprintf(q, q - (char *) 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);
1824
q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1825
q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1827
/* prepare output buffer */
1829
c->buffer_ptr = c->buffer;
1831
c->state = HTTPSTATE_SEND_HEADER;
1834
c->http_error = 404;
1836
q += snprintf(q, c->buffer_size,
1837
"HTTP/1.0 404 Not Found\r\n"
1838
"Content-type: text/html\r\n"
1841
"<head><title>404 Not Found</title></head>\n"
1844
/* prepare output buffer */
1845
c->buffer_ptr = c->buffer;
1847
c->state = HTTPSTATE_SEND_HEADER;
1851
c->http_error = 200; /* horrible : we use this value to avoid
1852
going to the send data state */
1853
c->state = HTTPSTATE_SEND_HEADER;
1857
static void fmt_bytecount(AVIOContext *pb, int64_t count)
1859
static const char *suffix = " kMGTP";
1862
for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1864
avio_printf(pb, "%"PRId64"%c", count, *s);
1867
static void compute_status(HTTPContext *c)
1876
if (avio_open_dyn_buf(&pb) < 0) {
1877
/* XXX: return an error ? */
1878
c->buffer_ptr = c->buffer;
1879
c->buffer_end = c->buffer;
1883
avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1884
avio_printf(pb, "Content-type: %s\r\n", "text/html");
1885
avio_printf(pb, "Pragma: no-cache\r\n");
1886
avio_printf(pb, "\r\n");
1888
avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1889
if (c->stream->feed_filename[0])
1890
avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1891
avio_printf(pb, "</head>\n<body>");
1892
avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1894
avio_printf(pb, "<h2>Available Streams</h2>\n");
1895
avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1896
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");
1897
stream = first_stream;
1898
while (stream != NULL) {
1899
char sfilename[1024];
1902
if (stream->feed != stream) {
1903
av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1904
eosf = sfilename + strlen(sfilename);
1905
if (eosf - sfilename >= 4) {
1906
if (strcmp(eosf - 4, ".asf") == 0)
1907
strcpy(eosf - 4, ".asx");
1908
else if (strcmp(eosf - 3, ".rm") == 0)
1909
strcpy(eosf - 3, ".ram");
1910
else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1911
/* generate a sample RTSP director if
1912
unicast. Generate an SDP redirector if
1914
eosf = strrchr(sfilename, '.');
1916
eosf = sfilename + strlen(sfilename);
1917
if (stream->is_multicast)
1918
strcpy(eosf, ".sdp");
1920
strcpy(eosf, ".rtsp");
1924
avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1925
sfilename, stream->filename);
1926
avio_printf(pb, "<td align=right> %d <td align=right> ",
1927
stream->conns_served);
1928
fmt_bytecount(pb, stream->bytes_served);
1929
switch(stream->stream_type) {
1930
case STREAM_TYPE_LIVE: {
1931
int audio_bit_rate = 0;
1932
int video_bit_rate = 0;
1933
const char *audio_codec_name = "";
1934
const char *video_codec_name = "";
1935
const char *audio_codec_name_extra = "";
1936
const char *video_codec_name_extra = "";
1938
for(i=0;i<stream->nb_streams;i++) {
1939
AVStream *st = stream->streams[i];
1940
AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1941
switch(st->codec->codec_type) {
1942
case AVMEDIA_TYPE_AUDIO:
1943
audio_bit_rate += st->codec->bit_rate;
1945
if (*audio_codec_name)
1946
audio_codec_name_extra = "...";
1947
audio_codec_name = codec->name;
1950
case AVMEDIA_TYPE_VIDEO:
1951
video_bit_rate += st->codec->bit_rate;
1953
if (*video_codec_name)
1954
video_codec_name_extra = "...";
1955
video_codec_name = codec->name;
1958
case AVMEDIA_TYPE_DATA:
1959
video_bit_rate += st->codec->bit_rate;
1965
avio_printf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
1968
video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1969
audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1971
avio_printf(pb, "<td>%s", stream->feed->filename);
1973
avio_printf(pb, "<td>%s", stream->feed_filename);
1974
avio_printf(pb, "\n");
1978
avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1982
stream = stream->next;
1984
avio_printf(pb, "</table>\n");
1986
stream = first_stream;
1987
while (stream != NULL) {
1988
if (stream->feed == stream) {
1989
avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1991
avio_printf(pb, "Running as pid %d.\n", stream->pid);
1993
#if defined(linux) && !defined(CONFIG_NOCUTILS)
1998
/* This is somewhat linux specific I guess */
1999
snprintf(ps_cmd, sizeof(ps_cmd),
2000
"ps -o \"%%cpu,cputime\" --no-headers %d",
2003
pid_stat = popen(ps_cmd, "r");
2008
if (fscanf(pid_stat, "%10s %64s", cpuperc,
2010
avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2018
avio_printf(pb, "<p>");
2020
avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
2022
for (i = 0; i < stream->nb_streams; i++) {
2023
AVStream *st = stream->streams[i];
2024
AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2025
const char *type = "unknown";
2026
char parameters[64];
2030
switch(st->codec->codec_type) {
2031
case AVMEDIA_TYPE_AUDIO:
2033
snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2035
case AVMEDIA_TYPE_VIDEO:
2037
snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2038
st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2043
avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2044
i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2046
avio_printf(pb, "</table>\n");
2049
stream = stream->next;
2052
/* connection status */
2053
avio_printf(pb, "<h2>Connection Status</h2>\n");
2055
avio_printf(pb, "Number of connections: %d / %d<br>\n",
2056
nb_connections, nb_max_connections);
2058
avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2059
current_bandwidth, max_bandwidth);
2061
avio_printf(pb, "<table>\n");
2062
avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
2063
c1 = first_http_ctx;
2065
while (c1 != NULL) {
2071
for (j = 0; j < c1->stream->nb_streams; j++) {
2072
if (!c1->stream->feed)
2073
bitrate += c1->stream->streams[j]->codec->bit_rate;
2074
else if (c1->feed_streams[j] >= 0)
2075
bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2080
p = inet_ntoa(c1->from_addr.sin_addr);
2081
avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2083
c1->stream ? c1->stream->filename : "",
2084
c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2087
http_state[c1->state]);
2088
fmt_bytecount(pb, bitrate);
2089
avio_printf(pb, "<td align=right>");
2090
fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2091
avio_printf(pb, "<td align=right>");
2092
fmt_bytecount(pb, c1->data_count);
2093
avio_printf(pb, "\n");
2096
avio_printf(pb, "</table>\n");
2101
avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2102
avio_printf(pb, "</body>\n</html>\n");
2104
len = avio_close_dyn_buf(pb, &c->pb_buffer);
2105
c->buffer_ptr = c->pb_buffer;
2106
c->buffer_end = c->pb_buffer + len;
2109
/* check if the parser needs to be opened for stream i */
2110
static void open_parser(AVFormatContext *s, int i)
2112
AVStream *st = s->streams[i];
2115
if (!st->codec->codec) {
2116
codec = avcodec_find_decoder(st->codec->codec_id);
2117
if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2118
st->codec->parse_only = 1;
2119
if (avcodec_open(st->codec, codec) < 0)
2120
st->codec->parse_only = 0;
2125
static int open_input_stream(HTTPContext *c, const char *info)
2128
char input_filename[1024];
2129
AVFormatContext *s = NULL;
2130
int buf_size, i, ret;
2133
/* find file name */
2134
if (c->stream->feed) {
2135
strcpy(input_filename, c->stream->feed->feed_filename);
2136
buf_size = FFM_PACKET_SIZE;
2137
/* compute position (absolute time) */
2138
if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2139
if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2141
} else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2142
int prebuffer = strtol(buf, 0, 10);
2143
stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2145
stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2147
strcpy(input_filename, c->stream->feed_filename);
2149
/* compute position (relative time) */
2150
if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2151
if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2156
if (input_filename[0] == '\0')
2160
if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2161
http_log("could not open %s: %d\n", input_filename, ret);
2164
s->flags |= AVFMT_FLAG_GENPTS;
2166
if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2167
http_log("Could not find stream info '%s'\n", input_filename);
2168
av_close_input_file(s);
2172
/* open each parser */
2173
for(i=0;i<s->nb_streams;i++)
2176
/* choose stream as clock source (we favorize video stream if
2177
present) for packet sending */
2178
c->pts_stream_index = 0;
2179
for(i=0;i<c->stream->nb_streams;i++) {
2180
if (c->pts_stream_index == 0 &&
2181
c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2182
c->pts_stream_index = i;
2186
if (c->fmt_in->iformat->read_seek)
2187
av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2188
/* set the start time (needed for maxtime and RTP packet timing) */
2189
c->start_time = cur_time;
2190
c->first_pts = AV_NOPTS_VALUE;
2194
/* return the server clock (in us) */
2195
static int64_t get_server_clock(HTTPContext *c)
2197
/* compute current pts value from system time */
2198
return (cur_time - c->start_time) * 1000;
2201
/* return the estimated time at which the current packet must be sent
2203
static int64_t get_packet_send_clock(HTTPContext *c)
2205
int bytes_left, bytes_sent, frame_bytes;
2207
frame_bytes = c->cur_frame_bytes;
2208
if (frame_bytes <= 0)
2211
bytes_left = c->buffer_end - c->buffer_ptr;
2212
bytes_sent = frame_bytes - bytes_left;
2213
return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2218
static int http_prepare_data(HTTPContext *c)
2221
AVFormatContext *ctx;
2223
av_freep(&c->pb_buffer);
2225
case HTTPSTATE_SEND_DATA_HEADER:
2226
memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2227
av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2228
av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2229
av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2230
av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2232
c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2234
for(i=0;i<c->stream->nb_streams;i++) {
2236
c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2237
/* if file or feed, then just take streams from FFStream struct */
2238
if (!c->stream->feed ||
2239
c->stream->feed == c->stream)
2240
src = c->stream->streams[i];
2242
src = c->stream->feed->streams[c->stream->feed_streams[i]];
2244
*(c->fmt_ctx.streams[i]) = *src;
2245
c->fmt_ctx.streams[i]->priv_data = 0;
2246
c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2247
AVStream, not in codec */
2249
/* set output format parameters */
2250
c->fmt_ctx.oformat = c->stream->fmt;
2251
c->fmt_ctx.nb_streams = c->stream->nb_streams;
2253
c->got_key_frame = 0;
2255
/* prepare header and save header data in a stream */
2256
if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2257
/* XXX: potential leak */
2260
c->fmt_ctx.pb->seekable = 0;
2263
* HACK to avoid mpeg ps muxer to spit many underflow errors
2264
* Default value from Libav
2265
* Try to set it use configuration option
2267
c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
2268
c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2270
if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2271
http_log("Error writing output header\n");
2274
av_dict_free(&c->fmt_ctx.metadata);
2276
len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2277
c->buffer_ptr = c->pb_buffer;
2278
c->buffer_end = c->pb_buffer + len;
2280
c->state = HTTPSTATE_SEND_DATA;
2281
c->last_packet_sent = 0;
2283
case HTTPSTATE_SEND_DATA:
2284
/* find a new packet */
2285
/* read a packet from the input stream */
2286
if (c->stream->feed)
2287
ffm_set_write_index(c->fmt_in,
2288
c->stream->feed->feed_write_index,
2289
c->stream->feed->feed_size);
2291
if (c->stream->max_time &&
2292
c->stream->max_time + c->start_time - cur_time < 0)
2293
/* We have timed out */
2294
c->state = HTTPSTATE_SEND_DATA_TRAILER;
2298
ret = av_read_frame(c->fmt_in, &pkt);
2300
if (c->stream->feed) {
2301
/* if coming from feed, it means we reached the end of the
2302
ffm file, so must wait for more data */
2303
c->state = HTTPSTATE_WAIT_FEED;
2304
return 1; /* state changed */
2305
} else if (ret == AVERROR(EAGAIN)) {
2306
/* input not ready, come back later */
2309
if (c->stream->loop) {
2310
av_close_input_file(c->fmt_in);
2312
if (open_input_stream(c, "") < 0)
2317
/* must send trailer now because eof or error */
2318
c->state = HTTPSTATE_SEND_DATA_TRAILER;
2322
int source_index = pkt.stream_index;
2323
/* update first pts if needed */
2324
if (c->first_pts == AV_NOPTS_VALUE) {
2325
c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2326
c->start_time = cur_time;
2328
/* send it to the appropriate stream */
2329
if (c->stream->feed) {
2330
/* if coming from a feed, select the right stream */
2331
if (c->switch_pending) {
2332
c->switch_pending = 0;
2333
for(i=0;i<c->stream->nb_streams;i++) {
2334
if (c->switch_feed_streams[i] == pkt.stream_index)
2335
if (pkt.flags & AV_PKT_FLAG_KEY)
2336
c->switch_feed_streams[i] = -1;
2337
if (c->switch_feed_streams[i] >= 0)
2338
c->switch_pending = 1;
2341
for(i=0;i<c->stream->nb_streams;i++) {
2342
if (c->stream->feed_streams[i] == pkt.stream_index) {
2343
AVStream *st = c->fmt_in->streams[source_index];
2344
pkt.stream_index = i;
2345
if (pkt.flags & AV_PKT_FLAG_KEY &&
2346
(st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2347
c->stream->nb_streams == 1))
2348
c->got_key_frame = 1;
2349
if (!c->stream->send_on_key || c->got_key_frame)
2354
AVCodecContext *codec;
2355
AVStream *ist, *ost;
2357
ist = c->fmt_in->streams[source_index];
2358
/* specific handling for RTP: we use several
2359
output stream (one for each RTP
2360
connection). XXX: need more abstract handling */
2361
if (c->is_packetized) {
2362
/* compute send time and duration */
2363
c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2364
c->cur_pts -= c->first_pts;
2365
c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2366
/* find RTP context */
2367
c->packet_stream_index = pkt.stream_index;
2368
ctx = c->rtp_ctx[c->packet_stream_index];
2370
av_free_packet(&pkt);
2373
codec = ctx->streams[0]->codec;
2374
/* only one stream per RTP connection */
2375
pkt.stream_index = 0;
2379
codec = ctx->streams[pkt.stream_index]->codec;
2382
if (c->is_packetized) {
2383
int max_packet_size;
2384
if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2385
max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2387
max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2388
ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2390
ret = avio_open_dyn_buf(&ctx->pb);
2393
/* XXX: potential leak */
2396
ost = ctx->streams[pkt.stream_index];
2398
ctx->pb->seekable = 0;
2399
if (pkt.dts != AV_NOPTS_VALUE)
2400
pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2401
if (pkt.pts != AV_NOPTS_VALUE)
2402
pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2403
pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2404
if (av_write_frame(ctx, &pkt) < 0) {
2405
http_log("Error writing frame to output\n");
2406
c->state = HTTPSTATE_SEND_DATA_TRAILER;
2409
len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2410
c->cur_frame_bytes = len;
2411
c->buffer_ptr = c->pb_buffer;
2412
c->buffer_end = c->pb_buffer + len;
2414
codec->frame_number++;
2416
av_free_packet(&pkt);
2420
av_free_packet(&pkt);
2425
case HTTPSTATE_SEND_DATA_TRAILER:
2426
/* last packet test ? */
2427
if (c->last_packet_sent || c->is_packetized)
2430
/* prepare header */
2431
if (avio_open_dyn_buf(&ctx->pb) < 0) {
2432
/* XXX: potential leak */
2435
c->fmt_ctx.pb->seekable = 0;
2436
av_write_trailer(ctx);
2437
len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2438
c->buffer_ptr = c->pb_buffer;
2439
c->buffer_end = c->pb_buffer + len;
2441
c->last_packet_sent = 1;
2447
/* should convert the format at the same time */
2448
/* send data starting at c->buffer_ptr to the output connection
2449
(either UDP or TCP connection) */
2450
static int http_send_data(HTTPContext *c)
2455
if (c->buffer_ptr >= c->buffer_end) {
2456
ret = http_prepare_data(c);
2460
/* state change requested */
2463
if (c->is_packetized) {
2464
/* RTP data output */
2465
len = c->buffer_end - c->buffer_ptr;
2467
/* fail safe - should never happen */
2469
c->buffer_ptr = c->buffer_end;
2472
len = (c->buffer_ptr[0] << 24) |
2473
(c->buffer_ptr[1] << 16) |
2474
(c->buffer_ptr[2] << 8) |
2476
if (len > (c->buffer_end - c->buffer_ptr))
2478
if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2479
/* nothing to send yet: we can wait */
2483
c->data_count += len;
2484
update_datarate(&c->datarate, c->data_count);
2486
c->stream->bytes_served += len;
2488
if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2489
/* RTP packets are sent inside the RTSP TCP connection */
2491
int interleaved_index, size;
2493
HTTPContext *rtsp_c;
2496
/* if no RTSP connection left, error */
2499
/* if already sending something, then wait. */
2500
if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2502
if (avio_open_dyn_buf(&pb) < 0)
2504
interleaved_index = c->packet_stream_index * 2;
2505
/* RTCP packets are sent at odd indexes */
2506
if (c->buffer_ptr[1] == 200)
2507
interleaved_index++;
2508
/* write RTSP TCP header */
2510
header[1] = interleaved_index;
2511
header[2] = len >> 8;
2513
avio_write(pb, header, 4);
2514
/* write RTP packet data */
2516
avio_write(pb, c->buffer_ptr, len);
2517
size = avio_close_dyn_buf(pb, &c->packet_buffer);
2518
/* prepare asynchronous TCP sending */
2519
rtsp_c->packet_buffer_ptr = c->packet_buffer;
2520
rtsp_c->packet_buffer_end = c->packet_buffer + size;
2521
c->buffer_ptr += len;
2523
/* send everything we can NOW */
2524
len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2525
rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2527
rtsp_c->packet_buffer_ptr += len;
2528
if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2529
/* if we could not send all the data, we will
2530
send it later, so a new state is needed to
2531
"lock" the RTSP TCP connection */
2532
rtsp_c->state = RTSPSTATE_SEND_PACKET;
2535
/* all data has been sent */
2536
av_freep(&c->packet_buffer);
2538
/* send RTP packet directly in UDP */
2540
url_write(c->rtp_handles[c->packet_stream_index],
2541
c->buffer_ptr, len);
2542
c->buffer_ptr += len;
2543
/* here we continue as we can send several packets per 10 ms slot */
2546
/* TCP data output */
2547
len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2549
if (ff_neterrno() != AVERROR(EAGAIN) &&
2550
ff_neterrno() != AVERROR(EINTR))
2551
/* error : close connection */
2556
c->buffer_ptr += len;
2558
c->data_count += len;
2559
update_datarate(&c->datarate, c->data_count);
2561
c->stream->bytes_served += len;
2569
static int http_start_receive_data(HTTPContext *c)
2573
if (c->stream->feed_opened)
2576
/* Don't permit writing to this one */
2577
if (c->stream->readonly)
2581
fd = open(c->stream->feed_filename, O_RDWR);
2583
http_log("Error opening feeder file: %s\n", strerror(errno));
2588
if (c->stream->truncate) {
2589
/* truncate feed file */
2590
ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2591
ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2592
http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2594
if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2595
http_log("Error reading write index from feed file: %s\n", strerror(errno));
2600
c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2601
c->stream->feed_size = lseek(fd, 0, SEEK_END);
2602
lseek(fd, 0, SEEK_SET);
2604
/* init buffer input */
2605
c->buffer_ptr = c->buffer;
2606
c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2607
c->stream->feed_opened = 1;
2608
c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2612
static int http_receive_data(HTTPContext *c)
2615
int len, loop_run = 0;
2617
while (c->chunked_encoding && !c->chunk_size &&
2618
c->buffer_end > c->buffer_ptr) {
2619
/* read chunk header, if present */
2620
len = recv(c->fd, c->buffer_ptr, 1, 0);
2623
if (ff_neterrno() != AVERROR(EAGAIN) &&
2624
ff_neterrno() != AVERROR(EINTR))
2625
/* error : close connection */
2628
} else if (len == 0) {
2629
/* end of connection : close it */
2631
} else if (c->buffer_ptr - c->buffer >= 2 &&
2632
!memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2633
c->chunk_size = strtol(c->buffer, 0, 16);
2634
if (c->chunk_size == 0) // end of stream
2636
c->buffer_ptr = c->buffer;
2638
} else if (++loop_run > 10) {
2639
/* no chunk header, abort */
2646
if (c->buffer_end > c->buffer_ptr) {
2647
len = recv(c->fd, c->buffer_ptr,
2648
FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2650
if (ff_neterrno() != AVERROR(EAGAIN) &&
2651
ff_neterrno() != AVERROR(EINTR))
2652
/* error : close connection */
2654
} else if (len == 0)
2655
/* end of connection : close it */
2658
c->chunk_size -= len;
2659
c->buffer_ptr += len;
2660
c->data_count += len;
2661
update_datarate(&c->datarate, c->data_count);
2665
if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2666
if (c->buffer[0] != 'f' ||
2667
c->buffer[1] != 'm') {
2668
http_log("Feed stream has become desynchronized -- disconnecting\n");
2673
if (c->buffer_ptr >= c->buffer_end) {
2674
FFStream *feed = c->stream;
2675
/* a packet has been received : write it in the store, except
2677
if (c->data_count > FFM_PACKET_SIZE) {
2679
// printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2680
/* XXX: use llseek or url_seek */
2681
lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2682
if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2683
http_log("Error writing to feed file: %s\n", strerror(errno));
2687
feed->feed_write_index += FFM_PACKET_SIZE;
2688
/* update file size */
2689
if (feed->feed_write_index > c->stream->feed_size)
2690
feed->feed_size = feed->feed_write_index;
2692
/* handle wrap around if max file size reached */
2693
if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2694
feed->feed_write_index = FFM_PACKET_SIZE;
2697
if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2698
http_log("Error writing index to feed file: %s\n", strerror(errno));
2702
/* wake up any waiting connections */
2703
for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2704
if (c1->state == HTTPSTATE_WAIT_FEED &&
2705
c1->stream->feed == c->stream->feed)
2706
c1->state = HTTPSTATE_SEND_DATA;
2709
/* We have a header in our hands that contains useful data */
2710
AVFormatContext *s = avformat_alloc_context();
2712
AVInputFormat *fmt_in;
2718
/* use feed output format name to find corresponding input format */
2719
fmt_in = av_find_input_format(feed->fmt->name);
2723
pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2724
0, NULL, NULL, NULL, NULL);
2728
if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2733
/* Now we have the actual streams */
2734
if (s->nb_streams != feed->nb_streams) {
2735
av_close_input_stream(s);
2737
http_log("Feed '%s' stream number does not match registered feed\n",
2738
c->stream->feed_filename);
2742
for (i = 0; i < s->nb_streams; i++) {
2743
AVStream *fst = feed->streams[i];
2744
AVStream *st = s->streams[i];
2745
avcodec_copy_context(fst->codec, st->codec);
2748
av_close_input_stream(s);
2751
c->buffer_ptr = c->buffer;
2756
c->stream->feed_opened = 0;
2758
/* wake up any waiting connections to stop waiting for feed */
2759
for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2760
if (c1->state == HTTPSTATE_WAIT_FEED &&
2761
c1->stream->feed == c->stream->feed)
2762
c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2767
/********************************************************************/
2770
static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2777
switch(error_number) {
2778
case RTSP_STATUS_OK:
2781
case RTSP_STATUS_METHOD:
2782
str = "Method Not Allowed";
2784
case RTSP_STATUS_BANDWIDTH:
2785
str = "Not Enough Bandwidth";
2787
case RTSP_STATUS_SESSION:
2788
str = "Session Not Found";
2790
case RTSP_STATUS_STATE:
2791
str = "Method Not Valid in This State";
2793
case RTSP_STATUS_AGGREGATE:
2794
str = "Aggregate operation not allowed";
2796
case RTSP_STATUS_ONLY_AGGREGATE:
2797
str = "Only aggregate operation allowed";
2799
case RTSP_STATUS_TRANSPORT:
2800
str = "Unsupported transport";
2802
case RTSP_STATUS_INTERNAL:
2803
str = "Internal Server Error";
2805
case RTSP_STATUS_SERVICE:
2806
str = "Service Unavailable";
2808
case RTSP_STATUS_VERSION:
2809
str = "RTSP Version not supported";
2812
str = "Unknown Error";
2816
avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2817
avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2819
/* output GMT time */
2822
strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2823
avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2826
static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2828
rtsp_reply_header(c, error_number);
2829
avio_printf(c->pb, "\r\n");
2832
static int rtsp_parse_request(HTTPContext *c)
2834
const char *p, *p1, *p2;
2840
RTSPMessageHeader header1, *header = &header1;
2842
c->buffer_ptr[0] = '\0';
2845
get_word(cmd, sizeof(cmd), &p);
2846
get_word(url, sizeof(url), &p);
2847
get_word(protocol, sizeof(protocol), &p);
2849
av_strlcpy(c->method, cmd, sizeof(c->method));
2850
av_strlcpy(c->url, url, sizeof(c->url));
2851
av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2853
if (avio_open_dyn_buf(&c->pb) < 0) {
2854
/* XXX: cannot do more */
2855
c->pb = NULL; /* safety */
2859
/* check version name */
2860
if (strcmp(protocol, "RTSP/1.0") != 0) {
2861
rtsp_reply_error(c, RTSP_STATUS_VERSION);
2865
/* parse each header line */
2866
memset(header, 0, sizeof(*header));
2867
/* skip to next line */
2868
while (*p != '\n' && *p != '\0')
2872
while (*p != '\0') {
2873
p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2877
if (p2 > p && p2[-1] == '\r')
2879
/* skip empty line */
2883
if (len > sizeof(line) - 1)
2884
len = sizeof(line) - 1;
2885
memcpy(line, p, len);
2887
ff_rtsp_parse_line(header, line, NULL, NULL);
2891
/* handle sequence number */
2892
c->seq = header->seq;
2894
if (!strcmp(cmd, "DESCRIBE"))
2895
rtsp_cmd_describe(c, url);
2896
else if (!strcmp(cmd, "OPTIONS"))
2897
rtsp_cmd_options(c, url);
2898
else if (!strcmp(cmd, "SETUP"))
2899
rtsp_cmd_setup(c, url, header);
2900
else if (!strcmp(cmd, "PLAY"))
2901
rtsp_cmd_play(c, url, header);
2902
else if (!strcmp(cmd, "PAUSE"))
2903
rtsp_cmd_pause(c, url, header);
2904
else if (!strcmp(cmd, "TEARDOWN"))
2905
rtsp_cmd_teardown(c, url, header);
2907
rtsp_reply_error(c, RTSP_STATUS_METHOD);
2910
len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2911
c->pb = NULL; /* safety */
2913
/* XXX: cannot do more */
2916
c->buffer_ptr = c->pb_buffer;
2917
c->buffer_end = c->pb_buffer + len;
2918
c->state = RTSPSTATE_SEND_REPLY;
2922
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2923
struct in_addr my_ip)
2925
AVFormatContext *avc;
2926
AVStream *avs = NULL;
2929
avc = avformat_alloc_context();
2933
av_dict_set(&avc->metadata, "title",
2934
stream->title[0] ? stream->title : "No Title", 0);
2935
avc->nb_streams = stream->nb_streams;
2936
if (stream->is_multicast) {
2937
snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2938
inet_ntoa(stream->multicast_ip),
2939
stream->multicast_port, stream->multicast_ttl);
2941
snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2944
if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2945
!(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2947
if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2948
!(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2951
for(i = 0; i < stream->nb_streams; i++) {
2952
avc->streams[i] = &avs[i];
2953
avc->streams[i]->codec = stream->streams[i]->codec;
2955
*pbuffer = av_mallocz(2048);
2956
av_sdp_create(&avc, 1, *pbuffer, 2048);
2959
av_free(avc->streams);
2960
av_dict_free(&avc->metadata);
2964
return strlen(*pbuffer);
2967
static void rtsp_cmd_options(HTTPContext *c, const char *url)
2969
// rtsp_reply_header(c, RTSP_STATUS_OK);
2970
avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2971
avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2972
avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2973
avio_printf(c->pb, "\r\n");
2976
static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2982
int content_length, len;
2983
struct sockaddr_in my_addr;
2985
/* find which url is asked */
2986
av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2991
for(stream = first_stream; stream != NULL; stream = stream->next) {
2992
if (!stream->is_feed &&
2993
stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2994
!strcmp(path, stream->filename)) {
2998
/* no stream found */
2999
rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3003
/* prepare the media description in sdp format */
3005
/* get the host IP */
3006
len = sizeof(my_addr);
3007
getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3008
content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3009
if (content_length < 0) {
3010
rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3013
rtsp_reply_header(c, RTSP_STATUS_OK);
3014
avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3015
avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3016
avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3017
avio_printf(c->pb, "\r\n");
3018
avio_write(c->pb, content, content_length);
3022
static HTTPContext *find_rtp_session(const char *session_id)
3026
if (session_id[0] == '\0')
3029
for(c = first_http_ctx; c != NULL; c = c->next) {
3030
if (!strcmp(c->session_id, session_id))
3036
static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3038
RTSPTransportField *th;
3041
for(i=0;i<h->nb_transports;i++) {
3042
th = &h->transports[i];
3043
if (th->lower_transport == lower_transport)
3049
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3050
RTSPMessageHeader *h)
3053
int stream_index, rtp_port, rtcp_port;
3058
RTSPTransportField *th;
3059
struct sockaddr_in dest_addr;
3060
RTSPActionServerSetup setup;
3062
/* find which url is asked */
3063
av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3068
/* now check each stream */
3069
for(stream = first_stream; stream != NULL; stream = stream->next) {
3070
if (!stream->is_feed &&
3071
stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3072
/* accept aggregate filenames only if single stream */
3073
if (!strcmp(path, stream->filename)) {
3074
if (stream->nb_streams != 1) {
3075
rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3082
for(stream_index = 0; stream_index < stream->nb_streams;
3084
snprintf(buf, sizeof(buf), "%s/streamid=%d",
3085
stream->filename, stream_index);
3086
if (!strcmp(path, buf))
3091
/* no stream found */
3092
rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3096
/* generate session id if needed */
3097
if (h->session_id[0] == '\0')
3098
snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3099
av_lfg_get(&random_state), av_lfg_get(&random_state));
3101
/* find rtp session, and create it if none found */
3102
rtp_c = find_rtp_session(h->session_id);
3104
/* always prefer UDP */
3105
th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3107
th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3109
rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3114
rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3115
th->lower_transport);
3117
rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3121
/* open input stream */
3122
if (open_input_stream(rtp_c, "") < 0) {
3123
rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3128
/* test if stream is OK (test needed because several SETUP needs
3129
to be done for a given file) */
3130
if (rtp_c->stream != stream) {
3131
rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3135
/* test if stream is already set up */
3136
if (rtp_c->rtp_ctx[stream_index]) {
3137
rtsp_reply_error(c, RTSP_STATUS_STATE);
3141
/* check transport */
3142
th = find_transport(h, rtp_c->rtp_protocol);
3143
if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3144
th->client_port_min <= 0)) {
3145
rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3149
/* setup default options */
3150
setup.transport_option[0] = '\0';
3151
dest_addr = rtp_c->from_addr;
3152
dest_addr.sin_port = htons(th->client_port_min);
3155
if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3156
rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3160
/* now everything is OK, so we can send the connection parameters */
3161
rtsp_reply_header(c, RTSP_STATUS_OK);
3163
avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3165
switch(rtp_c->rtp_protocol) {
3166
case RTSP_LOWER_TRANSPORT_UDP:
3167
rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3168
rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3169
avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3170
"client_port=%d-%d;server_port=%d-%d",
3171
th->client_port_min, th->client_port_max,
3172
rtp_port, rtcp_port);
3174
case RTSP_LOWER_TRANSPORT_TCP:
3175
avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3176
stream_index * 2, stream_index * 2 + 1);
3181
if (setup.transport_option[0] != '\0')
3182
avio_printf(c->pb, ";%s", setup.transport_option);
3183
avio_printf(c->pb, "\r\n");
3186
avio_printf(c->pb, "\r\n");
3190
/* find an rtp connection by using the session ID. Check consistency
3192
static HTTPContext *find_rtp_session_with_url(const char *url,
3193
const char *session_id)
3201
rtp_c = find_rtp_session(session_id);
3205
/* find which url is asked */
3206
av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3210
if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3211
for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3212
snprintf(buf, sizeof(buf), "%s/streamid=%d",
3213
rtp_c->stream->filename, s);
3214
if(!strncmp(path, buf, sizeof(buf))) {
3215
// XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3220
if (len > 0 && path[len - 1] == '/' &&
3221
!strncmp(path, rtp_c->stream->filename, len - 1))
3226
static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3230
rtp_c = find_rtp_session_with_url(url, h->session_id);
3232
rtsp_reply_error(c, RTSP_STATUS_SESSION);
3236
if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3237
rtp_c->state != HTTPSTATE_WAIT_FEED &&
3238
rtp_c->state != HTTPSTATE_READY) {
3239
rtsp_reply_error(c, RTSP_STATUS_STATE);
3243
rtp_c->state = HTTPSTATE_SEND_DATA;
3245
/* now everything is OK, so we can send the connection parameters */
3246
rtsp_reply_header(c, RTSP_STATUS_OK);
3248
avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3249
avio_printf(c->pb, "\r\n");
3252
static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3256
rtp_c = find_rtp_session_with_url(url, h->session_id);
3258
rtsp_reply_error(c, RTSP_STATUS_SESSION);
3262
if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3263
rtp_c->state != HTTPSTATE_WAIT_FEED) {
3264
rtsp_reply_error(c, RTSP_STATUS_STATE);
3268
rtp_c->state = HTTPSTATE_READY;
3269
rtp_c->first_pts = AV_NOPTS_VALUE;
3270
/* now everything is OK, so we can send the connection parameters */
3271
rtsp_reply_header(c, RTSP_STATUS_OK);
3273
avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3274
avio_printf(c->pb, "\r\n");
3277
static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3281
rtp_c = find_rtp_session_with_url(url, h->session_id);
3283
rtsp_reply_error(c, RTSP_STATUS_SESSION);
3287
/* now everything is OK, so we can send the connection parameters */
3288
rtsp_reply_header(c, RTSP_STATUS_OK);
3290
avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3291
avio_printf(c->pb, "\r\n");
3293
/* abort the session */
3294
close_connection(rtp_c);
3298
/********************************************************************/
3301
static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3302
FFStream *stream, const char *session_id,
3303
enum RTSPLowerTransport rtp_protocol)
3305
HTTPContext *c = NULL;
3306
const char *proto_str;
3308
/* XXX: should output a warning page when coming
3309
close to the connection limit */
3310
if (nb_connections >= nb_max_connections)
3313
/* add a new connection */
3314
c = av_mallocz(sizeof(HTTPContext));
3319
c->poll_entry = NULL;
3320
c->from_addr = *from_addr;
3321
c->buffer_size = IOBUFFER_INIT_SIZE;
3322
c->buffer = av_malloc(c->buffer_size);
3327
av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3328
c->state = HTTPSTATE_READY;
3329
c->is_packetized = 1;
3330
c->rtp_protocol = rtp_protocol;
3332
/* protocol is shown in statistics */
3333
switch(c->rtp_protocol) {
3334
case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3335
proto_str = "MCAST";
3337
case RTSP_LOWER_TRANSPORT_UDP:
3340
case RTSP_LOWER_TRANSPORT_TCP:
3347
av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3348
av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3350
current_bandwidth += stream->bandwidth;
3352
c->next = first_http_ctx;
3364
/* add a new RTP stream in an RTP connection (used in RTSP SETUP
3365
command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3367
static int rtp_new_av_stream(HTTPContext *c,
3368
int stream_index, struct sockaddr_in *dest_addr,
3369
HTTPContext *rtsp_c)
3371
AVFormatContext *ctx;
3374
URLContext *h = NULL;
3376
int max_packet_size;
3378
/* now we can open the relevant output stream */
3379
ctx = avformat_alloc_context();
3382
ctx->oformat = av_guess_format("rtp", NULL, NULL);
3384
st = av_mallocz(sizeof(AVStream));
3387
ctx->nb_streams = 1;
3388
ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3391
ctx->streams[0] = st;
3393
if (!c->stream->feed ||
3394
c->stream->feed == c->stream)
3395
memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3398
c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3400
st->priv_data = NULL;
3402
/* build destination RTP address */
3403
ipaddr = inet_ntoa(dest_addr->sin_addr);
3405
switch(c->rtp_protocol) {
3406
case RTSP_LOWER_TRANSPORT_UDP:
3407
case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3410
/* XXX: also pass as parameter to function ? */
3411
if (c->stream->is_multicast) {
3413
ttl = c->stream->multicast_ttl;
3416
snprintf(ctx->filename, sizeof(ctx->filename),
3417
"rtp://%s:%d?multicast=1&ttl=%d",
3418
ipaddr, ntohs(dest_addr->sin_port), ttl);
3420
snprintf(ctx->filename, sizeof(ctx->filename),
3421
"rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3424
if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
3426
c->rtp_handles[stream_index] = h;
3427
max_packet_size = url_get_max_packet_size(h);
3429
case RTSP_LOWER_TRANSPORT_TCP:
3432
max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3438
http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3439
ipaddr, ntohs(dest_addr->sin_port),
3440
c->stream->filename, stream_index, c->protocol);
3442
/* normally, no packets should be output here, but the packet size may be checked */
3443
if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3444
/* XXX: close stream */
3447
if (avformat_write_header(ctx, NULL) < 0) {
3454
avio_close_dyn_buf(ctx->pb, &dummy_buf);
3457
c->rtp_ctx[stream_index] = ctx;
3461
/********************************************************************/
3462
/* ffserver initialization */
3464
static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3468
fst = av_mallocz(sizeof(AVStream));
3472
fst->codec= avcodec_alloc_context();
3473
memcpy(fst->codec, codec, sizeof(AVCodecContext));
3474
if (codec->extradata_size) {
3475
fst->codec->extradata = av_malloc(codec->extradata_size);
3476
memcpy(fst->codec->extradata, codec->extradata,
3477
codec->extradata_size);
3480
/* live streams must use the actual feed's codec since it may be
3481
* updated later to carry extradata needed by the streams.
3485
fst->priv_data = av_mallocz(sizeof(FeedData));
3486
fst->index = stream->nb_streams;
3487
av_set_pts_info(fst, 33, 1, 90000);
3488
fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3489
stream->streams[stream->nb_streams++] = fst;
3493
/* return the stream number in the feed */
3494
static int add_av_stream(FFStream *feed, AVStream *st)
3497
AVCodecContext *av, *av1;
3501
for(i=0;i<feed->nb_streams;i++) {
3502
st = feed->streams[i];
3504
if (av1->codec_id == av->codec_id &&
3505
av1->codec_type == av->codec_type &&
3506
av1->bit_rate == av->bit_rate) {
3508
switch(av->codec_type) {
3509
case AVMEDIA_TYPE_AUDIO:
3510
if (av1->channels == av->channels &&
3511
av1->sample_rate == av->sample_rate)
3514
case AVMEDIA_TYPE_VIDEO:
3515
if (av1->width == av->width &&
3516
av1->height == av->height &&
3517
av1->time_base.den == av->time_base.den &&
3518
av1->time_base.num == av->time_base.num &&
3519
av1->gop_size == av->gop_size)
3528
fst = add_av_stream1(feed, av, 0);
3531
return feed->nb_streams - 1;
3536
static void remove_stream(FFStream *stream)
3540
while (*ps != NULL) {
3548
/* specific mpeg4 handling : we extract the raw parameters */
3549
static void extract_mpeg4_header(AVFormatContext *infile)
3551
int mpeg4_count, i, size;
3557
for(i=0;i<infile->nb_streams;i++) {
3558
st = infile->streams[i];
3559
if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3560
st->codec->extradata_size == 0) {
3567
printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3568
while (mpeg4_count > 0) {
3569
if (av_read_packet(infile, &pkt) < 0)
3571
st = infile->streams[pkt.stream_index];
3572
if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3573
st->codec->extradata_size == 0) {
3574
av_freep(&st->codec->extradata);
3575
/* fill extradata with the header */
3576
/* XXX: we make hard suppositions here ! */
3578
while (p < pkt.data + pkt.size - 4) {
3579
/* stop when vop header is found */
3580
if (p[0] == 0x00 && p[1] == 0x00 &&
3581
p[2] == 0x01 && p[3] == 0xb6) {
3582
size = p - pkt.data;
3583
// av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3584
st->codec->extradata = av_malloc(size);
3585
st->codec->extradata_size = size;
3586
memcpy(st->codec->extradata, pkt.data, size);
3593
av_free_packet(&pkt);
3597
/* compute the needed AVStream for each file */
3598
static void build_file_streams(void)
3600
FFStream *stream, *stream_next;
3603
/* gather all streams */
3604
for(stream = first_stream; stream != NULL; stream = stream_next) {
3605
AVFormatContext *infile = NULL;
3606
stream_next = stream->next;
3607
if (stream->stream_type == STREAM_TYPE_LIVE &&
3609
/* the stream comes from a file */
3610
/* try to open the file */
3612
if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3613
/* specific case : if transport stream output to RTP,
3614
we use a raw transport stream reader */
3615
av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3618
http_log("Opening file '%s'\n", stream->feed_filename);
3619
if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3620
http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3621
/* remove stream (no need to spend more time on it) */
3623
remove_stream(stream);
3625
/* find all the AVStreams inside and reference them in
3627
if (av_find_stream_info(infile) < 0) {
3628
http_log("Could not find codec parameters from '%s'\n",
3629
stream->feed_filename);
3630
av_close_input_file(infile);
3633
extract_mpeg4_header(infile);
3635
for(i=0;i<infile->nb_streams;i++)
3636
add_av_stream1(stream, infile->streams[i]->codec, 1);
3638
av_close_input_file(infile);
3644
/* compute the needed AVStream for each feed */
3645
static void build_feed_streams(void)
3647
FFStream *stream, *feed;
3650
/* gather all streams */
3651
for(stream = first_stream; stream != NULL; stream = stream->next) {
3652
feed = stream->feed;
3654
if (!stream->is_feed) {
3655
/* we handle a stream coming from a feed */
3656
for(i=0;i<stream->nb_streams;i++)
3657
stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3662
/* gather all streams */
3663
for(stream = first_stream; stream != NULL; stream = stream->next) {
3664
feed = stream->feed;
3666
if (stream->is_feed) {
3667
for(i=0;i<stream->nb_streams;i++)
3668
stream->feed_streams[i] = i;
3673
/* create feed files if needed */
3674
for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3677
if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3678
/* See if it matches */
3679
AVFormatContext *s = NULL;
3682
if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3683
/* Now see if it matches */
3684
if (s->nb_streams == feed->nb_streams) {
3686
for(i=0;i<s->nb_streams;i++) {
3688
sf = feed->streams[i];
3691
if (sf->index != ss->index ||
3693
http_log("Index & Id do not match for stream %d (%s)\n",
3694
i, feed->feed_filename);
3697
AVCodecContext *ccf, *ccs;
3701
#define CHECK_CODEC(x) (ccf->x != ccs->x)
3703
if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3704
http_log("Codecs do not match for stream %d\n", i);
3706
} else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3707
http_log("Codec bitrates do not match for stream %d\n", i);
3709
} else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3710
if (CHECK_CODEC(time_base.den) ||
3711
CHECK_CODEC(time_base.num) ||
3712
CHECK_CODEC(width) ||
3713
CHECK_CODEC(height)) {
3714
http_log("Codec width, height and framerate do not match for stream %d\n", i);
3717
} else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3718
if (CHECK_CODEC(sample_rate) ||
3719
CHECK_CODEC(channels) ||
3720
CHECK_CODEC(frame_size)) {
3721
http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3725
http_log("Unknown codec type\n");
3733
http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3734
feed->feed_filename, s->nb_streams, feed->nb_streams);
3736
av_close_input_file(s);
3738
http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3739
feed->feed_filename);
3742
if (feed->readonly) {
3743
http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3744
feed->feed_filename);
3747
unlink(feed->feed_filename);
3750
if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3751
AVFormatContext s1 = {0}, *s = &s1;
3753
if (feed->readonly) {
3754
http_log("Unable to create feed file '%s' as it is marked readonly\n",
3755
feed->feed_filename);
3759
/* only write the header of the ffm file */
3760
if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3761
http_log("Could not open output feed file '%s'\n",
3762
feed->feed_filename);
3765
s->oformat = feed->fmt;
3766
s->nb_streams = feed->nb_streams;
3767
s->streams = feed->streams;
3768
if (avformat_write_header(s, NULL) < 0) {
3769
http_log("Container doesn't supports the required parameters\n");
3772
/* XXX: need better api */
3773
av_freep(&s->priv_data);
3776
/* get feed size and write index */
3777
fd = open(feed->feed_filename, O_RDONLY);
3779
http_log("Could not open output feed file '%s'\n",
3780
feed->feed_filename);
3784
feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3785
feed->feed_size = lseek(fd, 0, SEEK_END);
3786
/* ensure that we do not wrap before the end of file */
3787
if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3788
feed->feed_max_size = feed->feed_size;
3794
/* compute the bandwidth used by each stream */
3795
static void compute_bandwidth(void)
3801
for(stream = first_stream; stream != NULL; stream = stream->next) {
3803
for(i=0;i<stream->nb_streams;i++) {
3804
AVStream *st = stream->streams[i];
3805
switch(st->codec->codec_type) {
3806
case AVMEDIA_TYPE_AUDIO:
3807
case AVMEDIA_TYPE_VIDEO:
3808
bandwidth += st->codec->bit_rate;
3814
stream->bandwidth = (bandwidth + 999) / 1000;
3818
/* add a codec and set the default parameters */
3819
static void add_codec(FFStream *stream, AVCodecContext *av)
3823
/* compute default parameters */
3824
switch(av->codec_type) {
3825
case AVMEDIA_TYPE_AUDIO:
3826
if (av->bit_rate == 0)
3827
av->bit_rate = 64000;
3828
if (av->sample_rate == 0)
3829
av->sample_rate = 22050;
3830
if (av->channels == 0)
3833
case AVMEDIA_TYPE_VIDEO:
3834
if (av->bit_rate == 0)
3835
av->bit_rate = 64000;
3836
if (av->time_base.num == 0){
3837
av->time_base.den = 5;
3838
av->time_base.num = 1;
3840
if (av->width == 0 || av->height == 0) {
3844
/* Bitrate tolerance is less for streaming */
3845
if (av->bit_rate_tolerance == 0)
3846
av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3847
(int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3852
if (av->max_qdiff == 0)
3854
av->qcompress = 0.5;
3857
if (!av->nsse_weight)
3858
av->nsse_weight = 8;
3860
av->frame_skip_cmp = FF_CMP_DCTMAX;
3862
av->me_method = ME_EPZS;
3863
av->rc_buffer_aggressivity = 1.0;
3866
av->rc_eq = "tex^qComp";
3867
if (!av->i_quant_factor)
3868
av->i_quant_factor = -0.8;
3869
if (!av->b_quant_factor)
3870
av->b_quant_factor = 1.25;
3871
if (!av->b_quant_offset)
3872
av->b_quant_offset = 1.25;
3873
if (!av->rc_max_rate)
3874
av->rc_max_rate = av->bit_rate * 2;
3876
if (av->rc_max_rate && !av->rc_buffer_size) {
3877
av->rc_buffer_size = av->rc_max_rate;
3886
st = av_mallocz(sizeof(AVStream));
3889
st->codec = avcodec_alloc_context();
3890
stream->streams[stream->nb_streams++] = st;
3891
memcpy(st->codec, av, sizeof(AVCodecContext));
3894
static enum CodecID opt_audio_codec(const char *arg)
3896
AVCodec *p= avcodec_find_encoder_by_name(arg);
3898
if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3899
return CODEC_ID_NONE;
3904
static enum CodecID opt_video_codec(const char *arg)
3906
AVCodec *p= avcodec_find_encoder_by_name(arg);
3908
if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3909
return CODEC_ID_NONE;
3914
/* simplistic plugin support */
3917
static void load_module(const char *filename)
3920
void (*init_func)(void);
3921
dll = dlopen(filename, RTLD_NOW);
3923
fprintf(stderr, "Could not load module '%s' - %s\n",
3924
filename, dlerror());
3928
init_func = dlsym(dll, "ffserver_module_init");
3931
"%s: init function 'ffserver_module_init()' not found\n",
3940
static int ffserver_opt_default(const char *opt, const char *arg,
3941
AVCodecContext *avctx, int type)
3944
const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3946
ret = av_set_string3(avctx, opt, arg, 1, NULL);
3950
static int ffserver_opt_preset(const char *arg,
3951
AVCodecContext *avctx, int type,
3952
enum CodecID *audio_id, enum CodecID *video_id)
3955
char filename[1000], tmp[1000], tmp2[1000], line[1000];
3957
AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3959
if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3960
codec ? codec->name : NULL))) {
3961
fprintf(stderr, "File for preset '%s' not found\n", arg);
3966
int e= fscanf(f, "%999[^\n]\n", line) - 1;
3967
if(line[0] == '#' && !e)
3969
e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3971
fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3975
if(!strcmp(tmp, "acodec")){
3976
*audio_id = opt_audio_codec(tmp2);
3977
}else if(!strcmp(tmp, "vcodec")){
3978
*video_id = opt_video_codec(tmp2);
3979
}else if(!strcmp(tmp, "scodec")){
3980
/* opt_subtitle_codec(tmp2); */
3981
}else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3982
fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3993
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3994
const char *mime_type)
3996
AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3999
AVOutputFormat *stream_fmt;
4000
char stream_format_name[64];
4002
snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4003
stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4012
static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4016
fprintf(stderr, "%s:%d: ", filename, line_num);
4017
vfprintf(stderr, fmt, vl);
4023
static int parse_ffconfig(const char *filename)
4030
int val, errors, line_num;
4031
FFStream **last_stream, *stream, *redirect;
4032
FFStream **last_feed, *feed, *s;
4033
AVCodecContext audio_enc, video_enc;
4034
enum CodecID audio_id, video_id;
4036
f = fopen(filename, "r");
4044
first_stream = NULL;
4045
last_stream = &first_stream;
4047
last_feed = &first_feed;
4051
audio_id = CODEC_ID_NONE;
4052
video_id = CODEC_ID_NONE;
4054
#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4056
if (fgets(line, sizeof(line), f) == NULL)
4062
if (*p == '\0' || *p == '#')
4065
get_arg(cmd, sizeof(cmd), &p);
4067
if (!strcasecmp(cmd, "Port")) {
4068
get_arg(arg, sizeof(arg), &p);
4070
if (val < 1 || val > 65536) {
4071
ERROR("Invalid_port: %s\n", arg);
4073
my_http_addr.sin_port = htons(val);
4074
} else if (!strcasecmp(cmd, "BindAddress")) {
4075
get_arg(arg, sizeof(arg), &p);
4076
if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4077
ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4079
} else if (!strcasecmp(cmd, "NoDaemon")) {
4080
ffserver_daemon = 0;
4081
} else if (!strcasecmp(cmd, "RTSPPort")) {
4082
get_arg(arg, sizeof(arg), &p);
4084
if (val < 1 || val > 65536) {
4085
ERROR("%s:%d: Invalid port: %s\n", arg);
4087
my_rtsp_addr.sin_port = htons(atoi(arg));
4088
} else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4089
get_arg(arg, sizeof(arg), &p);
4090
if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4091
ERROR("Invalid host/IP address: %s\n", arg);
4093
} else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4094
get_arg(arg, sizeof(arg), &p);
4096
if (val < 1 || val > 65536) {
4097
ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4099
nb_max_http_connections = val;
4100
} else if (!strcasecmp(cmd, "MaxClients")) {
4101
get_arg(arg, sizeof(arg), &p);
4103
if (val < 1 || val > nb_max_http_connections) {
4104
ERROR("Invalid MaxClients: %s\n", arg);
4106
nb_max_connections = val;
4108
} else if (!strcasecmp(cmd, "MaxBandwidth")) {
4110
get_arg(arg, sizeof(arg), &p);
4112
if (llval < 10 || llval > 10000000) {
4113
ERROR("Invalid MaxBandwidth: %s\n", arg);
4115
max_bandwidth = llval;
4116
} else if (!strcasecmp(cmd, "CustomLog")) {
4117
if (!ffserver_debug)
4118
get_arg(logfilename, sizeof(logfilename), &p);
4119
} else if (!strcasecmp(cmd, "<Feed")) {
4120
/*********************************************/
4121
/* Feed related options */
4123
if (stream || feed) {
4124
ERROR("Already in a tag\n");
4126
feed = av_mallocz(sizeof(FFStream));
4127
get_arg(feed->filename, sizeof(feed->filename), &p);
4128
q = strrchr(feed->filename, '>');
4132
for (s = first_feed; s; s = s->next) {
4133
if (!strcmp(feed->filename, s->filename)) {
4134
ERROR("Feed '%s' already registered\n", s->filename);
4138
feed->fmt = av_guess_format("ffm", NULL, NULL);
4139
/* defaut feed file */
4140
snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4141
"/tmp/%s.ffm", feed->filename);
4142
feed->feed_max_size = 5 * 1024 * 1024;
4144
feed->feed = feed; /* self feeding :-) */
4146
/* add in stream list */
4147
*last_stream = feed;
4148
last_stream = &feed->next;
4149
/* add in feed list */
4151
last_feed = &feed->next_feed;
4153
} else if (!strcasecmp(cmd, "Launch")) {
4157
feed->child_argv = av_mallocz(64 * sizeof(char *));
4159
for (i = 0; i < 62; i++) {
4160
get_arg(arg, sizeof(arg), &p);
4164
feed->child_argv[i] = av_strdup(arg);
4167
feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4169
snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4171
(my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4172
inet_ntoa(my_http_addr.sin_addr),
4173
ntohs(my_http_addr.sin_port), feed->filename);
4175
} else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4177
get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4179
} else if (stream) {
4180
get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4182
} else if (!strcasecmp(cmd, "File")) {
4184
get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4186
get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4187
} else if (!strcasecmp(cmd, "Truncate")) {
4189
get_arg(arg, sizeof(arg), &p);
4190
feed->truncate = strtod(arg, NULL);
4192
} else if (!strcasecmp(cmd, "FileMaxSize")) {
4197
get_arg(arg, sizeof(arg), &p);
4199
fsize = strtod(p1, &p1);
4200
switch(toupper(*p1)) {
4205
fsize *= 1024 * 1024;
4208
fsize *= 1024 * 1024 * 1024;
4211
feed->feed_max_size = (int64_t)fsize;
4212
if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4213
ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4216
} else if (!strcasecmp(cmd, "</Feed>")) {
4218
ERROR("No corresponding <Feed> for </Feed>\n");
4221
} else if (!strcasecmp(cmd, "<Stream")) {
4222
/*********************************************/
4223
/* Stream related options */
4225
if (stream || feed) {
4226
ERROR("Already in a tag\n");
4229
stream = av_mallocz(sizeof(FFStream));
4230
get_arg(stream->filename, sizeof(stream->filename), &p);
4231
q = strrchr(stream->filename, '>');
4235
for (s = first_stream; s; s = s->next) {
4236
if (!strcmp(stream->filename, s->filename)) {
4237
ERROR("Stream '%s' already registered\n", s->filename);
4241
stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4242
avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4243
avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4244
audio_id = CODEC_ID_NONE;
4245
video_id = CODEC_ID_NONE;
4247
audio_id = stream->fmt->audio_codec;
4248
video_id = stream->fmt->video_codec;
4251
*last_stream = stream;
4252
last_stream = &stream->next;
4254
} else if (!strcasecmp(cmd, "Feed")) {
4255
get_arg(arg, sizeof(arg), &p);
4260
while (sfeed != NULL) {
4261
if (!strcmp(sfeed->filename, arg))
4263
sfeed = sfeed->next_feed;
4266
ERROR("feed '%s' not defined\n", arg);
4268
stream->feed = sfeed;
4270
} else if (!strcasecmp(cmd, "Format")) {
4271
get_arg(arg, sizeof(arg), &p);
4273
if (!strcmp(arg, "status")) {
4274
stream->stream_type = STREAM_TYPE_STATUS;
4277
stream->stream_type = STREAM_TYPE_LIVE;
4278
/* jpeg cannot be used here, so use single frame jpeg */
4279
if (!strcmp(arg, "jpeg"))
4280
strcpy(arg, "mjpeg");
4281
stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4283
ERROR("Unknown Format: %s\n", arg);
4287
audio_id = stream->fmt->audio_codec;
4288
video_id = stream->fmt->video_codec;
4291
} else if (!strcasecmp(cmd, "InputFormat")) {
4292
get_arg(arg, sizeof(arg), &p);
4294
stream->ifmt = av_find_input_format(arg);
4295
if (!stream->ifmt) {
4296
ERROR("Unknown input format: %s\n", arg);
4299
} else if (!strcasecmp(cmd, "FaviconURL")) {
4300
if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4301
get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4303
ERROR("FaviconURL only permitted for status streams\n");
4305
} else if (!strcasecmp(cmd, "Author")) {
4307
get_arg(stream->author, sizeof(stream->author), &p);
4308
} else if (!strcasecmp(cmd, "Comment")) {
4310
get_arg(stream->comment, sizeof(stream->comment), &p);
4311
} else if (!strcasecmp(cmd, "Copyright")) {
4313
get_arg(stream->copyright, sizeof(stream->copyright), &p);
4314
} else if (!strcasecmp(cmd, "Title")) {
4316
get_arg(stream->title, sizeof(stream->title), &p);
4317
} else if (!strcasecmp(cmd, "Preroll")) {
4318
get_arg(arg, sizeof(arg), &p);
4320
stream->prebuffer = atof(arg) * 1000;
4321
} else if (!strcasecmp(cmd, "StartSendOnKey")) {
4323
stream->send_on_key = 1;
4324
} else if (!strcasecmp(cmd, "AudioCodec")) {
4325
get_arg(arg, sizeof(arg), &p);
4326
audio_id = opt_audio_codec(arg);
4327
if (audio_id == CODEC_ID_NONE) {
4328
ERROR("Unknown AudioCodec: %s\n", arg);
4330
} else if (!strcasecmp(cmd, "VideoCodec")) {
4331
get_arg(arg, sizeof(arg), &p);
4332
video_id = opt_video_codec(arg);
4333
if (video_id == CODEC_ID_NONE) {
4334
ERROR("Unknown VideoCodec: %s\n", arg);
4336
} else if (!strcasecmp(cmd, "MaxTime")) {
4337
get_arg(arg, sizeof(arg), &p);
4339
stream->max_time = atof(arg) * 1000;
4340
} else if (!strcasecmp(cmd, "AudioBitRate")) {
4341
get_arg(arg, sizeof(arg), &p);
4343
audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4344
} else if (!strcasecmp(cmd, "AudioChannels")) {
4345
get_arg(arg, sizeof(arg), &p);
4347
audio_enc.channels = atoi(arg);
4348
} else if (!strcasecmp(cmd, "AudioSampleRate")) {
4349
get_arg(arg, sizeof(arg), &p);
4351
audio_enc.sample_rate = atoi(arg);
4352
} else if (!strcasecmp(cmd, "AudioQuality")) {
4353
get_arg(arg, sizeof(arg), &p);
4355
// audio_enc.quality = atof(arg) * 1000;
4357
} else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4359
int minrate, maxrate;
4361
get_arg(arg, sizeof(arg), &p);
4363
if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4364
video_enc.rc_min_rate = minrate * 1000;
4365
video_enc.rc_max_rate = maxrate * 1000;
4367
ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4370
} else if (!strcasecmp(cmd, "Debug")) {
4372
get_arg(arg, sizeof(arg), &p);
4373
video_enc.debug = strtol(arg,0,0);
4375
} else if (!strcasecmp(cmd, "Strict")) {
4377
get_arg(arg, sizeof(arg), &p);
4378
video_enc.strict_std_compliance = atoi(arg);
4380
} else if (!strcasecmp(cmd, "VideoBufferSize")) {
4382
get_arg(arg, sizeof(arg), &p);
4383
video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4385
} else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4387
get_arg(arg, sizeof(arg), &p);
4388
video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4390
} else if (!strcasecmp(cmd, "VideoBitRate")) {
4391
get_arg(arg, sizeof(arg), &p);
4393
video_enc.bit_rate = atoi(arg) * 1000;
4395
} else if (!strcasecmp(cmd, "VideoSize")) {
4396
get_arg(arg, sizeof(arg), &p);
4398
av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4399
if ((video_enc.width % 16) != 0 ||
4400
(video_enc.height % 16) != 0) {
4401
ERROR("Image size must be a multiple of 16\n");
4404
} else if (!strcasecmp(cmd, "VideoFrameRate")) {
4405
get_arg(arg, sizeof(arg), &p);
4407
AVRational frame_rate;
4408
if (av_parse_video_rate(&frame_rate, arg) < 0) {
4409
ERROR("Incorrect frame rate: %s\n", arg);
4411
video_enc.time_base.num = frame_rate.den;
4412
video_enc.time_base.den = frame_rate.num;
4415
} else if (!strcasecmp(cmd, "VideoGopSize")) {
4416
get_arg(arg, sizeof(arg), &p);
4418
video_enc.gop_size = atoi(arg);
4419
} else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4421
video_enc.gop_size = 1;
4422
} else if (!strcasecmp(cmd, "VideoHighQuality")) {
4424
video_enc.mb_decision = FF_MB_DECISION_BITS;
4425
} else if (!strcasecmp(cmd, "Video4MotionVector")) {
4427
video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4428
video_enc.flags |= CODEC_FLAG_4MV;
4430
} else if (!strcasecmp(cmd, "AVOptionVideo") ||
4431
!strcasecmp(cmd, "AVOptionAudio")) {
4433
AVCodecContext *avctx;
4435
get_arg(arg, sizeof(arg), &p);
4436
get_arg(arg2, sizeof(arg2), &p);
4437
if (!strcasecmp(cmd, "AVOptionVideo")) {
4439
type = AV_OPT_FLAG_VIDEO_PARAM;
4442
type = AV_OPT_FLAG_AUDIO_PARAM;
4444
if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4445
ERROR("AVOption error: %s %s\n", arg, arg2);
4447
} else if (!strcasecmp(cmd, "AVPresetVideo") ||
4448
!strcasecmp(cmd, "AVPresetAudio")) {
4449
AVCodecContext *avctx;
4451
get_arg(arg, sizeof(arg), &p);
4452
if (!strcasecmp(cmd, "AVPresetVideo")) {
4454
video_enc.codec_id = video_id;
4455
type = AV_OPT_FLAG_VIDEO_PARAM;
4458
audio_enc.codec_id = audio_id;
4459
type = AV_OPT_FLAG_AUDIO_PARAM;
4461
if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4462
ERROR("AVPreset error: %s\n", arg);
4464
} else if (!strcasecmp(cmd, "VideoTag")) {
4465
get_arg(arg, sizeof(arg), &p);
4466
if ((strlen(arg) == 4) && stream)
4467
video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4468
} else if (!strcasecmp(cmd, "BitExact")) {
4470
video_enc.flags |= CODEC_FLAG_BITEXACT;
4471
} else if (!strcasecmp(cmd, "DctFastint")) {
4473
video_enc.dct_algo = FF_DCT_FASTINT;
4474
} else if (!strcasecmp(cmd, "IdctSimple")) {
4476
video_enc.idct_algo = FF_IDCT_SIMPLE;
4477
} else if (!strcasecmp(cmd, "Qscale")) {
4478
get_arg(arg, sizeof(arg), &p);
4480
video_enc.flags |= CODEC_FLAG_QSCALE;
4481
video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4483
} else if (!strcasecmp(cmd, "VideoQDiff")) {
4484
get_arg(arg, sizeof(arg), &p);
4486
video_enc.max_qdiff = atoi(arg);
4487
if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4488
ERROR("VideoQDiff out of range\n");
4491
} else if (!strcasecmp(cmd, "VideoQMax")) {
4492
get_arg(arg, sizeof(arg), &p);
4494
video_enc.qmax = atoi(arg);
4495
if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4496
ERROR("VideoQMax out of range\n");
4499
} else if (!strcasecmp(cmd, "VideoQMin")) {
4500
get_arg(arg, sizeof(arg), &p);
4502
video_enc.qmin = atoi(arg);
4503
if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4504
ERROR("VideoQMin out of range\n");
4507
} else if (!strcasecmp(cmd, "LumaElim")) {
4508
get_arg(arg, sizeof(arg), &p);
4510
video_enc.luma_elim_threshold = atoi(arg);
4511
} else if (!strcasecmp(cmd, "ChromaElim")) {
4512
get_arg(arg, sizeof(arg), &p);
4514
video_enc.chroma_elim_threshold = atoi(arg);
4515
} else if (!strcasecmp(cmd, "LumiMask")) {
4516
get_arg(arg, sizeof(arg), &p);
4518
video_enc.lumi_masking = atof(arg);
4519
} else if (!strcasecmp(cmd, "DarkMask")) {
4520
get_arg(arg, sizeof(arg), &p);
4522
video_enc.dark_masking = atof(arg);
4523
} else if (!strcasecmp(cmd, "NoVideo")) {
4524
video_id = CODEC_ID_NONE;
4525
} else if (!strcasecmp(cmd, "NoAudio")) {
4526
audio_id = CODEC_ID_NONE;
4527
} else if (!strcasecmp(cmd, "ACL")) {
4528
parse_acl_row(stream, feed, NULL, p, filename, line_num);
4529
} else if (!strcasecmp(cmd, "DynamicACL")) {
4531
get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4533
} else if (!strcasecmp(cmd, "RTSPOption")) {
4534
get_arg(arg, sizeof(arg), &p);
4536
av_freep(&stream->rtsp_option);
4537
stream->rtsp_option = av_strdup(arg);
4539
} else if (!strcasecmp(cmd, "MulticastAddress")) {
4540
get_arg(arg, sizeof(arg), &p);
4542
if (resolve_host(&stream->multicast_ip, arg) != 0) {
4543
ERROR("Invalid host/IP address: %s\n", arg);
4545
stream->is_multicast = 1;
4546
stream->loop = 1; /* default is looping */
4548
} else if (!strcasecmp(cmd, "MulticastPort")) {
4549
get_arg(arg, sizeof(arg), &p);
4551
stream->multicast_port = atoi(arg);
4552
} else if (!strcasecmp(cmd, "MulticastTTL")) {
4553
get_arg(arg, sizeof(arg), &p);
4555
stream->multicast_ttl = atoi(arg);
4556
} else if (!strcasecmp(cmd, "NoLoop")) {
4559
} else if (!strcasecmp(cmd, "</Stream>")) {
4561
ERROR("No corresponding <Stream> for </Stream>\n");
4563
if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4564
if (audio_id != CODEC_ID_NONE) {
4565
audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4566
audio_enc.codec_id = audio_id;
4567
add_codec(stream, &audio_enc);
4569
if (video_id != CODEC_ID_NONE) {
4570
video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4571
video_enc.codec_id = video_id;
4572
add_codec(stream, &video_enc);
4577
} else if (!strcasecmp(cmd, "<Redirect")) {
4578
/*********************************************/
4580
if (stream || feed || redirect) {
4581
ERROR("Already in a tag\n");
4583
redirect = av_mallocz(sizeof(FFStream));
4584
*last_stream = redirect;
4585
last_stream = &redirect->next;
4587
get_arg(redirect->filename, sizeof(redirect->filename), &p);
4588
q = strrchr(redirect->filename, '>');
4591
redirect->stream_type = STREAM_TYPE_REDIRECT;
4593
} else if (!strcasecmp(cmd, "URL")) {
4595
get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4596
} else if (!strcasecmp(cmd, "</Redirect>")) {
4598
ERROR("No corresponding <Redirect> for </Redirect>\n");
4600
if (!redirect->feed_filename[0]) {
4601
ERROR("No URL found for <Redirect>\n");
4605
} else if (!strcasecmp(cmd, "LoadModule")) {
4606
get_arg(arg, sizeof(arg), &p);
4610
ERROR("Module support not compiled into this version: '%s'\n", arg);
4613
ERROR("Incorrect keyword: '%s'\n", cmd);
4625
static void handle_child_exit(int sig)
4630
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4633
for (feed = first_feed; feed; feed = feed->next) {
4634
if (feed->pid == pid) {
4635
int uptime = time(0) - feed->pid_start;
4638
fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4641
/* Turn off any more restarts */
4642
feed->child_argv = 0;
4647
need_to_start_children = 1;
4650
static void opt_debug(void)
4653
ffserver_daemon = 0;
4654
logfilename[0] = '-';
4657
static void show_help(void)
4659
printf("usage: ffserver [options]\n"
4660
"Hyper fast multi format Audio/Video streaming server\n");
4662
show_help_options(options, "Main options:\n", 0, 0);
4665
static const OptionDef options[] = {
4666
#include "cmdutils_common_opts.h"
4667
{ "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4668
{ "d", 0, {(void*)opt_debug}, "enable debug mode" },
4669
{ "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4673
int main(int argc, char **argv)
4675
struct sigaction sigact;
4681
my_program_name = argv[0];
4682
my_program_dir = getcwd(0, 0);
4683
ffserver_daemon = 1;
4685
parse_options(argc, argv, options, NULL);
4687
unsetenv("http_proxy"); /* Kill the http_proxy */
4689
av_lfg_init(&random_state, av_get_random_seed());
4691
memset(&sigact, 0, sizeof(sigact));
4692
sigact.sa_handler = handle_child_exit;
4693
sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4694
sigaction(SIGCHLD, &sigact, 0);
4696
if (parse_ffconfig(config_filename) < 0) {
4697
fprintf(stderr, "Incorrect config file - exiting.\n");
4701
/* open log file if needed */
4702
if (logfilename[0] != '\0') {
4703
if (!strcmp(logfilename, "-"))
4706
logfile = fopen(logfilename, "a");
4707
av_log_set_callback(http_av_log);
4710
build_file_streams();
4712
build_feed_streams();
4714
compute_bandwidth();
4716
/* put the process in background and detach it from its TTY */
4717
if (ffserver_daemon) {
4724
} else if (pid > 0) {
4731
open("/dev/null", O_RDWR);
4732
if (strcmp(logfilename, "-") != 0) {
4742
signal(SIGPIPE, SIG_IGN);
4744
if (ffserver_daemon)
4747
if (http_server() < 0) {
4748
http_log("Could not start server\n");