소스 검색

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
Stephan Vedder 1 년 전
부모
커밋
1f55cc942d

+ 85 - 0
Userland/Libraries/LibVideo/CodecID.h

@@ -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);
+    }
+};
+}

+ 3 - 0
Userland/Libraries/LibVideo/Containers/Demuxer.h

@@ -8,6 +8,7 @@
 
 
 #include <AK/NonnullOwnPtr.h>
 #include <AK/NonnullOwnPtr.h>
 #include <LibCore/EventReceiver.h>
 #include <LibCore/EventReceiver.h>
+#include <LibVideo/CodecID.h>
 #include <LibVideo/DecoderError.h>
 #include <LibVideo/DecoderError.h>
 #include <LibVideo/Sample.h>
 #include <LibVideo/Sample.h>
 #include <LibVideo/Track.h>
 #include <LibVideo/Track.h>
@@ -28,6 +29,8 @@ public:
         return sample.release_nonnull<VideoSample>();
         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.
     // 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
     // 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.
     // in the case that the timestamp is closer to the current time than the nearest keyframe.

+ 32 - 0
Userland/Libraries/LibVideo/Containers/Matroska/MatroskaDemuxer.cpp

@@ -71,6 +71,32 @@ DecoderErrorOr<MatroskaDemuxer::TrackStatus*> MatroskaDemuxer::get_track_status(
     return &m_track_statuses.get(track).release_value();
     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)
 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.
     // 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());
     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);
+}
+
 }
 }

+ 3 - 0
Userland/Libraries/LibVideo/Containers/Matroska/MatroskaDemuxer.h

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

+ 12 - 2
Userland/Libraries/LibVideo/PlaybackManager.cpp

@@ -52,9 +52,19 @@ DecoderErrorOr<NonnullOwnPtr<PlaybackManager>> PlaybackManager::create(NonnullOw
 
 
     dbgln_if(PLAYBACK_MANAGER_DEBUG, "Selecting video track number {}", track.identifier());
     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 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(); }));
     playback_manager->m_state_update_timer = DECODER_TRY_ALLOC(Core::Timer::create_single_shot(0, [&self = *playback_manager] { self.timer_callback(); }));