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