sams last ladspa icons, libopus/vp9, mixer fixer, plugin resets, fmt frmsz, shm fixes
[goodguy/history.git] / cinelerra-5.1 / cinelerra / ffmpeg.C
index 10ad05036ee64b71a5cb8d7e2336434fe2e52108..c536a2652291595c3f2c7b12e3c4e00eac2a9ee2 100644 (file)
@@ -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");
 
@@ -148,10 +149,13 @@ void FFAudioStream::reset_history()
 {
        inp = outp = bfr;
        hpos = 0;
+       memset(bfr, 0, lmt-bfr);
 }
 
 void FFAudioStream::iseek(int64_t ofs)
 {
+       if( ofs > hpos ) ofs = hpos;
+       if( ofs > sz ) ofs = sz;
        outp = inp - ofs*nch;
        if( outp < bfr ) outp += sz*nch;
 }
@@ -320,11 +324,17 @@ int FFStream::decode_activate()
                                ret = AVERROR(ENOMEM);
                        }
                        if( ret >= 0 ) {
+                               av_codec_set_pkt_timebase(avctx, st->time_base);
+                               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 )
+                       if( ret >= 0 ) {
                                reading = 1;
+                       }
                        else
                                eprintf(_("open decoder failed\n"));
                }
@@ -388,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;
 }
 
@@ -411,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()) ) {
@@ -484,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;
@@ -501,11 +508,25 @@ int FFStream::seek(int64_t no, double rate)
                        npkts = MAX_RETRY;
                }
        }
-       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;
-       }
+       if( pos == curr_pos ) return 0;
+       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
@@ -515,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 ) {
@@ -549,9 +572,9 @@ int FFStream::seek(int64_t no, double rate)
                }
        }
        if( ret < 0 ) {
-printf("** seek fail %ld, %ld\n", pos, tstmp);
+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);
@@ -566,8 +589,10 @@ 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;
 
        aud_bfr_sz = 0;
        aud_bfr = 0;
@@ -588,6 +613,28 @@ FFAudioStream::~FFAudioStream()
        delete [] bfr;
 }
 
+void FFAudioStream::init_swr(int ichs, int ifmt, int irate)
+{
+       if( resample_context ) {
+               if( swr_ichs == ichs && swr_ifmt == ifmt && swr_irate == irate )
+                       return;
+               swr_free(&resample_context);
+       }
+       swr_ichs = ichs;  swr_ifmt = ifmt;  swr_irate = irate;
+       if( ichs == channels && ifmt == AV_SAMPLE_FMT_FLT && irate == sample_rate )
+               return;
+       uint64_t ilayout = av_get_default_channel_layout(ichs);
+       if( !ilayout ) ilayout = ((uint64_t)1<<ichs) - 1;
+       uint64_t olayout = av_get_default_channel_layout(channels);
+       if( !olayout ) olayout = ((uint64_t)1<<channels) - 1;
+       resample_context = swr_alloc_set_opts(NULL,
+               olayout, AV_SAMPLE_FMT_FLT, sample_rate,
+               ilayout, (AVSampleFormat)ifmt, irate,
+               0, NULL);
+       if( resample_context )
+               swr_init(resample_context);
+}
+
 int FFAudioStream::get_samples(float *&samples, uint8_t **data, int len)
 {
        samples = *(float **)data;
@@ -643,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();
@@ -687,10 +735,11 @@ 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<end_pos && i<MAX_RETRY; ++i ) {
+       int ret = 0, i = len / frame_sz + MAX_RETRY;
+       while( ret>=0 && !flushed && curr_pos<end_pos && --i>=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;
                }
@@ -706,7 +755,7 @@ int FFAudioStream::load(int64_t pos, int len)
 
 int FFAudioStream::audio_seek(int64_t pos)
 {
-       if( decode_activate() < 0 ) return -1;
+       if( decode_activate() <= 0 ) return -1;
        if( !st->codecpar ) return -1;
        if( in_history(pos) ) return 0;
        if( pos == curr_pos ) return 0;
@@ -759,6 +808,11 @@ int FFAudioStream::encode_frame(AVFrame *frame)
        return FFStream::encode_frame(frame);
 }
 
+int FFAudioStream::write_packet(FFPacket &pkt)
+{
+       return FFStream::write_packet(pkt);
+}
+
 void FFAudioStream::load_markers()
 {
        IndexState *index_state = ffmpeg->file_base->asset->index_state;
@@ -815,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<MAX_RETRY; ++i ) {
+       int i = MAX_RETRY + pos - curr_pos;
+       while( ret>=0 && !flushed && curr_pos<=pos && --i>=0 ) {
                ret = read_frame(frame);
                if( ret > 0 ) ++curr_pos;
        }
@@ -830,7 +885,7 @@ int FFVideoStream::load(VFrame *vframe, int64_t pos)
 
 int FFVideoStream::video_seek(int64_t pos)
 {
-       if( decode_activate() < 0 ) return -1;
+       if( decode_activate() <= 0 ) return -1;
        if( !st->codecpar ) return -1;
        if( pos == curr_pos-1 && !seeked ) return 0;
 // if close enough, just read up to current
@@ -889,6 +944,13 @@ int FFVideoStream::encode_frame(AVFrame *frame)
        return FFStream::encode_frame(frame);
 }
 
+int FFVideoStream::write_packet(FFPacket &pkt)
+{
+       if( !(ffmpeg->fmt_ctx->oformat->flags & AVFMT_VARIABLE_FPS) )
+               pkt->duration = 1;
+       return FFStream::write_packet(pkt);
+}
+
 AVPixelFormat FFVideoConvert::color_model_to_pix_fmt(int color_model)
 {
        switch( color_model ) {
@@ -1728,16 +1790,7 @@ int FFMPEG::open_decoder()
                        aud->sample_rate = avpar->sample_rate;
                        double secs = to_secs(st->duration, st->time_base);
                        aud->length = secs * aud->sample_rate;
-                       if( avpar->format != AV_SAMPLE_FMT_FLT ) {
-                               uint64_t layout = av_get_default_channel_layout(avpar->channels);
-                               if( !layout ) layout = ((uint64_t)1<<aud->channels) - 1;
-                               AVSampleFormat sample_format = (AVSampleFormat)avpar->format;
-                               aud->resample_context = swr_alloc_set_opts(NULL,
-                                       layout, AV_SAMPLE_FMT_FLT, avpar->sample_rate,
-                                       layout, sample_format, avpar->sample_rate,
-                                       0, NULL);
-                               swr_init(aud->resample_context);
-                       }
+                       aud->init_swr(aud->channels, avpar->format, aud->sample_rate);
                        aud->nudge = st->start_time;
                        aud->reading = -1;
                        if( opt_audio_filter )
@@ -1951,6 +2004,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);
@@ -2063,7 +2118,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; }
@@ -2071,7 +2127,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; }
@@ -2079,7 +2138,7 @@ int FFMPEG::decode_activate()
                        }
                }
                int64_t nudge = vstart_time > min_nudge ? vstart_time :
