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.
This commit is contained in:
Aliaksandr Kalenik 2026-05-05 11:29:14 +02:00 committed by Gregory Bertilson
parent ee4f9ef82c
commit a659c55504
6 changed files with 10 additions and 8 deletions

View file

@ -144,7 +144,7 @@ void FFmpegVideoDecoder::signal_end_of_stream()
VERIFY(result == 0 || result == AVERROR_EOF);
}
DecoderErrorOr<NonnullOwnPtr<VideoFrame>> FFmpegVideoDecoder::get_decoded_frame(CodingIndependentCodePoints const& container_cicp)
DecoderErrorOr<NonnullRefPtr<VideoFrame>> FFmpegVideoDecoder::get_decoded_frame(CodingIndependentCodePoints const& container_cicp)
{
auto result = avcodec_receive_frame(m_codec_context, m_frame);
@ -249,7 +249,7 @@ DecoderErrorOr<NonnullOwnPtr<VideoFrame>> FFmpegVideoDecoder::get_decoded_frame(
auto bitmap = DECODER_TRY_ALLOC(Gfx::ImmutableBitmap::create_from_yuv(move(yuv_data)));
return DECODER_TRY_ALLOC(try_make<VideoFrame>(timestamp, duration, size, bit_depth, cicp, move(bitmap)));
return DECODER_TRY_ALLOC(try_make_ref_counted<VideoFrame>(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);

View file

@ -22,7 +22,7 @@ public:
virtual DecoderErrorOr<void> receive_coded_data(AK::Duration timestamp, AK::Duration duration, ReadonlyBytes coded_data) override;
virtual void signal_end_of_stream() override;
virtual DecoderErrorOr<NonnullOwnPtr<VideoFrame>> get_decoded_frame(CodingIndependentCodePoints const& container_cicp) override;
virtual DecoderErrorOr<NonnullRefPtr<VideoFrame>> get_decoded_frame(CodingIndependentCodePoints const& container_cicp) override;
virtual void flush() override;

View file

@ -281,7 +281,7 @@ void VideoDataProvider::ThreadData::dispatch_frame_end_time(CodedFrame const& fr
});
}
void VideoDataProvider::ThreadData::queue_frame(NonnullOwnPtr<VideoFrame> const& frame)
void VideoDataProvider::ThreadData::queue_frame(NonnullRefPtr<VideoFrame> 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<VideoFrame> last_frame;
RefPtr<VideoFrame> last_frame;
while (new_seek_id == seek_id) {
auto coded_frame_result = m_demuxer->get_next_sample_for_track(m_track);

View file

@ -90,7 +90,7 @@ private:
template<typename Invokee>
void invoke_on_main_thread(Invokee);
void dispatch_frame_end_time(CodedFrame const&);
void queue_frame(NonnullOwnPtr<VideoFrame> const&);
void queue_frame(NonnullRefPtr<VideoFrame> const&);
void dispatch_error(DecoderError&&);
bool handle_seek();
template<typename Callback>

View file

@ -8,6 +8,7 @@
#include <AK/ByteBuffer.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/NonnullRefPtr.h>
#include <AK/Time.h>
#include <LibMedia/Color/CodingIndependentCodePoints.h>
@ -22,7 +23,7 @@ public:
virtual DecoderErrorOr<void> receive_coded_data(AK::Duration timestamp, AK::Duration duration, ReadonlyBytes coded_data) = 0;
DecoderErrorOr<void> 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<NonnullOwnPtr<VideoFrame>> get_decoded_frame(CodingIndependentCodePoints const& container_cicp) = 0;
virtual DecoderErrorOr<NonnullRefPtr<VideoFrame>> get_decoded_frame(CodingIndependentCodePoints const& container_cicp) = 0;
virtual void flush() = 0;
};

View file

@ -6,6 +6,7 @@
#pragma once
#include <AK/AtomicRefCounted.h>
#include <AK/NonnullRefPtr.h>
#include <AK/Time.h>
#include <LibGfx/Forward.h>
@ -15,7 +16,7 @@
namespace Media {
class MEDIA_API VideoFrame final {
class MEDIA_API VideoFrame final : public AtomicRefCounted<VideoFrame> {
public:
VideoFrame(