commit 62274859104bd828373ae406aa9309e610449ac5 Author: Ted Meyer Date: Fri Mar 22 19:56:55 2024 +0000 Replace deprecated use of AVCodecContext::reordered_opaque We can use the AV_CODEC_FLAG_COPY_OPAQUE flag on the codec context now to trigger timestamp propagation. Bug: 330573128 Change-Id: I6bc57241a35ab5283742aad8d42acb4dc5e85858 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5384308 Commit-Queue: Ted (Chromium) Meyer Reviewed-by: Dan Sanders Cr-Commit-Position: refs/heads/main@{#1277051} diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc index bd75477feeabb..8a658a58caac5 100644 --- a/media/filters/ffmpeg_video_decoder.cc +++ b/media/filters/ffmpeg_video_decoder.cc @@ -134,7 +134,7 @@ bool FFmpegVideoDecoder::IsCodecSupported(VideoCodec codec) { } FFmpegVideoDecoder::FFmpegVideoDecoder(MediaLog* media_log) - : media_log_(media_log) { + : media_log_(media_log), timestamp_map_(128) { DVLOG(1) << __func__; DETACH_FROM_SEQUENCE(sequence_checker_); } @@ -363,8 +363,10 @@ bool FFmpegVideoDecoder::FFmpegDecode(const DecoderBuffer& buffer) { DCHECK(packet->data); DCHECK_GT(packet->size, 0); - // Let FFmpeg handle presentation timestamp reordering. - codec_context_->reordered_opaque = buffer.timestamp().InMicroseconds(); + const int64_t timestamp = buffer.timestamp().InMicroseconds(); + const TimestampId timestamp_id = timestamp_id_generator_.GenerateNextId(); + timestamp_map_.Put(std::make_pair(timestamp_id, timestamp)); + packet->opaque = reinterpret_cast(timestamp_id.GetUnsafeValue()); } FFmpegDecodingLoop::DecodeStatus decode_status = decoding_loop_->DecodePacket( packet, base::BindRepeating(&FFmpegVideoDecoder::OnNewFrame, @@ -423,7 +425,12 @@ bool FFmpegVideoDecoder::OnNewFrame(AVFrame* frame) { } gfx::Size natural_size = aspect_ratio.GetNaturalSize(visible_rect); - const auto pts = base::Microseconds(frame->reordered_opaque); + const auto ts_id = TimestampId(reinterpret_cast(frame->opaque)); + const auto ts_lookup = timestamp_map_.Get(ts_id); + if (ts_lookup == timestamp_map_.end()) { + return false; + } + const auto pts = base::Microseconds(std::get<1>(*ts_lookup)); auto video_frame = VideoFrame::WrapExternalDataWithLayout( opaque->layout, visible_rect, natural_size, opaque->data, opaque->size, pts); @@ -498,8 +505,10 @@ bool FFmpegVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config, codec_context_->thread_count = GetFFmpegVideoDecoderThreadCount(config); codec_context_->thread_type = FF_THREAD_SLICE | (low_delay ? 0 : FF_THREAD_FRAME); + codec_context_->opaque = this; codec_context_->get_buffer2 = GetVideoBufferImpl; + codec_context_->flags |= AV_CODEC_FLAG_COPY_OPAQUE; if (base::FeatureList::IsEnabled(kFFmpegAllowLists)) { // Note: FFmpeg will try to free this string, so we must duplicate it. diff --git a/media/filters/ffmpeg_video_decoder.h b/media/filters/ffmpeg_video_decoder.h index d02cb89c3ddf7..0a2de1c623fff 100644 --- a/media/filters/ffmpeg_video_decoder.h +++ b/media/filters/ffmpeg_video_decoder.h @@ -7,10 +7,12 @@ #include +#include "base/containers/lru_cache.h" #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/sequence_checker.h" +#include "base/types/id_type.h" #include "media/base/frame_buffer_pool.h" #include "media/base/supported_video_decoder_config.h" #include "media/base/video_decoder.h" @@ -87,6 +89,20 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder { // FFmpeg structures owned by this object. std::unique_ptr codec_context_; + // The gist here is that timestamps need to be 64 bits to store microsecond + // precision. A 32 bit integer would overflow at ~35 minutes at this level of + // precision. We can't cast the timestamp to the void ptr object used by the + // opaque field in ffmpeg then, because it would lose data on a 32 bit build. + // However, we don't actually have 2^31 timestamped frames in a single + // playback, so it's fine to use the 32 bit value as a key in a map which + // contains the actual timestamps. Additionally, we've in the past set 128 + // outstanding frames for re-ordering as a limit for cross-thread decoding + // tasks, so we'll do that here too with the LRU cache. + using TimestampId = base::IdType; + + TimestampId::Generator timestamp_id_generator_; + base::LRUCache timestamp_map_; + VideoDecoderConfig config_; scoped_refptr frame_pool_;