X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffmpeg.c;h=4afc55b40c384e59f0d762c5dda7d7324ec6b248;hb=744bd8d08c18d68d92ead091c7e335b4b07459aa;hp=85ae4f3b70beb436ba87e815d5fbb7bb3ef4a1c4;hpb=8b0e173529c821957868acf39e95d92853f3b8e0;p=ffmpeg diff --git a/ffmpeg.c b/ffmpeg.c index 85ae4f3b70b..4afc55b40c3 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,6 +176,13 @@ static int print_stats = 1; static int debug_ts = 0; static int current_time; +static uint8_t *subtitle_out; + +#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 { @@ -201,19 +214,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; @@ -262,11 +262,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 { @@ -300,6 +308,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 */ @@ -524,8 +533,14 @@ static void reset_options(OptionsContext *o, int is_input) memset(o, 0, sizeof(*o)); - if(is_input) o->recording_time = bak.recording_time; - else o->recording_time = INT64_MAX; + if (is_input) { + o->recording_time = bak.recording_time; + if (o->recording_time != INT64_MAX) + av_log(NULL, AV_LOG_WARNING, + "-t is not an input option, keeping it for the next output;" + " consider fixing your command line.\n"); + } else + o->recording_time = INT64_MAX; o->mux_max_delay = 0.7; o->limit_filesize = UINT64_MAX; o->chapters_input_file = INT_MAX; @@ -534,145 +549,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) { @@ -841,7 +717,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 @@ -887,11 +763,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; @@ -916,17 +794,13 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, 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) @@ -940,8 +814,10 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, codec->width, codec->height, (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; @@ -952,6 +828,8 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, 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, @@ -971,8 +849,10 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, 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"), - "fps", args, NULL, fg->graph); + name, args, NULL, fg->graph); if (ret < 0) return ret; @@ -996,11 +876,14 @@ 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_old"), - "out", NULL, NULL, fg->graph); + avfilter_get_by_name("abuffersink"), + name, NULL, NULL, fg->graph); if (ret < 0) return ret; @@ -1063,9 +946,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; @@ -1077,16 +962,7 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, pad_idx = 0; } - if (audio_sync_method > 0 && 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=%d", -audio_sync_method); - AUTO_INSERT_FILTER("-async", "aresample", args); - } - - if (audio_volume != 256) { + if (audio_volume != 256 && 0) { char args[256]; snprintf(args, sizeof(args), "%f", audio_volume / 256.); @@ -1111,7 +987,7 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, \ avio_printf(pb, "%s", ctx->filter->name); \ if (nb_pads > 1) \ - avio_printf(pb, ":%s", pads[inout->pad_idx].name); \ + avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));\ avio_w8(pb, 0); \ avio_close_dyn_buf(pb, &f->name); \ } @@ -1121,7 +997,7 @@ static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFil av_freep(&ofilter->name); DESCRIBE_FILTER_LINK(ofilter, out, 0); - switch (out->filter_ctx->output_pads[out->pad_idx].type) { + 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); @@ -1137,29 +1013,43 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter, 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; - char args[255]; + 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; - snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d:flags=%d", ist->st->codec->width, + 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, in->name, - args, NULL, fg->graph)) < 0) + 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"), - "setpts", "N", NULL, + name, "N", NULL, fg->graph)) < 0) return ret; @@ -1182,18 +1072,20 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter, AVFilter *filter = avfilter_get_by_name("abuffer"); InputStream *ist = ifilter->ist; int pad_idx = in->pad_idx; - char args[255]; + 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, + 1, ist->st->codec->sample_rate, 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, - in->name, args, NULL, + name, args, NULL, fg->graph)) < 0) return ret; @@ -1203,9 +1095,11 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter, 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), \ - filter_name, arg, NULL, fg->graph); \ + name, arg, NULL, fg->graph); \ if (ret < 0) \ return ret; \ \ @@ -1256,7 +1150,7 @@ static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter, av_freep(&ifilter->name); DESCRIBE_FILTER_LINK(ifilter, in, 1); - switch (in->filter_ctx->input_pads[in->pad_idx].type) { + 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); @@ -1369,8 +1263,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); @@ -1479,6 +1376,8 @@ void av_noreturn exit_program(int ret) } av_freep(&filtergraphs); + av_freep(&subtitle_out); + /* close files */ for (i = 0; i < nb_output_files; i++) { AVFormatContext *s = output_files[i]->ctx; @@ -1497,6 +1396,7 @@ 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]); @@ -1508,7 +1408,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]); } @@ -1670,10 +1570,10 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; -#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->pts + frame->nb_samples; @@ -1753,7 +1653,6 @@ static void do_subtitle_out(AVFormatContext *s, AVSubtitle *sub, int64_t pts) { - static uint8_t *subtitle_out = NULL; int subtitle_out_max_size = 1024 * 1024; int subtitle_out_size, nb, i; AVCodecContext *enc; @@ -1782,6 +1681,8 @@ static void do_subtitle_out(AVFormatContext *s, for (i = 0; i < nb; i++) { ost->sync_opts = av_rescale_q(pts, ist->st->time_base, enc->time_base); + if (!check_recording_time(ost)) + return; sub->pts = av_rescale_q(pts, ist->st->time_base, AV_TIME_BASE_Q); // start_display_time is required to be 0 @@ -1799,6 +1700,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 */ @@ -1808,6 +1710,7 @@ static void do_subtitle_out(AVFormatContext *s, pkt.pts += 90 * sub->end_display_time; } write_frame(s, &pkt, ost); + subtitle_size += pkt.size; } } @@ -1819,7 +1722,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; @@ -1869,6 +1772,11 @@ static void do_video_out(AVFormatContext *s, av_log(NULL, AV_LOG_VERBOSE, "*** drop!\n"); return; } else if (nb_frames > 1) { + if (nb_frames > dts_error_threshold * 30) { + av_log(NULL, AV_LOG_ERROR, "%d frame duplication too large, skiping\n", nb_frames - 1); + nb_frames_drop++; + return; + } nb_frames_dup += nb_frames - 1; av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1); } @@ -1881,6 +1789,9 @@ duplicate_frame: in_picture->pts = ost->sync_opts; + if (!check_recording_time(ost)) + return; + if (s->oformat->flags & AVFMT_RAWPICTURE && enc->codec->id == CODEC_ID_RAWVIDEO) { /* raw pictures are written as AVPicture structure to @@ -1894,6 +1805,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; @@ -2027,7 +1939,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())) { @@ -2037,18 +1949,8 @@ static int poll_filters(void) 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 + ret = av_buffersink_get_buffer_ref(ost->filter->filter, &picref, + AV_BUFFERSINK_FLAG_NO_REQUEST); if (ret < 0) { if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) { char buf[256]; @@ -2078,7 +1980,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; @@ -2243,15 +2145,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"); } } @@ -2344,13 +2247,6 @@ static int check_output_constraints(InputStream *ist, OutputStream *ost) if (of->start_time && ist->pts < of->start_time) return 0; - if (of->recording_time != INT64_MAX && - av_compare_ts(ist->pts, AV_TIME_BASE_Q, of->recording_time + of->start_time, - (AVRational){ 1, 1000000 }) >= 0) { - ost->is_past_recording_time = 1; - return 0; - } - return 1; } @@ -2367,12 +2263,20 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p !ost->copy_initial_nonkeyframes) return; + if (of->recording_time != INT64_MAX && + ist->pts >= of->recording_time + of->start_time) { + ost->is_past_recording_time = 1; + return; + } + /* force the input stream PTS */ if (ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) audio_size += pkt->size; 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) @@ -2420,7 +2324,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); } } @@ -2453,6 +2357,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output) else avcodec_get_frame_defaults(ist->decoded_frame); decoded_frame = ist->decoded_frame; + av_codec_set_pkt_timebase(avctx, ist->st->time_base); update_benchmark(NULL); ret = avcodec_decode_audio4(avctx, decoded_frame, got_output, pkt); @@ -2530,13 +2435,27 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output) 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); + if (ist_in_filtergraph(filtergraphs[i], ist)) { + FilterGraph *fg = filtergraphs[i]; + int j; + if (configure_filtergraph(fg) < 0) { + av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n"); + exit_program(1); + } + for (j = 0; j < fg->nb_outputs; j++) { + OutputStream *ost = fg->outputs[j]->ost; + if (ost->enc->type == AVMEDIA_TYPE_AUDIO && + !(ost->enc->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) + av_buffersink_set_frame_size(ost->filter->filter, + ost->st->codec->frame_size); + } } } + if (decoded_frame->pts != AV_NOPTS_VALUE) + decoded_frame->pts = av_rescale_q(decoded_frame->pts, + ist->st->time_base, + (AVRational){1, ist->st->codec->sample_rate}); for (i = 0; i < ist->nb_filters; i++) av_buffersrc_add_frame(ist->filters[i]->filter, decoded_frame, 0); @@ -2558,6 +2477,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output) avcodec_get_frame_defaults(ist->decoded_frame); decoded_frame = ist->decoded_frame; pkt->dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base); + av_codec_set_pkt_timebase(ist->st->codec, ist->st->time_base); update_benchmark(NULL); ret = avcodec_decode_video2(ist->st->codec, @@ -2582,6 +2502,16 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output) 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); + if (debug_ts) { + av_log(NULL, AV_LOG_INFO, "decoder -> ist_index:%d type:video " + "frame_pts:%s frame_pts_time:%s best_effort_ts:%"PRId64" best_effort_ts_time:%s keyframe:%d frame_type:%d \n", + ist->st->index, av_ts2str(decoded_frame->pts), + av_ts2timestr(decoded_frame->pts, &ist->st->time_base), + best_effort_timestamp, + av_ts2timestr(best_effort_timestamp, &ist->st->time_base), + decoded_frame->key_frame, decoded_frame->pict_type); + } + pkt->size = 0; pre_process_video_frame(ist, (AVPicture *)decoded_frame, &buffer_to_free); @@ -2846,7 +2776,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)) @@ -2871,24 +2801,45 @@ 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); } - return NULL; + p = kf; + for (i = 0; i < n; i++) { + char *next = strchr(p, ','); + + if (next) + *next++ = 0; + + 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); + + p = next; + } } 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]; @@ -2996,6 +2947,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); @@ -3056,6 +3011,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) { @@ -3112,6 +3069,9 @@ static int transcode_init(void) 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}; @@ -3181,6 +3141,10 @@ static int transcode_init(void) ret = AVERROR(EINVAL); goto dump_format; } + if (ost->enc->type == AVMEDIA_TYPE_AUDIO && + !(ost->enc->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) + av_buffersink_set_frame_size(ost->filter->filter, + ost->st->codec->frame_size); assert_codec_experimental(ost->st->codec, 1); assert_avoptions(ost->opts); if (ost->st->codec->bit_rate && ost->st->codec->bit_rate < 1000) @@ -3308,6 +3272,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: