X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffmpeg.c;h=aa16e05f7e087fec4e120c347855b3a04327765e;hb=e377208d43d95d024cf1af3110036366ed4379c9;hp=c6297a1a1ca744cde0b3f9186f7adc08dc5ed227;hpb=d187e7616e32353e31c046cd095b19c96073bcad;p=ffmpeg diff --git a/ffmpeg.c b/ffmpeg.c index c6297a1a1ca..aa16e05f7e0 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -31,7 +31,9 @@ #include #include #include +#if HAVE_ISATTY #include +#endif #include "libavformat/avformat.h" #include "libavdevice/avdevice.h" #include "libswscale/swscale.h" @@ -51,6 +53,7 @@ #include "libavutil/imgutils.h" #include "libavutil/timestamp.h" #include "libavutil/bprint.h" +#include "libavutil/time.h" #include "libavformat/os_support.h" #include "libavformat/ffm.h" // not public API @@ -63,7 +66,6 @@ #if HAVE_SYS_RESOURCE_H #include -#include #include #elif HAVE_GETPROCESSTIMES #include @@ -85,6 +87,11 @@ #elif HAVE_KBHIT #include #endif + +#if HAVE_PTHREADS +#include +#endif + #include #include "cmdutils.h" @@ -97,8 +104,6 @@ #define VSYNC_VFR 2 #define VSYNC_DROP 0xff -#define SINKA - const char program_name[] = "ffmpeg"; const int program_birth_year = 2000; @@ -158,6 +163,7 @@ static int run_as_daemon = 0; static volatile int received_nb_signals = 0; static int64_t video_size = 0; static int64_t audio_size = 0; +static int64_t subtitle_size = 0; static int64_t extra_size = 0; static int nb_frames_dup = 0; static int nb_frames_drop = 0; @@ -170,18 +176,25 @@ static int print_stats = 1; static int debug_ts = 0; static int current_time; +#if HAVE_PTHREADS +/* signal to input threads that they should exit; set by the main thread */ +static int transcoding_finished; +#endif + #define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass" typedef struct InputFilter { AVFilterContext *filter; struct InputStream *ist; struct FilterGraph *graph; + uint8_t *name; } InputFilter; typedef struct OutputFilter { AVFilterContext *filter; struct OutputStream *ost; struct FilterGraph *graph; + uint8_t *name; /* temporary storage until stream maps are processed */ AVFilterInOut *out_tmp; @@ -199,19 +212,6 @@ typedef struct FilterGraph { int nb_outputs; } FilterGraph; -typedef struct FrameBuffer { - uint8_t *base[4]; - uint8_t *data[4]; - int linesize[4]; - - int h, w; - enum PixelFormat pix_fmt; - - int refcount; - struct InputStream *ist; - struct FrameBuffer *next; -} FrameBuffer; - typedef struct InputStream { int file_index; AVStream *st; @@ -234,6 +234,8 @@ typedef struct InputStream { int saw_first_ts; int showed_multi_packet_warning; AVDictionary *opts; + AVRational framerate; /* framerate forced with -r */ + int top_field_first; int resample_height; int resample_width; @@ -258,11 +260,19 @@ typedef struct InputFile { AVFormatContext *ctx; int eof_reached; /* true if eof reached */ int ist_index; /* index of first stream in input_streams */ - int buffer_size; /* current total buffer size */ int64_t ts_offset; int nb_streams; /* number of stream that ffmpeg is aware of; may be different from ctx.nb_streams if new streams appear during av_read_frame() */ int rate_emu; + +#if HAVE_PTHREADS + pthread_t thread; /* thread reading from this file */ + int finished; /* the thread has exited */ + int joined; /* the thread has been joined */ + pthread_mutex_t fifo_lock; /* lock for access to fifo */ + pthread_cond_t fifo_cond; /* the main thread will signal on this cond after reading from fifo */ + AVFifoBuffer *fifo; /* demuxed packets are stored here; freed by the main thread */ +#endif } InputFile; typedef struct OutputStream { @@ -296,6 +306,7 @@ typedef struct OutputStream { int64_t *forced_kf_pts; int forced_kf_count; int forced_kf_index; + char *forced_keyframes; /* audio only */ int audio_channels_map[SWR_CH_MAX]; /* list of the channels id to pick from the source stream */ @@ -530,145 +541,6 @@ static void reset_options(OptionsContext *o, int is_input) init_opts(); } -static int alloc_buffer(InputStream *ist, AVCodecContext *s, FrameBuffer **pbuf) -{ - FrameBuffer *buf = av_mallocz(sizeof(*buf)); - int i, ret; - const int pixel_size = av_pix_fmt_descriptors[s->pix_fmt].comp[0].step_minus1+1; - int h_chroma_shift, v_chroma_shift; - int edge = 32; // XXX should be avcodec_get_edge_width(), but that fails on svq1 - int w = s->width, h = s->height; - - if (!buf) - return AVERROR(ENOMEM); - - avcodec_align_dimensions(s, &w, &h); - - if (!(s->flags & CODEC_FLAG_EMU_EDGE)) { - w += 2*edge; - h += 2*edge; - } - - if ((ret = av_image_alloc(buf->base, buf->linesize, w, h, - s->pix_fmt, 32)) < 0) { - av_freep(&buf); - return ret; - } - /* XXX this shouldn't be needed, but some tests break without this line - * those decoders are buggy and need to be fixed. - * the following tests fail: - * cdgraphics, ansi, aasc, fraps-v1, qtrle-1bit - */ - memset(buf->base[0], 128, ret); - - avcodec_get_chroma_sub_sample(s->pix_fmt, &h_chroma_shift, &v_chroma_shift); - 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] || !buf->base[i]) - buf->data[i] = buf->base[i]; - else - buf->data[i] = buf->base[i] + - FFALIGN((buf->linesize[i]*edge >> v_shift) + - (pixel_size*edge >> h_shift), 32); - } - buf->w = s->width; - buf->h = s->height; - buf->pix_fmt = s->pix_fmt; - buf->ist = ist; - - *pbuf = buf; - return 0; -} - -static void free_buffer_pool(InputStream *ist) -{ - FrameBuffer *buf = ist->buffer_pool; - while (buf) { - ist->buffer_pool = buf->next; - av_freep(&buf->base[0]); - av_free(buf); - buf = ist->buffer_pool; - } -} - -static void unref_buffer(InputStream *ist, FrameBuffer *buf) -{ - 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; - } -} - -static int codec_get_buffer(AVCodecContext *s, AVFrame *frame) -{ - InputStream *ist = s->opaque; - FrameBuffer *buf; - int ret, i; - - if(av_image_check_size(s->width, s->height, 0, s) || s->pix_fmt<0) - return -1; - - if (!ist->buffer_pool && (ret = alloc_buffer(ist, s, &ist->buffer_pool)) < 0) - return ret; - - buf = ist->buffer_pool; - ist->buffer_pool = buf->next; - buf->next = NULL; - if (buf->w != s->width || buf->h != s->height || buf->pix_fmt != s->pix_fmt) { - av_freep(&buf->base[0]); - av_free(buf); - if ((ret = alloc_buffer(ist, s, &buf)) < 0) - return ret; - } - av_assert0(!buf->refcount); - buf->refcount++; - - frame->opaque = buf; - frame->type = FF_BUFFER_TYPE_USER; - frame->extended_data = frame->data; - frame->pkt_pts = s->pkt ? s->pkt->pts : AV_NOPTS_VALUE; - frame->width = buf->w; - frame->height = buf->h; - frame->format = buf->pix_fmt; - frame->sample_aspect_ratio = s->sample_aspect_ratio; - - for (i = 0; i < FF_ARRAY_ELEMS(buf->data); i++) { - frame->base[i] = buf->base[i]; // XXX h264.c uses base though it shouldn't - frame->data[i] = buf->data[i]; - frame->linesize[i] = buf->linesize[i]; - } - - return 0; -} - -static void codec_release_buffer(AVCodecContext *s, AVFrame *frame) -{ - InputStream *ist = s->opaque; - FrameBuffer *buf = frame->opaque; - int i; - - if(frame->type!=FF_BUFFER_TYPE_USER) - return avcodec_default_release_buffer(s, frame); - - for (i = 0; i < FF_ARRAY_ELEMS(frame->data); i++) - frame->data[i] = NULL; - - unref_buffer(ist, buf); -} - -static void filter_release_buffer(AVFilterBuffer *fb) -{ - FrameBuffer *buf = fb->priv; - av_free(fb); - unref_buffer(buf->ist, buf); -} - static enum PixelFormat choose_pixel_fmt(AVStream *st, AVCodec *codec, enum PixelFormat target) { if (codec && codec->pix_fmts) { @@ -799,267 +671,6 @@ DEF_CHOOSE_FORMAT(int, sample_rate, supported_samplerates, 0, 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; - } - -#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 (audio_sync_method > 0) { - 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); - AUTO_INSERT_FILTER("-async", "aresample", args); - } - - 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), "%f", 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 *filter; - AVCodecContext *codec = ost->st->codec; - AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc(); - char *pix_fmts; - AVRational sample_aspect_ratio; - char args[255]; - int ret; - - 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, - 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"), - "src", args, NULL, fg->graph); - if (ret < 0) - return ret; - -#if FF_API_OLD_VSINK_API - ret = avfilter_graph_create_filter(&fg->outputs[0]->filter, - avfilter_get_by_name("buffersink"), - "out", NULL, NULL, fg->graph); -#else - 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; - *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", - codec->width, - codec->height, - (unsigned)ost->sws_flags); - if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), - NULL, args, NULL, fg->graph)) < 0) - return ret; - if ((ret = avfilter_link(*in_filter, 0, filter, 0)) < 0) - return ret; - *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 = in_filter; - outputs->pad_idx = 0; - outputs->next = NULL; - - inputs->name = av_strdup("out"); - inputs->filter_ctx = out_filter; - inputs->pad_idx = 0; - inputs->next = NULL; - - if ((ret = avfilter_graph_parse(fg->graph, ost->avfilter, &inputs, &outputs, NULL)) < 0) - return ret; - av_freep(&ost->avfilter); - } else { - 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; - - ost->filter = fg->outputs[0]; - - return 0; -} - static FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost) { FilterGraph *fg = av_mallocz(sizeof(*fg)); @@ -1075,6 +686,8 @@ static FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost) fg->outputs[0]->ost = ost; fg->outputs[0]->graph = fg; + ost->filter = fg->outputs[0]; + fg->inputs = grow_array(fg->inputs, sizeof(*fg->inputs), &fg->nb_inputs, fg->nb_inputs + 1); if (!(fg->inputs[0] = av_mallocz(sizeof(*fg->inputs[0])))) @@ -1096,7 +709,7 @@ static FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost) static void init_input_filter(FilterGraph *fg, AVFilterInOut *in) { InputStream *ist = NULL; - enum AVMediaType type = in->filter_ctx->input_pads[in->pad_idx].type; + enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx); int i; // TODO: support other filter types @@ -1142,11 +755,13 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in) } if (i == nb_input_streams) { av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for " - "unlabeled input pad %d on filter %s", in->pad_idx, + "unlabeled input pad %d on filter %s\n", in->pad_idx, in->filter_ctx->name); exit_program(1); } } + av_assert0(ist); + ist->discard = 0; ist->decoding_needed = 1; ist->st->discard = AVDISCARD_NONE; @@ -1166,21 +781,18 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in) static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) { char *pix_fmts; - AVCodecContext *codec = ofilter->ost->st->codec; + OutputStream *ost = ofilter->ost; + AVCodecContext *codec = ost->st->codec; AVFilterContext *last_filter = out->filter_ctx; int pad_idx = out->pad_idx; int ret; + char name[255]; 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, NULL, fg->graph); -#else + snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index); ret = avfilter_graph_create_filter(&ofilter->filter, avfilter_get_by_name("buffersink"), - "out", NULL, buffersink_params, fg->graph); -#endif + name, NULL, NULL/*buffersink_params*/, fg->graph); av_freep(&buffersink_params); if (ret < 0) @@ -1193,9 +805,11 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, snprintf(args, sizeof(args), "%d:%d:flags=0x%X", codec->width, codec->height, - (unsigned)ofilter->ost->sws_flags); + (unsigned)ost->sws_flags); + snprintf(name, sizeof(name), "scaler for output stream %d:%d", + ost->file_index, ost->index); if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), - NULL, args, NULL, fg->graph)) < 0) + name, args, NULL, fg->graph)) < 0) return ret; if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0) return ret; @@ -1204,8 +818,10 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, pad_idx = 0; } - if ((pix_fmts = choose_pix_fmts(ofilter->ost))) { + if ((pix_fmts = choose_pix_fmts(ost))) { AVFilterContext *filter; + snprintf(name, sizeof(name), "pixel format for output stream %d:%d", + ost->file_index, ost->index); if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("format"), "format", pix_fmts, NULL, @@ -1219,6 +835,26 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, av_freep(&pix_fmts); } + if (ost->frame_rate.num && 0) { + AVFilterContext *fps; + char args[255]; + + snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num, + ost->frame_rate.den); + snprintf(name, sizeof(name), "fps for output stream %d:%d", + ost->file_index, ost->index); + ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"), + name, args, NULL, fg->graph); + if (ret < 0) + return ret; + + ret = avfilter_link(last_filter, pad_idx, fps, 0); + if (ret < 0) + return ret; + last_filter = fps; + pad_idx = 0; + } + if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) return ret; @@ -1232,14 +868,50 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterContext *last_filter = out->filter_ctx; int pad_idx = out->pad_idx; char *sample_fmts, *sample_rates, *channel_layouts; + char name[255]; int ret; + + snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index); ret = avfilter_graph_create_filter(&ofilter->filter, - avfilter_get_by_name("abuffersink"), - "out", NULL, NULL, fg->graph); + avfilter_get_by_name("abuffersink_old"), + name, NULL, NULL, fg->graph); if (ret < 0) return ret; +#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(last_filter, pad_idx, filt_ctx, 0); \ + if (ret < 0) \ + return ret; \ + \ + last_filter = filt_ctx; \ + pad_idx = 0; \ +} 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 (codec->channels && !codec->channel_layout) codec->channel_layout = av_get_default_channel_layout(codec->channels); @@ -1266,9 +938,11 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, av_freep(&sample_rates); av_freep(&channel_layouts); + snprintf(name, sizeof(name), "audio format for output stream %d:%d", + ost->file_index, ost->index); ret = avfilter_graph_create_filter(&format, avfilter_get_by_name("aformat"), - "aformat", args, NULL, fg->graph); + name, args, NULL, fg->graph); if (ret < 0) return ret; @@ -1280,106 +954,237 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, pad_idx = 0; } + if (audio_volume != 256 && 0) { + char args[256]; + + snprintf(args, sizeof(args), "%f", audio_volume / 256.); + AUTO_INSERT_FILTER("-vol", "volume", args); + } + + if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) + return ret; + + return 0; +} + +#define DESCRIBE_FILTER_LINK(f, inout, in) \ +{ \ + AVFilterContext *ctx = inout->filter_ctx; \ + AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads; \ + int nb_pads = in ? ctx->input_count : ctx->output_count; \ + AVIOContext *pb; \ + \ + if (avio_open_dyn_buf(&pb) < 0) \ + exit_program(1); \ + \ + avio_printf(pb, "%s", ctx->filter->name); \ + if (nb_pads > 1) \ + avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));\ + avio_w8(pb, 0); \ + avio_close_dyn_buf(pb, &f->name); \ +} + +static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) +{ + av_freep(&ofilter->name); + DESCRIBE_FILTER_LINK(ofilter, out, 0); + + switch (avfilter_pad_get_type(out->filter_ctx->output_pads, out->pad_idx)) { + 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_input_video_filter(FilterGraph *fg, InputFilter *ifilter, + AVFilterInOut *in) +{ + AVFilterContext *first_filter = in->filter_ctx; + AVFilter *filter = avfilter_get_by_name("buffer"); + InputStream *ist = ifilter->ist; + AVRational tb = ist->framerate.num ? (AVRational){ist->framerate.den, + ist->framerate.num} : + ist->st->time_base; + AVRational fr = ist->framerate.num ? ist->framerate : + ist->st->r_frame_rate; + AVRational sar; + AVBPrint args; + char name[255]; + int pad_idx = in->pad_idx; + int ret; + + sar = ist->st->sample_aspect_ratio.num ? + ist->st->sample_aspect_ratio : + ist->st->codec->sample_aspect_ratio; + if(!sar.den) + sar = (AVRational){0,1}; + av_bprint_init(&args, 0, 1); + av_bprintf(&args, + "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:" + "pixel_aspect=%d/%d:sws_param=flags=%d", ist->st->codec->width, + ist->st->codec->height, ist->st->codec->pix_fmt, + tb.num, tb.den, sar.num, sar.den, + SWS_BILINEAR + ((ist->st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0)); + if (fr.num && fr.den) + av_bprintf(&args, ":frame_rate=%d/%d", fr.num, fr.den); + snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index, + ist->file_index, ist->st->index); + + if ((ret = avfilter_graph_create_filter(&ifilter->filter, filter, name, + args.str, NULL, fg->graph)) < 0) + return ret; + + if (ist->framerate.num) { + AVFilterContext *setpts; + + snprintf(name, sizeof(name), "force CFR for input from stream %d:%d", + ist->file_index, ist->st->index); + if ((ret = avfilter_graph_create_filter(&setpts, + avfilter_get_by_name("setpts"), + name, "N", NULL, + fg->graph)) < 0) + return ret; + + if ((ret = avfilter_link(setpts, 0, first_filter, pad_idx)) < 0) + return ret; + + first_filter = setpts; + pad_idx = 0; + } + + if ((ret = avfilter_link(ifilter->filter, 0, first_filter, pad_idx)) < 0) + return ret; + return 0; +} + +static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter, + AVFilterInOut *in) +{ + AVFilterContext *first_filter = in->filter_ctx; + AVFilter *filter = avfilter_get_by_name("abuffer"); + InputStream *ist = ifilter->ist; + int pad_idx = in->pad_idx; + char args[255], name[255]; + int ret; + + 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); + snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index, + ist->file_index, ist->st->index); + + if ((ret = avfilter_graph_create_filter(&ifilter->filter, filter, + name, args, NULL, + fg->graph)) < 0) + return ret; + +#define AUTO_INSERT_FILTER_INPUT(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); \ + \ + snprintf(name, sizeof(name), "graph %d %s for input stream %d:%d", \ + fg->index, filter_name, ist->file_index, ist->st->index); \ + ret = avfilter_graph_create_filter(&filt_ctx, \ + avfilter_get_by_name(filter_name), \ + name, arg, NULL, fg->graph); \ + if (ret < 0) \ + return ret; \ + \ + ret = avfilter_link(filt_ctx, 0, first_filter, pad_idx); \ + if (ret < 0) \ + return ret; \ + \ + first_filter = filt_ctx; \ +} while (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"); + 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) - 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; + av_strlcatf(args, sizeof(args), ":max_soft_comp=%f", audio_sync_method/(double)ist->st->codec->sample_rate); + AUTO_INSERT_FILTER_INPUT("-async", "aresample", args); + } + +// 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_INPUT("-map_channel", "pan", pan_buf.str); +// av_bprint_finalize(&pan_buf, NULL); +// } - ret = avfilter_link(last_filter, pad_idx, async, 0); - if (ret < 0) - return ret; + if (audio_volume != 256) { + char args[256]; - last_filter = async; - pad_idx = 0; + snprintf(args, sizeof(args), "%f", audio_volume / 256.); + AUTO_INSERT_FILTER_INPUT("-vol", "volume", args); } - - if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) + if ((ret = avfilter_link(ifilter->filter, 0, first_filter, pad_idx)) < 0) return ret; return 0; } -static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) +static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter, + AVFilterInOut *in) { - 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); + av_freep(&ifilter->name); + DESCRIBE_FILTER_LINK(ifilter, in, 1); + + switch (avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx)) { + case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in); + case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in); default: av_assert0(0); } } -static int configure_complex_filter(FilterGraph *fg) +static int configure_filtergraph(FilterGraph *fg) { AVFilterInOut *inputs, *outputs, *cur; - int ret, i, init = !fg->graph; + int ret, i, init = !fg->graph, simple = !fg->graph_desc; + const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter : + fg->graph_desc; avfilter_graph_free(&fg->graph); if (!(fg->graph = avfilter_graph_alloc())) return AVERROR(ENOMEM); - if ((ret = avfilter_graph_parse2(fg->graph, fg->graph_desc, &inputs, &outputs)) < 0) - return ret; + if (simple) { + OutputStream *ost = fg->outputs[0]->ost; + char args[255]; + snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags); + fg->graph->scale_sws_opts = av_strdup(args); + } - for (cur = inputs; init && cur; cur = cur->next) - init_input_filter(fg, cur); + if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0) + return ret; - for (cur = inputs, i = 0; cur; cur = cur->next, i++) { - InputFilter *ifilter = fg->inputs[i]; - InputStream *ist = ifilter->ist; - AVRational sar; - AVFilter *filter; - char args[255]; + if (simple && (!inputs || inputs->next || !outputs || outputs->next)) { + av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' does not have " + "exactly one input and output.\n", graph_desc); + return AVERROR(EINVAL); + } - 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); - } + for (cur = inputs; !simple && init && cur; cur = cur->next) + init_input_filter(fg, cur); - if ((ret = avfilter_graph_create_filter(&ifilter->filter, - filter, cur->name, - args, NULL, fg->graph)) < 0) + for (cur = inputs, i = 0; cur; cur = cur->next, i++) + if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0) return ret; - if ((ret = avfilter_link(ifilter->filter, 0, - cur->filter_ctx, cur->pad_idx)) < 0) - return ret; - } avfilter_inout_free(&inputs); - if (!init) { + if (!init || simple) { /* we already know the mappings between lavfi outputs and output streams, * so we can finish the setup */ for (cur = outputs, i = 0; cur; cur = cur->next, i++) @@ -1411,17 +1216,11 @@ static int configure_complex_filters(void) for (i = 0; i < nb_filtergraphs; i++) if (!filtergraphs[i]->graph && - (ret = configure_complex_filter(filtergraphs[i])) < 0) + (ret = configure_filtergraph(filtergraphs[i])) < 0) return ret; return 0; } -static int configure_filtergraph(FilterGraph *fg) -{ - return fg->graph_desc ? configure_complex_filter(fg) : - configure_simple_filtergraph(fg); -} - static int ist_in_filtergraph(FilterGraph *fg, InputStream *ist) { int i; @@ -1456,8 +1255,11 @@ static void term_init(void) #if HAVE_TERMIOS_H if(!run_as_daemon){ struct termios tty; - - if (tcgetattr (0, &tty) == 0) { + int istty = 1; +#if HAVE_ISATTY + istty = isatty(0) && isatty(2); +#endif + if (istty && tcgetattr (0, &tty) == 0) { oldtty = tty; restore_tty = 1; atexit(term_exit); @@ -1552,11 +1354,15 @@ void av_noreturn exit_program(int ret) for (i = 0; i < nb_filtergraphs; i++) { avfilter_graph_free(&filtergraphs[i]->graph); - for (j = 0; j < filtergraphs[i]->nb_inputs; j++) + for (j = 0; j < filtergraphs[i]->nb_inputs; j++) { + av_freep(&filtergraphs[i]->inputs[j]->name); av_freep(&filtergraphs[i]->inputs[j]); + } av_freep(&filtergraphs[i]->inputs); - for (j = 0; j < filtergraphs[i]->nb_outputs; j++) + for (j = 0; j < filtergraphs[i]->nb_outputs; j++) { + av_freep(&filtergraphs[i]->outputs[j]->name); av_freep(&filtergraphs[i]->outputs[j]); + } av_freep(&filtergraphs[i]->outputs); av_freep(&filtergraphs[i]); } @@ -1580,7 +1386,9 @@ void av_noreturn exit_program(int ret) } output_streams[i]->bitstream_filters = NULL; + av_freep(&output_streams[i]->forced_keyframes); av_freep(&output_streams[i]->filtered_frame); + av_freep(&output_streams[i]->avfilter); av_freep(&output_streams[i]); } for (i = 0; i < nb_input_files; i++) { @@ -1590,7 +1398,7 @@ void av_noreturn exit_program(int ret) for (i = 0; i < nb_input_streams; i++) { av_freep(&input_streams[i]->decoded_frame); av_dict_free(&input_streams[i]->opts); - free_buffer_pool(input_streams[i]); + free_buffer_pool(&input_streams[i]->buffer_pool); av_freep(&input_streams[i]->filters); av_freep(&input_streams[i]); } @@ -1881,6 +1689,7 @@ static void do_subtitle_out(AVFormatContext *s, pkt.data = subtitle_out; pkt.size = subtitle_out_size; pkt.pts = av_rescale_q(sub->pts, AV_TIME_BASE_Q, ost->st->time_base); + pkt.duration = av_rescale_q(sub->end_display_time, (AVRational){ 1, 1000 }, ost->st->time_base); if (enc->codec_id == CODEC_ID_DVB_SUBTITLE) { /* XXX: the pts correction is handled here. Maybe handling it in the codec would be better */ @@ -1890,6 +1699,7 @@ static void do_subtitle_out(AVFormatContext *s, pkt.pts += 90 * sub->end_display_time; } write_frame(s, &pkt, ost); + subtitle_size += pkt.size; } } @@ -1901,7 +1711,7 @@ static void do_video_out(AVFormatContext *s, int ret, format_video_sync; AVPacket pkt; AVCodecContext *enc = ost->st->codec; - int nb_frames, i; + int nb_frames; double sync_ipts, delta; double duration = 0; int frame_size = 0; @@ -1976,6 +1786,7 @@ duplicate_frame: pkt.flags |= AV_PKT_FLAG_KEY; write_frame(s, &pkt, ost); + video_size += pkt.size; } else { int got_packet; AVFrame big_picture; @@ -2109,7 +1920,7 @@ static int poll_filters(void) OutputFile *of = output_files[ost->file_index]; int ret = 0; - if (!ost->filter || ost->is_past_recording_time) + if (!ost->filter) continue; if (!ost->filtered_frame && !(ost->filtered_frame = avcodec_alloc_frame())) { @@ -2118,19 +1929,16 @@ static int poll_filters(void) 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; + while (!ost->is_past_recording_time) { 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 + else if(ost->enc->type == AVMEDIA_TYPE_AUDIO) ret = av_buffersink_read(ost->filter->filter, &picref); -#else + 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]; @@ -2160,7 +1968,7 @@ static int poll_filters(void) switch (ost->filter->filter->inputs[0]->type) { case AVMEDIA_TYPE_VIDEO: - avfilter_fill_frame_from_video_buffer_ref(filtered_frame, picref); + avfilter_copy_buf_props(filtered_frame, picref); filtered_frame->pts = frame_pts; if (!ost->frame_aspect_ratio) ost->st->codec->sample_aspect_ratio = picref->video->sample_aspect_ratio; @@ -2325,15 +2133,16 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti fflush(stderr); if (is_last_report) { - int64_t raw= audio_size + video_size + extra_size; + int64_t raw= audio_size + video_size + subtitle_size + extra_size; av_log(NULL, AV_LOG_INFO, "\n"); - av_log(NULL, AV_LOG_INFO, "video:%1.0fkB audio:%1.0fkB global headers:%1.0fkB muxing overhead %f%%\n", + av_log(NULL, AV_LOG_INFO, "video:%1.0fkB audio:%1.0fkB subtitle:%1.0f global headers:%1.0fkB muxing overhead %f%%\n", video_size / 1024.0, audio_size / 1024.0, + subtitle_size / 1024.0, extra_size / 1024.0, 100.0 * (total_size - raw) / raw ); - if(video_size + audio_size + extra_size == 0){ + if(video_size + audio_size + subtitle_size + extra_size == 0){ av_log(NULL, AV_LOG_WARNING, "Output file is empty, nothing was encoded (check -ss / -t / -frames parameters if used)\n"); } } @@ -2455,6 +2264,8 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p else if (ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { video_size += pkt->size; ost->sync_opts++; + } else if (ost->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { + subtitle_size += pkt->size; } if (pkt->pts != AV_NOPTS_VALUE) @@ -2502,7 +2313,7 @@ static void rate_emu_sleep(InputStream *ist) int64_t pts = av_rescale(ist->dts, 1000000, AV_TIME_BASE); int64_t now = av_gettime() - ist->start; if (pts > now) - usleep(pts - now); + av_usleep(pts - now); } } @@ -2657,6 +2468,9 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output) return ret; } + if(ist->top_field_first>=0) + decoded_frame->top_field_first = ist->top_field_first; + 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); @@ -2925,7 +2739,7 @@ static int init_input_stream(int ist_index, char *error, int error_len) if (codec->type == AVMEDIA_TYPE_VIDEO && ist->dr1) { ist->st->codec->get_buffer = codec_get_buffer; ist->st->codec->release_buffer = codec_release_buffer; - ist->st->codec->opaque = ist; + ist->st->codec->opaque = &ist->buffer_pool; } if (!av_dict_get(ist->opts, "threads", NULL, 0)) @@ -2950,24 +2764,37 @@ static InputStream *get_input_stream(OutputStream *ost) { if (ost->source_index >= 0) return input_streams[ost->source_index]; + return NULL; +} - if (ost->filter) { - FilterGraph *fg = ost->filter->graph; - int i; +static void parse_forced_key_frames(char *kf, OutputStream *ost, + AVCodecContext *avctx) +{ + char *p; + int n = 1, i; + int64_t t; - for (i = 0; i < fg->nb_inputs; i++) - if (fg->inputs[i]->ist->st->codec->codec_type == ost->st->codec->codec_type) - return fg->inputs[i]->ist; + for (p = kf; *p; p++) + if (*p == ',') + n++; + ost->forced_kf_count = n; + ost->forced_kf_pts = av_malloc(sizeof(*ost->forced_kf_pts) * n); + if (!ost->forced_kf_pts) { + av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n"); + exit_program(1); + } + for (i = 0; i < n; i++) { + p = i ? strchr(p, ',') + 1 : kf; + t = parse_time_or_die("force_key_frames", p, 1); + ost->forced_kf_pts[i] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base); } - - return NULL; } static int transcode_init(void) { int ret = 0, i, j, k; AVFormatContext *oc; - AVCodecContext *codec, *icodec; + AVCodecContext *codec, *icodec = NULL; OutputStream *ost; InputStream *ist; char error[1024]; @@ -3075,6 +2902,10 @@ static int transcode_init(void) codec->time_base.num *= icodec->ticks_per_frame; } } + + if(ost->frame_rate.num) + codec->time_base = (AVRational){ost->frame_rate.den, ost->frame_rate.num}; + av_reduce(&codec->time_base.num, &codec->time_base.den, codec->time_base.num, codec->time_base.den, INT_MAX); @@ -3135,6 +2966,8 @@ static int transcode_init(void) ost->encoding_needed = 1; if (codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (ost->filter && !ost->frame_rate.num) + ost->frame_rate = av_buffersink_get_frame_rate(ost->filter->filter); 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) { @@ -3148,7 +2981,7 @@ static int transcode_init(void) codec->codec_type == AVMEDIA_TYPE_AUDIO)) { FilterGraph *fg; fg = init_simple_filtergraph(ist, ost); - if (configure_simple_filtergraph(fg)) { + if (configure_filtergraph(fg)) { av_log(NULL, AV_LOG_FATAL, "Error opening filters!\n"); exit(1); } @@ -3164,6 +2997,8 @@ static int transcode_init(void) break; case AVMEDIA_TYPE_VIDEO: codec->time_base = (AVRational){ost->frame_rate.den, ost->frame_rate.num}; + if (ost->filter && !(codec->time_base.num && codec->time_base.den)) + codec->time_base = ost->filter->filter->inputs[0]->time_base; 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)))){ av_log(oc, AV_LOG_WARNING, "Frame rate very high for a muxer not efficiently supporting it.\n" @@ -3182,12 +3017,16 @@ static int transcode_init(void) ost->filter->filter->inputs[0]->sample_aspect_ratio; codec->pix_fmt = ost->filter->filter->inputs[0]->format; - if (codec->width != icodec->width || + if (!icodec || + codec->width != icodec->width || codec->height != icodec->height || codec->pix_fmt != icodec->pix_fmt) { codec->bits_per_raw_sample = frame_bits_per_raw_sample; } + if (ost->forced_keyframes) + parse_forced_key_frames(ost->forced_keyframes, ost, + ost->st->codec); break; case AVMEDIA_TYPE_SUBTITLE: codec->time_base = (AVRational){1, 1000}; @@ -3322,13 +3161,10 @@ static int transcode_init(void) ist = input_streams[i]; for (j = 0; j < ist->nb_filters; j++) { - AVFilterLink *link = ist->filters[j]->filter->outputs[0]; if (ist->filters[j]->graph->graph_desc) { av_log(NULL, AV_LOG_INFO, " Stream #%d:%d (%s) -> %s", ist->file_index, ist->st->index, ist->dec ? ist->dec->name : "?", - link->dst->filter->name); - if (link->dst->input_count > 1) - av_log(NULL, AV_LOG_INFO, ":%s", link->dstpad->name); + ist->filters[j]->name); if (nb_filtergraphs > 1) av_log(NULL, AV_LOG_INFO, " (graph %d)", ist->filters[j]->graph->index); av_log(NULL, AV_LOG_INFO, "\n"); @@ -3348,10 +3184,7 @@ static int transcode_init(void) if (ost->filter && ost->filter->graph->graph_desc) { /* output from a complex graph */ - AVFilterLink *link = ost->filter->filter->inputs[0]; - av_log(NULL, AV_LOG_INFO, " %s", link->src->filter->name); - if (link->src->output_count > 1) - av_log(NULL, AV_LOG_INFO, ":%s", link->srcpad->name); + av_log(NULL, AV_LOG_INFO, " %s", ost->filter->name); if (nb_filtergraphs > 1) av_log(NULL, AV_LOG_INFO, " (graph %d)", ost->filter->graph->index); @@ -3390,6 +3223,269 @@ static int transcode_init(void) return 0; } +/** + * @return 1 if there are still streams where more output is wanted, + * 0 otherwise + */ +static int need_output(void) +{ + int i; + + for (i = 0; i < nb_output_streams; i++) { + OutputStream *ost = output_streams[i]; + OutputFile *of = output_files[ost->file_index]; + AVFormatContext *os = output_files[ost->file_index]->ctx; + + if (ost->is_past_recording_time || + (os->pb && avio_tell(os->pb) >= of->limit_filesize)) + continue; + if (ost->frame_number >= ost->max_frames) { + int j; + for (j = 0; j < of->ctx->nb_streams; j++) + output_streams[of->ost_index + j]->is_past_recording_time = 1; + continue; + } + + return 1; + } + + return 0; +} + +static int select_input_file(uint8_t *no_packet) +{ + int64_t ipts_min = INT64_MAX; + int i, file_index = -1; + + for (i = 0; i < nb_input_streams; i++) { + InputStream *ist = input_streams[i]; + int64_t ipts = ist->pts; + + if (ist->discard || no_packet[ist->file_index]) + continue; + if (!input_files[ist->file_index]->eof_reached) { + if (ipts < ipts_min) { + ipts_min = ipts; + file_index = ist->file_index; + } + } + } + + return file_index; +} + +static int check_keyboard_interaction(int64_t cur_time) +{ + int i, ret, key; + static int64_t last_time; + if (received_nb_signals) + return AVERROR_EXIT; + /* read_key() returns 0 on EOF */ + if(cur_time - last_time >= 100000 && !run_as_daemon){ + key = read_key(); + last_time = cur_time; + }else + key = -1; + if (key == 'q') + return AVERROR_EXIT; + if (key == '+') av_log_set_level(av_log_get_level()+10); + if (key == '-') av_log_set_level(av_log_get_level()-10); + if (key == 's') qp_hist ^= 1; + if (key == 'h'){ + if (do_hex_dump){ + do_hex_dump = do_pkt_dump = 0; + } else if(do_pkt_dump){ + do_hex_dump = 1; + } else + do_pkt_dump = 1; + av_log_set_level(AV_LOG_DEBUG); + } + if (key == 'c' || key == 'C'){ + char buf[4096], target[64], command[256], arg[256] = {0}; + double time; + int k, n = 0; + fprintf(stderr, "\nEnter command: