LibMedia: Separate file duration from track duration in Demuxer

Most users will only care about the total file duration, and shouldn't
be required to determine the file duration from multiple track
durations. To facilitate that, add a total_duration() function that
returns the demuxer's duration not associated to any particular track.
This commit is contained in:
Zaggy1024 2025-09-11 18:37:06 -05:00 committed by Jelle Raaijmakers
commit ae7f82591b
Notes: github-actions[bot] 2025-09-12 09:25:06 +00:00
6 changed files with 25 additions and 16 deletions

View file

@ -4,7 +4,9 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Assertions.h>
#include <AK/Debug.h>
#include <LibMedia/DecoderError.h>
#include "MatroskaDemuxer.h"
@ -192,10 +194,15 @@ DecoderErrorOr<Sample> MatroskaDemuxer::get_next_sample_for_track(Track track)
return Sample(status.block->timestamp(), move(sample_data), VideoSampleData(cicp));
}
DecoderErrorOr<AK::Duration> MatroskaDemuxer::duration(Track)
DecoderErrorOr<AK::Duration> MatroskaDemuxer::total_duration()
{
auto duration = TRY(m_reader.segment_information()).duration();
return duration.value_or(AK::Duration::zero());
}
DecoderErrorOr<AK::Duration> MatroskaDemuxer::duration_of_track(Track const&)
{
return total_duration();
}
}

View file

@ -32,7 +32,8 @@ public:
DecoderErrorOr<Optional<AK::Duration>> seek_to_most_recent_keyframe(Track track, AK::Duration timestamp, Optional<AK::Duration> earliest_available_sample = OptionalNone()) override;
DecoderErrorOr<AK::Duration> duration(Track track) override;
DecoderErrorOr<AK::Duration> duration_of_track(Track const& track) override;
DecoderErrorOr<AK::Duration> total_duration() override;
DecoderErrorOr<CodecID> get_codec_id_for_track(Track track) override;

View file

@ -36,7 +36,8 @@ public:
// in the case that the timestamp is closer to the current time than the nearest keyframe.
virtual DecoderErrorOr<Optional<AK::Duration>> seek_to_most_recent_keyframe(Track track, AK::Duration timestamp, Optional<AK::Duration> earliest_available_sample = OptionalNone()) = 0;
virtual DecoderErrorOr<AK::Duration> duration(Track track) = 0;
virtual DecoderErrorOr<AK::Duration> duration_of_track(Track const&) = 0;
virtual DecoderErrorOr<AK::Duration> total_duration() = 0;
};
}

View file

@ -68,6 +68,15 @@ static inline AK::Duration time_units_to_duration(i64 time_units, AVRational con
return time_units_to_duration(time_units, time_base.num, time_base.den);
}
DecoderErrorOr<AK::Duration> FFmpegDemuxer::total_duration()
{
if (m_format_context->duration < 0) {
return DecoderError::format(DecoderErrorCategory::Unknown, "Negative stream duration");
}
return time_units_to_duration(m_format_context->duration, 1, AV_TIME_BASE);
}
DecoderErrorOr<AK::Duration> FFmpegDemuxer::duration_of_track(Track const& track)
{
VERIFY(track.identifier() < m_format_context->nb_streams);
@ -78,11 +87,7 @@ DecoderErrorOr<AK::Duration> FFmpegDemuxer::duration_of_track(Track const& track
}
// If the stream doesn't specify the duration, fallback to what the container says the duration is.
// If the container doesn't know the duration, then we're out of luck. Return an error.
if (m_format_context->duration < 0)
return DecoderError::format(DecoderErrorCategory::Unknown, "Negative stream duration");
return time_units_to_duration(m_format_context->duration, 1, AV_TIME_BASE);
return total_duration();
}
DecoderErrorOr<Track> FFmpegDemuxer::get_track_for_stream_index(u32 stream_index)
@ -144,11 +149,6 @@ DecoderErrorOr<Optional<AK::Duration>> FFmpegDemuxer::seek_to_most_recent_keyfra
return timestamp;
}
DecoderErrorOr<AK::Duration> FFmpegDemuxer::duration(Track track)
{
return duration_of_track(track);
}
DecoderErrorOr<CodecID> FFmpegDemuxer::get_codec_id_for_track(Track track)
{
VERIFY(track.identifier() < m_format_context->nb_streams);

View file

@ -30,7 +30,8 @@ public:
virtual DecoderErrorOr<Optional<AK::Duration>> seek_to_most_recent_keyframe(Track track, AK::Duration timestamp, Optional<AK::Duration> earliest_available_sample = OptionalNone()) override;
virtual DecoderErrorOr<AK::Duration> duration(Track track) override;
virtual DecoderErrorOr<AK::Duration> duration_of_track(Track const&) override;
virtual DecoderErrorOr<AK::Duration> total_duration() override;
virtual DecoderErrorOr<CodecID> get_codec_id_for_track(Track track) override;
@ -39,7 +40,6 @@ public:
virtual DecoderErrorOr<Sample> get_next_sample_for_track(Track track) override;
private:
DecoderErrorOr<AK::Duration> duration_of_track(Track const& track);
DecoderErrorOr<Track> get_track_for_stream_index(u32 stream_index);
NonnullOwnPtr<SeekableStream> m_stream;

View file

@ -90,7 +90,7 @@ AK::Duration PlaybackManager::duration()
{
auto duration_result = ({
auto demuxer_locker = Threading::MutexLocker(m_decoder_mutex);
m_demuxer->duration(m_selected_video_track);
m_demuxer->duration_of_track(m_selected_video_track);
});
if (duration_result.is_error()) {
dispatch_decoder_error(duration_result.release_error());