1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 05:54:58 +00:00

LibVideo: Add the concept of codec identifiers

This is required for detecting which decoder should be used.
Only a small subset of codecs identifiers is added for now
This commit is contained in:
Stephan Vedder 2023-11-22 14:48:06 +01:00 committed by Luke Wilde
parent ff48b7333c
commit 1f55cc942d
5 changed files with 135 additions and 2 deletions

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2023, Stephan Vedder <stephan.vedder@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Format.h>
namespace Video {
enum class CodecID : u32 {
Unknown,
// On2 / Google
VP8,
VP9,
// MPEG
H261,
MPEG1,
H262,
H263,
H264,
H265,
// AOMedia
AV1,
// Xiph
Theora,
Vorbis,
Opus,
};
}
namespace AK {
template<>
struct Formatter<Video::CodecID> : Formatter<StringView> {
ErrorOr<void> format(FormatBuilder& builder, Video::CodecID value)
{
StringView codec;
switch (value) {
case Video::CodecID::Unknown:
codec = "Unknown"sv;
break;
case Video::CodecID::VP8:
codec = "VP8"sv;
break;
case Video::CodecID::VP9:
codec = "VP9"sv;
break;
case Video::CodecID::H261:
codec = "H.261"sv;
break;
case Video::CodecID::H262:
codec = "H.262"sv;
break;
case Video::CodecID::H263:
codec = "H.263"sv;
break;
case Video::CodecID::H264:
codec = "H.264"sv;
break;
case Video::CodecID::H265:
codec = "H.265"sv;
break;
case Video::CodecID::MPEG1:
codec = "MPEG1"sv;
break;
case Video::CodecID::AV1:
codec = "AV1"sv;
break;
case Video::CodecID::Theora:
codec = "Theora"sv;
break;
case Video::CodecID::Vorbis:
codec = "Vorbis"sv;
break;
case Video::CodecID::Opus:
codec = "Opus"sv;
break;
}
return builder.put_string(codec);
}
};
}

View file

@ -8,6 +8,7 @@
#include <AK/NonnullOwnPtr.h>
#include <LibCore/EventReceiver.h>
#include <LibVideo/CodecID.h>
#include <LibVideo/DecoderError.h>
#include <LibVideo/Sample.h>
#include <LibVideo/Track.h>
@ -28,6 +29,8 @@ public:
return sample.release_nonnull<VideoSample>();
}
virtual DecoderErrorOr<CodecID> get_codec_id_for_track(Track track) = 0;
// Returns the timestamp of the keyframe that was seeked to.
// The value is `Optional` to allow the demuxer to decide not to seek so that it can keep its position
// in the case that the timestamp is closer to the current time than the nearest keyframe.

View file

@ -71,6 +71,32 @@ DecoderErrorOr<MatroskaDemuxer::TrackStatus*> MatroskaDemuxer::get_track_status(
return &m_track_statuses.get(track).release_value();
}
CodecID MatroskaDemuxer::get_codec_id_for_string(DeprecatedFlyString const& codec_id)
{
dbgln_if(MATROSKA_DEBUG, "Codec ID: {}", codec_id);
if (codec_id == "V_VP8")
return CodecID::VP8;
if (codec_id == "V_VP9")
return CodecID::VP9;
if (codec_id == "V_MPEG1")
return CodecID::MPEG1;
if (codec_id == "V_MPEG2")
return CodecID::H262;
if (codec_id == "V_MPEG4/ISO/AVC")
return CodecID::H264;
if (codec_id == "V_MPEGH/ISO/HEVC")
return CodecID::H265;
if (codec_id == "V_AV1")
return CodecID::AV1;
if (codec_id == "V_THEORA")
return CodecID::Theora;
if (codec_id == "A_VORBIS")
return CodecID::Vorbis;
if (codec_id == "A_OPUS")
return CodecID::Opus;
return CodecID::Unknown;
}
DecoderErrorOr<Optional<Duration>> MatroskaDemuxer::seek_to_most_recent_keyframe(Track track, Duration timestamp, Optional<Duration> earliest_available_sample)
{
// Removing the track status will cause us to start from the beginning.
@ -119,4 +145,10 @@ DecoderErrorOr<Duration> MatroskaDemuxer::duration()
return duration.value_or(Duration::zero());
}
DecoderErrorOr<CodecID> MatroskaDemuxer::get_codec_id_for_track(Track track)
{
auto codec_id = TRY(m_reader.track_for_track_number(track.identifier())).codec_id();
return get_codec_id_for_string(codec_id);
}
}

View file

@ -33,6 +33,8 @@ public:
DecoderErrorOr<Duration> duration() override;
DecoderErrorOr<CodecID> get_codec_id_for_track(Track track) override;
protected:
DecoderErrorOr<NonnullOwnPtr<Sample>> get_next_sample_for_track(Track track) override;
@ -44,6 +46,7 @@ private:
};
DecoderErrorOr<TrackStatus*> get_track_status(Track track);
CodecID get_codec_id_for_string(DeprecatedFlyString const& codec_id);
Reader m_reader;

View file

@ -52,9 +52,19 @@ DecoderErrorOr<NonnullOwnPtr<PlaybackManager>> PlaybackManager::create(NonnullOw
dbgln_if(PLAYBACK_MANAGER_DEBUG, "Selecting video track number {}", track.identifier());
auto decoder = DECODER_TRY_ALLOC(try_make<VP9::Decoder>());
auto codec_id = TRY(demuxer->get_codec_id_for_track(track));
OwnPtr<VideoDecoder> decoder;
switch (codec_id) {
case CodecID::VP9:
decoder = DECODER_TRY_ALLOC(try_make<VP9::Decoder>());
break;
default:
return DecoderError::format(DecoderErrorCategory::Invalid, "Unsupported codec: {}", codec_id);
}
auto decoder_non_null = decoder.release_nonnull();
auto frame_queue = DECODER_TRY_ALLOC(VideoFrameQueue::create());
auto playback_manager = DECODER_TRY_ALLOC(try_make<PlaybackManager>(demuxer, track, move(decoder), move(frame_queue)));
auto playback_manager = DECODER_TRY_ALLOC(try_make<PlaybackManager>(demuxer, track, move(decoder_non_null), move(frame_queue)));
playback_manager->m_state_update_timer = DECODER_TRY_ALLOC(Core::Timer::create_single_shot(0, [&self = *playback_manager] { self.timer_callback(); }));