X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffmpeg.c;h=51cd58719826e9a157e69896fb65bc69d26bc8ed;hb=8c9971c35ee8fd01978a592f8f364755494f9a9a;hp=0abed0ce2eb5152ad8707b9cec765f522a39f58e;hpb=23a6e4749fa7134ce411ce186062f70f9d348603;p=ffmpeg diff --git a/ffmpeg.c b/ffmpeg.c index 0abed0ce2eb..51cd5871982 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -35,8 +35,8 @@ #include "libavformat/avformat.h" #include "libavdevice/avdevice.h" #include "libswscale/swscale.h" +#include "libswresample/swresample.h" #include "libavutil/opt.h" -#include "libavcodec/audioconvert.h" #include "libavutil/audioconvert.h" #include "libavutil/parseutils.h" #include "libavutil/samplefmt.h" @@ -50,17 +50,16 @@ #include "libavutil/libm.h" #include "libavutil/imgutils.h" #include "libavutil/timestamp.h" +#include "libavutil/bprint.h" #include "libavformat/os_support.h" -#include "libswresample/swresample.h" #include "libavformat/ffm.h" // not public API # include "libavfilter/avcodec.h" # include "libavfilter/avfilter.h" # include "libavfilter/avfiltergraph.h" -# include "libavfilter/buffersink.h" # include "libavfilter/buffersrc.h" -# include "libavfilter/vsrc_buffer.h" +# include "libavfilter/buffersink.h" #if HAVE_SYS_RESOURCE_H #include @@ -98,6 +97,8 @@ #define VSYNC_VFR 2 #define VSYNC_DROP 0xff +#define SINKA + const char program_name[] = "ffmpeg"; const int program_birth_year = 2000; @@ -169,11 +170,6 @@ static int print_stats = 1; static int debug_ts = 0; static int current_time; -static uint8_t *audio_buf; -static unsigned int allocated_audio_buf_size; -static uint8_t *async_buf; -static unsigned int allocated_async_buf_size; - #define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass" typedef struct InputFilter { @@ -231,10 +227,11 @@ typedef struct InputStream { /* dts of the last packet read for this stream */ int64_t dts; - int64_t next_pts; ///< synthetic pts for the next decode frame - int64_t pts; ///< current pts of the decoded frame + int64_t next_pts; /* synthetic pts for the next decode frame */ + int64_t pts; /* current pts of the decoded frame */ double ts_scale; int is_start; /* is 1 at the start and after a discontinuity */ + int saw_first_ts; int showed_multi_packet_warning; AVDictionary *opts; @@ -242,12 +239,17 @@ typedef struct InputStream { int resample_width; int resample_pix_fmt; + int resample_sample_fmt; + int resample_sample_rate; + int resample_channels; + uint64_t resample_channel_layout; + /* a pool of free buffers for decoded data */ FrameBuffer *buffer_pool; int dr1; /* decoded data from this stream goes into all those filters - * currently video only */ + * currently video and audio only */ InputFilter **filters; int nb_filters; } InputStream; @@ -274,10 +276,12 @@ typedef struct OutputStream { for A/V sync */ struct InputStream *sync_ist; /* input stream to sync against */ int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ // FIXME look at frame_number + /* pts of the first frame encoded for this stream, used for limiting + * recording time */ + int64_t first_pts; AVBitStreamFilterContext *bitstream_filters; AVCodec *enc; int64_t max_frames; - AVFrame *output_frame; AVFrame *filtered_frame; /* video only */ @@ -294,17 +298,10 @@ typedef struct OutputStream { int forced_kf_index; /* audio only */ - int audio_resample; - int audio_channels_map[SWR_CH_MAX]; ///< list of the channels id to pick from the source stream - int audio_channels_mapped; ///< number of channels in audio_channels_map - int resample_sample_fmt; - int resample_channels; - int resample_sample_rate; - float rematrix_volume; - AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */ - FILE *logfile; + int audio_channels_map[SWR_CH_MAX]; /* list of the channels id to pick from the source stream */ + int audio_channels_mapped; /* number of channels in audio_channels_map */ - SwrContext *swr; + FILE *logfile; OutputFilter *filter; char *avfilter; @@ -318,7 +315,7 @@ typedef struct OutputStream { const char *attachment_filename; int copy_initial_nonkeyframes; - enum PixelFormat pix_fmts[2]; + int keep_pix_fmt; } OutputStream; @@ -362,8 +359,6 @@ typedef struct OptionsContext { int nb_audio_channels; SpecifierOpt *audio_sample_rate; int nb_audio_sample_rate; - SpecifierOpt *rematrix_volume; - int nb_rematrix_volume; SpecifierOpt *frame_rates; int nb_frame_rates; SpecifierOpt *frame_sizes; @@ -383,8 +378,8 @@ typedef struct OptionsContext { /* output options */ StreamMap *stream_maps; int nb_stream_maps; - AudioChannelMap *audio_channel_maps; ///< one info entry per -map_channel - int nb_audio_channel_maps; ///< number of (valid) -map_channel settings + AudioChannelMap *audio_channel_maps; /* one info entry per -map_channel */ + int nb_audio_channel_maps; /* number of (valid) -map_channel settings */ int metadata_global_manual; int metadata_streams_manual; int metadata_chapters_manual; @@ -443,6 +438,8 @@ typedef struct OptionsContext { int nb_filters; } OptionsContext; +static void do_video_stats(AVFormatContext *os, OutputStream *ost, int frame_size); + #define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\ {\ int i, ret;\ @@ -545,12 +542,13 @@ static int alloc_buffer(InputStream *ist, AVCodecContext *s, FrameBuffer **pbuf) if (!buf) return AVERROR(ENOMEM); + avcodec_align_dimensions(s, &w, &h); + if (!(s->flags & CODEC_FLAG_EMU_EDGE)) { w += 2*edge; h += 2*edge; } - avcodec_align_dimensions(s, &w, &h); if ((ret = av_image_alloc(buf->base, buf->linesize, w, h, s->pix_fmt, 32)) < 0) { av_freep(&buf); @@ -567,7 +565,7 @@ static int alloc_buffer(InputStream *ist, AVCodecContext *s, FrameBuffer **pbuf) for (i = 0; i < FF_ARRAY_ELEMS(buf->data); i++) { const int h_shift = i==0 ? 0 : h_chroma_shift; const int v_shift = i==0 ? 0 : v_chroma_shift; - if ((s->flags & CODEC_FLAG_EMU_EDGE) || !buf->linesize[1]) + if ((s->flags & CODEC_FLAG_EMU_EDGE) || !buf->linesize[1] || !buf->base[i]) buf->data[i] = buf->base[i]; else buf->data[i] = buf->base[i] + @@ -596,9 +594,12 @@ static void free_buffer_pool(InputStream *ist) static void unref_buffer(InputStream *ist, FrameBuffer *buf) { - av_assert0(buf->refcount); + av_assert0(buf->refcount > 0); buf->refcount--; if (!buf->refcount) { + FrameBuffer *tmp; + for(tmp= ist->buffer_pool; tmp; tmp= tmp->next) + av_assert1(tmp != buf); buf->next = ist->buffer_pool; ist->buffer_pool = buf; } @@ -625,6 +626,7 @@ static int codec_get_buffer(AVCodecContext *s, AVFrame *frame) if ((ret = alloc_buffer(ist, s, &buf)) < 0) return ret; } + av_assert0(!buf->refcount); buf->refcount++; frame->opaque = buf; @@ -699,51 +701,267 @@ static enum PixelFormat choose_pixel_fmt(AVStream *st, AVCodec *codec, enum Pixe return target; } -static const enum PixelFormat *choose_pixel_fmts(OutputStream *ost) +static char *choose_pix_fmts(OutputStream *ost) { + if (ost->keep_pix_fmt) { + if (ost->filter) + avfilter_graph_set_auto_convert(ost->filter->graph->graph, + AVFILTER_AUTO_CONVERT_NONE); + if (ost->st->codec->pix_fmt == PIX_FMT_NONE) + return NULL; + return av_strdup(av_get_pix_fmt_name(ost->st->codec->pix_fmt)); + } if (ost->st->codec->pix_fmt != PIX_FMT_NONE) { - ost->pix_fmts[0] = choose_pixel_fmt(ost->st, ost->enc, ost->st->codec->pix_fmt); - return ost->pix_fmts; - } else if (ost->enc->pix_fmts) { + return av_strdup(av_get_pix_fmt_name(choose_pixel_fmt(ost->st, ost->enc, ost->st->codec->pix_fmt))); + } else if (ost->enc && ost->enc->pix_fmts) { + const enum PixelFormat *p; + AVIOContext *s = NULL; + uint8_t *ret; + int len; + + if (avio_open_dyn_buf(&s) < 0) + exit_program(1); + + p = ost->enc->pix_fmts; if (ost->st->codec->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) { if (ost->st->codec->codec_id == CODEC_ID_MJPEG) { - return (const enum PixelFormat[]) { PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_NONE }; + p = (const enum PixelFormat[]) { PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_NONE }; } else if (ost->st->codec->codec_id == CODEC_ID_LJPEG) { - return (const enum PixelFormat[]) { PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ444P, PIX_FMT_YUV420P, + p = (const enum PixelFormat[]) { PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ444P, PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV444P, PIX_FMT_BGRA, PIX_FMT_NONE }; } } - return ost->enc->pix_fmts; + + for (; *p != PIX_FMT_NONE; p++) { + const char *name = av_get_pix_fmt_name(*p); + avio_printf(s, "%s:", name); + } + len = avio_close_dyn_buf(s, &ret); + ret[len - 1] = 0; + return ret; } else return NULL; } -static int configure_video_filters(FilterGraph *fg) +/** + * Define a function for building a string containing a list of + * allowed formats, + */ +#define DEF_CHOOSE_FORMAT(type, var, supported_list, none, get_name, separator) \ +static char *choose_ ## var ## s(OutputStream *ost) \ +{ \ + if (ost->st->codec->var != none) { \ + get_name(ost->st->codec->var); \ + return av_strdup(name); \ + } else if (ost->enc->supported_list) { \ + const type *p; \ + AVIOContext *s = NULL; \ + uint8_t *ret; \ + int len; \ + \ + if (avio_open_dyn_buf(&s) < 0) \ + exit_program(1); \ + \ + for (p = ost->enc->supported_list; *p != none; p++) { \ + get_name(*p); \ + avio_printf(s, "%s" separator, name); \ + } \ + len = avio_close_dyn_buf(s, &ret); \ + ret[len - 1] = 0; \ + return ret; \ + } else \ + return NULL; \ +} + +#define GET_PIX_FMT_NAME(pix_fmt)\ + const char *name = av_get_pix_fmt_name(pix_fmt); + +// DEF_CHOOSE_FORMAT(enum PixelFormat, pix_fmt, pix_fmts, PIX_FMT_NONE, +// GET_PIX_FMT_NAME, ":") + +#define GET_SAMPLE_FMT_NAME(sample_fmt)\ + const char *name = av_get_sample_fmt_name(sample_fmt) + +DEF_CHOOSE_FORMAT(enum AVSampleFormat, sample_fmt, sample_fmts, + AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME, ",") + +#define GET_SAMPLE_RATE_NAME(rate)\ + char name[16];\ + snprintf(name, sizeof(name), "%d", rate); + +DEF_CHOOSE_FORMAT(int, sample_rate, supported_samplerates, 0, + GET_SAMPLE_RATE_NAME, ",") + +#define GET_CH_LAYOUT_NAME(ch_layout)\ + char name[16];\ + snprintf(name, sizeof(name), "0x%"PRIx64, ch_layout); + +DEF_CHOOSE_FORMAT(uint64_t, channel_layout, channel_layouts, 0, + GET_CH_LAYOUT_NAME, ",") + +static int configure_audio_filters(FilterGraph *fg, AVFilterContext **in_filter, + AVFilterContext **out_filter) +{ + InputStream *ist = fg->inputs[0]->ist; + OutputStream *ost = fg->outputs[0]->ost; + AVCodecContext *codec = ost->st->codec; + AVCodecContext *icodec = ist->st->codec; + char *sample_fmts, *sample_rates, *channel_layouts; + char args[256]; + int ret; + + avfilter_graph_free(&fg->graph); + if (!(fg->graph = avfilter_graph_alloc())) + return AVERROR(ENOMEM); + + snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:" + "channel_layout=0x%"PRIx64, ist->st->time_base.num, + ist->st->time_base.den, icodec->sample_rate, + av_get_sample_fmt_name(icodec->sample_fmt), icodec->channel_layout); + ret = avfilter_graph_create_filter(&fg->inputs[0]->filter, + avfilter_get_by_name("abuffer"), + "src", args, NULL, fg->graph); + if (ret < 0) + return ret; + + ret = avfilter_graph_create_filter(&fg->outputs[0]->filter, + avfilter_get_by_name("abuffersink_old"), + "out", NULL, NULL, fg->graph); + if (ret < 0) + return ret; + + *in_filter = fg->inputs[0]->filter; + *out_filter = fg->outputs[0]->filter; + + if (codec->channels && !codec->channel_layout) + codec->channel_layout = av_get_default_channel_layout(codec->channels); + + sample_fmts = choose_sample_fmts(ost); + sample_rates = choose_sample_rates(ost); + channel_layouts = choose_channel_layouts(ost); + if (sample_fmts || sample_rates || channel_layouts) { + AVFilterContext *format; + char args[256]; + int len = 0; + + if (sample_fmts) + len += snprintf(args + len, sizeof(args) - len, "sample_fmts=%s:", + sample_fmts); + if (sample_rates) + len += snprintf(args + len, sizeof(args) - len, "sample_rates=%s:", + sample_rates); + if (channel_layouts) + len += snprintf(args + len, sizeof(args) - len, "channel_layouts=%s:", + channel_layouts); + args[len - 1] = 0; + + av_freep(&sample_fmts); + av_freep(&sample_rates); + av_freep(&channel_layouts); + + ret = avfilter_graph_create_filter(&format, + avfilter_get_by_name("aformat"), + "aformat", args, NULL, fg->graph); + if (ret < 0) + return ret; + + ret = avfilter_link(format, 0, fg->outputs[0]->filter, 0); + if (ret < 0) + return ret; + + *out_filter = format; + } + + if (audio_sync_method > 0) { + AVFilterContext *aswr; + char args[256] = {0}; + + av_strlcatf(args, sizeof(args), "min_comp=0.001:min_hard_comp=%f", audio_drift_threshold); + + if (audio_sync_method > 1) + av_strlcatf(args, sizeof(args), ":max_soft_comp=%f", audio_sync_method/(double)icodec->sample_rate); + + av_log(NULL, AV_LOG_INFO, "-async %d is forwarded to lavfi similarly to -af aresample=%s\n", audio_sync_method, args); + + ret = avfilter_graph_create_filter(&aswr, avfilter_get_by_name("aresample"), + "aresample", args, NULL, fg->graph); + if (ret < 0) + return ret; + + ret = avfilter_link(*in_filter, 0, aswr, 0); + if (ret < 0) + return ret; + + *in_filter = aswr; + } + +#define AUTO_INSERT_FILTER(opt_name, filter_name, arg) do { \ + AVFilterContext *filt_ctx; \ + \ + av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi " \ + "similarly to -af " filter_name "=%s.\n", arg); \ + \ + ret = avfilter_graph_create_filter(&filt_ctx, \ + avfilter_get_by_name(filter_name), \ + filter_name, arg, NULL, fg->graph); \ + if (ret < 0) \ + return ret; \ + \ + ret = avfilter_link(*in_filter, 0, filt_ctx, 0); \ + if (ret < 0) \ + return ret; \ + \ + *in_filter = filt_ctx; \ +} while (0) + + if (ost->audio_channels_mapped) { + int i; + AVBPrint pan_buf; + + av_bprint_init(&pan_buf, 256, 8192); + av_bprintf(&pan_buf, "0x%"PRIx64, + av_get_default_channel_layout(ost->audio_channels_mapped)); + for (i = 0; i < ost->audio_channels_mapped; i++) + if (ost->audio_channels_map[i] != -1) + av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]); + + AUTO_INSERT_FILTER("-map_channel", "pan", pan_buf.str); + av_bprint_finalize(&pan_buf, NULL); + } + + if (audio_volume != 256) { + char args[256]; + + snprintf(args, sizeof(args), "%lf", audio_volume / 256.); + AUTO_INSERT_FILTER("-vol", "volume", args); + } + + return 0; +} + +static int configure_video_filters(FilterGraph *fg, AVFilterContext **in_filter, + AVFilterContext **out_filter) { InputStream *ist = fg->inputs[0]->ist; OutputStream *ost = fg->outputs[0]->ost; - AVFilterContext *last_filter, *filter; - /** filter graph containing all filters including input & output */ + AVFilterContext *filter; AVCodecContext *codec = ost->st->codec; - enum PixelFormat *pix_fmts = choose_pixel_fmts(ost); AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc(); + char *pix_fmts; AVRational sample_aspect_ratio; char args[255]; int ret; - avfilter_graph_free(&fg->graph); - fg->graph = avfilter_graph_alloc(); - if (!fg->graph) - return AVERROR(ENOMEM); - if (ist->st->sample_aspect_ratio.num) { sample_aspect_ratio = ist->st->sample_aspect_ratio; } else sample_aspect_ratio = ist->st->codec->sample_aspect_ratio; snprintf(args, 255, "%d:%d:%d:%d:%d:%d:%d:flags=%d", ist->st->codec->width, - ist->st->codec->height, ist->st->codec->pix_fmt, 1, AV_TIME_BASE, - sample_aspect_ratio.num, sample_aspect_ratio.den, SWS_BILINEAR + ((ist->st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0)); + ist->st->codec->height, ist->st->codec->pix_fmt, + ist->st->time_base.num, ist->st->time_base.den, + sample_aspect_ratio.num, sample_aspect_ratio.den, + SWS_BILINEAR + ((ist->st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0)); ret = avfilter_graph_create_filter(&fg->inputs[0]->filter, avfilter_get_by_name("buffer"), @@ -752,18 +970,20 @@ static int configure_video_filters(FilterGraph *fg) return ret; #if FF_API_OLD_VSINK_API - ret = avfilter_graph_create_filter(&fg->outputs[0]->filter, avfilter_get_by_name("buffersink"), - "out", NULL, pix_fmts, fg->graph); + ret = avfilter_graph_create_filter(&fg->outputs[0]->filter, + avfilter_get_by_name("buffersink"), + "out", NULL, NULL, fg->graph); #else - buffersink_params->pixel_fmts = pix_fmts; - ret = avfilter_graph_create_filter(&fg->outputs[0]->filter, avfilter_get_by_name("buffersink"), + ret = avfilter_graph_create_filter(&fg->outputs[0]->filter, + avfilter_get_by_name("buffersink"), "out", NULL, buffersink_params, fg->graph); #endif av_freep(&buffersink_params); if (ret < 0) return ret; - last_filter = fg->inputs[0]->filter; + *in_filter = fg->inputs[0]->filter; + *out_filter = fg->outputs[0]->filter; if (codec->width || codec->height) { snprintf(args, 255, "%d:%d:flags=0x%X", @@ -773,25 +993,64 @@ static int configure_video_filters(FilterGraph *fg) if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), NULL, args, NULL, fg->graph)) < 0) return ret; - if ((ret = avfilter_link(last_filter, 0, filter, 0)) < 0) + if ((ret = avfilter_link(*in_filter, 0, filter, 0)) < 0) return ret; - last_filter = filter; + *in_filter = filter; + } + + if ((pix_fmts = choose_pix_fmts(ost))) { + if ((ret = avfilter_graph_create_filter(&filter, + avfilter_get_by_name("format"), + "format", pix_fmts, NULL, + fg->graph)) < 0) + return ret; + if ((ret = avfilter_link(filter, 0, *out_filter, 0)) < 0) + return ret; + + *out_filter = filter; + av_freep(&pix_fmts); } snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags); fg->graph->scale_sws_opts = av_strdup(args); + return 0; +} + +static int configure_simple_filtergraph(FilterGraph *fg) +{ + OutputStream *ost = fg->outputs[0]->ost; + AVFilterContext *in_filter, *out_filter; + int ret; + + avfilter_graph_free(&fg->graph); + fg->graph = avfilter_graph_alloc(); + if (!fg->graph) + return AVERROR(ENOMEM); + + switch (ost->st->codec->codec_type) { + case AVMEDIA_TYPE_VIDEO: + ret = configure_video_filters(fg, &in_filter, &out_filter); + break; + case AVMEDIA_TYPE_AUDIO: + ret = configure_audio_filters(fg, &in_filter, &out_filter); + break; + default: av_assert0(0); + } + if (ret < 0) + return ret; + if (ost->avfilter) { AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); outputs->name = av_strdup("in"); - outputs->filter_ctx = last_filter; + outputs->filter_ctx = in_filter; outputs->pad_idx = 0; outputs->next = NULL; inputs->name = av_strdup("out"); - inputs->filter_ctx = fg->outputs[0]->filter; + inputs->filter_ctx = out_filter; inputs->pad_idx = 0; inputs->next = NULL; @@ -799,10 +1058,14 @@ static int configure_video_filters(FilterGraph *fg) return ret; av_freep(&ost->avfilter); } else { - if ((ret = avfilter_link(last_filter, 0, fg->outputs[0]->filter, 0)) < 0) + if ((ret = avfilter_link(in_filter, 0, out_filter, 0)) < 0) return ret; } + if (ost->keep_pix_fmt) + avfilter_graph_set_auto_convert(fg->graph, + AVFILTER_AUTO_CONVERT_NONE); + if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0) return ret; @@ -846,13 +1109,14 @@ static FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost) static void init_input_filter(FilterGraph *fg, AVFilterInOut *in) { - InputStream *ist; + InputStream *ist = NULL; enum AVMediaType type = in->filter_ctx->input_pads[in->pad_idx].type; int i; // TODO: support other filter types - if (type != AVMEDIA_TYPE_VIDEO) { - av_log(NULL, AV_LOG_FATAL, "Only video filters supported currently.\n"); + if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) { + av_log(NULL, AV_LOG_FATAL, "Only video and audio filters supported " + "currently.\n"); exit_program(1); } @@ -913,21 +1177,22 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in) ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1]; } -static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) +static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) { + char *pix_fmts; AVCodecContext *codec = ofilter->ost->st->codec; AVFilterContext *last_filter = out->filter_ctx; int pad_idx = out->pad_idx; int ret; - enum PixelFormat *pix_fmts = choose_pixel_fmts(ofilter->ost); AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc(); #if FF_API_OLD_VSINK_API - ret = avfilter_graph_create_filter(&ofilter->filter, avfilter_get_by_name("buffersink"), - "out", NULL, pix_fmts, fg->graph); + ret = avfilter_graph_create_filter(&ofilter->filter, + avfilter_get_by_name("buffersink"), + "out", NULL, NULL, fg->graph); #else - buffersink_params->pixel_fmts = pix_fmts; - ret = avfilter_graph_create_filter(&ofilter->filter, avfilter_get_by_name("buffersink"), + ret = avfilter_graph_create_filter(&ofilter->filter, + avfilter_get_by_name("buffersink"), "out", NULL, buffersink_params, fg->graph); #endif av_freep(&buffersink_params); @@ -937,24 +1202,141 @@ static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFil if (codec->width || codec->height) { char args[255]; + AVFilterContext *filter; + snprintf(args, sizeof(args), "%d:%d:flags=0x%X", codec->width, codec->height, (unsigned)ofilter->ost->sws_flags); - if ((ret = avfilter_graph_create_filter(&last_filter, avfilter_get_by_name("scale"), + if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), NULL, args, NULL, fg->graph)) < 0) return ret; - if ((ret = avfilter_link(out->filter_ctx, out->pad_idx, last_filter, 0)) < 0) + if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0) return ret; + + last_filter = filter; pad_idx = 0; } + if ((pix_fmts = choose_pix_fmts(ofilter->ost))) { + AVFilterContext *filter; + if ((ret = avfilter_graph_create_filter(&filter, + avfilter_get_by_name("format"), + "format", pix_fmts, NULL, + fg->graph)) < 0) + return ret; + if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0) + return ret; + + last_filter = filter; + pad_idx = 0; + av_freep(&pix_fmts); + } + if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) return ret; return 0; } +static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) +{ + OutputStream *ost = ofilter->ost; + AVCodecContext *codec = ost->st->codec; + AVFilterContext *last_filter = out->filter_ctx; + int pad_idx = out->pad_idx; + char *sample_fmts, *sample_rates, *channel_layouts; + int ret; + + ret = avfilter_graph_create_filter(&ofilter->filter, + avfilter_get_by_name("abuffersink"), + "out", NULL, NULL, fg->graph); + if (ret < 0) + return ret; + + if (codec->channels && !codec->channel_layout) + codec->channel_layout = av_get_default_channel_layout(codec->channels); + + sample_fmts = choose_sample_fmts(ost); + sample_rates = choose_sample_rates(ost); + channel_layouts = choose_channel_layouts(ost); + if (sample_fmts || sample_rates || channel_layouts) { + AVFilterContext *format; + char args[256]; + int len = 0; + + if (sample_fmts) + len += snprintf(args + len, sizeof(args) - len, "sample_fmts=%s:", + sample_fmts); + if (sample_rates) + len += snprintf(args + len, sizeof(args) - len, "sample_rates=%s:", + sample_rates); + if (channel_layouts) + len += snprintf(args + len, sizeof(args) - len, "channel_layouts=%s:", + channel_layouts); + args[len - 1] = 0; + + av_freep(&sample_fmts); + av_freep(&sample_rates); + av_freep(&channel_layouts); + + ret = avfilter_graph_create_filter(&format, + avfilter_get_by_name("aformat"), + "aformat", args, NULL, fg->graph); + if (ret < 0) + return ret; + + ret = avfilter_link(last_filter, pad_idx, format, 0); + if (ret < 0) + return ret; + + last_filter = format; + pad_idx = 0; + } + + if (audio_sync_method > 0) { + AVFilterContext *async; + char args[256]; + int len = 0; + + av_log(NULL, AV_LOG_WARNING, "-async has been deprecated. Used the " + "asyncts audio filter instead.\n"); + + if (audio_sync_method > 1) + len += snprintf(args + len, sizeof(args) - len, "compensate=1:" + "max_comp=%d:", audio_sync_method); + snprintf(args + len, sizeof(args) - len, "min_delta=%f", + audio_drift_threshold); + + ret = avfilter_graph_create_filter(&async, + avfilter_get_by_name("asyncts"), + "async", args, NULL, fg->graph); + if (ret < 0) + return ret; + + ret = avfilter_link(last_filter, pad_idx, async, 0); + if (ret < 0) + return ret; + + last_filter = async; + pad_idx = 0; + } + + if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) + return ret; + + return 0; +} + +static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) +{ + switch (out->filter_ctx->output_pads[out->pad_idx].type) { + case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, ofilter, out); + case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, ofilter, out); + default: av_assert0(0); + } +} + static int configure_complex_filter(FilterGraph *fg) { AVFilterInOut *inputs, *outputs, *cur; @@ -974,16 +1356,35 @@ static int configure_complex_filter(FilterGraph *fg) InputFilter *ifilter = fg->inputs[i]; InputStream *ist = ifilter->ist; AVRational sar; + AVFilter *filter; char args[255]; - sar = ist->st->sample_aspect_ratio.num ? ist->st->sample_aspect_ratio : - ist->st->codec->sample_aspect_ratio; - snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d", ist->st->codec->width, - ist->st->codec->height, ist->st->codec->pix_fmt, 1, AV_TIME_BASE, - sar.num, sar.den); + switch (cur->filter_ctx->input_pads[cur->pad_idx].type) { + case AVMEDIA_TYPE_VIDEO: + sar = ist->st->sample_aspect_ratio.num ? + ist->st->sample_aspect_ratio : + ist->st->codec->sample_aspect_ratio; + snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d", ist->st->codec->width, + ist->st->codec->height, ist->st->codec->pix_fmt, + ist->st->time_base.num, ist->st->time_base.den, + sar.num, sar.den); + filter = avfilter_get_by_name("buffer"); + break; + case AVMEDIA_TYPE_AUDIO: + snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:" + "sample_fmt=%s:channel_layout=0x%"PRIx64, + ist->st->time_base.num, ist->st->time_base.den, + ist->st->codec->sample_rate, + av_get_sample_fmt_name(ist->st->codec->sample_fmt), + ist->st->codec->channel_layout); + filter = avfilter_get_by_name("abuffer"); + break; + default: + av_assert0(0); + } if ((ret = avfilter_graph_create_filter(&ifilter->filter, - avfilter_get_by_name("buffer"), cur->name, + filter, cur->name, args, NULL, fg->graph)) < 0) return ret; if ((ret = avfilter_link(ifilter->filter, 0, @@ -1031,7 +1432,8 @@ static int configure_complex_filters(void) static int configure_filtergraph(FilterGraph *fg) { - return fg->graph_desc ? configure_complex_filter(fg) : configure_video_filters(fg); + return fg->graph_desc ? configure_complex_filter(fg) : + configure_simple_filtergraph(fg); } static int ist_in_filtergraph(FilterGraph *fg, InputStream *ist) @@ -1067,25 +1469,25 @@ static void term_init(void) { #if HAVE_TERMIOS_H if(!run_as_daemon){ - struct termios tty; + struct termios tty; - if (tcgetattr (0, &tty) == 0) { - oldtty = tty; - restore_tty = 1; - atexit(term_exit); + if (tcgetattr (0, &tty) == 0) { + oldtty = tty; + restore_tty = 1; + atexit(term_exit); - tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP - |INLCR|IGNCR|ICRNL|IXON); - tty.c_oflag |= OPOST; - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); - tty.c_cflag &= ~(CSIZE|PARENB); - tty.c_cflag |= CS8; - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 0; + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP + |INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag |= OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); + tty.c_cflag &= ~(CSIZE|PARENB); + tty.c_cflag |= CS8; + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; - tcsetattr (0, TCSANOW, &tty); - } - signal(SIGQUIT, sigterm_handler); /* Quit (POSIX). */ + tcsetattr (0, TCSANOW, &tty); + } + signal(SIGQUIT, sigterm_handler); /* Quit (POSIX). */ } #endif avformat_network_deinit(); @@ -1192,12 +1594,6 @@ void av_noreturn exit_program(int ret) } output_streams[i]->bitstream_filters = NULL; - if (output_streams[i]->output_frame) { - AVFrame *frame = output_streams[i]->output_frame; - if (frame->extended_data != frame->data) - av_freep(&frame->extended_data); - av_freep(&frame); - } av_freep(&output_streams[i]->filtered_frame); av_freep(&output_streams[i]); } @@ -1223,10 +1619,6 @@ void av_noreturn exit_program(int ret) av_freep(&output_files); uninit_opts(); - av_freep(&audio_buf); - allocated_audio_buf_size = 0; - av_freep(&async_buf); - allocated_async_buf_size = 0; avfilter_uninit(); avformat_network_deinit(); @@ -1237,7 +1629,7 @@ void av_noreturn exit_program(int ret) exit (255); } - exit(ret); /* not all OS-es handle main() return value */ + exit(ret); } static void assert_avoptions(AVDictionary *m) @@ -1288,44 +1680,6 @@ static void choose_sample_fmt(AVStream *st, AVCodec *codec) } } -static void choose_sample_rate(AVStream *st, AVCodec *codec) -{ - if (codec && codec->supported_samplerates) { - const int *p = codec->supported_samplerates; - int best = 0; - int best_dist = INT_MAX; - for (; *p; p++) { - int dist = abs(st->codec->sample_rate - *p); - if (dist < best_dist) { - best_dist = dist; - best = *p; - } - } - if (best_dist) { - int i; - const int *sample_rates = codec->supported_samplerates; - av_log(st->codec, AV_LOG_WARNING, - "Requested sampling rate (%dHz) unsupported, using %dHz instead\n" - "Available sampling rates for %s:", - st->codec->sample_rate, best, codec->name); - for (i = 0; sample_rates[i]; i++) { - if (!sample_rates[i + 1]) av_log(st->codec, AV_LOG_WARNING, " and"); - else if (i) av_log(st->codec, AV_LOG_WARNING, ","); - av_log(st->codec, AV_LOG_WARNING, " %d", sample_rates[i]); - } - av_log(st->codec, AV_LOG_WARNING, ".\n"); - } - st->codec->sample_rate = best; - } -} - -static double -get_sync_ipts(const OutputStream *ost, int64_t pts) -{ - OutputFile *of = output_files[ost->file_index]; - return (double)(pts - of->start_time) / AV_TIME_BASE; -} - static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost) { AVBitStreamFilterContext *bsfc = ost->bitstream_filters; @@ -1336,6 +1690,14 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost) (avctx->codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0)) pkt->pts = pkt->dts = AV_NOPTS_VALUE; + if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && pkt->dts != AV_NOPTS_VALUE) { + int64_t max = ost->st->cur_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT); + if (ost->st->cur_dts && ost->st->cur_dts != AV_NOPTS_VALUE && max > pkt->dts) { + av_log(s, max - pkt->dts > 2 ? AV_LOG_WARNING : AV_LOG_DEBUG, "Audio timestamp %"PRId64" < %"PRId64" invalid, cliping\n", pkt->dts, max); + pkt->pts = pkt->dts = max; + } + } + /* * Audio encoders may split the packets -- #frames in != #packets out. * But there is no reordering, so we can limit the number of output packets @@ -1381,104 +1743,38 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost) } } -static void get_default_channel_layouts(OutputStream *ost, InputStream *ist) +static int check_recording_time(OutputStream *ost) { - char layout_name[256]; - AVCodecContext *enc = ost->st->codec; - AVCodecContext *dec = ist->st->codec; - - if (dec->channel_layout && - av_get_channel_layout_nb_channels(dec->channel_layout) != dec->channels) { - av_get_channel_layout_string(layout_name, sizeof(layout_name), - dec->channels, dec->channel_layout); - av_log(NULL, AV_LOG_ERROR, "New channel layout (%s) is invalid\n", - layout_name); - dec->channel_layout = 0; - } - if (!dec->channel_layout) { - if (enc->channel_layout && dec->channels == enc->channels) { - dec->channel_layout = enc->channel_layout; - } else { - dec->channel_layout = av_get_default_channel_layout(dec->channels); + OutputFile *of = output_files[ost->file_index]; - if (!dec->channel_layout) { - av_log(NULL, AV_LOG_FATAL, "Unable to find default channel " - "layout for Input Stream #%d.%d\n", ist->file_index, - ist->st->index); - exit_program(1); - } - } - av_get_channel_layout_string(layout_name, sizeof(layout_name), - dec->channels, dec->channel_layout); - av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Input Stream " - "#%d.%d : %s\n", ist->file_index, ist->st->index, layout_name); - } - if (!enc->channel_layout) { - if (dec->channels == enc->channels) { - enc->channel_layout = dec->channel_layout; - return; - } else { - enc->channel_layout = av_get_default_channel_layout(enc->channels); - } - if (!enc->channel_layout) { - av_log(NULL, AV_LOG_FATAL, "Unable to find default channel layout " - "for Output Stream #%d.%d\n", ost->file_index, - ost->st->index); - exit_program(1); - } - av_get_channel_layout_string(layout_name, sizeof(layout_name), - enc->channels, enc->channel_layout); - av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Output Stream " - "#%d.%d : %s\n", ost->file_index, ost->st->index, layout_name); + if (of->recording_time != INT64_MAX && + av_compare_ts(ost->sync_opts - ost->first_pts, ost->st->codec->time_base, of->recording_time, + AV_TIME_BASE_Q) >= 0) { + ost->is_past_recording_time = 1; + return 0; } + return 1; } -static void generate_silence(uint8_t* buf, enum AVSampleFormat sample_fmt, size_t size) -{ - int fill_char = 0x00; - if (sample_fmt == AV_SAMPLE_FMT_U8) - fill_char = 0x80; - memset(buf, fill_char, size); -} - -static int encode_audio_frame(AVFormatContext *s, OutputStream *ost, - const uint8_t *buf, int buf_size) +static void do_audio_out(AVFormatContext *s, OutputStream *ost, + AVFrame *frame) { AVCodecContext *enc = ost->st->codec; - AVFrame *frame = NULL; AVPacket pkt; - int ret, got_packet; + int got_packet = 0; av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; - - if (buf && buf_size) { - if (!ost->output_frame) { - ost->output_frame = avcodec_alloc_frame(); - if (!ost->output_frame) { - av_log(NULL, AV_LOG_FATAL, "out-of-memory in encode_audio_frame()\n"); - exit_program(1); - } - } - frame = ost->output_frame; - if (frame->extended_data != frame->data) - av_freep(&frame->extended_data); - avcodec_get_frame_defaults(frame); - - frame->nb_samples = buf_size / - (enc->channels * av_get_bytes_per_sample(enc->sample_fmt)); - if ((ret = avcodec_fill_audio_frame(frame, enc->channels, enc->sample_fmt, - buf, buf_size, 1)) < 0) { - av_log(NULL, AV_LOG_FATAL, "Audio encoding failed (avcodec_fill_audio_frame)\n"); - exit_program(1); - } - +#if 0 + if (!check_recording_time(ost)) + return; +#endif + if (frame->pts == AV_NOPTS_VALUE || audio_sync_method < 0) frame->pts = ost->sync_opts; - ost->sync_opts += frame->nb_samples; - } + ost->sync_opts = frame->pts + frame->nb_samples; - got_packet = 0; + av_assert0(pkt.size || !pkt.data); update_benchmark(NULL); if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) { av_log(NULL, AV_LOG_FATAL, "Audio encoding failed (avcodec_encode_audio2)\n"); @@ -1486,250 +1782,26 @@ static int encode_audio_frame(AVFormatContext *s, OutputStream *ost, } update_benchmark("encode_audio %d.%d", ost->file_index, ost->index); - ret = pkt.size; - if (got_packet) { if (pkt.pts != AV_NOPTS_VALUE) pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base); - if (pkt.dts != AV_NOPTS_VALUE) { - int64_t max = ost->st->cur_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT); + if (pkt.dts != AV_NOPTS_VALUE) pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base); - if (ost->st->cur_dts && ost->st->cur_dts != AV_NOPTS_VALUE && max > pkt.dts) { - av_log(s, max - pkt.dts > 2 ? AV_LOG_WARNING : AV_LOG_DEBUG, "Audio timestamp %"PRId64" < %"PRId64" invalid, cliping\n", pkt.dts, max); - pkt.pts = pkt.dts = max; - } - } if (pkt.duration > 0) pkt.duration = av_rescale_q(pkt.duration, enc->time_base, ost->st->time_base); + if (debug_ts) { + av_log(NULL, AV_LOG_INFO, "encoder -> type:audio " + "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n", + av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base), + av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base)); + } + write_frame(s, &pkt, ost); audio_size += pkt.size; - av_free_packet(&pkt); } - - if (debug_ts) { - av_log(NULL, AV_LOG_INFO, "encoder -> type:audio " - "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n", - av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base), - av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base)); - } - - return ret; -} - -static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc, - int nb_samples) -{ - int64_t audio_buf_samples; - int audio_buf_size; - - /* calculate required number of samples to allocate */ - audio_buf_samples = ((int64_t)nb_samples * enc->sample_rate + dec->sample_rate) / - dec->sample_rate; - audio_buf_samples = 4 * audio_buf_samples + 10000; // safety factors for resampling - audio_buf_samples = FFMAX(audio_buf_samples, enc->frame_size); - if (audio_buf_samples > INT_MAX) - return AVERROR(EINVAL); - - audio_buf_size = av_samples_get_buffer_size(NULL, enc->channels, - audio_buf_samples, - enc->sample_fmt, 0); - if (audio_buf_size < 0) - return audio_buf_size; - - av_fast_malloc(&audio_buf, &allocated_audio_buf_size, audio_buf_size); - if (!audio_buf) - return AVERROR(ENOMEM); - - return 0; -} - -static void do_audio_out(AVFormatContext *s, OutputStream *ost, - InputStream *ist, AVFrame *decoded_frame) -{ - uint8_t *buftmp; - int64_t size_out; - - int frame_bytes, resample_changed; - AVCodecContext *enc = ost->st->codec; - AVCodecContext *dec = ist->st->codec; - int osize = av_get_bytes_per_sample(enc->sample_fmt); - int isize = av_get_bytes_per_sample(dec->sample_fmt); - uint8_t *buf[AV_NUM_DATA_POINTERS]; - int size = decoded_frame->nb_samples * dec->channels * isize; - int planes = av_sample_fmt_is_planar(dec->sample_fmt) ? dec->channels : 1; - int i; - - av_assert0(planes <= AV_NUM_DATA_POINTERS); - - for(i=0; idata[i]; - - get_default_channel_layouts(ost, ist); - - if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples) < 0) { - av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); - exit_program(1); - } - - if (enc->channels != dec->channels - || enc->sample_fmt != dec->sample_fmt - || enc->sample_rate!= dec->sample_rate - ) - ost->audio_resample = 1; - - resample_changed = ost->resample_sample_fmt != dec->sample_fmt || - ost->resample_channels != dec->channels || - ost->resample_sample_rate != dec->sample_rate; - - if ((ost->audio_resample && !ost->swr) || resample_changed || ost->audio_channels_mapped) { - if (resample_changed) { - av_log(NULL, AV_LOG_INFO, "Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d to rate:%d fmt:%s ch:%d\n", - ist->file_index, ist->st->index, - ost->resample_sample_rate, av_get_sample_fmt_name(ost->resample_sample_fmt), ost->resample_channels, - dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), dec->channels); - ost->resample_sample_fmt = dec->sample_fmt; - ost->resample_channels = dec->channels; - ost->resample_sample_rate = dec->sample_rate; - swr_free(&ost->swr); - } - /* if audio_sync_method is >1 the resampler is needed for audio drift compensation */ - if (audio_sync_method <= 1 && !ost->audio_channels_mapped && - ost->resample_sample_fmt == enc->sample_fmt && - ost->resample_channels == enc->channels && - ost->resample_sample_rate == enc->sample_rate) { - //ost->swr = NULL; - ost->audio_resample = 0; - } else { - ost->swr = swr_alloc_set_opts(ost->swr, - enc->channel_layout, enc->sample_fmt, enc->sample_rate, - dec->channel_layout, dec->sample_fmt, dec->sample_rate, - 0, NULL); - av_opt_set_int(ost->swr, "dither_method", ost->swr_dither_method,0); - av_opt_set_int(ost->swr, "dither_scale", ost->swr_dither_scale,0); - if (ost->audio_channels_mapped) - swr_set_channel_mapping(ost->swr, ost->audio_channels_map); - av_opt_set_double(ost->swr, "rmvol", ost->rematrix_volume, 0); - if (ost->audio_channels_mapped) { - av_opt_set_int(ost->swr, "icl", av_get_default_channel_layout(ost->audio_channels_mapped), 0); - av_opt_set_int(ost->swr, "uch", ost->audio_channels_mapped, 0); - } - if (av_opt_set_int(ost->swr, "ich", dec->channels, 0) < 0) { - av_log(NULL, AV_LOG_FATAL, "Unsupported number of input channels\n"); - exit_program(1); - } - if (av_opt_set_int(ost->swr, "och", enc->channels, 0) < 0) { - av_log(NULL, AV_LOG_FATAL, "Unsupported number of output channels\n"); - exit_program(1); - } - if(audio_sync_method>1) av_opt_set_int(ost->swr, "flags", SWR_FLAG_RESAMPLE, 0); - if(ost->swr && swr_init(ost->swr) < 0){ - av_log(NULL, AV_LOG_FATAL, "swr_init() failed\n"); - swr_free(&ost->swr); - } - - if (!ost->swr) { - av_log(NULL, AV_LOG_FATAL, "Can not resample %d channels @ %d Hz to %d channels @ %d Hz\n", - dec->channels, dec->sample_rate, - enc->channels, enc->sample_rate); - exit_program(1); - } - } - } - - av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt); - - if (audio_sync_method > 0) { - double delta = get_sync_ipts(ost, ist->pts) * enc->sample_rate - ost->sync_opts - - av_fifo_size(ost->fifo) / (enc->channels * osize); - int idelta = delta * dec->sample_rate / enc->sample_rate; - int byte_delta = idelta * isize * dec->channels; - - // FIXME resample delay - if (fabs(delta) > 50) { - if (ist->is_start || fabs(delta) > audio_drift_threshold*enc->sample_rate) { - if (byte_delta < 0) { - byte_delta = FFMAX(byte_delta, -size); - size += byte_delta; - for (i=0; ichannels)); - if (!size) - return; - ist->is_start = 0; - } else { - av_fast_malloc(&async_buf, &allocated_async_buf_size, - byte_delta + size); - if (!async_buf) { - av_log(NULL, AV_LOG_FATAL, "Out of memory in do_audio_out\n"); - exit_program(1); - } - - if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples + idelta) < 0) { - av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); - exit_program(1); - } - ist->is_start = 0; - - for (i=0; isample_fmt, byte_delta/planes); - memcpy(t + byte_delta/planes, buf[i], size/planes); - buf[i] = t; - } - size += byte_delta; - av_log(NULL, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", idelta); - } - } else if (audio_sync_method > 1) { - int comp = av_clip(delta, -audio_sync_method, audio_sync_method); - av_assert0(ost->audio_resample); - av_log(NULL, AV_LOG_VERBOSE, "compensating audio timestamp drift:%f compensation:%d in:%d\n", - delta, comp, enc->sample_rate); -// fprintf(stderr, "drift:%f len:%d opts:%"PRId64" ipts:%"PRId64" fifo:%d\n", delta, -1, ost->sync_opts, (int64_t)(get_sync_ipts(ost) * enc->sample_rate), av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2)); - swr_set_compensation(ost->swr, comp, enc->sample_rate); - } - } - } else if (audio_sync_method == 0) - ost->sync_opts = lrintf(get_sync_ipts(ost, ist->pts) * enc->sample_rate) - - av_fifo_size(ost->fifo) / (enc->channels * osize); // FIXME wrong - - if (ost->audio_resample || ost->audio_channels_mapped) { - buftmp = audio_buf; - size_out = swr_convert(ost->swr, ( uint8_t*[]){buftmp}, allocated_audio_buf_size / (enc->channels * osize), - buf, size / (dec->channels * isize)); - if (size_out < 0) { - av_log(NULL, AV_LOG_FATAL, "swr_convert failed\n"); - exit_program(1); - } - size_out = size_out * enc->channels * osize; - } else { - buftmp = buf[0]; - size_out = size; - } - - av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt); - - /* now encode as many frames as possible */ - if (!(enc->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) { - /* output resampled raw samples */ - if (av_fifo_realloc2(ost->fifo, av_fifo_size(ost->fifo) + size_out) < 0) { - av_log(NULL, AV_LOG_FATAL, "av_fifo_realloc2() failed\n"); - exit_program(1); - } - av_fifo_generic_write(ost->fifo, buftmp, size_out, NULL); - - frame_bytes = enc->frame_size * osize * enc->channels; - - while (av_fifo_size(ost->fifo) >= frame_bytes) { - av_fifo_generic_read(ost->fifo, audio_buf, frame_bytes, NULL); - encode_audio_frame(s, ost, audio_buf, frame_bytes); - } - } else { - encode_audio_frame(s, ost, buftmp, size_out); - } } static void pre_process_video_frame(InputStream *ist, AVPicture *picture, void **bufp) @@ -1827,62 +1899,23 @@ static void do_subtitle_out(AVFormatContext *s, /* XXX: the pts correction is handled here. Maybe handling it in the codec would be better */ if (i == 0) - pkt.pts += 90 * sub->start_display_time; - else - pkt.pts += 90 * sub->end_display_time; - } - write_frame(s, &pkt, ost); - } -} - -static double psnr(double d) -{ - return -10.0 * log(d) / log(10.0); -} - -static void do_video_stats(AVFormatContext *os, OutputStream *ost, - int frame_size) -{ - AVCodecContext *enc; - int frame_number; - double ti1, bitrate, avg_bitrate; - - /* this is executed just the first time do_video_stats is called */ - if (!vstats_file) { - vstats_file = fopen(vstats_filename, "w"); - if (!vstats_file) { - perror("fopen"); - exit_program(1); - } - } - - enc = ost->st->codec; - if (enc->codec_type == AVMEDIA_TYPE_VIDEO) { - frame_number = ost->frame_number; - fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality / (float)FF_QP2LAMBDA); - if (enc->flags&CODEC_FLAG_PSNR) - fprintf(vstats_file, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0] / (enc->width * enc->height * 255.0 * 255.0))); - - fprintf(vstats_file,"f_size= %6d ", frame_size); - /* compute pts value */ - ti1 = ost->sync_opts * av_q2d(enc->time_base); - if (ti1 < 0.01) - ti1 = 0.01; - - bitrate = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0; - avg_bitrate = (double)(video_size * 8) / ti1 / 1000.0; - fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ", - (double)video_size / 1024, ti1, bitrate, avg_bitrate); - fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(enc->coded_frame->pict_type)); + pkt.pts += 90 * sub->start_display_time; + else + pkt.pts += 90 * sub->end_display_time; + } + write_frame(s, &pkt, ost); } } - -static void do_video_out(AVFormatContext *s, OutputStream *ost, - AVFrame *in_picture, float quality) +static void do_video_out(AVFormatContext *s, + OutputStream *ost, + AVFrame *in_picture, + float quality) { - int nb_frames, i, ret, format_video_sync; - AVCodecContext *enc; + int ret, format_video_sync; + AVPacket pkt; + AVCodecContext *enc = ost->st->codec; + int nb_frames, i; double sync_ipts, delta; double duration = 0; int frame_size = 0; @@ -1891,19 +1924,10 @@ static void do_video_out(AVFormatContext *s, OutputStream *ost, if (ost->source_index >= 0) ist = input_streams[ost->source_index]; - enc = ost->st->codec; - - if (ist && ist->st->start_time != AV_NOPTS_VALUE && ist->st->first_dts != AV_NOPTS_VALUE) { - duration = FFMAX(av_q2d(ist->st->time_base), av_q2d(ist->st->codec->time_base)); - if(ist->st->r_frame_rate.num) - duration= FFMAX(duration, 1/av_q2d(ist->st->r_frame_rate)); - if(ist->st->avg_frame_rate.num && 0) - duration= FFMAX(duration, 1/av_q2d(ist->st->avg_frame_rate)); - - duration /= av_q2d(enc->time_base); - } + if(ist && ist->st->start_time != AV_NOPTS_VALUE && ist->st->first_dts != AV_NOPTS_VALUE && ost->frame_rate.num) + duration = 1/(av_q2d(ost->frame_rate) * av_q2d(enc->time_base)); - sync_ipts = get_sync_ipts(ost, in_picture->pts) / av_q2d(enc->time_base); + sync_ipts = in_picture->pts; delta = sync_ipts - ost->sync_opts + duration; /* by default, we output a single frame */ @@ -1925,11 +1949,11 @@ static void do_video_out(AVFormatContext *s, OutputStream *ost, if (delta <= -0.6) nb_frames = 0; else if (delta > 0.6) - ost->sync_opts = lrintf(sync_ipts); + ost->sync_opts = lrint(sync_ipts); break; case VSYNC_DROP: case VSYNC_PASSTHROUGH: - ost->sync_opts = lrintf(sync_ipts); + ost->sync_opts = lrint(sync_ipts); break; default: av_assert0(0); @@ -1945,153 +1969,254 @@ static void do_video_out(AVFormatContext *s, OutputStream *ost, av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1); } - /* duplicates frame if needed */ - for (i = 0; i < nb_frames; i++) { - AVPacket pkt; - av_init_packet(&pkt); - pkt.data = NULL; - pkt.size = 0; - - if (s->oformat->flags & AVFMT_RAWPICTURE && - enc->codec->id == CODEC_ID_RAWVIDEO) { - /* raw pictures are written as AVPicture structure to - avoid any copies. We support temporarily the older - method. */ - enc->coded_frame->interlaced_frame = in_picture->interlaced_frame; - enc->coded_frame->top_field_first = in_picture->top_field_first; - pkt.data = (uint8_t *)in_picture; - pkt.size = sizeof(AVPicture); - pkt.pts = av_rescale_q(ost->sync_opts, enc->time_base, ost->st->time_base); - pkt.flags |= AV_PKT_FLAG_KEY; - write_frame(s, &pkt, ost); - } else { - int got_packet; - AVFrame big_picture; - - big_picture = *in_picture; - /* better than nothing: use input picture interlaced - settings */ - big_picture.interlaced_frame = in_picture->interlaced_frame; - if (ost->st->codec->flags & (CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME)) { - if (ost->top_field_first == -1) - big_picture.top_field_first = in_picture->top_field_first; - else - big_picture.top_field_first = !!ost->top_field_first; - } +duplicate_frame: + av_init_packet(&pkt); + pkt.data = NULL; + pkt.size = 0; - /* handles same_quant here. This is not correct because it may - not be a global option */ - big_picture.quality = quality; - if (!enc->me_threshold) - big_picture.pict_type = 0; - big_picture.pts = ost->sync_opts; - if (ost->forced_kf_index < ost->forced_kf_count && - big_picture.pts >= ost->forced_kf_pts[ost->forced_kf_index]) { - big_picture.pict_type = AV_PICTURE_TYPE_I; - ost->forced_kf_index++; - } - update_benchmark(NULL); - ret = avcodec_encode_video2(enc, &pkt, &big_picture, &got_packet); - update_benchmark("encode_video %d.%d", ost->file_index, ost->index); - if (ret < 0) { - av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n"); - exit_program(1); - } + in_picture->pts = ost->sync_opts; - if (got_packet) { - if (pkt.pts == AV_NOPTS_VALUE && !(enc->codec->capabilities & CODEC_CAP_DELAY)) - pkt.pts = ost->sync_opts; + if (s->oformat->flags & AVFMT_RAWPICTURE && + enc->codec->id == CODEC_ID_RAWVIDEO) { + /* raw pictures are written as AVPicture structure to + avoid any copies. We support temporarily the older + method. */ + enc->coded_frame->interlaced_frame = in_picture->interlaced_frame; + enc->coded_frame->top_field_first = in_picture->top_field_first; + pkt.data = (uint8_t *)in_picture; + pkt.size = sizeof(AVPicture); + pkt.pts = av_rescale_q(in_picture->pts, enc->time_base, ost->st->time_base); + pkt.flags |= AV_PKT_FLAG_KEY; - if (pkt.pts != AV_NOPTS_VALUE) - pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base); - if (pkt.dts != AV_NOPTS_VALUE) - pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base); + write_frame(s, &pkt, ost); + } else { + int got_packet; + AVFrame big_picture; + + big_picture = *in_picture; + /* better than nothing: use input picture interlaced + settings */ + big_picture.interlaced_frame = in_picture->interlaced_frame; + if (ost->st->codec->flags & (CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME)) { + if (ost->top_field_first == -1) + big_picture.top_field_first = in_picture->top_field_first; + else + big_picture.top_field_first = !!ost->top_field_first; + } + + /* handles same_quant here. This is not correct because it may + not be a global option */ + big_picture.quality = quality; + if (!enc->me_threshold) + big_picture.pict_type = 0; + if (ost->forced_kf_index < ost->forced_kf_count && + big_picture.pts >= ost->forced_kf_pts[ost->forced_kf_index]) { + big_picture.pict_type = AV_PICTURE_TYPE_I; + ost->forced_kf_index++; + } + update_benchmark(NULL); + ret = avcodec_encode_video2(enc, &pkt, &big_picture, &got_packet); + update_benchmark("encode_video %d.%d", ost->file_index, ost->index); + if (ret < 0) { + av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n"); + exit_program(1); + } - if (debug_ts) { - av_log(NULL, AV_LOG_INFO, "encoder -> type:video " - "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n", - av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base), - av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base)); - } + if (got_packet) { + if (pkt.pts == AV_NOPTS_VALUE && !(enc->codec->capabilities & CODEC_CAP_DELAY)) + pkt.pts = ost->sync_opts; - write_frame(s, &pkt, ost); - frame_size = pkt.size; - video_size += pkt.size; - av_free_packet(&pkt); + if (pkt.pts != AV_NOPTS_VALUE) + pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base); + if (pkt.dts != AV_NOPTS_VALUE) + pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base); - /* if two pass, output log */ - if (ost->logfile && enc->stats_out) { - fprintf(ost->logfile, "%s", enc->stats_out); - } + if (debug_ts) { + av_log(NULL, AV_LOG_INFO, "encoder -> type:video " + "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n", + av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base), + av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base)); + } + + write_frame(s, &pkt, ost); + frame_size = pkt.size; + video_size += pkt.size; + av_free_packet(&pkt); + + /* if two pass, output log */ + if (ost->logfile && enc->stats_out) { + fprintf(ost->logfile, "%s", enc->stats_out); } } - ost->sync_opts++; - /* - * For video, number of frames in == number of packets out. - * But there may be reordering, so we can't throw away frames on encoder - * flush, we need to limit them here, before they go into encoder. - */ - ost->frame_number++; } + ost->sync_opts++; + /* + * For video, number of frames in == number of packets out. + * But there may be reordering, so we can't throw away frames on encoder + * flush, we need to limit them here, before they go into encoder. + */ + ost->frame_number++; + + if(--nb_frames) + goto duplicate_frame; + if (vstats_filename && frame_size) do_video_stats(output_files[ost->file_index]->ctx, ost, frame_size); } +static double psnr(double d) +{ + return -10.0 * log(d) / log(10.0); +} + +static void do_video_stats(AVFormatContext *os, OutputStream *ost, + int frame_size) +{ + AVCodecContext *enc; + int frame_number; + double ti1, bitrate, avg_bitrate; + + /* this is executed just the first time do_video_stats is called */ + if (!vstats_file) { + vstats_file = fopen(vstats_filename, "w"); + if (!vstats_file) { + perror("fopen"); + exit_program(1); + } + } + + enc = ost->st->codec; + if (enc->codec_type == AVMEDIA_TYPE_VIDEO) { + frame_number = ost->frame_number; + fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality / (float)FF_QP2LAMBDA); + if (enc->flags&CODEC_FLAG_PSNR) + fprintf(vstats_file, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0] / (enc->width * enc->height * 255.0 * 255.0))); + + fprintf(vstats_file,"f_size= %6d ", frame_size); + /* compute pts value */ + ti1 = ost->sync_opts * av_q2d(enc->time_base); + if (ti1 < 0.01) + ti1 = 0.01; + + bitrate = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0; + avg_bitrate = (double)(video_size * 8) / ti1 / 1000.0; + fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ", + (double)video_size / 1024, ti1, bitrate, avg_bitrate); + fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(enc->coded_frame->pict_type)); + } +} + /* check for new output on any of the filtergraphs */ static int poll_filters(void) { AVFilterBufferRef *picref; AVFrame *filtered_frame = NULL; - int i, ret; + int i, ret, ret_all; + unsigned nb_success, nb_eof; + int64_t frame_pts; - for (i = 0; i < nb_output_streams; i++) { - OutputStream *ost = output_streams[i]; - OutputFile *of = output_files[ost->file_index]; + while (1) { + /* Reap all buffers present in the buffer sinks */ + for (i = 0; i < nb_output_streams; i++) { + OutputStream *ost = output_streams[i]; + OutputFile *of = output_files[ost->file_index]; + int ret = 0; - if (!ost->filter || ost->is_past_recording_time) - continue; + if (!ost->filter || ost->is_past_recording_time) + continue; - if (!ost->filtered_frame && !(ost->filtered_frame = avcodec_alloc_frame())) { - return AVERROR(ENOMEM); - } else - avcodec_get_frame_defaults(ost->filtered_frame); - filtered_frame = ost->filtered_frame; - - while (avfilter_poll_frame(ost->filter->filter->inputs[0])) { - AVRational ist_pts_tb = ost->filter->filter->inputs[0]->time_base; - if ((ret = av_buffersink_get_buffer_ref(ost->filter->filter, - &picref, - 0)) < 0) { - av_log(NULL, AV_LOG_WARNING, "AV Filter told us it has a frame available but failed to output one\n"); - return ret; - } - filtered_frame->pts = av_rescale_q(picref->pts, ist_pts_tb, AV_TIME_BASE_Q); -// if (ost->source_index >= 0) -// *filtered_frame= *input_streams[ost->source_index]->decoded_frame; //for me_threshold + if (!ost->filtered_frame && !(ost->filtered_frame = avcodec_alloc_frame())) { + return AVERROR(ENOMEM); + } else + avcodec_get_frame_defaults(ost->filtered_frame); + filtered_frame = ost->filtered_frame; + + while (1) { + AVRational ist_pts_tb = ost->filter->filter->inputs[0]->time_base; + if (ost->enc->type == AVMEDIA_TYPE_AUDIO && + !(ost->enc->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) + ret = av_buffersink_read_samples(ost->filter->filter, &picref, + ost->st->codec->frame_size); + else +#ifdef SINKA + ret = av_buffersink_read(ost->filter->filter, &picref); +#else + ret = av_buffersink_get_buffer_ref(ost->filter->filter, &picref, + AV_BUFFERSINK_FLAG_NO_REQUEST); +#endif + if (ret < 0) { + if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) { + char buf[256]; + av_strerror(ret, buf, sizeof(buf)); + av_log(NULL, AV_LOG_WARNING, + "Error in av_buffersink_get_buffer_ref(): %s\n", buf); + } + break; + } + frame_pts = AV_NOPTS_VALUE; + if (picref->pts != AV_NOPTS_VALUE) { + filtered_frame->pts = frame_pts = av_rescale_q(picref->pts, + ost->filter->filter->inputs[0]->time_base, + ost->st->codec->time_base) - + av_rescale_q(of->start_time, + AV_TIME_BASE_Q, + ost->st->codec->time_base); + + if (of->start_time && filtered_frame->pts < 0) { + avfilter_unref_buffer(picref); + continue; + } + } + //if (ost->source_index >= 0) + // *filtered_frame= *input_streams[ost->source_index]->decoded_frame; //for me_threshold - if (of->start_time && filtered_frame->pts < of->start_time) - return 0; - switch (ost->filter->filter->inputs[0]->type) { - case AVMEDIA_TYPE_VIDEO: - avfilter_fill_frame_from_video_buffer_ref(filtered_frame, picref); - if (!ost->frame_aspect_ratio) - ost->st->codec->sample_aspect_ratio = picref->video->sample_aspect_ratio; + switch (ost->filter->filter->inputs[0]->type) { + case AVMEDIA_TYPE_VIDEO: + avfilter_fill_frame_from_video_buffer_ref(filtered_frame, picref); + filtered_frame->pts = frame_pts; + if (!ost->frame_aspect_ratio) + ost->st->codec->sample_aspect_ratio = picref->video->sample_aspect_ratio; - do_video_out(of->ctx, ost, filtered_frame, - same_quant ? ost->last_quality : - ost->st->codec->global_quality); - break; - default: - // TODO support audio/subtitle filters - av_assert0(0); - } + do_video_out(of->ctx, ost, filtered_frame, + same_quant ? ost->last_quality : + ost->st->codec->global_quality); + break; + case AVMEDIA_TYPE_AUDIO: + avfilter_copy_buf_props(filtered_frame, picref); + filtered_frame->pts = frame_pts; + do_audio_out(of->ctx, ost, filtered_frame); + break; + default: + // TODO support subtitle filters + av_assert0(0); + } - avfilter_unref_buffer(picref); + avfilter_unref_buffer(picref); + } + } + /* Request frames through all the graphs */ + ret_all = nb_success = nb_eof = 0; + for (i = 0; i < nb_filtergraphs; i++) { + ret = avfilter_graph_request_oldest(filtergraphs[i]->graph); + if (!ret) { + nb_success++; + } else if (ret == AVERROR_EOF) { + nb_eof++; + } else if (ret != AVERROR(EAGAIN)) { + char buf[256]; + av_strerror(ret, buf, sizeof(buf)); + av_log(NULL, AV_LOG_WARNING, + "Error in request_frame(): %s\n", buf); + ret_all = ret; + } } + if (!nb_success) + break; + /* Try again if anything succeeded */ } - return 0; + return nb_eof == nb_filtergraphs ? AVERROR_EOF : ret_all; } static void print_report(int is_last_report, int64_t timer_start, int64_t cur_time) @@ -2247,48 +2372,40 @@ static void flush_encoders(void) continue; for (;;) { - AVPacket pkt; - int fifo_bytes, got_packet; - av_init_packet(&pkt); - pkt.data = NULL; - pkt.size = 0; + int (*encode)(AVCodecContext*, AVPacket*, const AVFrame*, int*) = NULL; + const char *desc; + int64_t *size; switch (ost->st->codec->codec_type) { case AVMEDIA_TYPE_AUDIO: - fifo_bytes = av_fifo_size(ost->fifo); - if (fifo_bytes > 0) { - /* encode any samples remaining in fifo */ - int frame_bytes = fifo_bytes; - - av_fifo_generic_read(ost->fifo, audio_buf, fifo_bytes, NULL); - - /* pad last frame with silence if needed */ - if (!(enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME)) { - frame_bytes = enc->frame_size * enc->channels * - av_get_bytes_per_sample(enc->sample_fmt); - if (allocated_audio_buf_size < frame_bytes) - exit_program(1); - generate_silence(audio_buf+fifo_bytes, enc->sample_fmt, frame_bytes - fifo_bytes); - } - encode_audio_frame(os, ost, audio_buf, frame_bytes); - } else { - /* flush encoder with NULL frames until it is done - returning packets */ - if (encode_audio_frame(os, ost, NULL, 0) == 0) { - stop_encoding = 1; - break; - } - } + encode = avcodec_encode_audio2; + desc = "Audio"; + size = &audio_size; break; case AVMEDIA_TYPE_VIDEO: + encode = avcodec_encode_video2; + desc = "Video"; + size = &video_size; + break; + default: + stop_encoding = 1; + } + + if (encode) { + AVPacket pkt; + int got_packet; + av_init_packet(&pkt); + pkt.data = NULL; + pkt.size = 0; + update_benchmark(NULL); - ret = avcodec_encode_video2(enc, &pkt, NULL, &got_packet); - update_benchmark("encode_video %d.%d", ost->file_index, ost->index); + ret = encode(enc, &pkt, NULL, &got_packet); + update_benchmark("flush %s %d.%d", desc, ost->file_index, ost->index); if (ret < 0) { - av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n"); + av_log(NULL, AV_LOG_FATAL, "%s encoding failed\n", desc); exit_program(1); } - video_size += pkt.size; + *size += pkt.size; if (ost->logfile && enc->stats_out) { fprintf(ost->logfile, "%s", enc->stats_out); } @@ -2301,10 +2418,8 @@ static void flush_encoders(void) if (pkt.dts != AV_NOPTS_VALUE) pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base); write_frame(os, &pkt, ost); - break; - default: - stop_encoding = 1; } + if (stop_encoding) break; } @@ -2405,12 +2520,29 @@ static void rate_emu_sleep(InputStream *ist) } } -static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output) +static int guess_input_channel_layout(InputStream *ist) +{ + AVCodecContext *dec = ist->st->codec; + + if (!dec->channel_layout) { + char layout_name[256]; + + dec->channel_layout = av_get_default_channel_layout(dec->channels); + if (!dec->channel_layout) + return 0; + av_get_channel_layout_string(layout_name, sizeof(layout_name), + dec->channels, dec->channel_layout); + av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Input Stream " + "#%d.%d : %s\n", ist->file_index, ist->st->index, layout_name); + } + return 1; +} + +static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output) { AVFrame *decoded_frame; AVCodecContext *avctx = ist->st->codec; - int bps = av_get_bytes_per_sample(ist->st->codec->sample_fmt); - int i, ret; + int i, ret, resample_changed; if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame())) return AVERROR(ENOMEM); @@ -2431,6 +2563,10 @@ static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output) if (!*got_output) { /* no audio frame */ + if (!pkt->size) + for (i = 0; i < ist->nb_filters; i++) + av_buffersrc_add_ref(ist->filters[i]->filter, NULL, + AV_BUFFERSRC_FLAG_NO_COPY); return ret; } @@ -2438,92 +2574,77 @@ static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output) the decoder could be delaying output by a packet or more. */ if (decoded_frame->pts != AV_NOPTS_VALUE) ist->dts = ist->next_dts = ist->pts = ist->next_pts = decoded_frame->pts; + else if (pkt->pts != AV_NOPTS_VALUE) { + decoded_frame->pts = pkt->pts; + pkt->pts = AV_NOPTS_VALUE; + }else + decoded_frame->pts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base); + +#if 1 /* increment next_dts to use for the case where the input stream does not have timestamps or there are multiple frames in the packet */ ist->next_pts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) / avctx->sample_rate; ist->next_dts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) / avctx->sample_rate; +#endif + rate_emu_sleep(ist); - // preprocess audio (volume) - if (audio_volume != 256) { - int decoded_data_size = decoded_frame->nb_samples * avctx->channels * bps; - void *samples = decoded_frame->data[0]; - switch (avctx->sample_fmt) { - case AV_SAMPLE_FMT_U8: - { - uint8_t *volp = samples; - for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) { - int v = (((*volp - 128) * audio_volume + 128) >> 8) + 128; - *volp++ = av_clip_uint8(v); - } - break; - } - case AV_SAMPLE_FMT_S16: - { - int16_t *volp = samples; - for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) { - int v = ((*volp) * audio_volume + 128) >> 8; - *volp++ = av_clip_int16(v); - } - break; - } - case AV_SAMPLE_FMT_S32: - { - int32_t *volp = samples; - for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) { - int64_t v = (((int64_t)*volp * audio_volume + 128) >> 8); - *volp++ = av_clipl_int32(v); - } - break; - } - case AV_SAMPLE_FMT_FLT: - { - float *volp = samples; - float scale = audio_volume / 256.f; - for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) { - *volp++ *= scale; - } - break; - } - case AV_SAMPLE_FMT_DBL: - { - double *volp = samples; - double scale = audio_volume / 256.; - for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) { - *volp++ *= scale; - } - break; - } - default: - av_log(NULL, AV_LOG_FATAL, - "Audio volume adjustment on sample format %s is not supported.\n", - av_get_sample_fmt_name(ist->st->codec->sample_fmt)); + resample_changed = ist->resample_sample_fmt != decoded_frame->format || + ist->resample_channels != avctx->channels || + ist->resample_channel_layout != decoded_frame->channel_layout || + ist->resample_sample_rate != decoded_frame->sample_rate; + if (resample_changed) { + char layout1[64], layout2[64]; + + if (!guess_input_channel_layout(ist)) { + av_log(NULL, AV_LOG_FATAL, "Unable to find default channel " + "layout for Input Stream #%d.%d\n", ist->file_index, + ist->st->index); exit_program(1); } - } + decoded_frame->channel_layout = avctx->channel_layout; - rate_emu_sleep(ist); + av_get_channel_layout_string(layout1, sizeof(layout1), ist->resample_channels, + ist->resample_channel_layout); + av_get_channel_layout_string(layout2, sizeof(layout2), avctx->channels, + decoded_frame->channel_layout); - for (i = 0; i < nb_output_streams; i++) { - OutputStream *ost = output_streams[i]; + av_log(NULL, AV_LOG_INFO, + "Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d chl:%s to rate:%d fmt:%s ch:%d chl:%s\n", + ist->file_index, ist->st->index, + ist->resample_sample_rate, av_get_sample_fmt_name(ist->resample_sample_fmt), + ist->resample_channels, layout1, + decoded_frame->sample_rate, av_get_sample_fmt_name(decoded_frame->format), + avctx->channels, layout2); - if (!check_output_constraints(ist, ost) || !ost->encoding_needed) - continue; - do_audio_out(output_files[ost->file_index]->ctx, ost, ist, decoded_frame); + ist->resample_sample_fmt = decoded_frame->format; + ist->resample_sample_rate = decoded_frame->sample_rate; + ist->resample_channel_layout = decoded_frame->channel_layout; + ist->resample_channels = avctx->channels; + + for (i = 0; i < nb_filtergraphs; i++) + if (ist_in_filtergraph(filtergraphs[i], ist) && + configure_filtergraph(filtergraphs[i]) < 0) { + av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n"); + exit_program(1); + } } + for (i = 0; i < ist->nb_filters; i++) + av_buffersrc_add_frame(ist->filters[i]->filter, decoded_frame, 0); + return ret; } -static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_t *pkt_pts) +static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output) { AVFrame *decoded_frame; void *buffer_to_free = NULL; int i, ret = 0, resample_changed; - int64_t *best_effort_timestamp; + int64_t best_effort_timestamp; AVRational *frame_sample_aspect; float quality; @@ -2532,9 +2653,7 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int else avcodec_get_frame_defaults(ist->decoded_frame); decoded_frame = ist->decoded_frame; - pkt->pts = *pkt_pts; - pkt->dts = ist->dts; - *pkt_pts = AV_NOPTS_VALUE; + pkt->dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base); update_benchmark(NULL); ret = avcodec_decode_video2(ist->st->codec, @@ -2548,16 +2667,15 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int /* no picture yet */ if (!pkt->size) for (i = 0; i < ist->nb_filters; i++) - av_buffersrc_buffer(ist->filters[i]->filter, NULL); + av_buffersrc_add_ref(ist->filters[i]->filter, NULL, AV_BUFFERSRC_FLAG_NO_COPY); return ret; } - best_effort_timestamp= av_opt_ptr(avcodec_get_frame_class(), decoded_frame, "best_effort_timestamp"); - if(*best_effort_timestamp != AV_NOPTS_VALUE) - ist->next_pts = ist->pts = decoded_frame->pts = *best_effort_timestamp; + best_effort_timestamp= av_frame_get_best_effort_timestamp(decoded_frame); + if(best_effort_timestamp != AV_NOPTS_VALUE) + ist->next_pts = ist->pts = av_rescale_q(decoded_frame->pts = best_effort_timestamp, ist->st->time_base, AV_TIME_BASE_Q); pkt->size = 0; - pre_process_video_frame(ist, (AVPicture *)decoded_frame, &buffer_to_free); rate_emu_sleep(ist); @@ -2610,10 +2728,13 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int fb->buf->priv = buf; fb->buf->free = filter_release_buffer; + av_assert0(buf->refcount>0); buf->refcount++; - av_buffersrc_buffer(ist->filters[i]->filter, fb); + av_buffersrc_add_ref(ist->filters[i]->filter, fb, + AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT | + AV_BUFFERSRC_FLAG_NO_COPY); } else - if(av_vsrc_buffer_add_frame(ist->filters[i]->filter, decoded_frame,AV_VSRC_BUF_FLAG_OVERWRITE)<0) { + if(av_buffersrc_add_frame(ist->filters[i]->filter, decoded_frame, 0)<0) { av_log(NULL, AV_LOG_FATAL, "Failed to inject frame into filter network\n"); exit_program(1); } @@ -2654,9 +2775,17 @@ static int output_packet(InputStream *ist, const AVPacket *pkt) { int ret = 0, i; int got_output; - int64_t pkt_pts = AV_NOPTS_VALUE; AVPacket avpkt; + if (!ist->saw_first_ts) { + ist->dts = ist->st->avg_frame_rate.num ? - ist->st->codec->has_b_frames * AV_TIME_BASE / av_q2d(ist->st->avg_frame_rate) : 0; + ist->pts = 0; + if (pkt != NULL && pkt->pts != AV_NOPTS_VALUE && !ist->decoding_needed) { + ist->dts += av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q); + ist->pts = ist->dts; //unused but better to set it to a value thats not totally wrong + } + ist->saw_first_ts = 1; + } if (ist->next_dts == AV_NOPTS_VALUE) ist->next_dts = ist->dts; @@ -2678,8 +2807,6 @@ static int output_packet(InputStream *ist, const AVPacket *pkt) if (ist->st->codec->codec_type != AVMEDIA_TYPE_VIDEO || !ist->decoding_needed) ist->next_pts = ist->pts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q); } - if(pkt->pts != AV_NOPTS_VALUE) - pkt_pts = av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q); // while we have more to decode or while the decoder did output something on EOF while (ist->decoding_needed && (avpkt.size > 0 || (!pkt && got_output))) { @@ -2697,10 +2824,10 @@ static int output_packet(InputStream *ist, const AVPacket *pkt) switch (ist->st->codec->codec_type) { case AVMEDIA_TYPE_AUDIO: - ret = transcode_audio (ist, &avpkt, &got_output); + ret = decode_audio (ist, &avpkt, &got_output); break; case AVMEDIA_TYPE_VIDEO: - ret = transcode_video (ist, &avpkt, &got_output, &pkt_pts); + ret = decode_video (ist, &avpkt, &got_output); if (avpkt.duration) { duration = av_rescale_q(avpkt.duration, ist->st->time_base, AV_TIME_BASE_Q); } else if(ist->st->codec->time_base.num != 0 && ist->st->codec->time_base.den != 0) { @@ -2798,7 +2925,6 @@ static void print_sdp(void) static int init_input_stream(int ist_index, char *error, int error_len) { - int i; InputStream *ist = input_streams[ist_index]; if (ist->decoding_needed) { @@ -2809,7 +2935,7 @@ static int init_input_stream(int ist_index, char *error, int error_len) return AVERROR(EINVAL); } - ist->dr1 = codec->capabilities & CODEC_CAP_DR1; + ist->dr1 = (codec->capabilities & CODEC_CAP_DR1) && !do_deinterlace; if (codec->type == AVMEDIA_TYPE_VIDEO && ist->dr1) { ist->st->codec->get_buffer = codec_get_buffer; ist->st->codec->release_buffer = codec_release_buffer; @@ -2825,20 +2951,8 @@ static int init_input_stream(int ist_index, char *error, int error_len) } assert_codec_experimental(ist->st->codec, 0); assert_avoptions(ist->opts); - - if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - for (i = 0; i < nb_output_streams; i++) { - OutputStream *ost = output_streams[i]; - if (ost->source_index == ist_index) { - if (!ist->st->codec->channel_layout || !ost->st->codec->channel_layout) - get_default_channel_layouts(ost, ist); - break; - } - } - } } - ist->dts = ist->st->avg_frame_rate.num ? - ist->st->codec->has_b_frames * AV_TIME_BASE / av_q2d(ist->st->avg_frame_rate) : 0; ist->next_pts = AV_NOPTS_VALUE; ist->next_dts = AV_NOPTS_VALUE; ist->is_start = 1; @@ -2916,7 +3030,11 @@ static int transcode_init(void) } if (ost->stream_copy) { - uint64_t extra_size = (uint64_t)icodec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE; + uint64_t extra_size; + + av_assert0(ist && !ost->filter); + + extra_size = (uint64_t)icodec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE; if (extra_size > INT_MAX) { return AVERROR(EINVAL); @@ -2943,6 +3061,7 @@ static int transcode_init(void) } memcpy(codec->extradata, icodec->extradata, icodec->extradata_size); codec->extradata_size= icodec->extradata_size; + codec->bits_per_coded_sample = icodec->bits_per_coded_sample; codec->time_base = ist->st->time_base; /* @@ -2985,6 +3104,10 @@ static int transcode_init(void) codec->frame_size = icodec->frame_size; codec->audio_service_type = icodec->audio_service_type; codec->block_align = icodec->block_align; + if(codec->block_align == 1 && codec->codec_id == CODEC_ID_MP3) + codec->block_align= 0; + if(codec->codec_id == CODEC_ID_AC3) + codec->block_align= 0; break; case AVMEDIA_TYPE_VIDEO: codec->pix_fmt = icodec->pix_fmt; @@ -3025,68 +3148,35 @@ static int transcode_init(void) ist->decoding_needed = 1; ost->encoding_needed = 1; - switch (codec->codec_type) { - case AVMEDIA_TYPE_AUDIO: - ost->fifo = av_fifo_alloc(1024); - if (!ost->fifo) { - return AVERROR(ENOMEM); - } - if (!codec->sample_rate) - codec->sample_rate = icodec->sample_rate; - choose_sample_rate(ost->st, ost->enc); - codec->time_base = (AVRational){ 1, codec->sample_rate }; - - if (codec->sample_fmt == AV_SAMPLE_FMT_NONE) - codec->sample_fmt = icodec->sample_fmt; - choose_sample_fmt(ost->st, ost->enc); - - if (ost->audio_channels_mapped) { - /* the requested output channel is set to the number of - * -map_channel only if no -ac are specified */ - if (!codec->channels) { - codec->channels = ost->audio_channels_mapped; - codec->channel_layout = av_get_default_channel_layout(codec->channels); - if (!codec->channel_layout) { - av_log(NULL, AV_LOG_FATAL, "Unable to find an appropriate channel layout for requested number of channel\n"); - exit_program(1); - } - } - /* fill unused channel mapping with -1 (which means a muted - * channel in case the number of output channels is bigger - * than the number of mapped channel) */ - for (j = ost->audio_channels_mapped; j < FF_ARRAY_ELEMS(ost->audio_channels_map); j++) - ost->audio_channels_map[j] = -1; - } else if (!codec->channels) { - codec->channels = icodec->channels; - codec->channel_layout = icodec->channel_layout; + if (codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (ist && !ost->frame_rate.num) + ost->frame_rate = ist->st->r_frame_rate.num ? ist->st->r_frame_rate : (AVRational){25, 1}; + if (ost->enc && ost->enc->supported_framerates && !ost->force_fps) { + int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates); + ost->frame_rate = ost->enc->supported_framerates[idx]; } - if (av_get_channel_layout_nb_channels(codec->channel_layout) != codec->channels) - codec->channel_layout = 0; - - ost->audio_resample = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1; - ost->audio_resample |= codec->sample_fmt != icodec->sample_fmt - || codec->channel_layout != icodec->channel_layout; - icodec->request_channels = codec->channels; - ost->resample_sample_fmt = icodec->sample_fmt; - ost->resample_sample_rate = icodec->sample_rate; - ost->resample_channels = icodec->channels; - break; - case AVMEDIA_TYPE_VIDEO: - if (!ost->filter) { + } + + if (!ost->filter && + (codec->codec_type == AVMEDIA_TYPE_VIDEO || + codec->codec_type == AVMEDIA_TYPE_AUDIO)) { FilterGraph *fg; fg = init_simple_filtergraph(ist, ost); - if (configure_video_filters(fg)) { + if (configure_simple_filtergraph(fg)) { av_log(NULL, AV_LOG_FATAL, "Error opening filters!\n"); exit(1); } - } + } - if (ist && !ost->frame_rate.num) - ost->frame_rate = ist->st->r_frame_rate.num ? ist->st->r_frame_rate : (AVRational) { 25, 1 }; - if (ost->enc && ost->enc->supported_framerates && !ost->force_fps) { - int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates); - ost->frame_rate = ost->enc->supported_framerates[idx]; - } + switch (codec->codec_type) { + case AVMEDIA_TYPE_AUDIO: + codec->sample_fmt = ost->filter->filter->inputs[0]->format; + codec->sample_rate = ost->filter->filter->inputs[0]->sample_rate; + codec->channel_layout = ost->filter->filter->inputs[0]->channel_layout; + codec->channels = av_get_channel_layout_nb_channels(codec->channel_layout); + codec->time_base = (AVRational){ 1, codec->sample_rate }; + break; + case AVMEDIA_TYPE_VIDEO: codec->time_base = (AVRational){ost->frame_rate.den, ost->frame_rate.num}; if ( av_q2d(codec->time_base) < 0.001 && video_sync_method != VSYNC_PASSTHROUGH && (video_sync_method == VSYNC_CFR || (video_sync_method == VSYNC_AUTO && !(oc->oformat->flags & AVFMT_VARIABLE_FPS)))){ @@ -3136,7 +3226,7 @@ static int transcode_init(void) size_t logbuffer_size; if (cmdutils_read_file(logfilename, &logbuffer, &logbuffer_size) < 0) { av_log(NULL, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n", - logfilename); + logfilename); exit_program(1); } codec->stats_in = logbuffer; @@ -3285,15 +3375,6 @@ static int transcode_init(void) input_streams[ost->source_index]->st->index, ost->file_index, ost->index); - if (ost->audio_channels_mapped) { - av_log(NULL, AV_LOG_INFO, " [ch:"); - for (j = 0; j < ost->audio_channels_mapped; j++) - if (ost->audio_channels_map[j] == -1) - av_log(NULL, AV_LOG_INFO, " M"); - else - av_log(NULL, AV_LOG_INFO, " %d", ost->audio_channels_map[j]); - av_log(NULL, AV_LOG_INFO, "]"); - } if (ost->sync_ist != input_streams[ost->source_index]) av_log(NULL, AV_LOG_INFO, " [sync #%d:%d]", ost->sync_ist->file_index, @@ -3542,8 +3623,9 @@ static int transcode(void) if (debug_ts) { av_log(NULL, AV_LOG_INFO, "demuxer -> ist_index:%d type:%s " - "next_pts:%s next_pts_time:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%"PRId64"\n", + "next_dts:%s next_dts_time:%s next_pts:%s next_pts_time:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%"PRId64"\n", ist_index, av_get_media_type_string(ist->st->codec->codec_type), + av_ts2str(ist->next_dts), av_ts2timestr(ist->next_dts, &ist->st->time_base), av_ts2str(ist->next_pts), av_ts2timestr(ist->next_pts, &ist->st->time_base), av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ist->st->time_base), av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ist->st->time_base), @@ -3587,7 +3669,8 @@ static int transcode(void) } // fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->st->index, pkt.size); - if (output_packet(ist, &pkt) < 0 || poll_filters() < 0) { + if (output_packet(ist, &pkt) < 0 || + ((ret = poll_filters()) < 0 && ret != AVERROR_EOF)) { av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d\n", ist->file_index, ist->st->index); if (exit_on_error) @@ -3657,11 +3740,8 @@ static int transcode(void) fclose(ost->logfile); ost->logfile = NULL; } - av_fifo_free(ost->fifo); /* works even if fifo is not - initialized but set to zero */ av_freep(&ost->st->codec->subtitle_header); av_free(ost->forced_kf_pts); - swr_free(&ost->swr); av_dict_free(&ost->opts); } } @@ -4094,6 +4174,14 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) break; case AVMEDIA_TYPE_AUDIO: + guess_input_channel_layout(ist); + + ist->resample_sample_fmt = dec->sample_fmt; + ist->resample_sample_rate = dec->sample_rate; + ist->resample_channels = dec->channels; + ist->resample_channel_layout = dec->channel_layout; + + break; case AVMEDIA_TYPE_DATA: case AVMEDIA_TYPE_SUBTITLE: if(!ist->dec) @@ -4316,9 +4404,12 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost) av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n"); exit_program(1); } + p = kf; for (i = 0; i < n; i++) { - p = i ? strchr(p, ',') + 1 : kf; + char *next = strchr(p, ','); + if (next) *next++ = 0; ost->forced_kf_pts[i] = parse_time_or_die("force_key_frames", p, 1); + p = next; } } @@ -4494,8 +4585,6 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e input_streams[source_index]->st->discard = AVDISCARD_NONE; } - ost->pix_fmts[0] = ost->pix_fmts[1] = PIX_FMT_NONE; - return ost; } @@ -4558,6 +4647,11 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in video_enc->bits_per_raw_sample = frame_bits_per_raw_sample; MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st); + if (frame_pix_fmt && *frame_pix_fmt == '+') { + ost->keep_pix_fmt = 1; + if (!*++frame_pix_fmt) + frame_pix_fmt = NULL; + } if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == PIX_FMT_NONE) { av_log(NULL, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", frame_pix_fmt); exit_program(1); @@ -4659,7 +4753,7 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, in audio_enc->codec_type = AVMEDIA_TYPE_AUDIO; if (!ost->stream_copy) { - char *sample_fmt = NULL; + char *sample_fmt = NULL, *filters = NULL; MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st); @@ -4672,22 +4766,23 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, in MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st); - ost->rematrix_volume=1.0; - MATCH_PER_STREAM_OPT(rematrix_volume, f, ost->rematrix_volume, oc, st); - } + MATCH_PER_STREAM_OPT(filters, str, filters, oc, st); + if (filters) + ost->avfilter = av_strdup(filters); - /* check for channel mapping for this audio stream */ - for (n = 0; n < o->nb_audio_channel_maps; n++) { - AudioChannelMap *map = &o->audio_channel_maps[n]; - InputStream *ist = input_streams[ost->source_index]; - if ((map->channel_idx == -1 || (ist->file_index == map->file_idx && ist->st->index == map->stream_idx)) && - (map->ofile_idx == -1 || ost->file_index == map->ofile_idx) && - (map->ostream_idx == -1 || ost->st->index == map->ostream_idx)) { - if (ost->audio_channels_mapped < FF_ARRAY_ELEMS(ost->audio_channels_map)) - ost->audio_channels_map[ost->audio_channels_mapped++] = map->channel_idx; - else - av_log(NULL, AV_LOG_FATAL, "Max channel mapping for output %d.%d reached\n", - ost->file_index, ost->st->index); + /* check for channel mapping for this audio stream */ + for (n = 0; n < o->nb_audio_channel_maps; n++) { + AudioChannelMap *map = &o->audio_channel_maps[n]; + InputStream *ist = input_streams[ost->source_index]; + if ((map->channel_idx == -1 || (ist->file_index == map->file_idx && ist->st->index == map->stream_idx)) && + (map->ofile_idx == -1 || ost->file_index == map->ofile_idx) && + (map->ostream_idx == -1 || ost->st->index == map->ostream_idx)) { + if (ost->audio_channels_mapped < FF_ARRAY_ELEMS(ost->audio_channels_map)) + ost->audio_channels_map[ost->audio_channels_mapped++] = map->channel_idx; + else + av_log(NULL, AV_LOG_FATAL, "Max channel mapping for output %d.%d reached\n", + ost->file_index, ost->st->index); + } } } @@ -4838,17 +4933,27 @@ static void init_output_filter(OutputFilter *ofilter, OptionsContext *o, { OutputStream *ost; - if (ofilter->out_tmp->filter_ctx->output_pads[ofilter->out_tmp->pad_idx].type != AVMEDIA_TYPE_VIDEO) { - av_log(NULL, AV_LOG_FATAL, "Only video filters are supported currently.\n"); + switch (ofilter->out_tmp->filter_ctx->output_pads[ofilter->out_tmp->pad_idx].type) { + case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc, -1); break; + case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc, -1); break; + default: + av_log(NULL, AV_LOG_FATAL, "Only video and audio filters are supported " + "currently.\n"); exit_program(1); } - ost = new_video_stream(o, oc, -1); ost->source_index = -1; ost->filter = ofilter; ofilter->ost = ost; + if (ost->stream_copy) { + av_log(NULL, AV_LOG_ERROR, "Streamcopy requested for output stream %d:%d, " + "which is fed from a complex filtergraph. Filtering and streamcopy " + "cannot be used together.\n", ost->file_index, ost->index); + exit_program(1); + } + if (configure_output_filter(ofilter->graph, ofilter, ofilter->out_tmp) < 0) { av_log(NULL, AV_LOG_FATAL, "Error configuring filter.\n"); exit_program(1); @@ -5017,7 +5122,7 @@ loop_end: case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc, src_idx); break; default: av_log(NULL, AV_LOG_FATAL, "Cannot map stream #%d:%d - unsupported type.\n", - map->file_index, map->stream_index); + map->file_index, map->stream_index); exit_program(1); } } @@ -5455,7 +5560,7 @@ static int opt_data_frames(OptionsContext *o, const char *opt, const char *arg) static int opt_preset(OptionsContext *o, const char *opt, const char *arg) { FILE *f=NULL; - char filename[1000], tmp[1000], tmp2[1000], line[1000]; + char filename[1000], line[1000], tmp_line[1000]; const char *codec_name = *opt == 'v' ? video_codec_name : *opt == 'a' ? audio_codec_name : subtitle_codec_name; @@ -5468,25 +5573,26 @@ static int opt_preset(OptionsContext *o, const char *opt, const char *arg) exit_program(1); } - while(!feof(f)){ - int e= fscanf(f, "%999[^\n]\n", line) - 1; - if(line[0] == '#' && !e) + while (fgets(line, sizeof(line), f)) { + char *key = tmp_line, *value, *endptr; + + if (strcspn(line, "#\n\r") == 0) continue; - e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2; - if(e){ + strcpy(tmp_line, line); + if (!av_strtok(key, "=", &value) || + !av_strtok(value, "\r\n", &endptr)) { av_log(NULL, AV_LOG_FATAL, "%s: Invalid syntax: '%s'\n", filename, line); exit_program(1); } - if(!strcmp(tmp, "acodec")){ - opt_audio_codec(o, tmp, tmp2); - }else if(!strcmp(tmp, "vcodec")){ - opt_video_codec(o, tmp, tmp2); - }else if(!strcmp(tmp, "scodec")){ - opt_subtitle_codec(o, tmp, tmp2); - }else if(!strcmp(tmp, "dcodec")){ - opt_data_codec(o, tmp, tmp2); - }else if(opt_default(tmp, tmp2) < 0){ - av_log(NULL, AV_LOG_FATAL, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2); + av_log(NULL, AV_LOG_DEBUG, "ffpreset[%s]: set '%s' = '%s'\n", filename, key, value); + + if (!strcmp(key, "acodec")) opt_audio_codec (o, key, value); + else if (!strcmp(key, "vcodec")) opt_video_codec (o, key, value); + else if (!strcmp(key, "scodec")) opt_subtitle_codec(o, key, value); + else if (!strcmp(key, "dcodec")) opt_data_codec (o, key, value); + else if (opt_default(key, value) < 0) { + av_log(NULL, AV_LOG_FATAL, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", + filename, line, key, value); exit_program(1); } } @@ -5555,6 +5661,11 @@ static int opt_video_filters(OptionsContext *o, const char *opt, const char *arg return parse_option(o, "filter:v", arg, options); } +static int opt_audio_filters(OptionsContext *o, const char *opt, const char *arg) +{ + return parse_option(o, "filter:a", arg, options); +} + static int opt_vsync(const char *opt, const char *arg) { if (!av_strcasecmp(arg, "cfr")) video_sync_method = VSYNC_CFR; @@ -5737,8 +5848,8 @@ static const OptionDef options[] = { { "atag", HAS_ARG | OPT_EXPERT | OPT_AUDIO | OPT_FUNC2, {(void*)opt_old2new}, "force audio tag/fourcc", "fourcc/tag" }, { "vol", OPT_INT | HAS_ARG | OPT_AUDIO, {(void*)&audio_volume}, "change audio volume (256=normal)" , "volume" }, // { "sample_fmt", HAS_ARG | OPT_EXPERT | OPT_AUDIO | OPT_SPEC | OPT_STRING, {.off = OFFSET(sample_fmts)}, "set sample format", "format" }, - { "rmvol", HAS_ARG | OPT_AUDIO | OPT_FLOAT | OPT_SPEC, {.off = OFFSET(rematrix_volume)}, "rematrix volume (as factor)", "volume" }, { "channel_layout", HAS_ARG | OPT_EXPERT | OPT_AUDIO | OPT_FUNC2, {(void*)opt_channel_layout}, "set channel layout", "layout" }, + { "af", HAS_ARG | OPT_AUDIO | OPT_FUNC2, {(void*)opt_audio_filters}, "audio filters", "filter list" }, /* subtitle options */ { "sn", OPT_BOOL | OPT_SUBTITLE | OPT_OFFSET, {.off = OFFSET(subtitle_disable)}, "disable subtitle" },