From a659c555045e360be86136a4f3f8a7ee295808b0 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Tue, 5 May 2026 11:29:14 +0200 Subject: [PATCH] LibMedia: Make video frames ref-counted Video frames are about to be shared between the decoder, the data provider, the display sink, and Web painting code. Passing them by value keeps ownership tied to the old bitmap-shaped pipeline and makes later lifetime changes harder to reason about. Make VideoFrame ref-counted and return NonnullRefPtr from the decoder and media queues. This changes ownership only: a VideoFrame still wraps an ImmutableBitmap at this point, so playback behavior remains unchanged while later commits can move storage and painting independently. --- Libraries/LibMedia/FFmpeg/FFmpegVideoDecoder.cpp | 4 ++-- Libraries/LibMedia/FFmpeg/FFmpegVideoDecoder.h | 2 +- Libraries/LibMedia/Providers/VideoDataProvider.cpp | 4 ++-- Libraries/LibMedia/Providers/VideoDataProvider.h | 2 +- Libraries/LibMedia/VideoDecoder.h | 3 ++- Libraries/LibMedia/VideoFrame.h | 3 ++- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Libraries/LibMedia/FFmpeg/FFmpegVideoDecoder.cpp b/Libraries/LibMedia/FFmpeg/FFmpegVideoDecoder.cpp index 711cd96755..cf653a834b 100644 --- a/Libraries/LibMedia/FFmpeg/FFmpegVideoDecoder.cpp +++ b/Libraries/LibMedia/FFmpeg/FFmpegVideoDecoder.cpp @@ -144,7 +144,7 @@ void FFmpegVideoDecoder::signal_end_of_stream() VERIFY(result == 0 || result == AVERROR_EOF); } -DecoderErrorOr> FFmpegVideoDecoder::get_decoded_frame(CodingIndependentCodePoints const& container_cicp) +DecoderErrorOr> FFmpegVideoDecoder::get_decoded_frame(CodingIndependentCodePoints const& container_cicp) { auto result = avcodec_receive_frame(m_codec_context, m_frame); @@ -249,7 +249,7 @@ DecoderErrorOr> FFmpegVideoDecoder::get_decoded_frame( auto bitmap = DECODER_TRY_ALLOC(Gfx::ImmutableBitmap::create_from_yuv(move(yuv_data))); - return DECODER_TRY_ALLOC(try_make(timestamp, duration, size, bit_depth, cicp, move(bitmap))); + return DECODER_TRY_ALLOC(try_make_ref_counted(timestamp, duration, size, bit_depth, cicp, move(bitmap))); } case AVERROR(EAGAIN): return DecoderError::with_description(DecoderErrorCategory::NeedsMoreInput, "FFmpeg decoder has no frames available, send more input"sv); diff --git a/Libraries/LibMedia/FFmpeg/FFmpegVideoDecoder.h b/Libraries/LibMedia/FFmpeg/FFmpegVideoDecoder.h index c99302e4cd..5fbeb5a7da 100644 --- a/Libraries/LibMedia/FFmpeg/FFmpegVideoDecoder.h +++ b/Libraries/LibMedia/FFmpeg/FFmpegVideoDecoder.h @@ -22,7 +22,7 @@ public: virtual DecoderErrorOr receive_coded_data(AK::Duration timestamp, AK::Duration duration, ReadonlyBytes coded_data) override; virtual void signal_end_of_stream() override; - virtual DecoderErrorOr> get_decoded_frame(CodingIndependentCodePoints const& container_cicp) override; + virtual DecoderErrorOr> get_decoded_frame(CodingIndependentCodePoints const& container_cicp) override; virtual void flush() override; diff --git a/Libraries/LibMedia/Providers/VideoDataProvider.cpp b/Libraries/LibMedia/Providers/VideoDataProvider.cpp index 24e769a3cd..18cb1c6f6d 100644 --- a/Libraries/LibMedia/Providers/VideoDataProvider.cpp +++ b/Libraries/LibMedia/Providers/VideoDataProvider.cpp @@ -281,7 +281,7 @@ void VideoDataProvider::ThreadData::dispatch_frame_end_time(CodedFrame const& fr }); } -void VideoDataProvider::ThreadData::queue_frame(NonnullOwnPtr const& frame) +void VideoDataProvider::ThreadData::queue_frame(NonnullRefPtr const& frame) { m_queue.enqueue(TimedImage(frame->timestamp(), frame->immutable_bitmap())); } @@ -391,7 +391,7 @@ bool VideoDataProvider::ThreadData::handle_seek() auto new_seek_id = m_seek_id.load(); auto found_desired_keyframe = false; - OwnPtr last_frame; + RefPtr last_frame; while (new_seek_id == seek_id) { auto coded_frame_result = m_demuxer->get_next_sample_for_track(m_track); diff --git a/Libraries/LibMedia/Providers/VideoDataProvider.h b/Libraries/LibMedia/Providers/VideoDataProvider.h index de3ff4566c..2fe76fbb38 100644 --- a/Libraries/LibMedia/Providers/VideoDataProvider.h +++ b/Libraries/LibMedia/Providers/VideoDataProvider.h @@ -90,7 +90,7 @@ private: template void invoke_on_main_thread(Invokee); void dispatch_frame_end_time(CodedFrame const&); - void queue_frame(NonnullOwnPtr const&); + void queue_frame(NonnullRefPtr const&); void dispatch_error(DecoderError&&); bool handle_seek(); template diff --git a/Libraries/LibMedia/VideoDecoder.h b/Libraries/LibMedia/VideoDecoder.h index 8c4781c83d..d04a4b1560 100644 --- a/Libraries/LibMedia/VideoDecoder.h +++ b/Libraries/LibMedia/VideoDecoder.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -22,7 +23,7 @@ public: virtual DecoderErrorOr receive_coded_data(AK::Duration timestamp, AK::Duration duration, ReadonlyBytes coded_data) = 0; DecoderErrorOr receive_coded_data(AK::Duration timestamp, AK::Duration duration, ByteBuffer const& coded_data) { return receive_coded_data(timestamp, duration, coded_data.span()); } virtual void signal_end_of_stream() = 0; - virtual DecoderErrorOr> get_decoded_frame(CodingIndependentCodePoints const& container_cicp) = 0; + virtual DecoderErrorOr> get_decoded_frame(CodingIndependentCodePoints const& container_cicp) = 0; virtual void flush() = 0; }; diff --git a/Libraries/LibMedia/VideoFrame.h b/Libraries/LibMedia/VideoFrame.h index ef58b49e70..9960b79b8c 100644 --- a/Libraries/LibMedia/VideoFrame.h +++ b/Libraries/LibMedia/VideoFrame.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -15,7 +16,7 @@ namespace Media { -class MEDIA_API VideoFrame final { +class MEDIA_API VideoFrame final : public AtomicRefCounted { public: VideoFrame(