Shaka Packager SDK
seek_head.cc
1 // Copyright 2015 Google Inc. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include "packager/media/formats/webm/seek_head.h"
8 
9 #include <algorithm>
10 #include <limits>
11 
12 #include "packager/base/logging.h"
13 #include "packager/third_party/libwebm/src/mkvmuxerutil.hpp"
14 #include "packager/third_party/libwebm/src/webmids.hpp"
15 
16 namespace shaka {
17 namespace media {
18 namespace {
19 
20 // Cluster, Cues, Info, Tracks.
21 const size_t kElementIdCount = 4u;
22 
23 uint64_t EbmlMasterElementWithPayloadSize(mkvmuxer::MkvId id, uint64_t payload_size) {
24  return EbmlMasterElementSize(id, payload_size) + payload_size;
25 }
26 
27 uint64_t MaxSeekEntrySize() {
28  const uint64_t max_entry_payload_size =
29  EbmlElementSize(
30  mkvmuxer::kMkvSeekID,
31  static_cast<mkvmuxer::uint64>(std::numeric_limits<uint32_t>::max())) +
32  EbmlElementSize(mkvmuxer::kMkvSeekPosition,
33  std::numeric_limits<mkvmuxer::uint64>::max());
34  return EbmlMasterElementWithPayloadSize(mkvmuxer::kMkvSeek,
35  max_entry_payload_size);
36 }
37 
38 } // namespace
39 
40 SeekHead::SeekHead()
41  : total_void_size_(EbmlMasterElementWithPayloadSize(
42  mkvmuxer::kMkvSeekHead,
43  kElementIdCount * MaxSeekEntrySize())) {}
44 
45 SeekHead::~SeekHead() {}
46 
47 bool SeekHead::Write(mkvmuxer::IMkvWriter* writer) {
48  std::vector<SeekElement> seek_elements = CreateSeekElements();
49  if (seek_elements.empty())
50  return true;
51 
52  uint64_t payload_size = 0;
53  for (const SeekHead::SeekElement& seek_element : seek_elements) {
54  payload_size +=
55  EbmlMasterElementWithPayloadSize(mkvmuxer::kMkvSeek, seek_element.size);
56  }
57 
58  const int64_t start_pos = writer->Position();
59  if (!WriteEbmlMasterElement(writer, mkvmuxer::kMkvSeekHead, payload_size))
60  return false;
61 
62  for (const SeekHead::SeekElement& element : seek_elements) {
63  if (!WriteEbmlMasterElement(writer, mkvmuxer::kMkvSeek, element.size) ||
64  !WriteEbmlElement(writer, mkvmuxer::kMkvSeekID, element.id) ||
65  !WriteEbmlElement(writer, mkvmuxer::kMkvSeekPosition, element.position))
66  return false;
67  }
68 
69  // If we wrote void before, then fill in the extra with void.
70  if (wrote_void_) {
71  const uint64_t extra_void =
72  total_void_size_ - (writer->Position() - start_pos);
73  if (!WriteVoidElement(writer, extra_void))
74  return false;
75  }
76 
77  return true;
78 }
79 
80 bool SeekHead::WriteVoid(mkvmuxer::IMkvWriter* writer) {
81  const uint64_t written = WriteVoidElement(writer, total_void_size_);
82  if (!written)
83  return false;
84  wrote_void_ = true;
85  return true;
86 }
87 
88 std::vector<SeekHead::SeekElement> SeekHead::CreateSeekElements() {
89  std::vector<SeekHead::SeekElement> seek_elements;
90  if (info_pos_ != 0)
91  seek_elements.emplace_back(mkvmuxer::kMkvInfo, info_pos_);
92  if (tracks_pos_ != 0)
93  seek_elements.emplace_back(mkvmuxer::kMkvTracks, tracks_pos_);
94  if (cues_pos_ != 0)
95  seek_elements.emplace_back(mkvmuxer::kMkvCues, cues_pos_);
96  if (cluster_pos_ != 0)
97  seek_elements.emplace_back(mkvmuxer::kMkvCluster, cluster_pos_);
98  DCHECK_LE(seek_elements.size(), kElementIdCount);
99 
100  std::sort(seek_elements.begin(), seek_elements.end(),
101  [](const SeekHead::SeekElement& left,
102  const SeekHead::SeekElement& right) {
103  return left.position < right.position;
104  });
105  for (SeekHead::SeekElement& element : seek_elements) {
106  element.size =
107  EbmlElementSize(mkvmuxer::kMkvSeekID, element.id) +
108  EbmlElementSize(mkvmuxer::kMkvSeekPosition, element.position);
109  }
110  return seek_elements;
111 }
112 
113 } // namespace media
114 } // namespace shaka
shaka::media::SeekHead::Write
bool Write(mkvmuxer::IMkvWriter *writer)
Definition: seek_head.cc:47
shaka
All the methods that are virtual are virtual for mocking.
Definition: gflags_hex_bytes.cc:11
shaka::media::SeekHead::WriteVoid
bool WriteVoid(mkvmuxer::IMkvWriter *writer)
Writes a void element large enough to fit the SeekHead.
Definition: seek_head.cc:80