#include "libavutil/avstring.h"
#include "libavutil/lfg.h"
#include "libavutil/random_seed.h"
+#include "libavcore/parseutils.h"
#include "libavcodec/opt.h"
#include <stdarg.h>
#include <unistd.h>
{
char buffer[300];
int len = snprintf(buffer, sizeof(buffer),
- "HTTP/1.0 200 Server too busy\r\n"
+ "HTTP/1.0 503 Server too busy\r\n"
"Content-type: text/html\r\n"
"\r\n"
"<html><head><title>Too busy</title></head><body>\r\n"
ctx = c->rtp_ctx[i];
if (ctx) {
av_write_trailer(ctx);
+ av_metadata_free(&ctx->metadata);
+ av_free(ctx->streams[0]);
av_free(ctx);
}
h = c->rtp_handles[i];
}
if (c->post == 0 && max_bandwidth < current_bandwidth) {
- c->http_error = 200;
+ c->http_error = 503;
q = c->buffer;
q += snprintf(q, c->buffer_size,
- "HTTP/1.0 200 Server too busy\r\n"
+ "HTTP/1.0 503 Server too busy\r\n"
"Content-type: text/html\r\n"
"\r\n"
"<html><head><title>Too busy</title></head><body>\r\n"
switch(c->state) {
case HTTPSTATE_SEND_DATA_HEADER:
memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
- 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);
+ av_metadata_set2(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
+ av_metadata_set2(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
+ av_metadata_set2(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
+ av_metadata_set2(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
for(i=0;i<c->stream->nb_streams;i++) {
AVStream *st;
http_log("Error writing output header\n");
return -1;
}
+ av_metadata_free(&c->fmt_ctx.metadata);
len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
c->buffer_ptr = c->pb_buffer;
else {
AVPacket pkt;
redo:
- if (av_read_frame(c->fmt_in, &pkt) < 0) {
- if (c->stream->feed && c->stream->feed->feed_opened) {
+ ret = av_read_frame(c->fmt_in, &pkt);
+ if (ret < 0) {
+ if (c->stream->feed) {
/* if coming from feed, it means we reached the end of the
ffm file, so must wait for more data */
c->state = HTTPSTATE_WAIT_FEED;
return 1; /* state changed */
+ } else if (ret == AVERROR(EAGAIN)) {
+ /* input not ready, come back later */
+ return 0;
} else {
if (c->stream->loop) {
av_close_input_file(c->fmt_in);
}
}
for(i=0;i<c->stream->nb_streams;i++) {
- if (c->feed_streams[i] == pkt.stream_index) {
+ if (c->stream->feed_streams[i] == pkt.stream_index) {
AVStream *st = c->fmt_in->streams[source_index];
pkt.stream_index = i;
if (pkt.flags & AV_PKT_FLAG_KEY &&
if (c->is_packetized) {
/* compute send time and duration */
c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
- if (ist->start_time != AV_NOPTS_VALUE)
- c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
+ c->cur_pts -= c->first_pts;
c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
/* find RTP context */
c->packet_stream_index = pkt.stream_index;
ff_neterrno() != FF_NETERROR(EINTR))
/* error : close connection */
goto fail;
+ return 0;
} else if (len == 0) {
/* end of connection : close it */
goto fail;
for (i = 0; i < s->nb_streams; i++) {
AVStream *fst = feed->streams[i];
AVStream *st = s->streams[i];
- memcpy(fst->codec, st->codec, sizeof(AVCodecContext));
- if (fst->codec->extradata_size) {
- fst->codec->extradata = av_malloc(fst->codec->extradata_size);
- if (!fst->codec->extradata)
- goto fail;
- memcpy(fst->codec->extradata, st->codec->extradata,
- fst->codec->extradata_size);
- }
+ avcodec_copy_context(fst->codec, st->codec);
}
av_close_input_stream(s);
{
const char *str;
time_t ti;
- char *p;
+ struct tm *tm;
char buf2[32];
switch(error_number) {
/* output GMT time */
ti = time(NULL);
- p = ctime(&ti);
- strcpy(buf2, p);
- p = buf2 + strlen(p) - 1;
- if (*p == '\n')
- *p = '\0';
+ tm = gmtime(&ti);
+ strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
}
if (*p == '\n')
p++;
while (*p != '\0') {
- p1 = strchr(p, '\n');
+ p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
if (!p1)
break;
p2 = p1;
if (avc == NULL) {
return -1;
}
- av_metadata_set(&avc->metadata, "title",
- stream->title[0] ? stream->title : "No Title");
+ av_metadata_set2(&avc->metadata, "title",
+ stream->title[0] ? stream->title : "No Title", 0);
avc->nb_streams = stream->nb_streams;
if (stream->is_multicast) {
snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
inet_ntoa(stream->multicast_ip),
stream->multicast_port, stream->multicast_ttl);
+ } else {
+ snprintf(avc->filename, 1024, "rtp://0.0.0.0");
}
for(i = 0; i < stream->nb_streams; i++) {
}
*pbuffer = av_mallocz(2048);
avf_sdp_create(&avc, 1, *pbuffer, 2048);
+ av_metadata_free(&avc->metadata);
av_free(avc);
return strlen(*pbuffer);
struct sockaddr_in my_addr;
/* find which url is asked */
- ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
+ av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
path = path1;
if (*path == '/')
path++;
return;
}
rtsp_reply_header(c, RTSP_STATUS_OK);
+ url_fprintf(c->pb, "Content-Base: %s/\r\n", url);
url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
url_fprintf(c->pb, "\r\n");
put_buffer(c->pb, content, content_length);
+ av_free(content);
}
static HTTPContext *find_rtp_session(const char *session_id)
RTSPActionServerSetup setup;
/* find which url is asked */
- ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
+ av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
path = path1;
if (*path == '/')
path++;
return NULL;
/* find which url is asked */
- ff_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
+ av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
path = path1;
if (*path == '/')
path++;
st = av_mallocz(sizeof(AVStream));
if (!st)
goto fail;
- st->codec= avcodec_alloc_context();
ctx->nb_streams = 1;
ctx->streams[0] = st;
/********************************************************************/
/* ffserver initialization */
-static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
+static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
{
AVStream *fst;
fst = av_mallocz(sizeof(AVStream));
if (!fst)
return NULL;
- fst->codec= avcodec_alloc_context();
+ if (copy) {
+ fst->codec= avcodec_alloc_context();
+ memcpy(fst->codec, codec, sizeof(AVCodecContext));
+ if (codec->extradata_size) {
+ fst->codec->extradata = av_malloc(codec->extradata_size);
+ memcpy(fst->codec->extradata, codec->extradata,
+ codec->extradata_size);
+ }
+ } else {
+ /* live streams must use the actual feed's codec since it may be
+ * updated later to carry extradata needed by the streams.
+ */
+ fst->codec = codec;
+ }
fst->priv_data = av_mallocz(sizeof(FeedData));
- memcpy(fst->codec, codec, sizeof(AVCodecContext));
fst->index = stream->nb_streams;
av_set_pts_info(fst, 33, 1, 90000);
stream->streams[stream->nb_streams++] = fst;
}
}
- fst = add_av_stream1(feed, av);
+ fst = add_av_stream1(feed, av, 0);
if (!fst)
return -1;
return feed->nb_streams - 1;
extract_mpeg4_header(infile);
for(i=0;i<infile->nb_streams;i++)
- add_av_stream1(stream, infile->streams[i]->codec);
+ add_av_stream1(stream, infile->streams[i]->codec, 1);
av_close_input_file(infile);
}
ccs = ss->codec;
#define CHECK_CODEC(x) (ccf->x != ccs->x)
- if (CHECK_CODEC(codec) || CHECK_CODEC(codec_type)) {
+ if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
http_log("Codecs do not match for stream %d\n", i);
matches = 0;
} else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
av->nsse_weight = 8;
av->frame_skip_cmp = FF_CMP_DCTMAX;
- av->me_method = ME_EPZS;
+ if (!av->me_method)
+ av->me_method = ME_EPZS;
av->rc_buffer_aggressivity = 1.0;
if (!av->rc_eq)
return ret;
}
+static int ffserver_opt_preset(const char *arg,
+ AVCodecContext *avctx, int type,
+ enum CodecID *audio_id, enum CodecID *video_id)
+{
+ FILE *f=NULL;
+ char filename[1000], tmp[1000], tmp2[1000], line[1000];
+ int i, ret = 0;
+ const char *base[3]= { getenv("FFMPEG_DATADIR"),
+ getenv("HOME"),
+ FFMPEG_DATADIR,
+ };
+
+ for(i=0; i<3 && !f; i++){
+ if(!base[i])
+ continue;
+ snprintf(filename, sizeof(filename), "%s%s/%s.ffpreset", base[i], i != 1 ? "" : "/.ffmpeg", arg);
+ f= fopen(filename, "r");
+ if(!f){
+ AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
+ if (codec) {
+ snprintf(filename, sizeof(filename), "%s%s/%s-%s.ffpreset", base[i], i != 1 ? "" : "/.ffmpeg", codec->name, arg);
+ f= fopen(filename, "r");
+ }
+ }
+ }
+
+ if(!f){
+ fprintf(stderr, "File for preset '%s' not found\n", arg);
+ return 1;
+ }
+
+ while(!feof(f)){
+ int e= fscanf(f, "%999[^\n]\n", line) - 1;
+ if(line[0] == '#' && !e)
+ continue;
+ e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
+ if(e){
+ fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
+ ret = 1;
+ break;
+ }
+ if(!strcmp(tmp, "acodec")){
+ *audio_id = opt_audio_codec(tmp2);
+ }else if(!strcmp(tmp, "vcodec")){
+ *video_id = opt_video_codec(tmp2);
+ }else if(!strcmp(tmp, "scodec")){
+ /* opt_subtitle_codec(tmp2); */
+ }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
+ fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
+ ret = 1;
+ break;
+ }
+ }
+
+ fclose(f);
+
+ return ret;
+}
+
static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
const char *mime_type)
{
} else if (!strcasecmp(cmd, "AudioBitRate")) {
get_arg(arg, sizeof(arg), &p);
if (stream)
- audio_enc.bit_rate = atoi(arg) * 1000;
+ audio_enc.bit_rate = lrintf(atof(arg) * 1000);
} else if (!strcasecmp(cmd, "AudioChannels")) {
get_arg(arg, sizeof(arg), &p);
if (stream)
} else if (!strcasecmp(cmd, "VideoSize")) {
get_arg(arg, sizeof(arg), &p);
if (stream) {
- av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);
+ av_parse_video_size(&video_enc.width, &video_enc.height, arg);
if ((video_enc.width % 16) != 0 ||
(video_enc.height % 16) != 0) {
ERROR("Image size must be a multiple of 16\n");
get_arg(arg, sizeof(arg), &p);
if (stream) {
AVRational frame_rate;
- if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {
+ if (av_parse_video_rate(&frame_rate, arg) < 0) {
ERROR("Incorrect frame rate: %s\n", arg);
} else {
video_enc.time_base.num = frame_rate.den;
if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
ERROR("AVOption error: %s %s\n", arg, arg2);
}
+ } else if (!strcasecmp(cmd, "AVPresetVideo") ||
+ !strcasecmp(cmd, "AVPresetAudio")) {
+ AVCodecContext *avctx;
+ int type;
+ get_arg(arg, sizeof(arg), &p);
+ if (!strcasecmp(cmd, "AVPresetVideo")) {
+ avctx = &video_enc;
+ video_enc.codec_id = video_id;
+ type = AV_OPT_FLAG_VIDEO_PARAM;
+ } else {
+ avctx = &audio_enc;
+ audio_enc.codec_id = audio_id;
+ type = AV_OPT_FLAG_AUDIO_PARAM;
+ }
+ if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
+ ERROR("AVPreset error: %s\n", arg);
+ }
} else if (!strcasecmp(cmd, "VideoTag")) {
get_arg(arg, sizeof(arg), &p);
if ((strlen(arg) == 4) && stream)
unsetenv("http_proxy"); /* Kill the http_proxy */
- av_lfg_init(&random_state, ff_random_get_seed());
+ av_lfg_init(&random_state, av_get_random_seed());
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = handle_child_exit;