diff options
-rw-r--r-- | intern/ffmpeg/ffmpeg_compat.h | 49 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/writeffmpeg.c | 16 | ||||
-rw-r--r-- | source/blender/imbuf/intern/indexer.c | 3 |
3 files changed, 63 insertions, 5 deletions
diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h index 54a004d53e2..0c22cf82688 100644 --- a/intern/ffmpeg/ffmpeg_compat.h +++ b/intern/ffmpeg/ffmpeg_compat.h @@ -43,6 +43,55 @@ # define FFMPEG_INLINE static inline #endif +#if (LIBAVFORMAT_VERSION_MAJOR < 58) || \ + ((LIBAVFORMAT_VERSION_MAJOR == 58) && (LIBAVFORMAT_VERSION_MINOR < 76)) +# define FFMPEG_USE_DURATION_WORKAROUND 1 + +/* Before ffmpeg 4.4, package duration calculation used depricated variables to calculate the + * packet duration. Use the function from commit + * github.com/FFmpeg/FFmpeg/commit/1c0885334dda9ee8652e60c586fa2e3674056586 + * to calculate the correct framerate for ffmpeg < 4.4. + */ + +FFMPEG_INLINE +void my_guess_pkt_duration(AVFormatContext *s, AVStream *st, AVPacket *pkt) +{ + if (pkt->duration < 0 && st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) { + av_log(s, + AV_LOG_WARNING, + "Packet with invalid duration %" PRId64 " in stream %d\n", + pkt->duration, + pkt->stream_index); + pkt->duration = 0; + } + + if (pkt->duration) { + return; + } + + switch (st->codecpar->codec_type) { + case AVMEDIA_TYPE_VIDEO: + if (st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0) { + pkt->duration = av_rescale_q(1, av_inv_q(st->avg_frame_rate), st->time_base); + } + else if (st->time_base.num * 1000LL > st->time_base.den) { + pkt->duration = 1; + } + break; + case AVMEDIA_TYPE_AUDIO: { + int frame_size = av_get_audio_frame_duration2(st->codecpar, pkt->size); + if (frame_size && st->codecpar->sample_rate) { + pkt->duration = av_rescale_q( + frame_size, (AVRational){1, st->codecpar->sample_rate}, st->time_base); + } + break; + } + default: + break; + } +} +#endif + FFMPEG_INLINE void my_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp) { diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 39f65d76e3c..3408f990fd1 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -205,12 +205,11 @@ static int write_audio_frame(FFMpegContext *context) success = -1; } - av_packet_rescale_ts(pkt, c->time_base, context->audio_stream->time_base); - if (pkt->duration > 0) { - pkt->duration = av_rescale_q(pkt->duration, c->time_base, context->audio_stream->time_base); - } - pkt->stream_index = context->audio_stream->index; + av_packet_rescale_ts(pkt, c->time_base, context->audio_stream->time_base); +# ifdef FFMPEG_USE_DURATION_WORKAROUND + my_guess_pkt_duration(context->outfile, context->audio_stream, pkt); +# endif pkt->flags |= AV_PKT_FLAG_KEY; @@ -349,6 +348,10 @@ static int write_video_frame(FFMpegContext *context, int cfra, AVFrame *frame, R packet->stream_index = context->video_stream->index; av_packet_rescale_ts(packet, c->time_base, context->video_stream->time_base); +# ifdef FFMPEG_USE_DURATION_WORKAROUND + my_guess_pkt_duration(context->outfile, context->video_stream, packet); +# endif + if (av_interleaved_write_frame(context->outfile, packet) != 0) { success = -1; break; @@ -1181,6 +1184,9 @@ static void flush_ffmpeg(FFMpegContext *context) packet->stream_index = context->video_stream->index; av_packet_rescale_ts(packet, c->time_base, context->video_stream->time_base); +# ifdef FFMPEG_USE_DURATION_WORKAROUND + my_guess_pkt_duration(context->outfile, context->video_stream, packet); +# endif int write_ret = av_interleaved_write_frame(context->outfile, packet); if (write_ret != 0) { diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 26f332bd575..453df6078ce 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -683,6 +683,9 @@ static void add_to_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, AVFrame *fr packet->stream_index = ctx->st->index; av_packet_rescale_ts(packet, ctx->c->time_base, ctx->st->time_base); +# ifdef FFMPEG_USE_DURATION_WORKAROUND + my_guess_pkt_duration(ctx->of, ctx->st, packet); +# endif int write_ret = av_interleaved_write_frame(ctx->of, packet); if (write_ret != 0) { |