1*103e46e4SHarish Mahendrakar // Copyright (c) 2012 The WebM project authors. All Rights Reserved.
2*103e46e4SHarish Mahendrakar //
3*103e46e4SHarish Mahendrakar // Use of this source code is governed by a BSD-style license
4*103e46e4SHarish Mahendrakar // that can be found in the LICENSE file in the root of the source
5*103e46e4SHarish Mahendrakar // tree. An additional intellectual property rights grant can be found
6*103e46e4SHarish Mahendrakar // in the file PATENTS. All contributing project authors may
7*103e46e4SHarish Mahendrakar // be found in the AUTHORS file in the root of the source tree.
8*103e46e4SHarish Mahendrakar //
9*103e46e4SHarish Mahendrakar // This sample application demonstrates how to use the matroska parser
10*103e46e4SHarish Mahendrakar // library, which allows clients to handle a matroska format file.
11*103e46e4SHarish Mahendrakar
12*103e46e4SHarish Mahendrakar #include "sample_muxer_metadata.h"
13*103e46e4SHarish Mahendrakar
14*103e46e4SHarish Mahendrakar #include <cstdio>
15*103e46e4SHarish Mahendrakar #include <string>
16*103e46e4SHarish Mahendrakar
17*103e46e4SHarish Mahendrakar #include "mkvmuxer/mkvmuxer.h"
18*103e46e4SHarish Mahendrakar #include "webvtt/vttreader.h"
19*103e46e4SHarish Mahendrakar
SampleMuxerMetadata()20*103e46e4SHarish Mahendrakar SampleMuxerMetadata::SampleMuxerMetadata() : segment_(NULL) {}
21*103e46e4SHarish Mahendrakar
Init(mkvmuxer::Segment * segment)22*103e46e4SHarish Mahendrakar bool SampleMuxerMetadata::Init(mkvmuxer::Segment* segment) {
23*103e46e4SHarish Mahendrakar if (segment == NULL || segment_ != NULL)
24*103e46e4SHarish Mahendrakar return false;
25*103e46e4SHarish Mahendrakar
26*103e46e4SHarish Mahendrakar segment_ = segment;
27*103e46e4SHarish Mahendrakar return true;
28*103e46e4SHarish Mahendrakar }
29*103e46e4SHarish Mahendrakar
Load(const char * file,Kind kind)30*103e46e4SHarish Mahendrakar bool SampleMuxerMetadata::Load(const char* file, Kind kind) {
31*103e46e4SHarish Mahendrakar if (kind == kChapters)
32*103e46e4SHarish Mahendrakar return LoadChapters(file);
33*103e46e4SHarish Mahendrakar
34*103e46e4SHarish Mahendrakar uint64_t track_num;
35*103e46e4SHarish Mahendrakar
36*103e46e4SHarish Mahendrakar if (!AddTrack(kind, &track_num)) {
37*103e46e4SHarish Mahendrakar printf("Unable to add track for WebVTT file \"%s\"\n", file);
38*103e46e4SHarish Mahendrakar return false;
39*103e46e4SHarish Mahendrakar }
40*103e46e4SHarish Mahendrakar
41*103e46e4SHarish Mahendrakar return Parse(file, kind, track_num);
42*103e46e4SHarish Mahendrakar }
43*103e46e4SHarish Mahendrakar
AddChapters()44*103e46e4SHarish Mahendrakar bool SampleMuxerMetadata::AddChapters() {
45*103e46e4SHarish Mahendrakar typedef cue_list_t::const_iterator iter_t;
46*103e46e4SHarish Mahendrakar iter_t i = chapter_cues_.begin();
47*103e46e4SHarish Mahendrakar const iter_t j = chapter_cues_.end();
48*103e46e4SHarish Mahendrakar
49*103e46e4SHarish Mahendrakar while (i != j) {
50*103e46e4SHarish Mahendrakar const cue_t& chapter = *i++;
51*103e46e4SHarish Mahendrakar
52*103e46e4SHarish Mahendrakar if (!AddChapter(chapter))
53*103e46e4SHarish Mahendrakar return false;
54*103e46e4SHarish Mahendrakar }
55*103e46e4SHarish Mahendrakar
56*103e46e4SHarish Mahendrakar return true;
57*103e46e4SHarish Mahendrakar }
58*103e46e4SHarish Mahendrakar
Write(int64_t time_ns)59*103e46e4SHarish Mahendrakar bool SampleMuxerMetadata::Write(int64_t time_ns) {
60*103e46e4SHarish Mahendrakar typedef cues_set_t::iterator iter_t;
61*103e46e4SHarish Mahendrakar
62*103e46e4SHarish Mahendrakar iter_t i = cues_set_.begin();
63*103e46e4SHarish Mahendrakar const iter_t j = cues_set_.end();
64*103e46e4SHarish Mahendrakar
65*103e46e4SHarish Mahendrakar while (i != j) {
66*103e46e4SHarish Mahendrakar const cues_set_t::value_type& v = *i;
67*103e46e4SHarish Mahendrakar
68*103e46e4SHarish Mahendrakar if (time_ns >= 0 && v > time_ns)
69*103e46e4SHarish Mahendrakar return true; // nothing else to do just yet
70*103e46e4SHarish Mahendrakar
71*103e46e4SHarish Mahendrakar if (!v.Write(segment_)) {
72*103e46e4SHarish Mahendrakar printf("\nCould not add metadata.\n");
73*103e46e4SHarish Mahendrakar return false; // error
74*103e46e4SHarish Mahendrakar }
75*103e46e4SHarish Mahendrakar
76*103e46e4SHarish Mahendrakar cues_set_.erase(i++);
77*103e46e4SHarish Mahendrakar }
78*103e46e4SHarish Mahendrakar
79*103e46e4SHarish Mahendrakar return true;
80*103e46e4SHarish Mahendrakar }
81*103e46e4SHarish Mahendrakar
LoadChapters(const char * file)82*103e46e4SHarish Mahendrakar bool SampleMuxerMetadata::LoadChapters(const char* file) {
83*103e46e4SHarish Mahendrakar if (!chapter_cues_.empty()) {
84*103e46e4SHarish Mahendrakar printf("Support for more than one chapters file is not yet implemented\n");
85*103e46e4SHarish Mahendrakar return false;
86*103e46e4SHarish Mahendrakar }
87*103e46e4SHarish Mahendrakar
88*103e46e4SHarish Mahendrakar cue_list_t cues;
89*103e46e4SHarish Mahendrakar
90*103e46e4SHarish Mahendrakar if (!ParseChapters(file, &cues))
91*103e46e4SHarish Mahendrakar return false;
92*103e46e4SHarish Mahendrakar
93*103e46e4SHarish Mahendrakar // TODO(matthewjheaney): support more than one chapters file
94*103e46e4SHarish Mahendrakar chapter_cues_.swap(cues);
95*103e46e4SHarish Mahendrakar
96*103e46e4SHarish Mahendrakar return true;
97*103e46e4SHarish Mahendrakar }
98*103e46e4SHarish Mahendrakar
ParseChapters(const char * file,cue_list_t * cues_ptr)99*103e46e4SHarish Mahendrakar bool SampleMuxerMetadata::ParseChapters(const char* file,
100*103e46e4SHarish Mahendrakar cue_list_t* cues_ptr) {
101*103e46e4SHarish Mahendrakar cue_list_t& cues = *cues_ptr;
102*103e46e4SHarish Mahendrakar cues.clear();
103*103e46e4SHarish Mahendrakar
104*103e46e4SHarish Mahendrakar libwebvtt::VttReader r;
105*103e46e4SHarish Mahendrakar int e = r.Open(file);
106*103e46e4SHarish Mahendrakar
107*103e46e4SHarish Mahendrakar if (e) {
108*103e46e4SHarish Mahendrakar printf("Unable to open WebVTT file: \"%s\"\n", file);
109*103e46e4SHarish Mahendrakar return false;
110*103e46e4SHarish Mahendrakar }
111*103e46e4SHarish Mahendrakar
112*103e46e4SHarish Mahendrakar libwebvtt::Parser p(&r);
113*103e46e4SHarish Mahendrakar e = p.Init();
114*103e46e4SHarish Mahendrakar
115*103e46e4SHarish Mahendrakar if (e < 0) { // error
116*103e46e4SHarish Mahendrakar printf("Error parsing WebVTT file: \"%s\"\n", file);
117*103e46e4SHarish Mahendrakar return false;
118*103e46e4SHarish Mahendrakar }
119*103e46e4SHarish Mahendrakar
120*103e46e4SHarish Mahendrakar libwebvtt::Time t;
121*103e46e4SHarish Mahendrakar t.hours = -1;
122*103e46e4SHarish Mahendrakar
123*103e46e4SHarish Mahendrakar for (;;) {
124*103e46e4SHarish Mahendrakar cue_t c;
125*103e46e4SHarish Mahendrakar e = p.Parse(&c);
126*103e46e4SHarish Mahendrakar
127*103e46e4SHarish Mahendrakar if (e < 0) { // error
128*103e46e4SHarish Mahendrakar printf("Error parsing WebVTT file: \"%s\"\n", file);
129*103e46e4SHarish Mahendrakar return false;
130*103e46e4SHarish Mahendrakar }
131*103e46e4SHarish Mahendrakar
132*103e46e4SHarish Mahendrakar if (e > 0) // EOF
133*103e46e4SHarish Mahendrakar return true;
134*103e46e4SHarish Mahendrakar
135*103e46e4SHarish Mahendrakar if (c.start_time < t) {
136*103e46e4SHarish Mahendrakar printf("bad WebVTT cue timestamp (out-of-order)\n");
137*103e46e4SHarish Mahendrakar return false;
138*103e46e4SHarish Mahendrakar }
139*103e46e4SHarish Mahendrakar
140*103e46e4SHarish Mahendrakar if (c.stop_time < c.start_time) {
141*103e46e4SHarish Mahendrakar printf("bad WebVTT cue timestamp (stop < start)\n");
142*103e46e4SHarish Mahendrakar return false;
143*103e46e4SHarish Mahendrakar }
144*103e46e4SHarish Mahendrakar
145*103e46e4SHarish Mahendrakar t = c.start_time;
146*103e46e4SHarish Mahendrakar cues.push_back(c);
147*103e46e4SHarish Mahendrakar }
148*103e46e4SHarish Mahendrakar }
149*103e46e4SHarish Mahendrakar
AddChapter(const cue_t & cue)150*103e46e4SHarish Mahendrakar bool SampleMuxerMetadata::AddChapter(const cue_t& cue) {
151*103e46e4SHarish Mahendrakar // TODO(matthewjheaney): support language and country
152*103e46e4SHarish Mahendrakar
153*103e46e4SHarish Mahendrakar mkvmuxer::Chapter* const chapter = segment_->AddChapter();
154*103e46e4SHarish Mahendrakar
155*103e46e4SHarish Mahendrakar if (chapter == NULL) {
156*103e46e4SHarish Mahendrakar printf("Unable to add chapter\n");
157*103e46e4SHarish Mahendrakar return false;
158*103e46e4SHarish Mahendrakar }
159*103e46e4SHarish Mahendrakar
160*103e46e4SHarish Mahendrakar if (cue.identifier.empty()) {
161*103e46e4SHarish Mahendrakar chapter->set_id(NULL);
162*103e46e4SHarish Mahendrakar } else {
163*103e46e4SHarish Mahendrakar const char* const id = cue.identifier.c_str();
164*103e46e4SHarish Mahendrakar if (!chapter->set_id(id)) {
165*103e46e4SHarish Mahendrakar printf("Unable to set chapter id\n");
166*103e46e4SHarish Mahendrakar return false;
167*103e46e4SHarish Mahendrakar }
168*103e46e4SHarish Mahendrakar }
169*103e46e4SHarish Mahendrakar
170*103e46e4SHarish Mahendrakar typedef libwebvtt::presentation_t time_ms_t;
171*103e46e4SHarish Mahendrakar const time_ms_t start_time_ms = cue.start_time.presentation();
172*103e46e4SHarish Mahendrakar const time_ms_t stop_time_ms = cue.stop_time.presentation();
173*103e46e4SHarish Mahendrakar
174*103e46e4SHarish Mahendrakar enum { kNsPerMs = 1000000 };
175*103e46e4SHarish Mahendrakar const uint64_t start_time_ns = start_time_ms * kNsPerMs;
176*103e46e4SHarish Mahendrakar const uint64_t stop_time_ns = stop_time_ms * kNsPerMs;
177*103e46e4SHarish Mahendrakar
178*103e46e4SHarish Mahendrakar chapter->set_time(*segment_, start_time_ns, stop_time_ns);
179*103e46e4SHarish Mahendrakar
180*103e46e4SHarish Mahendrakar typedef libwebvtt::Cue::payload_t::const_iterator iter_t;
181*103e46e4SHarish Mahendrakar iter_t i = cue.payload.begin();
182*103e46e4SHarish Mahendrakar const iter_t j = cue.payload.end();
183*103e46e4SHarish Mahendrakar
184*103e46e4SHarish Mahendrakar std::string title;
185*103e46e4SHarish Mahendrakar
186*103e46e4SHarish Mahendrakar for (;;) {
187*103e46e4SHarish Mahendrakar title += *i++;
188*103e46e4SHarish Mahendrakar
189*103e46e4SHarish Mahendrakar if (i == j)
190*103e46e4SHarish Mahendrakar break;
191*103e46e4SHarish Mahendrakar
192*103e46e4SHarish Mahendrakar enum { kLF = '\x0A' };
193*103e46e4SHarish Mahendrakar title += kLF;
194*103e46e4SHarish Mahendrakar }
195*103e46e4SHarish Mahendrakar
196*103e46e4SHarish Mahendrakar if (!chapter->add_string(title.c_str(), NULL, NULL)) {
197*103e46e4SHarish Mahendrakar printf("Unable to set chapter title\n");
198*103e46e4SHarish Mahendrakar return false;
199*103e46e4SHarish Mahendrakar }
200*103e46e4SHarish Mahendrakar
201*103e46e4SHarish Mahendrakar return true;
202*103e46e4SHarish Mahendrakar }
203*103e46e4SHarish Mahendrakar
AddTrack(Kind kind,uint64_t * track_num)204*103e46e4SHarish Mahendrakar bool SampleMuxerMetadata::AddTrack(Kind kind, uint64_t* track_num) {
205*103e46e4SHarish Mahendrakar *track_num = 0;
206*103e46e4SHarish Mahendrakar
207*103e46e4SHarish Mahendrakar // Track number value 0 means "let muxer choose track number"
208*103e46e4SHarish Mahendrakar mkvmuxer::Track* const track = segment_->AddTrack(0);
209*103e46e4SHarish Mahendrakar
210*103e46e4SHarish Mahendrakar if (track == NULL) // error
211*103e46e4SHarish Mahendrakar return false;
212*103e46e4SHarish Mahendrakar
213*103e46e4SHarish Mahendrakar // Return the track number value chosen by the muxer
214*103e46e4SHarish Mahendrakar *track_num = track->number();
215*103e46e4SHarish Mahendrakar
216*103e46e4SHarish Mahendrakar int type;
217*103e46e4SHarish Mahendrakar const char* codec_id;
218*103e46e4SHarish Mahendrakar
219*103e46e4SHarish Mahendrakar switch (kind) {
220*103e46e4SHarish Mahendrakar case kSubtitles:
221*103e46e4SHarish Mahendrakar type = 0x11;
222*103e46e4SHarish Mahendrakar codec_id = "D_WEBVTT/SUBTITLES";
223*103e46e4SHarish Mahendrakar break;
224*103e46e4SHarish Mahendrakar
225*103e46e4SHarish Mahendrakar case kCaptions:
226*103e46e4SHarish Mahendrakar type = 0x11;
227*103e46e4SHarish Mahendrakar codec_id = "D_WEBVTT/CAPTIONS";
228*103e46e4SHarish Mahendrakar break;
229*103e46e4SHarish Mahendrakar
230*103e46e4SHarish Mahendrakar case kDescriptions:
231*103e46e4SHarish Mahendrakar type = 0x21;
232*103e46e4SHarish Mahendrakar codec_id = "D_WEBVTT/DESCRIPTIONS";
233*103e46e4SHarish Mahendrakar break;
234*103e46e4SHarish Mahendrakar
235*103e46e4SHarish Mahendrakar case kMetadata:
236*103e46e4SHarish Mahendrakar type = 0x21;
237*103e46e4SHarish Mahendrakar codec_id = "D_WEBVTT/METADATA";
238*103e46e4SHarish Mahendrakar break;
239*103e46e4SHarish Mahendrakar
240*103e46e4SHarish Mahendrakar default:
241*103e46e4SHarish Mahendrakar return false;
242*103e46e4SHarish Mahendrakar }
243*103e46e4SHarish Mahendrakar
244*103e46e4SHarish Mahendrakar track->set_type(type);
245*103e46e4SHarish Mahendrakar track->set_codec_id(codec_id);
246*103e46e4SHarish Mahendrakar
247*103e46e4SHarish Mahendrakar // TODO(matthewjheaney): set name and language
248*103e46e4SHarish Mahendrakar
249*103e46e4SHarish Mahendrakar return true;
250*103e46e4SHarish Mahendrakar }
251*103e46e4SHarish Mahendrakar
Parse(const char * file,Kind,uint64_t track_num)252*103e46e4SHarish Mahendrakar bool SampleMuxerMetadata::Parse(const char* file, Kind /* kind */,
253*103e46e4SHarish Mahendrakar uint64_t track_num) {
254*103e46e4SHarish Mahendrakar libwebvtt::VttReader r;
255*103e46e4SHarish Mahendrakar int e = r.Open(file);
256*103e46e4SHarish Mahendrakar
257*103e46e4SHarish Mahendrakar if (e) {
258*103e46e4SHarish Mahendrakar printf("Unable to open WebVTT file: \"%s\"\n", file);
259*103e46e4SHarish Mahendrakar return false;
260*103e46e4SHarish Mahendrakar }
261*103e46e4SHarish Mahendrakar
262*103e46e4SHarish Mahendrakar libwebvtt::Parser p(&r);
263*103e46e4SHarish Mahendrakar
264*103e46e4SHarish Mahendrakar e = p.Init();
265*103e46e4SHarish Mahendrakar
266*103e46e4SHarish Mahendrakar if (e < 0) { // error
267*103e46e4SHarish Mahendrakar printf("Error parsing WebVTT file: \"%s\"\n", file);
268*103e46e4SHarish Mahendrakar return false;
269*103e46e4SHarish Mahendrakar }
270*103e46e4SHarish Mahendrakar
271*103e46e4SHarish Mahendrakar SortableCue cue;
272*103e46e4SHarish Mahendrakar cue.track_num = track_num;
273*103e46e4SHarish Mahendrakar
274*103e46e4SHarish Mahendrakar libwebvtt::Time t;
275*103e46e4SHarish Mahendrakar t.hours = -1;
276*103e46e4SHarish Mahendrakar
277*103e46e4SHarish Mahendrakar for (;;) {
278*103e46e4SHarish Mahendrakar cue_t& c = cue.cue;
279*103e46e4SHarish Mahendrakar e = p.Parse(&c);
280*103e46e4SHarish Mahendrakar
281*103e46e4SHarish Mahendrakar if (e < 0) { // error
282*103e46e4SHarish Mahendrakar printf("Error parsing WebVTT file: \"%s\"\n", file);
283*103e46e4SHarish Mahendrakar return false;
284*103e46e4SHarish Mahendrakar }
285*103e46e4SHarish Mahendrakar
286*103e46e4SHarish Mahendrakar if (e > 0) // EOF
287*103e46e4SHarish Mahendrakar return true;
288*103e46e4SHarish Mahendrakar
289*103e46e4SHarish Mahendrakar if (c.start_time >= t) {
290*103e46e4SHarish Mahendrakar t = c.start_time;
291*103e46e4SHarish Mahendrakar } else {
292*103e46e4SHarish Mahendrakar printf("bad WebVTT cue timestamp (out-of-order)\n");
293*103e46e4SHarish Mahendrakar return false;
294*103e46e4SHarish Mahendrakar }
295*103e46e4SHarish Mahendrakar
296*103e46e4SHarish Mahendrakar if (c.stop_time < c.start_time) {
297*103e46e4SHarish Mahendrakar printf("bad WebVTT cue timestamp (stop < start)\n");
298*103e46e4SHarish Mahendrakar return false;
299*103e46e4SHarish Mahendrakar }
300*103e46e4SHarish Mahendrakar
301*103e46e4SHarish Mahendrakar cues_set_.insert(cue);
302*103e46e4SHarish Mahendrakar }
303*103e46e4SHarish Mahendrakar }
304*103e46e4SHarish Mahendrakar
MakeFrame(const cue_t & c,std::string * pf)305*103e46e4SHarish Mahendrakar void SampleMuxerMetadata::MakeFrame(const cue_t& c, std::string* pf) {
306*103e46e4SHarish Mahendrakar pf->clear();
307*103e46e4SHarish Mahendrakar WriteCueIdentifier(c.identifier, pf);
308*103e46e4SHarish Mahendrakar WriteCueSettings(c.settings, pf);
309*103e46e4SHarish Mahendrakar WriteCuePayload(c.payload, pf);
310*103e46e4SHarish Mahendrakar }
311*103e46e4SHarish Mahendrakar
WriteCueIdentifier(const std::string & identifier,std::string * pf)312*103e46e4SHarish Mahendrakar void SampleMuxerMetadata::WriteCueIdentifier(const std::string& identifier,
313*103e46e4SHarish Mahendrakar std::string* pf) {
314*103e46e4SHarish Mahendrakar pf->append(identifier);
315*103e46e4SHarish Mahendrakar pf->push_back('\x0A'); // LF
316*103e46e4SHarish Mahendrakar }
317*103e46e4SHarish Mahendrakar
WriteCueSettings(const cue_t::settings_t & settings,std::string * pf)318*103e46e4SHarish Mahendrakar void SampleMuxerMetadata::WriteCueSettings(const cue_t::settings_t& settings,
319*103e46e4SHarish Mahendrakar std::string* pf) {
320*103e46e4SHarish Mahendrakar if (settings.empty()) {
321*103e46e4SHarish Mahendrakar pf->push_back('\x0A'); // LF
322*103e46e4SHarish Mahendrakar return;
323*103e46e4SHarish Mahendrakar }
324*103e46e4SHarish Mahendrakar
325*103e46e4SHarish Mahendrakar typedef cue_t::settings_t::const_iterator iter_t;
326*103e46e4SHarish Mahendrakar
327*103e46e4SHarish Mahendrakar iter_t i = settings.begin();
328*103e46e4SHarish Mahendrakar const iter_t j = settings.end();
329*103e46e4SHarish Mahendrakar
330*103e46e4SHarish Mahendrakar for (;;) {
331*103e46e4SHarish Mahendrakar const libwebvtt::Setting& setting = *i++;
332*103e46e4SHarish Mahendrakar
333*103e46e4SHarish Mahendrakar pf->append(setting.name);
334*103e46e4SHarish Mahendrakar pf->push_back(':');
335*103e46e4SHarish Mahendrakar pf->append(setting.value);
336*103e46e4SHarish Mahendrakar
337*103e46e4SHarish Mahendrakar if (i == j)
338*103e46e4SHarish Mahendrakar break;
339*103e46e4SHarish Mahendrakar
340*103e46e4SHarish Mahendrakar pf->push_back(' '); // separate settings with whitespace
341*103e46e4SHarish Mahendrakar }
342*103e46e4SHarish Mahendrakar
343*103e46e4SHarish Mahendrakar pf->push_back('\x0A'); // LF
344*103e46e4SHarish Mahendrakar }
345*103e46e4SHarish Mahendrakar
WriteCuePayload(const cue_t::payload_t & payload,std::string * pf)346*103e46e4SHarish Mahendrakar void SampleMuxerMetadata::WriteCuePayload(const cue_t::payload_t& payload,
347*103e46e4SHarish Mahendrakar std::string* pf) {
348*103e46e4SHarish Mahendrakar typedef cue_t::payload_t::const_iterator iter_t;
349*103e46e4SHarish Mahendrakar
350*103e46e4SHarish Mahendrakar iter_t i = payload.begin();
351*103e46e4SHarish Mahendrakar const iter_t j = payload.end();
352*103e46e4SHarish Mahendrakar
353*103e46e4SHarish Mahendrakar while (i != j) {
354*103e46e4SHarish Mahendrakar const std::string& line = *i++;
355*103e46e4SHarish Mahendrakar pf->append(line);
356*103e46e4SHarish Mahendrakar pf->push_back('\x0A'); // LF
357*103e46e4SHarish Mahendrakar }
358*103e46e4SHarish Mahendrakar }
359*103e46e4SHarish Mahendrakar
Write(mkvmuxer::Segment * segment) const360*103e46e4SHarish Mahendrakar bool SampleMuxerMetadata::SortableCue::Write(mkvmuxer::Segment* segment) const {
361*103e46e4SHarish Mahendrakar // Cue start time expressed in milliseconds
362*103e46e4SHarish Mahendrakar const int64_t start_ms = cue.start_time.presentation();
363*103e46e4SHarish Mahendrakar
364*103e46e4SHarish Mahendrakar // Cue start time expressed in nanoseconds (MKV time)
365*103e46e4SHarish Mahendrakar const int64_t start_ns = start_ms * 1000000;
366*103e46e4SHarish Mahendrakar
367*103e46e4SHarish Mahendrakar // Cue stop time expressed in milliseconds
368*103e46e4SHarish Mahendrakar const int64_t stop_ms = cue.stop_time.presentation();
369*103e46e4SHarish Mahendrakar
370*103e46e4SHarish Mahendrakar // Cue stop time expressed in nanonseconds
371*103e46e4SHarish Mahendrakar const int64_t stop_ns = stop_ms * 1000000;
372*103e46e4SHarish Mahendrakar
373*103e46e4SHarish Mahendrakar // Metadata blocks always specify the block duration.
374*103e46e4SHarish Mahendrakar const int64_t duration_ns = stop_ns - start_ns;
375*103e46e4SHarish Mahendrakar
376*103e46e4SHarish Mahendrakar std::string frame;
377*103e46e4SHarish Mahendrakar MakeFrame(cue, &frame);
378*103e46e4SHarish Mahendrakar
379*103e46e4SHarish Mahendrakar typedef const uint8_t* data_t;
380*103e46e4SHarish Mahendrakar const data_t buf = reinterpret_cast<data_t>(frame.data());
381*103e46e4SHarish Mahendrakar const uint64_t len = frame.length();
382*103e46e4SHarish Mahendrakar
383*103e46e4SHarish Mahendrakar mkvmuxer::Frame muxer_frame;
384*103e46e4SHarish Mahendrakar if (!muxer_frame.Init(buf, len))
385*103e46e4SHarish Mahendrakar return 0;
386*103e46e4SHarish Mahendrakar muxer_frame.set_track_number(track_num);
387*103e46e4SHarish Mahendrakar muxer_frame.set_timestamp(start_ns);
388*103e46e4SHarish Mahendrakar muxer_frame.set_duration(duration_ns);
389*103e46e4SHarish Mahendrakar muxer_frame.set_is_key(true); // All metadata frames are keyframes.
390*103e46e4SHarish Mahendrakar return segment->AddGenericFrame(&muxer_frame);
391*103e46e4SHarish Mahendrakar }