-                       astart_time > min_nudge ? astart_time : AV_NOPTS_VALUE;
+                       astart_time > min_nudge ? astart_time : 0;
                for( int vidx=0; vidx<ffvideo.size(); ++vidx ) {
                        if( ffvideo[vidx]->nudge == AV_NOPTS_VALUE )
                                ffvideo[vidx]->nudge = nudge;
@@ -2628,30 +2687,32 @@ 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);
-               if( ret < 0 ) {
-                       fprintf(stderr,"FFMPEG::scan: ");
-                       fprintf(stderr,_("codec open failed\n"));
-                       continue;
-               }
-               AVCodecParameters *avpar = st->codecpar;
-               switch( avpar->codec_type ) {
-               case AVMEDIA_TYPE_VIDEO: {
-                       int vidx = ffvideo.size();
-                       while( --vidx>=0 && ffvideo[vidx]->fidx != i );
-                       if( vidx < 0 ) break;
-                       ffvideo[vidx]->avctx = avctx;
-                       break; }
-               case AVMEDIA_TYPE_AUDIO: {
-                       int aidx = ffaudio.size();
-                       while( --aidx>=0 && ffaudio[aidx]->fidx != i );
-                       if( aidx < 0 ) continue;
-                       ffaudio[aidx]->avctx = avctx;
-                       break; }
-               default: break;
+               if( ret >= 0 ) {
+                       AVCodecParameters *avpar = st->codecpar;
+                       switch( avpar->codec_type ) {
+                       case AVMEDIA_TYPE_VIDEO: {
+                               int vidx = ffvideo.size();
+                               while( --vidx>=0 && ffvideo[vidx]->fidx != i );
+                               if( vidx < 0 ) break;
+                               ffvideo[vidx]->avctx = avctx;
+                               continue; }
+                       case AVMEDIA_TYPE_AUDIO: {
+                               int aidx = ffaudio.size();
+                               while( --aidx>=0 && ffaudio[aidx]->fidx != i );
+                               if( aidx < 0 ) break;
+                               ffaudio[aidx]->avctx = avctx;
+                               continue; }
+                       default: break;
+                       }
                }
+               fprintf(stderr,"FFMPEG::scan: ");
+               fprintf(stderr,_("codec open failed\n"));
+               avcodec_free_context(&avctx);
        }
 
        decode_activate();
@@ -2697,6 +2758,7 @@ int FFMPEG::scan(IndexState *index_state, int64_t *scan_position, int *canceled)
                        while( --vidx>=0 && ffvideo[vidx]->fidx != i );
                        if( vidx < 0 ) break;
                        FFVideoStream *vid = ffvideo[vidx];
+                       if( !vid->avctx ) break;
                        int64_t tstmp = pkt.dts;
                        if( tstmp == AV_NOPTS_VALUE ) tstmp = pkt.pts;
                        if( tstmp != AV_NOPTS_VALUE && (pkt.flags & AV_PKT_FLAG_KEY) && pkt.pos > 0 ) {
@@ -2717,6 +2779,7 @@ int FFMPEG::scan(IndexState *index_state, int64_t *scan_position, int *canceled)
                        while( --aidx>=0 && ffaudio[aidx]->fidx != i );
                        if( aidx < 0 ) break;
                        FFAudioStream *aud = ffaudio[aidx];
+                       if( !aud->avctx ) break;
                        int64_t tstmp = pkt.pts;
                        if( tstmp == AV_NOPTS_VALUE ) tstmp = pkt.dts;
                        if( tstmp != AV_NOPTS_VALUE && (pkt.flags & AV_PKT_FLAG_KEY) && pkt.pos > 0 ) {
@@ -2736,7 +2799,8 @@ printf("audio%d pad %jd %jd (%jd)\n", aud->idx, pos, aud->curr_pos, pos-aud->cur
                                index_state->pad_data(ch, nch, aud->curr_pos);
                        }
                        while( (ret=aud->decode_frame(frame)) > 0 ) {
-                               if( frame->channels != nch ) break;
+                               //if( frame->channels != nch ) break;
+                               aud->init_swr(frame->channels, frame->format, frame->sample_rate);
                                float *samples;
                                int len = aud->get_samples(samples,
                                         &frame->extended_data[0], frame->nb_samples);