MatroskaDemuxer.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /*
  2. * Copyright (c) 2022, Gregory Bertilson <zaggy1024@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "MatroskaDemuxer.h"
  7. namespace Video::Matroska {
  8. DecoderErrorOr<NonnullOwnPtr<MatroskaDemuxer>> MatroskaDemuxer::from_file(StringView filename)
  9. {
  10. return make<MatroskaDemuxer>(TRY(Reader::parse_matroska_from_file(filename)));
  11. }
  12. DecoderErrorOr<NonnullOwnPtr<MatroskaDemuxer>> MatroskaDemuxer::from_data(ReadonlyBytes data)
  13. {
  14. return make<MatroskaDemuxer>(TRY(Reader::parse_matroska_from_data(data)));
  15. }
  16. Vector<Track> MatroskaDemuxer::get_tracks_for_type(TrackType type)
  17. {
  18. TrackEntry::TrackType matroska_track_type;
  19. switch (type) {
  20. case TrackType::Video:
  21. matroska_track_type = TrackEntry::TrackType::Video;
  22. break;
  23. case TrackType::Audio:
  24. matroska_track_type = TrackEntry::TrackType::Audio;
  25. break;
  26. case TrackType::Subtitles:
  27. matroska_track_type = TrackEntry::TrackType::Subtitle;
  28. break;
  29. }
  30. Vector<Track> tracks;
  31. for (auto const& track_table_entry : m_document->tracks()) {
  32. auto const& track_entry = track_table_entry.value;
  33. if (matroska_track_type == track_entry->track_type())
  34. tracks.append(Track(type, track_entry->track_number()));
  35. }
  36. // FIXME: Sort the vector, presumably the hashtable will not have a consistent order.
  37. return tracks;
  38. }
  39. ErrorOr<MatroskaDemuxer::TrackStatus*> MatroskaDemuxer::get_track_status(Track track)
  40. {
  41. if (!m_track_statuses.contains(track))
  42. TRY(m_track_statuses.try_set(track, TrackStatus()));
  43. return &m_track_statuses.get(track).release_value();
  44. }
  45. DecoderErrorOr<void> MatroskaDemuxer::seek_to_most_recent_keyframe(Track track, size_t timestamp)
  46. {
  47. if (timestamp == 0) {
  48. auto track_status = DECODER_TRY_ALLOC(get_track_status(track));
  49. track_status->m_cluster_index = 0;
  50. track_status->m_block_index = 0;
  51. track_status->m_frame_index = 0;
  52. return {};
  53. }
  54. return DecoderError::not_implemented();
  55. }
  56. DecoderErrorOr<NonnullOwnPtr<Sample>> MatroskaDemuxer::get_next_sample_for_track(Track track)
  57. {
  58. auto track_status = DECODER_TRY_ALLOC(get_track_status(track));
  59. for (; track_status->m_cluster_index < m_document->clusters().size(); track_status->m_cluster_index++) {
  60. auto const& cluster = m_document->clusters()[track_status->m_cluster_index];
  61. for (; track_status->m_block_index < cluster.blocks().size(); track_status->m_block_index++) {
  62. auto const& block = cluster.blocks()[track_status->m_block_index];
  63. if (block.track_number() != track.identifier())
  64. continue;
  65. if (track_status->m_frame_index < block.frame_count()) {
  66. switch (track.type()) {
  67. case TrackType::Video: {
  68. // FIXME: This makes a copy of the sample, which shouldn't be necessary.
  69. // Matroska should make a RefPtr<ByteBuffer>, probably.
  70. auto cicp = m_document->track_for_track_number(track.identifier())->video_track()->color_format.to_cicp();
  71. Time timestamp = Time::from_nanoseconds((cluster.timestamp() + block.timestamp()) * m_document->segment_information()->timestamp_scale());
  72. return make<VideoSample>(block.frame(track_status->m_frame_index++), cicp, timestamp);
  73. }
  74. default:
  75. return DecoderError::not_implemented();
  76. }
  77. }
  78. track_status->m_frame_index = 0;
  79. }
  80. track_status->m_block_index = 0;
  81. }
  82. return DecoderError::with_description(DecoderErrorCategory::EndOfStream, "End of stream reached."sv);
  83. }
  84. Time MatroskaDemuxer::duration()
  85. {
  86. if (!m_document->segment_information().has_value())
  87. return Time::zero();
  88. if (!m_document->segment_information()->duration().has_value())
  89. return Time::zero();
  90. return Time::from_nanoseconds(m_document->segment_information()->duration().value() * m_document->segment_information()->timestamp_scale());
  91. }
  92. }