X-Git-Url: http://git.cinelerra-gg.org/git/?a=blobdiff_plain;f=cinelerra-5.1%2Fcinelerra%2Fffmpeg.C;h=75131dca2c878dd1843b7f998bbbf282526e88a0;hb=047485402c380ee034045712121c649ddf89eda4;hp=f79a240ef5c844d091070f205e3dd68e1a799ee5;hpb=58d99c74e65066486dbebf7e1cb3087e7de1c92b;p=goodguy%2Fhistory.git diff --git a/cinelerra-5.1/cinelerra/ffmpeg.C b/cinelerra-5.1/cinelerra/ffmpeg.C index f79a240e..75131dca 100644 --- a/cinelerra-5.1/cinelerra/ffmpeg.C +++ b/cinelerra-5.1/cinelerra/ffmpeg.C @@ -33,6 +33,7 @@ #define AUDIO_INBUF_SIZE 0x10000 #define VIDEO_REFILL_THRESH 0 #define AUDIO_REFILL_THRESH 0x1000 +#define AUDIO_MIN_FRAME_SZ 128 Mutex FFMPEG::fflock("FFMPEG::fflock"); @@ -327,6 +328,8 @@ int FFStream::decode_activate() if( decoder->capabilities & AV_CODEC_CAP_DR1 ) avctx->flags |= CODEC_FLAG_EMU_EDGE; avcodec_parameters_to_context(avctx, st->codecpar); + if( !av_dict_get(copts, "threads", NULL, 0) ) + avctx->thread_count = ffmpeg->ff_cpus(); ret = avcodec_open2(avctx, decoder, &copts); } if( ret >= 0 ) { @@ -395,12 +398,9 @@ int FFStream::decode(AVFrame *frame) int FFStream::load_filter(AVFrame *frame) { - int ret = av_buffersrc_add_frame_flags(buffersrc_ctx, - frame, AV_BUFFERSRC_FLAG_KEEP_REF); - if( ret < 0 ) { - av_frame_unref(frame); + int ret = av_buffersrc_add_frame_flags(buffersrc_ctx, frame, 0); + if( ret < 0 ) eprintf(_("av_buffersrc_add_frame_flags failed\n")); - } return ret; } @@ -418,6 +418,7 @@ int FFStream::read_filter(AVFrame *frame) int FFStream::read_frame(AVFrame *frame) { + av_frame_unref(frame); if( !filter_graph || !buffersrc_ctx || !buffersink_ctx ) return decode(frame); if( !fframe && !(fframe=av_frame_alloc()) ) { @@ -491,7 +492,6 @@ int FFStream::flush() int FFStream::seek(int64_t no, double rate) { - int64_t tstmp = -INT64_MAX+1; // default ffmpeg native seek int npkts = 1; int64_t pos = no, pkt_pos = -1; @@ -509,11 +509,24 @@ int FFStream::seek(int64_t no, double rate) } } if( pos == curr_pos ) return 0; - if( pos > 0 && st->time_base.num > 0 ) { - double secs = pos / rate; - tstmp = secs * st->time_base.den / st->time_base.num; - if( nudge != AV_NOPTS_VALUE ) tstmp += nudge; - } + double secs = pos < 0 ? 0. : pos / rate; + AVRational time_base = st->time_base; + int64_t tstmp = time_base.num > 0 ? secs * time_base.den/time_base.num : 0; + if( !tstmp ) { + if( st->nb_index_entries > 0 ) tstmp = st->index_entries[0].timestamp; + else if( st->start_time != AV_NOPTS_VALUE ) tstmp = st->start_time; + else if( st->first_dts != AV_NOPTS_VALUE ) tstmp = st->first_dts; + else tstmp = INT64_MIN+1; + } + else if( nudge != AV_NOPTS_VALUE ) tstmp += nudge; + int idx = st->index; +#if 0 +// seek all streams using the default timebase. +// this is how ffmpeg and ffplay work. stream seeks are less tested. + tstmp = av_rescale_q(tstmp, time_base, AV_TIME_BASE_Q); + idx = -1; +#endif + avcodec_flush_buffers(avctx); avformat_flush(fmt_ctx); #if 0 @@ -523,9 +536,11 @@ int FFStream::seek(int64_t no, double rate) seek = pkt_pos; flags = AVSEEK_FLAG_BYTE; } - int ret = avformat_seek_file(fmt_ctx, st->index, -INT64_MAX, seek, INT64_MAX, flags); + int ret = avformat_seek_file(fmt_ctx, st->index, -INT64_MAX, seek, INT64_MAX, flags); #else - int ret = av_seek_frame(fmt_ctx, st->index, tstmp, AVSEEK_FLAG_ANY); +// finds the first index frame below the target time + int flags = AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY; + int ret = av_seek_frame(fmt_ctx, idx, tstmp, flags); #endif int retry = MAX_RETRY; while( ret >= 0 ) { @@ -559,7 +574,7 @@ int FFStream::seek(int64_t no, double rate) if( ret < 0 ) { printf("** seek fail %jd, %jd\n", pos, tstmp); seeked = need_packet = 0; - st_eof(flushed=1); + st_eof(flushed=1); return -1; } //printf("seeked pos = %ld, %ld\n", pos, tstmp); @@ -574,6 +589,7 @@ FFAudioStream::FFAudioStream(FFMPEG *ffmpeg, AVStream *strm, int idx, int fidx) channel0 = channels = 0; sample_rate = 0; mbsz = 0; + frame_sz = AUDIO_MIN_FRAME_SZ; length = 0; resample_context = 0; swr_ichs = swr_ifmt = swr_irate = 0; @@ -674,6 +690,7 @@ int FFAudioStream::decode_frame(AVFrame *frame) int FFAudioStream::encode_activate() { if( writing >= 0 ) return writing; + if( !avctx->codec ) return writing = 0; frame_sz = avctx->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE ? 10000 : avctx->frame_size; return FFStream::encode_activate(); @@ -718,10 +735,10 @@ int FFAudioStream::load(int64_t pos, int len) } if( mbsz < len ) mbsz = len; int64_t end_pos = pos + len; - int ret = 0; - for( int i=0; ret>=0 && !flushed && curr_pos=0 && !flushed && curr_pos=0 ) { ret = read_frame(frame); - if( ret > 0 ) { + if( ret > 0 && frame->nb_samples > 0 ) { init_swr(frame->channels, frame->format, frame->sample_rate); load_history(&frame->extended_data[0], frame->nb_samples); curr_pos += frame->nb_samples; @@ -852,7 +869,8 @@ int FFVideoStream::load(VFrame *vframe, int64_t pos) fprintf(stderr, "FFVideoStream::load: av_frame_alloc failed\n"); return -1; } - for( int i=0; ret>=0 && !flushed && curr_pos<=pos && i=0 && !flushed && curr_pos<=pos && --i>=0 ) { ret = read_frame(frame); if( ret > 0 ) ++curr_pos; } @@ -1725,8 +1743,11 @@ int FFMPEG::open_decoder() estimated = 1; } } - if( estimated ) + static int notified = 0; + if( !notified && estimated ) { + notified = 1; printf("FFMPEG::open_decoder: some stream times estimated\n"); + } ff_lock("FFMPEG::open_decoder"); int ret = 0, bad_time = 0; @@ -1892,6 +1913,19 @@ int FFMPEG::open_encoder(const char *type, const char *spec) sprintf(arg, "%d", asset->ff_audio_bitrate); av_dict_set(&sopts, "b", arg, 0); } + else if( asset->ff_audio_quality >= 0 ) { + ctx->global_quality = asset->ff_audio_quality * FF_QP2LAMBDA; + ctx->qmin = ctx->qmax = asset->ff_audio_quality; + ctx->mb_lmin = ctx->qmin * FF_QP2LAMBDA; + ctx->mb_lmax = ctx->qmax * FF_QP2LAMBDA; + ctx->flags |= CODEC_FLAG_QSCALE; + char arg[BCSTRLEN]; + av_dict_set(&sopts, "flags", "+qscale", 0); + sprintf(arg, "%d", asset->ff_audio_quality); + av_dict_set(&sopts, "qscale", arg, 0); + sprintf(arg, "%d", ctx->global_quality); + av_dict_set(&sopts, "global_quality", arg, 0); + } int aidx = ffaudio.size(); int fidx = aidx + ffvideo.size(); FFAudioStream *aud = new FFAudioStream(this, st, aidx, fidx); @@ -1968,6 +2002,7 @@ int FFMPEG::open_encoder(const char *type, const char *spec) break; } ctx->time_base = (AVRational) { frame_rate.den, frame_rate.num }; + st->avg_frame_rate = frame_rate; st->time_base = ctx->time_base; vid->writing = -1; vid->interlaced = asset->interlace_mode == ILACE_MODE_TOP_FIRST || @@ -1986,6 +2021,8 @@ int FFMPEG::open_encoder(const char *type, const char *spec) av_dict_set(&sopts, "cin_bitrate", 0, 0); av_dict_set(&sopts, "cin_quality", 0, 0); + if( !av_dict_get(sopts, "threads", NULL, 0) ) + ctx->thread_count = ff_cpus(); ret = avcodec_open2(ctx, codec, &sopts); if( ret >= 0 ) { ret = avcodec_parameters_from_context(st->codecpar, ctx); @@ -2098,7 +2135,8 @@ int FFMPEG::decode_activate() if( st->start_time == AV_NOPTS_VALUE ) continue; int vidx = ffvideo.size(); while( --vidx >= 0 && ffvideo[vidx]->fidx != i ); - if( vidx >= 0 && ffvideo[vidx]->nudge != AV_NOPTS_VALUE ) continue; + if( vidx < 0 ) continue; + if( ffvideo[vidx]->nudge != AV_NOPTS_VALUE ) continue; if( vstart_time < st->start_time ) vstart_time = st->start_time; break; } @@ -2106,7 +2144,10 @@ int FFMPEG::decode_activate() if( st->start_time == AV_NOPTS_VALUE ) continue; int aidx = ffaudio.size(); while( --aidx >= 0 && ffaudio[aidx]->fidx != i ); - if( aidx >= 0 && ffaudio[aidx]->nudge != AV_NOPTS_VALUE ) continue; + if( aidx < 0 ) continue; + if( ffaudio[aidx]->frame_sz < avpar->frame_size ) + ffaudio[aidx]->frame_sz = avpar->frame_size; + if( ffaudio[aidx]->nudge != AV_NOPTS_VALUE ) continue; if( astart_time < st->start_time ) astart_time = st->start_time; break; } @@ -2509,6 +2550,10 @@ int FFMPEG::ff_video_pid(int stream) return ffvideo[stream]->st->id; } +int FFMPEG::ff_video_mpeg_color_range(int stream) +{ + return ffvideo[stream]->st->codecpar->color_range == AVCOL_RANGE_MPEG ? 1 : 0; +} int FFMPEG::ff_cpus() { @@ -2663,6 +2708,8 @@ int FFMPEG::scan(IndexState *index_state, int64_t *scan_position, int *canceled) } if( ret >= 0 ) { avcodec_parameters_to_context(avctx, st->codecpar); + if( !av_dict_get(copts, "threads", NULL, 0) ) + avctx->thread_count = ff_cpus(); ret = avcodec_open2(avctx, decoder, &copts); } av_dict_free(&copts);