#include "libavformat/os_support.h"
#include "libavformat/rtp.h"
#include "libavformat/rtsp.h"
-
+#include "libavcodec/opt.h"
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
RTSPSTATE_SEND_PACKET,
};
-const char *http_state[] = {
+static const char *http_state[] = {
"HTTP_WAIT_REQUEST",
"HTTP_SEND_HEADER",
static int handle_connection(HTTPContext *c);
static int http_parse_request(HTTPContext *c);
static int http_send_data(HTTPContext *c);
-static void compute_stats(HTTPContext *c);
+static void compute_status(HTTPContext *c);
static int open_input_stream(HTTPContext *c, const char *info);
static int http_start_receive_data(HTTPContext *c);
static int http_receive_data(HTTPContext *c);
static int nb_max_connections;
static int nb_connections;
-static int max_bandwidth;
-static int current_bandwidth;
+static uint64_t max_bandwidth;
+static uint64_t current_bandwidth;
static int64_t cur_time; // Making this global saves on passing it around everywhere
feed->pid = fork();
if (feed->pid < 0) {
- fprintf(stderr, "Unable to create children\n");
+ http_log("Unable to create children\n");
exit(1);
}
if (!feed->pid) {
continue;
if (open_input_stream(rtp_c, "") < 0) {
- fprintf(stderr, "Could not open input stream for stream '%s'\n",
- stream->filename);
+ http_log("Could not open input stream for stream '%s'\n",
+ stream->filename);
continue;
}
dest_addr.sin_port = htons(stream->multicast_port +
2 * stream_index);
if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
- fprintf(stderr, "Could not open output stream '%s/streamid=%d'\n",
- stream->filename, stream_index);
+ http_log("Could not open output stream '%s/streamid=%d'\n",
+ stream->filename, stream_index);
exit(1);
}
}
len = sizeof(from_addr);
fd = accept(server_fd, (struct sockaddr *)&from_addr,
&len);
- if (fd < 0)
+ if (fd < 0) {
+ http_log("error during accept %s\n", strerror(errno));
return;
+ }
ff_socket_nonblock(fd, 1);
/* XXX: should output a warning page when coming
q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The server is too busy to serve your request at this time.</p>\r\n");
- q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec.</p>\r\n",
+ q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The bandwidth being served (including your stream) is %lldkbit/sec, and this exceeds the limit of %lldkbit/sec.</p>\r\n",
current_bandwidth, max_bandwidth);
q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
#endif
if (c->stream->stream_type == STREAM_TYPE_STATUS)
- goto send_stats;
+ goto send_status;
/* open input stream */
if (open_input_stream(c, info) < 0) {
c->buffer_end = q;
c->state = HTTPSTATE_SEND_HEADER;
return 0;
- send_stats:
- compute_stats(c);
+ send_status:
+ compute_status(c);
c->http_error = 200; /* horrible : we use this value to avoid
going to the send data state */
c->state = HTTPSTATE_SEND_HEADER;
url_fprintf(pb, "%"PRId64"%c", count, *s);
}
-static void compute_stats(HTTPContext *c)
+static void compute_status(HTTPContext *c)
{
HTTPContext *c1;
FFStream *stream;
url_fprintf(pb, "Pragma: no-cache\r\n");
url_fprintf(pb, "\r\n");
- url_fprintf(pb, "<HEAD><TITLE>FFServer Status</TITLE>\n");
+ url_fprintf(pb, "<HEAD><TITLE>%s Status</TITLE>\n", program_name);
if (c->stream->feed_filename)
url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
url_fprintf(pb, "</HEAD>\n<BODY>");
- url_fprintf(pb, "<H1>FFServer Status</H1>\n");
+ 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, "Number of connections: %d / %d<BR>\n",
nb_connections, nb_max_connections);
- url_fprintf(pb, "Bandwidth in use: %dk / %dk<BR>\n",
+ url_fprintf(pb, "Bandwidth in use: %lldk / %lldk<BR>\n",
current_bandwidth, max_bandwidth);
url_fprintf(pb, "<TABLE>\n");
}
for(i=0;i<c->stream->nb_streams;i++) {
if (c->feed_streams[i] == pkt.stream_index) {
+ AVStream *st = c->fmt_in->streams[source_index];
pkt.stream_index = i;
- if (pkt.flags & PKT_FLAG_KEY)
- c->got_key_frame |= 1 << i;
- /* See if we have all the key frames, then
- * we start to send. This logic is not quite
- * right, but it works for the case of a
- * single video stream with one or more
- * audio streams (for which every frame is
- * typically a key frame).
- */
- if (!c->stream->send_on_key ||
- ((c->got_key_frame + 1) >> c->stream->nb_streams))
+ if (pkt.flags & PKT_FLAG_KEY &&
+ (st->codec->codec_type == CODEC_TYPE_VIDEO ||
+ c->stream->nb_streams == 1))
+ c->got_key_frame = 1;
+ if (!c->stream->send_on_key || c->got_key_frame)
goto send_it;
}
}
pkt.pts = av_rescale_q(pkt.pts,
c->fmt_in->streams[source_index]->time_base,
ctx->streams[pkt.stream_index]->time_base);
- if (av_write_frame(ctx, &pkt))
+ pkt.duration = av_rescale_q(pkt.duration,
+ c->fmt_in->streams[source_index]->time_base,
+ ctx->streams[pkt.stream_index]->time_base);
+ if (av_write_frame(ctx, &pkt) < 0) {
+ http_log("Error writing frame to output\n");
c->state = HTTPSTATE_SEND_DATA_TRAILER;
+ }
len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
c->cur_frame_bytes = len;
/* find all the AVStreams inside and reference them in
'stream' */
if (av_find_stream_info(infile) < 0) {
- http_log("Could not find codec parameters from '%s'",
+ http_log("Could not find codec parameters from '%s'\n",
stream->feed_filename);
av_close_input_file(infile);
goto fail;
/* only write the header of the ffm file */
if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
- fprintf(stderr, "Could not open output feed file '%s'\n",
- feed->feed_filename);
+ http_log("Could not open output feed file '%s'\n",
+ feed->feed_filename);
exit(1);
}
s->oformat = feed->fmt;
}
av_set_parameters(s, NULL);
if (av_write_header(s) < 0) {
- fprintf(stderr, "Container doesn't supports the required parameters\n");
+ http_log("Container doesn't supports the required parameters\n");
exit(1);
}
/* XXX: need better api */
/* get feed size and write index */
fd = open(feed->feed_filename, O_RDONLY);
if (fd < 0) {
- fprintf(stderr, "Could not open output feed file '%s'\n",
+ http_log("Could not open output feed file '%s'\n",
feed->feed_filename);
exit(1);
}
}
#endif
+static int 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_string(avctx, opt, arg);
+ if(!o)
+ return -1;
+ return 0;
+}
+
static int parse_ffconfig(const char *filename)
{
FILE *f;
nb_max_connections = val;
}
} else if (!strcasecmp(cmd, "MaxBandwidth")) {
+ int64_t llval;
get_arg(arg, sizeof(arg), &p);
- val = atoi(arg);
- if (val < 10 || val > 100000) {
+ llval = atoll(arg);
+ if (llval < 10 || llval > 10000000) {
fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",
filename, line_num, arg);
errors++;
} else
- max_bandwidth = val;
+ max_bandwidth = llval;
} else if (!strcasecmp(cmd, "CustomLog")) {
- get_arg(logfilename, sizeof(logfilename), &p);
+ if (!ffserver_debug)
+ get_arg(logfilename, sizeof(logfilename), &p);
} else if (!strcasecmp(cmd, "<Feed")) {
/*********************************************/
/* Feed related options */
fprintf(stderr, "%s:%d: Already in a tag\n",
filename, line_num);
} else {
+ const AVClass *class;
stream = av_mallocz(sizeof(FFStream));
*last_stream = stream;
last_stream = &stream->next;
if (*q)
*q = '\0';
stream->fmt = guess_stream_format(NULL, stream->filename, NULL);
+ /* fetch avclass so AVOption works
+ * FIXME try to use avcodec_get_context_defaults2
+ * without changing defaults too much */
+ avcodec_get_context_defaults(&video_enc);
+ class = video_enc.av_class;
memset(&audio_enc, 0, sizeof(AVCodecContext));
memset(&video_enc, 0, sizeof(AVCodecContext));
+ audio_enc.av_class = class;
+ video_enc.av_class = class;
audio_id = CODEC_ID_NONE;
video_id = CODEC_ID_NONE;
if (stream->fmt) {
video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
video_enc.flags |= CODEC_FLAG_4MV;
}
+ } else if (!strcasecmp(cmd, "AVOptionVideo") ||
+ !strcasecmp(cmd, "AVOptionAudio")) {
+ char arg2[1024];
+ AVCodecContext *avctx;
+ int type;
+ get_arg(arg, sizeof(arg), &p);
+ get_arg(arg2, sizeof(arg2), &p);
+ if (!strcasecmp(cmd, "AVOptionVideo")) {
+ avctx = &video_enc;
+ type = AV_OPT_FLAG_VIDEO_PARAM;
+ } else {
+ avctx = &audio_enc;
+ type = AV_OPT_FLAG_AUDIO_PARAM;
+ }
+ if (opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
+ fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);
+ errors++;
+ }
} else if (!strcasecmp(cmd, "VideoTag")) {
get_arg(arg, sizeof(arg), &p);
if ((strlen(arg) == 4) && stream)
{
ffserver_debug = 1;
ffserver_daemon = 0;
+ logfilename[0] = '-';
}
static void opt_show_help(void)
parse_options(argc, argv, options, NULL);
- putenv("http_proxy"); /* Kill the http_proxy */
+ unsetenv("http_proxy"); /* Kill the http_proxy */
av_init_random(av_gettime() + (getpid() << 16), &random_state);
nb_max_connections = 5;
max_bandwidth = 1000;
first_stream = NULL;
- logfilename[0] = '\0';
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = handle_child_exit;
}
if (http_server() < 0) {
- fprintf(stderr, "Could not start server\n");
+ http_log("Could not start server\n");
exit(1);
}