add ffmpeg audio pts tolerance, update plugin info
[goodguy/history.git] / cinelerra-5.1 / cinelerra / ffmpeg.C
index 2ac09f730a9612126925dcc7fd5df14bb4517946..65e0c780e793cfaa82b04cd3860cafbe8cb98066 100644 (file)
@@ -15,6 +15,8 @@
 #define INT64_MAX 9223372036854775807LL
 #endif
 #define MAX_RETRY 1000
+// max pts/curr_pos drift allowed before correction (in seconds)
+#define AUDIO_PTS_TOLERANCE 0.04
 
 #include "asset.h"
 #include "bccmodels.h"
 #include "mwindow.h"
 #include "vframe.h"
 
+#ifdef FFMPEG3
+#define url filename
+#else
+#define av_register_all(s)
+#define avfilter_register_all(s)
+#endif
 
 #define VIDEO_INBUF_SIZE 0x10000
 #define AUDIO_INBUF_SIZE 0x10000
@@ -752,6 +760,7 @@ int FFAudioStream::load_history(uint8_t **data, int len)
 int FFAudioStream::decode_frame(AVFrame *frame)
 {
        int first_frame = seeked;  seeked = 0;
+       frame->best_effort_timestamp = AV_NOPTS_VALUE;
        int ret = avcodec_receive_frame(avctx, frame);
        if( ret < 0 ) {
                if( first_frame || ret == AVERROR(EAGAIN) ) return 0;
@@ -760,8 +769,13 @@ int FFAudioStream::decode_frame(AVFrame *frame)
                return -1;
        }
        int64_t pkt_ts = frame->best_effort_timestamp;
-       if( pkt_ts != AV_NOPTS_VALUE )
-               curr_pos = ffmpeg->to_secs(pkt_ts - nudge, st->time_base) * sample_rate + 0.5;
+       if( pkt_ts != AV_NOPTS_VALUE ) {
+               double ts = ffmpeg->to_secs(pkt_ts - nudge, st->time_base);
+               double t = (double)curr_pos / sample_rate;
+// some time_base clocks are very grainy, too grainy for audio (clicks, pops)
+               if( fabs(ts - t) > AUDIO_PTS_TOLERANCE )
+                       curr_pos = ts * sample_rate + 0.5;
+       }
        return 1;
 }
 
@@ -839,7 +853,8 @@ int FFAudioStream::audio_seek(int64_t pos)
        if( pos == curr_pos ) return 0;
        reset_history();  mbsz = 0;
 // guarentee preload > 1sec samples
-       if( seek(pos-sample_rate, sample_rate) < 0 ) return -1;
+       if( (pos-=sample_rate) < 0 ) pos = 0;
+       if( seek(pos, sample_rate) < 0 ) return -1;
        return 1;
 }
 
@@ -1108,6 +1123,7 @@ int FFVideoConvert::convert_picture_vframe(VFrame *frame, AVFrame *ip, AVFrame *
        case BC_YUV422P:
                usz /= 2;
        case BC_YUV444P:
+       case BC_GBRP:
                // override av_image_fill_arrays() for planar types
                ipic->data[0] = frame->get_y();  ipic->linesize[0] = ysz;
                ipic->data[1] = frame->get_u();  ipic->linesize[1] = usz;
@@ -1208,6 +1224,7 @@ int FFVideoConvert::convert_vframe_picture(VFrame *frame, AVFrame *op, AVFrame *
        case BC_YUV422P:
                usz /= 2;
        case BC_YUV444P:
+       case BC_GBRP:
                // override av_image_fill_arrays() for planar types
                opic->data[0] = frame->get_y();  opic->linesize[0] = ysz;
                opic->data[1] = frame->get_u();  opic->linesize[1] = usz;
@@ -1925,6 +1942,7 @@ int FFMPEG::info(char *text, int len)
 int FFMPEG::init_decoder(const char *filename)
 {
        ff_lock("FFMPEG::init_decoder");
+       av_register_all();
        char file_opts[BCTEXTLEN];
        char *bp = strrchr(strcpy(file_opts, filename), '/');
        char *sp = strrchr(!bp ? file_opts : bp, '.');
@@ -2070,6 +2088,7 @@ int FFMPEG::init_encoder(const char *filename)
                return 1;
        }
        ff_lock("FFMPEG::init_encoder");
+       av_register_all();
        char format[BCSTRLEN];
        if( get_format(format, "format", file_format) )
                strcpy(format, file_format);
@@ -2103,7 +2122,9 @@ int FFMPEG::open_encoder(const char *type, const char *spec)
                return 1;
        }
 
+#ifdef HAVE_DV
        if( !strcmp(codec_name, CODEC_TAG_DVSD) ) strcpy(codec_name, "dv");
+#endif
        else if( !strcmp(codec_name, CODEC_TAG_MJPEG) ) strcpy(codec_name, "mjpeg");
        else if( !strcmp(codec_name, CODEC_TAG_JPEG) ) strcpy(codec_name, "jpeg");
 
@@ -2856,6 +2877,7 @@ int FFMPEG::ff_cpus()
 
 int FFVideoStream::create_filter(const char *filter_spec, AVCodecParameters *avpar)
 {
+       avfilter_register_all();
        const char *sp = filter_spec;
        char filter_name[BCSTRLEN], *np = filter_name;
        int i = sizeof(filter_name);
@@ -2896,6 +2918,7 @@ int FFVideoStream::create_filter(const char *filter_spec, AVCodecParameters *avp
 
 int FFAudioStream::create_filter(const char *filter_spec, AVCodecParameters *avpar)
 {
+       avfilter_register_all();
        const char *sp = filter_spec;
        char filter_name[BCSTRLEN], *np = filter_name;
        int i = sizeof(filter_name);
@@ -2980,6 +3003,7 @@ int FFMPEG::scan(IndexState *index_state, int64_t *scan_position, int *canceled)
        if( !frame ) {
                fprintf(stderr,"FFMPEG::scan: ");
                fprintf(stderr,_("av_frame_alloc failed\n"));
+               fprintf(stderr,"FFMPEG::scan:file=%s\n", file_base->asset->path);
                return -1;
        }
 
@@ -3025,6 +3049,7 @@ int FFMPEG::scan(IndexState *index_state, int64_t *scan_position, int *canceled)
                }
                fprintf(stderr,"FFMPEG::scan: ");
                fprintf(stderr,_("codec open failed\n"));
+               fprintf(stderr,"FFMPEG::scan:file=%s\n", file_base->asset->path);
                avcodec_free_context(&avctx);
        }