2022-10-29 17:02:43 -05:00
/*
* Copyright ( c ) 2022 , Gregory Bertilson < zaggy1024 @ gmail . com >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "MatroskaDemuxer.h"
2023-06-01 16:17:13 +02:00
# include <AK/Debug.h>
2022-10-29 17:02:43 -05:00
2022-11-09 19:47:56 -06:00
namespace Video : : Matroska {
2022-10-29 17:02:43 -05:00
DecoderErrorOr < NonnullOwnPtr < MatroskaDemuxer > > MatroskaDemuxer : : from_file ( StringView filename )
{
2022-11-11 17:14:27 -06:00
return make < MatroskaDemuxer > ( TRY ( Reader : : from_file ( filename ) ) ) ;
2022-10-29 17:02:43 -05:00
}
2023-05-11 12:25:52 +01:00
DecoderErrorOr < NonnullOwnPtr < MatroskaDemuxer > > MatroskaDemuxer : : from_mapped_file ( NonnullRefPtr < Core : : MappedFile > mapped_file )
{
return make < MatroskaDemuxer > ( TRY ( Reader : : from_mapped_file ( move ( mapped_file ) ) ) ) ;
}
2022-11-04 18:00:09 -05:00
DecoderErrorOr < NonnullOwnPtr < MatroskaDemuxer > > MatroskaDemuxer : : from_data ( ReadonlyBytes data )
2022-10-29 17:02:43 -05:00
{
2022-11-11 17:14:27 -06:00
return make < MatroskaDemuxer > ( TRY ( Reader : : from_data ( data ) ) ) ;
2022-10-29 17:02:43 -05:00
}
2022-11-11 17:14:27 -06:00
DecoderErrorOr < Vector < Track > > MatroskaDemuxer : : get_tracks_for_type ( TrackType type )
2022-10-29 17:02:43 -05:00
{
2022-11-09 19:47:56 -06:00
TrackEntry : : TrackType matroska_track_type ;
2022-10-29 17:02:43 -05:00
switch ( type ) {
case TrackType : : Video :
2022-11-09 19:47:56 -06:00
matroska_track_type = TrackEntry : : TrackType : : Video ;
2022-10-29 17:02:43 -05:00
break ;
case TrackType : : Audio :
2022-11-09 19:47:56 -06:00
matroska_track_type = TrackEntry : : TrackType : : Audio ;
2022-10-29 17:02:43 -05:00
break ;
case TrackType : : Subtitles :
2022-11-09 19:47:56 -06:00
matroska_track_type = TrackEntry : : TrackType : : Subtitle ;
2022-10-29 17:02:43 -05:00
break ;
}
Vector < Track > tracks ;
2022-11-11 17:14:27 -06:00
TRY ( m_reader . for_each_track_of_type ( matroska_track_type , [ & ] ( TrackEntry const & track_entry ) - > DecoderErrorOr < IterationDecision > {
VERIFY ( track_entry . track_type ( ) = = matroska_track_type ) ;
2023-04-04 13:18:35 -04:00
Track track ( type , track_entry . track_number ( ) ) ;
switch ( type ) {
case TrackType : : Video :
if ( auto video_track = track_entry . video_track ( ) ; video_track . has_value ( ) )
track . set_video_data ( { TRY ( duration ( ) ) , video_track - > pixel_width , video_track - > pixel_height } ) ;
break ;
default :
break ;
}
DECODER_TRY_ALLOC ( tracks . try_append ( track ) ) ;
2022-11-11 17:14:27 -06:00
return IterationDecision : : Continue ;
} ) ) ;
2023-04-04 13:18:35 -04:00
2022-10-29 17:02:43 -05:00
return tracks ;
}
2022-11-11 17:14:27 -06:00
DecoderErrorOr < MatroskaDemuxer : : TrackStatus * > MatroskaDemuxer : : get_track_status ( Track track )
2022-10-29 17:02:43 -05:00
{
2022-11-11 17:14:27 -06:00
if ( ! m_track_statuses . contains ( track ) ) {
auto iterator = TRY ( m_reader . create_sample_iterator ( track . identifier ( ) ) ) ;
DECODER_TRY_ALLOC ( m_track_statuses . try_set ( track , { iterator } ) ) ;
}
2022-10-29 17:02:43 -05:00
return & m_track_statuses . get ( track ) . release_value ( ) ;
}
2023-03-13 16:30:34 +01:00
DecoderErrorOr < Optional < Duration > > MatroskaDemuxer : : seek_to_most_recent_keyframe ( Track track , Duration timestamp , Optional < Duration > earliest_available_sample )
2022-10-29 17:02:43 -05:00
{
2022-11-14 00:54:21 -06:00
// Removing the track status will cause us to start from the beginning.
2022-11-12 04:04:13 -06:00
if ( timestamp . is_zero ( ) ) {
m_track_statuses . remove ( track ) ;
2022-11-13 20:33:23 -06:00
return timestamp ;
2022-11-12 04:04:13 -06:00
}
auto & track_status = * TRY ( get_track_status ( track ) ) ;
2023-02-06 01:25:02 -06:00
auto seeked_iterator = TRY ( m_reader . seek_to_random_access_point ( track_status . iterator , timestamp ) ) ;
VERIFY ( seeked_iterator . last_timestamp ( ) . has_value ( ) ) ;
auto last_sample = earliest_available_sample ;
if ( ! last_sample . has_value ( ) ) {
last_sample = track_status . iterator . last_timestamp ( ) ;
}
if ( last_sample . has_value ( ) ) {
bool skip_seek = seeked_iterator . last_timestamp ( ) . value ( ) < = last_sample . value ( ) & & last_sample . value ( ) < = timestamp ;
dbgln_if ( MATROSKA_DEBUG , " The last available sample at {}ms is {}closer to target timestamp {}ms than the keyframe at {}ms, {} " , last_sample - > to_milliseconds ( ) , skip_seek ? " " sv : " not " sv , timestamp . to_milliseconds ( ) , seeked_iterator . last_timestamp ( ) - > to_milliseconds ( ) , skip_seek ? " skipping seek " sv : " seeking " sv ) ;
if ( skip_seek ) {
return OptionalNone ( ) ;
}
}
track_status . iterator = move ( seeked_iterator ) ;
2022-11-13 20:33:23 -06:00
return track_status . iterator . last_timestamp ( ) ;
2022-10-29 17:02:43 -05:00
}
DecoderErrorOr < NonnullOwnPtr < Sample > > MatroskaDemuxer : : get_next_sample_for_track ( Track track )
{
2022-11-11 17:14:27 -06:00
// FIXME: This makes a copy of the sample, which shouldn't be necessary.
// Matroska should make a RefPtr<ByteBuffer>, probably.
auto & status = * TRY ( get_track_status ( track ) ) ;
2022-10-29 17:02:43 -05:00
2022-11-11 17:14:27 -06:00
if ( ! status . block . has_value ( ) | | status . frame_index > = status . block - > frame_count ( ) ) {
status . block = TRY ( status . iterator . next_block ( ) ) ;
status . frame_index = 0 ;
2022-10-29 17:02:43 -05:00
}
2022-11-11 17:14:27 -06:00
auto cicp = TRY ( m_reader . track_for_track_number ( track . identifier ( ) ) ) . video_track ( ) - > color_format . to_cicp ( ) ;
2022-11-12 02:28:15 -06:00
return make < VideoSample > ( status . block - > frame ( status . frame_index + + ) , cicp , status . block - > timestamp ( ) ) ;
2022-10-29 17:02:43 -05:00
}
2023-03-13 16:30:34 +01:00
DecoderErrorOr < Duration > MatroskaDemuxer : : duration ( )
2022-10-29 17:02:43 -05:00
{
2022-11-13 19:13:50 -06:00
auto duration = TRY ( m_reader . segment_information ( ) ) . duration ( ) ;
2023-03-13 16:30:34 +01:00
return duration . value_or ( Duration : : zero ( ) ) ;
2022-10-29 17:02:43 -05:00
}
}