LibMedia+LibWeb: Align Media::Track more to the web spec

...giving tracks a kind attribute, and renaming name to label.

Demuxers will need to determine the kind attribute, since the spec for
sourcing tracks requires us to select based on info we don't expose.
This commit is contained in:
Zaggy1024 2026-03-25 15:48:00 -05:00 committed by Gregory Bertilson
parent 9664c11c15
commit b4db8f11c5
6 changed files with 65 additions and 26 deletions

View file

@ -68,6 +68,8 @@ static TrackType track_type_from_matroska_track_type(TrackEntry::TrackType type)
static Track track_from_track_entry(TrackEntry const& track_entry)
{
// FIXME: Set the kind correctly.
auto kind = Track::Kind::None;
auto name = Utf16String::from_utf8(track_entry.name());
auto language = [&] {
// LanguageBCP47 - The language of the track, in the BCP47 form; see basics on language codes. If this Element is used,
@ -76,7 +78,7 @@ static Track track_from_track_entry(TrackEntry const& track_entry)
return Utf16String::from_utf8(track_entry.language_bcp_47().value());
return Utf16String::from_utf8(track_entry.language());
}();
Track track(track_type_from_matroska_track_type(track_entry.track_type()), track_entry.track_number(), name, language);
Track track(track_type_from_matroska_track_type(track_entry.track_type()), track_entry.track_number(), kind, name, language);
if (track.type() == TrackType::Video) {
auto video_track = track_entry.video_track();

View file

@ -57,9 +57,11 @@ static DecoderErrorOr<Track> create_track_from_stream(AVStream const& stream)
return Utf16String();
return Utf16String::from_utf8(StringView(name_entry->value, strlen(name_entry->value)));
};
// FIXME: Set the kind correctly.
auto kind = Track::Kind::None;
auto name = get_string_metadata("title");
auto language = get_string_metadata("language");
Track track(type, stream.index, name, language);
Track track(type, stream.index, kind, name, language);
if (type == TrackType::Video) {
auto color_primaries = static_cast<ColorPrimaries>(stream.codecpar->color_primaries);

View file

@ -6,6 +6,7 @@
#pragma once
#include <AK/Assertions.h>
#include <AK/HashFunctions.h>
#include <AK/Time.h>
#include <AK/Traits.h>
@ -19,6 +20,7 @@
namespace Media {
class Track {
public:
struct VideoData {
u64 pixel_width { 0 };
u64 pixel_height { 0 };
@ -29,11 +31,27 @@ class Track {
Audio::SampleSpecification sample_specification;
};
public:
Track(TrackType type, size_t identifier, Utf16String const& name, Utf16String const& language)
// Derived from the "kind" attributes in:
// https://dev.w3.org/html5/html-sourcing-inband-tracks/
enum class Kind : u8 {
None,
Alternative,
Captions,
Descriptions,
Main,
MainDesc,
Metadata,
Sign,
Subtitles,
Translation,
Commentary,
};
Track(TrackType type, size_t identifier, Kind kind, Utf16String const& label, Utf16String const& language)
: m_type(type)
, m_identifier(identifier)
, m_name(name)
, m_kind(kind)
, m_label(label)
, m_language(language)
{
switch (m_type) {
@ -51,7 +69,8 @@ public:
TrackType type() const { return m_type; }
size_t identifier() const { return m_identifier; }
Utf16String const& name() const { return m_name; }
Kind kind() const { return m_kind; }
Utf16String const& label() const { return m_label; }
Utf16String const& language() const { return m_language; }
void set_video_data(VideoData data)
@ -91,12 +110,42 @@ public:
private:
TrackType m_type { 0 };
size_t m_identifier { 0 };
Utf16String m_name;
Kind m_kind { Kind::None };
Utf16String m_label;
Utf16String m_language;
Variant<Empty, VideoData, AudioData> m_track_data;
};
constexpr Utf16View track_kind_to_string(Track::Kind kind)
{
switch (kind) {
case Track::Kind::None:
return u""sv;
case Track::Kind::Alternative:
return u"alternative"sv;
case Track::Kind::Captions:
return u"captions"sv;
case Track::Kind::Descriptions:
return u"descriptions"sv;
case Track::Kind::Main:
return u"main"sv;
case Track::Kind::MainDesc:
return u"maindesc"sv;
case Track::Kind::Metadata:
return u"metadata"sv;
case Track::Kind::Sign:
return u"sign"sv;
case Track::Kind::Subtitles:
return u"subtitles"sv;
case Track::Kind::Translation:
return u"translation"sv;
case Track::Kind::Commentary:
return u"commentary"sv;
}
VERIFY_NOT_REACHED();
}
}
template<>

View file

@ -1377,18 +1377,6 @@ void HTMLMediaElement::on_audio_track_added(Media::Track const& track)
if (enable == TriState::True)
audio_track->set_enabled(true);
// NB: According to https://dev.w3.org/html5/html-sourcing-inband-tracks/, kind should be set according to format, and the following criteria within
// the specified formats.
// WebM:
// - "main": the FlagDefault element is set on the track
// - "translation": not first audio (video) track
// MP4:
// - "main": first audio (video) track
// - "translation": not first audio (video) track
// Though the behavior for WebM is not clear if its first track is not marked with FlagDefault, the idea here seems to be that the preferred
// track should be marked as "main", and the rest should be marked as "translation".
audio_track->set_kind(enable == TriState::True ? "main"_utf16 : "translation"_utf16);
// 7. Fire an event named addtrack at this AudioTrackList object, using TrackEvent, with the track attribute initialized to the new AudioTrack object.
TrackEventInit event_init {};
event_init.track = GC::make_root(audio_track);
@ -1432,9 +1420,6 @@ void HTMLMediaElement::on_video_track_added(Media::Track const& track)
if (enable == TriState::True)
video_track->set_selected(true);
// NB: See the comment regarding AudioTrack.kind above with regard to https://dev.w3.org/html5/html-sourcing-inband-tracks/.
video_track->set_kind(enable == TriState::True ? "main"_utf16 : "translation"_utf16);
// 7. Fire an event named addtrack at this VideoTrackList object, using TrackEvent, with the track attribute initialized to the new VideoTrack object.
TrackEventInit event_init {};
event_init.track = GC::make_root(video_track);

View file

@ -15,7 +15,8 @@ MediaTrackBase::MediaTrackBase(JS::Realm& realm, GC::Ref<HTMLMediaElement> media
, m_media_element(media_element)
, m_track_in_playback_manager(track)
, m_id(Utf16String::number(track.identifier()))
, m_label(track.name())
, m_kind(track.kind())
, m_label(track.label())
{
// https://html.spec.whatwg.org/multipage/media.html#dom-audiotrack-language
// https://html.spec.whatwg.org/multipage/media.html#dom-videotrack-language

View file

@ -22,8 +22,8 @@ public:
Media::Track const& track_in_playback_manager() const { return m_track_in_playback_manager; }
Utf16String const& id() const { return m_id; }
Utf16String const& kind() const { return m_kind; }
void set_kind(Utf16String const& kind) { m_kind = kind; }
Utf16View kind() const { return Media::track_kind_to_string(m_kind); }
void set_kind(Media::Track::Kind kind) { m_kind = kind; }
Utf16String const& label() const { return m_label; }
Utf16String const& language() const { return m_language; }
@ -43,7 +43,7 @@ private:
// https://html.spec.whatwg.org/multipage/media.html#dom-audiotrack-kind
// https://html.spec.whatwg.org/multipage/media.html#dom-videotrack-kind
Utf16String m_kind;
Media::Track::Kind m_kind;
// https://html.spec.whatwg.org/multipage/media.html#dom-audiotrack-label
// https://html.spec.whatwg.org/multipage/media.html#dom-videotrack-label