1 // Copyright (c) 2010 The WebM project authors. All Rights Reserved.
2 //
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the LICENSE file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8 //
9 // This sample application demonstrates how to use the Matroska parser
10 // library, which allows clients to handle a Matroska format file.
11 #include <cstdio>
12 #include <cstdlib>
13 #include <memory>
14 #include <new>
15
16 #include "mkvparser/mkvparser.h"
17 #include "mkvparser/mkvreader.h"
18
19 namespace {
utf8towcs(const char * str)20 const wchar_t* utf8towcs(const char* str) {
21 if (str == NULL)
22 return NULL;
23
24 // TODO: this probably requires that the locale be
25 // configured somehow:
26
27 const size_t size = mbstowcs(NULL, str, 0);
28
29 if (size == 0 || size == static_cast<size_t>(-1))
30 return NULL;
31
32 wchar_t* const val = new (std::nothrow) wchar_t[size + 1];
33 if (val == NULL)
34 return NULL;
35
36 mbstowcs(val, str, size);
37 val[size] = L'\0';
38
39 return val;
40 }
41
InputHasCues(const mkvparser::Segment * const segment)42 bool InputHasCues(const mkvparser::Segment* const segment) {
43 const mkvparser::Cues* const cues = segment->GetCues();
44 if (cues == NULL)
45 return false;
46
47 while (!cues->DoneParsing())
48 cues->LoadCuePoint();
49
50 const mkvparser::CuePoint* const cue_point = cues->GetFirst();
51 if (cue_point == NULL)
52 return false;
53
54 return true;
55 }
56
MasteringMetadataValuePresent(double value)57 bool MasteringMetadataValuePresent(double value) {
58 return value != mkvparser::MasteringMetadata::kValueNotPresent;
59 }
60
ColourValuePresent(long long value)61 bool ColourValuePresent(long long value) {
62 return value != mkvparser::Colour::kValueNotPresent;
63 }
64 } // namespace
65
main(int argc,char * argv[])66 int main(int argc, char* argv[]) {
67 if (argc == 1) {
68 printf("Mkv Parser Sample Application\n");
69 printf(" Usage: %s <input file> \n", argv[0]);
70 return EXIT_FAILURE;
71 }
72
73 mkvparser::MkvReader reader;
74
75 if (reader.Open(argv[1])) {
76 printf("\n Filename is invalid or error while opening.\n");
77 return EXIT_FAILURE;
78 }
79
80 int maj, min, build, rev;
81
82 mkvparser::GetVersion(maj, min, build, rev);
83 printf("\t\t libwebm version: %d.%d.%d.%d\n", maj, min, build, rev);
84
85 long long pos = 0;
86
87 mkvparser::EBMLHeader ebmlHeader;
88
89 long long ret = ebmlHeader.Parse(&reader, pos);
90 if (ret < 0) {
91 printf("\n EBMLHeader::Parse() failed.");
92 return EXIT_FAILURE;
93 }
94
95 printf("\t\t\t EBML Header\n");
96 printf("\t\tEBML Version\t\t: %lld\n", ebmlHeader.m_version);
97 printf("\t\tEBML MaxIDLength\t: %lld\n", ebmlHeader.m_maxIdLength);
98 printf("\t\tEBML MaxSizeLength\t: %lld\n", ebmlHeader.m_maxSizeLength);
99 printf("\t\tDoc Type\t\t: %s\n", ebmlHeader.m_docType);
100 printf("\t\tPos\t\t\t: %lld\n", pos);
101
102 typedef mkvparser::Segment seg_t;
103 seg_t* pSegment_;
104
105 ret = seg_t::CreateInstance(&reader, pos, pSegment_);
106 if (ret) {
107 printf("\n Segment::CreateInstance() failed.");
108 return EXIT_FAILURE;
109 }
110
111 const std::unique_ptr<seg_t> pSegment(pSegment_);
112
113 ret = pSegment->Load();
114 if (ret < 0) {
115 printf("\n Segment::Load() failed.");
116 return EXIT_FAILURE;
117 }
118
119 const mkvparser::SegmentInfo* const pSegmentInfo = pSegment->GetInfo();
120 if (pSegmentInfo == NULL) {
121 printf("\n Segment::GetInfo() failed.");
122 return EXIT_FAILURE;
123 }
124
125 const long long timeCodeScale = pSegmentInfo->GetTimeCodeScale();
126 const long long duration_ns = pSegmentInfo->GetDuration();
127
128 const char* const pTitle_ = pSegmentInfo->GetTitleAsUTF8();
129 const wchar_t* const pTitle = utf8towcs(pTitle_);
130
131 const char* const pMuxingApp_ = pSegmentInfo->GetMuxingAppAsUTF8();
132 const wchar_t* const pMuxingApp = utf8towcs(pMuxingApp_);
133
134 const char* const pWritingApp_ = pSegmentInfo->GetWritingAppAsUTF8();
135 const wchar_t* const pWritingApp = utf8towcs(pWritingApp_);
136
137 printf("\n");
138 printf("\t\t\t Segment Info\n");
139 printf("\t\tTimeCodeScale\t\t: %lld \n", timeCodeScale);
140 printf("\t\tDuration\t\t: %lld\n", duration_ns);
141
142 const double duration_sec = double(duration_ns) / 1000000000;
143 printf("\t\tDuration(secs)\t\t: %7.3lf\n", duration_sec);
144
145 if (pTitle == NULL)
146 printf("\t\tTrack Name\t\t: NULL\n");
147 else {
148 printf("\t\tTrack Name\t\t: %ls\n", pTitle);
149 delete[] pTitle;
150 }
151
152 if (pMuxingApp == NULL)
153 printf("\t\tMuxing App\t\t: NULL\n");
154 else {
155 printf("\t\tMuxing App\t\t: %ls\n", pMuxingApp);
156 delete[] pMuxingApp;
157 }
158
159 if (pWritingApp == NULL)
160 printf("\t\tWriting App\t\t: NULL\n");
161 else {
162 printf("\t\tWriting App\t\t: %ls\n", pWritingApp);
163 delete[] pWritingApp;
164 }
165
166 // pos of segment payload
167 printf("\t\tPosition(Segment)\t: %lld\n", pSegment->m_start);
168
169 // size of segment payload
170 printf("\t\tSize(Segment)\t\t: %lld\n", pSegment->m_size);
171
172 const mkvparser::Tracks* pTracks = pSegment->GetTracks();
173
174 unsigned long track_num = 0;
175 const unsigned long num_tracks = pTracks->GetTracksCount();
176
177 printf("\n\t\t\t Track Info\n");
178
179 while (track_num != num_tracks) {
180 const mkvparser::Track* const pTrack =
181 pTracks->GetTrackByIndex(track_num++);
182
183 if (pTrack == NULL)
184 continue;
185
186 const long trackType = pTrack->GetType();
187 const long trackNumber = pTrack->GetNumber();
188 const unsigned long long trackUid = pTrack->GetUid();
189 const wchar_t* const pTrackName = utf8towcs(pTrack->GetNameAsUTF8());
190
191 printf("\t\tTrack Type\t\t: %ld\n", trackType);
192 printf("\t\tTrack Number\t\t: %ld\n", trackNumber);
193 printf("\t\tTrack Uid\t\t: %lld\n", trackUid);
194
195 if (pTrackName == NULL)
196 printf("\t\tTrack Name\t\t: NULL\n");
197 else {
198 printf("\t\tTrack Name\t\t: %ls \n", pTrackName);
199 delete[] pTrackName;
200 }
201
202 const char* const pCodecId = pTrack->GetCodecId();
203
204 if (pCodecId == NULL)
205 printf("\t\tCodec Id\t\t: NULL\n");
206 else
207 printf("\t\tCodec Id\t\t: %s\n", pCodecId);
208
209 size_t codec_private_size = 0;
210 if (pTrack->GetCodecPrivate(codec_private_size)) {
211 printf("\t\tCodec private length: %u bytes\n",
212 static_cast<unsigned int>(codec_private_size));
213 }
214
215 const char* const pCodecName_ = pTrack->GetCodecNameAsUTF8();
216 const wchar_t* const pCodecName = utf8towcs(pCodecName_);
217
218 if (pCodecName == NULL)
219 printf("\t\tCodec Name\t\t: NULL\n");
220 else {
221 printf("\t\tCodec Name\t\t: %ls\n", pCodecName);
222 delete[] pCodecName;
223 }
224
225 if (trackType == mkvparser::Track::kVideo) {
226 const mkvparser::VideoTrack* const pVideoTrack =
227 static_cast<const mkvparser::VideoTrack*>(pTrack);
228
229 const long long width = pVideoTrack->GetWidth();
230 printf("\t\tVideo Width\t\t: %lld\n", width);
231
232 const long long height = pVideoTrack->GetHeight();
233 printf("\t\tVideo Height\t\t: %lld\n", height);
234
235 const double rate = pVideoTrack->GetFrameRate();
236 printf("\t\tVideo Rate\t\t: %f\n", rate);
237
238 const mkvparser::Colour* const colour = pVideoTrack->GetColour();
239 if (colour) {
240 printf("\t\tVideo Colour:\n");
241 if (ColourValuePresent(colour->matrix_coefficients))
242 printf("\t\t\tMatrixCoefficients: %lld\n",
243 colour->matrix_coefficients);
244 if (ColourValuePresent(colour->bits_per_channel))
245 printf("\t\t\tBitsPerChannel: %lld\n", colour->bits_per_channel);
246 if (ColourValuePresent(colour->chroma_subsampling_horz))
247 printf("\t\t\tChromaSubsamplingHorz: %lld\n",
248 colour->chroma_subsampling_horz);
249 if (ColourValuePresent(colour->chroma_subsampling_vert))
250 printf("\t\t\tChromaSubsamplingVert: %lld\n",
251 colour->chroma_subsampling_vert);
252 if (ColourValuePresent(colour->cb_subsampling_horz))
253 printf("\t\t\tCbSubsamplingHorz: %lld\n",
254 colour->cb_subsampling_horz);
255 if (ColourValuePresent(colour->cb_subsampling_vert))
256 printf("\t\t\tCbSubsamplingVert: %lld\n",
257 colour->cb_subsampling_vert);
258 if (ColourValuePresent(colour->chroma_siting_horz))
259 printf("\t\t\tChromaSitingHorz: %lld\n", colour->chroma_siting_horz);
260 if (ColourValuePresent(colour->chroma_siting_vert))
261 printf("\t\t\tChromaSitingVert: %lld\n", colour->chroma_siting_vert);
262 if (ColourValuePresent(colour->range))
263 printf("\t\t\tRange: %lld\n", colour->range);
264 if (ColourValuePresent(colour->transfer_characteristics))
265 printf("\t\t\tTransferCharacteristics: %lld\n",
266 colour->transfer_characteristics);
267 if (ColourValuePresent(colour->primaries))
268 printf("\t\t\tPrimaries: %lld\n", colour->primaries);
269 if (ColourValuePresent(colour->max_cll))
270 printf("\t\t\tMaxCLL: %lld\n", colour->max_cll);
271 if (ColourValuePresent(colour->max_fall))
272 printf("\t\t\tMaxFALL: %lld\n", colour->max_fall);
273 if (colour->mastering_metadata) {
274 const mkvparser::MasteringMetadata* const mm =
275 colour->mastering_metadata;
276 printf("\t\t\tMastering Metadata:\n");
277 if (MasteringMetadataValuePresent(mm->luminance_max))
278 printf("\t\t\t\tLuminanceMax: %f\n", mm->luminance_max);
279 if (MasteringMetadataValuePresent(mm->luminance_min))
280 printf("\t\t\t\tLuminanceMin: %f\n", mm->luminance_min);
281 if (mm->r) {
282 printf("\t\t\t\t\tPrimaryRChromaticityX: %f\n", mm->r->x);
283 printf("\t\t\t\t\tPrimaryRChromaticityY: %f\n", mm->r->y);
284 }
285 if (mm->g) {
286 printf("\t\t\t\t\tPrimaryGChromaticityX: %f\n", mm->g->x);
287 printf("\t\t\t\t\tPrimaryGChromaticityY: %f\n", mm->g->y);
288 }
289 if (mm->b) {
290 printf("\t\t\t\t\tPrimaryBChromaticityX: %f\n", mm->b->x);
291 printf("\t\t\t\t\tPrimaryBChromaticityY: %f\n", mm->b->y);
292 }
293 if (mm->white_point) {
294 printf("\t\t\t\t\tWhitePointChromaticityX: %f\n",
295 mm->white_point->x);
296 printf("\t\t\t\t\tWhitePointChromaticityY: %f\n",
297 mm->white_point->y);
298 }
299 }
300 }
301
302 const mkvparser::Projection* const projection =
303 pVideoTrack->GetProjection();
304 if (projection) {
305 printf("\t\tVideo Projection:\n");
306 if (projection->type != mkvparser::Projection::kTypeNotPresent)
307 printf("\t\t\tProjectionType: %d\n",
308 static_cast<int>(projection->type));
309 if (projection->private_data) {
310 printf("\t\t\tProjectionPrivate: %u bytes\n",
311 static_cast<unsigned int>(projection->private_data_length));
312 }
313 if (projection->pose_yaw != mkvparser::Projection::kValueNotPresent)
314 printf("\t\t\tProjectionPoseYaw: %f\n", projection->pose_yaw);
315 if (projection->pose_pitch != mkvparser::Projection::kValueNotPresent)
316 printf("\t\t\tProjectionPosePitch: %f\n", projection->pose_pitch);
317 if (projection->pose_roll != mkvparser::Projection::kValueNotPresent)
318 printf("\t\t\tProjectionPosePitch: %f\n", projection->pose_roll);
319 }
320 }
321
322 if (trackType == mkvparser::Track::kAudio) {
323 const mkvparser::AudioTrack* const pAudioTrack =
324 static_cast<const mkvparser::AudioTrack*>(pTrack);
325
326 const long long channels = pAudioTrack->GetChannels();
327 printf("\t\tAudio Channels\t\t: %lld\n", channels);
328
329 const long long bitDepth = pAudioTrack->GetBitDepth();
330 printf("\t\tAudio BitDepth\t\t: %lld\n", bitDepth);
331
332 const double sampleRate = pAudioTrack->GetSamplingRate();
333 printf("\t\tAddio Sample Rate\t: %.3f\n", sampleRate);
334
335 const long long codecDelay = pAudioTrack->GetCodecDelay();
336 printf("\t\tAudio Codec Delay\t\t: %lld\n", codecDelay);
337
338 const long long seekPreRoll = pAudioTrack->GetSeekPreRoll();
339 printf("\t\tAudio Seek Pre Roll\t\t: %lld\n", seekPreRoll);
340 }
341 }
342
343 printf("\n\n\t\t\t Cluster Info\n");
344 const unsigned long clusterCount = pSegment->GetCount();
345
346 printf("\t\tCluster Count\t: %ld\n\n", clusterCount);
347
348 if (clusterCount == 0) {
349 printf("\t\tSegment has no clusters.\n");
350 return EXIT_FAILURE;
351 }
352
353 const mkvparser::Cluster* pCluster = pSegment->GetFirst();
354
355 while (pCluster != NULL && !pCluster->EOS()) {
356 const long long timeCode = pCluster->GetTimeCode();
357 printf("\t\tCluster Time Code\t: %lld\n", timeCode);
358
359 const long long time_ns = pCluster->GetTime();
360 printf("\t\tCluster Time (ns)\t: %lld\n", time_ns);
361
362 const mkvparser::BlockEntry* pBlockEntry;
363
364 long status = pCluster->GetFirst(pBlockEntry);
365
366 if (status < 0) // error
367 {
368 printf("\t\tError parsing first block of cluster\n");
369 fflush(stdout);
370 return EXIT_FAILURE;
371 }
372
373 while (pBlockEntry != NULL && !pBlockEntry->EOS()) {
374 const mkvparser::Block* const pBlock = pBlockEntry->GetBlock();
375 const long long trackNum = pBlock->GetTrackNumber();
376 const unsigned long tn = static_cast<unsigned long>(trackNum);
377 const mkvparser::Track* const pTrack = pTracks->GetTrackByNumber(tn);
378
379 if (pTrack == NULL)
380 printf("\t\t\tBlock\t\t:UNKNOWN TRACK TYPE\n");
381 else {
382 const long long trackType = pTrack->GetType();
383 const int frameCount = pBlock->GetFrameCount();
384 const long long time_ns = pBlock->GetTime(pCluster);
385 const long long discard_padding = pBlock->GetDiscardPadding();
386
387 printf("\t\t\tBlock\t\t:%s,%s,%15lld,%lld\n",
388 (trackType == mkvparser::Track::kVideo) ? "V" : "A",
389 pBlock->IsKey() ? "I" : "P", time_ns, discard_padding);
390
391 for (int i = 0; i < frameCount; ++i) {
392 const mkvparser::Block::Frame& theFrame = pBlock->GetFrame(i);
393 const long size = theFrame.len;
394 const long long offset = theFrame.pos;
395 printf("\t\t\t %15ld,%15llx\n", size, offset);
396 }
397 }
398
399 status = pCluster->GetNext(pBlockEntry, pBlockEntry);
400
401 if (status < 0) {
402 printf("\t\t\tError parsing next block of cluster\n");
403 fflush(stdout);
404 return EXIT_FAILURE;
405 }
406 }
407
408 pCluster = pSegment->GetNext(pCluster);
409 }
410
411 if (InputHasCues(pSegment.get())) {
412 // Walk them.
413 const mkvparser::Cues* const cues = pSegment->GetCues();
414 const mkvparser::CuePoint* cue = cues->GetFirst();
415 int cue_point_num = 1;
416
417 printf("\t\tCues\n");
418 do {
419 for (track_num = 0; track_num < num_tracks; ++track_num) {
420 const mkvparser::Track* const track =
421 pTracks->GetTrackByIndex(track_num);
422 const mkvparser::CuePoint::TrackPosition* const track_pos =
423 cue->Find(track);
424
425 if (track_pos != NULL) {
426 const char track_type =
427 (track->GetType() == mkvparser::Track::kVideo) ? 'V' : 'A';
428 printf(
429 "\t\t\tCue Point %4d Track %3lu(%c) Time %14lld "
430 "Block %4lld Pos %8llx\n",
431 cue_point_num, track->GetNumber(), track_type,
432 cue->GetTime(pSegment.get()), track_pos->m_block,
433 track_pos->m_pos);
434 }
435 }
436
437 cue = cues->GetNext(cue);
438 ++cue_point_num;
439 } while (cue != NULL);
440 }
441
442 const mkvparser::Tags* const tags = pSegment->GetTags();
443 if (tags && tags->GetTagCount() > 0) {
444 printf("\t\tTags\n");
445 for (int i = 0; i < tags->GetTagCount(); ++i) {
446 const mkvparser::Tags::Tag* const tag = tags->GetTag(i);
447 printf("\t\t\tTag\n");
448 for (int j = 0; j < tag->GetSimpleTagCount(); j++) {
449 const mkvparser::Tags::SimpleTag* const simple_tag =
450 tag->GetSimpleTag(j);
451 printf("\t\t\t\tSimple Tag \"%s\" Value \"%s\"\n",
452 simple_tag->GetTagName(), simple_tag->GetTagString());
453 }
454 }
455 }
456
457 fflush(stdout);
458 return EXIT_SUCCESS;
459 }
460