MatroskaDemuxer.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. * Copyright (c) 2022, Gregory Bertilson <zaggy1024@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "MatroskaDemuxer.h"
  7. #include "AK/Debug.h"
  8. namespace Video::Matroska {
  9. DecoderErrorOr<NonnullOwnPtr<MatroskaDemuxer>> MatroskaDemuxer::from_file(StringView filename)
  10. {
  11. return make<MatroskaDemuxer>(TRY(Reader::from_file(filename)));
  12. }
  13. DecoderErrorOr<NonnullOwnPtr<MatroskaDemuxer>> MatroskaDemuxer::from_mapped_file(NonnullRefPtr<Core::MappedFile> mapped_file)
  14. {
  15. return make<MatroskaDemuxer>(TRY(Reader::from_mapped_file(move(mapped_file))));
  16. }
  17. DecoderErrorOr<NonnullOwnPtr<MatroskaDemuxer>> MatroskaDemuxer::from_data(ReadonlyBytes data)
  18. {
  19. return make<MatroskaDemuxer>(TRY(Reader::from_data(data)));
  20. }
  21. DecoderErrorOr<Vector<Track>> MatroskaDemuxer::get_tracks_for_type(TrackType type)
  22. {
  23. TrackEntry::TrackType matroska_track_type;
  24. switch (type) {
  25. case TrackType::Video:
  26. matroska_track_type = TrackEntry::TrackType::Video;
  27. break;
  28. case TrackType::Audio:
  29. matroska_track_type = TrackEntry::TrackType::Audio;
  30. break;
  31. case TrackType::Subtitles:
  32. matroska_track_type = TrackEntry::TrackType::Subtitle;
  33. break;
  34. }
  35. Vector<Track> tracks;
  36. TRY(m_reader.for_each_track_of_type(matroska_track_type, [&](TrackEntry const& track_entry) -> DecoderErrorOr<IterationDecision> {
  37. VERIFY(track_entry.track_type() == matroska_track_type);
  38. Track track(type, track_entry.track_number());
  39. switch (type) {
  40. case TrackType::Video:
  41. if (auto video_track = track_entry.video_track(); video_track.has_value())
  42. track.set_video_data({ TRY(duration()), video_track->pixel_width, video_track->pixel_height });
  43. break;
  44. default:
  45. break;
  46. }
  47. DECODER_TRY_ALLOC(tracks.try_append(track));
  48. return IterationDecision::Continue;
  49. }));
  50. return tracks;
  51. }
  52. DecoderErrorOr<MatroskaDemuxer::TrackStatus*> MatroskaDemuxer::get_track_status(Track track)
  53. {
  54. if (!m_track_statuses.contains(track)) {
  55. auto iterator = TRY(m_reader.create_sample_iterator(track.identifier()));
  56. DECODER_TRY_ALLOC(m_track_statuses.try_set(track, { iterator }));
  57. }
  58. return &m_track_statuses.get(track).release_value();
  59. }
  60. DecoderErrorOr<Optional<Time>> MatroskaDemuxer::seek_to_most_recent_keyframe(Track track, Time timestamp, Optional<Time> earliest_available_sample)
  61. {
  62. // Removing the track status will cause us to start from the beginning.
  63. if (timestamp.is_zero()) {
  64. m_track_statuses.remove(track);
  65. return timestamp;
  66. }
  67. auto& track_status = *TRY(get_track_status(track));
  68. auto seeked_iterator = TRY(m_reader.seek_to_random_access_point(track_status.iterator, timestamp));
  69. VERIFY(seeked_iterator.last_timestamp().has_value());
  70. auto last_sample = earliest_available_sample;
  71. if (!last_sample.has_value()) {
  72. last_sample = track_status.iterator.last_timestamp();
  73. }
  74. if (last_sample.has_value()) {
  75. bool skip_seek = seeked_iterator.last_timestamp().value() <= last_sample.value() && last_sample.value() <= timestamp;
  76. 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);
  77. if (skip_seek) {
  78. return OptionalNone();
  79. }
  80. }
  81. track_status.iterator = move(seeked_iterator);
  82. return track_status.iterator.last_timestamp();
  83. }
  84. DecoderErrorOr<NonnullOwnPtr<Sample>> MatroskaDemuxer::get_next_sample_for_track(Track track)
  85. {
  86. // FIXME: This makes a copy of the sample, which shouldn't be necessary.
  87. // Matroska should make a RefPtr<ByteBuffer>, probably.
  88. auto& status = *TRY(get_track_status(track));
  89. if (!status.block.has_value() || status.frame_index >= status.block->frame_count()) {
  90. status.block = TRY(status.iterator.next_block());
  91. status.frame_index = 0;
  92. }
  93. auto cicp = TRY(m_reader.track_for_track_number(track.identifier())).video_track()->color_format.to_cicp();
  94. return make<VideoSample>(status.block->frame(status.frame_index++), cicp, status.block->timestamp());
  95. }
  96. DecoderErrorOr<Time> MatroskaDemuxer::duration()
  97. {
  98. auto duration = TRY(m_reader.segment_information()).duration();
  99. return duration.value_or(Time::zero());
  100. }
  101. }