#define _XOPEN_SOURCE 600
#include "config.h"
-#ifndef HAVE_CLOSESOCKET
+#if !HAVE_CLOSESOCKET
#define closesocket close
#endif
#include <string.h>
#include <strings.h>
#include <stdlib.h>
-#include "libavutil/random.h"
-#include "libavutil/avstring.h"
+/* avformat.h defines LIBAVFORMAT_BUILD, include it before all the other libav* headers which use it */
#include "libavformat/avformat.h"
#include "libavformat/network.h"
#include "libavformat/os_support.h"
-#include "libavformat/rtp.h"
+#include "libavformat/rtpdec.h"
#include "libavformat/rtsp.h"
+#include "libavutil/avstring.h"
+#include "libavutil/lfg.h"
+#include "libavutil/random_seed.h"
+#include "libavutil/intreadwrite.h"
#include "libavcodec/opt.h"
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
-#ifdef HAVE_POLL_H
+#if HAVE_POLL_H
#include <poll.h>
#endif
#include <errno.h>
#include <time.h>
#include <sys/wait.h>
#include <signal.h>
-#ifdef HAVE_DLFCN_H
+#if HAVE_DLFCN_H
#include <dlfcn.h>
#endif
#define SYNC_TIMEOUT (10 * 1000)
+typedef struct RTSPActionServerSetup {
+ uint32_t ipaddr;
+ char transport_option[512];
+} RTSPActionServerSetup;
+
typedef struct {
int64_t count1, count2;
int64_t time1, time2;
int feed_opened; /* true if someone is writing to the feed */
int is_feed; /* true if it is a feed */
int readonly; /* True if writing is prohibited to the file */
+ int truncate; /* True if feeder connection truncate the feed file */
int conns_served;
int64_t bytes_served;
int64_t feed_max_size; /* maximum storage size, zero means unlimited */
static int rtsp_parse_request(HTTPContext *c);
static void rtsp_cmd_describe(HTTPContext *c, const char *url);
static void rtsp_cmd_options(HTTPContext *c, const char *url);
-static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
-static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
-static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
-static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
+static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
+static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
+static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
+static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
/* SDP handling */
static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
static int64_t cur_time; // Making this global saves on passing it around everywhere
-static AVRandomState random_state;
+static AVLFG random_state;
static FILE *logfile = NULL;
{
static int print_prefix = 1;
AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
- if (level > av_log_level)
+ if (level > av_log_get_level())
return;
if (print_prefix && avc)
http_log("[%s @ %p]", avc->item_name(ptr), ptr);
if (stream->is_multicast) {
/* open the RTP connection */
snprintf(session_id, sizeof(session_id), "%08x%08x",
- av_random(&random_state), av_random(&random_state));
+ av_lfg_get(&random_state), av_lfg_get(&random_state));
/* choose a port if none given */
if (stream->multicast_port == 0) {
}
}
+static void http_send_too_busy_reply(int fd)
+{
+ char buffer[300];
+ int len = snprintf(buffer, sizeof(buffer),
+ "HTTP/1.0 200 Server too busy\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<html><head><title>Too busy</title></head><body>\r\n"
+ "<p>The server is too busy to serve your request at this time.</p>\r\n"
+ "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
+ "</body></html>\r\n",
+ nb_connections, nb_max_connections);
+ send(fd, buffer, len, 0);
+}
+
+
static void new_connection(int server_fd, int is_rtsp)
{
struct sockaddr_in from_addr;
}
ff_socket_nonblock(fd, 1);
- /* XXX: should output a warning page when coming
- close to the connection limit */
- if (nb_connections >= nb_max_connections)
+ if (nb_connections >= nb_max_connections) {
+ http_send_too_busy_reply(fd);
goto fail;
+ }
/* add a new connection */
c = av_mallocz(sizeof(HTTPContext));
*pp = p;
}
+static void get_arg(char *buf, int buf_size, const char **pp)
+{
+ const char *p;
+ char *q;
+ int quote;
+
+ p = *pp;
+ while (isspace(*p)) p++;
+ q = buf;
+ quote = 0;
+ if (*p == '\"' || *p == '\'')
+ quote = *p++;
+ for(;;) {
+ if (quote) {
+ if (*p == quote)
+ break;
+ } else {
+ if (isspace(*p))
+ break;
+ }
+ if (*p == '\0')
+ break;
+ if ((q - buf) < buf_size - 1)
+ *q++ = *p;
+ p++;
+ }
+ *q = '\0';
+ if (quote && *p == quote)
+ p++;
+ *pp = p;
+}
+
static int validate_acl(FFStream *stream, HTTPContext *c)
{
enum IPAddressAction last_action = IP_DENY;
av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
if (ffserver_debug)
- http_log("New connection: %s %s\n", cmd, url);
+ http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
/* find the filename and the optional info string in the request */
p = strchr(url, '?');
}
if (stream == NULL) {
snprintf(msg, sizeof(msg), "File '%s' not found", url);
+ http_log("File '%s' not found\n", url);
goto send_error;
}
}
}
+ if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
+ current_bandwidth += stream->bandwidth;
+
/* If already streaming this feed, do not let start another feeder. */
if (stream->feed_opened) {
snprintf(msg, sizeof(msg), "This feed is already being received.");
- http_log("feed %s already being received\n", stream->feed_filename);
+ http_log("Feed '%s' already being received\n", stream->feed_filename);
goto send_error;
}
- if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
- current_bandwidth += stream->bandwidth;
-
if (c->post == 0 && max_bandwidth < current_bandwidth) {
c->http_error = 200;
q = c->buffer;
if (!strcmp(c->stream->fmt->name,"asf_stream")) {
/* Need to allocate a client id */
- c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
+ c->wmp_client_id = av_lfg_get(&random_state);
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);
}
"HTTP/1.0 404 Not Found\r\n"
"Content-type: text/html\r\n"
"\r\n"
- "<HTML>\n"
- "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
- "<BODY>%s</BODY>\n"
- "</HTML>\n", msg);
+ "<html>\n"
+ "<head><title>404 Not Found</title></head>\n"
+ "<body>%s</body>\n"
+ "</html>\n", msg);
/* prepare output buffer */
c->buffer_ptr = c->buffer;
c->buffer_end = q;
url_fprintf(pb, "Pragma: no-cache\r\n");
url_fprintf(pb, "\r\n");
- url_fprintf(pb, "<HTML><HEAD><TITLE>%s Status</TITLE>\n", program_name);
+ url_fprintf(pb, "<html><head><title>%s Status</title>\n", program_name);
if (c->stream->feed_filename[0])
url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
- url_fprintf(pb, "</HEAD>\n<BODY>");
- url_fprintf(pb, "<H1>%s Status</H1>\n", program_name);
+ url_fprintf(pb, "</head>\n<body>");
+ url_fprintf(pb, "<h1>%s Status</h1>\n", program_name);
/* format status */
- url_fprintf(pb, "<H2>Available Streams</H2>\n");
- url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
- url_fprintf(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");
+ url_fprintf(pb, "<h2>Available Streams</h2>\n");
+ url_fprintf(pb, "<table cellspacing=0 cellpadding=4>\n");
+ url_fprintf(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");
stream = first_stream;
while (stream != NULL) {
char sfilename[1024];
}
}
- url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
+ url_fprintf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
sfilename, stream->filename);
url_fprintf(pb, "<td align=right> %d <td align=right> ",
stream->conns_served);
abort();
}
}
- url_fprintf(pb, "<TD align=center> %s <TD align=right> %d <TD align=right> %d <TD> %s %s <TD align=right> %d <TD> %s %s",
+ url_fprintf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
stream->fmt->name,
stream->bandwidth,
video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
if (stream->feed)
- url_fprintf(pb, "<TD>%s", stream->feed->filename);
+ url_fprintf(pb, "<td>%s", stream->feed->filename);
else
- url_fprintf(pb, "<TD>%s", stream->feed_filename);
+ url_fprintf(pb, "<td>%s", stream->feed_filename);
url_fprintf(pb, "\n");
}
break;
default:
- url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
+ url_fprintf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
break;
}
}
stream = stream->next;
}
- url_fprintf(pb, "</TABLE>\n");
+ url_fprintf(pb, "</table>\n");
stream = first_stream;
while (stream != NULL) {
/* feed status */
stream = first_feed;
while (stream != NULL) {
- url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
- url_fprintf(pb, "<TABLE>\n");
- url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
+ url_fprintf(pb, "<h1>Feed '%s'</h1>\n", stream->filename);
+ url_fprintf(pb, "<table>\n");
+ url_fprintf(pb, "<tr><td>Parameters<td>Frame count<td>Size<td>Avg bitrate (kbits/s)\n");
for(i=0;i<stream->nb_streams;i++) {
AVStream *st = stream->streams[i];
FeedData *fdata = st->priv_data;
avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
avg /= enc->frame_size;
- url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %"PRId64" <TD> %0.1f\n",
+ url_fprintf(pb, "<tr><td>%s <td> %d <td> %"PRId64" <td> %0.1f\n",
buf, enc->frame_number, fdata->data_count, avg / 1000.0);
}
- url_fprintf(pb, "</TABLE>\n");
+ url_fprintf(pb, "</table>\n");
stream = stream->next_feed;
}
}
#endif
/* connection status */
- url_fprintf(pb, "<H2>Connection Status</H2>\n");
+ url_fprintf(pb, "<h2>Connection Status</h2>\n");
- url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
+ url_fprintf(pb, "Number of connections: %d / %d<br>\n",
nb_connections, nb_max_connections);
- url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<BR>\n",
+ url_fprintf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
current_bandwidth, max_bandwidth);
- url_fprintf(pb, "<TABLE>\n");
- url_fprintf(pb, "<TR><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
+ url_fprintf(pb, "<table>\n");
+ url_fprintf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
c1 = first_http_ctx;
i = 0;
while (c1 != NULL) {
i++;
p = inet_ntoa(c1->from_addr.sin_addr);
- url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
+ url_fprintf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
i,
c1->stream ? c1->stream->filename : "",
c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
url_fprintf(pb, "\n");
c1 = c1->next;
}
- url_fprintf(pb, "</TABLE>\n");
+ url_fprintf(pb, "</table>\n");
/* date */
ti = time(NULL);
p = ctime(&ti);
- url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
- url_fprintf(pb, "</BODY>\n</HTML>\n");
+ url_fprintf(pb, "<hr size=1 noshade>Generated at %s", p);
+ url_fprintf(pb, "</body>\n</html>\n");
len = url_close_dyn_buf(pb, &c->pb_buffer);
c->buffer_ptr = c->pb_buffer;
}
s->flags |= AVFMT_FLAG_GENPTS;
c->fmt_in = s;
- av_find_stream_info(c->fmt_in);
+ if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
+ http_log("Could not find stream info '%s'\n", input_filename);
+ av_close_input_file(s);
+ return -1;
+ }
/* open each parser */
for(i=0;i<s->nb_streams;i++)
switch(c->state) {
case HTTPSTATE_SEND_DATA_HEADER:
memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
- av_strlcpy(c->fmt_ctx.author, c->stream->author,
- sizeof(c->fmt_ctx.author));
- av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
- sizeof(c->fmt_ctx.comment));
- av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
- sizeof(c->fmt_ctx.copyright));
- av_strlcpy(c->fmt_ctx.title, c->stream->title,
- sizeof(c->fmt_ctx.title));
+ av_metadata_set(&c->fmt_ctx.metadata, "author" ,c->stream->author);
+ av_metadata_set(&c->fmt_ctx.metadata, "comment" ,c->stream->comment);
+ av_metadata_set(&c->fmt_ctx.metadata, "copyright",c->stream->copyright);
+ av_metadata_set(&c->fmt_ctx.metadata, "title" ,c->stream->title);
for(i=0;i<c->stream->nb_streams;i++) {
AVStream *st;
}
c->feed_fd = fd;
- c->stream->feed_write_index = ffm_read_write_index(fd);
+ if (c->stream->truncate) {
+ /* truncate feed file */
+ ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
+ ftruncate(c->feed_fd, FFM_PACKET_SIZE);
+ http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
+ } else {
+ if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
+ http_log("Error reading write index from feed file: %s\n", strerror(errno));
+ return -1;
+ }
+ }
+
+ c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
c->stream->feed_size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
feed->feed_write_index = FFM_PACKET_SIZE;
/* write index */
- ffm_write_write_index(c->feed_fd, feed->feed_write_index);
+ if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
+ http_log("Error writing index to feed file: %s\n", strerror(errno));
+ goto fail;
+ }
/* wake up any waiting connections */
for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
if (s->nb_streams != feed->nb_streams) {
av_close_input_stream(s);
av_free(pb);
+ http_log("Feed '%s' stream number does not match registered feed\n",
+ c->stream->feed_filename);
goto fail;
}
char protocol[32];
char line[1024];
int len;
- RTSPHeader header1, *header = &header1;
+ RTSPMessageHeader header1, *header = &header1;
c->buffer_ptr[0] = '\0';
p = c->buffer;
}
/* parse each header line */
- memset(header, 0, sizeof(RTSPHeader));
+ memset(header, 0, sizeof(*header));
/* skip to next line */
while (*p != '\n' && *p != '\0')
p++;
AVStream avs[MAX_STREAMS];
int i;
- avc = av_alloc_format_context();
+ avc = avformat_alloc_context();
if (avc == NULL) {
return -1;
}
- if (stream->title[0] != 0) {
- av_strlcpy(avc->title, stream->title, sizeof(avc->title));
- } else {
- av_strlcpy(avc->title, "No Title", sizeof(avc->title));
- }
+ av_metadata_set(&avc->metadata, "title",
+ stream->title[0] ? stream->title : "No Title");
avc->nb_streams = stream->nb_streams;
if (stream->is_multicast) {
snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
return NULL;
}
-static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPLowerTransport lower_transport)
+static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
{
RTSPTransportField *th;
int i;
}
static void rtsp_cmd_setup(HTTPContext *c, const char *url,
- RTSPHeader *h)
+ RTSPMessageHeader *h)
{
FFStream *stream;
int stream_index, port;
/* generate session id if needed */
if (h->session_id[0] == '\0')
snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
- av_random(&random_state), av_random(&random_state));
+ av_lfg_get(&random_state), av_lfg_get(&random_state));
/* find rtp session, and create it if none found */
rtp_c = find_rtp_session(h->session_id);
return NULL;
}
-static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
+static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
{
HTTPContext *rtp_c;
url_fprintf(c->pb, "\r\n");
}
-static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
+static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
{
HTTPContext *rtp_c;
url_fprintf(c->pb, "\r\n");
}
-static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
+static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
{
HTTPContext *rtp_c;
char session_id[32];
int max_packet_size;
/* now we can open the relevant output stream */
- ctx = av_alloc_format_context();
+ ctx = avformat_alloc_context();
if (!ctx)
return -1;
ctx->oformat = guess_format("rtp", NULL, NULL);
stream->ap_in->mpeg2ts_compute_pcr = 1;
}
+ http_log("Opening file '%s'\n", stream->feed_filename);
if ((ret = av_open_input_file(&infile, stream->feed_filename,
stream->ifmt, 0, stream->ap_in)) < 0) {
- http_log("could not open %s: %d\n", stream->feed_filename, ret);
+ http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
/* remove stream (no need to spend more time on it) */
fail:
remove_stream(stream);
}
}
if (!url_exist(feed->feed_filename)) {
- AVFormatContext s1, *s = &s1;
+ AVFormatContext s1 = {0}, *s = &s1;
if (feed->readonly) {
http_log("Unable to create feed file '%s' as it is marked readonly\n",
exit(1);
}
- feed->feed_write_index = ffm_read_write_index(fd);
+ feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
feed->feed_size = lseek(fd, 0, SEEK_END);
/* ensure that we do not wrap before the end of file */
if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
}
}
-static void get_arg(char *buf, int buf_size, const char **pp)
-{
- const char *p;
- char *q;
- int quote;
-
- p = *pp;
- while (isspace(*p)) p++;
- q = buf;
- quote = 0;
- if (*p == '\"' || *p == '\'')
- quote = *p++;
- for(;;) {
- if (quote) {
- if (*p == quote)
- break;
- } else {
- if (isspace(*p))
- break;
- }
- if (*p == '\0')
- break;
- if ((q - buf) < buf_size - 1)
- *q++ = *p;
- p++;
- }
- *q = '\0';
- if (quote && *p == quote)
- p++;
- *pp = p;
-}
-
/* add a codec and set the default parameters */
static void add_codec(FFStream *stream, AVCodecContext *av)
{
memcpy(st->codec, av, sizeof(AVCodecContext));
}
-static int opt_audio_codec(const char *arg)
+static enum CodecID opt_audio_codec(const char *arg)
{
AVCodec *p= avcodec_find_encoder_by_name(arg);
return p->id;
}
-static int opt_video_codec(const char *arg)
+static enum CodecID opt_video_codec(const char *arg)
{
AVCodec *p= avcodec_find_encoder_by_name(arg);
/* simplistic plugin support */
-#ifdef HAVE_DLOPEN
+#if HAVE_DLOPEN
static void load_module(const char *filename)
{
void *dll;
static int ffserver_opt_default(const char *opt, const char *arg,
AVCodecContext *avctx, int type)
{
- const AVOption *o = NULL;
- const AVOption *o2 = av_find_opt(avctx, opt, NULL, type, type);
- if(o2)
- o = av_set_string2(avctx, opt, arg, 1);
- if(!o)
- return -1;
- return 0;
+ int ret = 0;
+ const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
+ if(o)
+ ret = av_set_string3(avctx, opt, arg, 1, NULL);
+ return ret;
}
static int parse_ffconfig(const char *filename)
const char *p;
int val, errors, line_num;
FFStream **last_stream, *stream, *redirect;
- FFStream **last_feed, *feed;
+ FFStream **last_feed, *feed, *s;
AVCodecContext audio_enc, video_enc;
- int audio_id, video_id;
+ enum CodecID audio_id, video_id;
f = fopen(filename, "r");
if (!f) {
filename, line_num);
} else {
feed = av_mallocz(sizeof(FFStream));
- /* add in stream list */
- *last_stream = feed;
- last_stream = &feed->next;
- /* add in feed list */
- *last_feed = feed;
- last_feed = &feed->next_feed;
-
get_arg(feed->filename, sizeof(feed->filename), &p);
q = strrchr(feed->filename, '>');
if (*q)
*q = '\0';
+
+ for (s = first_feed; s; s = s->next) {
+ if (!strcmp(feed->filename, s->filename)) {
+ fprintf(stderr, "%s:%d: Feed '%s' already registered\n",
+ filename, line_num, s->filename);
+ errors++;
+ }
+ }
+
feed->fmt = guess_format("ffm", NULL, NULL);
/* defaut feed file */
snprintf(feed->feed_filename, sizeof(feed->feed_filename),
feed->feed_max_size = 5 * 1024 * 1024;
feed->is_feed = 1;
feed->feed = feed; /* self feeding :-) */
+
+ /* add in stream list */
+ *last_stream = feed;
+ last_stream = &feed->next;
+ /* add in feed list */
+ *last_feed = feed;
+ last_feed = &feed->next_feed;
}
} else if (!strcasecmp(cmd, "Launch")) {
if (feed) {
get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
} else if (stream)
get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
+ } else if (!strcasecmp(cmd, "Truncate")) {
+ if (feed) {
+ get_arg(arg, sizeof(arg), &p);
+ feed->truncate = strtod(arg, NULL);
+ }
} else if (!strcasecmp(cmd, "FileMaxSize")) {
if (feed) {
char *p1;
break;
}
feed->feed_max_size = (int64_t)fsize;
+ if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
+ fprintf(stderr, "%s:%d: Feed max file size is too small, "
+ "must be at least %d\n", filename, line_num, FFM_PACKET_SIZE*4);
+ errors++;
+ }
}
} else if (!strcasecmp(cmd, "</Feed>")) {
if (!feed) {
fprintf(stderr, "%s:%d: Already in a tag\n",
filename, line_num);
} else {
+ FFStream *s;
const AVClass *class;
stream = av_mallocz(sizeof(FFStream));
- *last_stream = stream;
- last_stream = &stream->next;
-
get_arg(stream->filename, sizeof(stream->filename), &p);
q = strrchr(stream->filename, '>');
if (*q)
*q = '\0';
+
+ for (s = first_stream; s; s = s->next) {
+ if (!strcmp(stream->filename, s->filename)) {
+ fprintf(stderr, "%s:%d: Stream '%s' already registered\n",
+ filename, line_num, s->filename);
+ errors++;
+ }
+ }
+
stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
/* fetch avclass so AVOption works
* FIXME try to use avcodec_get_context_defaults2
audio_id = stream->fmt->audio_codec;
video_id = stream->fmt->video_codec;
}
+
+ *last_stream = stream;
+ last_stream = &stream->next;
}
} else if (!strcasecmp(cmd, "Feed")) {
get_arg(arg, sizeof(arg), &p);
} else if (!strcasecmp(cmd, "VideoTag")) {
get_arg(arg, sizeof(arg), &p);
if ((strlen(arg) == 4) && stream)
- video_enc.codec_tag = ff_get_fourcc(arg);
+ video_enc.codec_tag = AV_RL32(arg);
} else if (!strcasecmp(cmd, "BitExact")) {
if (stream)
video_enc.flags |= CODEC_FLAG_BITEXACT;
}
} else if (!strcasecmp(cmd, "LoadModule")) {
get_arg(arg, sizeof(arg), &p);
-#ifdef HAVE_DLOPEN
+#if HAVE_DLOPEN
load_module(arg);
#else
fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",
} else {
fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",
filename, line_num, cmd);
- errors++;
}
}
need_to_start_children = 1;
}
-static void opt_debug()
+static void opt_debug(void)
{
ffserver_debug = 1;
ffserver_daemon = 0;
unsetenv("http_proxy"); /* Kill the http_proxy */
- av_init_random(av_gettime() + (getpid() << 16), &random_state);
+ av_lfg_init(&random_state, ff_random_get_seed());
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = handle_child_exit;