xref: /aosp_15_r20/external/libwebm/mkvmuxer/mkvmuxer.cc (revision 103e46e4cd4b6efcf6001f23fa8665fb110abf8d)
1*103e46e4SHarish Mahendrakar // Copyright (c) 2012 The WebM project authors. All Rights Reserved.
2*103e46e4SHarish Mahendrakar //
3*103e46e4SHarish Mahendrakar // Use of this source code is governed by a BSD-style license
4*103e46e4SHarish Mahendrakar // that can be found in the LICENSE file in the root of the source
5*103e46e4SHarish Mahendrakar // tree. An additional intellectual property rights grant can be found
6*103e46e4SHarish Mahendrakar // in the file PATENTS.  All contributing project authors may
7*103e46e4SHarish Mahendrakar // be found in the AUTHORS file in the root of the source tree.
8*103e46e4SHarish Mahendrakar 
9*103e46e4SHarish Mahendrakar #include "mkvmuxer/mkvmuxer.h"
10*103e46e4SHarish Mahendrakar 
11*103e46e4SHarish Mahendrakar #include <stdint.h>
12*103e46e4SHarish Mahendrakar 
13*103e46e4SHarish Mahendrakar #include <cfloat>
14*103e46e4SHarish Mahendrakar #include <climits>
15*103e46e4SHarish Mahendrakar #include <cstdio>
16*103e46e4SHarish Mahendrakar #include <cstdlib>
17*103e46e4SHarish Mahendrakar #include <cstring>
18*103e46e4SHarish Mahendrakar #include <ctime>
19*103e46e4SHarish Mahendrakar #include <memory>
20*103e46e4SHarish Mahendrakar #include <new>
21*103e46e4SHarish Mahendrakar #include <string>
22*103e46e4SHarish Mahendrakar #include <vector>
23*103e46e4SHarish Mahendrakar 
24*103e46e4SHarish Mahendrakar #include "common/webmids.h"
25*103e46e4SHarish Mahendrakar #include "mkvmuxer/mkvmuxerutil.h"
26*103e46e4SHarish Mahendrakar #include "mkvmuxer/mkvwriter.h"
27*103e46e4SHarish Mahendrakar #include "mkvparser/mkvparser.h"
28*103e46e4SHarish Mahendrakar 
29*103e46e4SHarish Mahendrakar namespace mkvmuxer {
30*103e46e4SHarish Mahendrakar 
31*103e46e4SHarish Mahendrakar const float PrimaryChromaticity::kChromaticityMin = 0.0f;
32*103e46e4SHarish Mahendrakar const float PrimaryChromaticity::kChromaticityMax = 1.0f;
33*103e46e4SHarish Mahendrakar const float MasteringMetadata::kMinLuminance = 0.0f;
34*103e46e4SHarish Mahendrakar const float MasteringMetadata::kMinLuminanceMax = 999.99f;
35*103e46e4SHarish Mahendrakar const float MasteringMetadata::kMaxLuminanceMax = 9999.99f;
36*103e46e4SHarish Mahendrakar const float MasteringMetadata::kValueNotPresent = FLT_MAX;
37*103e46e4SHarish Mahendrakar const uint64_t Colour::kValueNotPresent = UINT64_MAX;
38*103e46e4SHarish Mahendrakar 
39*103e46e4SHarish Mahendrakar namespace {
40*103e46e4SHarish Mahendrakar 
41*103e46e4SHarish Mahendrakar const char kDocTypeWebm[] = "webm";
42*103e46e4SHarish Mahendrakar const char kDocTypeMatroska[] = "matroska";
43*103e46e4SHarish Mahendrakar 
44*103e46e4SHarish Mahendrakar // Deallocate the string designated by |dst|, and then copy the |src|
45*103e46e4SHarish Mahendrakar // string to |dst|.  The caller owns both the |src| string and the
46*103e46e4SHarish Mahendrakar // |dst| copy (hence the caller is responsible for eventually
47*103e46e4SHarish Mahendrakar // deallocating the strings, either directly, or indirectly via
48*103e46e4SHarish Mahendrakar // StrCpy).  Returns true if the source string was successfully copied
49*103e46e4SHarish Mahendrakar // to the destination.
StrCpy(const char * src,char ** dst_ptr)50*103e46e4SHarish Mahendrakar bool StrCpy(const char* src, char** dst_ptr) {
51*103e46e4SHarish Mahendrakar   if (dst_ptr == NULL)
52*103e46e4SHarish Mahendrakar     return false;
53*103e46e4SHarish Mahendrakar 
54*103e46e4SHarish Mahendrakar   char*& dst = *dst_ptr;
55*103e46e4SHarish Mahendrakar 
56*103e46e4SHarish Mahendrakar   delete[] dst;
57*103e46e4SHarish Mahendrakar   dst = NULL;
58*103e46e4SHarish Mahendrakar 
59*103e46e4SHarish Mahendrakar   if (src == NULL)
60*103e46e4SHarish Mahendrakar     return true;
61*103e46e4SHarish Mahendrakar 
62*103e46e4SHarish Mahendrakar   const size_t size = strlen(src) + 1;
63*103e46e4SHarish Mahendrakar 
64*103e46e4SHarish Mahendrakar   dst = new (std::nothrow) char[size];  // NOLINT
65*103e46e4SHarish Mahendrakar   if (dst == NULL)
66*103e46e4SHarish Mahendrakar     return false;
67*103e46e4SHarish Mahendrakar 
68*103e46e4SHarish Mahendrakar   memcpy(dst, src, size - 1);
69*103e46e4SHarish Mahendrakar   dst[size - 1] = '\0';
70*103e46e4SHarish Mahendrakar   return true;
71*103e46e4SHarish Mahendrakar }
72*103e46e4SHarish Mahendrakar 
73*103e46e4SHarish Mahendrakar typedef std::unique_ptr<PrimaryChromaticity> PrimaryChromaticityPtr;
CopyChromaticity(const PrimaryChromaticity * src,PrimaryChromaticityPtr * dst)74*103e46e4SHarish Mahendrakar bool CopyChromaticity(const PrimaryChromaticity* src,
75*103e46e4SHarish Mahendrakar                       PrimaryChromaticityPtr* dst) {
76*103e46e4SHarish Mahendrakar   if (!dst)
77*103e46e4SHarish Mahendrakar     return false;
78*103e46e4SHarish Mahendrakar 
79*103e46e4SHarish Mahendrakar   dst->reset(new (std::nothrow) PrimaryChromaticity(src->x(), src->y()));
80*103e46e4SHarish Mahendrakar   if (!dst->get())
81*103e46e4SHarish Mahendrakar     return false;
82*103e46e4SHarish Mahendrakar 
83*103e46e4SHarish Mahendrakar   return true;
84*103e46e4SHarish Mahendrakar }
85*103e46e4SHarish Mahendrakar 
86*103e46e4SHarish Mahendrakar }  // namespace
87*103e46e4SHarish Mahendrakar 
88*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
89*103e46e4SHarish Mahendrakar //
90*103e46e4SHarish Mahendrakar // IMkvWriter Class
91*103e46e4SHarish Mahendrakar 
IMkvWriter()92*103e46e4SHarish Mahendrakar IMkvWriter::IMkvWriter() {}
93*103e46e4SHarish Mahendrakar 
~IMkvWriter()94*103e46e4SHarish Mahendrakar IMkvWriter::~IMkvWriter() {}
95*103e46e4SHarish Mahendrakar 
WriteEbmlHeader(IMkvWriter * writer,uint64_t doc_type_version,const char * const doc_type)96*103e46e4SHarish Mahendrakar bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version,
97*103e46e4SHarish Mahendrakar                      const char* const doc_type) {
98*103e46e4SHarish Mahendrakar   // Level 0
99*103e46e4SHarish Mahendrakar   uint64_t size =
100*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvEBMLVersion, static_cast<uint64>(1));
101*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvEBMLReadVersion, static_cast<uint64>(1));
102*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvEBMLMaxIDLength, static_cast<uint64>(4));
103*103e46e4SHarish Mahendrakar   size +=
104*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvEBMLMaxSizeLength, static_cast<uint64>(8));
105*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvDocType, doc_type);
106*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvDocTypeVersion,
107*103e46e4SHarish Mahendrakar                           static_cast<uint64>(doc_type_version));
108*103e46e4SHarish Mahendrakar   size +=
109*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvDocTypeReadVersion, static_cast<uint64>(2));
110*103e46e4SHarish Mahendrakar 
111*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvEBML, size))
112*103e46e4SHarish Mahendrakar     return false;
113*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvEBMLVersion,
114*103e46e4SHarish Mahendrakar                         static_cast<uint64>(1))) {
115*103e46e4SHarish Mahendrakar     return false;
116*103e46e4SHarish Mahendrakar   }
117*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvEBMLReadVersion,
118*103e46e4SHarish Mahendrakar                         static_cast<uint64>(1))) {
119*103e46e4SHarish Mahendrakar     return false;
120*103e46e4SHarish Mahendrakar   }
121*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxIDLength,
122*103e46e4SHarish Mahendrakar                         static_cast<uint64>(4))) {
123*103e46e4SHarish Mahendrakar     return false;
124*103e46e4SHarish Mahendrakar   }
125*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxSizeLength,
126*103e46e4SHarish Mahendrakar                         static_cast<uint64>(8))) {
127*103e46e4SHarish Mahendrakar     return false;
128*103e46e4SHarish Mahendrakar   }
129*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvDocType, doc_type))
130*103e46e4SHarish Mahendrakar     return false;
131*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeVersion,
132*103e46e4SHarish Mahendrakar                         static_cast<uint64>(doc_type_version))) {
133*103e46e4SHarish Mahendrakar     return false;
134*103e46e4SHarish Mahendrakar   }
135*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeReadVersion,
136*103e46e4SHarish Mahendrakar                         static_cast<uint64>(2))) {
137*103e46e4SHarish Mahendrakar     return false;
138*103e46e4SHarish Mahendrakar   }
139*103e46e4SHarish Mahendrakar 
140*103e46e4SHarish Mahendrakar   return true;
141*103e46e4SHarish Mahendrakar }
142*103e46e4SHarish Mahendrakar 
WriteEbmlHeader(IMkvWriter * writer,uint64_t doc_type_version)143*103e46e4SHarish Mahendrakar bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version) {
144*103e46e4SHarish Mahendrakar   return WriteEbmlHeader(writer, doc_type_version, kDocTypeWebm);
145*103e46e4SHarish Mahendrakar }
146*103e46e4SHarish Mahendrakar 
WriteEbmlHeader(IMkvWriter * writer)147*103e46e4SHarish Mahendrakar bool WriteEbmlHeader(IMkvWriter* writer) {
148*103e46e4SHarish Mahendrakar   return WriteEbmlHeader(writer, mkvmuxer::Segment::kDefaultDocTypeVersion);
149*103e46e4SHarish Mahendrakar }
150*103e46e4SHarish Mahendrakar 
ChunkedCopy(mkvparser::IMkvReader * source,mkvmuxer::IMkvWriter * dst,int64_t start,int64_t size)151*103e46e4SHarish Mahendrakar bool ChunkedCopy(mkvparser::IMkvReader* source, mkvmuxer::IMkvWriter* dst,
152*103e46e4SHarish Mahendrakar                  int64_t start, int64_t size) {
153*103e46e4SHarish Mahendrakar   // TODO(vigneshv): Check if this is a reasonable value.
154*103e46e4SHarish Mahendrakar   const uint32_t kBufSize = 2048;
155*103e46e4SHarish Mahendrakar   uint8_t* buf = new uint8_t[kBufSize];
156*103e46e4SHarish Mahendrakar   int64_t offset = start;
157*103e46e4SHarish Mahendrakar   while (size > 0) {
158*103e46e4SHarish Mahendrakar     const int64_t read_len = (size > kBufSize) ? kBufSize : size;
159*103e46e4SHarish Mahendrakar     if (source->Read(offset, static_cast<long>(read_len), buf))
160*103e46e4SHarish Mahendrakar       return false;
161*103e46e4SHarish Mahendrakar     dst->Write(buf, static_cast<uint32_t>(read_len));
162*103e46e4SHarish Mahendrakar     offset += read_len;
163*103e46e4SHarish Mahendrakar     size -= read_len;
164*103e46e4SHarish Mahendrakar   }
165*103e46e4SHarish Mahendrakar   delete[] buf;
166*103e46e4SHarish Mahendrakar   return true;
167*103e46e4SHarish Mahendrakar }
168*103e46e4SHarish Mahendrakar 
169*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
170*103e46e4SHarish Mahendrakar //
171*103e46e4SHarish Mahendrakar // Frame Class
172*103e46e4SHarish Mahendrakar 
Frame()173*103e46e4SHarish Mahendrakar Frame::Frame()
174*103e46e4SHarish Mahendrakar     : add_id_(0),
175*103e46e4SHarish Mahendrakar       additional_(NULL),
176*103e46e4SHarish Mahendrakar       additional_length_(0),
177*103e46e4SHarish Mahendrakar       duration_(0),
178*103e46e4SHarish Mahendrakar       duration_set_(false),
179*103e46e4SHarish Mahendrakar       frame_(NULL),
180*103e46e4SHarish Mahendrakar       is_key_(false),
181*103e46e4SHarish Mahendrakar       length_(0),
182*103e46e4SHarish Mahendrakar       track_number_(0),
183*103e46e4SHarish Mahendrakar       timestamp_(0),
184*103e46e4SHarish Mahendrakar       discard_padding_(0),
185*103e46e4SHarish Mahendrakar       reference_block_timestamp_(0),
186*103e46e4SHarish Mahendrakar       reference_block_timestamp_set_(false) {}
187*103e46e4SHarish Mahendrakar 
~Frame()188*103e46e4SHarish Mahendrakar Frame::~Frame() {
189*103e46e4SHarish Mahendrakar   delete[] frame_;
190*103e46e4SHarish Mahendrakar   delete[] additional_;
191*103e46e4SHarish Mahendrakar }
192*103e46e4SHarish Mahendrakar 
CopyFrom(const Frame & frame)193*103e46e4SHarish Mahendrakar bool Frame::CopyFrom(const Frame& frame) {
194*103e46e4SHarish Mahendrakar   delete[] frame_;
195*103e46e4SHarish Mahendrakar   frame_ = NULL;
196*103e46e4SHarish Mahendrakar   length_ = 0;
197*103e46e4SHarish Mahendrakar   if (frame.length() > 0 && frame.frame() != NULL &&
198*103e46e4SHarish Mahendrakar       !Init(frame.frame(), frame.length())) {
199*103e46e4SHarish Mahendrakar     return false;
200*103e46e4SHarish Mahendrakar   }
201*103e46e4SHarish Mahendrakar   add_id_ = 0;
202*103e46e4SHarish Mahendrakar   delete[] additional_;
203*103e46e4SHarish Mahendrakar   additional_ = NULL;
204*103e46e4SHarish Mahendrakar   additional_length_ = 0;
205*103e46e4SHarish Mahendrakar   if (frame.additional_length() > 0 && frame.additional() != NULL &&
206*103e46e4SHarish Mahendrakar       !AddAdditionalData(frame.additional(), frame.additional_length(),
207*103e46e4SHarish Mahendrakar                          frame.add_id())) {
208*103e46e4SHarish Mahendrakar     return false;
209*103e46e4SHarish Mahendrakar   }
210*103e46e4SHarish Mahendrakar   duration_ = frame.duration();
211*103e46e4SHarish Mahendrakar   duration_set_ = frame.duration_set();
212*103e46e4SHarish Mahendrakar   is_key_ = frame.is_key();
213*103e46e4SHarish Mahendrakar   track_number_ = frame.track_number();
214*103e46e4SHarish Mahendrakar   timestamp_ = frame.timestamp();
215*103e46e4SHarish Mahendrakar   discard_padding_ = frame.discard_padding();
216*103e46e4SHarish Mahendrakar   reference_block_timestamp_ = frame.reference_block_timestamp();
217*103e46e4SHarish Mahendrakar   reference_block_timestamp_set_ = frame.reference_block_timestamp_set();
218*103e46e4SHarish Mahendrakar   return true;
219*103e46e4SHarish Mahendrakar }
220*103e46e4SHarish Mahendrakar 
Init(const uint8_t * frame,uint64_t length)221*103e46e4SHarish Mahendrakar bool Frame::Init(const uint8_t* frame, uint64_t length) {
222*103e46e4SHarish Mahendrakar   uint8_t* const data =
223*103e46e4SHarish Mahendrakar       new (std::nothrow) uint8_t[static_cast<size_t>(length)];  // NOLINT
224*103e46e4SHarish Mahendrakar   if (!data)
225*103e46e4SHarish Mahendrakar     return false;
226*103e46e4SHarish Mahendrakar 
227*103e46e4SHarish Mahendrakar   delete[] frame_;
228*103e46e4SHarish Mahendrakar   frame_ = data;
229*103e46e4SHarish Mahendrakar   length_ = length;
230*103e46e4SHarish Mahendrakar 
231*103e46e4SHarish Mahendrakar   memcpy(frame_, frame, static_cast<size_t>(length_));
232*103e46e4SHarish Mahendrakar   return true;
233*103e46e4SHarish Mahendrakar }
234*103e46e4SHarish Mahendrakar 
AddAdditionalData(const uint8_t * additional,uint64_t length,uint64_t add_id)235*103e46e4SHarish Mahendrakar bool Frame::AddAdditionalData(const uint8_t* additional, uint64_t length,
236*103e46e4SHarish Mahendrakar                               uint64_t add_id) {
237*103e46e4SHarish Mahendrakar   uint8_t* const data =
238*103e46e4SHarish Mahendrakar       new (std::nothrow) uint8_t[static_cast<size_t>(length)];  // NOLINT
239*103e46e4SHarish Mahendrakar   if (!data)
240*103e46e4SHarish Mahendrakar     return false;
241*103e46e4SHarish Mahendrakar 
242*103e46e4SHarish Mahendrakar   delete[] additional_;
243*103e46e4SHarish Mahendrakar   additional_ = data;
244*103e46e4SHarish Mahendrakar   additional_length_ = length;
245*103e46e4SHarish Mahendrakar   add_id_ = add_id;
246*103e46e4SHarish Mahendrakar 
247*103e46e4SHarish Mahendrakar   memcpy(additional_, additional, static_cast<size_t>(additional_length_));
248*103e46e4SHarish Mahendrakar   return true;
249*103e46e4SHarish Mahendrakar }
250*103e46e4SHarish Mahendrakar 
IsValid() const251*103e46e4SHarish Mahendrakar bool Frame::IsValid() const {
252*103e46e4SHarish Mahendrakar   if (length_ == 0 || !frame_) {
253*103e46e4SHarish Mahendrakar     return false;
254*103e46e4SHarish Mahendrakar   }
255*103e46e4SHarish Mahendrakar   if ((additional_length_ != 0 && !additional_) ||
256*103e46e4SHarish Mahendrakar       (additional_ != NULL && additional_length_ == 0)) {
257*103e46e4SHarish Mahendrakar     return false;
258*103e46e4SHarish Mahendrakar   }
259*103e46e4SHarish Mahendrakar   if (track_number_ == 0 || track_number_ > kMaxTrackNumber) {
260*103e46e4SHarish Mahendrakar     return false;
261*103e46e4SHarish Mahendrakar   }
262*103e46e4SHarish Mahendrakar   if (!CanBeSimpleBlock() && !is_key_ && !reference_block_timestamp_set_) {
263*103e46e4SHarish Mahendrakar     return false;
264*103e46e4SHarish Mahendrakar   }
265*103e46e4SHarish Mahendrakar   return true;
266*103e46e4SHarish Mahendrakar }
267*103e46e4SHarish Mahendrakar 
CanBeSimpleBlock() const268*103e46e4SHarish Mahendrakar bool Frame::CanBeSimpleBlock() const {
269*103e46e4SHarish Mahendrakar   return additional_ == NULL && discard_padding_ == 0 && duration_ == 0;
270*103e46e4SHarish Mahendrakar }
271*103e46e4SHarish Mahendrakar 
set_duration(uint64_t duration)272*103e46e4SHarish Mahendrakar void Frame::set_duration(uint64_t duration) {
273*103e46e4SHarish Mahendrakar   duration_ = duration;
274*103e46e4SHarish Mahendrakar   duration_set_ = true;
275*103e46e4SHarish Mahendrakar }
276*103e46e4SHarish Mahendrakar 
set_reference_block_timestamp(int64_t reference_block_timestamp)277*103e46e4SHarish Mahendrakar void Frame::set_reference_block_timestamp(int64_t reference_block_timestamp) {
278*103e46e4SHarish Mahendrakar   reference_block_timestamp_ = reference_block_timestamp;
279*103e46e4SHarish Mahendrakar   reference_block_timestamp_set_ = true;
280*103e46e4SHarish Mahendrakar }
281*103e46e4SHarish Mahendrakar 
282*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
283*103e46e4SHarish Mahendrakar //
284*103e46e4SHarish Mahendrakar // CuePoint Class
285*103e46e4SHarish Mahendrakar 
CuePoint()286*103e46e4SHarish Mahendrakar CuePoint::CuePoint()
287*103e46e4SHarish Mahendrakar     : time_(0),
288*103e46e4SHarish Mahendrakar       track_(0),
289*103e46e4SHarish Mahendrakar       cluster_pos_(0),
290*103e46e4SHarish Mahendrakar       block_number_(1),
291*103e46e4SHarish Mahendrakar       output_block_number_(true) {}
292*103e46e4SHarish Mahendrakar 
~CuePoint()293*103e46e4SHarish Mahendrakar CuePoint::~CuePoint() {}
294*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const295*103e46e4SHarish Mahendrakar bool CuePoint::Write(IMkvWriter* writer) const {
296*103e46e4SHarish Mahendrakar   if (!writer || track_ < 1 || cluster_pos_ < 1)
297*103e46e4SHarish Mahendrakar     return false;
298*103e46e4SHarish Mahendrakar 
299*103e46e4SHarish Mahendrakar   uint64_t size = EbmlElementSize(libwebm::kMkvCueClusterPosition,
300*103e46e4SHarish Mahendrakar                                   static_cast<uint64>(cluster_pos_));
301*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvCueTrack, static_cast<uint64>(track_));
302*103e46e4SHarish Mahendrakar   if (output_block_number_ && block_number_ > 1)
303*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvCueBlockNumber,
304*103e46e4SHarish Mahendrakar                             static_cast<uint64>(block_number_));
305*103e46e4SHarish Mahendrakar   const uint64_t track_pos_size =
306*103e46e4SHarish Mahendrakar       EbmlMasterElementSize(libwebm::kMkvCueTrackPositions, size) + size;
307*103e46e4SHarish Mahendrakar   const uint64_t payload_size =
308*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvCueTime, static_cast<uint64>(time_)) +
309*103e46e4SHarish Mahendrakar       track_pos_size;
310*103e46e4SHarish Mahendrakar 
311*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvCuePoint, payload_size))
312*103e46e4SHarish Mahendrakar     return false;
313*103e46e4SHarish Mahendrakar 
314*103e46e4SHarish Mahendrakar   const int64_t payload_position = writer->Position();
315*103e46e4SHarish Mahendrakar   if (payload_position < 0)
316*103e46e4SHarish Mahendrakar     return false;
317*103e46e4SHarish Mahendrakar 
318*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvCueTime,
319*103e46e4SHarish Mahendrakar                         static_cast<uint64>(time_))) {
320*103e46e4SHarish Mahendrakar     return false;
321*103e46e4SHarish Mahendrakar   }
322*103e46e4SHarish Mahendrakar 
323*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvCueTrackPositions, size))
324*103e46e4SHarish Mahendrakar     return false;
325*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvCueTrack,
326*103e46e4SHarish Mahendrakar                         static_cast<uint64>(track_))) {
327*103e46e4SHarish Mahendrakar     return false;
328*103e46e4SHarish Mahendrakar   }
329*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvCueClusterPosition,
330*103e46e4SHarish Mahendrakar                         static_cast<uint64>(cluster_pos_))) {
331*103e46e4SHarish Mahendrakar     return false;
332*103e46e4SHarish Mahendrakar   }
333*103e46e4SHarish Mahendrakar   if (output_block_number_ && block_number_ > 1) {
334*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvCueBlockNumber,
335*103e46e4SHarish Mahendrakar                           static_cast<uint64>(block_number_))) {
336*103e46e4SHarish Mahendrakar       return false;
337*103e46e4SHarish Mahendrakar     }
338*103e46e4SHarish Mahendrakar   }
339*103e46e4SHarish Mahendrakar 
340*103e46e4SHarish Mahendrakar   const int64_t stop_position = writer->Position();
341*103e46e4SHarish Mahendrakar   if (stop_position < 0)
342*103e46e4SHarish Mahendrakar     return false;
343*103e46e4SHarish Mahendrakar 
344*103e46e4SHarish Mahendrakar   if (stop_position - payload_position != static_cast<int64_t>(payload_size))
345*103e46e4SHarish Mahendrakar     return false;
346*103e46e4SHarish Mahendrakar 
347*103e46e4SHarish Mahendrakar   return true;
348*103e46e4SHarish Mahendrakar }
349*103e46e4SHarish Mahendrakar 
PayloadSize() const350*103e46e4SHarish Mahendrakar uint64_t CuePoint::PayloadSize() const {
351*103e46e4SHarish Mahendrakar   uint64_t size = EbmlElementSize(libwebm::kMkvCueClusterPosition,
352*103e46e4SHarish Mahendrakar                                   static_cast<uint64>(cluster_pos_));
353*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvCueTrack, static_cast<uint64>(track_));
354*103e46e4SHarish Mahendrakar   if (output_block_number_ && block_number_ > 1)
355*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvCueBlockNumber,
356*103e46e4SHarish Mahendrakar                             static_cast<uint64>(block_number_));
357*103e46e4SHarish Mahendrakar   const uint64_t track_pos_size =
358*103e46e4SHarish Mahendrakar       EbmlMasterElementSize(libwebm::kMkvCueTrackPositions, size) + size;
359*103e46e4SHarish Mahendrakar   const uint64_t payload_size =
360*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvCueTime, static_cast<uint64>(time_)) +
361*103e46e4SHarish Mahendrakar       track_pos_size;
362*103e46e4SHarish Mahendrakar 
363*103e46e4SHarish Mahendrakar   return payload_size;
364*103e46e4SHarish Mahendrakar }
365*103e46e4SHarish Mahendrakar 
Size() const366*103e46e4SHarish Mahendrakar uint64_t CuePoint::Size() const {
367*103e46e4SHarish Mahendrakar   const uint64_t payload_size = PayloadSize();
368*103e46e4SHarish Mahendrakar   return EbmlMasterElementSize(libwebm::kMkvCuePoint, payload_size) +
369*103e46e4SHarish Mahendrakar          payload_size;
370*103e46e4SHarish Mahendrakar }
371*103e46e4SHarish Mahendrakar 
372*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
373*103e46e4SHarish Mahendrakar //
374*103e46e4SHarish Mahendrakar // Cues Class
375*103e46e4SHarish Mahendrakar 
Cues()376*103e46e4SHarish Mahendrakar Cues::Cues()
377*103e46e4SHarish Mahendrakar     : cue_entries_capacity_(0),
378*103e46e4SHarish Mahendrakar       cue_entries_size_(0),
379*103e46e4SHarish Mahendrakar       cue_entries_(NULL),
380*103e46e4SHarish Mahendrakar       output_block_number_(true) {}
381*103e46e4SHarish Mahendrakar 
~Cues()382*103e46e4SHarish Mahendrakar Cues::~Cues() {
383*103e46e4SHarish Mahendrakar   if (cue_entries_) {
384*103e46e4SHarish Mahendrakar     for (int32_t i = 0; i < cue_entries_size_; ++i) {
385*103e46e4SHarish Mahendrakar       CuePoint* const cue = cue_entries_[i];
386*103e46e4SHarish Mahendrakar       delete cue;
387*103e46e4SHarish Mahendrakar     }
388*103e46e4SHarish Mahendrakar     delete[] cue_entries_;
389*103e46e4SHarish Mahendrakar   }
390*103e46e4SHarish Mahendrakar }
391*103e46e4SHarish Mahendrakar 
AddCue(CuePoint * cue)392*103e46e4SHarish Mahendrakar bool Cues::AddCue(CuePoint* cue) {
393*103e46e4SHarish Mahendrakar   if (!cue)
394*103e46e4SHarish Mahendrakar     return false;
395*103e46e4SHarish Mahendrakar 
396*103e46e4SHarish Mahendrakar   if ((cue_entries_size_ + 1) > cue_entries_capacity_) {
397*103e46e4SHarish Mahendrakar     // Add more CuePoints.
398*103e46e4SHarish Mahendrakar     const int32_t new_capacity =
399*103e46e4SHarish Mahendrakar         (!cue_entries_capacity_) ? 2 : cue_entries_capacity_ * 2;
400*103e46e4SHarish Mahendrakar 
401*103e46e4SHarish Mahendrakar     if (new_capacity < 1)
402*103e46e4SHarish Mahendrakar       return false;
403*103e46e4SHarish Mahendrakar 
404*103e46e4SHarish Mahendrakar     CuePoint** const cues =
405*103e46e4SHarish Mahendrakar         new (std::nothrow) CuePoint*[new_capacity];  // NOLINT
406*103e46e4SHarish Mahendrakar     if (!cues)
407*103e46e4SHarish Mahendrakar       return false;
408*103e46e4SHarish Mahendrakar 
409*103e46e4SHarish Mahendrakar     for (int32_t i = 0; i < cue_entries_size_; ++i) {
410*103e46e4SHarish Mahendrakar       cues[i] = cue_entries_[i];
411*103e46e4SHarish Mahendrakar     }
412*103e46e4SHarish Mahendrakar 
413*103e46e4SHarish Mahendrakar     delete[] cue_entries_;
414*103e46e4SHarish Mahendrakar 
415*103e46e4SHarish Mahendrakar     cue_entries_ = cues;
416*103e46e4SHarish Mahendrakar     cue_entries_capacity_ = new_capacity;
417*103e46e4SHarish Mahendrakar   }
418*103e46e4SHarish Mahendrakar 
419*103e46e4SHarish Mahendrakar   cue->set_output_block_number(output_block_number_);
420*103e46e4SHarish Mahendrakar   cue_entries_[cue_entries_size_++] = cue;
421*103e46e4SHarish Mahendrakar   return true;
422*103e46e4SHarish Mahendrakar }
423*103e46e4SHarish Mahendrakar 
GetCueByIndex(int32_t index) const424*103e46e4SHarish Mahendrakar CuePoint* Cues::GetCueByIndex(int32_t index) const {
425*103e46e4SHarish Mahendrakar   if (cue_entries_ == NULL)
426*103e46e4SHarish Mahendrakar     return NULL;
427*103e46e4SHarish Mahendrakar 
428*103e46e4SHarish Mahendrakar   if (index >= cue_entries_size_)
429*103e46e4SHarish Mahendrakar     return NULL;
430*103e46e4SHarish Mahendrakar 
431*103e46e4SHarish Mahendrakar   return cue_entries_[index];
432*103e46e4SHarish Mahendrakar }
433*103e46e4SHarish Mahendrakar 
Size()434*103e46e4SHarish Mahendrakar uint64_t Cues::Size() {
435*103e46e4SHarish Mahendrakar   uint64_t size = 0;
436*103e46e4SHarish Mahendrakar   for (int32_t i = 0; i < cue_entries_size_; ++i)
437*103e46e4SHarish Mahendrakar     size += GetCueByIndex(i)->Size();
438*103e46e4SHarish Mahendrakar   size += EbmlMasterElementSize(libwebm::kMkvCues, size);
439*103e46e4SHarish Mahendrakar   return size;
440*103e46e4SHarish Mahendrakar }
441*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const442*103e46e4SHarish Mahendrakar bool Cues::Write(IMkvWriter* writer) const {
443*103e46e4SHarish Mahendrakar   if (!writer)
444*103e46e4SHarish Mahendrakar     return false;
445*103e46e4SHarish Mahendrakar 
446*103e46e4SHarish Mahendrakar   uint64_t size = 0;
447*103e46e4SHarish Mahendrakar   for (int32_t i = 0; i < cue_entries_size_; ++i) {
448*103e46e4SHarish Mahendrakar     const CuePoint* const cue = GetCueByIndex(i);
449*103e46e4SHarish Mahendrakar 
450*103e46e4SHarish Mahendrakar     if (!cue)
451*103e46e4SHarish Mahendrakar       return false;
452*103e46e4SHarish Mahendrakar 
453*103e46e4SHarish Mahendrakar     size += cue->Size();
454*103e46e4SHarish Mahendrakar   }
455*103e46e4SHarish Mahendrakar 
456*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvCues, size))
457*103e46e4SHarish Mahendrakar     return false;
458*103e46e4SHarish Mahendrakar 
459*103e46e4SHarish Mahendrakar   const int64_t payload_position = writer->Position();
460*103e46e4SHarish Mahendrakar   if (payload_position < 0)
461*103e46e4SHarish Mahendrakar     return false;
462*103e46e4SHarish Mahendrakar 
463*103e46e4SHarish Mahendrakar   for (int32_t i = 0; i < cue_entries_size_; ++i) {
464*103e46e4SHarish Mahendrakar     const CuePoint* const cue = GetCueByIndex(i);
465*103e46e4SHarish Mahendrakar 
466*103e46e4SHarish Mahendrakar     if (!cue->Write(writer))
467*103e46e4SHarish Mahendrakar       return false;
468*103e46e4SHarish Mahendrakar   }
469*103e46e4SHarish Mahendrakar 
470*103e46e4SHarish Mahendrakar   const int64_t stop_position = writer->Position();
471*103e46e4SHarish Mahendrakar   if (stop_position < 0)
472*103e46e4SHarish Mahendrakar     return false;
473*103e46e4SHarish Mahendrakar 
474*103e46e4SHarish Mahendrakar   if (stop_position - payload_position != static_cast<int64_t>(size))
475*103e46e4SHarish Mahendrakar     return false;
476*103e46e4SHarish Mahendrakar 
477*103e46e4SHarish Mahendrakar   return true;
478*103e46e4SHarish Mahendrakar }
479*103e46e4SHarish Mahendrakar 
480*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
481*103e46e4SHarish Mahendrakar //
482*103e46e4SHarish Mahendrakar // ContentEncAESSettings Class
483*103e46e4SHarish Mahendrakar 
ContentEncAESSettings()484*103e46e4SHarish Mahendrakar ContentEncAESSettings::ContentEncAESSettings() : cipher_mode_(kCTR) {}
485*103e46e4SHarish Mahendrakar 
Size() const486*103e46e4SHarish Mahendrakar uint64_t ContentEncAESSettings::Size() const {
487*103e46e4SHarish Mahendrakar   const uint64_t payload = PayloadSize();
488*103e46e4SHarish Mahendrakar   const uint64_t size =
489*103e46e4SHarish Mahendrakar       EbmlMasterElementSize(libwebm::kMkvContentEncAESSettings, payload) +
490*103e46e4SHarish Mahendrakar       payload;
491*103e46e4SHarish Mahendrakar   return size;
492*103e46e4SHarish Mahendrakar }
493*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const494*103e46e4SHarish Mahendrakar bool ContentEncAESSettings::Write(IMkvWriter* writer) const {
495*103e46e4SHarish Mahendrakar   const uint64_t payload = PayloadSize();
496*103e46e4SHarish Mahendrakar 
497*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncAESSettings,
498*103e46e4SHarish Mahendrakar                               payload))
499*103e46e4SHarish Mahendrakar     return false;
500*103e46e4SHarish Mahendrakar 
501*103e46e4SHarish Mahendrakar   const int64_t payload_position = writer->Position();
502*103e46e4SHarish Mahendrakar   if (payload_position < 0)
503*103e46e4SHarish Mahendrakar     return false;
504*103e46e4SHarish Mahendrakar 
505*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvAESSettingsCipherMode,
506*103e46e4SHarish Mahendrakar                         static_cast<uint64>(cipher_mode_))) {
507*103e46e4SHarish Mahendrakar     return false;
508*103e46e4SHarish Mahendrakar   }
509*103e46e4SHarish Mahendrakar 
510*103e46e4SHarish Mahendrakar   const int64_t stop_position = writer->Position();
511*103e46e4SHarish Mahendrakar   if (stop_position < 0 ||
512*103e46e4SHarish Mahendrakar       stop_position - payload_position != static_cast<int64_t>(payload))
513*103e46e4SHarish Mahendrakar     return false;
514*103e46e4SHarish Mahendrakar 
515*103e46e4SHarish Mahendrakar   return true;
516*103e46e4SHarish Mahendrakar }
517*103e46e4SHarish Mahendrakar 
PayloadSize() const518*103e46e4SHarish Mahendrakar uint64_t ContentEncAESSettings::PayloadSize() const {
519*103e46e4SHarish Mahendrakar   uint64_t size = EbmlElementSize(libwebm::kMkvAESSettingsCipherMode,
520*103e46e4SHarish Mahendrakar                                   static_cast<uint64>(cipher_mode_));
521*103e46e4SHarish Mahendrakar   return size;
522*103e46e4SHarish Mahendrakar }
523*103e46e4SHarish Mahendrakar 
524*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
525*103e46e4SHarish Mahendrakar //
526*103e46e4SHarish Mahendrakar // ContentEncoding Class
527*103e46e4SHarish Mahendrakar 
ContentEncoding()528*103e46e4SHarish Mahendrakar ContentEncoding::ContentEncoding()
529*103e46e4SHarish Mahendrakar     : enc_algo_(5),
530*103e46e4SHarish Mahendrakar       enc_key_id_(NULL),
531*103e46e4SHarish Mahendrakar       encoding_order_(0),
532*103e46e4SHarish Mahendrakar       encoding_scope_(1),
533*103e46e4SHarish Mahendrakar       encoding_type_(1),
534*103e46e4SHarish Mahendrakar       enc_key_id_length_(0) {}
535*103e46e4SHarish Mahendrakar 
~ContentEncoding()536*103e46e4SHarish Mahendrakar ContentEncoding::~ContentEncoding() { delete[] enc_key_id_; }
537*103e46e4SHarish Mahendrakar 
SetEncryptionID(const uint8_t * id,uint64_t length)538*103e46e4SHarish Mahendrakar bool ContentEncoding::SetEncryptionID(const uint8_t* id, uint64_t length) {
539*103e46e4SHarish Mahendrakar   if (!id || length < 1)
540*103e46e4SHarish Mahendrakar     return false;
541*103e46e4SHarish Mahendrakar 
542*103e46e4SHarish Mahendrakar   delete[] enc_key_id_;
543*103e46e4SHarish Mahendrakar 
544*103e46e4SHarish Mahendrakar   enc_key_id_ =
545*103e46e4SHarish Mahendrakar       new (std::nothrow) uint8_t[static_cast<size_t>(length)];  // NOLINT
546*103e46e4SHarish Mahendrakar   if (!enc_key_id_)
547*103e46e4SHarish Mahendrakar     return false;
548*103e46e4SHarish Mahendrakar 
549*103e46e4SHarish Mahendrakar   memcpy(enc_key_id_, id, static_cast<size_t>(length));
550*103e46e4SHarish Mahendrakar   enc_key_id_length_ = length;
551*103e46e4SHarish Mahendrakar 
552*103e46e4SHarish Mahendrakar   return true;
553*103e46e4SHarish Mahendrakar }
554*103e46e4SHarish Mahendrakar 
Size() const555*103e46e4SHarish Mahendrakar uint64_t ContentEncoding::Size() const {
556*103e46e4SHarish Mahendrakar   const uint64_t encryption_size = EncryptionSize();
557*103e46e4SHarish Mahendrakar   const uint64_t encoding_size = EncodingSize(0, encryption_size);
558*103e46e4SHarish Mahendrakar   const uint64_t encodings_size =
559*103e46e4SHarish Mahendrakar       EbmlMasterElementSize(libwebm::kMkvContentEncoding, encoding_size) +
560*103e46e4SHarish Mahendrakar       encoding_size;
561*103e46e4SHarish Mahendrakar 
562*103e46e4SHarish Mahendrakar   return encodings_size;
563*103e46e4SHarish Mahendrakar }
564*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const565*103e46e4SHarish Mahendrakar bool ContentEncoding::Write(IMkvWriter* writer) const {
566*103e46e4SHarish Mahendrakar   const uint64_t encryption_size = EncryptionSize();
567*103e46e4SHarish Mahendrakar   const uint64_t encoding_size = EncodingSize(0, encryption_size);
568*103e46e4SHarish Mahendrakar   const uint64_t size =
569*103e46e4SHarish Mahendrakar       EbmlMasterElementSize(libwebm::kMkvContentEncoding, encoding_size) +
570*103e46e4SHarish Mahendrakar       encoding_size;
571*103e46e4SHarish Mahendrakar 
572*103e46e4SHarish Mahendrakar   const int64_t payload_position = writer->Position();
573*103e46e4SHarish Mahendrakar   if (payload_position < 0)
574*103e46e4SHarish Mahendrakar     return false;
575*103e46e4SHarish Mahendrakar 
576*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncoding,
577*103e46e4SHarish Mahendrakar                               encoding_size))
578*103e46e4SHarish Mahendrakar     return false;
579*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingOrder,
580*103e46e4SHarish Mahendrakar                         static_cast<uint64>(encoding_order_)))
581*103e46e4SHarish Mahendrakar     return false;
582*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingScope,
583*103e46e4SHarish Mahendrakar                         static_cast<uint64>(encoding_scope_)))
584*103e46e4SHarish Mahendrakar     return false;
585*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingType,
586*103e46e4SHarish Mahendrakar                         static_cast<uint64>(encoding_type_)))
587*103e46e4SHarish Mahendrakar     return false;
588*103e46e4SHarish Mahendrakar 
589*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncryption,
590*103e46e4SHarish Mahendrakar                               encryption_size))
591*103e46e4SHarish Mahendrakar     return false;
592*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvContentEncAlgo,
593*103e46e4SHarish Mahendrakar                         static_cast<uint64>(enc_algo_))) {
594*103e46e4SHarish Mahendrakar     return false;
595*103e46e4SHarish Mahendrakar   }
596*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvContentEncKeyID, enc_key_id_,
597*103e46e4SHarish Mahendrakar                         enc_key_id_length_))
598*103e46e4SHarish Mahendrakar     return false;
599*103e46e4SHarish Mahendrakar 
600*103e46e4SHarish Mahendrakar   if (!enc_aes_settings_.Write(writer))
601*103e46e4SHarish Mahendrakar     return false;
602*103e46e4SHarish Mahendrakar 
603*103e46e4SHarish Mahendrakar   const int64_t stop_position = writer->Position();
604*103e46e4SHarish Mahendrakar   if (stop_position < 0 ||
605*103e46e4SHarish Mahendrakar       stop_position - payload_position != static_cast<int64_t>(size))
606*103e46e4SHarish Mahendrakar     return false;
607*103e46e4SHarish Mahendrakar 
608*103e46e4SHarish Mahendrakar   return true;
609*103e46e4SHarish Mahendrakar }
610*103e46e4SHarish Mahendrakar 
EncodingSize(uint64_t compression_size,uint64_t encryption_size) const611*103e46e4SHarish Mahendrakar uint64_t ContentEncoding::EncodingSize(uint64_t compression_size,
612*103e46e4SHarish Mahendrakar                                        uint64_t encryption_size) const {
613*103e46e4SHarish Mahendrakar   // TODO(fgalligan): Add support for compression settings.
614*103e46e4SHarish Mahendrakar   if (compression_size != 0)
615*103e46e4SHarish Mahendrakar     return 0;
616*103e46e4SHarish Mahendrakar 
617*103e46e4SHarish Mahendrakar   uint64_t encoding_size = 0;
618*103e46e4SHarish Mahendrakar 
619*103e46e4SHarish Mahendrakar   if (encryption_size > 0) {
620*103e46e4SHarish Mahendrakar     encoding_size +=
621*103e46e4SHarish Mahendrakar         EbmlMasterElementSize(libwebm::kMkvContentEncryption, encryption_size) +
622*103e46e4SHarish Mahendrakar         encryption_size;
623*103e46e4SHarish Mahendrakar   }
624*103e46e4SHarish Mahendrakar   encoding_size += EbmlElementSize(libwebm::kMkvContentEncodingType,
625*103e46e4SHarish Mahendrakar                                    static_cast<uint64>(encoding_type_));
626*103e46e4SHarish Mahendrakar   encoding_size += EbmlElementSize(libwebm::kMkvContentEncodingScope,
627*103e46e4SHarish Mahendrakar                                    static_cast<uint64>(encoding_scope_));
628*103e46e4SHarish Mahendrakar   encoding_size += EbmlElementSize(libwebm::kMkvContentEncodingOrder,
629*103e46e4SHarish Mahendrakar                                    static_cast<uint64>(encoding_order_));
630*103e46e4SHarish Mahendrakar 
631*103e46e4SHarish Mahendrakar   return encoding_size;
632*103e46e4SHarish Mahendrakar }
633*103e46e4SHarish Mahendrakar 
EncryptionSize() const634*103e46e4SHarish Mahendrakar uint64_t ContentEncoding::EncryptionSize() const {
635*103e46e4SHarish Mahendrakar   const uint64_t aes_size = enc_aes_settings_.Size();
636*103e46e4SHarish Mahendrakar 
637*103e46e4SHarish Mahendrakar   uint64_t encryption_size = EbmlElementSize(libwebm::kMkvContentEncKeyID,
638*103e46e4SHarish Mahendrakar                                              enc_key_id_, enc_key_id_length_);
639*103e46e4SHarish Mahendrakar   encryption_size += EbmlElementSize(libwebm::kMkvContentEncAlgo,
640*103e46e4SHarish Mahendrakar                                      static_cast<uint64>(enc_algo_));
641*103e46e4SHarish Mahendrakar 
642*103e46e4SHarish Mahendrakar   return encryption_size + aes_size;
643*103e46e4SHarish Mahendrakar }
644*103e46e4SHarish Mahendrakar 
645*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
646*103e46e4SHarish Mahendrakar //
647*103e46e4SHarish Mahendrakar // Track Class
648*103e46e4SHarish Mahendrakar 
Track(unsigned int * seed)649*103e46e4SHarish Mahendrakar Track::Track(unsigned int* seed)
650*103e46e4SHarish Mahendrakar     : codec_id_(NULL),
651*103e46e4SHarish Mahendrakar       codec_private_(NULL),
652*103e46e4SHarish Mahendrakar       language_(NULL),
653*103e46e4SHarish Mahendrakar       max_block_additional_id_(0),
654*103e46e4SHarish Mahendrakar       name_(NULL),
655*103e46e4SHarish Mahendrakar       number_(0),
656*103e46e4SHarish Mahendrakar       type_(0),
657*103e46e4SHarish Mahendrakar       uid_(MakeUID(seed)),
658*103e46e4SHarish Mahendrakar       codec_delay_(0),
659*103e46e4SHarish Mahendrakar       seek_pre_roll_(0),
660*103e46e4SHarish Mahendrakar       default_duration_(0),
661*103e46e4SHarish Mahendrakar       codec_private_length_(0),
662*103e46e4SHarish Mahendrakar       content_encoding_entries_(NULL),
663*103e46e4SHarish Mahendrakar       content_encoding_entries_size_(0) {}
664*103e46e4SHarish Mahendrakar 
~Track()665*103e46e4SHarish Mahendrakar Track::~Track() {
666*103e46e4SHarish Mahendrakar   delete[] codec_id_;
667*103e46e4SHarish Mahendrakar   delete[] codec_private_;
668*103e46e4SHarish Mahendrakar   delete[] language_;
669*103e46e4SHarish Mahendrakar   delete[] name_;
670*103e46e4SHarish Mahendrakar 
671*103e46e4SHarish Mahendrakar   if (content_encoding_entries_) {
672*103e46e4SHarish Mahendrakar     for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
673*103e46e4SHarish Mahendrakar       ContentEncoding* const encoding = content_encoding_entries_[i];
674*103e46e4SHarish Mahendrakar       delete encoding;
675*103e46e4SHarish Mahendrakar     }
676*103e46e4SHarish Mahendrakar     delete[] content_encoding_entries_;
677*103e46e4SHarish Mahendrakar   }
678*103e46e4SHarish Mahendrakar }
679*103e46e4SHarish Mahendrakar 
AddContentEncoding()680*103e46e4SHarish Mahendrakar bool Track::AddContentEncoding() {
681*103e46e4SHarish Mahendrakar   const uint32_t count = content_encoding_entries_size_ + 1;
682*103e46e4SHarish Mahendrakar 
683*103e46e4SHarish Mahendrakar   ContentEncoding** const content_encoding_entries =
684*103e46e4SHarish Mahendrakar       new (std::nothrow) ContentEncoding*[count];  // NOLINT
685*103e46e4SHarish Mahendrakar   if (!content_encoding_entries)
686*103e46e4SHarish Mahendrakar     return false;
687*103e46e4SHarish Mahendrakar 
688*103e46e4SHarish Mahendrakar   ContentEncoding* const content_encoding =
689*103e46e4SHarish Mahendrakar       new (std::nothrow) ContentEncoding();  // NOLINT
690*103e46e4SHarish Mahendrakar   if (!content_encoding) {
691*103e46e4SHarish Mahendrakar     delete[] content_encoding_entries;
692*103e46e4SHarish Mahendrakar     return false;
693*103e46e4SHarish Mahendrakar   }
694*103e46e4SHarish Mahendrakar 
695*103e46e4SHarish Mahendrakar   for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
696*103e46e4SHarish Mahendrakar     content_encoding_entries[i] = content_encoding_entries_[i];
697*103e46e4SHarish Mahendrakar   }
698*103e46e4SHarish Mahendrakar 
699*103e46e4SHarish Mahendrakar   delete[] content_encoding_entries_;
700*103e46e4SHarish Mahendrakar 
701*103e46e4SHarish Mahendrakar   content_encoding_entries_ = content_encoding_entries;
702*103e46e4SHarish Mahendrakar   content_encoding_entries_[content_encoding_entries_size_] = content_encoding;
703*103e46e4SHarish Mahendrakar   content_encoding_entries_size_ = count;
704*103e46e4SHarish Mahendrakar   return true;
705*103e46e4SHarish Mahendrakar }
706*103e46e4SHarish Mahendrakar 
GetContentEncodingByIndex(uint32_t index) const707*103e46e4SHarish Mahendrakar ContentEncoding* Track::GetContentEncodingByIndex(uint32_t index) const {
708*103e46e4SHarish Mahendrakar   if (content_encoding_entries_ == NULL)
709*103e46e4SHarish Mahendrakar     return NULL;
710*103e46e4SHarish Mahendrakar 
711*103e46e4SHarish Mahendrakar   if (index >= content_encoding_entries_size_)
712*103e46e4SHarish Mahendrakar     return NULL;
713*103e46e4SHarish Mahendrakar 
714*103e46e4SHarish Mahendrakar   return content_encoding_entries_[index];
715*103e46e4SHarish Mahendrakar }
716*103e46e4SHarish Mahendrakar 
PayloadSize() const717*103e46e4SHarish Mahendrakar uint64_t Track::PayloadSize() const {
718*103e46e4SHarish Mahendrakar   uint64_t size =
719*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvTrackNumber, static_cast<uint64>(number_));
720*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvTrackUID, static_cast<uint64>(uid_));
721*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvTrackType, static_cast<uint64>(type_));
722*103e46e4SHarish Mahendrakar   if (codec_id_)
723*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvCodecID, codec_id_);
724*103e46e4SHarish Mahendrakar   if (codec_private_)
725*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvCodecPrivate, codec_private_,
726*103e46e4SHarish Mahendrakar                             codec_private_length_);
727*103e46e4SHarish Mahendrakar   if (language_)
728*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvLanguage, language_);
729*103e46e4SHarish Mahendrakar   if (name_)
730*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvName, name_);
731*103e46e4SHarish Mahendrakar   if (max_block_additional_id_) {
732*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvMaxBlockAdditionID,
733*103e46e4SHarish Mahendrakar                             static_cast<uint64>(max_block_additional_id_));
734*103e46e4SHarish Mahendrakar   }
735*103e46e4SHarish Mahendrakar   if (codec_delay_) {
736*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvCodecDelay,
737*103e46e4SHarish Mahendrakar                             static_cast<uint64>(codec_delay_));
738*103e46e4SHarish Mahendrakar   }
739*103e46e4SHarish Mahendrakar   if (seek_pre_roll_) {
740*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvSeekPreRoll,
741*103e46e4SHarish Mahendrakar                             static_cast<uint64>(seek_pre_roll_));
742*103e46e4SHarish Mahendrakar   }
743*103e46e4SHarish Mahendrakar   if (default_duration_) {
744*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvDefaultDuration,
745*103e46e4SHarish Mahendrakar                             static_cast<uint64>(default_duration_));
746*103e46e4SHarish Mahendrakar   }
747*103e46e4SHarish Mahendrakar 
748*103e46e4SHarish Mahendrakar   if (content_encoding_entries_size_ > 0) {
749*103e46e4SHarish Mahendrakar     uint64_t content_encodings_size = 0;
750*103e46e4SHarish Mahendrakar     for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
751*103e46e4SHarish Mahendrakar       ContentEncoding* const encoding = content_encoding_entries_[i];
752*103e46e4SHarish Mahendrakar       content_encodings_size += encoding->Size();
753*103e46e4SHarish Mahendrakar     }
754*103e46e4SHarish Mahendrakar 
755*103e46e4SHarish Mahendrakar     size += EbmlMasterElementSize(libwebm::kMkvContentEncodings,
756*103e46e4SHarish Mahendrakar                                   content_encodings_size) +
757*103e46e4SHarish Mahendrakar             content_encodings_size;
758*103e46e4SHarish Mahendrakar   }
759*103e46e4SHarish Mahendrakar 
760*103e46e4SHarish Mahendrakar   return size;
761*103e46e4SHarish Mahendrakar }
762*103e46e4SHarish Mahendrakar 
Size() const763*103e46e4SHarish Mahendrakar uint64_t Track::Size() const {
764*103e46e4SHarish Mahendrakar   uint64_t size = PayloadSize();
765*103e46e4SHarish Mahendrakar   size += EbmlMasterElementSize(libwebm::kMkvTrackEntry, size);
766*103e46e4SHarish Mahendrakar   return size;
767*103e46e4SHarish Mahendrakar }
768*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const769*103e46e4SHarish Mahendrakar bool Track::Write(IMkvWriter* writer) const {
770*103e46e4SHarish Mahendrakar   if (!writer)
771*103e46e4SHarish Mahendrakar     return false;
772*103e46e4SHarish Mahendrakar 
773*103e46e4SHarish Mahendrakar   // mandatory elements without a default value.
774*103e46e4SHarish Mahendrakar   if (!type_ || !codec_id_)
775*103e46e4SHarish Mahendrakar     return false;
776*103e46e4SHarish Mahendrakar 
777*103e46e4SHarish Mahendrakar   // AV1 tracks require a CodecPrivate. See
778*103e46e4SHarish Mahendrakar   // https://github.com/ietf-wg-cellar/matroska-specification/blob/HEAD/codec/av1.md
779*103e46e4SHarish Mahendrakar   // TODO(tomfinegan): Update the above link to the AV1 Matroska mappings to
780*103e46e4SHarish Mahendrakar   // point to a stable version once it is finalized, or our own WebM mappings
781*103e46e4SHarish Mahendrakar   // page on webmproject.org should we decide to release them.
782*103e46e4SHarish Mahendrakar   if (!strcmp(codec_id_, Tracks::kAv1CodecId) && !codec_private_)
783*103e46e4SHarish Mahendrakar     return false;
784*103e46e4SHarish Mahendrakar 
785*103e46e4SHarish Mahendrakar   // |size| may be bigger than what is written out in this function because
786*103e46e4SHarish Mahendrakar   // derived classes may write out more data in the Track element.
787*103e46e4SHarish Mahendrakar   const uint64_t payload_size = PayloadSize();
788*103e46e4SHarish Mahendrakar 
789*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvTrackEntry, payload_size))
790*103e46e4SHarish Mahendrakar     return false;
791*103e46e4SHarish Mahendrakar 
792*103e46e4SHarish Mahendrakar   uint64_t size =
793*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvTrackNumber, static_cast<uint64>(number_));
794*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvTrackUID, static_cast<uint64>(uid_));
795*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvTrackType, static_cast<uint64>(type_));
796*103e46e4SHarish Mahendrakar   if (codec_id_)
797*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvCodecID, codec_id_);
798*103e46e4SHarish Mahendrakar   if (codec_private_)
799*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvCodecPrivate, codec_private_,
800*103e46e4SHarish Mahendrakar                             static_cast<uint64>(codec_private_length_));
801*103e46e4SHarish Mahendrakar   if (language_)
802*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvLanguage, language_);
803*103e46e4SHarish Mahendrakar   if (name_)
804*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvName, name_);
805*103e46e4SHarish Mahendrakar   if (max_block_additional_id_)
806*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvMaxBlockAdditionID,
807*103e46e4SHarish Mahendrakar                             static_cast<uint64>(max_block_additional_id_));
808*103e46e4SHarish Mahendrakar   if (codec_delay_)
809*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvCodecDelay,
810*103e46e4SHarish Mahendrakar                             static_cast<uint64>(codec_delay_));
811*103e46e4SHarish Mahendrakar   if (seek_pre_roll_)
812*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvSeekPreRoll,
813*103e46e4SHarish Mahendrakar                             static_cast<uint64>(seek_pre_roll_));
814*103e46e4SHarish Mahendrakar   if (default_duration_)
815*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvDefaultDuration,
816*103e46e4SHarish Mahendrakar                             static_cast<uint64>(default_duration_));
817*103e46e4SHarish Mahendrakar 
818*103e46e4SHarish Mahendrakar   const int64_t payload_position = writer->Position();
819*103e46e4SHarish Mahendrakar   if (payload_position < 0)
820*103e46e4SHarish Mahendrakar     return false;
821*103e46e4SHarish Mahendrakar 
822*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvTrackNumber,
823*103e46e4SHarish Mahendrakar                         static_cast<uint64>(number_)))
824*103e46e4SHarish Mahendrakar     return false;
825*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvTrackUID,
826*103e46e4SHarish Mahendrakar                         static_cast<uint64>(uid_)))
827*103e46e4SHarish Mahendrakar     return false;
828*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvTrackType,
829*103e46e4SHarish Mahendrakar                         static_cast<uint64>(type_)))
830*103e46e4SHarish Mahendrakar     return false;
831*103e46e4SHarish Mahendrakar   if (max_block_additional_id_) {
832*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvMaxBlockAdditionID,
833*103e46e4SHarish Mahendrakar                           static_cast<uint64>(max_block_additional_id_))) {
834*103e46e4SHarish Mahendrakar       return false;
835*103e46e4SHarish Mahendrakar     }
836*103e46e4SHarish Mahendrakar   }
837*103e46e4SHarish Mahendrakar   if (codec_delay_) {
838*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvCodecDelay,
839*103e46e4SHarish Mahendrakar                           static_cast<uint64>(codec_delay_)))
840*103e46e4SHarish Mahendrakar       return false;
841*103e46e4SHarish Mahendrakar   }
842*103e46e4SHarish Mahendrakar   if (seek_pre_roll_) {
843*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvSeekPreRoll,
844*103e46e4SHarish Mahendrakar                           static_cast<uint64>(seek_pre_roll_)))
845*103e46e4SHarish Mahendrakar       return false;
846*103e46e4SHarish Mahendrakar   }
847*103e46e4SHarish Mahendrakar   if (default_duration_) {
848*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvDefaultDuration,
849*103e46e4SHarish Mahendrakar                           static_cast<uint64>(default_duration_)))
850*103e46e4SHarish Mahendrakar       return false;
851*103e46e4SHarish Mahendrakar   }
852*103e46e4SHarish Mahendrakar   if (codec_id_) {
853*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvCodecID, codec_id_))
854*103e46e4SHarish Mahendrakar       return false;
855*103e46e4SHarish Mahendrakar   }
856*103e46e4SHarish Mahendrakar   if (codec_private_) {
857*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvCodecPrivate, codec_private_,
858*103e46e4SHarish Mahendrakar                           static_cast<uint64>(codec_private_length_)))
859*103e46e4SHarish Mahendrakar       return false;
860*103e46e4SHarish Mahendrakar   }
861*103e46e4SHarish Mahendrakar   if (language_) {
862*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvLanguage, language_))
863*103e46e4SHarish Mahendrakar       return false;
864*103e46e4SHarish Mahendrakar   }
865*103e46e4SHarish Mahendrakar   if (name_) {
866*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvName, name_))
867*103e46e4SHarish Mahendrakar       return false;
868*103e46e4SHarish Mahendrakar   }
869*103e46e4SHarish Mahendrakar 
870*103e46e4SHarish Mahendrakar   int64_t stop_position = writer->Position();
871*103e46e4SHarish Mahendrakar   if (stop_position < 0 ||
872*103e46e4SHarish Mahendrakar       stop_position - payload_position != static_cast<int64_t>(size))
873*103e46e4SHarish Mahendrakar     return false;
874*103e46e4SHarish Mahendrakar 
875*103e46e4SHarish Mahendrakar   if (content_encoding_entries_size_ > 0) {
876*103e46e4SHarish Mahendrakar     uint64_t content_encodings_size = 0;
877*103e46e4SHarish Mahendrakar     for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
878*103e46e4SHarish Mahendrakar       ContentEncoding* const encoding = content_encoding_entries_[i];
879*103e46e4SHarish Mahendrakar       content_encodings_size += encoding->Size();
880*103e46e4SHarish Mahendrakar     }
881*103e46e4SHarish Mahendrakar 
882*103e46e4SHarish Mahendrakar     if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncodings,
883*103e46e4SHarish Mahendrakar                                 content_encodings_size))
884*103e46e4SHarish Mahendrakar       return false;
885*103e46e4SHarish Mahendrakar 
886*103e46e4SHarish Mahendrakar     for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
887*103e46e4SHarish Mahendrakar       ContentEncoding* const encoding = content_encoding_entries_[i];
888*103e46e4SHarish Mahendrakar       if (!encoding->Write(writer))
889*103e46e4SHarish Mahendrakar         return false;
890*103e46e4SHarish Mahendrakar     }
891*103e46e4SHarish Mahendrakar   }
892*103e46e4SHarish Mahendrakar 
893*103e46e4SHarish Mahendrakar   stop_position = writer->Position();
894*103e46e4SHarish Mahendrakar   if (stop_position < 0)
895*103e46e4SHarish Mahendrakar     return false;
896*103e46e4SHarish Mahendrakar   return true;
897*103e46e4SHarish Mahendrakar }
898*103e46e4SHarish Mahendrakar 
SetCodecPrivate(const uint8_t * codec_private,uint64_t length)899*103e46e4SHarish Mahendrakar bool Track::SetCodecPrivate(const uint8_t* codec_private, uint64_t length) {
900*103e46e4SHarish Mahendrakar   if (!codec_private || length < 1)
901*103e46e4SHarish Mahendrakar     return false;
902*103e46e4SHarish Mahendrakar 
903*103e46e4SHarish Mahendrakar   delete[] codec_private_;
904*103e46e4SHarish Mahendrakar 
905*103e46e4SHarish Mahendrakar   codec_private_ =
906*103e46e4SHarish Mahendrakar       new (std::nothrow) uint8_t[static_cast<size_t>(length)];  // NOLINT
907*103e46e4SHarish Mahendrakar   if (!codec_private_)
908*103e46e4SHarish Mahendrakar     return false;
909*103e46e4SHarish Mahendrakar 
910*103e46e4SHarish Mahendrakar   memcpy(codec_private_, codec_private, static_cast<size_t>(length));
911*103e46e4SHarish Mahendrakar   codec_private_length_ = length;
912*103e46e4SHarish Mahendrakar 
913*103e46e4SHarish Mahendrakar   return true;
914*103e46e4SHarish Mahendrakar }
915*103e46e4SHarish Mahendrakar 
set_codec_id(const char * codec_id)916*103e46e4SHarish Mahendrakar void Track::set_codec_id(const char* codec_id) {
917*103e46e4SHarish Mahendrakar   if (codec_id) {
918*103e46e4SHarish Mahendrakar     delete[] codec_id_;
919*103e46e4SHarish Mahendrakar 
920*103e46e4SHarish Mahendrakar     const size_t length = strlen(codec_id) + 1;
921*103e46e4SHarish Mahendrakar     codec_id_ = new (std::nothrow) char[length];  // NOLINT
922*103e46e4SHarish Mahendrakar     if (codec_id_) {
923*103e46e4SHarish Mahendrakar       memcpy(codec_id_, codec_id, length - 1);
924*103e46e4SHarish Mahendrakar       codec_id_[length - 1] = '\0';
925*103e46e4SHarish Mahendrakar     }
926*103e46e4SHarish Mahendrakar   }
927*103e46e4SHarish Mahendrakar }
928*103e46e4SHarish Mahendrakar 
929*103e46e4SHarish Mahendrakar // TODO(fgalligan): Vet the language parameter.
set_language(const char * language)930*103e46e4SHarish Mahendrakar void Track::set_language(const char* language) {
931*103e46e4SHarish Mahendrakar   if (language) {
932*103e46e4SHarish Mahendrakar     delete[] language_;
933*103e46e4SHarish Mahendrakar 
934*103e46e4SHarish Mahendrakar     const size_t length = strlen(language) + 1;
935*103e46e4SHarish Mahendrakar     language_ = new (std::nothrow) char[length];  // NOLINT
936*103e46e4SHarish Mahendrakar     if (language_) {
937*103e46e4SHarish Mahendrakar       memcpy(language_, language, length - 1);
938*103e46e4SHarish Mahendrakar       language_[length - 1] = '\0';
939*103e46e4SHarish Mahendrakar     }
940*103e46e4SHarish Mahendrakar   }
941*103e46e4SHarish Mahendrakar }
942*103e46e4SHarish Mahendrakar 
set_name(const char * name)943*103e46e4SHarish Mahendrakar void Track::set_name(const char* name) {
944*103e46e4SHarish Mahendrakar   if (name) {
945*103e46e4SHarish Mahendrakar     delete[] name_;
946*103e46e4SHarish Mahendrakar 
947*103e46e4SHarish Mahendrakar     const size_t length = strlen(name) + 1;
948*103e46e4SHarish Mahendrakar     name_ = new (std::nothrow) char[length];  // NOLINT
949*103e46e4SHarish Mahendrakar     if (name_) {
950*103e46e4SHarish Mahendrakar       memcpy(name_, name, length - 1);
951*103e46e4SHarish Mahendrakar       name_[length - 1] = '\0';
952*103e46e4SHarish Mahendrakar     }
953*103e46e4SHarish Mahendrakar   }
954*103e46e4SHarish Mahendrakar }
955*103e46e4SHarish Mahendrakar 
956*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
957*103e46e4SHarish Mahendrakar //
958*103e46e4SHarish Mahendrakar // Colour and its child elements
959*103e46e4SHarish Mahendrakar 
PrimaryChromaticitySize(libwebm::MkvId x_id,libwebm::MkvId y_id) const960*103e46e4SHarish Mahendrakar uint64_t PrimaryChromaticity::PrimaryChromaticitySize(
961*103e46e4SHarish Mahendrakar     libwebm::MkvId x_id, libwebm::MkvId y_id) const {
962*103e46e4SHarish Mahendrakar   return EbmlElementSize(x_id, x_) + EbmlElementSize(y_id, y_);
963*103e46e4SHarish Mahendrakar }
964*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer,libwebm::MkvId x_id,libwebm::MkvId y_id) const965*103e46e4SHarish Mahendrakar bool PrimaryChromaticity::Write(IMkvWriter* writer, libwebm::MkvId x_id,
966*103e46e4SHarish Mahendrakar                                 libwebm::MkvId y_id) const {
967*103e46e4SHarish Mahendrakar   if (!Valid()) {
968*103e46e4SHarish Mahendrakar     return false;
969*103e46e4SHarish Mahendrakar   }
970*103e46e4SHarish Mahendrakar   return WriteEbmlElement(writer, x_id, x_) &&
971*103e46e4SHarish Mahendrakar          WriteEbmlElement(writer, y_id, y_);
972*103e46e4SHarish Mahendrakar }
973*103e46e4SHarish Mahendrakar 
Valid() const974*103e46e4SHarish Mahendrakar bool PrimaryChromaticity::Valid() const {
975*103e46e4SHarish Mahendrakar   return (x_ >= kChromaticityMin && x_ <= kChromaticityMax &&
976*103e46e4SHarish Mahendrakar           y_ >= kChromaticityMin && y_ <= kChromaticityMax);
977*103e46e4SHarish Mahendrakar }
978*103e46e4SHarish Mahendrakar 
MasteringMetadataSize() const979*103e46e4SHarish Mahendrakar uint64_t MasteringMetadata::MasteringMetadataSize() const {
980*103e46e4SHarish Mahendrakar   uint64_t size = PayloadSize();
981*103e46e4SHarish Mahendrakar 
982*103e46e4SHarish Mahendrakar   if (size > 0)
983*103e46e4SHarish Mahendrakar     size += EbmlMasterElementSize(libwebm::kMkvMasteringMetadata, size);
984*103e46e4SHarish Mahendrakar 
985*103e46e4SHarish Mahendrakar   return size;
986*103e46e4SHarish Mahendrakar }
987*103e46e4SHarish Mahendrakar 
Valid() const988*103e46e4SHarish Mahendrakar bool MasteringMetadata::Valid() const {
989*103e46e4SHarish Mahendrakar   if (luminance_min_ != kValueNotPresent) {
990*103e46e4SHarish Mahendrakar     if (luminance_min_ < kMinLuminance || luminance_min_ > kMinLuminanceMax ||
991*103e46e4SHarish Mahendrakar         luminance_min_ > luminance_max_) {
992*103e46e4SHarish Mahendrakar       return false;
993*103e46e4SHarish Mahendrakar     }
994*103e46e4SHarish Mahendrakar   }
995*103e46e4SHarish Mahendrakar   if (luminance_max_ != kValueNotPresent) {
996*103e46e4SHarish Mahendrakar     if (luminance_max_ < kMinLuminance || luminance_max_ > kMaxLuminanceMax ||
997*103e46e4SHarish Mahendrakar         luminance_max_ < luminance_min_) {
998*103e46e4SHarish Mahendrakar       return false;
999*103e46e4SHarish Mahendrakar     }
1000*103e46e4SHarish Mahendrakar   }
1001*103e46e4SHarish Mahendrakar   if (r_ && !r_->Valid())
1002*103e46e4SHarish Mahendrakar     return false;
1003*103e46e4SHarish Mahendrakar   if (g_ && !g_->Valid())
1004*103e46e4SHarish Mahendrakar     return false;
1005*103e46e4SHarish Mahendrakar   if (b_ && !b_->Valid())
1006*103e46e4SHarish Mahendrakar     return false;
1007*103e46e4SHarish Mahendrakar   if (white_point_ && !white_point_->Valid())
1008*103e46e4SHarish Mahendrakar     return false;
1009*103e46e4SHarish Mahendrakar 
1010*103e46e4SHarish Mahendrakar   return true;
1011*103e46e4SHarish Mahendrakar }
1012*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const1013*103e46e4SHarish Mahendrakar bool MasteringMetadata::Write(IMkvWriter* writer) const {
1014*103e46e4SHarish Mahendrakar   const uint64_t size = PayloadSize();
1015*103e46e4SHarish Mahendrakar 
1016*103e46e4SHarish Mahendrakar   // Don't write an empty element.
1017*103e46e4SHarish Mahendrakar   if (size == 0)
1018*103e46e4SHarish Mahendrakar     return true;
1019*103e46e4SHarish Mahendrakar 
1020*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvMasteringMetadata, size))
1021*103e46e4SHarish Mahendrakar     return false;
1022*103e46e4SHarish Mahendrakar   if (luminance_max_ != kValueNotPresent &&
1023*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvLuminanceMax, luminance_max_)) {
1024*103e46e4SHarish Mahendrakar     return false;
1025*103e46e4SHarish Mahendrakar   }
1026*103e46e4SHarish Mahendrakar   if (luminance_min_ != kValueNotPresent &&
1027*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvLuminanceMin, luminance_min_)) {
1028*103e46e4SHarish Mahendrakar     return false;
1029*103e46e4SHarish Mahendrakar   }
1030*103e46e4SHarish Mahendrakar   if (r_ && !r_->Write(writer, libwebm::kMkvPrimaryRChromaticityX,
1031*103e46e4SHarish Mahendrakar                        libwebm::kMkvPrimaryRChromaticityY)) {
1032*103e46e4SHarish Mahendrakar     return false;
1033*103e46e4SHarish Mahendrakar   }
1034*103e46e4SHarish Mahendrakar   if (g_ && !g_->Write(writer, libwebm::kMkvPrimaryGChromaticityX,
1035*103e46e4SHarish Mahendrakar                        libwebm::kMkvPrimaryGChromaticityY)) {
1036*103e46e4SHarish Mahendrakar     return false;
1037*103e46e4SHarish Mahendrakar   }
1038*103e46e4SHarish Mahendrakar   if (b_ && !b_->Write(writer, libwebm::kMkvPrimaryBChromaticityX,
1039*103e46e4SHarish Mahendrakar                        libwebm::kMkvPrimaryBChromaticityY)) {
1040*103e46e4SHarish Mahendrakar     return false;
1041*103e46e4SHarish Mahendrakar   }
1042*103e46e4SHarish Mahendrakar   if (white_point_ &&
1043*103e46e4SHarish Mahendrakar       !white_point_->Write(writer, libwebm::kMkvWhitePointChromaticityX,
1044*103e46e4SHarish Mahendrakar                            libwebm::kMkvWhitePointChromaticityY)) {
1045*103e46e4SHarish Mahendrakar     return false;
1046*103e46e4SHarish Mahendrakar   }
1047*103e46e4SHarish Mahendrakar 
1048*103e46e4SHarish Mahendrakar   return true;
1049*103e46e4SHarish Mahendrakar }
1050*103e46e4SHarish Mahendrakar 
SetChromaticity(const PrimaryChromaticity * r,const PrimaryChromaticity * g,const PrimaryChromaticity * b,const PrimaryChromaticity * white_point)1051*103e46e4SHarish Mahendrakar bool MasteringMetadata::SetChromaticity(
1052*103e46e4SHarish Mahendrakar     const PrimaryChromaticity* r, const PrimaryChromaticity* g,
1053*103e46e4SHarish Mahendrakar     const PrimaryChromaticity* b, const PrimaryChromaticity* white_point) {
1054*103e46e4SHarish Mahendrakar   PrimaryChromaticityPtr r_ptr(nullptr);
1055*103e46e4SHarish Mahendrakar   if (r) {
1056*103e46e4SHarish Mahendrakar     if (!CopyChromaticity(r, &r_ptr))
1057*103e46e4SHarish Mahendrakar       return false;
1058*103e46e4SHarish Mahendrakar   }
1059*103e46e4SHarish Mahendrakar   PrimaryChromaticityPtr g_ptr(nullptr);
1060*103e46e4SHarish Mahendrakar   if (g) {
1061*103e46e4SHarish Mahendrakar     if (!CopyChromaticity(g, &g_ptr))
1062*103e46e4SHarish Mahendrakar       return false;
1063*103e46e4SHarish Mahendrakar   }
1064*103e46e4SHarish Mahendrakar   PrimaryChromaticityPtr b_ptr(nullptr);
1065*103e46e4SHarish Mahendrakar   if (b) {
1066*103e46e4SHarish Mahendrakar     if (!CopyChromaticity(b, &b_ptr))
1067*103e46e4SHarish Mahendrakar       return false;
1068*103e46e4SHarish Mahendrakar   }
1069*103e46e4SHarish Mahendrakar   PrimaryChromaticityPtr wp_ptr(nullptr);
1070*103e46e4SHarish Mahendrakar   if (white_point) {
1071*103e46e4SHarish Mahendrakar     if (!CopyChromaticity(white_point, &wp_ptr))
1072*103e46e4SHarish Mahendrakar       return false;
1073*103e46e4SHarish Mahendrakar   }
1074*103e46e4SHarish Mahendrakar 
1075*103e46e4SHarish Mahendrakar   r_ = r_ptr.release();
1076*103e46e4SHarish Mahendrakar   g_ = g_ptr.release();
1077*103e46e4SHarish Mahendrakar   b_ = b_ptr.release();
1078*103e46e4SHarish Mahendrakar   white_point_ = wp_ptr.release();
1079*103e46e4SHarish Mahendrakar   return true;
1080*103e46e4SHarish Mahendrakar }
1081*103e46e4SHarish Mahendrakar 
PayloadSize() const1082*103e46e4SHarish Mahendrakar uint64_t MasteringMetadata::PayloadSize() const {
1083*103e46e4SHarish Mahendrakar   uint64_t size = 0;
1084*103e46e4SHarish Mahendrakar 
1085*103e46e4SHarish Mahendrakar   if (luminance_max_ != kValueNotPresent)
1086*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvLuminanceMax, luminance_max_);
1087*103e46e4SHarish Mahendrakar   if (luminance_min_ != kValueNotPresent)
1088*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvLuminanceMin, luminance_min_);
1089*103e46e4SHarish Mahendrakar 
1090*103e46e4SHarish Mahendrakar   if (r_) {
1091*103e46e4SHarish Mahendrakar     size += r_->PrimaryChromaticitySize(libwebm::kMkvPrimaryRChromaticityX,
1092*103e46e4SHarish Mahendrakar                                         libwebm::kMkvPrimaryRChromaticityY);
1093*103e46e4SHarish Mahendrakar   }
1094*103e46e4SHarish Mahendrakar   if (g_) {
1095*103e46e4SHarish Mahendrakar     size += g_->PrimaryChromaticitySize(libwebm::kMkvPrimaryGChromaticityX,
1096*103e46e4SHarish Mahendrakar                                         libwebm::kMkvPrimaryGChromaticityY);
1097*103e46e4SHarish Mahendrakar   }
1098*103e46e4SHarish Mahendrakar   if (b_) {
1099*103e46e4SHarish Mahendrakar     size += b_->PrimaryChromaticitySize(libwebm::kMkvPrimaryBChromaticityX,
1100*103e46e4SHarish Mahendrakar                                         libwebm::kMkvPrimaryBChromaticityY);
1101*103e46e4SHarish Mahendrakar   }
1102*103e46e4SHarish Mahendrakar   if (white_point_) {
1103*103e46e4SHarish Mahendrakar     size += white_point_->PrimaryChromaticitySize(
1104*103e46e4SHarish Mahendrakar         libwebm::kMkvWhitePointChromaticityX,
1105*103e46e4SHarish Mahendrakar         libwebm::kMkvWhitePointChromaticityY);
1106*103e46e4SHarish Mahendrakar   }
1107*103e46e4SHarish Mahendrakar 
1108*103e46e4SHarish Mahendrakar   return size;
1109*103e46e4SHarish Mahendrakar }
1110*103e46e4SHarish Mahendrakar 
ColourSize() const1111*103e46e4SHarish Mahendrakar uint64_t Colour::ColourSize() const {
1112*103e46e4SHarish Mahendrakar   uint64_t size = PayloadSize();
1113*103e46e4SHarish Mahendrakar 
1114*103e46e4SHarish Mahendrakar   if (size > 0)
1115*103e46e4SHarish Mahendrakar     size += EbmlMasterElementSize(libwebm::kMkvColour, size);
1116*103e46e4SHarish Mahendrakar 
1117*103e46e4SHarish Mahendrakar   return size;
1118*103e46e4SHarish Mahendrakar }
1119*103e46e4SHarish Mahendrakar 
Valid() const1120*103e46e4SHarish Mahendrakar bool Colour::Valid() const {
1121*103e46e4SHarish Mahendrakar   if (mastering_metadata_ && !mastering_metadata_->Valid())
1122*103e46e4SHarish Mahendrakar     return false;
1123*103e46e4SHarish Mahendrakar   if (matrix_coefficients_ != kValueNotPresent &&
1124*103e46e4SHarish Mahendrakar       !IsMatrixCoefficientsValueValid(matrix_coefficients_)) {
1125*103e46e4SHarish Mahendrakar     return false;
1126*103e46e4SHarish Mahendrakar   }
1127*103e46e4SHarish Mahendrakar   if (chroma_siting_horz_ != kValueNotPresent &&
1128*103e46e4SHarish Mahendrakar       !IsChromaSitingHorzValueValid(chroma_siting_horz_)) {
1129*103e46e4SHarish Mahendrakar     return false;
1130*103e46e4SHarish Mahendrakar   }
1131*103e46e4SHarish Mahendrakar   if (chroma_siting_vert_ != kValueNotPresent &&
1132*103e46e4SHarish Mahendrakar       !IsChromaSitingVertValueValid(chroma_siting_vert_)) {
1133*103e46e4SHarish Mahendrakar     return false;
1134*103e46e4SHarish Mahendrakar   }
1135*103e46e4SHarish Mahendrakar   if (range_ != kValueNotPresent && !IsColourRangeValueValid(range_))
1136*103e46e4SHarish Mahendrakar     return false;
1137*103e46e4SHarish Mahendrakar   if (transfer_characteristics_ != kValueNotPresent &&
1138*103e46e4SHarish Mahendrakar       !IsTransferCharacteristicsValueValid(transfer_characteristics_)) {
1139*103e46e4SHarish Mahendrakar     return false;
1140*103e46e4SHarish Mahendrakar   }
1141*103e46e4SHarish Mahendrakar   if (primaries_ != kValueNotPresent && !IsPrimariesValueValid(primaries_))
1142*103e46e4SHarish Mahendrakar     return false;
1143*103e46e4SHarish Mahendrakar 
1144*103e46e4SHarish Mahendrakar   return true;
1145*103e46e4SHarish Mahendrakar }
1146*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const1147*103e46e4SHarish Mahendrakar bool Colour::Write(IMkvWriter* writer) const {
1148*103e46e4SHarish Mahendrakar   const uint64_t size = PayloadSize();
1149*103e46e4SHarish Mahendrakar 
1150*103e46e4SHarish Mahendrakar   // Don't write an empty element.
1151*103e46e4SHarish Mahendrakar   if (size == 0)
1152*103e46e4SHarish Mahendrakar     return true;
1153*103e46e4SHarish Mahendrakar 
1154*103e46e4SHarish Mahendrakar   // Don't write an invalid element.
1155*103e46e4SHarish Mahendrakar   if (!Valid())
1156*103e46e4SHarish Mahendrakar     return false;
1157*103e46e4SHarish Mahendrakar 
1158*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvColour, size))
1159*103e46e4SHarish Mahendrakar     return false;
1160*103e46e4SHarish Mahendrakar 
1161*103e46e4SHarish Mahendrakar   if (matrix_coefficients_ != kValueNotPresent &&
1162*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvMatrixCoefficients,
1163*103e46e4SHarish Mahendrakar                         static_cast<uint64>(matrix_coefficients_))) {
1164*103e46e4SHarish Mahendrakar     return false;
1165*103e46e4SHarish Mahendrakar   }
1166*103e46e4SHarish Mahendrakar   if (bits_per_channel_ != kValueNotPresent &&
1167*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvBitsPerChannel,
1168*103e46e4SHarish Mahendrakar                         static_cast<uint64>(bits_per_channel_))) {
1169*103e46e4SHarish Mahendrakar     return false;
1170*103e46e4SHarish Mahendrakar   }
1171*103e46e4SHarish Mahendrakar   if (chroma_subsampling_horz_ != kValueNotPresent &&
1172*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvChromaSubsamplingHorz,
1173*103e46e4SHarish Mahendrakar                         static_cast<uint64>(chroma_subsampling_horz_))) {
1174*103e46e4SHarish Mahendrakar     return false;
1175*103e46e4SHarish Mahendrakar   }
1176*103e46e4SHarish Mahendrakar   if (chroma_subsampling_vert_ != kValueNotPresent &&
1177*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvChromaSubsamplingVert,
1178*103e46e4SHarish Mahendrakar                         static_cast<uint64>(chroma_subsampling_vert_))) {
1179*103e46e4SHarish Mahendrakar     return false;
1180*103e46e4SHarish Mahendrakar   }
1181*103e46e4SHarish Mahendrakar 
1182*103e46e4SHarish Mahendrakar   if (cb_subsampling_horz_ != kValueNotPresent &&
1183*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvCbSubsamplingHorz,
1184*103e46e4SHarish Mahendrakar                         static_cast<uint64>(cb_subsampling_horz_))) {
1185*103e46e4SHarish Mahendrakar     return false;
1186*103e46e4SHarish Mahendrakar   }
1187*103e46e4SHarish Mahendrakar   if (cb_subsampling_vert_ != kValueNotPresent &&
1188*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvCbSubsamplingVert,
1189*103e46e4SHarish Mahendrakar                         static_cast<uint64>(cb_subsampling_vert_))) {
1190*103e46e4SHarish Mahendrakar     return false;
1191*103e46e4SHarish Mahendrakar   }
1192*103e46e4SHarish Mahendrakar   if (chroma_siting_horz_ != kValueNotPresent &&
1193*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvChromaSitingHorz,
1194*103e46e4SHarish Mahendrakar                         static_cast<uint64>(chroma_siting_horz_))) {
1195*103e46e4SHarish Mahendrakar     return false;
1196*103e46e4SHarish Mahendrakar   }
1197*103e46e4SHarish Mahendrakar   if (chroma_siting_vert_ != kValueNotPresent &&
1198*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvChromaSitingVert,
1199*103e46e4SHarish Mahendrakar                         static_cast<uint64>(chroma_siting_vert_))) {
1200*103e46e4SHarish Mahendrakar     return false;
1201*103e46e4SHarish Mahendrakar   }
1202*103e46e4SHarish Mahendrakar   if (range_ != kValueNotPresent &&
1203*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvRange,
1204*103e46e4SHarish Mahendrakar                         static_cast<uint64>(range_))) {
1205*103e46e4SHarish Mahendrakar     return false;
1206*103e46e4SHarish Mahendrakar   }
1207*103e46e4SHarish Mahendrakar   if (transfer_characteristics_ != kValueNotPresent &&
1208*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvTransferCharacteristics,
1209*103e46e4SHarish Mahendrakar                         static_cast<uint64>(transfer_characteristics_))) {
1210*103e46e4SHarish Mahendrakar     return false;
1211*103e46e4SHarish Mahendrakar   }
1212*103e46e4SHarish Mahendrakar   if (primaries_ != kValueNotPresent &&
1213*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvPrimaries,
1214*103e46e4SHarish Mahendrakar                         static_cast<uint64>(primaries_))) {
1215*103e46e4SHarish Mahendrakar     return false;
1216*103e46e4SHarish Mahendrakar   }
1217*103e46e4SHarish Mahendrakar   if (max_cll_ != kValueNotPresent &&
1218*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvMaxCLL,
1219*103e46e4SHarish Mahendrakar                         static_cast<uint64>(max_cll_))) {
1220*103e46e4SHarish Mahendrakar     return false;
1221*103e46e4SHarish Mahendrakar   }
1222*103e46e4SHarish Mahendrakar   if (max_fall_ != kValueNotPresent &&
1223*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvMaxFALL,
1224*103e46e4SHarish Mahendrakar                         static_cast<uint64>(max_fall_))) {
1225*103e46e4SHarish Mahendrakar     return false;
1226*103e46e4SHarish Mahendrakar   }
1227*103e46e4SHarish Mahendrakar 
1228*103e46e4SHarish Mahendrakar   if (mastering_metadata_ && !mastering_metadata_->Write(writer))
1229*103e46e4SHarish Mahendrakar     return false;
1230*103e46e4SHarish Mahendrakar 
1231*103e46e4SHarish Mahendrakar   return true;
1232*103e46e4SHarish Mahendrakar }
1233*103e46e4SHarish Mahendrakar 
SetMasteringMetadata(const MasteringMetadata & mastering_metadata)1234*103e46e4SHarish Mahendrakar bool Colour::SetMasteringMetadata(const MasteringMetadata& mastering_metadata) {
1235*103e46e4SHarish Mahendrakar   std::unique_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata());
1236*103e46e4SHarish Mahendrakar   if (!mm_ptr.get())
1237*103e46e4SHarish Mahendrakar     return false;
1238*103e46e4SHarish Mahendrakar 
1239*103e46e4SHarish Mahendrakar   mm_ptr->set_luminance_max(mastering_metadata.luminance_max());
1240*103e46e4SHarish Mahendrakar   mm_ptr->set_luminance_min(mastering_metadata.luminance_min());
1241*103e46e4SHarish Mahendrakar 
1242*103e46e4SHarish Mahendrakar   if (!mm_ptr->SetChromaticity(mastering_metadata.r(), mastering_metadata.g(),
1243*103e46e4SHarish Mahendrakar                                mastering_metadata.b(),
1244*103e46e4SHarish Mahendrakar                                mastering_metadata.white_point())) {
1245*103e46e4SHarish Mahendrakar     return false;
1246*103e46e4SHarish Mahendrakar   }
1247*103e46e4SHarish Mahendrakar 
1248*103e46e4SHarish Mahendrakar   delete mastering_metadata_;
1249*103e46e4SHarish Mahendrakar   mastering_metadata_ = mm_ptr.release();
1250*103e46e4SHarish Mahendrakar   return true;
1251*103e46e4SHarish Mahendrakar }
1252*103e46e4SHarish Mahendrakar 
PayloadSize() const1253*103e46e4SHarish Mahendrakar uint64_t Colour::PayloadSize() const {
1254*103e46e4SHarish Mahendrakar   uint64_t size = 0;
1255*103e46e4SHarish Mahendrakar 
1256*103e46e4SHarish Mahendrakar   if (matrix_coefficients_ != kValueNotPresent) {
1257*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvMatrixCoefficients,
1258*103e46e4SHarish Mahendrakar                             static_cast<uint64>(matrix_coefficients_));
1259*103e46e4SHarish Mahendrakar   }
1260*103e46e4SHarish Mahendrakar   if (bits_per_channel_ != kValueNotPresent) {
1261*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvBitsPerChannel,
1262*103e46e4SHarish Mahendrakar                             static_cast<uint64>(bits_per_channel_));
1263*103e46e4SHarish Mahendrakar   }
1264*103e46e4SHarish Mahendrakar   if (chroma_subsampling_horz_ != kValueNotPresent) {
1265*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvChromaSubsamplingHorz,
1266*103e46e4SHarish Mahendrakar                             static_cast<uint64>(chroma_subsampling_horz_));
1267*103e46e4SHarish Mahendrakar   }
1268*103e46e4SHarish Mahendrakar   if (chroma_subsampling_vert_ != kValueNotPresent) {
1269*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvChromaSubsamplingVert,
1270*103e46e4SHarish Mahendrakar                             static_cast<uint64>(chroma_subsampling_vert_));
1271*103e46e4SHarish Mahendrakar   }
1272*103e46e4SHarish Mahendrakar   if (cb_subsampling_horz_ != kValueNotPresent) {
1273*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvCbSubsamplingHorz,
1274*103e46e4SHarish Mahendrakar                             static_cast<uint64>(cb_subsampling_horz_));
1275*103e46e4SHarish Mahendrakar   }
1276*103e46e4SHarish Mahendrakar   if (cb_subsampling_vert_ != kValueNotPresent) {
1277*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvCbSubsamplingVert,
1278*103e46e4SHarish Mahendrakar                             static_cast<uint64>(cb_subsampling_vert_));
1279*103e46e4SHarish Mahendrakar   }
1280*103e46e4SHarish Mahendrakar   if (chroma_siting_horz_ != kValueNotPresent) {
1281*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvChromaSitingHorz,
1282*103e46e4SHarish Mahendrakar                             static_cast<uint64>(chroma_siting_horz_));
1283*103e46e4SHarish Mahendrakar   }
1284*103e46e4SHarish Mahendrakar   if (chroma_siting_vert_ != kValueNotPresent) {
1285*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvChromaSitingVert,
1286*103e46e4SHarish Mahendrakar                             static_cast<uint64>(chroma_siting_vert_));
1287*103e46e4SHarish Mahendrakar   }
1288*103e46e4SHarish Mahendrakar   if (range_ != kValueNotPresent) {
1289*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvRange, static_cast<uint64>(range_));
1290*103e46e4SHarish Mahendrakar   }
1291*103e46e4SHarish Mahendrakar   if (transfer_characteristics_ != kValueNotPresent) {
1292*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvTransferCharacteristics,
1293*103e46e4SHarish Mahendrakar                             static_cast<uint64>(transfer_characteristics_));
1294*103e46e4SHarish Mahendrakar   }
1295*103e46e4SHarish Mahendrakar   if (primaries_ != kValueNotPresent) {
1296*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvPrimaries,
1297*103e46e4SHarish Mahendrakar                             static_cast<uint64>(primaries_));
1298*103e46e4SHarish Mahendrakar   }
1299*103e46e4SHarish Mahendrakar   if (max_cll_ != kValueNotPresent) {
1300*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvMaxCLL, static_cast<uint64>(max_cll_));
1301*103e46e4SHarish Mahendrakar   }
1302*103e46e4SHarish Mahendrakar   if (max_fall_ != kValueNotPresent) {
1303*103e46e4SHarish Mahendrakar     size +=
1304*103e46e4SHarish Mahendrakar         EbmlElementSize(libwebm::kMkvMaxFALL, static_cast<uint64>(max_fall_));
1305*103e46e4SHarish Mahendrakar   }
1306*103e46e4SHarish Mahendrakar 
1307*103e46e4SHarish Mahendrakar   if (mastering_metadata_)
1308*103e46e4SHarish Mahendrakar     size += mastering_metadata_->MasteringMetadataSize();
1309*103e46e4SHarish Mahendrakar 
1310*103e46e4SHarish Mahendrakar   return size;
1311*103e46e4SHarish Mahendrakar }
1312*103e46e4SHarish Mahendrakar 
1313*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
1314*103e46e4SHarish Mahendrakar //
1315*103e46e4SHarish Mahendrakar // Projection element
1316*103e46e4SHarish Mahendrakar 
ProjectionSize() const1317*103e46e4SHarish Mahendrakar uint64_t Projection::ProjectionSize() const {
1318*103e46e4SHarish Mahendrakar   uint64_t size = PayloadSize();
1319*103e46e4SHarish Mahendrakar 
1320*103e46e4SHarish Mahendrakar   if (size > 0)
1321*103e46e4SHarish Mahendrakar     size += EbmlMasterElementSize(libwebm::kMkvProjection, size);
1322*103e46e4SHarish Mahendrakar 
1323*103e46e4SHarish Mahendrakar   return size;
1324*103e46e4SHarish Mahendrakar }
1325*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const1326*103e46e4SHarish Mahendrakar bool Projection::Write(IMkvWriter* writer) const {
1327*103e46e4SHarish Mahendrakar   const uint64_t size = PayloadSize();
1328*103e46e4SHarish Mahendrakar 
1329*103e46e4SHarish Mahendrakar   // Don't write an empty element.
1330*103e46e4SHarish Mahendrakar   if (size == 0)
1331*103e46e4SHarish Mahendrakar     return true;
1332*103e46e4SHarish Mahendrakar 
1333*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvProjection, size))
1334*103e46e4SHarish Mahendrakar     return false;
1335*103e46e4SHarish Mahendrakar 
1336*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvProjectionType,
1337*103e46e4SHarish Mahendrakar                         static_cast<uint64>(type_))) {
1338*103e46e4SHarish Mahendrakar     return false;
1339*103e46e4SHarish Mahendrakar   }
1340*103e46e4SHarish Mahendrakar 
1341*103e46e4SHarish Mahendrakar   if (private_data_length_ > 0 && private_data_ != NULL &&
1342*103e46e4SHarish Mahendrakar       !WriteEbmlElement(writer, libwebm::kMkvProjectionPrivate, private_data_,
1343*103e46e4SHarish Mahendrakar                         private_data_length_)) {
1344*103e46e4SHarish Mahendrakar     return false;
1345*103e46e4SHarish Mahendrakar   }
1346*103e46e4SHarish Mahendrakar 
1347*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvProjectionPoseYaw, pose_yaw_))
1348*103e46e4SHarish Mahendrakar     return false;
1349*103e46e4SHarish Mahendrakar 
1350*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvProjectionPosePitch,
1351*103e46e4SHarish Mahendrakar                         pose_pitch_)) {
1352*103e46e4SHarish Mahendrakar     return false;
1353*103e46e4SHarish Mahendrakar   }
1354*103e46e4SHarish Mahendrakar 
1355*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvProjectionPoseRoll, pose_roll_)) {
1356*103e46e4SHarish Mahendrakar     return false;
1357*103e46e4SHarish Mahendrakar   }
1358*103e46e4SHarish Mahendrakar 
1359*103e46e4SHarish Mahendrakar   return true;
1360*103e46e4SHarish Mahendrakar }
1361*103e46e4SHarish Mahendrakar 
SetProjectionPrivate(const uint8_t * data,uint64_t data_length)1362*103e46e4SHarish Mahendrakar bool Projection::SetProjectionPrivate(const uint8_t* data,
1363*103e46e4SHarish Mahendrakar                                       uint64_t data_length) {
1364*103e46e4SHarish Mahendrakar   if (data == NULL || data_length == 0) {
1365*103e46e4SHarish Mahendrakar     return false;
1366*103e46e4SHarish Mahendrakar   }
1367*103e46e4SHarish Mahendrakar 
1368*103e46e4SHarish Mahendrakar   if (data_length != static_cast<size_t>(data_length)) {
1369*103e46e4SHarish Mahendrakar     return false;
1370*103e46e4SHarish Mahendrakar   }
1371*103e46e4SHarish Mahendrakar 
1372*103e46e4SHarish Mahendrakar   uint8_t* new_private_data =
1373*103e46e4SHarish Mahendrakar       new (std::nothrow) uint8_t[static_cast<size_t>(data_length)];
1374*103e46e4SHarish Mahendrakar   if (new_private_data == NULL) {
1375*103e46e4SHarish Mahendrakar     return false;
1376*103e46e4SHarish Mahendrakar   }
1377*103e46e4SHarish Mahendrakar 
1378*103e46e4SHarish Mahendrakar   delete[] private_data_;
1379*103e46e4SHarish Mahendrakar   private_data_ = new_private_data;
1380*103e46e4SHarish Mahendrakar   private_data_length_ = data_length;
1381*103e46e4SHarish Mahendrakar   memcpy(private_data_, data, static_cast<size_t>(data_length));
1382*103e46e4SHarish Mahendrakar 
1383*103e46e4SHarish Mahendrakar   return true;
1384*103e46e4SHarish Mahendrakar }
1385*103e46e4SHarish Mahendrakar 
PayloadSize() const1386*103e46e4SHarish Mahendrakar uint64_t Projection::PayloadSize() const {
1387*103e46e4SHarish Mahendrakar   uint64_t size =
1388*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvProjection, static_cast<uint64>(type_));
1389*103e46e4SHarish Mahendrakar 
1390*103e46e4SHarish Mahendrakar   if (private_data_length_ > 0 && private_data_ != NULL) {
1391*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvProjectionPrivate, private_data_,
1392*103e46e4SHarish Mahendrakar                             private_data_length_);
1393*103e46e4SHarish Mahendrakar   }
1394*103e46e4SHarish Mahendrakar 
1395*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvProjectionPoseYaw, pose_yaw_);
1396*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvProjectionPosePitch, pose_pitch_);
1397*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvProjectionPoseRoll, pose_roll_);
1398*103e46e4SHarish Mahendrakar 
1399*103e46e4SHarish Mahendrakar   return size;
1400*103e46e4SHarish Mahendrakar }
1401*103e46e4SHarish Mahendrakar 
1402*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
1403*103e46e4SHarish Mahendrakar //
1404*103e46e4SHarish Mahendrakar // VideoTrack Class
1405*103e46e4SHarish Mahendrakar 
VideoTrack(unsigned int * seed)1406*103e46e4SHarish Mahendrakar VideoTrack::VideoTrack(unsigned int* seed)
1407*103e46e4SHarish Mahendrakar     : Track(seed),
1408*103e46e4SHarish Mahendrakar       display_height_(0),
1409*103e46e4SHarish Mahendrakar       display_width_(0),
1410*103e46e4SHarish Mahendrakar       pixel_height_(0),
1411*103e46e4SHarish Mahendrakar       pixel_width_(0),
1412*103e46e4SHarish Mahendrakar       crop_left_(0),
1413*103e46e4SHarish Mahendrakar       crop_right_(0),
1414*103e46e4SHarish Mahendrakar       crop_top_(0),
1415*103e46e4SHarish Mahendrakar       crop_bottom_(0),
1416*103e46e4SHarish Mahendrakar       frame_rate_(0.0),
1417*103e46e4SHarish Mahendrakar       height_(0),
1418*103e46e4SHarish Mahendrakar       stereo_mode_(0),
1419*103e46e4SHarish Mahendrakar       alpha_mode_(0),
1420*103e46e4SHarish Mahendrakar       width_(0),
1421*103e46e4SHarish Mahendrakar       colour_space_(NULL),
1422*103e46e4SHarish Mahendrakar       colour_(NULL),
1423*103e46e4SHarish Mahendrakar       projection_(NULL) {}
1424*103e46e4SHarish Mahendrakar 
~VideoTrack()1425*103e46e4SHarish Mahendrakar VideoTrack::~VideoTrack() {
1426*103e46e4SHarish Mahendrakar   delete colour_;
1427*103e46e4SHarish Mahendrakar   delete projection_;
1428*103e46e4SHarish Mahendrakar }
1429*103e46e4SHarish Mahendrakar 
SetStereoMode(uint64_t stereo_mode)1430*103e46e4SHarish Mahendrakar bool VideoTrack::SetStereoMode(uint64_t stereo_mode) {
1431*103e46e4SHarish Mahendrakar   if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst &&
1432*103e46e4SHarish Mahendrakar       stereo_mode != kTopBottomRightIsFirst &&
1433*103e46e4SHarish Mahendrakar       stereo_mode != kTopBottomLeftIsFirst &&
1434*103e46e4SHarish Mahendrakar       stereo_mode != kSideBySideRightIsFirst)
1435*103e46e4SHarish Mahendrakar     return false;
1436*103e46e4SHarish Mahendrakar 
1437*103e46e4SHarish Mahendrakar   stereo_mode_ = stereo_mode;
1438*103e46e4SHarish Mahendrakar   return true;
1439*103e46e4SHarish Mahendrakar }
1440*103e46e4SHarish Mahendrakar 
SetAlphaMode(uint64_t alpha_mode)1441*103e46e4SHarish Mahendrakar bool VideoTrack::SetAlphaMode(uint64_t alpha_mode) {
1442*103e46e4SHarish Mahendrakar   if (alpha_mode != kNoAlpha && alpha_mode != kAlpha)
1443*103e46e4SHarish Mahendrakar     return false;
1444*103e46e4SHarish Mahendrakar 
1445*103e46e4SHarish Mahendrakar   alpha_mode_ = alpha_mode;
1446*103e46e4SHarish Mahendrakar   return true;
1447*103e46e4SHarish Mahendrakar }
1448*103e46e4SHarish Mahendrakar 
PayloadSize() const1449*103e46e4SHarish Mahendrakar uint64_t VideoTrack::PayloadSize() const {
1450*103e46e4SHarish Mahendrakar   const uint64_t parent_size = Track::PayloadSize();
1451*103e46e4SHarish Mahendrakar 
1452*103e46e4SHarish Mahendrakar   uint64_t size = VideoPayloadSize();
1453*103e46e4SHarish Mahendrakar   size += EbmlMasterElementSize(libwebm::kMkvVideo, size);
1454*103e46e4SHarish Mahendrakar 
1455*103e46e4SHarish Mahendrakar   return parent_size + size;
1456*103e46e4SHarish Mahendrakar }
1457*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const1458*103e46e4SHarish Mahendrakar bool VideoTrack::Write(IMkvWriter* writer) const {
1459*103e46e4SHarish Mahendrakar   if (!Track::Write(writer))
1460*103e46e4SHarish Mahendrakar     return false;
1461*103e46e4SHarish Mahendrakar 
1462*103e46e4SHarish Mahendrakar   const uint64_t size = VideoPayloadSize();
1463*103e46e4SHarish Mahendrakar 
1464*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvVideo, size))
1465*103e46e4SHarish Mahendrakar     return false;
1466*103e46e4SHarish Mahendrakar 
1467*103e46e4SHarish Mahendrakar   const int64_t payload_position = writer->Position();
1468*103e46e4SHarish Mahendrakar   if (payload_position < 0)
1469*103e46e4SHarish Mahendrakar     return false;
1470*103e46e4SHarish Mahendrakar 
1471*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(
1472*103e46e4SHarish Mahendrakar           writer, libwebm::kMkvPixelWidth,
1473*103e46e4SHarish Mahendrakar           static_cast<uint64>((pixel_width_ > 0) ? pixel_width_ : width_)))
1474*103e46e4SHarish Mahendrakar     return false;
1475*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(
1476*103e46e4SHarish Mahendrakar           writer, libwebm::kMkvPixelHeight,
1477*103e46e4SHarish Mahendrakar           static_cast<uint64>((pixel_height_ > 0) ? pixel_height_ : height_)))
1478*103e46e4SHarish Mahendrakar     return false;
1479*103e46e4SHarish Mahendrakar   if (display_width_ > 0) {
1480*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvDisplayWidth,
1481*103e46e4SHarish Mahendrakar                           static_cast<uint64>(display_width_)))
1482*103e46e4SHarish Mahendrakar       return false;
1483*103e46e4SHarish Mahendrakar   }
1484*103e46e4SHarish Mahendrakar   if (display_height_ > 0) {
1485*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvDisplayHeight,
1486*103e46e4SHarish Mahendrakar                           static_cast<uint64>(display_height_)))
1487*103e46e4SHarish Mahendrakar       return false;
1488*103e46e4SHarish Mahendrakar   }
1489*103e46e4SHarish Mahendrakar   if (crop_left_ > 0) {
1490*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropLeft,
1491*103e46e4SHarish Mahendrakar                           static_cast<uint64>(crop_left_)))
1492*103e46e4SHarish Mahendrakar       return false;
1493*103e46e4SHarish Mahendrakar   }
1494*103e46e4SHarish Mahendrakar   if (crop_right_ > 0) {
1495*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropRight,
1496*103e46e4SHarish Mahendrakar                           static_cast<uint64>(crop_right_)))
1497*103e46e4SHarish Mahendrakar       return false;
1498*103e46e4SHarish Mahendrakar   }
1499*103e46e4SHarish Mahendrakar   if (crop_top_ > 0) {
1500*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropTop,
1501*103e46e4SHarish Mahendrakar                           static_cast<uint64>(crop_top_)))
1502*103e46e4SHarish Mahendrakar       return false;
1503*103e46e4SHarish Mahendrakar   }
1504*103e46e4SHarish Mahendrakar   if (crop_bottom_ > 0) {
1505*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropBottom,
1506*103e46e4SHarish Mahendrakar                           static_cast<uint64>(crop_bottom_)))
1507*103e46e4SHarish Mahendrakar       return false;
1508*103e46e4SHarish Mahendrakar   }
1509*103e46e4SHarish Mahendrakar   if (stereo_mode_ > kMono) {
1510*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvStereoMode,
1511*103e46e4SHarish Mahendrakar                           static_cast<uint64>(stereo_mode_)))
1512*103e46e4SHarish Mahendrakar       return false;
1513*103e46e4SHarish Mahendrakar   }
1514*103e46e4SHarish Mahendrakar   if (alpha_mode_ > kNoAlpha) {
1515*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvAlphaMode,
1516*103e46e4SHarish Mahendrakar                           static_cast<uint64>(alpha_mode_)))
1517*103e46e4SHarish Mahendrakar       return false;
1518*103e46e4SHarish Mahendrakar   }
1519*103e46e4SHarish Mahendrakar   if (colour_space_) {
1520*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvColourSpace, colour_space_))
1521*103e46e4SHarish Mahendrakar       return false;
1522*103e46e4SHarish Mahendrakar   }
1523*103e46e4SHarish Mahendrakar   if (frame_rate_ > 0.0) {
1524*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvFrameRate,
1525*103e46e4SHarish Mahendrakar                           static_cast<float>(frame_rate_))) {
1526*103e46e4SHarish Mahendrakar       return false;
1527*103e46e4SHarish Mahendrakar     }
1528*103e46e4SHarish Mahendrakar   }
1529*103e46e4SHarish Mahendrakar   if (colour_) {
1530*103e46e4SHarish Mahendrakar     if (!colour_->Write(writer))
1531*103e46e4SHarish Mahendrakar       return false;
1532*103e46e4SHarish Mahendrakar   }
1533*103e46e4SHarish Mahendrakar   if (projection_) {
1534*103e46e4SHarish Mahendrakar     if (!projection_->Write(writer))
1535*103e46e4SHarish Mahendrakar       return false;
1536*103e46e4SHarish Mahendrakar   }
1537*103e46e4SHarish Mahendrakar 
1538*103e46e4SHarish Mahendrakar   const int64_t stop_position = writer->Position();
1539*103e46e4SHarish Mahendrakar   if (stop_position < 0 ||
1540*103e46e4SHarish Mahendrakar       stop_position - payload_position != static_cast<int64_t>(size)) {
1541*103e46e4SHarish Mahendrakar     return false;
1542*103e46e4SHarish Mahendrakar   }
1543*103e46e4SHarish Mahendrakar 
1544*103e46e4SHarish Mahendrakar   return true;
1545*103e46e4SHarish Mahendrakar }
1546*103e46e4SHarish Mahendrakar 
set_colour_space(const char * colour_space)1547*103e46e4SHarish Mahendrakar void VideoTrack::set_colour_space(const char* colour_space) {
1548*103e46e4SHarish Mahendrakar   if (colour_space) {
1549*103e46e4SHarish Mahendrakar     delete[] colour_space_;
1550*103e46e4SHarish Mahendrakar 
1551*103e46e4SHarish Mahendrakar     const size_t length = strlen(colour_space) + 1;
1552*103e46e4SHarish Mahendrakar     colour_space_ = new (std::nothrow) char[length];  // NOLINT
1553*103e46e4SHarish Mahendrakar     if (colour_space_) {
1554*103e46e4SHarish Mahendrakar       memcpy(colour_space_, colour_space, length - 1);
1555*103e46e4SHarish Mahendrakar       colour_space_[length - 1] = '\0';
1556*103e46e4SHarish Mahendrakar     }
1557*103e46e4SHarish Mahendrakar   }
1558*103e46e4SHarish Mahendrakar }
1559*103e46e4SHarish Mahendrakar 
SetColour(const Colour & colour)1560*103e46e4SHarish Mahendrakar bool VideoTrack::SetColour(const Colour& colour) {
1561*103e46e4SHarish Mahendrakar   std::unique_ptr<Colour> colour_ptr(new Colour());
1562*103e46e4SHarish Mahendrakar   if (!colour_ptr.get())
1563*103e46e4SHarish Mahendrakar     return false;
1564*103e46e4SHarish Mahendrakar 
1565*103e46e4SHarish Mahendrakar   if (colour.mastering_metadata()) {
1566*103e46e4SHarish Mahendrakar     if (!colour_ptr->SetMasteringMetadata(*colour.mastering_metadata()))
1567*103e46e4SHarish Mahendrakar       return false;
1568*103e46e4SHarish Mahendrakar   }
1569*103e46e4SHarish Mahendrakar 
1570*103e46e4SHarish Mahendrakar   colour_ptr->set_matrix_coefficients(colour.matrix_coefficients());
1571*103e46e4SHarish Mahendrakar   colour_ptr->set_bits_per_channel(colour.bits_per_channel());
1572*103e46e4SHarish Mahendrakar   colour_ptr->set_chroma_subsampling_horz(colour.chroma_subsampling_horz());
1573*103e46e4SHarish Mahendrakar   colour_ptr->set_chroma_subsampling_vert(colour.chroma_subsampling_vert());
1574*103e46e4SHarish Mahendrakar   colour_ptr->set_cb_subsampling_horz(colour.cb_subsampling_horz());
1575*103e46e4SHarish Mahendrakar   colour_ptr->set_cb_subsampling_vert(colour.cb_subsampling_vert());
1576*103e46e4SHarish Mahendrakar   colour_ptr->set_chroma_siting_horz(colour.chroma_siting_horz());
1577*103e46e4SHarish Mahendrakar   colour_ptr->set_chroma_siting_vert(colour.chroma_siting_vert());
1578*103e46e4SHarish Mahendrakar   colour_ptr->set_range(colour.range());
1579*103e46e4SHarish Mahendrakar   colour_ptr->set_transfer_characteristics(colour.transfer_characteristics());
1580*103e46e4SHarish Mahendrakar   colour_ptr->set_primaries(colour.primaries());
1581*103e46e4SHarish Mahendrakar   colour_ptr->set_max_cll(colour.max_cll());
1582*103e46e4SHarish Mahendrakar   colour_ptr->set_max_fall(colour.max_fall());
1583*103e46e4SHarish Mahendrakar   delete colour_;
1584*103e46e4SHarish Mahendrakar   colour_ = colour_ptr.release();
1585*103e46e4SHarish Mahendrakar   return true;
1586*103e46e4SHarish Mahendrakar }
1587*103e46e4SHarish Mahendrakar 
SetProjection(const Projection & projection)1588*103e46e4SHarish Mahendrakar bool VideoTrack::SetProjection(const Projection& projection) {
1589*103e46e4SHarish Mahendrakar   std::unique_ptr<Projection> projection_ptr(new Projection());
1590*103e46e4SHarish Mahendrakar   if (!projection_ptr.get())
1591*103e46e4SHarish Mahendrakar     return false;
1592*103e46e4SHarish Mahendrakar 
1593*103e46e4SHarish Mahendrakar   if (projection.private_data()) {
1594*103e46e4SHarish Mahendrakar     if (!projection_ptr->SetProjectionPrivate(
1595*103e46e4SHarish Mahendrakar             projection.private_data(), projection.private_data_length())) {
1596*103e46e4SHarish Mahendrakar       return false;
1597*103e46e4SHarish Mahendrakar     }
1598*103e46e4SHarish Mahendrakar   }
1599*103e46e4SHarish Mahendrakar 
1600*103e46e4SHarish Mahendrakar   projection_ptr->set_type(projection.type());
1601*103e46e4SHarish Mahendrakar   projection_ptr->set_pose_yaw(projection.pose_yaw());
1602*103e46e4SHarish Mahendrakar   projection_ptr->set_pose_pitch(projection.pose_pitch());
1603*103e46e4SHarish Mahendrakar   projection_ptr->set_pose_roll(projection.pose_roll());
1604*103e46e4SHarish Mahendrakar   delete projection_;
1605*103e46e4SHarish Mahendrakar   projection_ = projection_ptr.release();
1606*103e46e4SHarish Mahendrakar   return true;
1607*103e46e4SHarish Mahendrakar }
1608*103e46e4SHarish Mahendrakar 
VideoPayloadSize() const1609*103e46e4SHarish Mahendrakar uint64_t VideoTrack::VideoPayloadSize() const {
1610*103e46e4SHarish Mahendrakar   uint64_t size = EbmlElementSize(
1611*103e46e4SHarish Mahendrakar       libwebm::kMkvPixelWidth,
1612*103e46e4SHarish Mahendrakar       static_cast<uint64>((pixel_width_ > 0) ? pixel_width_ : width_));
1613*103e46e4SHarish Mahendrakar   size += EbmlElementSize(
1614*103e46e4SHarish Mahendrakar       libwebm::kMkvPixelHeight,
1615*103e46e4SHarish Mahendrakar       static_cast<uint64>((pixel_height_ > 0) ? pixel_height_ : height_));
1616*103e46e4SHarish Mahendrakar   if (display_width_ > 0)
1617*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvDisplayWidth,
1618*103e46e4SHarish Mahendrakar                             static_cast<uint64>(display_width_));
1619*103e46e4SHarish Mahendrakar   if (display_height_ > 0)
1620*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvDisplayHeight,
1621*103e46e4SHarish Mahendrakar                             static_cast<uint64>(display_height_));
1622*103e46e4SHarish Mahendrakar   if (crop_left_ > 0)
1623*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvPixelCropLeft,
1624*103e46e4SHarish Mahendrakar                             static_cast<uint64>(crop_left_));
1625*103e46e4SHarish Mahendrakar   if (crop_right_ > 0)
1626*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvPixelCropRight,
1627*103e46e4SHarish Mahendrakar                             static_cast<uint64>(crop_right_));
1628*103e46e4SHarish Mahendrakar   if (crop_top_ > 0)
1629*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvPixelCropTop,
1630*103e46e4SHarish Mahendrakar                             static_cast<uint64>(crop_top_));
1631*103e46e4SHarish Mahendrakar   if (crop_bottom_ > 0)
1632*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvPixelCropBottom,
1633*103e46e4SHarish Mahendrakar                             static_cast<uint64>(crop_bottom_));
1634*103e46e4SHarish Mahendrakar   if (stereo_mode_ > kMono)
1635*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvStereoMode,
1636*103e46e4SHarish Mahendrakar                             static_cast<uint64>(stereo_mode_));
1637*103e46e4SHarish Mahendrakar   if (alpha_mode_ > kNoAlpha)
1638*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvAlphaMode,
1639*103e46e4SHarish Mahendrakar                             static_cast<uint64>(alpha_mode_));
1640*103e46e4SHarish Mahendrakar   if (frame_rate_ > 0.0)
1641*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvFrameRate,
1642*103e46e4SHarish Mahendrakar                             static_cast<float>(frame_rate_));
1643*103e46e4SHarish Mahendrakar   if (colour_space_)
1644*103e46e4SHarish Mahendrakar     size += EbmlElementSize(libwebm::kMkvColourSpace, colour_space_);
1645*103e46e4SHarish Mahendrakar   if (colour_)
1646*103e46e4SHarish Mahendrakar     size += colour_->ColourSize();
1647*103e46e4SHarish Mahendrakar   if (projection_)
1648*103e46e4SHarish Mahendrakar     size += projection_->ProjectionSize();
1649*103e46e4SHarish Mahendrakar 
1650*103e46e4SHarish Mahendrakar   return size;
1651*103e46e4SHarish Mahendrakar }
1652*103e46e4SHarish Mahendrakar 
1653*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
1654*103e46e4SHarish Mahendrakar //
1655*103e46e4SHarish Mahendrakar // AudioTrack Class
1656*103e46e4SHarish Mahendrakar 
AudioTrack(unsigned int * seed)1657*103e46e4SHarish Mahendrakar AudioTrack::AudioTrack(unsigned int* seed)
1658*103e46e4SHarish Mahendrakar     : Track(seed), bit_depth_(0), channels_(1), sample_rate_(0.0) {}
1659*103e46e4SHarish Mahendrakar 
~AudioTrack()1660*103e46e4SHarish Mahendrakar AudioTrack::~AudioTrack() {}
1661*103e46e4SHarish Mahendrakar 
PayloadSize() const1662*103e46e4SHarish Mahendrakar uint64_t AudioTrack::PayloadSize() const {
1663*103e46e4SHarish Mahendrakar   const uint64_t parent_size = Track::PayloadSize();
1664*103e46e4SHarish Mahendrakar 
1665*103e46e4SHarish Mahendrakar   uint64_t size = EbmlElementSize(libwebm::kMkvSamplingFrequency,
1666*103e46e4SHarish Mahendrakar                                   static_cast<float>(sample_rate_));
1667*103e46e4SHarish Mahendrakar   size +=
1668*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvChannels, static_cast<uint64>(channels_));
1669*103e46e4SHarish Mahendrakar   if (bit_depth_ > 0)
1670*103e46e4SHarish Mahendrakar     size +=
1671*103e46e4SHarish Mahendrakar         EbmlElementSize(libwebm::kMkvBitDepth, static_cast<uint64>(bit_depth_));
1672*103e46e4SHarish Mahendrakar   size += EbmlMasterElementSize(libwebm::kMkvAudio, size);
1673*103e46e4SHarish Mahendrakar 
1674*103e46e4SHarish Mahendrakar   return parent_size + size;
1675*103e46e4SHarish Mahendrakar }
1676*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const1677*103e46e4SHarish Mahendrakar bool AudioTrack::Write(IMkvWriter* writer) const {
1678*103e46e4SHarish Mahendrakar   if (!Track::Write(writer))
1679*103e46e4SHarish Mahendrakar     return false;
1680*103e46e4SHarish Mahendrakar 
1681*103e46e4SHarish Mahendrakar   // Calculate AudioSettings size.
1682*103e46e4SHarish Mahendrakar   uint64_t size = EbmlElementSize(libwebm::kMkvSamplingFrequency,
1683*103e46e4SHarish Mahendrakar                                   static_cast<float>(sample_rate_));
1684*103e46e4SHarish Mahendrakar   size +=
1685*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvChannels, static_cast<uint64>(channels_));
1686*103e46e4SHarish Mahendrakar   if (bit_depth_ > 0)
1687*103e46e4SHarish Mahendrakar     size +=
1688*103e46e4SHarish Mahendrakar         EbmlElementSize(libwebm::kMkvBitDepth, static_cast<uint64>(bit_depth_));
1689*103e46e4SHarish Mahendrakar 
1690*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvAudio, size))
1691*103e46e4SHarish Mahendrakar     return false;
1692*103e46e4SHarish Mahendrakar 
1693*103e46e4SHarish Mahendrakar   const int64_t payload_position = writer->Position();
1694*103e46e4SHarish Mahendrakar   if (payload_position < 0)
1695*103e46e4SHarish Mahendrakar     return false;
1696*103e46e4SHarish Mahendrakar 
1697*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvSamplingFrequency,
1698*103e46e4SHarish Mahendrakar                         static_cast<float>(sample_rate_)))
1699*103e46e4SHarish Mahendrakar     return false;
1700*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvChannels,
1701*103e46e4SHarish Mahendrakar                         static_cast<uint64>(channels_)))
1702*103e46e4SHarish Mahendrakar     return false;
1703*103e46e4SHarish Mahendrakar   if (bit_depth_ > 0)
1704*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvBitDepth,
1705*103e46e4SHarish Mahendrakar                           static_cast<uint64>(bit_depth_)))
1706*103e46e4SHarish Mahendrakar       return false;
1707*103e46e4SHarish Mahendrakar 
1708*103e46e4SHarish Mahendrakar   const int64_t stop_position = writer->Position();
1709*103e46e4SHarish Mahendrakar   if (stop_position < 0 ||
1710*103e46e4SHarish Mahendrakar       stop_position - payload_position != static_cast<int64_t>(size))
1711*103e46e4SHarish Mahendrakar     return false;
1712*103e46e4SHarish Mahendrakar 
1713*103e46e4SHarish Mahendrakar   return true;
1714*103e46e4SHarish Mahendrakar }
1715*103e46e4SHarish Mahendrakar 
1716*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
1717*103e46e4SHarish Mahendrakar //
1718*103e46e4SHarish Mahendrakar // Tracks Class
1719*103e46e4SHarish Mahendrakar 
1720*103e46e4SHarish Mahendrakar const char Tracks::kOpusCodecId[] = "A_OPUS";
1721*103e46e4SHarish Mahendrakar const char Tracks::kVorbisCodecId[] = "A_VORBIS";
1722*103e46e4SHarish Mahendrakar const char Tracks::kAv1CodecId[] = "V_AV1";
1723*103e46e4SHarish Mahendrakar const char Tracks::kVp8CodecId[] = "V_VP8";
1724*103e46e4SHarish Mahendrakar const char Tracks::kVp9CodecId[] = "V_VP9";
1725*103e46e4SHarish Mahendrakar const char Tracks::kWebVttCaptionsId[] = "D_WEBVTT/CAPTIONS";
1726*103e46e4SHarish Mahendrakar const char Tracks::kWebVttDescriptionsId[] = "D_WEBVTT/DESCRIPTIONS";
1727*103e46e4SHarish Mahendrakar const char Tracks::kWebVttMetadataId[] = "D_WEBVTT/METADATA";
1728*103e46e4SHarish Mahendrakar const char Tracks::kWebVttSubtitlesId[] = "D_WEBVTT/SUBTITLES";
1729*103e46e4SHarish Mahendrakar 
Tracks()1730*103e46e4SHarish Mahendrakar Tracks::Tracks()
1731*103e46e4SHarish Mahendrakar     : track_entries_(NULL), track_entries_size_(0), wrote_tracks_(false) {}
1732*103e46e4SHarish Mahendrakar 
~Tracks()1733*103e46e4SHarish Mahendrakar Tracks::~Tracks() {
1734*103e46e4SHarish Mahendrakar   if (track_entries_) {
1735*103e46e4SHarish Mahendrakar     for (uint32_t i = 0; i < track_entries_size_; ++i) {
1736*103e46e4SHarish Mahendrakar       Track* const track = track_entries_[i];
1737*103e46e4SHarish Mahendrakar       delete track;
1738*103e46e4SHarish Mahendrakar     }
1739*103e46e4SHarish Mahendrakar     delete[] track_entries_;
1740*103e46e4SHarish Mahendrakar   }
1741*103e46e4SHarish Mahendrakar }
1742*103e46e4SHarish Mahendrakar 
AddTrack(Track * track,int32_t number)1743*103e46e4SHarish Mahendrakar bool Tracks::AddTrack(Track* track, int32_t number) {
1744*103e46e4SHarish Mahendrakar   if (number < 0 || wrote_tracks_)
1745*103e46e4SHarish Mahendrakar     return false;
1746*103e46e4SHarish Mahendrakar 
1747*103e46e4SHarish Mahendrakar   // This muxer only supports track numbers in the range [1, 126], in
1748*103e46e4SHarish Mahendrakar   // order to be able (to use Matroska integer representation) to
1749*103e46e4SHarish Mahendrakar   // serialize the block header (of which the track number is a part)
1750*103e46e4SHarish Mahendrakar   // for a frame using exactly 4 bytes.
1751*103e46e4SHarish Mahendrakar 
1752*103e46e4SHarish Mahendrakar   if (number > 0x7E)
1753*103e46e4SHarish Mahendrakar     return false;
1754*103e46e4SHarish Mahendrakar 
1755*103e46e4SHarish Mahendrakar   uint32_t track_num = number;
1756*103e46e4SHarish Mahendrakar 
1757*103e46e4SHarish Mahendrakar   if (track_num > 0) {
1758*103e46e4SHarish Mahendrakar     // Check to make sure a track does not already have |track_num|.
1759*103e46e4SHarish Mahendrakar     for (uint32_t i = 0; i < track_entries_size_; ++i) {
1760*103e46e4SHarish Mahendrakar       if (track_entries_[i]->number() == track_num)
1761*103e46e4SHarish Mahendrakar         return false;
1762*103e46e4SHarish Mahendrakar     }
1763*103e46e4SHarish Mahendrakar   }
1764*103e46e4SHarish Mahendrakar 
1765*103e46e4SHarish Mahendrakar   const uint32_t count = track_entries_size_ + 1;
1766*103e46e4SHarish Mahendrakar 
1767*103e46e4SHarish Mahendrakar   Track** const track_entries = new (std::nothrow) Track*[count];  // NOLINT
1768*103e46e4SHarish Mahendrakar   if (!track_entries)
1769*103e46e4SHarish Mahendrakar     return false;
1770*103e46e4SHarish Mahendrakar 
1771*103e46e4SHarish Mahendrakar   for (uint32_t i = 0; i < track_entries_size_; ++i) {
1772*103e46e4SHarish Mahendrakar     track_entries[i] = track_entries_[i];
1773*103e46e4SHarish Mahendrakar   }
1774*103e46e4SHarish Mahendrakar 
1775*103e46e4SHarish Mahendrakar   delete[] track_entries_;
1776*103e46e4SHarish Mahendrakar 
1777*103e46e4SHarish Mahendrakar   // Find the lowest availible track number > 0.
1778*103e46e4SHarish Mahendrakar   if (track_num == 0) {
1779*103e46e4SHarish Mahendrakar     track_num = count;
1780*103e46e4SHarish Mahendrakar 
1781*103e46e4SHarish Mahendrakar     // Check to make sure a track does not already have |track_num|.
1782*103e46e4SHarish Mahendrakar     bool exit = false;
1783*103e46e4SHarish Mahendrakar     do {
1784*103e46e4SHarish Mahendrakar       exit = true;
1785*103e46e4SHarish Mahendrakar       for (uint32_t i = 0; i < track_entries_size_; ++i) {
1786*103e46e4SHarish Mahendrakar         if (track_entries[i]->number() == track_num) {
1787*103e46e4SHarish Mahendrakar           track_num++;
1788*103e46e4SHarish Mahendrakar           exit = false;
1789*103e46e4SHarish Mahendrakar           break;
1790*103e46e4SHarish Mahendrakar         }
1791*103e46e4SHarish Mahendrakar       }
1792*103e46e4SHarish Mahendrakar     } while (!exit);
1793*103e46e4SHarish Mahendrakar   }
1794*103e46e4SHarish Mahendrakar   track->set_number(track_num);
1795*103e46e4SHarish Mahendrakar 
1796*103e46e4SHarish Mahendrakar   track_entries_ = track_entries;
1797*103e46e4SHarish Mahendrakar   track_entries_[track_entries_size_] = track;
1798*103e46e4SHarish Mahendrakar   track_entries_size_ = count;
1799*103e46e4SHarish Mahendrakar   return true;
1800*103e46e4SHarish Mahendrakar }
1801*103e46e4SHarish Mahendrakar 
GetTrackByIndex(uint32_t index) const1802*103e46e4SHarish Mahendrakar const Track* Tracks::GetTrackByIndex(uint32_t index) const {
1803*103e46e4SHarish Mahendrakar   if (track_entries_ == NULL)
1804*103e46e4SHarish Mahendrakar     return NULL;
1805*103e46e4SHarish Mahendrakar 
1806*103e46e4SHarish Mahendrakar   if (index >= track_entries_size_)
1807*103e46e4SHarish Mahendrakar     return NULL;
1808*103e46e4SHarish Mahendrakar 
1809*103e46e4SHarish Mahendrakar   return track_entries_[index];
1810*103e46e4SHarish Mahendrakar }
1811*103e46e4SHarish Mahendrakar 
GetTrackByNumber(uint64_t track_number) const1812*103e46e4SHarish Mahendrakar Track* Tracks::GetTrackByNumber(uint64_t track_number) const {
1813*103e46e4SHarish Mahendrakar   const int32_t count = track_entries_size();
1814*103e46e4SHarish Mahendrakar   for (int32_t i = 0; i < count; ++i) {
1815*103e46e4SHarish Mahendrakar     if (track_entries_[i]->number() == track_number)
1816*103e46e4SHarish Mahendrakar       return track_entries_[i];
1817*103e46e4SHarish Mahendrakar   }
1818*103e46e4SHarish Mahendrakar 
1819*103e46e4SHarish Mahendrakar   return NULL;
1820*103e46e4SHarish Mahendrakar }
1821*103e46e4SHarish Mahendrakar 
TrackIsAudio(uint64_t track_number) const1822*103e46e4SHarish Mahendrakar bool Tracks::TrackIsAudio(uint64_t track_number) const {
1823*103e46e4SHarish Mahendrakar   const Track* const track = GetTrackByNumber(track_number);
1824*103e46e4SHarish Mahendrakar 
1825*103e46e4SHarish Mahendrakar   if (track->type() == kAudio)
1826*103e46e4SHarish Mahendrakar     return true;
1827*103e46e4SHarish Mahendrakar 
1828*103e46e4SHarish Mahendrakar   return false;
1829*103e46e4SHarish Mahendrakar }
1830*103e46e4SHarish Mahendrakar 
TrackIsVideo(uint64_t track_number) const1831*103e46e4SHarish Mahendrakar bool Tracks::TrackIsVideo(uint64_t track_number) const {
1832*103e46e4SHarish Mahendrakar   const Track* const track = GetTrackByNumber(track_number);
1833*103e46e4SHarish Mahendrakar 
1834*103e46e4SHarish Mahendrakar   if (track->type() == kVideo)
1835*103e46e4SHarish Mahendrakar     return true;
1836*103e46e4SHarish Mahendrakar 
1837*103e46e4SHarish Mahendrakar   return false;
1838*103e46e4SHarish Mahendrakar }
1839*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const1840*103e46e4SHarish Mahendrakar bool Tracks::Write(IMkvWriter* writer) const {
1841*103e46e4SHarish Mahendrakar   uint64_t size = 0;
1842*103e46e4SHarish Mahendrakar   const int32_t count = track_entries_size();
1843*103e46e4SHarish Mahendrakar   for (int32_t i = 0; i < count; ++i) {
1844*103e46e4SHarish Mahendrakar     const Track* const track = GetTrackByIndex(i);
1845*103e46e4SHarish Mahendrakar 
1846*103e46e4SHarish Mahendrakar     if (!track)
1847*103e46e4SHarish Mahendrakar       return false;
1848*103e46e4SHarish Mahendrakar 
1849*103e46e4SHarish Mahendrakar     size += track->Size();
1850*103e46e4SHarish Mahendrakar   }
1851*103e46e4SHarish Mahendrakar 
1852*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvTracks, size))
1853*103e46e4SHarish Mahendrakar     return false;
1854*103e46e4SHarish Mahendrakar 
1855*103e46e4SHarish Mahendrakar   const int64_t payload_position = writer->Position();
1856*103e46e4SHarish Mahendrakar   if (payload_position < 0)
1857*103e46e4SHarish Mahendrakar     return false;
1858*103e46e4SHarish Mahendrakar 
1859*103e46e4SHarish Mahendrakar   for (int32_t i = 0; i < count; ++i) {
1860*103e46e4SHarish Mahendrakar     const Track* const track = GetTrackByIndex(i);
1861*103e46e4SHarish Mahendrakar     if (!track->Write(writer))
1862*103e46e4SHarish Mahendrakar       return false;
1863*103e46e4SHarish Mahendrakar   }
1864*103e46e4SHarish Mahendrakar 
1865*103e46e4SHarish Mahendrakar   const int64_t stop_position = writer->Position();
1866*103e46e4SHarish Mahendrakar   if (stop_position < 0 ||
1867*103e46e4SHarish Mahendrakar       stop_position - payload_position != static_cast<int64_t>(size))
1868*103e46e4SHarish Mahendrakar     return false;
1869*103e46e4SHarish Mahendrakar 
1870*103e46e4SHarish Mahendrakar   wrote_tracks_ = true;
1871*103e46e4SHarish Mahendrakar   return true;
1872*103e46e4SHarish Mahendrakar }
1873*103e46e4SHarish Mahendrakar 
1874*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
1875*103e46e4SHarish Mahendrakar //
1876*103e46e4SHarish Mahendrakar // Chapter Class
1877*103e46e4SHarish Mahendrakar 
set_id(const char * id)1878*103e46e4SHarish Mahendrakar bool Chapter::set_id(const char* id) { return StrCpy(id, &id_); }
1879*103e46e4SHarish Mahendrakar 
set_time(const Segment & segment,uint64_t start_ns,uint64_t end_ns)1880*103e46e4SHarish Mahendrakar void Chapter::set_time(const Segment& segment, uint64_t start_ns,
1881*103e46e4SHarish Mahendrakar                        uint64_t end_ns) {
1882*103e46e4SHarish Mahendrakar   const SegmentInfo* const info = segment.GetSegmentInfo();
1883*103e46e4SHarish Mahendrakar   const uint64_t timecode_scale = info->timecode_scale();
1884*103e46e4SHarish Mahendrakar   start_timecode_ = start_ns / timecode_scale;
1885*103e46e4SHarish Mahendrakar   end_timecode_ = end_ns / timecode_scale;
1886*103e46e4SHarish Mahendrakar }
1887*103e46e4SHarish Mahendrakar 
add_string(const char * title,const char * language,const char * country)1888*103e46e4SHarish Mahendrakar bool Chapter::add_string(const char* title, const char* language,
1889*103e46e4SHarish Mahendrakar                          const char* country) {
1890*103e46e4SHarish Mahendrakar   if (!ExpandDisplaysArray())
1891*103e46e4SHarish Mahendrakar     return false;
1892*103e46e4SHarish Mahendrakar 
1893*103e46e4SHarish Mahendrakar   Display& d = displays_[displays_count_++];
1894*103e46e4SHarish Mahendrakar   d.Init();
1895*103e46e4SHarish Mahendrakar 
1896*103e46e4SHarish Mahendrakar   if (!d.set_title(title))
1897*103e46e4SHarish Mahendrakar     return false;
1898*103e46e4SHarish Mahendrakar 
1899*103e46e4SHarish Mahendrakar   if (!d.set_language(language))
1900*103e46e4SHarish Mahendrakar     return false;
1901*103e46e4SHarish Mahendrakar 
1902*103e46e4SHarish Mahendrakar   if (!d.set_country(country))
1903*103e46e4SHarish Mahendrakar     return false;
1904*103e46e4SHarish Mahendrakar 
1905*103e46e4SHarish Mahendrakar   return true;
1906*103e46e4SHarish Mahendrakar }
1907*103e46e4SHarish Mahendrakar 
Chapter()1908*103e46e4SHarish Mahendrakar Chapter::Chapter() {
1909*103e46e4SHarish Mahendrakar   // This ctor only constructs the object.  Proper initialization is
1910*103e46e4SHarish Mahendrakar   // done in Init() (called in Chapters::AddChapter()).  The only
1911*103e46e4SHarish Mahendrakar   // reason we bother implementing this ctor is because we had to
1912*103e46e4SHarish Mahendrakar   // declare it as private (along with the dtor), in order to prevent
1913*103e46e4SHarish Mahendrakar   // clients from creating Chapter instances (a privelege we grant
1914*103e46e4SHarish Mahendrakar   // only to the Chapters class).  Doing no initialization here also
1915*103e46e4SHarish Mahendrakar   // means that creating arrays of chapter objects is more efficient,
1916*103e46e4SHarish Mahendrakar   // because we only initialize each new chapter object as it becomes
1917*103e46e4SHarish Mahendrakar   // active on the array.
1918*103e46e4SHarish Mahendrakar }
1919*103e46e4SHarish Mahendrakar 
~Chapter()1920*103e46e4SHarish Mahendrakar Chapter::~Chapter() {}
1921*103e46e4SHarish Mahendrakar 
Init(unsigned int * seed)1922*103e46e4SHarish Mahendrakar void Chapter::Init(unsigned int* seed) {
1923*103e46e4SHarish Mahendrakar   id_ = NULL;
1924*103e46e4SHarish Mahendrakar   start_timecode_ = 0;
1925*103e46e4SHarish Mahendrakar   end_timecode_ = 0;
1926*103e46e4SHarish Mahendrakar   displays_ = NULL;
1927*103e46e4SHarish Mahendrakar   displays_size_ = 0;
1928*103e46e4SHarish Mahendrakar   displays_count_ = 0;
1929*103e46e4SHarish Mahendrakar   uid_ = MakeUID(seed);
1930*103e46e4SHarish Mahendrakar }
1931*103e46e4SHarish Mahendrakar 
ShallowCopy(Chapter * dst) const1932*103e46e4SHarish Mahendrakar void Chapter::ShallowCopy(Chapter* dst) const {
1933*103e46e4SHarish Mahendrakar   dst->id_ = id_;
1934*103e46e4SHarish Mahendrakar   dst->start_timecode_ = start_timecode_;
1935*103e46e4SHarish Mahendrakar   dst->end_timecode_ = end_timecode_;
1936*103e46e4SHarish Mahendrakar   dst->uid_ = uid_;
1937*103e46e4SHarish Mahendrakar   dst->displays_ = displays_;
1938*103e46e4SHarish Mahendrakar   dst->displays_size_ = displays_size_;
1939*103e46e4SHarish Mahendrakar   dst->displays_count_ = displays_count_;
1940*103e46e4SHarish Mahendrakar }
1941*103e46e4SHarish Mahendrakar 
Clear()1942*103e46e4SHarish Mahendrakar void Chapter::Clear() {
1943*103e46e4SHarish Mahendrakar   StrCpy(NULL, &id_);
1944*103e46e4SHarish Mahendrakar 
1945*103e46e4SHarish Mahendrakar   while (displays_count_ > 0) {
1946*103e46e4SHarish Mahendrakar     Display& d = displays_[--displays_count_];
1947*103e46e4SHarish Mahendrakar     d.Clear();
1948*103e46e4SHarish Mahendrakar   }
1949*103e46e4SHarish Mahendrakar 
1950*103e46e4SHarish Mahendrakar   delete[] displays_;
1951*103e46e4SHarish Mahendrakar   displays_ = NULL;
1952*103e46e4SHarish Mahendrakar 
1953*103e46e4SHarish Mahendrakar   displays_size_ = 0;
1954*103e46e4SHarish Mahendrakar }
1955*103e46e4SHarish Mahendrakar 
ExpandDisplaysArray()1956*103e46e4SHarish Mahendrakar bool Chapter::ExpandDisplaysArray() {
1957*103e46e4SHarish Mahendrakar   if (displays_size_ > displays_count_)
1958*103e46e4SHarish Mahendrakar     return true;  // nothing to do yet
1959*103e46e4SHarish Mahendrakar 
1960*103e46e4SHarish Mahendrakar   const int size = (displays_size_ == 0) ? 1 : 2 * displays_size_;
1961*103e46e4SHarish Mahendrakar 
1962*103e46e4SHarish Mahendrakar   Display* const displays = new (std::nothrow) Display[size];  // NOLINT
1963*103e46e4SHarish Mahendrakar   if (displays == NULL)
1964*103e46e4SHarish Mahendrakar     return false;
1965*103e46e4SHarish Mahendrakar 
1966*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < displays_count_; ++idx) {
1967*103e46e4SHarish Mahendrakar     displays[idx] = displays_[idx];  // shallow copy
1968*103e46e4SHarish Mahendrakar   }
1969*103e46e4SHarish Mahendrakar 
1970*103e46e4SHarish Mahendrakar   delete[] displays_;
1971*103e46e4SHarish Mahendrakar 
1972*103e46e4SHarish Mahendrakar   displays_ = displays;
1973*103e46e4SHarish Mahendrakar   displays_size_ = size;
1974*103e46e4SHarish Mahendrakar 
1975*103e46e4SHarish Mahendrakar   return true;
1976*103e46e4SHarish Mahendrakar }
1977*103e46e4SHarish Mahendrakar 
WriteAtom(IMkvWriter * writer) const1978*103e46e4SHarish Mahendrakar uint64_t Chapter::WriteAtom(IMkvWriter* writer) const {
1979*103e46e4SHarish Mahendrakar   uint64_t payload_size =
1980*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvChapterStringUID, id_) +
1981*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvChapterUID, static_cast<uint64>(uid_)) +
1982*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvChapterTimeStart,
1983*103e46e4SHarish Mahendrakar                       static_cast<uint64>(start_timecode_)) +
1984*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvChapterTimeEnd,
1985*103e46e4SHarish Mahendrakar                       static_cast<uint64>(end_timecode_));
1986*103e46e4SHarish Mahendrakar 
1987*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < displays_count_; ++idx) {
1988*103e46e4SHarish Mahendrakar     const Display& d = displays_[idx];
1989*103e46e4SHarish Mahendrakar     payload_size += d.WriteDisplay(NULL);
1990*103e46e4SHarish Mahendrakar   }
1991*103e46e4SHarish Mahendrakar 
1992*103e46e4SHarish Mahendrakar   const uint64_t atom_size =
1993*103e46e4SHarish Mahendrakar       EbmlMasterElementSize(libwebm::kMkvChapterAtom, payload_size) +
1994*103e46e4SHarish Mahendrakar       payload_size;
1995*103e46e4SHarish Mahendrakar 
1996*103e46e4SHarish Mahendrakar   if (writer == NULL)
1997*103e46e4SHarish Mahendrakar     return atom_size;
1998*103e46e4SHarish Mahendrakar 
1999*103e46e4SHarish Mahendrakar   const int64_t start = writer->Position();
2000*103e46e4SHarish Mahendrakar 
2001*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapterAtom, payload_size))
2002*103e46e4SHarish Mahendrakar     return 0;
2003*103e46e4SHarish Mahendrakar 
2004*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvChapterStringUID, id_))
2005*103e46e4SHarish Mahendrakar     return 0;
2006*103e46e4SHarish Mahendrakar 
2007*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvChapterUID,
2008*103e46e4SHarish Mahendrakar                         static_cast<uint64>(uid_)))
2009*103e46e4SHarish Mahendrakar     return 0;
2010*103e46e4SHarish Mahendrakar 
2011*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeStart,
2012*103e46e4SHarish Mahendrakar                         static_cast<uint64>(start_timecode_)))
2013*103e46e4SHarish Mahendrakar     return 0;
2014*103e46e4SHarish Mahendrakar 
2015*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeEnd,
2016*103e46e4SHarish Mahendrakar                         static_cast<uint64>(end_timecode_)))
2017*103e46e4SHarish Mahendrakar     return 0;
2018*103e46e4SHarish Mahendrakar 
2019*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < displays_count_; ++idx) {
2020*103e46e4SHarish Mahendrakar     const Display& d = displays_[idx];
2021*103e46e4SHarish Mahendrakar 
2022*103e46e4SHarish Mahendrakar     if (!d.WriteDisplay(writer))
2023*103e46e4SHarish Mahendrakar       return 0;
2024*103e46e4SHarish Mahendrakar   }
2025*103e46e4SHarish Mahendrakar 
2026*103e46e4SHarish Mahendrakar   const int64_t stop = writer->Position();
2027*103e46e4SHarish Mahendrakar 
2028*103e46e4SHarish Mahendrakar   if (stop >= start && uint64_t(stop - start) != atom_size)
2029*103e46e4SHarish Mahendrakar     return 0;
2030*103e46e4SHarish Mahendrakar 
2031*103e46e4SHarish Mahendrakar   return atom_size;
2032*103e46e4SHarish Mahendrakar }
2033*103e46e4SHarish Mahendrakar 
Init()2034*103e46e4SHarish Mahendrakar void Chapter::Display::Init() {
2035*103e46e4SHarish Mahendrakar   title_ = NULL;
2036*103e46e4SHarish Mahendrakar   language_ = NULL;
2037*103e46e4SHarish Mahendrakar   country_ = NULL;
2038*103e46e4SHarish Mahendrakar }
2039*103e46e4SHarish Mahendrakar 
Clear()2040*103e46e4SHarish Mahendrakar void Chapter::Display::Clear() {
2041*103e46e4SHarish Mahendrakar   StrCpy(NULL, &title_);
2042*103e46e4SHarish Mahendrakar   StrCpy(NULL, &language_);
2043*103e46e4SHarish Mahendrakar   StrCpy(NULL, &country_);
2044*103e46e4SHarish Mahendrakar }
2045*103e46e4SHarish Mahendrakar 
set_title(const char * title)2046*103e46e4SHarish Mahendrakar bool Chapter::Display::set_title(const char* title) {
2047*103e46e4SHarish Mahendrakar   return StrCpy(title, &title_);
2048*103e46e4SHarish Mahendrakar }
2049*103e46e4SHarish Mahendrakar 
set_language(const char * language)2050*103e46e4SHarish Mahendrakar bool Chapter::Display::set_language(const char* language) {
2051*103e46e4SHarish Mahendrakar   return StrCpy(language, &language_);
2052*103e46e4SHarish Mahendrakar }
2053*103e46e4SHarish Mahendrakar 
set_country(const char * country)2054*103e46e4SHarish Mahendrakar bool Chapter::Display::set_country(const char* country) {
2055*103e46e4SHarish Mahendrakar   return StrCpy(country, &country_);
2056*103e46e4SHarish Mahendrakar }
2057*103e46e4SHarish Mahendrakar 
WriteDisplay(IMkvWriter * writer) const2058*103e46e4SHarish Mahendrakar uint64_t Chapter::Display::WriteDisplay(IMkvWriter* writer) const {
2059*103e46e4SHarish Mahendrakar   uint64_t payload_size = EbmlElementSize(libwebm::kMkvChapString, title_);
2060*103e46e4SHarish Mahendrakar 
2061*103e46e4SHarish Mahendrakar   if (language_)
2062*103e46e4SHarish Mahendrakar     payload_size += EbmlElementSize(libwebm::kMkvChapLanguage, language_);
2063*103e46e4SHarish Mahendrakar 
2064*103e46e4SHarish Mahendrakar   if (country_)
2065*103e46e4SHarish Mahendrakar     payload_size += EbmlElementSize(libwebm::kMkvChapCountry, country_);
2066*103e46e4SHarish Mahendrakar 
2067*103e46e4SHarish Mahendrakar   const uint64_t display_size =
2068*103e46e4SHarish Mahendrakar       EbmlMasterElementSize(libwebm::kMkvChapterDisplay, payload_size) +
2069*103e46e4SHarish Mahendrakar       payload_size;
2070*103e46e4SHarish Mahendrakar 
2071*103e46e4SHarish Mahendrakar   if (writer == NULL)
2072*103e46e4SHarish Mahendrakar     return display_size;
2073*103e46e4SHarish Mahendrakar 
2074*103e46e4SHarish Mahendrakar   const int64_t start = writer->Position();
2075*103e46e4SHarish Mahendrakar 
2076*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapterDisplay,
2077*103e46e4SHarish Mahendrakar                               payload_size))
2078*103e46e4SHarish Mahendrakar     return 0;
2079*103e46e4SHarish Mahendrakar 
2080*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvChapString, title_))
2081*103e46e4SHarish Mahendrakar     return 0;
2082*103e46e4SHarish Mahendrakar 
2083*103e46e4SHarish Mahendrakar   if (language_) {
2084*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvChapLanguage, language_))
2085*103e46e4SHarish Mahendrakar       return 0;
2086*103e46e4SHarish Mahendrakar   }
2087*103e46e4SHarish Mahendrakar 
2088*103e46e4SHarish Mahendrakar   if (country_) {
2089*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvChapCountry, country_))
2090*103e46e4SHarish Mahendrakar       return 0;
2091*103e46e4SHarish Mahendrakar   }
2092*103e46e4SHarish Mahendrakar 
2093*103e46e4SHarish Mahendrakar   const int64_t stop = writer->Position();
2094*103e46e4SHarish Mahendrakar 
2095*103e46e4SHarish Mahendrakar   if (stop >= start && uint64_t(stop - start) != display_size)
2096*103e46e4SHarish Mahendrakar     return 0;
2097*103e46e4SHarish Mahendrakar 
2098*103e46e4SHarish Mahendrakar   return display_size;
2099*103e46e4SHarish Mahendrakar }
2100*103e46e4SHarish Mahendrakar 
2101*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
2102*103e46e4SHarish Mahendrakar //
2103*103e46e4SHarish Mahendrakar // Chapters Class
2104*103e46e4SHarish Mahendrakar 
Chapters()2105*103e46e4SHarish Mahendrakar Chapters::Chapters() : chapters_size_(0), chapters_count_(0), chapters_(NULL) {}
2106*103e46e4SHarish Mahendrakar 
~Chapters()2107*103e46e4SHarish Mahendrakar Chapters::~Chapters() {
2108*103e46e4SHarish Mahendrakar   while (chapters_count_ > 0) {
2109*103e46e4SHarish Mahendrakar     Chapter& chapter = chapters_[--chapters_count_];
2110*103e46e4SHarish Mahendrakar     chapter.Clear();
2111*103e46e4SHarish Mahendrakar   }
2112*103e46e4SHarish Mahendrakar 
2113*103e46e4SHarish Mahendrakar   delete[] chapters_;
2114*103e46e4SHarish Mahendrakar   chapters_ = NULL;
2115*103e46e4SHarish Mahendrakar }
2116*103e46e4SHarish Mahendrakar 
Count() const2117*103e46e4SHarish Mahendrakar int Chapters::Count() const { return chapters_count_; }
2118*103e46e4SHarish Mahendrakar 
AddChapter(unsigned int * seed)2119*103e46e4SHarish Mahendrakar Chapter* Chapters::AddChapter(unsigned int* seed) {
2120*103e46e4SHarish Mahendrakar   if (!ExpandChaptersArray())
2121*103e46e4SHarish Mahendrakar     return NULL;
2122*103e46e4SHarish Mahendrakar 
2123*103e46e4SHarish Mahendrakar   Chapter& chapter = chapters_[chapters_count_++];
2124*103e46e4SHarish Mahendrakar   chapter.Init(seed);
2125*103e46e4SHarish Mahendrakar 
2126*103e46e4SHarish Mahendrakar   return &chapter;
2127*103e46e4SHarish Mahendrakar }
2128*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const2129*103e46e4SHarish Mahendrakar bool Chapters::Write(IMkvWriter* writer) const {
2130*103e46e4SHarish Mahendrakar   if (writer == NULL)
2131*103e46e4SHarish Mahendrakar     return false;
2132*103e46e4SHarish Mahendrakar 
2133*103e46e4SHarish Mahendrakar   const uint64_t payload_size = WriteEdition(NULL);  // return size only
2134*103e46e4SHarish Mahendrakar 
2135*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapters, payload_size))
2136*103e46e4SHarish Mahendrakar     return false;
2137*103e46e4SHarish Mahendrakar 
2138*103e46e4SHarish Mahendrakar   const int64_t start = writer->Position();
2139*103e46e4SHarish Mahendrakar 
2140*103e46e4SHarish Mahendrakar   if (WriteEdition(writer) == 0)  // error
2141*103e46e4SHarish Mahendrakar     return false;
2142*103e46e4SHarish Mahendrakar 
2143*103e46e4SHarish Mahendrakar   const int64_t stop = writer->Position();
2144*103e46e4SHarish Mahendrakar 
2145*103e46e4SHarish Mahendrakar   if (stop >= start && uint64_t(stop - start) != payload_size)
2146*103e46e4SHarish Mahendrakar     return false;
2147*103e46e4SHarish Mahendrakar 
2148*103e46e4SHarish Mahendrakar   return true;
2149*103e46e4SHarish Mahendrakar }
2150*103e46e4SHarish Mahendrakar 
ExpandChaptersArray()2151*103e46e4SHarish Mahendrakar bool Chapters::ExpandChaptersArray() {
2152*103e46e4SHarish Mahendrakar   if (chapters_size_ > chapters_count_)
2153*103e46e4SHarish Mahendrakar     return true;  // nothing to do yet
2154*103e46e4SHarish Mahendrakar 
2155*103e46e4SHarish Mahendrakar   const int size = (chapters_size_ == 0) ? 1 : 2 * chapters_size_;
2156*103e46e4SHarish Mahendrakar 
2157*103e46e4SHarish Mahendrakar   Chapter* const chapters = new (std::nothrow) Chapter[size];  // NOLINT
2158*103e46e4SHarish Mahendrakar   if (chapters == NULL)
2159*103e46e4SHarish Mahendrakar     return false;
2160*103e46e4SHarish Mahendrakar 
2161*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < chapters_count_; ++idx) {
2162*103e46e4SHarish Mahendrakar     const Chapter& src = chapters_[idx];
2163*103e46e4SHarish Mahendrakar     Chapter* const dst = chapters + idx;
2164*103e46e4SHarish Mahendrakar     src.ShallowCopy(dst);
2165*103e46e4SHarish Mahendrakar   }
2166*103e46e4SHarish Mahendrakar 
2167*103e46e4SHarish Mahendrakar   delete[] chapters_;
2168*103e46e4SHarish Mahendrakar 
2169*103e46e4SHarish Mahendrakar   chapters_ = chapters;
2170*103e46e4SHarish Mahendrakar   chapters_size_ = size;
2171*103e46e4SHarish Mahendrakar 
2172*103e46e4SHarish Mahendrakar   return true;
2173*103e46e4SHarish Mahendrakar }
2174*103e46e4SHarish Mahendrakar 
WriteEdition(IMkvWriter * writer) const2175*103e46e4SHarish Mahendrakar uint64_t Chapters::WriteEdition(IMkvWriter* writer) const {
2176*103e46e4SHarish Mahendrakar   uint64_t payload_size = 0;
2177*103e46e4SHarish Mahendrakar 
2178*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < chapters_count_; ++idx) {
2179*103e46e4SHarish Mahendrakar     const Chapter& chapter = chapters_[idx];
2180*103e46e4SHarish Mahendrakar     payload_size += chapter.WriteAtom(NULL);
2181*103e46e4SHarish Mahendrakar   }
2182*103e46e4SHarish Mahendrakar 
2183*103e46e4SHarish Mahendrakar   const uint64_t edition_size =
2184*103e46e4SHarish Mahendrakar       EbmlMasterElementSize(libwebm::kMkvEditionEntry, payload_size) +
2185*103e46e4SHarish Mahendrakar       payload_size;
2186*103e46e4SHarish Mahendrakar 
2187*103e46e4SHarish Mahendrakar   if (writer == NULL)  // return size only
2188*103e46e4SHarish Mahendrakar     return edition_size;
2189*103e46e4SHarish Mahendrakar 
2190*103e46e4SHarish Mahendrakar   const int64_t start = writer->Position();
2191*103e46e4SHarish Mahendrakar 
2192*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvEditionEntry, payload_size))
2193*103e46e4SHarish Mahendrakar     return 0;  // error
2194*103e46e4SHarish Mahendrakar 
2195*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < chapters_count_; ++idx) {
2196*103e46e4SHarish Mahendrakar     const Chapter& chapter = chapters_[idx];
2197*103e46e4SHarish Mahendrakar 
2198*103e46e4SHarish Mahendrakar     const uint64_t chapter_size = chapter.WriteAtom(writer);
2199*103e46e4SHarish Mahendrakar     if (chapter_size == 0)  // error
2200*103e46e4SHarish Mahendrakar       return 0;
2201*103e46e4SHarish Mahendrakar   }
2202*103e46e4SHarish Mahendrakar 
2203*103e46e4SHarish Mahendrakar   const int64_t stop = writer->Position();
2204*103e46e4SHarish Mahendrakar 
2205*103e46e4SHarish Mahendrakar   if (stop >= start && uint64_t(stop - start) != edition_size)
2206*103e46e4SHarish Mahendrakar     return 0;
2207*103e46e4SHarish Mahendrakar 
2208*103e46e4SHarish Mahendrakar   return edition_size;
2209*103e46e4SHarish Mahendrakar }
2210*103e46e4SHarish Mahendrakar 
2211*103e46e4SHarish Mahendrakar // Tag Class
2212*103e46e4SHarish Mahendrakar 
add_simple_tag(const char * tag_name,const char * tag_string)2213*103e46e4SHarish Mahendrakar bool Tag::add_simple_tag(const char* tag_name, const char* tag_string) {
2214*103e46e4SHarish Mahendrakar   if (!ExpandSimpleTagsArray())
2215*103e46e4SHarish Mahendrakar     return false;
2216*103e46e4SHarish Mahendrakar 
2217*103e46e4SHarish Mahendrakar   SimpleTag& st = simple_tags_[simple_tags_count_++];
2218*103e46e4SHarish Mahendrakar   st.Init();
2219*103e46e4SHarish Mahendrakar 
2220*103e46e4SHarish Mahendrakar   if (!st.set_tag_name(tag_name))
2221*103e46e4SHarish Mahendrakar     return false;
2222*103e46e4SHarish Mahendrakar 
2223*103e46e4SHarish Mahendrakar   if (!st.set_tag_string(tag_string))
2224*103e46e4SHarish Mahendrakar     return false;
2225*103e46e4SHarish Mahendrakar 
2226*103e46e4SHarish Mahendrakar   return true;
2227*103e46e4SHarish Mahendrakar }
2228*103e46e4SHarish Mahendrakar 
Tag()2229*103e46e4SHarish Mahendrakar Tag::Tag() {
2230*103e46e4SHarish Mahendrakar   simple_tags_ = NULL;
2231*103e46e4SHarish Mahendrakar   simple_tags_size_ = 0;
2232*103e46e4SHarish Mahendrakar   simple_tags_count_ = 0;
2233*103e46e4SHarish Mahendrakar }
2234*103e46e4SHarish Mahendrakar 
~Tag()2235*103e46e4SHarish Mahendrakar Tag::~Tag() {}
2236*103e46e4SHarish Mahendrakar 
ShallowCopy(Tag * dst) const2237*103e46e4SHarish Mahendrakar void Tag::ShallowCopy(Tag* dst) const {
2238*103e46e4SHarish Mahendrakar   dst->simple_tags_ = simple_tags_;
2239*103e46e4SHarish Mahendrakar   dst->simple_tags_size_ = simple_tags_size_;
2240*103e46e4SHarish Mahendrakar   dst->simple_tags_count_ = simple_tags_count_;
2241*103e46e4SHarish Mahendrakar }
2242*103e46e4SHarish Mahendrakar 
Clear()2243*103e46e4SHarish Mahendrakar void Tag::Clear() {
2244*103e46e4SHarish Mahendrakar   while (simple_tags_count_ > 0) {
2245*103e46e4SHarish Mahendrakar     SimpleTag& st = simple_tags_[--simple_tags_count_];
2246*103e46e4SHarish Mahendrakar     st.Clear();
2247*103e46e4SHarish Mahendrakar   }
2248*103e46e4SHarish Mahendrakar 
2249*103e46e4SHarish Mahendrakar   delete[] simple_tags_;
2250*103e46e4SHarish Mahendrakar   simple_tags_ = NULL;
2251*103e46e4SHarish Mahendrakar 
2252*103e46e4SHarish Mahendrakar   simple_tags_size_ = 0;
2253*103e46e4SHarish Mahendrakar }
2254*103e46e4SHarish Mahendrakar 
ExpandSimpleTagsArray()2255*103e46e4SHarish Mahendrakar bool Tag::ExpandSimpleTagsArray() {
2256*103e46e4SHarish Mahendrakar   if (simple_tags_size_ > simple_tags_count_)
2257*103e46e4SHarish Mahendrakar     return true;  // nothing to do yet
2258*103e46e4SHarish Mahendrakar 
2259*103e46e4SHarish Mahendrakar   const int size = (simple_tags_size_ == 0) ? 1 : 2 * simple_tags_size_;
2260*103e46e4SHarish Mahendrakar 
2261*103e46e4SHarish Mahendrakar   SimpleTag* const simple_tags = new (std::nothrow) SimpleTag[size];  // NOLINT
2262*103e46e4SHarish Mahendrakar   if (simple_tags == NULL)
2263*103e46e4SHarish Mahendrakar     return false;
2264*103e46e4SHarish Mahendrakar 
2265*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < simple_tags_count_; ++idx) {
2266*103e46e4SHarish Mahendrakar     simple_tags[idx] = simple_tags_[idx];  // shallow copy
2267*103e46e4SHarish Mahendrakar   }
2268*103e46e4SHarish Mahendrakar 
2269*103e46e4SHarish Mahendrakar   delete[] simple_tags_;
2270*103e46e4SHarish Mahendrakar 
2271*103e46e4SHarish Mahendrakar   simple_tags_ = simple_tags;
2272*103e46e4SHarish Mahendrakar   simple_tags_size_ = size;
2273*103e46e4SHarish Mahendrakar 
2274*103e46e4SHarish Mahendrakar   return true;
2275*103e46e4SHarish Mahendrakar }
2276*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const2277*103e46e4SHarish Mahendrakar uint64_t Tag::Write(IMkvWriter* writer) const {
2278*103e46e4SHarish Mahendrakar   uint64_t payload_size = 0;
2279*103e46e4SHarish Mahendrakar 
2280*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < simple_tags_count_; ++idx) {
2281*103e46e4SHarish Mahendrakar     const SimpleTag& st = simple_tags_[idx];
2282*103e46e4SHarish Mahendrakar     payload_size += st.Write(NULL);
2283*103e46e4SHarish Mahendrakar   }
2284*103e46e4SHarish Mahendrakar 
2285*103e46e4SHarish Mahendrakar   const uint64_t tag_size =
2286*103e46e4SHarish Mahendrakar       EbmlMasterElementSize(libwebm::kMkvTag, payload_size) + payload_size;
2287*103e46e4SHarish Mahendrakar 
2288*103e46e4SHarish Mahendrakar   if (writer == NULL)
2289*103e46e4SHarish Mahendrakar     return tag_size;
2290*103e46e4SHarish Mahendrakar 
2291*103e46e4SHarish Mahendrakar   const int64_t start = writer->Position();
2292*103e46e4SHarish Mahendrakar 
2293*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvTag, payload_size))
2294*103e46e4SHarish Mahendrakar     return 0;
2295*103e46e4SHarish Mahendrakar 
2296*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < simple_tags_count_; ++idx) {
2297*103e46e4SHarish Mahendrakar     const SimpleTag& st = simple_tags_[idx];
2298*103e46e4SHarish Mahendrakar 
2299*103e46e4SHarish Mahendrakar     if (!st.Write(writer))
2300*103e46e4SHarish Mahendrakar       return 0;
2301*103e46e4SHarish Mahendrakar   }
2302*103e46e4SHarish Mahendrakar 
2303*103e46e4SHarish Mahendrakar   const int64_t stop = writer->Position();
2304*103e46e4SHarish Mahendrakar 
2305*103e46e4SHarish Mahendrakar   if (stop >= start && uint64_t(stop - start) != tag_size)
2306*103e46e4SHarish Mahendrakar     return 0;
2307*103e46e4SHarish Mahendrakar 
2308*103e46e4SHarish Mahendrakar   return tag_size;
2309*103e46e4SHarish Mahendrakar }
2310*103e46e4SHarish Mahendrakar 
2311*103e46e4SHarish Mahendrakar // Tag::SimpleTag
2312*103e46e4SHarish Mahendrakar 
Init()2313*103e46e4SHarish Mahendrakar void Tag::SimpleTag::Init() {
2314*103e46e4SHarish Mahendrakar   tag_name_ = NULL;
2315*103e46e4SHarish Mahendrakar   tag_string_ = NULL;
2316*103e46e4SHarish Mahendrakar }
2317*103e46e4SHarish Mahendrakar 
Clear()2318*103e46e4SHarish Mahendrakar void Tag::SimpleTag::Clear() {
2319*103e46e4SHarish Mahendrakar   StrCpy(NULL, &tag_name_);
2320*103e46e4SHarish Mahendrakar   StrCpy(NULL, &tag_string_);
2321*103e46e4SHarish Mahendrakar }
2322*103e46e4SHarish Mahendrakar 
set_tag_name(const char * tag_name)2323*103e46e4SHarish Mahendrakar bool Tag::SimpleTag::set_tag_name(const char* tag_name) {
2324*103e46e4SHarish Mahendrakar   return StrCpy(tag_name, &tag_name_);
2325*103e46e4SHarish Mahendrakar }
2326*103e46e4SHarish Mahendrakar 
set_tag_string(const char * tag_string)2327*103e46e4SHarish Mahendrakar bool Tag::SimpleTag::set_tag_string(const char* tag_string) {
2328*103e46e4SHarish Mahendrakar   return StrCpy(tag_string, &tag_string_);
2329*103e46e4SHarish Mahendrakar }
2330*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const2331*103e46e4SHarish Mahendrakar uint64_t Tag::SimpleTag::Write(IMkvWriter* writer) const {
2332*103e46e4SHarish Mahendrakar   uint64_t payload_size = EbmlElementSize(libwebm::kMkvTagName, tag_name_);
2333*103e46e4SHarish Mahendrakar 
2334*103e46e4SHarish Mahendrakar   payload_size += EbmlElementSize(libwebm::kMkvTagString, tag_string_);
2335*103e46e4SHarish Mahendrakar 
2336*103e46e4SHarish Mahendrakar   const uint64_t simple_tag_size =
2337*103e46e4SHarish Mahendrakar       EbmlMasterElementSize(libwebm::kMkvSimpleTag, payload_size) +
2338*103e46e4SHarish Mahendrakar       payload_size;
2339*103e46e4SHarish Mahendrakar 
2340*103e46e4SHarish Mahendrakar   if (writer == NULL)
2341*103e46e4SHarish Mahendrakar     return simple_tag_size;
2342*103e46e4SHarish Mahendrakar 
2343*103e46e4SHarish Mahendrakar   const int64_t start = writer->Position();
2344*103e46e4SHarish Mahendrakar 
2345*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvSimpleTag, payload_size))
2346*103e46e4SHarish Mahendrakar     return 0;
2347*103e46e4SHarish Mahendrakar 
2348*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvTagName, tag_name_))
2349*103e46e4SHarish Mahendrakar     return 0;
2350*103e46e4SHarish Mahendrakar 
2351*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvTagString, tag_string_))
2352*103e46e4SHarish Mahendrakar     return 0;
2353*103e46e4SHarish Mahendrakar 
2354*103e46e4SHarish Mahendrakar   const int64_t stop = writer->Position();
2355*103e46e4SHarish Mahendrakar 
2356*103e46e4SHarish Mahendrakar   if (stop >= start && uint64_t(stop - start) != simple_tag_size)
2357*103e46e4SHarish Mahendrakar     return 0;
2358*103e46e4SHarish Mahendrakar 
2359*103e46e4SHarish Mahendrakar   return simple_tag_size;
2360*103e46e4SHarish Mahendrakar }
2361*103e46e4SHarish Mahendrakar 
2362*103e46e4SHarish Mahendrakar // Tags Class
2363*103e46e4SHarish Mahendrakar 
Tags()2364*103e46e4SHarish Mahendrakar Tags::Tags() : tags_size_(0), tags_count_(0), tags_(NULL) {}
2365*103e46e4SHarish Mahendrakar 
~Tags()2366*103e46e4SHarish Mahendrakar Tags::~Tags() {
2367*103e46e4SHarish Mahendrakar   while (tags_count_ > 0) {
2368*103e46e4SHarish Mahendrakar     Tag& tag = tags_[--tags_count_];
2369*103e46e4SHarish Mahendrakar     tag.Clear();
2370*103e46e4SHarish Mahendrakar   }
2371*103e46e4SHarish Mahendrakar 
2372*103e46e4SHarish Mahendrakar   delete[] tags_;
2373*103e46e4SHarish Mahendrakar   tags_ = NULL;
2374*103e46e4SHarish Mahendrakar }
2375*103e46e4SHarish Mahendrakar 
Count() const2376*103e46e4SHarish Mahendrakar int Tags::Count() const { return tags_count_; }
2377*103e46e4SHarish Mahendrakar 
AddTag()2378*103e46e4SHarish Mahendrakar Tag* Tags::AddTag() {
2379*103e46e4SHarish Mahendrakar   if (!ExpandTagsArray())
2380*103e46e4SHarish Mahendrakar     return NULL;
2381*103e46e4SHarish Mahendrakar 
2382*103e46e4SHarish Mahendrakar   Tag& tag = tags_[tags_count_++];
2383*103e46e4SHarish Mahendrakar 
2384*103e46e4SHarish Mahendrakar   return &tag;
2385*103e46e4SHarish Mahendrakar }
2386*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer) const2387*103e46e4SHarish Mahendrakar bool Tags::Write(IMkvWriter* writer) const {
2388*103e46e4SHarish Mahendrakar   if (writer == NULL)
2389*103e46e4SHarish Mahendrakar     return false;
2390*103e46e4SHarish Mahendrakar 
2391*103e46e4SHarish Mahendrakar   uint64_t payload_size = 0;
2392*103e46e4SHarish Mahendrakar 
2393*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < tags_count_; ++idx) {
2394*103e46e4SHarish Mahendrakar     const Tag& tag = tags_[idx];
2395*103e46e4SHarish Mahendrakar     payload_size += tag.Write(NULL);
2396*103e46e4SHarish Mahendrakar   }
2397*103e46e4SHarish Mahendrakar 
2398*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvTags, payload_size))
2399*103e46e4SHarish Mahendrakar     return false;
2400*103e46e4SHarish Mahendrakar 
2401*103e46e4SHarish Mahendrakar   const int64_t start = writer->Position();
2402*103e46e4SHarish Mahendrakar 
2403*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < tags_count_; ++idx) {
2404*103e46e4SHarish Mahendrakar     const Tag& tag = tags_[idx];
2405*103e46e4SHarish Mahendrakar 
2406*103e46e4SHarish Mahendrakar     const uint64_t tag_size = tag.Write(writer);
2407*103e46e4SHarish Mahendrakar     if (tag_size == 0)  // error
2408*103e46e4SHarish Mahendrakar       return 0;
2409*103e46e4SHarish Mahendrakar   }
2410*103e46e4SHarish Mahendrakar 
2411*103e46e4SHarish Mahendrakar   const int64_t stop = writer->Position();
2412*103e46e4SHarish Mahendrakar 
2413*103e46e4SHarish Mahendrakar   if (stop >= start && uint64_t(stop - start) != payload_size)
2414*103e46e4SHarish Mahendrakar     return false;
2415*103e46e4SHarish Mahendrakar 
2416*103e46e4SHarish Mahendrakar   return true;
2417*103e46e4SHarish Mahendrakar }
2418*103e46e4SHarish Mahendrakar 
ExpandTagsArray()2419*103e46e4SHarish Mahendrakar bool Tags::ExpandTagsArray() {
2420*103e46e4SHarish Mahendrakar   if (tags_size_ > tags_count_)
2421*103e46e4SHarish Mahendrakar     return true;  // nothing to do yet
2422*103e46e4SHarish Mahendrakar 
2423*103e46e4SHarish Mahendrakar   const int size = (tags_size_ == 0) ? 1 : 2 * tags_size_;
2424*103e46e4SHarish Mahendrakar 
2425*103e46e4SHarish Mahendrakar   Tag* const tags = new (std::nothrow) Tag[size];  // NOLINT
2426*103e46e4SHarish Mahendrakar   if (tags == NULL)
2427*103e46e4SHarish Mahendrakar     return false;
2428*103e46e4SHarish Mahendrakar 
2429*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < tags_count_; ++idx) {
2430*103e46e4SHarish Mahendrakar     const Tag& src = tags_[idx];
2431*103e46e4SHarish Mahendrakar     Tag* const dst = tags + idx;
2432*103e46e4SHarish Mahendrakar     src.ShallowCopy(dst);
2433*103e46e4SHarish Mahendrakar   }
2434*103e46e4SHarish Mahendrakar 
2435*103e46e4SHarish Mahendrakar   delete[] tags_;
2436*103e46e4SHarish Mahendrakar 
2437*103e46e4SHarish Mahendrakar   tags_ = tags;
2438*103e46e4SHarish Mahendrakar   tags_size_ = size;
2439*103e46e4SHarish Mahendrakar 
2440*103e46e4SHarish Mahendrakar   return true;
2441*103e46e4SHarish Mahendrakar }
2442*103e46e4SHarish Mahendrakar 
2443*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
2444*103e46e4SHarish Mahendrakar //
2445*103e46e4SHarish Mahendrakar // Cluster class
2446*103e46e4SHarish Mahendrakar 
Cluster(uint64_t timecode,int64_t cues_pos,uint64_t timecode_scale,bool write_last_frame_with_duration,bool fixed_size_timecode)2447*103e46e4SHarish Mahendrakar Cluster::Cluster(uint64_t timecode, int64_t cues_pos, uint64_t timecode_scale,
2448*103e46e4SHarish Mahendrakar                  bool write_last_frame_with_duration, bool fixed_size_timecode)
2449*103e46e4SHarish Mahendrakar     : blocks_added_(0),
2450*103e46e4SHarish Mahendrakar       finalized_(false),
2451*103e46e4SHarish Mahendrakar       fixed_size_timecode_(fixed_size_timecode),
2452*103e46e4SHarish Mahendrakar       header_written_(false),
2453*103e46e4SHarish Mahendrakar       payload_size_(0),
2454*103e46e4SHarish Mahendrakar       position_for_cues_(cues_pos),
2455*103e46e4SHarish Mahendrakar       size_position_(-1),
2456*103e46e4SHarish Mahendrakar       timecode_(timecode),
2457*103e46e4SHarish Mahendrakar       timecode_scale_(timecode_scale),
2458*103e46e4SHarish Mahendrakar       write_last_frame_with_duration_(write_last_frame_with_duration),
2459*103e46e4SHarish Mahendrakar       writer_(NULL) {}
2460*103e46e4SHarish Mahendrakar 
~Cluster()2461*103e46e4SHarish Mahendrakar Cluster::~Cluster() {
2462*103e46e4SHarish Mahendrakar   // Delete any stored frames that are left behind. This will happen if the
2463*103e46e4SHarish Mahendrakar   // Cluster was not Finalized for whatever reason.
2464*103e46e4SHarish Mahendrakar   while (!stored_frames_.empty()) {
2465*103e46e4SHarish Mahendrakar     while (!stored_frames_.begin()->second.empty()) {
2466*103e46e4SHarish Mahendrakar       delete stored_frames_.begin()->second.front();
2467*103e46e4SHarish Mahendrakar       stored_frames_.begin()->second.pop_front();
2468*103e46e4SHarish Mahendrakar     }
2469*103e46e4SHarish Mahendrakar     stored_frames_.erase(stored_frames_.begin()->first);
2470*103e46e4SHarish Mahendrakar   }
2471*103e46e4SHarish Mahendrakar }
2472*103e46e4SHarish Mahendrakar 
Init(IMkvWriter * ptr_writer)2473*103e46e4SHarish Mahendrakar bool Cluster::Init(IMkvWriter* ptr_writer) {
2474*103e46e4SHarish Mahendrakar   if (!ptr_writer) {
2475*103e46e4SHarish Mahendrakar     return false;
2476*103e46e4SHarish Mahendrakar   }
2477*103e46e4SHarish Mahendrakar   writer_ = ptr_writer;
2478*103e46e4SHarish Mahendrakar   return true;
2479*103e46e4SHarish Mahendrakar }
2480*103e46e4SHarish Mahendrakar 
AddFrame(const Frame * const frame)2481*103e46e4SHarish Mahendrakar bool Cluster::AddFrame(const Frame* const frame) {
2482*103e46e4SHarish Mahendrakar   return QueueOrWriteFrame(frame);
2483*103e46e4SHarish Mahendrakar }
2484*103e46e4SHarish Mahendrakar 
AddFrame(const uint8_t * data,uint64_t length,uint64_t track_number,uint64_t abs_timecode,bool is_key)2485*103e46e4SHarish Mahendrakar bool Cluster::AddFrame(const uint8_t* data, uint64_t length,
2486*103e46e4SHarish Mahendrakar                        uint64_t track_number, uint64_t abs_timecode,
2487*103e46e4SHarish Mahendrakar                        bool is_key) {
2488*103e46e4SHarish Mahendrakar   Frame frame;
2489*103e46e4SHarish Mahendrakar   if (!frame.Init(data, length))
2490*103e46e4SHarish Mahendrakar     return false;
2491*103e46e4SHarish Mahendrakar   frame.set_track_number(track_number);
2492*103e46e4SHarish Mahendrakar   frame.set_timestamp(abs_timecode);
2493*103e46e4SHarish Mahendrakar   frame.set_is_key(is_key);
2494*103e46e4SHarish Mahendrakar   return QueueOrWriteFrame(&frame);
2495*103e46e4SHarish Mahendrakar }
2496*103e46e4SHarish Mahendrakar 
AddFrameWithAdditional(const uint8_t * data,uint64_t length,const uint8_t * additional,uint64_t additional_length,uint64_t add_id,uint64_t track_number,uint64_t abs_timecode,bool is_key)2497*103e46e4SHarish Mahendrakar bool Cluster::AddFrameWithAdditional(const uint8_t* data, uint64_t length,
2498*103e46e4SHarish Mahendrakar                                      const uint8_t* additional,
2499*103e46e4SHarish Mahendrakar                                      uint64_t additional_length,
2500*103e46e4SHarish Mahendrakar                                      uint64_t add_id, uint64_t track_number,
2501*103e46e4SHarish Mahendrakar                                      uint64_t abs_timecode, bool is_key) {
2502*103e46e4SHarish Mahendrakar   if (!additional || additional_length == 0) {
2503*103e46e4SHarish Mahendrakar     return false;
2504*103e46e4SHarish Mahendrakar   }
2505*103e46e4SHarish Mahendrakar   Frame frame;
2506*103e46e4SHarish Mahendrakar   if (!frame.Init(data, length) ||
2507*103e46e4SHarish Mahendrakar       !frame.AddAdditionalData(additional, additional_length, add_id)) {
2508*103e46e4SHarish Mahendrakar     return false;
2509*103e46e4SHarish Mahendrakar   }
2510*103e46e4SHarish Mahendrakar   frame.set_track_number(track_number);
2511*103e46e4SHarish Mahendrakar   frame.set_timestamp(abs_timecode);
2512*103e46e4SHarish Mahendrakar   frame.set_is_key(is_key);
2513*103e46e4SHarish Mahendrakar   return QueueOrWriteFrame(&frame);
2514*103e46e4SHarish Mahendrakar }
2515*103e46e4SHarish Mahendrakar 
AddFrameWithDiscardPadding(const uint8_t * data,uint64_t length,int64_t discard_padding,uint64_t track_number,uint64_t abs_timecode,bool is_key)2516*103e46e4SHarish Mahendrakar bool Cluster::AddFrameWithDiscardPadding(const uint8_t* data, uint64_t length,
2517*103e46e4SHarish Mahendrakar                                          int64_t discard_padding,
2518*103e46e4SHarish Mahendrakar                                          uint64_t track_number,
2519*103e46e4SHarish Mahendrakar                                          uint64_t abs_timecode, bool is_key) {
2520*103e46e4SHarish Mahendrakar   Frame frame;
2521*103e46e4SHarish Mahendrakar   if (!frame.Init(data, length))
2522*103e46e4SHarish Mahendrakar     return false;
2523*103e46e4SHarish Mahendrakar   frame.set_discard_padding(discard_padding);
2524*103e46e4SHarish Mahendrakar   frame.set_track_number(track_number);
2525*103e46e4SHarish Mahendrakar   frame.set_timestamp(abs_timecode);
2526*103e46e4SHarish Mahendrakar   frame.set_is_key(is_key);
2527*103e46e4SHarish Mahendrakar   return QueueOrWriteFrame(&frame);
2528*103e46e4SHarish Mahendrakar }
2529*103e46e4SHarish Mahendrakar 
AddMetadata(const uint8_t * data,uint64_t length,uint64_t track_number,uint64_t abs_timecode,uint64_t duration_timecode)2530*103e46e4SHarish Mahendrakar bool Cluster::AddMetadata(const uint8_t* data, uint64_t length,
2531*103e46e4SHarish Mahendrakar                           uint64_t track_number, uint64_t abs_timecode,
2532*103e46e4SHarish Mahendrakar                           uint64_t duration_timecode) {
2533*103e46e4SHarish Mahendrakar   Frame frame;
2534*103e46e4SHarish Mahendrakar   if (!frame.Init(data, length))
2535*103e46e4SHarish Mahendrakar     return false;
2536*103e46e4SHarish Mahendrakar   frame.set_track_number(track_number);
2537*103e46e4SHarish Mahendrakar   frame.set_timestamp(abs_timecode);
2538*103e46e4SHarish Mahendrakar   frame.set_duration(duration_timecode);
2539*103e46e4SHarish Mahendrakar   frame.set_is_key(true);  // All metadata blocks are keyframes.
2540*103e46e4SHarish Mahendrakar   return QueueOrWriteFrame(&frame);
2541*103e46e4SHarish Mahendrakar }
2542*103e46e4SHarish Mahendrakar 
AddPayloadSize(uint64_t size)2543*103e46e4SHarish Mahendrakar void Cluster::AddPayloadSize(uint64_t size) { payload_size_ += size; }
2544*103e46e4SHarish Mahendrakar 
Finalize()2545*103e46e4SHarish Mahendrakar bool Cluster::Finalize() {
2546*103e46e4SHarish Mahendrakar   return !write_last_frame_with_duration_ && Finalize(false, 0);
2547*103e46e4SHarish Mahendrakar }
2548*103e46e4SHarish Mahendrakar 
Finalize(bool set_last_frame_duration,uint64_t duration)2549*103e46e4SHarish Mahendrakar bool Cluster::Finalize(bool set_last_frame_duration, uint64_t duration) {
2550*103e46e4SHarish Mahendrakar   if (!writer_ || finalized_)
2551*103e46e4SHarish Mahendrakar     return false;
2552*103e46e4SHarish Mahendrakar 
2553*103e46e4SHarish Mahendrakar   if (write_last_frame_with_duration_) {
2554*103e46e4SHarish Mahendrakar     // Write out held back Frames. This essentially performs a k-way merge
2555*103e46e4SHarish Mahendrakar     // across all tracks in the increasing order of timestamps.
2556*103e46e4SHarish Mahendrakar     while (!stored_frames_.empty()) {
2557*103e46e4SHarish Mahendrakar       Frame* frame = stored_frames_.begin()->second.front();
2558*103e46e4SHarish Mahendrakar 
2559*103e46e4SHarish Mahendrakar       // Get the next frame to write (frame with least timestamp across all
2560*103e46e4SHarish Mahendrakar       // tracks).
2561*103e46e4SHarish Mahendrakar       for (FrameMapIterator frames_iterator = ++stored_frames_.begin();
2562*103e46e4SHarish Mahendrakar            frames_iterator != stored_frames_.end(); ++frames_iterator) {
2563*103e46e4SHarish Mahendrakar         if (frames_iterator->second.front()->timestamp() < frame->timestamp()) {
2564*103e46e4SHarish Mahendrakar           frame = frames_iterator->second.front();
2565*103e46e4SHarish Mahendrakar         }
2566*103e46e4SHarish Mahendrakar       }
2567*103e46e4SHarish Mahendrakar 
2568*103e46e4SHarish Mahendrakar       // Set the duration if it's the last frame for the track.
2569*103e46e4SHarish Mahendrakar       if (set_last_frame_duration &&
2570*103e46e4SHarish Mahendrakar           stored_frames_[frame->track_number()].size() == 1 &&
2571*103e46e4SHarish Mahendrakar           !frame->duration_set()) {
2572*103e46e4SHarish Mahendrakar         frame->set_duration(duration - frame->timestamp());
2573*103e46e4SHarish Mahendrakar         if (!frame->is_key() && !frame->reference_block_timestamp_set()) {
2574*103e46e4SHarish Mahendrakar           frame->set_reference_block_timestamp(
2575*103e46e4SHarish Mahendrakar               last_block_timestamp_[frame->track_number()]);
2576*103e46e4SHarish Mahendrakar         }
2577*103e46e4SHarish Mahendrakar       }
2578*103e46e4SHarish Mahendrakar 
2579*103e46e4SHarish Mahendrakar       // Write the frame and remove it from |stored_frames_|.
2580*103e46e4SHarish Mahendrakar       const bool wrote_frame = DoWriteFrame(frame);
2581*103e46e4SHarish Mahendrakar       stored_frames_[frame->track_number()].pop_front();
2582*103e46e4SHarish Mahendrakar       if (stored_frames_[frame->track_number()].empty()) {
2583*103e46e4SHarish Mahendrakar         stored_frames_.erase(frame->track_number());
2584*103e46e4SHarish Mahendrakar       }
2585*103e46e4SHarish Mahendrakar       delete frame;
2586*103e46e4SHarish Mahendrakar       if (!wrote_frame)
2587*103e46e4SHarish Mahendrakar         return false;
2588*103e46e4SHarish Mahendrakar     }
2589*103e46e4SHarish Mahendrakar   }
2590*103e46e4SHarish Mahendrakar 
2591*103e46e4SHarish Mahendrakar   if (size_position_ == -1)
2592*103e46e4SHarish Mahendrakar     return false;
2593*103e46e4SHarish Mahendrakar 
2594*103e46e4SHarish Mahendrakar   if (writer_->Seekable()) {
2595*103e46e4SHarish Mahendrakar     const int64_t pos = writer_->Position();
2596*103e46e4SHarish Mahendrakar 
2597*103e46e4SHarish Mahendrakar     if (writer_->Position(size_position_))
2598*103e46e4SHarish Mahendrakar       return false;
2599*103e46e4SHarish Mahendrakar 
2600*103e46e4SHarish Mahendrakar     if (WriteUIntSize(writer_, payload_size(), 8))
2601*103e46e4SHarish Mahendrakar       return false;
2602*103e46e4SHarish Mahendrakar 
2603*103e46e4SHarish Mahendrakar     if (writer_->Position(pos))
2604*103e46e4SHarish Mahendrakar       return false;
2605*103e46e4SHarish Mahendrakar   }
2606*103e46e4SHarish Mahendrakar 
2607*103e46e4SHarish Mahendrakar   finalized_ = true;
2608*103e46e4SHarish Mahendrakar 
2609*103e46e4SHarish Mahendrakar   return true;
2610*103e46e4SHarish Mahendrakar }
2611*103e46e4SHarish Mahendrakar 
Size() const2612*103e46e4SHarish Mahendrakar uint64_t Cluster::Size() const {
2613*103e46e4SHarish Mahendrakar   const uint64_t element_size =
2614*103e46e4SHarish Mahendrakar       EbmlMasterElementSize(libwebm::kMkvCluster, 0xFFFFFFFFFFFFFFFFULL) +
2615*103e46e4SHarish Mahendrakar       payload_size_;
2616*103e46e4SHarish Mahendrakar   return element_size;
2617*103e46e4SHarish Mahendrakar }
2618*103e46e4SHarish Mahendrakar 
PreWriteBlock()2619*103e46e4SHarish Mahendrakar bool Cluster::PreWriteBlock() {
2620*103e46e4SHarish Mahendrakar   if (finalized_)
2621*103e46e4SHarish Mahendrakar     return false;
2622*103e46e4SHarish Mahendrakar 
2623*103e46e4SHarish Mahendrakar   if (!header_written_) {
2624*103e46e4SHarish Mahendrakar     if (!WriteClusterHeader())
2625*103e46e4SHarish Mahendrakar       return false;
2626*103e46e4SHarish Mahendrakar   }
2627*103e46e4SHarish Mahendrakar 
2628*103e46e4SHarish Mahendrakar   return true;
2629*103e46e4SHarish Mahendrakar }
2630*103e46e4SHarish Mahendrakar 
PostWriteBlock(uint64_t element_size)2631*103e46e4SHarish Mahendrakar void Cluster::PostWriteBlock(uint64_t element_size) {
2632*103e46e4SHarish Mahendrakar   AddPayloadSize(element_size);
2633*103e46e4SHarish Mahendrakar   ++blocks_added_;
2634*103e46e4SHarish Mahendrakar }
2635*103e46e4SHarish Mahendrakar 
GetRelativeTimecode(int64_t abs_timecode) const2636*103e46e4SHarish Mahendrakar int64_t Cluster::GetRelativeTimecode(int64_t abs_timecode) const {
2637*103e46e4SHarish Mahendrakar   const int64_t cluster_timecode = this->Cluster::timecode();
2638*103e46e4SHarish Mahendrakar   const int64_t rel_timecode =
2639*103e46e4SHarish Mahendrakar       static_cast<int64_t>(abs_timecode) - cluster_timecode;
2640*103e46e4SHarish Mahendrakar 
2641*103e46e4SHarish Mahendrakar   if (rel_timecode < 0 || rel_timecode > kMaxBlockTimecode)
2642*103e46e4SHarish Mahendrakar     return -1;
2643*103e46e4SHarish Mahendrakar 
2644*103e46e4SHarish Mahendrakar   return rel_timecode;
2645*103e46e4SHarish Mahendrakar }
2646*103e46e4SHarish Mahendrakar 
DoWriteFrame(const Frame * const frame)2647*103e46e4SHarish Mahendrakar bool Cluster::DoWriteFrame(const Frame* const frame) {
2648*103e46e4SHarish Mahendrakar   if (!frame || !frame->IsValid())
2649*103e46e4SHarish Mahendrakar     return false;
2650*103e46e4SHarish Mahendrakar 
2651*103e46e4SHarish Mahendrakar   if (!PreWriteBlock())
2652*103e46e4SHarish Mahendrakar     return false;
2653*103e46e4SHarish Mahendrakar 
2654*103e46e4SHarish Mahendrakar   const uint64_t element_size = WriteFrame(writer_, frame, this);
2655*103e46e4SHarish Mahendrakar   if (element_size == 0)
2656*103e46e4SHarish Mahendrakar     return false;
2657*103e46e4SHarish Mahendrakar 
2658*103e46e4SHarish Mahendrakar   PostWriteBlock(element_size);
2659*103e46e4SHarish Mahendrakar   last_block_timestamp_[frame->track_number()] = frame->timestamp();
2660*103e46e4SHarish Mahendrakar   return true;
2661*103e46e4SHarish Mahendrakar }
2662*103e46e4SHarish Mahendrakar 
QueueOrWriteFrame(const Frame * const frame)2663*103e46e4SHarish Mahendrakar bool Cluster::QueueOrWriteFrame(const Frame* const frame) {
2664*103e46e4SHarish Mahendrakar   if (!frame || !frame->IsValid())
2665*103e46e4SHarish Mahendrakar     return false;
2666*103e46e4SHarish Mahendrakar 
2667*103e46e4SHarish Mahendrakar   // If |write_last_frame_with_duration_| is not set, then write the frame right
2668*103e46e4SHarish Mahendrakar   // away.
2669*103e46e4SHarish Mahendrakar   if (!write_last_frame_with_duration_) {
2670*103e46e4SHarish Mahendrakar     return DoWriteFrame(frame);
2671*103e46e4SHarish Mahendrakar   }
2672*103e46e4SHarish Mahendrakar 
2673*103e46e4SHarish Mahendrakar   // Queue the current frame.
2674*103e46e4SHarish Mahendrakar   uint64_t track_number = frame->track_number();
2675*103e46e4SHarish Mahendrakar   Frame* const frame_to_store = new Frame();
2676*103e46e4SHarish Mahendrakar   frame_to_store->CopyFrom(*frame);
2677*103e46e4SHarish Mahendrakar   stored_frames_[track_number].push_back(frame_to_store);
2678*103e46e4SHarish Mahendrakar 
2679*103e46e4SHarish Mahendrakar   // Iterate through all queued frames in the current track except the last one
2680*103e46e4SHarish Mahendrakar   // and write it if it is okay to do so (i.e.) no other track has an held back
2681*103e46e4SHarish Mahendrakar   // frame with timestamp <= the timestamp of the frame in question.
2682*103e46e4SHarish Mahendrakar   std::vector<std::list<Frame*>::iterator> frames_to_erase;
2683*103e46e4SHarish Mahendrakar   for (std::list<Frame*>::iterator
2684*103e46e4SHarish Mahendrakar            current_track_iterator = stored_frames_[track_number].begin(),
2685*103e46e4SHarish Mahendrakar            end = --stored_frames_[track_number].end();
2686*103e46e4SHarish Mahendrakar        current_track_iterator != end; ++current_track_iterator) {
2687*103e46e4SHarish Mahendrakar     const Frame* const frame_to_write = *current_track_iterator;
2688*103e46e4SHarish Mahendrakar     bool okay_to_write = true;
2689*103e46e4SHarish Mahendrakar     for (FrameMapIterator track_iterator = stored_frames_.begin();
2690*103e46e4SHarish Mahendrakar          track_iterator != stored_frames_.end(); ++track_iterator) {
2691*103e46e4SHarish Mahendrakar       if (track_iterator->first == track_number) {
2692*103e46e4SHarish Mahendrakar         continue;
2693*103e46e4SHarish Mahendrakar       }
2694*103e46e4SHarish Mahendrakar       if (track_iterator->second.front()->timestamp() <
2695*103e46e4SHarish Mahendrakar           frame_to_write->timestamp()) {
2696*103e46e4SHarish Mahendrakar         okay_to_write = false;
2697*103e46e4SHarish Mahendrakar         break;
2698*103e46e4SHarish Mahendrakar       }
2699*103e46e4SHarish Mahendrakar     }
2700*103e46e4SHarish Mahendrakar     if (okay_to_write) {
2701*103e46e4SHarish Mahendrakar       const bool wrote_frame = DoWriteFrame(frame_to_write);
2702*103e46e4SHarish Mahendrakar       delete frame_to_write;
2703*103e46e4SHarish Mahendrakar       if (!wrote_frame)
2704*103e46e4SHarish Mahendrakar         return false;
2705*103e46e4SHarish Mahendrakar       frames_to_erase.push_back(current_track_iterator);
2706*103e46e4SHarish Mahendrakar     } else {
2707*103e46e4SHarish Mahendrakar       break;
2708*103e46e4SHarish Mahendrakar     }
2709*103e46e4SHarish Mahendrakar   }
2710*103e46e4SHarish Mahendrakar   for (std::vector<std::list<Frame*>::iterator>::iterator iterator =
2711*103e46e4SHarish Mahendrakar            frames_to_erase.begin();
2712*103e46e4SHarish Mahendrakar        iterator != frames_to_erase.end(); ++iterator) {
2713*103e46e4SHarish Mahendrakar     stored_frames_[track_number].erase(*iterator);
2714*103e46e4SHarish Mahendrakar   }
2715*103e46e4SHarish Mahendrakar   return true;
2716*103e46e4SHarish Mahendrakar }
2717*103e46e4SHarish Mahendrakar 
WriteClusterHeader()2718*103e46e4SHarish Mahendrakar bool Cluster::WriteClusterHeader() {
2719*103e46e4SHarish Mahendrakar   if (finalized_)
2720*103e46e4SHarish Mahendrakar     return false;
2721*103e46e4SHarish Mahendrakar 
2722*103e46e4SHarish Mahendrakar   if (WriteID(writer_, libwebm::kMkvCluster))
2723*103e46e4SHarish Mahendrakar     return false;
2724*103e46e4SHarish Mahendrakar 
2725*103e46e4SHarish Mahendrakar   // Save for later.
2726*103e46e4SHarish Mahendrakar   size_position_ = writer_->Position();
2727*103e46e4SHarish Mahendrakar 
2728*103e46e4SHarish Mahendrakar   // Write "unknown" (EBML coded -1) as cluster size value. We need to write 8
2729*103e46e4SHarish Mahendrakar   // bytes because we do not know how big our cluster will be.
2730*103e46e4SHarish Mahendrakar   if (SerializeInt(writer_, kEbmlUnknownValue, 8))
2731*103e46e4SHarish Mahendrakar     return false;
2732*103e46e4SHarish Mahendrakar 
2733*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer_, libwebm::kMkvTimecode, timecode(),
2734*103e46e4SHarish Mahendrakar                         fixed_size_timecode_ ? 8 : 0)) {
2735*103e46e4SHarish Mahendrakar     return false;
2736*103e46e4SHarish Mahendrakar   }
2737*103e46e4SHarish Mahendrakar   AddPayloadSize(EbmlElementSize(libwebm::kMkvTimecode, timecode(),
2738*103e46e4SHarish Mahendrakar                                  fixed_size_timecode_ ? 8 : 0));
2739*103e46e4SHarish Mahendrakar   header_written_ = true;
2740*103e46e4SHarish Mahendrakar 
2741*103e46e4SHarish Mahendrakar   return true;
2742*103e46e4SHarish Mahendrakar }
2743*103e46e4SHarish Mahendrakar 
2744*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
2745*103e46e4SHarish Mahendrakar //
2746*103e46e4SHarish Mahendrakar // SeekHead Class
2747*103e46e4SHarish Mahendrakar 
SeekHead()2748*103e46e4SHarish Mahendrakar SeekHead::SeekHead() : start_pos_(0ULL) {
2749*103e46e4SHarish Mahendrakar   for (int32_t i = 0; i < kSeekEntryCount; ++i) {
2750*103e46e4SHarish Mahendrakar     seek_entry_id_[i] = 0;
2751*103e46e4SHarish Mahendrakar     seek_entry_pos_[i] = 0;
2752*103e46e4SHarish Mahendrakar   }
2753*103e46e4SHarish Mahendrakar }
2754*103e46e4SHarish Mahendrakar 
~SeekHead()2755*103e46e4SHarish Mahendrakar SeekHead::~SeekHead() {}
2756*103e46e4SHarish Mahendrakar 
Finalize(IMkvWriter * writer) const2757*103e46e4SHarish Mahendrakar bool SeekHead::Finalize(IMkvWriter* writer) const {
2758*103e46e4SHarish Mahendrakar   if (writer->Seekable()) {
2759*103e46e4SHarish Mahendrakar     if (start_pos_ == -1)
2760*103e46e4SHarish Mahendrakar       return false;
2761*103e46e4SHarish Mahendrakar 
2762*103e46e4SHarish Mahendrakar     uint64_t payload_size = 0;
2763*103e46e4SHarish Mahendrakar     uint64_t entry_size[kSeekEntryCount];
2764*103e46e4SHarish Mahendrakar 
2765*103e46e4SHarish Mahendrakar     for (int32_t i = 0; i < kSeekEntryCount; ++i) {
2766*103e46e4SHarish Mahendrakar       if (seek_entry_id_[i] != 0) {
2767*103e46e4SHarish Mahendrakar         entry_size[i] = EbmlElementSize(libwebm::kMkvSeekID,
2768*103e46e4SHarish Mahendrakar                                         static_cast<uint64>(seek_entry_id_[i]));
2769*103e46e4SHarish Mahendrakar         entry_size[i] += EbmlElementSize(
2770*103e46e4SHarish Mahendrakar             libwebm::kMkvSeekPosition, static_cast<uint64>(seek_entry_pos_[i]));
2771*103e46e4SHarish Mahendrakar 
2772*103e46e4SHarish Mahendrakar         payload_size +=
2773*103e46e4SHarish Mahendrakar             EbmlMasterElementSize(libwebm::kMkvSeek, entry_size[i]) +
2774*103e46e4SHarish Mahendrakar             entry_size[i];
2775*103e46e4SHarish Mahendrakar       }
2776*103e46e4SHarish Mahendrakar     }
2777*103e46e4SHarish Mahendrakar 
2778*103e46e4SHarish Mahendrakar     // No SeekHead elements
2779*103e46e4SHarish Mahendrakar     if (payload_size == 0)
2780*103e46e4SHarish Mahendrakar       return true;
2781*103e46e4SHarish Mahendrakar 
2782*103e46e4SHarish Mahendrakar     const int64_t pos = writer->Position();
2783*103e46e4SHarish Mahendrakar     if (writer->Position(start_pos_))
2784*103e46e4SHarish Mahendrakar       return false;
2785*103e46e4SHarish Mahendrakar 
2786*103e46e4SHarish Mahendrakar     if (!WriteEbmlMasterElement(writer, libwebm::kMkvSeekHead, payload_size))
2787*103e46e4SHarish Mahendrakar       return false;
2788*103e46e4SHarish Mahendrakar 
2789*103e46e4SHarish Mahendrakar     for (int32_t i = 0; i < kSeekEntryCount; ++i) {
2790*103e46e4SHarish Mahendrakar       if (seek_entry_id_[i] != 0) {
2791*103e46e4SHarish Mahendrakar         if (!WriteEbmlMasterElement(writer, libwebm::kMkvSeek, entry_size[i]))
2792*103e46e4SHarish Mahendrakar           return false;
2793*103e46e4SHarish Mahendrakar 
2794*103e46e4SHarish Mahendrakar         if (!WriteEbmlElement(writer, libwebm::kMkvSeekID,
2795*103e46e4SHarish Mahendrakar                               static_cast<uint64>(seek_entry_id_[i])))
2796*103e46e4SHarish Mahendrakar           return false;
2797*103e46e4SHarish Mahendrakar 
2798*103e46e4SHarish Mahendrakar         if (!WriteEbmlElement(writer, libwebm::kMkvSeekPosition,
2799*103e46e4SHarish Mahendrakar                               static_cast<uint64>(seek_entry_pos_[i])))
2800*103e46e4SHarish Mahendrakar           return false;
2801*103e46e4SHarish Mahendrakar       }
2802*103e46e4SHarish Mahendrakar     }
2803*103e46e4SHarish Mahendrakar 
2804*103e46e4SHarish Mahendrakar     const uint64_t total_entry_size = kSeekEntryCount * MaxEntrySize();
2805*103e46e4SHarish Mahendrakar     const uint64_t total_size =
2806*103e46e4SHarish Mahendrakar         EbmlMasterElementSize(libwebm::kMkvSeekHead, total_entry_size) +
2807*103e46e4SHarish Mahendrakar         total_entry_size;
2808*103e46e4SHarish Mahendrakar     const int64_t size_left = total_size - (writer->Position() - start_pos_);
2809*103e46e4SHarish Mahendrakar 
2810*103e46e4SHarish Mahendrakar     const uint64_t bytes_written = WriteVoidElement(writer, size_left);
2811*103e46e4SHarish Mahendrakar     if (!bytes_written)
2812*103e46e4SHarish Mahendrakar       return false;
2813*103e46e4SHarish Mahendrakar 
2814*103e46e4SHarish Mahendrakar     if (writer->Position(pos))
2815*103e46e4SHarish Mahendrakar       return false;
2816*103e46e4SHarish Mahendrakar   }
2817*103e46e4SHarish Mahendrakar 
2818*103e46e4SHarish Mahendrakar   return true;
2819*103e46e4SHarish Mahendrakar }
2820*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer)2821*103e46e4SHarish Mahendrakar bool SeekHead::Write(IMkvWriter* writer) {
2822*103e46e4SHarish Mahendrakar   const uint64_t entry_size = kSeekEntryCount * MaxEntrySize();
2823*103e46e4SHarish Mahendrakar   const uint64_t size =
2824*103e46e4SHarish Mahendrakar       EbmlMasterElementSize(libwebm::kMkvSeekHead, entry_size);
2825*103e46e4SHarish Mahendrakar 
2826*103e46e4SHarish Mahendrakar   start_pos_ = writer->Position();
2827*103e46e4SHarish Mahendrakar 
2828*103e46e4SHarish Mahendrakar   const uint64_t bytes_written = WriteVoidElement(writer, size + entry_size);
2829*103e46e4SHarish Mahendrakar   if (!bytes_written)
2830*103e46e4SHarish Mahendrakar     return false;
2831*103e46e4SHarish Mahendrakar 
2832*103e46e4SHarish Mahendrakar   return true;
2833*103e46e4SHarish Mahendrakar }
2834*103e46e4SHarish Mahendrakar 
AddSeekEntry(uint32_t id,uint64_t pos)2835*103e46e4SHarish Mahendrakar bool SeekHead::AddSeekEntry(uint32_t id, uint64_t pos) {
2836*103e46e4SHarish Mahendrakar   for (int32_t i = 0; i < kSeekEntryCount; ++i) {
2837*103e46e4SHarish Mahendrakar     if (seek_entry_id_[i] == 0) {
2838*103e46e4SHarish Mahendrakar       seek_entry_id_[i] = id;
2839*103e46e4SHarish Mahendrakar       seek_entry_pos_[i] = pos;
2840*103e46e4SHarish Mahendrakar       return true;
2841*103e46e4SHarish Mahendrakar     }
2842*103e46e4SHarish Mahendrakar   }
2843*103e46e4SHarish Mahendrakar   return false;
2844*103e46e4SHarish Mahendrakar }
2845*103e46e4SHarish Mahendrakar 
GetId(int index) const2846*103e46e4SHarish Mahendrakar uint32_t SeekHead::GetId(int index) const {
2847*103e46e4SHarish Mahendrakar   if (index < 0 || index >= kSeekEntryCount)
2848*103e46e4SHarish Mahendrakar     return UINT32_MAX;
2849*103e46e4SHarish Mahendrakar   return seek_entry_id_[index];
2850*103e46e4SHarish Mahendrakar }
2851*103e46e4SHarish Mahendrakar 
GetPosition(int index) const2852*103e46e4SHarish Mahendrakar uint64_t SeekHead::GetPosition(int index) const {
2853*103e46e4SHarish Mahendrakar   if (index < 0 || index >= kSeekEntryCount)
2854*103e46e4SHarish Mahendrakar     return UINT64_MAX;
2855*103e46e4SHarish Mahendrakar   return seek_entry_pos_[index];
2856*103e46e4SHarish Mahendrakar }
2857*103e46e4SHarish Mahendrakar 
SetSeekEntry(int index,uint32_t id,uint64_t position)2858*103e46e4SHarish Mahendrakar bool SeekHead::SetSeekEntry(int index, uint32_t id, uint64_t position) {
2859*103e46e4SHarish Mahendrakar   if (index < 0 || index >= kSeekEntryCount)
2860*103e46e4SHarish Mahendrakar     return false;
2861*103e46e4SHarish Mahendrakar   seek_entry_id_[index] = id;
2862*103e46e4SHarish Mahendrakar   seek_entry_pos_[index] = position;
2863*103e46e4SHarish Mahendrakar   return true;
2864*103e46e4SHarish Mahendrakar }
2865*103e46e4SHarish Mahendrakar 
MaxEntrySize() const2866*103e46e4SHarish Mahendrakar uint64_t SeekHead::MaxEntrySize() const {
2867*103e46e4SHarish Mahendrakar   const uint64_t max_entry_payload_size =
2868*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvSeekID,
2869*103e46e4SHarish Mahendrakar                       static_cast<uint64>(UINT64_C(0xffffffff))) +
2870*103e46e4SHarish Mahendrakar       EbmlElementSize(libwebm::kMkvSeekPosition,
2871*103e46e4SHarish Mahendrakar                       static_cast<uint64>(UINT64_C(0xffffffffffffffff)));
2872*103e46e4SHarish Mahendrakar   const uint64_t max_entry_size =
2873*103e46e4SHarish Mahendrakar       EbmlMasterElementSize(libwebm::kMkvSeek, max_entry_payload_size) +
2874*103e46e4SHarish Mahendrakar       max_entry_payload_size;
2875*103e46e4SHarish Mahendrakar 
2876*103e46e4SHarish Mahendrakar   return max_entry_size;
2877*103e46e4SHarish Mahendrakar }
2878*103e46e4SHarish Mahendrakar 
2879*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
2880*103e46e4SHarish Mahendrakar //
2881*103e46e4SHarish Mahendrakar // SegmentInfo Class
2882*103e46e4SHarish Mahendrakar 
SegmentInfo()2883*103e46e4SHarish Mahendrakar SegmentInfo::SegmentInfo()
2884*103e46e4SHarish Mahendrakar     : duration_(-1.0),
2885*103e46e4SHarish Mahendrakar       muxing_app_(NULL),
2886*103e46e4SHarish Mahendrakar       timecode_scale_(1000000ULL),
2887*103e46e4SHarish Mahendrakar       writing_app_(NULL),
2888*103e46e4SHarish Mahendrakar       date_utc_(INT64_MIN),
2889*103e46e4SHarish Mahendrakar       duration_pos_(-1) {}
2890*103e46e4SHarish Mahendrakar 
~SegmentInfo()2891*103e46e4SHarish Mahendrakar SegmentInfo::~SegmentInfo() {
2892*103e46e4SHarish Mahendrakar   delete[] muxing_app_;
2893*103e46e4SHarish Mahendrakar   delete[] writing_app_;
2894*103e46e4SHarish Mahendrakar }
2895*103e46e4SHarish Mahendrakar 
Init()2896*103e46e4SHarish Mahendrakar bool SegmentInfo::Init() {
2897*103e46e4SHarish Mahendrakar   int32_t major;
2898*103e46e4SHarish Mahendrakar   int32_t minor;
2899*103e46e4SHarish Mahendrakar   int32_t build;
2900*103e46e4SHarish Mahendrakar   int32_t revision;
2901*103e46e4SHarish Mahendrakar   GetVersion(&major, &minor, &build, &revision);
2902*103e46e4SHarish Mahendrakar   char temp[256];
2903*103e46e4SHarish Mahendrakar #ifdef _MSC_VER
2904*103e46e4SHarish Mahendrakar   sprintf_s(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
2905*103e46e4SHarish Mahendrakar             minor, build, revision);
2906*103e46e4SHarish Mahendrakar #else
2907*103e46e4SHarish Mahendrakar   snprintf(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
2908*103e46e4SHarish Mahendrakar            minor, build, revision);
2909*103e46e4SHarish Mahendrakar #endif
2910*103e46e4SHarish Mahendrakar 
2911*103e46e4SHarish Mahendrakar   const size_t app_len = strlen(temp) + 1;
2912*103e46e4SHarish Mahendrakar 
2913*103e46e4SHarish Mahendrakar   delete[] muxing_app_;
2914*103e46e4SHarish Mahendrakar 
2915*103e46e4SHarish Mahendrakar   muxing_app_ = new (std::nothrow) char[app_len];  // NOLINT
2916*103e46e4SHarish Mahendrakar   if (!muxing_app_)
2917*103e46e4SHarish Mahendrakar     return false;
2918*103e46e4SHarish Mahendrakar 
2919*103e46e4SHarish Mahendrakar   memcpy(muxing_app_, temp, app_len - 1);
2920*103e46e4SHarish Mahendrakar   muxing_app_[app_len - 1] = '\0';
2921*103e46e4SHarish Mahendrakar 
2922*103e46e4SHarish Mahendrakar   set_writing_app(temp);
2923*103e46e4SHarish Mahendrakar   if (!writing_app_)
2924*103e46e4SHarish Mahendrakar     return false;
2925*103e46e4SHarish Mahendrakar   return true;
2926*103e46e4SHarish Mahendrakar }
2927*103e46e4SHarish Mahendrakar 
Finalize(IMkvWriter * writer) const2928*103e46e4SHarish Mahendrakar bool SegmentInfo::Finalize(IMkvWriter* writer) const {
2929*103e46e4SHarish Mahendrakar   if (!writer)
2930*103e46e4SHarish Mahendrakar     return false;
2931*103e46e4SHarish Mahendrakar 
2932*103e46e4SHarish Mahendrakar   if (duration_ > 0.0) {
2933*103e46e4SHarish Mahendrakar     if (writer->Seekable()) {
2934*103e46e4SHarish Mahendrakar       if (duration_pos_ == -1)
2935*103e46e4SHarish Mahendrakar         return false;
2936*103e46e4SHarish Mahendrakar 
2937*103e46e4SHarish Mahendrakar       const int64_t pos = writer->Position();
2938*103e46e4SHarish Mahendrakar 
2939*103e46e4SHarish Mahendrakar       if (writer->Position(duration_pos_))
2940*103e46e4SHarish Mahendrakar         return false;
2941*103e46e4SHarish Mahendrakar 
2942*103e46e4SHarish Mahendrakar       if (!WriteEbmlElement(writer, libwebm::kMkvDuration,
2943*103e46e4SHarish Mahendrakar                             static_cast<float>(duration_)))
2944*103e46e4SHarish Mahendrakar         return false;
2945*103e46e4SHarish Mahendrakar 
2946*103e46e4SHarish Mahendrakar       if (writer->Position(pos))
2947*103e46e4SHarish Mahendrakar         return false;
2948*103e46e4SHarish Mahendrakar     }
2949*103e46e4SHarish Mahendrakar   }
2950*103e46e4SHarish Mahendrakar 
2951*103e46e4SHarish Mahendrakar   return true;
2952*103e46e4SHarish Mahendrakar }
2953*103e46e4SHarish Mahendrakar 
Write(IMkvWriter * writer)2954*103e46e4SHarish Mahendrakar bool SegmentInfo::Write(IMkvWriter* writer) {
2955*103e46e4SHarish Mahendrakar   if (!writer || !muxing_app_ || !writing_app_)
2956*103e46e4SHarish Mahendrakar     return false;
2957*103e46e4SHarish Mahendrakar 
2958*103e46e4SHarish Mahendrakar   uint64_t size = EbmlElementSize(libwebm::kMkvTimecodeScale,
2959*103e46e4SHarish Mahendrakar                                   static_cast<uint64>(timecode_scale_));
2960*103e46e4SHarish Mahendrakar   if (duration_ > 0.0)
2961*103e46e4SHarish Mahendrakar     size +=
2962*103e46e4SHarish Mahendrakar         EbmlElementSize(libwebm::kMkvDuration, static_cast<float>(duration_));
2963*103e46e4SHarish Mahendrakar   if (date_utc_ != INT64_MIN)
2964*103e46e4SHarish Mahendrakar     size += EbmlDateElementSize(libwebm::kMkvDateUTC);
2965*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvMuxingApp, muxing_app_);
2966*103e46e4SHarish Mahendrakar   size += EbmlElementSize(libwebm::kMkvWritingApp, writing_app_);
2967*103e46e4SHarish Mahendrakar 
2968*103e46e4SHarish Mahendrakar   if (!WriteEbmlMasterElement(writer, libwebm::kMkvInfo, size))
2969*103e46e4SHarish Mahendrakar     return false;
2970*103e46e4SHarish Mahendrakar 
2971*103e46e4SHarish Mahendrakar   const int64_t payload_position = writer->Position();
2972*103e46e4SHarish Mahendrakar   if (payload_position < 0)
2973*103e46e4SHarish Mahendrakar     return false;
2974*103e46e4SHarish Mahendrakar 
2975*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvTimecodeScale,
2976*103e46e4SHarish Mahendrakar                         static_cast<uint64>(timecode_scale_)))
2977*103e46e4SHarish Mahendrakar     return false;
2978*103e46e4SHarish Mahendrakar 
2979*103e46e4SHarish Mahendrakar   if (duration_ > 0.0) {
2980*103e46e4SHarish Mahendrakar     // Save for later
2981*103e46e4SHarish Mahendrakar     duration_pos_ = writer->Position();
2982*103e46e4SHarish Mahendrakar 
2983*103e46e4SHarish Mahendrakar     if (!WriteEbmlElement(writer, libwebm::kMkvDuration,
2984*103e46e4SHarish Mahendrakar                           static_cast<float>(duration_)))
2985*103e46e4SHarish Mahendrakar       return false;
2986*103e46e4SHarish Mahendrakar   }
2987*103e46e4SHarish Mahendrakar 
2988*103e46e4SHarish Mahendrakar   if (date_utc_ != INT64_MIN)
2989*103e46e4SHarish Mahendrakar     WriteEbmlDateElement(writer, libwebm::kMkvDateUTC, date_utc_);
2990*103e46e4SHarish Mahendrakar 
2991*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvMuxingApp, muxing_app_))
2992*103e46e4SHarish Mahendrakar     return false;
2993*103e46e4SHarish Mahendrakar   if (!WriteEbmlElement(writer, libwebm::kMkvWritingApp, writing_app_))
2994*103e46e4SHarish Mahendrakar     return false;
2995*103e46e4SHarish Mahendrakar 
2996*103e46e4SHarish Mahendrakar   const int64_t stop_position = writer->Position();
2997*103e46e4SHarish Mahendrakar   if (stop_position < 0 ||
2998*103e46e4SHarish Mahendrakar       stop_position - payload_position != static_cast<int64_t>(size))
2999*103e46e4SHarish Mahendrakar     return false;
3000*103e46e4SHarish Mahendrakar 
3001*103e46e4SHarish Mahendrakar   return true;
3002*103e46e4SHarish Mahendrakar }
3003*103e46e4SHarish Mahendrakar 
set_muxing_app(const char * app)3004*103e46e4SHarish Mahendrakar void SegmentInfo::set_muxing_app(const char* app) {
3005*103e46e4SHarish Mahendrakar   if (app) {
3006*103e46e4SHarish Mahendrakar     const size_t length = strlen(app) + 1;
3007*103e46e4SHarish Mahendrakar     char* temp_str = new (std::nothrow) char[length];  // NOLINT
3008*103e46e4SHarish Mahendrakar     if (!temp_str)
3009*103e46e4SHarish Mahendrakar       return;
3010*103e46e4SHarish Mahendrakar 
3011*103e46e4SHarish Mahendrakar     memcpy(temp_str, app, length - 1);
3012*103e46e4SHarish Mahendrakar     temp_str[length - 1] = '\0';
3013*103e46e4SHarish Mahendrakar 
3014*103e46e4SHarish Mahendrakar     delete[] muxing_app_;
3015*103e46e4SHarish Mahendrakar     muxing_app_ = temp_str;
3016*103e46e4SHarish Mahendrakar   }
3017*103e46e4SHarish Mahendrakar }
3018*103e46e4SHarish Mahendrakar 
set_writing_app(const char * app)3019*103e46e4SHarish Mahendrakar void SegmentInfo::set_writing_app(const char* app) {
3020*103e46e4SHarish Mahendrakar   if (app) {
3021*103e46e4SHarish Mahendrakar     const size_t length = strlen(app) + 1;
3022*103e46e4SHarish Mahendrakar     char* temp_str = new (std::nothrow) char[length];  // NOLINT
3023*103e46e4SHarish Mahendrakar     if (!temp_str)
3024*103e46e4SHarish Mahendrakar       return;
3025*103e46e4SHarish Mahendrakar 
3026*103e46e4SHarish Mahendrakar     memcpy(temp_str, app, length - 1);
3027*103e46e4SHarish Mahendrakar     temp_str[length - 1] = '\0';
3028*103e46e4SHarish Mahendrakar 
3029*103e46e4SHarish Mahendrakar     delete[] writing_app_;
3030*103e46e4SHarish Mahendrakar     writing_app_ = temp_str;
3031*103e46e4SHarish Mahendrakar   }
3032*103e46e4SHarish Mahendrakar }
3033*103e46e4SHarish Mahendrakar 
3034*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
3035*103e46e4SHarish Mahendrakar //
3036*103e46e4SHarish Mahendrakar // Segment Class
3037*103e46e4SHarish Mahendrakar 
Segment()3038*103e46e4SHarish Mahendrakar Segment::Segment()
3039*103e46e4SHarish Mahendrakar     : chunk_count_(0),
3040*103e46e4SHarish Mahendrakar       chunk_name_(NULL),
3041*103e46e4SHarish Mahendrakar       chunk_writer_cluster_(NULL),
3042*103e46e4SHarish Mahendrakar       chunk_writer_cues_(NULL),
3043*103e46e4SHarish Mahendrakar       chunk_writer_header_(NULL),
3044*103e46e4SHarish Mahendrakar       chunking_(false),
3045*103e46e4SHarish Mahendrakar       chunking_base_name_(NULL),
3046*103e46e4SHarish Mahendrakar       cluster_list_(NULL),
3047*103e46e4SHarish Mahendrakar       cluster_list_capacity_(0),
3048*103e46e4SHarish Mahendrakar       cluster_list_size_(0),
3049*103e46e4SHarish Mahendrakar       cues_position_(kAfterClusters),
3050*103e46e4SHarish Mahendrakar       cues_track_(0),
3051*103e46e4SHarish Mahendrakar       force_new_cluster_(false),
3052*103e46e4SHarish Mahendrakar       frames_(NULL),
3053*103e46e4SHarish Mahendrakar       frames_capacity_(0),
3054*103e46e4SHarish Mahendrakar       frames_size_(0),
3055*103e46e4SHarish Mahendrakar       has_video_(false),
3056*103e46e4SHarish Mahendrakar       header_written_(false),
3057*103e46e4SHarish Mahendrakar       last_block_duration_(0),
3058*103e46e4SHarish Mahendrakar       last_timestamp_(0),
3059*103e46e4SHarish Mahendrakar       max_cluster_duration_(kDefaultMaxClusterDuration),
3060*103e46e4SHarish Mahendrakar       max_cluster_size_(0),
3061*103e46e4SHarish Mahendrakar       mode_(kFile),
3062*103e46e4SHarish Mahendrakar       new_cuepoint_(false),
3063*103e46e4SHarish Mahendrakar       output_cues_(true),
3064*103e46e4SHarish Mahendrakar       accurate_cluster_duration_(false),
3065*103e46e4SHarish Mahendrakar       fixed_size_cluster_timecode_(false),
3066*103e46e4SHarish Mahendrakar       estimate_file_duration_(false),
3067*103e46e4SHarish Mahendrakar       ebml_header_size_(0),
3068*103e46e4SHarish Mahendrakar       payload_pos_(0),
3069*103e46e4SHarish Mahendrakar       size_position_(0),
3070*103e46e4SHarish Mahendrakar       doc_type_version_(kDefaultDocTypeVersion),
3071*103e46e4SHarish Mahendrakar       doc_type_version_written_(0),
3072*103e46e4SHarish Mahendrakar       duration_(0.0),
3073*103e46e4SHarish Mahendrakar       writer_cluster_(NULL),
3074*103e46e4SHarish Mahendrakar       writer_cues_(NULL),
3075*103e46e4SHarish Mahendrakar       writer_header_(NULL) {
3076*103e46e4SHarish Mahendrakar   const time_t curr_time = time(NULL);
3077*103e46e4SHarish Mahendrakar   seed_ = static_cast<unsigned int>(curr_time);
3078*103e46e4SHarish Mahendrakar #ifdef _WIN32
3079*103e46e4SHarish Mahendrakar   srand(seed_);
3080*103e46e4SHarish Mahendrakar #endif
3081*103e46e4SHarish Mahendrakar }
3082*103e46e4SHarish Mahendrakar 
~Segment()3083*103e46e4SHarish Mahendrakar Segment::~Segment() {
3084*103e46e4SHarish Mahendrakar   if (cluster_list_) {
3085*103e46e4SHarish Mahendrakar     for (int32_t i = 0; i < cluster_list_size_; ++i) {
3086*103e46e4SHarish Mahendrakar       Cluster* const cluster = cluster_list_[i];
3087*103e46e4SHarish Mahendrakar       delete cluster;
3088*103e46e4SHarish Mahendrakar     }
3089*103e46e4SHarish Mahendrakar     delete[] cluster_list_;
3090*103e46e4SHarish Mahendrakar   }
3091*103e46e4SHarish Mahendrakar 
3092*103e46e4SHarish Mahendrakar   if (frames_) {
3093*103e46e4SHarish Mahendrakar     for (int32_t i = 0; i < frames_size_; ++i) {
3094*103e46e4SHarish Mahendrakar       Frame* const frame = frames_[i];
3095*103e46e4SHarish Mahendrakar       delete frame;
3096*103e46e4SHarish Mahendrakar     }
3097*103e46e4SHarish Mahendrakar     delete[] frames_;
3098*103e46e4SHarish Mahendrakar   }
3099*103e46e4SHarish Mahendrakar 
3100*103e46e4SHarish Mahendrakar   delete[] chunk_name_;
3101*103e46e4SHarish Mahendrakar   delete[] chunking_base_name_;
3102*103e46e4SHarish Mahendrakar 
3103*103e46e4SHarish Mahendrakar   if (chunk_writer_cluster_) {
3104*103e46e4SHarish Mahendrakar     chunk_writer_cluster_->Close();
3105*103e46e4SHarish Mahendrakar     delete chunk_writer_cluster_;
3106*103e46e4SHarish Mahendrakar   }
3107*103e46e4SHarish Mahendrakar   if (chunk_writer_cues_) {
3108*103e46e4SHarish Mahendrakar     chunk_writer_cues_->Close();
3109*103e46e4SHarish Mahendrakar     delete chunk_writer_cues_;
3110*103e46e4SHarish Mahendrakar   }
3111*103e46e4SHarish Mahendrakar   if (chunk_writer_header_) {
3112*103e46e4SHarish Mahendrakar     chunk_writer_header_->Close();
3113*103e46e4SHarish Mahendrakar     delete chunk_writer_header_;
3114*103e46e4SHarish Mahendrakar   }
3115*103e46e4SHarish Mahendrakar }
3116*103e46e4SHarish Mahendrakar 
MoveCuesBeforeClustersHelper(uint64_t diff,int32_t index,uint64_t * cues_size)3117*103e46e4SHarish Mahendrakar void Segment::MoveCuesBeforeClustersHelper(uint64_t diff, int32_t index,
3118*103e46e4SHarish Mahendrakar                                            uint64_t* cues_size) {
3119*103e46e4SHarish Mahendrakar   CuePoint* const cue_point = cues_.GetCueByIndex(index);
3120*103e46e4SHarish Mahendrakar   if (cue_point == NULL)
3121*103e46e4SHarish Mahendrakar     return;
3122*103e46e4SHarish Mahendrakar   const uint64_t old_cue_point_size = cue_point->Size();
3123*103e46e4SHarish Mahendrakar   const uint64_t cluster_pos = cue_point->cluster_pos() + diff;
3124*103e46e4SHarish Mahendrakar   cue_point->set_cluster_pos(cluster_pos);  // update the new cluster position
3125*103e46e4SHarish Mahendrakar   // New size of the cue is computed as follows
3126*103e46e4SHarish Mahendrakar   //    Let a = current sum of size of all CuePoints
3127*103e46e4SHarish Mahendrakar   //    Let b = Increase in Cue Point's size due to this iteration
3128*103e46e4SHarish Mahendrakar   //    Let c = Increase in size of Cues Element's length due to this iteration
3129*103e46e4SHarish Mahendrakar   //            (This is computed as CodedSize(a + b) - CodedSize(a))
3130*103e46e4SHarish Mahendrakar   //    Let d = b + c. Now d is the |diff| passed to the next recursive call.
3131*103e46e4SHarish Mahendrakar   //    Let e = a + b. Now e is the |cues_size| passed to the next recursive
3132*103e46e4SHarish Mahendrakar   //                   call.
3133*103e46e4SHarish Mahendrakar   const uint64_t cue_point_size_diff = cue_point->Size() - old_cue_point_size;
3134*103e46e4SHarish Mahendrakar   const uint64_t cue_size_diff =
3135*103e46e4SHarish Mahendrakar       GetCodedUIntSize(*cues_size + cue_point_size_diff) -
3136*103e46e4SHarish Mahendrakar       GetCodedUIntSize(*cues_size);
3137*103e46e4SHarish Mahendrakar   *cues_size += cue_point_size_diff;
3138*103e46e4SHarish Mahendrakar   diff = cue_size_diff + cue_point_size_diff;
3139*103e46e4SHarish Mahendrakar   if (diff > 0) {
3140*103e46e4SHarish Mahendrakar     for (int32_t i = 0; i < cues_.cue_entries_size(); ++i) {
3141*103e46e4SHarish Mahendrakar       MoveCuesBeforeClustersHelper(diff, i, cues_size);
3142*103e46e4SHarish Mahendrakar     }
3143*103e46e4SHarish Mahendrakar   }
3144*103e46e4SHarish Mahendrakar }
3145*103e46e4SHarish Mahendrakar 
MoveCuesBeforeClusters()3146*103e46e4SHarish Mahendrakar void Segment::MoveCuesBeforeClusters() {
3147*103e46e4SHarish Mahendrakar   const uint64_t current_cue_size = cues_.Size();
3148*103e46e4SHarish Mahendrakar   uint64_t cue_size = 0;
3149*103e46e4SHarish Mahendrakar   for (int32_t i = 0; i < cues_.cue_entries_size(); ++i)
3150*103e46e4SHarish Mahendrakar     cue_size += cues_.GetCueByIndex(i)->Size();
3151*103e46e4SHarish Mahendrakar   for (int32_t i = 0; i < cues_.cue_entries_size(); ++i)
3152*103e46e4SHarish Mahendrakar     MoveCuesBeforeClustersHelper(current_cue_size, i, &cue_size);
3153*103e46e4SHarish Mahendrakar 
3154*103e46e4SHarish Mahendrakar   // Adjust the Seek Entry to reflect the change in position
3155*103e46e4SHarish Mahendrakar   // of Cluster and Cues
3156*103e46e4SHarish Mahendrakar   int32_t cluster_index = 0;
3157*103e46e4SHarish Mahendrakar   int32_t cues_index = 0;
3158*103e46e4SHarish Mahendrakar   for (int32_t i = 0; i < SeekHead::kSeekEntryCount; ++i) {
3159*103e46e4SHarish Mahendrakar     if (seek_head_.GetId(i) == libwebm::kMkvCluster)
3160*103e46e4SHarish Mahendrakar       cluster_index = i;
3161*103e46e4SHarish Mahendrakar     if (seek_head_.GetId(i) == libwebm::kMkvCues)
3162*103e46e4SHarish Mahendrakar       cues_index = i;
3163*103e46e4SHarish Mahendrakar   }
3164*103e46e4SHarish Mahendrakar   seek_head_.SetSeekEntry(cues_index, libwebm::kMkvCues,
3165*103e46e4SHarish Mahendrakar                           seek_head_.GetPosition(cluster_index));
3166*103e46e4SHarish Mahendrakar   seek_head_.SetSeekEntry(cluster_index, libwebm::kMkvCluster,
3167*103e46e4SHarish Mahendrakar                           cues_.Size() + seek_head_.GetPosition(cues_index));
3168*103e46e4SHarish Mahendrakar }
3169*103e46e4SHarish Mahendrakar 
Init(IMkvWriter * ptr_writer)3170*103e46e4SHarish Mahendrakar bool Segment::Init(IMkvWriter* ptr_writer) {
3171*103e46e4SHarish Mahendrakar   if (!ptr_writer) {
3172*103e46e4SHarish Mahendrakar     return false;
3173*103e46e4SHarish Mahendrakar   }
3174*103e46e4SHarish Mahendrakar   writer_cluster_ = ptr_writer;
3175*103e46e4SHarish Mahendrakar   writer_cues_ = ptr_writer;
3176*103e46e4SHarish Mahendrakar   writer_header_ = ptr_writer;
3177*103e46e4SHarish Mahendrakar   memset(&track_frames_written_, 0,
3178*103e46e4SHarish Mahendrakar          sizeof(track_frames_written_[0]) * kMaxTrackNumber);
3179*103e46e4SHarish Mahendrakar   memset(&last_track_timestamp_, 0,
3180*103e46e4SHarish Mahendrakar          sizeof(last_track_timestamp_[0]) * kMaxTrackNumber);
3181*103e46e4SHarish Mahendrakar   return segment_info_.Init();
3182*103e46e4SHarish Mahendrakar }
3183*103e46e4SHarish Mahendrakar 
CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader * reader,IMkvWriter * writer)3184*103e46e4SHarish Mahendrakar bool Segment::CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader* reader,
3185*103e46e4SHarish Mahendrakar                                             IMkvWriter* writer) {
3186*103e46e4SHarish Mahendrakar   if (!writer->Seekable() || chunking_)
3187*103e46e4SHarish Mahendrakar     return false;
3188*103e46e4SHarish Mahendrakar   const int64_t cluster_offset =
3189*103e46e4SHarish Mahendrakar       cluster_list_[0]->size_position() - GetUIntSize(libwebm::kMkvCluster);
3190*103e46e4SHarish Mahendrakar 
3191*103e46e4SHarish Mahendrakar   // Copy the headers.
3192*103e46e4SHarish Mahendrakar   if (!ChunkedCopy(reader, writer, 0, cluster_offset))
3193*103e46e4SHarish Mahendrakar     return false;
3194*103e46e4SHarish Mahendrakar 
3195*103e46e4SHarish Mahendrakar   // Recompute cue positions and seek entries.
3196*103e46e4SHarish Mahendrakar   MoveCuesBeforeClusters();
3197*103e46e4SHarish Mahendrakar 
3198*103e46e4SHarish Mahendrakar   // Write cues and seek entries.
3199*103e46e4SHarish Mahendrakar   // TODO(vigneshv): As of now, it's safe to call seek_head_.Finalize() for the
3200*103e46e4SHarish Mahendrakar   // second time with a different writer object. But the name Finalize() doesn't
3201*103e46e4SHarish Mahendrakar   // indicate something we want to call more than once. So consider renaming it
3202*103e46e4SHarish Mahendrakar   // to write() or some such.
3203*103e46e4SHarish Mahendrakar   if (!cues_.Write(writer) || !seek_head_.Finalize(writer))
3204*103e46e4SHarish Mahendrakar     return false;
3205*103e46e4SHarish Mahendrakar 
3206*103e46e4SHarish Mahendrakar   // Copy the Clusters.
3207*103e46e4SHarish Mahendrakar   if (!ChunkedCopy(reader, writer, cluster_offset,
3208*103e46e4SHarish Mahendrakar                    cluster_end_offset_ - cluster_offset))
3209*103e46e4SHarish Mahendrakar     return false;
3210*103e46e4SHarish Mahendrakar 
3211*103e46e4SHarish Mahendrakar   // Update the Segment size in case the Cues size has changed.
3212*103e46e4SHarish Mahendrakar   const int64_t pos = writer->Position();
3213*103e46e4SHarish Mahendrakar   const int64_t segment_size = writer->Position() - payload_pos_;
3214*103e46e4SHarish Mahendrakar   if (writer->Position(size_position_) ||
3215*103e46e4SHarish Mahendrakar       WriteUIntSize(writer, segment_size, 8) || writer->Position(pos))
3216*103e46e4SHarish Mahendrakar     return false;
3217*103e46e4SHarish Mahendrakar   return true;
3218*103e46e4SHarish Mahendrakar }
3219*103e46e4SHarish Mahendrakar 
Finalize()3220*103e46e4SHarish Mahendrakar bool Segment::Finalize() {
3221*103e46e4SHarish Mahendrakar   if (WriteFramesAll() < 0)
3222*103e46e4SHarish Mahendrakar     return false;
3223*103e46e4SHarish Mahendrakar 
3224*103e46e4SHarish Mahendrakar   // In kLive mode, call Cluster::Finalize only if |accurate_cluster_duration_|
3225*103e46e4SHarish Mahendrakar   // is set. In all other modes, always call Cluster::Finalize.
3226*103e46e4SHarish Mahendrakar   if ((mode_ == kLive ? accurate_cluster_duration_ : true) &&
3227*103e46e4SHarish Mahendrakar       cluster_list_size_ > 0) {
3228*103e46e4SHarish Mahendrakar     // Update last cluster's size
3229*103e46e4SHarish Mahendrakar     Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
3230*103e46e4SHarish Mahendrakar 
3231*103e46e4SHarish Mahendrakar     // For the last frame of the last Cluster, we don't write it as a BlockGroup
3232*103e46e4SHarish Mahendrakar     // with Duration unless the frame itself has duration set explicitly.
3233*103e46e4SHarish Mahendrakar     if (!old_cluster || !old_cluster->Finalize(false, 0))
3234*103e46e4SHarish Mahendrakar       return false;
3235*103e46e4SHarish Mahendrakar   }
3236*103e46e4SHarish Mahendrakar 
3237*103e46e4SHarish Mahendrakar   if (mode_ == kFile) {
3238*103e46e4SHarish Mahendrakar     if (chunking_ && chunk_writer_cluster_) {
3239*103e46e4SHarish Mahendrakar       chunk_writer_cluster_->Close();
3240*103e46e4SHarish Mahendrakar       chunk_count_++;
3241*103e46e4SHarish Mahendrakar     }
3242*103e46e4SHarish Mahendrakar 
3243*103e46e4SHarish Mahendrakar     double duration =
3244*103e46e4SHarish Mahendrakar         (static_cast<double>(last_timestamp_) + last_block_duration_) /
3245*103e46e4SHarish Mahendrakar         segment_info_.timecode_scale();
3246*103e46e4SHarish Mahendrakar     if (duration_ > 0.0) {
3247*103e46e4SHarish Mahendrakar       duration = duration_;
3248*103e46e4SHarish Mahendrakar     } else {
3249*103e46e4SHarish Mahendrakar       if (last_block_duration_ == 0 && estimate_file_duration_) {
3250*103e46e4SHarish Mahendrakar         const int num_tracks = static_cast<int>(tracks_.track_entries_size());
3251*103e46e4SHarish Mahendrakar         for (int i = 0; i < num_tracks; ++i) {
3252*103e46e4SHarish Mahendrakar           if (track_frames_written_[i] < 2)
3253*103e46e4SHarish Mahendrakar             continue;
3254*103e46e4SHarish Mahendrakar 
3255*103e46e4SHarish Mahendrakar           // Estimate the duration for the last block of a Track.
3256*103e46e4SHarish Mahendrakar           const double nano_per_frame =
3257*103e46e4SHarish Mahendrakar               static_cast<double>(last_track_timestamp_[i]) /
3258*103e46e4SHarish Mahendrakar               (track_frames_written_[i] - 1);
3259*103e46e4SHarish Mahendrakar           const double track_duration =
3260*103e46e4SHarish Mahendrakar               (last_track_timestamp_[i] + nano_per_frame) /
3261*103e46e4SHarish Mahendrakar               segment_info_.timecode_scale();
3262*103e46e4SHarish Mahendrakar           if (track_duration > duration)
3263*103e46e4SHarish Mahendrakar             duration = track_duration;
3264*103e46e4SHarish Mahendrakar         }
3265*103e46e4SHarish Mahendrakar       }
3266*103e46e4SHarish Mahendrakar     }
3267*103e46e4SHarish Mahendrakar     segment_info_.set_duration(duration);
3268*103e46e4SHarish Mahendrakar     if (!segment_info_.Finalize(writer_header_))
3269*103e46e4SHarish Mahendrakar       return false;
3270*103e46e4SHarish Mahendrakar 
3271*103e46e4SHarish Mahendrakar     if (output_cues_)
3272*103e46e4SHarish Mahendrakar       if (!seek_head_.AddSeekEntry(libwebm::kMkvCues, MaxOffset()))
3273*103e46e4SHarish Mahendrakar         return false;
3274*103e46e4SHarish Mahendrakar 
3275*103e46e4SHarish Mahendrakar     if (chunking_) {
3276*103e46e4SHarish Mahendrakar       if (!chunk_writer_cues_)
3277*103e46e4SHarish Mahendrakar         return false;
3278*103e46e4SHarish Mahendrakar 
3279*103e46e4SHarish Mahendrakar       char* name = NULL;
3280*103e46e4SHarish Mahendrakar       if (!UpdateChunkName("cues", &name))
3281*103e46e4SHarish Mahendrakar         return false;
3282*103e46e4SHarish Mahendrakar 
3283*103e46e4SHarish Mahendrakar       const bool cues_open = chunk_writer_cues_->Open(name);
3284*103e46e4SHarish Mahendrakar       delete[] name;
3285*103e46e4SHarish Mahendrakar       if (!cues_open)
3286*103e46e4SHarish Mahendrakar         return false;
3287*103e46e4SHarish Mahendrakar     }
3288*103e46e4SHarish Mahendrakar 
3289*103e46e4SHarish Mahendrakar     cluster_end_offset_ = writer_cluster_->Position();
3290*103e46e4SHarish Mahendrakar 
3291*103e46e4SHarish Mahendrakar     // Write the seek headers and cues
3292*103e46e4SHarish Mahendrakar     if (output_cues_)
3293*103e46e4SHarish Mahendrakar       if (!cues_.Write(writer_cues_))
3294*103e46e4SHarish Mahendrakar         return false;
3295*103e46e4SHarish Mahendrakar 
3296*103e46e4SHarish Mahendrakar     if (!seek_head_.Finalize(writer_header_))
3297*103e46e4SHarish Mahendrakar       return false;
3298*103e46e4SHarish Mahendrakar 
3299*103e46e4SHarish Mahendrakar     if (writer_header_->Seekable()) {
3300*103e46e4SHarish Mahendrakar       if (size_position_ == -1)
3301*103e46e4SHarish Mahendrakar         return false;
3302*103e46e4SHarish Mahendrakar 
3303*103e46e4SHarish Mahendrakar       const int64_t segment_size = MaxOffset();
3304*103e46e4SHarish Mahendrakar       if (segment_size < 1)
3305*103e46e4SHarish Mahendrakar         return false;
3306*103e46e4SHarish Mahendrakar 
3307*103e46e4SHarish Mahendrakar       const int64_t pos = writer_header_->Position();
3308*103e46e4SHarish Mahendrakar       UpdateDocTypeVersion();
3309*103e46e4SHarish Mahendrakar       if (doc_type_version_ != doc_type_version_written_) {
3310*103e46e4SHarish Mahendrakar         if (writer_header_->Position(0))
3311*103e46e4SHarish Mahendrakar           return false;
3312*103e46e4SHarish Mahendrakar 
3313*103e46e4SHarish Mahendrakar         const char* const doc_type =
3314*103e46e4SHarish Mahendrakar             DocTypeIsWebm() ? kDocTypeWebm : kDocTypeMatroska;
3315*103e46e4SHarish Mahendrakar         if (!WriteEbmlHeader(writer_header_, doc_type_version_, doc_type))
3316*103e46e4SHarish Mahendrakar           return false;
3317*103e46e4SHarish Mahendrakar         if (writer_header_->Position() != ebml_header_size_)
3318*103e46e4SHarish Mahendrakar           return false;
3319*103e46e4SHarish Mahendrakar 
3320*103e46e4SHarish Mahendrakar         doc_type_version_written_ = doc_type_version_;
3321*103e46e4SHarish Mahendrakar       }
3322*103e46e4SHarish Mahendrakar 
3323*103e46e4SHarish Mahendrakar       if (writer_header_->Position(size_position_))
3324*103e46e4SHarish Mahendrakar         return false;
3325*103e46e4SHarish Mahendrakar 
3326*103e46e4SHarish Mahendrakar       if (WriteUIntSize(writer_header_, segment_size, 8))
3327*103e46e4SHarish Mahendrakar         return false;
3328*103e46e4SHarish Mahendrakar 
3329*103e46e4SHarish Mahendrakar       if (writer_header_->Position(pos))
3330*103e46e4SHarish Mahendrakar         return false;
3331*103e46e4SHarish Mahendrakar     }
3332*103e46e4SHarish Mahendrakar 
3333*103e46e4SHarish Mahendrakar     if (chunking_) {
3334*103e46e4SHarish Mahendrakar       // Do not close any writers until the segment size has been written,
3335*103e46e4SHarish Mahendrakar       // otherwise the size may be off.
3336*103e46e4SHarish Mahendrakar       if (!chunk_writer_cues_ || !chunk_writer_header_)
3337*103e46e4SHarish Mahendrakar         return false;
3338*103e46e4SHarish Mahendrakar 
3339*103e46e4SHarish Mahendrakar       chunk_writer_cues_->Close();
3340*103e46e4SHarish Mahendrakar       chunk_writer_header_->Close();
3341*103e46e4SHarish Mahendrakar     }
3342*103e46e4SHarish Mahendrakar   }
3343*103e46e4SHarish Mahendrakar 
3344*103e46e4SHarish Mahendrakar   return true;
3345*103e46e4SHarish Mahendrakar }
3346*103e46e4SHarish Mahendrakar 
AddTrack(int32_t number)3347*103e46e4SHarish Mahendrakar Track* Segment::AddTrack(int32_t number) {
3348*103e46e4SHarish Mahendrakar   Track* const track = new (std::nothrow) Track(&seed_);  // NOLINT
3349*103e46e4SHarish Mahendrakar 
3350*103e46e4SHarish Mahendrakar   if (!track)
3351*103e46e4SHarish Mahendrakar     return NULL;
3352*103e46e4SHarish Mahendrakar 
3353*103e46e4SHarish Mahendrakar   if (!tracks_.AddTrack(track, number)) {
3354*103e46e4SHarish Mahendrakar     delete track;
3355*103e46e4SHarish Mahendrakar     return NULL;
3356*103e46e4SHarish Mahendrakar   }
3357*103e46e4SHarish Mahendrakar 
3358*103e46e4SHarish Mahendrakar   return track;
3359*103e46e4SHarish Mahendrakar }
3360*103e46e4SHarish Mahendrakar 
AddChapter()3361*103e46e4SHarish Mahendrakar Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); }
3362*103e46e4SHarish Mahendrakar 
AddTag()3363*103e46e4SHarish Mahendrakar Tag* Segment::AddTag() { return tags_.AddTag(); }
3364*103e46e4SHarish Mahendrakar 
AddVideoTrack(int32_t width,int32_t height,int32_t number)3365*103e46e4SHarish Mahendrakar uint64_t Segment::AddVideoTrack(int32_t width, int32_t height, int32_t number) {
3366*103e46e4SHarish Mahendrakar   VideoTrack* const track = new (std::nothrow) VideoTrack(&seed_);  // NOLINT
3367*103e46e4SHarish Mahendrakar   if (!track)
3368*103e46e4SHarish Mahendrakar     return 0;
3369*103e46e4SHarish Mahendrakar 
3370*103e46e4SHarish Mahendrakar   track->set_type(Tracks::kVideo);
3371*103e46e4SHarish Mahendrakar   track->set_codec_id(Tracks::kVp8CodecId);
3372*103e46e4SHarish Mahendrakar   track->set_width(width);
3373*103e46e4SHarish Mahendrakar   track->set_height(height);
3374*103e46e4SHarish Mahendrakar 
3375*103e46e4SHarish Mahendrakar   if (!tracks_.AddTrack(track, number)) {
3376*103e46e4SHarish Mahendrakar     delete track;
3377*103e46e4SHarish Mahendrakar     return 0;
3378*103e46e4SHarish Mahendrakar   }
3379*103e46e4SHarish Mahendrakar   has_video_ = true;
3380*103e46e4SHarish Mahendrakar 
3381*103e46e4SHarish Mahendrakar   return track->number();
3382*103e46e4SHarish Mahendrakar }
3383*103e46e4SHarish Mahendrakar 
AddCuePoint(uint64_t timestamp,uint64_t track)3384*103e46e4SHarish Mahendrakar bool Segment::AddCuePoint(uint64_t timestamp, uint64_t track) {
3385*103e46e4SHarish Mahendrakar   if (cluster_list_size_ < 1)
3386*103e46e4SHarish Mahendrakar     return false;
3387*103e46e4SHarish Mahendrakar 
3388*103e46e4SHarish Mahendrakar   const Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
3389*103e46e4SHarish Mahendrakar   if (!cluster)
3390*103e46e4SHarish Mahendrakar     return false;
3391*103e46e4SHarish Mahendrakar 
3392*103e46e4SHarish Mahendrakar   CuePoint* const cue = new (std::nothrow) CuePoint();  // NOLINT
3393*103e46e4SHarish Mahendrakar   if (!cue)
3394*103e46e4SHarish Mahendrakar     return false;
3395*103e46e4SHarish Mahendrakar 
3396*103e46e4SHarish Mahendrakar   cue->set_time(timestamp / segment_info_.timecode_scale());
3397*103e46e4SHarish Mahendrakar   cue->set_block_number(cluster->blocks_added());
3398*103e46e4SHarish Mahendrakar   cue->set_cluster_pos(cluster->position_for_cues());
3399*103e46e4SHarish Mahendrakar   cue->set_track(track);
3400*103e46e4SHarish Mahendrakar   if (!cues_.AddCue(cue)) {
3401*103e46e4SHarish Mahendrakar     delete cue;
3402*103e46e4SHarish Mahendrakar     return false;
3403*103e46e4SHarish Mahendrakar   }
3404*103e46e4SHarish Mahendrakar 
3405*103e46e4SHarish Mahendrakar   new_cuepoint_ = false;
3406*103e46e4SHarish Mahendrakar   return true;
3407*103e46e4SHarish Mahendrakar }
3408*103e46e4SHarish Mahendrakar 
AddAudioTrack(int32_t sample_rate,int32_t channels,int32_t number)3409*103e46e4SHarish Mahendrakar uint64_t Segment::AddAudioTrack(int32_t sample_rate, int32_t channels,
3410*103e46e4SHarish Mahendrakar                                 int32_t number) {
3411*103e46e4SHarish Mahendrakar   AudioTrack* const track = new (std::nothrow) AudioTrack(&seed_);  // NOLINT
3412*103e46e4SHarish Mahendrakar   if (!track)
3413*103e46e4SHarish Mahendrakar     return 0;
3414*103e46e4SHarish Mahendrakar 
3415*103e46e4SHarish Mahendrakar   track->set_type(Tracks::kAudio);
3416*103e46e4SHarish Mahendrakar   track->set_codec_id(Tracks::kVorbisCodecId);
3417*103e46e4SHarish Mahendrakar   track->set_sample_rate(sample_rate);
3418*103e46e4SHarish Mahendrakar   track->set_channels(channels);
3419*103e46e4SHarish Mahendrakar 
3420*103e46e4SHarish Mahendrakar   if (!tracks_.AddTrack(track, number)) {
3421*103e46e4SHarish Mahendrakar     delete track;
3422*103e46e4SHarish Mahendrakar     return 0;
3423*103e46e4SHarish Mahendrakar   }
3424*103e46e4SHarish Mahendrakar 
3425*103e46e4SHarish Mahendrakar   return track->number();
3426*103e46e4SHarish Mahendrakar }
3427*103e46e4SHarish Mahendrakar 
AddFrame(const uint8_t * data,uint64_t length,uint64_t track_number,uint64_t timestamp,bool is_key)3428*103e46e4SHarish Mahendrakar bool Segment::AddFrame(const uint8_t* data, uint64_t length,
3429*103e46e4SHarish Mahendrakar                        uint64_t track_number, uint64_t timestamp, bool is_key) {
3430*103e46e4SHarish Mahendrakar   if (!data)
3431*103e46e4SHarish Mahendrakar     return false;
3432*103e46e4SHarish Mahendrakar 
3433*103e46e4SHarish Mahendrakar   Frame frame;
3434*103e46e4SHarish Mahendrakar   if (!frame.Init(data, length))
3435*103e46e4SHarish Mahendrakar     return false;
3436*103e46e4SHarish Mahendrakar   frame.set_track_number(track_number);
3437*103e46e4SHarish Mahendrakar   frame.set_timestamp(timestamp);
3438*103e46e4SHarish Mahendrakar   frame.set_is_key(is_key);
3439*103e46e4SHarish Mahendrakar   return AddGenericFrame(&frame);
3440*103e46e4SHarish Mahendrakar }
3441*103e46e4SHarish Mahendrakar 
AddFrameWithAdditional(const uint8_t * data,uint64_t length,const uint8_t * additional,uint64_t additional_length,uint64_t add_id,uint64_t track_number,uint64_t timestamp,bool is_key)3442*103e46e4SHarish Mahendrakar bool Segment::AddFrameWithAdditional(const uint8_t* data, uint64_t length,
3443*103e46e4SHarish Mahendrakar                                      const uint8_t* additional,
3444*103e46e4SHarish Mahendrakar                                      uint64_t additional_length,
3445*103e46e4SHarish Mahendrakar                                      uint64_t add_id, uint64_t track_number,
3446*103e46e4SHarish Mahendrakar                                      uint64_t timestamp, bool is_key) {
3447*103e46e4SHarish Mahendrakar   if (!data || !additional)
3448*103e46e4SHarish Mahendrakar     return false;
3449*103e46e4SHarish Mahendrakar 
3450*103e46e4SHarish Mahendrakar   Frame frame;
3451*103e46e4SHarish Mahendrakar   if (!frame.Init(data, length) ||
3452*103e46e4SHarish Mahendrakar       !frame.AddAdditionalData(additional, additional_length, add_id)) {
3453*103e46e4SHarish Mahendrakar     return false;
3454*103e46e4SHarish Mahendrakar   }
3455*103e46e4SHarish Mahendrakar   frame.set_track_number(track_number);
3456*103e46e4SHarish Mahendrakar   frame.set_timestamp(timestamp);
3457*103e46e4SHarish Mahendrakar   frame.set_is_key(is_key);
3458*103e46e4SHarish Mahendrakar   return AddGenericFrame(&frame);
3459*103e46e4SHarish Mahendrakar }
3460*103e46e4SHarish Mahendrakar 
AddFrameWithDiscardPadding(const uint8_t * data,uint64_t length,int64_t discard_padding,uint64_t track_number,uint64_t timestamp,bool is_key)3461*103e46e4SHarish Mahendrakar bool Segment::AddFrameWithDiscardPadding(const uint8_t* data, uint64_t length,
3462*103e46e4SHarish Mahendrakar                                          int64_t discard_padding,
3463*103e46e4SHarish Mahendrakar                                          uint64_t track_number,
3464*103e46e4SHarish Mahendrakar                                          uint64_t timestamp, bool is_key) {
3465*103e46e4SHarish Mahendrakar   if (!data)
3466*103e46e4SHarish Mahendrakar     return false;
3467*103e46e4SHarish Mahendrakar 
3468*103e46e4SHarish Mahendrakar   Frame frame;
3469*103e46e4SHarish Mahendrakar   if (!frame.Init(data, length))
3470*103e46e4SHarish Mahendrakar     return false;
3471*103e46e4SHarish Mahendrakar   frame.set_discard_padding(discard_padding);
3472*103e46e4SHarish Mahendrakar   frame.set_track_number(track_number);
3473*103e46e4SHarish Mahendrakar   frame.set_timestamp(timestamp);
3474*103e46e4SHarish Mahendrakar   frame.set_is_key(is_key);
3475*103e46e4SHarish Mahendrakar   return AddGenericFrame(&frame);
3476*103e46e4SHarish Mahendrakar }
3477*103e46e4SHarish Mahendrakar 
AddMetadata(const uint8_t * data,uint64_t length,uint64_t track_number,uint64_t timestamp_ns,uint64_t duration_ns)3478*103e46e4SHarish Mahendrakar bool Segment::AddMetadata(const uint8_t* data, uint64_t length,
3479*103e46e4SHarish Mahendrakar                           uint64_t track_number, uint64_t timestamp_ns,
3480*103e46e4SHarish Mahendrakar                           uint64_t duration_ns) {
3481*103e46e4SHarish Mahendrakar   if (!data)
3482*103e46e4SHarish Mahendrakar     return false;
3483*103e46e4SHarish Mahendrakar 
3484*103e46e4SHarish Mahendrakar   Frame frame;
3485*103e46e4SHarish Mahendrakar   if (!frame.Init(data, length))
3486*103e46e4SHarish Mahendrakar     return false;
3487*103e46e4SHarish Mahendrakar   frame.set_track_number(track_number);
3488*103e46e4SHarish Mahendrakar   frame.set_timestamp(timestamp_ns);
3489*103e46e4SHarish Mahendrakar   frame.set_duration(duration_ns);
3490*103e46e4SHarish Mahendrakar   frame.set_is_key(true);  // All metadata blocks are keyframes.
3491*103e46e4SHarish Mahendrakar   return AddGenericFrame(&frame);
3492*103e46e4SHarish Mahendrakar }
3493*103e46e4SHarish Mahendrakar 
AddGenericFrame(const Frame * frame)3494*103e46e4SHarish Mahendrakar bool Segment::AddGenericFrame(const Frame* frame) {
3495*103e46e4SHarish Mahendrakar   if (!frame)
3496*103e46e4SHarish Mahendrakar     return false;
3497*103e46e4SHarish Mahendrakar 
3498*103e46e4SHarish Mahendrakar   if (!CheckHeaderInfo())
3499*103e46e4SHarish Mahendrakar     return false;
3500*103e46e4SHarish Mahendrakar 
3501*103e46e4SHarish Mahendrakar   // Check for non-monotonically increasing timestamps.
3502*103e46e4SHarish Mahendrakar   if (frame->timestamp() < last_timestamp_)
3503*103e46e4SHarish Mahendrakar     return false;
3504*103e46e4SHarish Mahendrakar 
3505*103e46e4SHarish Mahendrakar   // Check if the track number is valid.
3506*103e46e4SHarish Mahendrakar   if (!tracks_.GetTrackByNumber(frame->track_number()))
3507*103e46e4SHarish Mahendrakar     return false;
3508*103e46e4SHarish Mahendrakar 
3509*103e46e4SHarish Mahendrakar   if (frame->discard_padding() != 0)
3510*103e46e4SHarish Mahendrakar     doc_type_version_ = 4;
3511*103e46e4SHarish Mahendrakar 
3512*103e46e4SHarish Mahendrakar   if (cluster_list_size_ > 0) {
3513*103e46e4SHarish Mahendrakar     const uint64_t timecode_scale = segment_info_.timecode_scale();
3514*103e46e4SHarish Mahendrakar     const uint64_t frame_timecode = frame->timestamp() / timecode_scale;
3515*103e46e4SHarish Mahendrakar 
3516*103e46e4SHarish Mahendrakar     const Cluster* const last_cluster = cluster_list_[cluster_list_size_ - 1];
3517*103e46e4SHarish Mahendrakar     const uint64_t last_cluster_timecode = last_cluster->timecode();
3518*103e46e4SHarish Mahendrakar 
3519*103e46e4SHarish Mahendrakar     const uint64_t rel_timecode = frame_timecode - last_cluster_timecode;
3520*103e46e4SHarish Mahendrakar     if (rel_timecode > kMaxBlockTimecode) {
3521*103e46e4SHarish Mahendrakar       force_new_cluster_ = true;
3522*103e46e4SHarish Mahendrakar     }
3523*103e46e4SHarish Mahendrakar   }
3524*103e46e4SHarish Mahendrakar 
3525*103e46e4SHarish Mahendrakar   // If the segment has a video track hold onto audio frames to make sure the
3526*103e46e4SHarish Mahendrakar   // audio that is associated with the start time of a video key-frame is
3527*103e46e4SHarish Mahendrakar   // muxed into the same cluster.
3528*103e46e4SHarish Mahendrakar   if (has_video_ && tracks_.TrackIsAudio(frame->track_number()) &&
3529*103e46e4SHarish Mahendrakar       !force_new_cluster_) {
3530*103e46e4SHarish Mahendrakar     Frame* const new_frame = new (std::nothrow) Frame();
3531*103e46e4SHarish Mahendrakar     if (!new_frame || !new_frame->CopyFrom(*frame)) {
3532*103e46e4SHarish Mahendrakar       delete new_frame;
3533*103e46e4SHarish Mahendrakar       return false;
3534*103e46e4SHarish Mahendrakar     }
3535*103e46e4SHarish Mahendrakar     if (!QueueFrame(new_frame)) {
3536*103e46e4SHarish Mahendrakar       delete new_frame;
3537*103e46e4SHarish Mahendrakar       return false;
3538*103e46e4SHarish Mahendrakar     }
3539*103e46e4SHarish Mahendrakar     track_frames_written_[frame->track_number() - 1]++;
3540*103e46e4SHarish Mahendrakar     return true;
3541*103e46e4SHarish Mahendrakar   }
3542*103e46e4SHarish Mahendrakar 
3543*103e46e4SHarish Mahendrakar   if (!DoNewClusterProcessing(frame->track_number(), frame->timestamp(),
3544*103e46e4SHarish Mahendrakar                               frame->is_key())) {
3545*103e46e4SHarish Mahendrakar     return false;
3546*103e46e4SHarish Mahendrakar   }
3547*103e46e4SHarish Mahendrakar 
3548*103e46e4SHarish Mahendrakar   if (cluster_list_size_ < 1)
3549*103e46e4SHarish Mahendrakar     return false;
3550*103e46e4SHarish Mahendrakar 
3551*103e46e4SHarish Mahendrakar   Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
3552*103e46e4SHarish Mahendrakar   if (!cluster)
3553*103e46e4SHarish Mahendrakar     return false;
3554*103e46e4SHarish Mahendrakar 
3555*103e46e4SHarish Mahendrakar   // If the Frame is not a SimpleBlock, then set the reference_block_timestamp
3556*103e46e4SHarish Mahendrakar   // if it is not set already.
3557*103e46e4SHarish Mahendrakar   bool frame_created = false;
3558*103e46e4SHarish Mahendrakar   if (!frame->CanBeSimpleBlock() && !frame->is_key() &&
3559*103e46e4SHarish Mahendrakar       !frame->reference_block_timestamp_set()) {
3560*103e46e4SHarish Mahendrakar     Frame* const new_frame = new (std::nothrow) Frame();
3561*103e46e4SHarish Mahendrakar     if (!new_frame || !new_frame->CopyFrom(*frame)) {
3562*103e46e4SHarish Mahendrakar       delete new_frame;
3563*103e46e4SHarish Mahendrakar       return false;
3564*103e46e4SHarish Mahendrakar     }
3565*103e46e4SHarish Mahendrakar     new_frame->set_reference_block_timestamp(
3566*103e46e4SHarish Mahendrakar         last_track_timestamp_[frame->track_number() - 1]);
3567*103e46e4SHarish Mahendrakar     frame = new_frame;
3568*103e46e4SHarish Mahendrakar     frame_created = true;
3569*103e46e4SHarish Mahendrakar   }
3570*103e46e4SHarish Mahendrakar 
3571*103e46e4SHarish Mahendrakar   if (!cluster->AddFrame(frame))
3572*103e46e4SHarish Mahendrakar     return false;
3573*103e46e4SHarish Mahendrakar 
3574*103e46e4SHarish Mahendrakar   if (new_cuepoint_ && cues_track_ == frame->track_number()) {
3575*103e46e4SHarish Mahendrakar     if (!AddCuePoint(frame->timestamp(), cues_track_))
3576*103e46e4SHarish Mahendrakar       return false;
3577*103e46e4SHarish Mahendrakar   }
3578*103e46e4SHarish Mahendrakar 
3579*103e46e4SHarish Mahendrakar   last_timestamp_ = frame->timestamp();
3580*103e46e4SHarish Mahendrakar   last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
3581*103e46e4SHarish Mahendrakar   last_block_duration_ = frame->duration();
3582*103e46e4SHarish Mahendrakar   track_frames_written_[frame->track_number() - 1]++;
3583*103e46e4SHarish Mahendrakar 
3584*103e46e4SHarish Mahendrakar   if (frame_created)
3585*103e46e4SHarish Mahendrakar     delete frame;
3586*103e46e4SHarish Mahendrakar   return true;
3587*103e46e4SHarish Mahendrakar }
3588*103e46e4SHarish Mahendrakar 
OutputCues(bool output_cues)3589*103e46e4SHarish Mahendrakar void Segment::OutputCues(bool output_cues) { output_cues_ = output_cues; }
3590*103e46e4SHarish Mahendrakar 
AccurateClusterDuration(bool accurate_cluster_duration)3591*103e46e4SHarish Mahendrakar void Segment::AccurateClusterDuration(bool accurate_cluster_duration) {
3592*103e46e4SHarish Mahendrakar   accurate_cluster_duration_ = accurate_cluster_duration;
3593*103e46e4SHarish Mahendrakar }
3594*103e46e4SHarish Mahendrakar 
UseFixedSizeClusterTimecode(bool fixed_size_cluster_timecode)3595*103e46e4SHarish Mahendrakar void Segment::UseFixedSizeClusterTimecode(bool fixed_size_cluster_timecode) {
3596*103e46e4SHarish Mahendrakar   fixed_size_cluster_timecode_ = fixed_size_cluster_timecode;
3597*103e46e4SHarish Mahendrakar }
3598*103e46e4SHarish Mahendrakar 
SetChunking(bool chunking,const char * filename)3599*103e46e4SHarish Mahendrakar bool Segment::SetChunking(bool chunking, const char* filename) {
3600*103e46e4SHarish Mahendrakar   if (chunk_count_ > 0)
3601*103e46e4SHarish Mahendrakar     return false;
3602*103e46e4SHarish Mahendrakar 
3603*103e46e4SHarish Mahendrakar   if (chunking) {
3604*103e46e4SHarish Mahendrakar     if (!filename)
3605*103e46e4SHarish Mahendrakar       return false;
3606*103e46e4SHarish Mahendrakar 
3607*103e46e4SHarish Mahendrakar     // Check if we are being set to what is already set.
3608*103e46e4SHarish Mahendrakar     if (chunking_ && !strcmp(filename, chunking_base_name_))
3609*103e46e4SHarish Mahendrakar       return true;
3610*103e46e4SHarish Mahendrakar 
3611*103e46e4SHarish Mahendrakar     const size_t filename_length = strlen(filename);
3612*103e46e4SHarish Mahendrakar     char* const temp = new (std::nothrow) char[filename_length + 1];  // NOLINT
3613*103e46e4SHarish Mahendrakar     if (!temp)
3614*103e46e4SHarish Mahendrakar       return false;
3615*103e46e4SHarish Mahendrakar 
3616*103e46e4SHarish Mahendrakar     memcpy(temp, filename, filename_length);
3617*103e46e4SHarish Mahendrakar     temp[filename_length] = '\0';
3618*103e46e4SHarish Mahendrakar 
3619*103e46e4SHarish Mahendrakar     delete[] chunking_base_name_;
3620*103e46e4SHarish Mahendrakar     chunking_base_name_ = temp;
3621*103e46e4SHarish Mahendrakar     // From this point, strlen(chunking_base_name_) == filename_length
3622*103e46e4SHarish Mahendrakar 
3623*103e46e4SHarish Mahendrakar     if (!UpdateChunkName("chk", &chunk_name_))
3624*103e46e4SHarish Mahendrakar       return false;
3625*103e46e4SHarish Mahendrakar 
3626*103e46e4SHarish Mahendrakar     if (!chunk_writer_cluster_) {
3627*103e46e4SHarish Mahendrakar       chunk_writer_cluster_ = new (std::nothrow) MkvWriter();  // NOLINT
3628*103e46e4SHarish Mahendrakar       if (!chunk_writer_cluster_)
3629*103e46e4SHarish Mahendrakar         return false;
3630*103e46e4SHarish Mahendrakar     }
3631*103e46e4SHarish Mahendrakar 
3632*103e46e4SHarish Mahendrakar     if (!chunk_writer_cues_) {
3633*103e46e4SHarish Mahendrakar       chunk_writer_cues_ = new (std::nothrow) MkvWriter();  // NOLINT
3634*103e46e4SHarish Mahendrakar       if (!chunk_writer_cues_)
3635*103e46e4SHarish Mahendrakar         return false;
3636*103e46e4SHarish Mahendrakar     }
3637*103e46e4SHarish Mahendrakar 
3638*103e46e4SHarish Mahendrakar     if (!chunk_writer_header_) {
3639*103e46e4SHarish Mahendrakar       chunk_writer_header_ = new (std::nothrow) MkvWriter();  // NOLINT
3640*103e46e4SHarish Mahendrakar       if (!chunk_writer_header_)
3641*103e46e4SHarish Mahendrakar         return false;
3642*103e46e4SHarish Mahendrakar     }
3643*103e46e4SHarish Mahendrakar 
3644*103e46e4SHarish Mahendrakar     if (!chunk_writer_cluster_->Open(chunk_name_))
3645*103e46e4SHarish Mahendrakar       return false;
3646*103e46e4SHarish Mahendrakar 
3647*103e46e4SHarish Mahendrakar     const size_t hdr_length = strlen(".hdr");
3648*103e46e4SHarish Mahendrakar     const size_t header_length = filename_length + hdr_length + 1;
3649*103e46e4SHarish Mahendrakar     char* const header = new (std::nothrow) char[header_length];  // NOLINT
3650*103e46e4SHarish Mahendrakar     if (!header)
3651*103e46e4SHarish Mahendrakar       return false;
3652*103e46e4SHarish Mahendrakar 
3653*103e46e4SHarish Mahendrakar     memcpy(header, chunking_base_name_, filename_length);
3654*103e46e4SHarish Mahendrakar     memcpy(&header[filename_length], ".hdr", hdr_length);
3655*103e46e4SHarish Mahendrakar     header[filename_length + hdr_length] = '\0';
3656*103e46e4SHarish Mahendrakar 
3657*103e46e4SHarish Mahendrakar     if (!chunk_writer_header_->Open(header)) {
3658*103e46e4SHarish Mahendrakar       delete[] header;
3659*103e46e4SHarish Mahendrakar       return false;
3660*103e46e4SHarish Mahendrakar     }
3661*103e46e4SHarish Mahendrakar 
3662*103e46e4SHarish Mahendrakar     writer_cluster_ = chunk_writer_cluster_;
3663*103e46e4SHarish Mahendrakar     writer_cues_ = chunk_writer_cues_;
3664*103e46e4SHarish Mahendrakar     writer_header_ = chunk_writer_header_;
3665*103e46e4SHarish Mahendrakar 
3666*103e46e4SHarish Mahendrakar     delete[] header;
3667*103e46e4SHarish Mahendrakar   }
3668*103e46e4SHarish Mahendrakar 
3669*103e46e4SHarish Mahendrakar   chunking_ = chunking;
3670*103e46e4SHarish Mahendrakar 
3671*103e46e4SHarish Mahendrakar   return true;
3672*103e46e4SHarish Mahendrakar }
3673*103e46e4SHarish Mahendrakar 
CuesTrack(uint64_t track_number)3674*103e46e4SHarish Mahendrakar bool Segment::CuesTrack(uint64_t track_number) {
3675*103e46e4SHarish Mahendrakar   const Track* const track = GetTrackByNumber(track_number);
3676*103e46e4SHarish Mahendrakar   if (!track)
3677*103e46e4SHarish Mahendrakar     return false;
3678*103e46e4SHarish Mahendrakar 
3679*103e46e4SHarish Mahendrakar   cues_track_ = track_number;
3680*103e46e4SHarish Mahendrakar   return true;
3681*103e46e4SHarish Mahendrakar }
3682*103e46e4SHarish Mahendrakar 
ForceNewClusterOnNextFrame()3683*103e46e4SHarish Mahendrakar void Segment::ForceNewClusterOnNextFrame() { force_new_cluster_ = true; }
3684*103e46e4SHarish Mahendrakar 
GetTrackByNumber(uint64_t track_number) const3685*103e46e4SHarish Mahendrakar Track* Segment::GetTrackByNumber(uint64_t track_number) const {
3686*103e46e4SHarish Mahendrakar   return tracks_.GetTrackByNumber(track_number);
3687*103e46e4SHarish Mahendrakar }
3688*103e46e4SHarish Mahendrakar 
WriteSegmentHeader()3689*103e46e4SHarish Mahendrakar bool Segment::WriteSegmentHeader() {
3690*103e46e4SHarish Mahendrakar   UpdateDocTypeVersion();
3691*103e46e4SHarish Mahendrakar 
3692*103e46e4SHarish Mahendrakar   const char* const doc_type =
3693*103e46e4SHarish Mahendrakar       DocTypeIsWebm() ? kDocTypeWebm : kDocTypeMatroska;
3694*103e46e4SHarish Mahendrakar   if (!WriteEbmlHeader(writer_header_, doc_type_version_, doc_type))
3695*103e46e4SHarish Mahendrakar     return false;
3696*103e46e4SHarish Mahendrakar   doc_type_version_written_ = doc_type_version_;
3697*103e46e4SHarish Mahendrakar   ebml_header_size_ = static_cast<int32_t>(writer_header_->Position());
3698*103e46e4SHarish Mahendrakar 
3699*103e46e4SHarish Mahendrakar   // Write "unknown" (-1) as segment size value. If mode is kFile, Segment
3700*103e46e4SHarish Mahendrakar   // will write over duration when the file is finalized.
3701*103e46e4SHarish Mahendrakar   if (WriteID(writer_header_, libwebm::kMkvSegment))
3702*103e46e4SHarish Mahendrakar     return false;
3703*103e46e4SHarish Mahendrakar 
3704*103e46e4SHarish Mahendrakar   // Save for later.
3705*103e46e4SHarish Mahendrakar   size_position_ = writer_header_->Position();
3706*103e46e4SHarish Mahendrakar 
3707*103e46e4SHarish Mahendrakar   // Write "unknown" (EBML coded -1) as segment size value. We need to write 8
3708*103e46e4SHarish Mahendrakar   // bytes because if we are going to overwrite the segment size later we do
3709*103e46e4SHarish Mahendrakar   // not know how big our segment will be.
3710*103e46e4SHarish Mahendrakar   if (SerializeInt(writer_header_, kEbmlUnknownValue, 8))
3711*103e46e4SHarish Mahendrakar     return false;
3712*103e46e4SHarish Mahendrakar 
3713*103e46e4SHarish Mahendrakar   payload_pos_ = writer_header_->Position();
3714*103e46e4SHarish Mahendrakar 
3715*103e46e4SHarish Mahendrakar   if (mode_ == kFile && writer_header_->Seekable()) {
3716*103e46e4SHarish Mahendrakar     // Set the duration > 0.0 so SegmentInfo will write out the duration. When
3717*103e46e4SHarish Mahendrakar     // the muxer is done writing we will set the correct duration and have
3718*103e46e4SHarish Mahendrakar     // SegmentInfo upadte it.
3719*103e46e4SHarish Mahendrakar     segment_info_.set_duration(1.0);
3720*103e46e4SHarish Mahendrakar 
3721*103e46e4SHarish Mahendrakar     if (!seek_head_.Write(writer_header_))
3722*103e46e4SHarish Mahendrakar       return false;
3723*103e46e4SHarish Mahendrakar   }
3724*103e46e4SHarish Mahendrakar 
3725*103e46e4SHarish Mahendrakar   if (!seek_head_.AddSeekEntry(libwebm::kMkvInfo, MaxOffset()))
3726*103e46e4SHarish Mahendrakar     return false;
3727*103e46e4SHarish Mahendrakar   if (!segment_info_.Write(writer_header_))
3728*103e46e4SHarish Mahendrakar     return false;
3729*103e46e4SHarish Mahendrakar 
3730*103e46e4SHarish Mahendrakar   if (!seek_head_.AddSeekEntry(libwebm::kMkvTracks, MaxOffset()))
3731*103e46e4SHarish Mahendrakar     return false;
3732*103e46e4SHarish Mahendrakar   if (!tracks_.Write(writer_header_))
3733*103e46e4SHarish Mahendrakar     return false;
3734*103e46e4SHarish Mahendrakar 
3735*103e46e4SHarish Mahendrakar   if (chapters_.Count() > 0) {
3736*103e46e4SHarish Mahendrakar     if (!seek_head_.AddSeekEntry(libwebm::kMkvChapters, MaxOffset()))
3737*103e46e4SHarish Mahendrakar       return false;
3738*103e46e4SHarish Mahendrakar     if (!chapters_.Write(writer_header_))
3739*103e46e4SHarish Mahendrakar       return false;
3740*103e46e4SHarish Mahendrakar   }
3741*103e46e4SHarish Mahendrakar 
3742*103e46e4SHarish Mahendrakar   if (tags_.Count() > 0) {
3743*103e46e4SHarish Mahendrakar     if (!seek_head_.AddSeekEntry(libwebm::kMkvTags, MaxOffset()))
3744*103e46e4SHarish Mahendrakar       return false;
3745*103e46e4SHarish Mahendrakar     if (!tags_.Write(writer_header_))
3746*103e46e4SHarish Mahendrakar       return false;
3747*103e46e4SHarish Mahendrakar   }
3748*103e46e4SHarish Mahendrakar 
3749*103e46e4SHarish Mahendrakar   if (chunking_ && (mode_ == kLive || !writer_header_->Seekable())) {
3750*103e46e4SHarish Mahendrakar     if (!chunk_writer_header_)
3751*103e46e4SHarish Mahendrakar       return false;
3752*103e46e4SHarish Mahendrakar 
3753*103e46e4SHarish Mahendrakar     chunk_writer_header_->Close();
3754*103e46e4SHarish Mahendrakar   }
3755*103e46e4SHarish Mahendrakar 
3756*103e46e4SHarish Mahendrakar   header_written_ = true;
3757*103e46e4SHarish Mahendrakar 
3758*103e46e4SHarish Mahendrakar   return true;
3759*103e46e4SHarish Mahendrakar }
3760*103e46e4SHarish Mahendrakar 
3761*103e46e4SHarish Mahendrakar // Here we are testing whether to create a new cluster, given a frame
3762*103e46e4SHarish Mahendrakar // having time frame_timestamp_ns.
3763*103e46e4SHarish Mahendrakar //
TestFrame(uint64_t track_number,uint64_t frame_timestamp_ns,bool is_key) const3764*103e46e4SHarish Mahendrakar int Segment::TestFrame(uint64_t track_number, uint64_t frame_timestamp_ns,
3765*103e46e4SHarish Mahendrakar                        bool is_key) const {
3766*103e46e4SHarish Mahendrakar   if (force_new_cluster_)
3767*103e46e4SHarish Mahendrakar     return 1;
3768*103e46e4SHarish Mahendrakar 
3769*103e46e4SHarish Mahendrakar   // If no clusters have been created yet, then create a new cluster
3770*103e46e4SHarish Mahendrakar   // and write this frame immediately, in the new cluster.  This path
3771*103e46e4SHarish Mahendrakar   // should only be followed once, the first time we attempt to write
3772*103e46e4SHarish Mahendrakar   // a frame.
3773*103e46e4SHarish Mahendrakar 
3774*103e46e4SHarish Mahendrakar   if (cluster_list_size_ <= 0)
3775*103e46e4SHarish Mahendrakar     return 1;
3776*103e46e4SHarish Mahendrakar 
3777*103e46e4SHarish Mahendrakar   // There exists at least one cluster. We must compare the frame to
3778*103e46e4SHarish Mahendrakar   // the last cluster, in order to determine whether the frame is
3779*103e46e4SHarish Mahendrakar   // written to the existing cluster, or that a new cluster should be
3780*103e46e4SHarish Mahendrakar   // created.
3781*103e46e4SHarish Mahendrakar 
3782*103e46e4SHarish Mahendrakar   const uint64_t timecode_scale = segment_info_.timecode_scale();
3783*103e46e4SHarish Mahendrakar   const uint64_t frame_timecode = frame_timestamp_ns / timecode_scale;
3784*103e46e4SHarish Mahendrakar 
3785*103e46e4SHarish Mahendrakar   const Cluster* const last_cluster = cluster_list_[cluster_list_size_ - 1];
3786*103e46e4SHarish Mahendrakar   const uint64_t last_cluster_timecode = last_cluster->timecode();
3787*103e46e4SHarish Mahendrakar 
3788*103e46e4SHarish Mahendrakar   // For completeness we test for the case when the frame's timecode
3789*103e46e4SHarish Mahendrakar   // is less than the cluster's timecode.  Although in principle that
3790*103e46e4SHarish Mahendrakar   // is allowed, this muxer doesn't actually write clusters like that,
3791*103e46e4SHarish Mahendrakar   // so this indicates a bug somewhere in our algorithm.
3792*103e46e4SHarish Mahendrakar 
3793*103e46e4SHarish Mahendrakar   if (frame_timecode < last_cluster_timecode)  // should never happen
3794*103e46e4SHarish Mahendrakar     return -1;
3795*103e46e4SHarish Mahendrakar 
3796*103e46e4SHarish Mahendrakar   // If the frame has a timestamp significantly larger than the last
3797*103e46e4SHarish Mahendrakar   // cluster (in Matroska, cluster-relative timestamps are serialized
3798*103e46e4SHarish Mahendrakar   // using a 16-bit signed integer), then we cannot write this frame
3799*103e46e4SHarish Mahendrakar   // to that cluster, and so we must create a new cluster.
3800*103e46e4SHarish Mahendrakar 
3801*103e46e4SHarish Mahendrakar   const int64_t delta_timecode = frame_timecode - last_cluster_timecode;
3802*103e46e4SHarish Mahendrakar 
3803*103e46e4SHarish Mahendrakar   if (delta_timecode > kMaxBlockTimecode)
3804*103e46e4SHarish Mahendrakar     return 2;
3805*103e46e4SHarish Mahendrakar 
3806*103e46e4SHarish Mahendrakar   // We decide to create a new cluster when we have a video keyframe.
3807*103e46e4SHarish Mahendrakar   // This will flush queued (audio) frames, and write the keyframe
3808*103e46e4SHarish Mahendrakar   // immediately, in the newly-created cluster.
3809*103e46e4SHarish Mahendrakar 
3810*103e46e4SHarish Mahendrakar   if (is_key && tracks_.TrackIsVideo(track_number))
3811*103e46e4SHarish Mahendrakar     return 1;
3812*103e46e4SHarish Mahendrakar 
3813*103e46e4SHarish Mahendrakar   // Create a new cluster if we have accumulated too many frames
3814*103e46e4SHarish Mahendrakar   // already, where "too many" is defined as "the total time of frames
3815*103e46e4SHarish Mahendrakar   // in the cluster exceeds a threshold".
3816*103e46e4SHarish Mahendrakar 
3817*103e46e4SHarish Mahendrakar   const uint64_t delta_ns = delta_timecode * timecode_scale;
3818*103e46e4SHarish Mahendrakar 
3819*103e46e4SHarish Mahendrakar   if (max_cluster_duration_ > 0 && delta_ns >= max_cluster_duration_)
3820*103e46e4SHarish Mahendrakar     return 1;
3821*103e46e4SHarish Mahendrakar 
3822*103e46e4SHarish Mahendrakar   // This is similar to the case above, with the difference that a new
3823*103e46e4SHarish Mahendrakar   // cluster is created when the size of the current cluster exceeds a
3824*103e46e4SHarish Mahendrakar   // threshold.
3825*103e46e4SHarish Mahendrakar 
3826*103e46e4SHarish Mahendrakar   const uint64_t cluster_size = last_cluster->payload_size();
3827*103e46e4SHarish Mahendrakar 
3828*103e46e4SHarish Mahendrakar   if (max_cluster_size_ > 0 && cluster_size >= max_cluster_size_)
3829*103e46e4SHarish Mahendrakar     return 1;
3830*103e46e4SHarish Mahendrakar 
3831*103e46e4SHarish Mahendrakar   // There's no need to create a new cluster, so emit this frame now.
3832*103e46e4SHarish Mahendrakar 
3833*103e46e4SHarish Mahendrakar   return 0;
3834*103e46e4SHarish Mahendrakar }
3835*103e46e4SHarish Mahendrakar 
MakeNewCluster(uint64_t frame_timestamp_ns)3836*103e46e4SHarish Mahendrakar bool Segment::MakeNewCluster(uint64_t frame_timestamp_ns) {
3837*103e46e4SHarish Mahendrakar   const int32_t new_size = cluster_list_size_ + 1;
3838*103e46e4SHarish Mahendrakar 
3839*103e46e4SHarish Mahendrakar   if (new_size > cluster_list_capacity_) {
3840*103e46e4SHarish Mahendrakar     // Add more clusters.
3841*103e46e4SHarish Mahendrakar     const int32_t new_capacity =
3842*103e46e4SHarish Mahendrakar         (cluster_list_capacity_ <= 0) ? 1 : cluster_list_capacity_ * 2;
3843*103e46e4SHarish Mahendrakar     Cluster** const clusters =
3844*103e46e4SHarish Mahendrakar         new (std::nothrow) Cluster*[new_capacity];  // NOLINT
3845*103e46e4SHarish Mahendrakar     if (!clusters)
3846*103e46e4SHarish Mahendrakar       return false;
3847*103e46e4SHarish Mahendrakar 
3848*103e46e4SHarish Mahendrakar     for (int32_t i = 0; i < cluster_list_size_; ++i) {
3849*103e46e4SHarish Mahendrakar       clusters[i] = cluster_list_[i];
3850*103e46e4SHarish Mahendrakar     }
3851*103e46e4SHarish Mahendrakar 
3852*103e46e4SHarish Mahendrakar     delete[] cluster_list_;
3853*103e46e4SHarish Mahendrakar 
3854*103e46e4SHarish Mahendrakar     cluster_list_ = clusters;
3855*103e46e4SHarish Mahendrakar     cluster_list_capacity_ = new_capacity;
3856*103e46e4SHarish Mahendrakar   }
3857*103e46e4SHarish Mahendrakar 
3858*103e46e4SHarish Mahendrakar   if (!WriteFramesLessThan(frame_timestamp_ns))
3859*103e46e4SHarish Mahendrakar     return false;
3860*103e46e4SHarish Mahendrakar 
3861*103e46e4SHarish Mahendrakar   if (cluster_list_size_ > 0) {
3862*103e46e4SHarish Mahendrakar     // Update old cluster's size
3863*103e46e4SHarish Mahendrakar     Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
3864*103e46e4SHarish Mahendrakar 
3865*103e46e4SHarish Mahendrakar     if (!old_cluster || !old_cluster->Finalize(true, frame_timestamp_ns))
3866*103e46e4SHarish Mahendrakar       return false;
3867*103e46e4SHarish Mahendrakar   }
3868*103e46e4SHarish Mahendrakar 
3869*103e46e4SHarish Mahendrakar   if (output_cues_)
3870*103e46e4SHarish Mahendrakar     new_cuepoint_ = true;
3871*103e46e4SHarish Mahendrakar 
3872*103e46e4SHarish Mahendrakar   if (chunking_ && cluster_list_size_ > 0) {
3873*103e46e4SHarish Mahendrakar     chunk_writer_cluster_->Close();
3874*103e46e4SHarish Mahendrakar     chunk_count_++;
3875*103e46e4SHarish Mahendrakar 
3876*103e46e4SHarish Mahendrakar     if (!UpdateChunkName("chk", &chunk_name_))
3877*103e46e4SHarish Mahendrakar       return false;
3878*103e46e4SHarish Mahendrakar     if (!chunk_writer_cluster_->Open(chunk_name_))
3879*103e46e4SHarish Mahendrakar       return false;
3880*103e46e4SHarish Mahendrakar   }
3881*103e46e4SHarish Mahendrakar 
3882*103e46e4SHarish Mahendrakar   const uint64_t timecode_scale = segment_info_.timecode_scale();
3883*103e46e4SHarish Mahendrakar   const uint64_t frame_timecode = frame_timestamp_ns / timecode_scale;
3884*103e46e4SHarish Mahendrakar 
3885*103e46e4SHarish Mahendrakar   uint64_t cluster_timecode = frame_timecode;
3886*103e46e4SHarish Mahendrakar 
3887*103e46e4SHarish Mahendrakar   if (frames_size_ > 0) {
3888*103e46e4SHarish Mahendrakar     const Frame* const f = frames_[0];  // earliest queued frame
3889*103e46e4SHarish Mahendrakar     const uint64_t ns = f->timestamp();
3890*103e46e4SHarish Mahendrakar     const uint64_t tc = ns / timecode_scale;
3891*103e46e4SHarish Mahendrakar 
3892*103e46e4SHarish Mahendrakar     if (tc < cluster_timecode)
3893*103e46e4SHarish Mahendrakar       cluster_timecode = tc;
3894*103e46e4SHarish Mahendrakar   }
3895*103e46e4SHarish Mahendrakar 
3896*103e46e4SHarish Mahendrakar   Cluster*& cluster = cluster_list_[cluster_list_size_];
3897*103e46e4SHarish Mahendrakar   const int64_t offset = MaxOffset();
3898*103e46e4SHarish Mahendrakar   cluster = new (std::nothrow)
3899*103e46e4SHarish Mahendrakar       Cluster(cluster_timecode, offset, segment_info_.timecode_scale(),
3900*103e46e4SHarish Mahendrakar               accurate_cluster_duration_, fixed_size_cluster_timecode_);
3901*103e46e4SHarish Mahendrakar   if (!cluster)
3902*103e46e4SHarish Mahendrakar     return false;
3903*103e46e4SHarish Mahendrakar 
3904*103e46e4SHarish Mahendrakar   if (!cluster->Init(writer_cluster_))
3905*103e46e4SHarish Mahendrakar     return false;
3906*103e46e4SHarish Mahendrakar 
3907*103e46e4SHarish Mahendrakar   cluster_list_size_ = new_size;
3908*103e46e4SHarish Mahendrakar   return true;
3909*103e46e4SHarish Mahendrakar }
3910*103e46e4SHarish Mahendrakar 
DoNewClusterProcessing(uint64_t track_number,uint64_t frame_timestamp_ns,bool is_key)3911*103e46e4SHarish Mahendrakar bool Segment::DoNewClusterProcessing(uint64_t track_number,
3912*103e46e4SHarish Mahendrakar                                      uint64_t frame_timestamp_ns, bool is_key) {
3913*103e46e4SHarish Mahendrakar   for (;;) {
3914*103e46e4SHarish Mahendrakar     // Based on the characteristics of the current frame and current
3915*103e46e4SHarish Mahendrakar     // cluster, decide whether to create a new cluster.
3916*103e46e4SHarish Mahendrakar     const int result = TestFrame(track_number, frame_timestamp_ns, is_key);
3917*103e46e4SHarish Mahendrakar     if (result < 0)  // error
3918*103e46e4SHarish Mahendrakar       return false;
3919*103e46e4SHarish Mahendrakar 
3920*103e46e4SHarish Mahendrakar     // Always set force_new_cluster_ to false after TestFrame.
3921*103e46e4SHarish Mahendrakar     force_new_cluster_ = false;
3922*103e46e4SHarish Mahendrakar 
3923*103e46e4SHarish Mahendrakar     // A non-zero result means create a new cluster.
3924*103e46e4SHarish Mahendrakar     if (result > 0 && !MakeNewCluster(frame_timestamp_ns))
3925*103e46e4SHarish Mahendrakar       return false;
3926*103e46e4SHarish Mahendrakar 
3927*103e46e4SHarish Mahendrakar     // Write queued (audio) frames.
3928*103e46e4SHarish Mahendrakar     const int frame_count = WriteFramesAll();
3929*103e46e4SHarish Mahendrakar     if (frame_count < 0)  // error
3930*103e46e4SHarish Mahendrakar       return false;
3931*103e46e4SHarish Mahendrakar 
3932*103e46e4SHarish Mahendrakar     // Write the current frame to the current cluster (if TestFrame
3933*103e46e4SHarish Mahendrakar     // returns 0) or to a newly created cluster (TestFrame returns 1).
3934*103e46e4SHarish Mahendrakar     if (result <= 1)
3935*103e46e4SHarish Mahendrakar       return true;
3936*103e46e4SHarish Mahendrakar 
3937*103e46e4SHarish Mahendrakar     // TestFrame returned 2, which means there was a large time
3938*103e46e4SHarish Mahendrakar     // difference between the cluster and the frame itself.  Do the
3939*103e46e4SHarish Mahendrakar     // test again, comparing the frame to the new cluster.
3940*103e46e4SHarish Mahendrakar   }
3941*103e46e4SHarish Mahendrakar }
3942*103e46e4SHarish Mahendrakar 
CheckHeaderInfo()3943*103e46e4SHarish Mahendrakar bool Segment::CheckHeaderInfo() {
3944*103e46e4SHarish Mahendrakar   if (!header_written_) {
3945*103e46e4SHarish Mahendrakar     if (!WriteSegmentHeader())
3946*103e46e4SHarish Mahendrakar       return false;
3947*103e46e4SHarish Mahendrakar 
3948*103e46e4SHarish Mahendrakar     if (!seek_head_.AddSeekEntry(libwebm::kMkvCluster, MaxOffset()))
3949*103e46e4SHarish Mahendrakar       return false;
3950*103e46e4SHarish Mahendrakar 
3951*103e46e4SHarish Mahendrakar     if (output_cues_ && cues_track_ == 0) {
3952*103e46e4SHarish Mahendrakar       // Check for a video track
3953*103e46e4SHarish Mahendrakar       for (uint32_t i = 0; i < tracks_.track_entries_size(); ++i) {
3954*103e46e4SHarish Mahendrakar         const Track* const track = tracks_.GetTrackByIndex(i);
3955*103e46e4SHarish Mahendrakar         if (!track)
3956*103e46e4SHarish Mahendrakar           return false;
3957*103e46e4SHarish Mahendrakar 
3958*103e46e4SHarish Mahendrakar         if (tracks_.TrackIsVideo(track->number())) {
3959*103e46e4SHarish Mahendrakar           cues_track_ = track->number();
3960*103e46e4SHarish Mahendrakar           break;
3961*103e46e4SHarish Mahendrakar         }
3962*103e46e4SHarish Mahendrakar       }
3963*103e46e4SHarish Mahendrakar 
3964*103e46e4SHarish Mahendrakar       // Set first track found
3965*103e46e4SHarish Mahendrakar       if (cues_track_ == 0) {
3966*103e46e4SHarish Mahendrakar         const Track* const track = tracks_.GetTrackByIndex(0);
3967*103e46e4SHarish Mahendrakar         if (!track)
3968*103e46e4SHarish Mahendrakar           return false;
3969*103e46e4SHarish Mahendrakar 
3970*103e46e4SHarish Mahendrakar         cues_track_ = track->number();
3971*103e46e4SHarish Mahendrakar       }
3972*103e46e4SHarish Mahendrakar     }
3973*103e46e4SHarish Mahendrakar   }
3974*103e46e4SHarish Mahendrakar   return true;
3975*103e46e4SHarish Mahendrakar }
3976*103e46e4SHarish Mahendrakar 
UpdateDocTypeVersion()3977*103e46e4SHarish Mahendrakar void Segment::UpdateDocTypeVersion() {
3978*103e46e4SHarish Mahendrakar   for (uint32_t index = 0; index < tracks_.track_entries_size(); ++index) {
3979*103e46e4SHarish Mahendrakar     const Track* track = tracks_.GetTrackByIndex(index);
3980*103e46e4SHarish Mahendrakar     if (track == NULL)
3981*103e46e4SHarish Mahendrakar       break;
3982*103e46e4SHarish Mahendrakar     if ((track->codec_delay() || track->seek_pre_roll()) &&
3983*103e46e4SHarish Mahendrakar         doc_type_version_ < 4) {
3984*103e46e4SHarish Mahendrakar       doc_type_version_ = 4;
3985*103e46e4SHarish Mahendrakar       break;
3986*103e46e4SHarish Mahendrakar     }
3987*103e46e4SHarish Mahendrakar   }
3988*103e46e4SHarish Mahendrakar }
3989*103e46e4SHarish Mahendrakar 
UpdateChunkName(const char * ext,char ** name) const3990*103e46e4SHarish Mahendrakar bool Segment::UpdateChunkName(const char* ext, char** name) const {
3991*103e46e4SHarish Mahendrakar   if (!name || !ext)
3992*103e46e4SHarish Mahendrakar     return false;
3993*103e46e4SHarish Mahendrakar 
3994*103e46e4SHarish Mahendrakar   char ext_chk[64];
3995*103e46e4SHarish Mahendrakar #ifdef _MSC_VER
3996*103e46e4SHarish Mahendrakar   sprintf_s(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
3997*103e46e4SHarish Mahendrakar #else
3998*103e46e4SHarish Mahendrakar   snprintf(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
3999*103e46e4SHarish Mahendrakar #endif
4000*103e46e4SHarish Mahendrakar 
4001*103e46e4SHarish Mahendrakar   const size_t chunking_base_name_length = strlen(chunking_base_name_);
4002*103e46e4SHarish Mahendrakar   const size_t ext_chk_length = strlen(ext_chk);
4003*103e46e4SHarish Mahendrakar   const size_t length = chunking_base_name_length + ext_chk_length + 1;
4004*103e46e4SHarish Mahendrakar   char* const str = new (std::nothrow) char[length];  // NOLINT
4005*103e46e4SHarish Mahendrakar   if (!str)
4006*103e46e4SHarish Mahendrakar     return false;
4007*103e46e4SHarish Mahendrakar 
4008*103e46e4SHarish Mahendrakar   memcpy(str, chunking_base_name_, chunking_base_name_length);
4009*103e46e4SHarish Mahendrakar   memcpy(&str[chunking_base_name_length], ext_chk, ext_chk_length);
4010*103e46e4SHarish Mahendrakar   str[chunking_base_name_length + ext_chk_length] = '\0';
4011*103e46e4SHarish Mahendrakar 
4012*103e46e4SHarish Mahendrakar   delete[] * name;
4013*103e46e4SHarish Mahendrakar   *name = str;
4014*103e46e4SHarish Mahendrakar 
4015*103e46e4SHarish Mahendrakar   return true;
4016*103e46e4SHarish Mahendrakar }
4017*103e46e4SHarish Mahendrakar 
MaxOffset()4018*103e46e4SHarish Mahendrakar int64_t Segment::MaxOffset() {
4019*103e46e4SHarish Mahendrakar   if (!writer_header_)
4020*103e46e4SHarish Mahendrakar     return -1;
4021*103e46e4SHarish Mahendrakar 
4022*103e46e4SHarish Mahendrakar   int64_t offset = writer_header_->Position() - payload_pos_;
4023*103e46e4SHarish Mahendrakar 
4024*103e46e4SHarish Mahendrakar   if (chunking_) {
4025*103e46e4SHarish Mahendrakar     for (int32_t i = 0; i < cluster_list_size_; ++i) {
4026*103e46e4SHarish Mahendrakar       Cluster* const cluster = cluster_list_[i];
4027*103e46e4SHarish Mahendrakar       offset += cluster->Size();
4028*103e46e4SHarish Mahendrakar     }
4029*103e46e4SHarish Mahendrakar 
4030*103e46e4SHarish Mahendrakar     if (writer_cues_)
4031*103e46e4SHarish Mahendrakar       offset += writer_cues_->Position();
4032*103e46e4SHarish Mahendrakar   }
4033*103e46e4SHarish Mahendrakar 
4034*103e46e4SHarish Mahendrakar   return offset;
4035*103e46e4SHarish Mahendrakar }
4036*103e46e4SHarish Mahendrakar 
QueueFrame(Frame * frame)4037*103e46e4SHarish Mahendrakar bool Segment::QueueFrame(Frame* frame) {
4038*103e46e4SHarish Mahendrakar   const int32_t new_size = frames_size_ + 1;
4039*103e46e4SHarish Mahendrakar 
4040*103e46e4SHarish Mahendrakar   if (new_size > frames_capacity_) {
4041*103e46e4SHarish Mahendrakar     // Add more frames.
4042*103e46e4SHarish Mahendrakar     const int32_t new_capacity = (!frames_capacity_) ? 2 : frames_capacity_ * 2;
4043*103e46e4SHarish Mahendrakar 
4044*103e46e4SHarish Mahendrakar     if (new_capacity < 1)
4045*103e46e4SHarish Mahendrakar       return false;
4046*103e46e4SHarish Mahendrakar 
4047*103e46e4SHarish Mahendrakar     Frame** const frames = new (std::nothrow) Frame*[new_capacity];  // NOLINT
4048*103e46e4SHarish Mahendrakar     if (!frames)
4049*103e46e4SHarish Mahendrakar       return false;
4050*103e46e4SHarish Mahendrakar 
4051*103e46e4SHarish Mahendrakar     for (int32_t i = 0; i < frames_size_; ++i) {
4052*103e46e4SHarish Mahendrakar       frames[i] = frames_[i];
4053*103e46e4SHarish Mahendrakar     }
4054*103e46e4SHarish Mahendrakar 
4055*103e46e4SHarish Mahendrakar     delete[] frames_;
4056*103e46e4SHarish Mahendrakar     frames_ = frames;
4057*103e46e4SHarish Mahendrakar     frames_capacity_ = new_capacity;
4058*103e46e4SHarish Mahendrakar   }
4059*103e46e4SHarish Mahendrakar 
4060*103e46e4SHarish Mahendrakar   frames_[frames_size_++] = frame;
4061*103e46e4SHarish Mahendrakar 
4062*103e46e4SHarish Mahendrakar   return true;
4063*103e46e4SHarish Mahendrakar }
4064*103e46e4SHarish Mahendrakar 
WriteFramesAll()4065*103e46e4SHarish Mahendrakar int Segment::WriteFramesAll() {
4066*103e46e4SHarish Mahendrakar   if (frames_ == NULL)
4067*103e46e4SHarish Mahendrakar     return 0;
4068*103e46e4SHarish Mahendrakar 
4069*103e46e4SHarish Mahendrakar   if (cluster_list_size_ < 1)
4070*103e46e4SHarish Mahendrakar     return -1;
4071*103e46e4SHarish Mahendrakar 
4072*103e46e4SHarish Mahendrakar   Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
4073*103e46e4SHarish Mahendrakar 
4074*103e46e4SHarish Mahendrakar   if (!cluster)
4075*103e46e4SHarish Mahendrakar     return -1;
4076*103e46e4SHarish Mahendrakar 
4077*103e46e4SHarish Mahendrakar   for (int32_t i = 0; i < frames_size_; ++i) {
4078*103e46e4SHarish Mahendrakar     Frame*& frame = frames_[i];
4079*103e46e4SHarish Mahendrakar     // TODO(jzern/vigneshv): using Segment::AddGenericFrame here would limit the
4080*103e46e4SHarish Mahendrakar     // places where |doc_type_version_| needs to be updated.
4081*103e46e4SHarish Mahendrakar     if (frame->discard_padding() != 0)
4082*103e46e4SHarish Mahendrakar       doc_type_version_ = 4;
4083*103e46e4SHarish Mahendrakar     if (!cluster->AddFrame(frame)) {
4084*103e46e4SHarish Mahendrakar       delete frame;
4085*103e46e4SHarish Mahendrakar       continue;
4086*103e46e4SHarish Mahendrakar     }
4087*103e46e4SHarish Mahendrakar 
4088*103e46e4SHarish Mahendrakar     if (new_cuepoint_ && cues_track_ == frame->track_number()) {
4089*103e46e4SHarish Mahendrakar       if (!AddCuePoint(frame->timestamp(), cues_track_)) {
4090*103e46e4SHarish Mahendrakar         delete frame;
4091*103e46e4SHarish Mahendrakar         continue;
4092*103e46e4SHarish Mahendrakar       }
4093*103e46e4SHarish Mahendrakar     }
4094*103e46e4SHarish Mahendrakar 
4095*103e46e4SHarish Mahendrakar     if (frame->timestamp() > last_timestamp_) {
4096*103e46e4SHarish Mahendrakar       last_timestamp_ = frame->timestamp();
4097*103e46e4SHarish Mahendrakar       last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
4098*103e46e4SHarish Mahendrakar     }
4099*103e46e4SHarish Mahendrakar 
4100*103e46e4SHarish Mahendrakar     delete frame;
4101*103e46e4SHarish Mahendrakar     frame = NULL;
4102*103e46e4SHarish Mahendrakar   }
4103*103e46e4SHarish Mahendrakar 
4104*103e46e4SHarish Mahendrakar   const int result = frames_size_;
4105*103e46e4SHarish Mahendrakar   frames_size_ = 0;
4106*103e46e4SHarish Mahendrakar 
4107*103e46e4SHarish Mahendrakar   return result;
4108*103e46e4SHarish Mahendrakar }
4109*103e46e4SHarish Mahendrakar 
WriteFramesLessThan(uint64_t timestamp)4110*103e46e4SHarish Mahendrakar bool Segment::WriteFramesLessThan(uint64_t timestamp) {
4111*103e46e4SHarish Mahendrakar   // Check |cluster_list_size_| to see if this is the first cluster. If it is
4112*103e46e4SHarish Mahendrakar   // the first cluster the audio frames that are less than the first video
4113*103e46e4SHarish Mahendrakar   // timesatmp will be written in a later step.
4114*103e46e4SHarish Mahendrakar   if (frames_size_ > 0 && cluster_list_size_ > 0) {
4115*103e46e4SHarish Mahendrakar     if (!frames_)
4116*103e46e4SHarish Mahendrakar       return false;
4117*103e46e4SHarish Mahendrakar 
4118*103e46e4SHarish Mahendrakar     Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
4119*103e46e4SHarish Mahendrakar     if (!cluster)
4120*103e46e4SHarish Mahendrakar       return false;
4121*103e46e4SHarish Mahendrakar 
4122*103e46e4SHarish Mahendrakar     int32_t shift_left = 0;
4123*103e46e4SHarish Mahendrakar 
4124*103e46e4SHarish Mahendrakar     // TODO(fgalligan): Change this to use the durations of frames instead of
4125*103e46e4SHarish Mahendrakar     // the next frame's start time if the duration is accurate.
4126*103e46e4SHarish Mahendrakar     for (int32_t i = 1; i < frames_size_; ++i) {
4127*103e46e4SHarish Mahendrakar       const Frame* const frame_curr = frames_[i];
4128*103e46e4SHarish Mahendrakar 
4129*103e46e4SHarish Mahendrakar       if (frame_curr->timestamp() > timestamp)
4130*103e46e4SHarish Mahendrakar         break;
4131*103e46e4SHarish Mahendrakar 
4132*103e46e4SHarish Mahendrakar       const Frame* const frame_prev = frames_[i - 1];
4133*103e46e4SHarish Mahendrakar       if (frame_prev->discard_padding() != 0)
4134*103e46e4SHarish Mahendrakar         doc_type_version_ = 4;
4135*103e46e4SHarish Mahendrakar       if (!cluster->AddFrame(frame_prev)) {
4136*103e46e4SHarish Mahendrakar         delete frame_prev;
4137*103e46e4SHarish Mahendrakar         continue;
4138*103e46e4SHarish Mahendrakar       }
4139*103e46e4SHarish Mahendrakar 
4140*103e46e4SHarish Mahendrakar       if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) {
4141*103e46e4SHarish Mahendrakar         if (!AddCuePoint(frame_prev->timestamp(), cues_track_)) {
4142*103e46e4SHarish Mahendrakar           delete frame_prev;
4143*103e46e4SHarish Mahendrakar           continue;
4144*103e46e4SHarish Mahendrakar         }
4145*103e46e4SHarish Mahendrakar       }
4146*103e46e4SHarish Mahendrakar 
4147*103e46e4SHarish Mahendrakar       ++shift_left;
4148*103e46e4SHarish Mahendrakar       if (frame_prev->timestamp() > last_timestamp_) {
4149*103e46e4SHarish Mahendrakar         last_timestamp_ = frame_prev->timestamp();
4150*103e46e4SHarish Mahendrakar         last_track_timestamp_[frame_prev->track_number() - 1] =
4151*103e46e4SHarish Mahendrakar             frame_prev->timestamp();
4152*103e46e4SHarish Mahendrakar       }
4153*103e46e4SHarish Mahendrakar 
4154*103e46e4SHarish Mahendrakar       delete frame_prev;
4155*103e46e4SHarish Mahendrakar     }
4156*103e46e4SHarish Mahendrakar 
4157*103e46e4SHarish Mahendrakar     if (shift_left > 0) {
4158*103e46e4SHarish Mahendrakar       if (shift_left >= frames_size_)
4159*103e46e4SHarish Mahendrakar         return false;
4160*103e46e4SHarish Mahendrakar 
4161*103e46e4SHarish Mahendrakar       const int32_t new_frames_size = frames_size_ - shift_left;
4162*103e46e4SHarish Mahendrakar       for (int32_t i = 0; i < new_frames_size; ++i) {
4163*103e46e4SHarish Mahendrakar         frames_[i] = frames_[i + shift_left];
4164*103e46e4SHarish Mahendrakar       }
4165*103e46e4SHarish Mahendrakar 
4166*103e46e4SHarish Mahendrakar       frames_size_ = new_frames_size;
4167*103e46e4SHarish Mahendrakar     }
4168*103e46e4SHarish Mahendrakar   }
4169*103e46e4SHarish Mahendrakar 
4170*103e46e4SHarish Mahendrakar   return true;
4171*103e46e4SHarish Mahendrakar }
4172*103e46e4SHarish Mahendrakar 
DocTypeIsWebm() const4173*103e46e4SHarish Mahendrakar bool Segment::DocTypeIsWebm() const {
4174*103e46e4SHarish Mahendrakar   const int kNumCodecIds = 9;
4175*103e46e4SHarish Mahendrakar 
4176*103e46e4SHarish Mahendrakar   // TODO(vigneshv): Tweak .clang-format.
4177*103e46e4SHarish Mahendrakar   const char* kWebmCodecIds[kNumCodecIds] = {
4178*103e46e4SHarish Mahendrakar       Tracks::kOpusCodecId,          Tracks::kVorbisCodecId,
4179*103e46e4SHarish Mahendrakar       Tracks::kAv1CodecId,           Tracks::kVp8CodecId,
4180*103e46e4SHarish Mahendrakar       Tracks::kVp9CodecId,           Tracks::kWebVttCaptionsId,
4181*103e46e4SHarish Mahendrakar       Tracks::kWebVttDescriptionsId, Tracks::kWebVttMetadataId,
4182*103e46e4SHarish Mahendrakar       Tracks::kWebVttSubtitlesId};
4183*103e46e4SHarish Mahendrakar 
4184*103e46e4SHarish Mahendrakar   const int num_tracks = static_cast<int>(tracks_.track_entries_size());
4185*103e46e4SHarish Mahendrakar   for (int track_index = 0; track_index < num_tracks; ++track_index) {
4186*103e46e4SHarish Mahendrakar     const Track* const track = tracks_.GetTrackByIndex(track_index);
4187*103e46e4SHarish Mahendrakar     const std::string codec_id = track->codec_id();
4188*103e46e4SHarish Mahendrakar 
4189*103e46e4SHarish Mahendrakar     bool id_is_webm = false;
4190*103e46e4SHarish Mahendrakar     for (int id_index = 0; id_index < kNumCodecIds; ++id_index) {
4191*103e46e4SHarish Mahendrakar       if (codec_id == kWebmCodecIds[id_index]) {
4192*103e46e4SHarish Mahendrakar         id_is_webm = true;
4193*103e46e4SHarish Mahendrakar         break;
4194*103e46e4SHarish Mahendrakar       }
4195*103e46e4SHarish Mahendrakar     }
4196*103e46e4SHarish Mahendrakar 
4197*103e46e4SHarish Mahendrakar     if (!id_is_webm)
4198*103e46e4SHarish Mahendrakar       return false;
4199*103e46e4SHarish Mahendrakar   }
4200*103e46e4SHarish Mahendrakar 
4201*103e46e4SHarish Mahendrakar   return true;
4202*103e46e4SHarish Mahendrakar }
4203*103e46e4SHarish Mahendrakar 
4204*103e46e4SHarish Mahendrakar }  // namespace mkvmuxer
4205