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 #include <inttypes.h>
9*103e46e4SHarish Mahendrakar #include <stdint.h>
10*103e46e4SHarish Mahendrakar
11*103e46e4SHarish Mahendrakar #include <cstdlib>
12*103e46e4SHarish Mahendrakar #include <cstring>
13*103e46e4SHarish Mahendrakar #include <limits>
14*103e46e4SHarish Mahendrakar #include <memory>
15*103e46e4SHarish Mahendrakar #include <queue>
16*103e46e4SHarish Mahendrakar #include <string>
17*103e46e4SHarish Mahendrakar #include <vector>
18*103e46e4SHarish Mahendrakar
19*103e46e4SHarish Mahendrakar #include "common/hdr_util.h"
20*103e46e4SHarish Mahendrakar #include "common/indent.h"
21*103e46e4SHarish Mahendrakar #include "common/vp9_header_parser.h"
22*103e46e4SHarish Mahendrakar #include "common/vp9_level_stats.h"
23*103e46e4SHarish Mahendrakar #include "common/webm_constants.h"
24*103e46e4SHarish Mahendrakar #include "common/webm_endian.h"
25*103e46e4SHarish Mahendrakar
26*103e46e4SHarish Mahendrakar #include "mkvparser/mkvparser.h"
27*103e46e4SHarish Mahendrakar #include "mkvparser/mkvreader.h"
28*103e46e4SHarish Mahendrakar
29*103e46e4SHarish Mahendrakar namespace {
30*103e46e4SHarish Mahendrakar
31*103e46e4SHarish Mahendrakar using libwebm::Indent;
32*103e46e4SHarish Mahendrakar using libwebm::kNanosecondsPerSecond;
33*103e46e4SHarish Mahendrakar using libwebm::kNanosecondsPerSecondi;
34*103e46e4SHarish Mahendrakar using mkvparser::ContentEncoding;
35*103e46e4SHarish Mahendrakar using std::string;
36*103e46e4SHarish Mahendrakar using std::wstring;
37*103e46e4SHarish Mahendrakar
38*103e46e4SHarish Mahendrakar const char VERSION_STRING[] = "1.0.4.5";
39*103e46e4SHarish Mahendrakar
40*103e46e4SHarish Mahendrakar struct Options {
41*103e46e4SHarish Mahendrakar Options();
42*103e46e4SHarish Mahendrakar
43*103e46e4SHarish Mahendrakar // Returns true if |value| matches -|option| or -no|option|.
44*103e46e4SHarish Mahendrakar static bool MatchesBooleanOption(const string& option, const string& value);
45*103e46e4SHarish Mahendrakar
46*103e46e4SHarish Mahendrakar // Set all of the member variables to |value|.
47*103e46e4SHarish Mahendrakar void SetAll(bool value);
48*103e46e4SHarish Mahendrakar
49*103e46e4SHarish Mahendrakar bool output_video;
50*103e46e4SHarish Mahendrakar bool output_audio;
51*103e46e4SHarish Mahendrakar bool output_size;
52*103e46e4SHarish Mahendrakar bool output_offset;
53*103e46e4SHarish Mahendrakar bool output_seconds;
54*103e46e4SHarish Mahendrakar bool output_ebml_header;
55*103e46e4SHarish Mahendrakar bool output_segment;
56*103e46e4SHarish Mahendrakar bool output_seekhead;
57*103e46e4SHarish Mahendrakar bool output_segment_info;
58*103e46e4SHarish Mahendrakar bool output_tracks;
59*103e46e4SHarish Mahendrakar bool output_clusters;
60*103e46e4SHarish Mahendrakar bool output_blocks;
61*103e46e4SHarish Mahendrakar bool output_codec_info;
62*103e46e4SHarish Mahendrakar bool output_clusters_size;
63*103e46e4SHarish Mahendrakar bool output_encrypted_info;
64*103e46e4SHarish Mahendrakar bool output_cues;
65*103e46e4SHarish Mahendrakar bool output_frame_stats;
66*103e46e4SHarish Mahendrakar bool output_vp9_level;
67*103e46e4SHarish Mahendrakar };
68*103e46e4SHarish Mahendrakar
Options()69*103e46e4SHarish Mahendrakar Options::Options()
70*103e46e4SHarish Mahendrakar : output_video(true),
71*103e46e4SHarish Mahendrakar output_audio(true),
72*103e46e4SHarish Mahendrakar output_size(false),
73*103e46e4SHarish Mahendrakar output_offset(false),
74*103e46e4SHarish Mahendrakar output_seconds(true),
75*103e46e4SHarish Mahendrakar output_ebml_header(true),
76*103e46e4SHarish Mahendrakar output_segment(true),
77*103e46e4SHarish Mahendrakar output_seekhead(false),
78*103e46e4SHarish Mahendrakar output_segment_info(true),
79*103e46e4SHarish Mahendrakar output_tracks(true),
80*103e46e4SHarish Mahendrakar output_clusters(false),
81*103e46e4SHarish Mahendrakar output_blocks(false),
82*103e46e4SHarish Mahendrakar output_codec_info(false),
83*103e46e4SHarish Mahendrakar output_clusters_size(false),
84*103e46e4SHarish Mahendrakar output_encrypted_info(false),
85*103e46e4SHarish Mahendrakar output_cues(false),
86*103e46e4SHarish Mahendrakar output_frame_stats(false),
87*103e46e4SHarish Mahendrakar output_vp9_level(false) {}
88*103e46e4SHarish Mahendrakar
SetAll(bool value)89*103e46e4SHarish Mahendrakar void Options::SetAll(bool value) {
90*103e46e4SHarish Mahendrakar output_video = value;
91*103e46e4SHarish Mahendrakar output_audio = value;
92*103e46e4SHarish Mahendrakar output_size = value;
93*103e46e4SHarish Mahendrakar output_offset = value;
94*103e46e4SHarish Mahendrakar output_ebml_header = value;
95*103e46e4SHarish Mahendrakar output_seconds = value;
96*103e46e4SHarish Mahendrakar output_segment = value;
97*103e46e4SHarish Mahendrakar output_segment_info = value;
98*103e46e4SHarish Mahendrakar output_tracks = value;
99*103e46e4SHarish Mahendrakar output_clusters = value;
100*103e46e4SHarish Mahendrakar output_blocks = value;
101*103e46e4SHarish Mahendrakar output_codec_info = value;
102*103e46e4SHarish Mahendrakar output_clusters_size = value;
103*103e46e4SHarish Mahendrakar output_encrypted_info = value;
104*103e46e4SHarish Mahendrakar output_cues = value;
105*103e46e4SHarish Mahendrakar output_frame_stats = value;
106*103e46e4SHarish Mahendrakar output_vp9_level = value;
107*103e46e4SHarish Mahendrakar }
108*103e46e4SHarish Mahendrakar
MatchesBooleanOption(const string & option,const string & value)109*103e46e4SHarish Mahendrakar bool Options::MatchesBooleanOption(const string& option, const string& value) {
110*103e46e4SHarish Mahendrakar const string opt = "-" + option;
111*103e46e4SHarish Mahendrakar const string noopt = "-no" + option;
112*103e46e4SHarish Mahendrakar return value == opt || value == noopt;
113*103e46e4SHarish Mahendrakar }
114*103e46e4SHarish Mahendrakar
115*103e46e4SHarish Mahendrakar struct FrameStats {
FrameStats__anonaa7ba1c20111::FrameStats116*103e46e4SHarish Mahendrakar FrameStats()
117*103e46e4SHarish Mahendrakar : frames(0),
118*103e46e4SHarish Mahendrakar displayed_frames(0),
119*103e46e4SHarish Mahendrakar first_altref(true),
120*103e46e4SHarish Mahendrakar frames_since_last_altref(0),
121*103e46e4SHarish Mahendrakar minimum_altref_distance(std::numeric_limits<int>::max()),
122*103e46e4SHarish Mahendrakar min_altref_end_ns(0),
123*103e46e4SHarish Mahendrakar max_window_size(0),
124*103e46e4SHarish Mahendrakar max_window_end_ns(0) {}
125*103e46e4SHarish Mahendrakar
126*103e46e4SHarish Mahendrakar int frames;
127*103e46e4SHarish Mahendrakar int displayed_frames;
128*103e46e4SHarish Mahendrakar
129*103e46e4SHarish Mahendrakar bool first_altref;
130*103e46e4SHarish Mahendrakar int frames_since_last_altref;
131*103e46e4SHarish Mahendrakar int minimum_altref_distance;
132*103e46e4SHarish Mahendrakar int64_t min_altref_end_ns;
133*103e46e4SHarish Mahendrakar
134*103e46e4SHarish Mahendrakar std::queue<int64_t> window;
135*103e46e4SHarish Mahendrakar int64_t max_window_size;
136*103e46e4SHarish Mahendrakar int64_t max_window_end_ns;
137*103e46e4SHarish Mahendrakar };
138*103e46e4SHarish Mahendrakar
Usage()139*103e46e4SHarish Mahendrakar void Usage() {
140*103e46e4SHarish Mahendrakar printf("Usage: webm_info [options] -i input\n");
141*103e46e4SHarish Mahendrakar printf("\n");
142*103e46e4SHarish Mahendrakar printf("Main options:\n");
143*103e46e4SHarish Mahendrakar printf(" -h | -? show help\n");
144*103e46e4SHarish Mahendrakar printf(" -v show version\n");
145*103e46e4SHarish Mahendrakar printf(" -all Enable all output options.\n");
146*103e46e4SHarish Mahendrakar printf(" -video Output video tracks (true)\n");
147*103e46e4SHarish Mahendrakar printf(" -audio Output audio tracks (true)\n");
148*103e46e4SHarish Mahendrakar printf(" -size Output element sizes (false)\n");
149*103e46e4SHarish Mahendrakar printf(" -offset Output element offsets (false)\n");
150*103e46e4SHarish Mahendrakar printf(" -times_seconds Output times as seconds (true)\n");
151*103e46e4SHarish Mahendrakar printf(" -ebml_header Output EBML header (true)\n");
152*103e46e4SHarish Mahendrakar printf(" -segment Output Segment (true)\n");
153*103e46e4SHarish Mahendrakar printf(" -seekhead Output SeekHead (false)\n");
154*103e46e4SHarish Mahendrakar printf(" -segment_info Output SegmentInfo (true)\n");
155*103e46e4SHarish Mahendrakar printf(" -tracks Output Tracks (true)\n");
156*103e46e4SHarish Mahendrakar printf(" -clusters Output Clusters (false)\n");
157*103e46e4SHarish Mahendrakar printf(" -blocks Output Blocks (false)\n");
158*103e46e4SHarish Mahendrakar printf(" -codec_info Output video codec information (false)\n");
159*103e46e4SHarish Mahendrakar printf(" -clusters_size Output Total Clusters size (false)\n");
160*103e46e4SHarish Mahendrakar printf(" -encrypted_info Output encrypted frame info (false)\n");
161*103e46e4SHarish Mahendrakar printf(" -cues Output Cues entries (false)\n");
162*103e46e4SHarish Mahendrakar printf(" -frame_stats Output frame stats (VP9)(false)\n");
163*103e46e4SHarish Mahendrakar printf(" -vp9_level Output VP9 level(false)\n");
164*103e46e4SHarish Mahendrakar printf("\nOutput options may be negated by prefixing 'no'.\n");
165*103e46e4SHarish Mahendrakar }
166*103e46e4SHarish Mahendrakar
167*103e46e4SHarish Mahendrakar // TODO(fgalligan): Add support for non-ascii.
UTF8ToWideString(const char * str)168*103e46e4SHarish Mahendrakar wstring UTF8ToWideString(const char* str) {
169*103e46e4SHarish Mahendrakar wstring wstr;
170*103e46e4SHarish Mahendrakar
171*103e46e4SHarish Mahendrakar if (str == NULL)
172*103e46e4SHarish Mahendrakar return wstr;
173*103e46e4SHarish Mahendrakar
174*103e46e4SHarish Mahendrakar string temp_str(str, strlen(str));
175*103e46e4SHarish Mahendrakar wstr.assign(temp_str.begin(), temp_str.end());
176*103e46e4SHarish Mahendrakar
177*103e46e4SHarish Mahendrakar return wstr;
178*103e46e4SHarish Mahendrakar }
179*103e46e4SHarish Mahendrakar
ToString(const char * str)180*103e46e4SHarish Mahendrakar string ToString(const char* str) { return string((str == NULL) ? "" : str); }
181*103e46e4SHarish Mahendrakar
OutputEBMLHeader(const mkvparser::EBMLHeader & ebml,FILE * o,Indent * indent)182*103e46e4SHarish Mahendrakar void OutputEBMLHeader(const mkvparser::EBMLHeader& ebml, FILE* o,
183*103e46e4SHarish Mahendrakar Indent* indent) {
184*103e46e4SHarish Mahendrakar fprintf(o, "EBML Header:\n");
185*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kIncreaseIndent);
186*103e46e4SHarish Mahendrakar fprintf(o, "%sEBMLVersion : %lld\n", indent->indent_str().c_str(),
187*103e46e4SHarish Mahendrakar ebml.m_version);
188*103e46e4SHarish Mahendrakar fprintf(o, "%sEBMLReadVersion : %lld\n", indent->indent_str().c_str(),
189*103e46e4SHarish Mahendrakar ebml.m_readVersion);
190*103e46e4SHarish Mahendrakar fprintf(o, "%sEBMLMaxIDLength : %lld\n", indent->indent_str().c_str(),
191*103e46e4SHarish Mahendrakar ebml.m_maxIdLength);
192*103e46e4SHarish Mahendrakar fprintf(o, "%sEBMLMaxSizeLength : %lld\n", indent->indent_str().c_str(),
193*103e46e4SHarish Mahendrakar ebml.m_maxSizeLength);
194*103e46e4SHarish Mahendrakar fprintf(o, "%sDoc Type : %s\n", indent->indent_str().c_str(),
195*103e46e4SHarish Mahendrakar ebml.m_docType);
196*103e46e4SHarish Mahendrakar fprintf(o, "%sDocTypeVersion : %lld\n", indent->indent_str().c_str(),
197*103e46e4SHarish Mahendrakar ebml.m_docTypeVersion);
198*103e46e4SHarish Mahendrakar fprintf(o, "%sDocTypeReadVersion: %lld\n", indent->indent_str().c_str(),
199*103e46e4SHarish Mahendrakar ebml.m_docTypeReadVersion);
200*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kDecreaseIndent);
201*103e46e4SHarish Mahendrakar }
202*103e46e4SHarish Mahendrakar
OutputSegment(const mkvparser::Segment & segment,const Options & options,FILE * o)203*103e46e4SHarish Mahendrakar void OutputSegment(const mkvparser::Segment& segment, const Options& options,
204*103e46e4SHarish Mahendrakar FILE* o) {
205*103e46e4SHarish Mahendrakar fprintf(o, "Segment:");
206*103e46e4SHarish Mahendrakar if (options.output_offset)
207*103e46e4SHarish Mahendrakar fprintf(o, " @: %lld", segment.m_element_start);
208*103e46e4SHarish Mahendrakar if (options.output_size)
209*103e46e4SHarish Mahendrakar fprintf(o, " size: %lld",
210*103e46e4SHarish Mahendrakar segment.m_size + segment.m_start - segment.m_element_start);
211*103e46e4SHarish Mahendrakar fprintf(o, "\n");
212*103e46e4SHarish Mahendrakar }
213*103e46e4SHarish Mahendrakar
OutputSeekHead(const mkvparser::Segment & segment,const Options & options,FILE * o,Indent * indent)214*103e46e4SHarish Mahendrakar bool OutputSeekHead(const mkvparser::Segment& segment, const Options& options,
215*103e46e4SHarish Mahendrakar FILE* o, Indent* indent) {
216*103e46e4SHarish Mahendrakar const mkvparser::SeekHead* const seekhead = segment.GetSeekHead();
217*103e46e4SHarish Mahendrakar if (!seekhead) {
218*103e46e4SHarish Mahendrakar // SeekHeads are optional.
219*103e46e4SHarish Mahendrakar return true;
220*103e46e4SHarish Mahendrakar }
221*103e46e4SHarish Mahendrakar
222*103e46e4SHarish Mahendrakar fprintf(o, "%sSeekHead:", indent->indent_str().c_str());
223*103e46e4SHarish Mahendrakar if (options.output_offset)
224*103e46e4SHarish Mahendrakar fprintf(o, " @: %lld", seekhead->m_element_start);
225*103e46e4SHarish Mahendrakar if (options.output_size)
226*103e46e4SHarish Mahendrakar fprintf(o, " size: %lld", seekhead->m_element_size);
227*103e46e4SHarish Mahendrakar fprintf(o, "\n");
228*103e46e4SHarish Mahendrakar
229*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kIncreaseIndent);
230*103e46e4SHarish Mahendrakar
231*103e46e4SHarish Mahendrakar for (int i = 0; i < seekhead->GetCount(); ++i) {
232*103e46e4SHarish Mahendrakar const mkvparser::SeekHead::Entry* const entry = seekhead->GetEntry(i);
233*103e46e4SHarish Mahendrakar if (!entry) {
234*103e46e4SHarish Mahendrakar fprintf(stderr, "Error retrieving SeekHead entry #%d\n", i);
235*103e46e4SHarish Mahendrakar return false;
236*103e46e4SHarish Mahendrakar }
237*103e46e4SHarish Mahendrakar
238*103e46e4SHarish Mahendrakar fprintf(o, "%sEntry[%d]", indent->indent_str().c_str(), i);
239*103e46e4SHarish Mahendrakar if (options.output_offset)
240*103e46e4SHarish Mahendrakar fprintf(o, " @: %lld", entry->element_start);
241*103e46e4SHarish Mahendrakar if (options.output_size)
242*103e46e4SHarish Mahendrakar fprintf(o, " size: %lld", entry->element_size);
243*103e46e4SHarish Mahendrakar fprintf(o, "\n");
244*103e46e4SHarish Mahendrakar
245*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kIncreaseIndent);
246*103e46e4SHarish Mahendrakar std::string entry_indent = indent->indent_str();
247*103e46e4SHarish Mahendrakar // TODO(jzern): 1) known ids could be stringified. 2) ids could be
248*103e46e4SHarish Mahendrakar // reencoded to EBML for ease of lookup.
249*103e46e4SHarish Mahendrakar fprintf(o, "%sSeek ID : %llx\n", entry_indent.c_str(), entry->id);
250*103e46e4SHarish Mahendrakar fprintf(o, "%sSeek position : %lld\n", entry_indent.c_str(), entry->pos);
251*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kDecreaseIndent);
252*103e46e4SHarish Mahendrakar }
253*103e46e4SHarish Mahendrakar
254*103e46e4SHarish Mahendrakar for (int i = 0; i < seekhead->GetVoidElementCount(); ++i) {
255*103e46e4SHarish Mahendrakar const mkvparser::SeekHead::VoidElement* const entry =
256*103e46e4SHarish Mahendrakar seekhead->GetVoidElement(i);
257*103e46e4SHarish Mahendrakar if (!entry) {
258*103e46e4SHarish Mahendrakar fprintf(stderr, "Error retrieving SeekHead void element #%d\n", i);
259*103e46e4SHarish Mahendrakar return false;
260*103e46e4SHarish Mahendrakar }
261*103e46e4SHarish Mahendrakar
262*103e46e4SHarish Mahendrakar fprintf(o, "%sVoid element[%d]", indent->indent_str().c_str(), i);
263*103e46e4SHarish Mahendrakar if (options.output_offset)
264*103e46e4SHarish Mahendrakar fprintf(o, " @: %lld", entry->element_start);
265*103e46e4SHarish Mahendrakar if (options.output_size)
266*103e46e4SHarish Mahendrakar fprintf(o, " size: %lld", entry->element_size);
267*103e46e4SHarish Mahendrakar fprintf(o, "\n");
268*103e46e4SHarish Mahendrakar }
269*103e46e4SHarish Mahendrakar
270*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kDecreaseIndent);
271*103e46e4SHarish Mahendrakar return true;
272*103e46e4SHarish Mahendrakar }
273*103e46e4SHarish Mahendrakar
OutputSegmentInfo(const mkvparser::Segment & segment,const Options & options,FILE * o,Indent * indent)274*103e46e4SHarish Mahendrakar bool OutputSegmentInfo(const mkvparser::Segment& segment,
275*103e46e4SHarish Mahendrakar const Options& options, FILE* o, Indent* indent) {
276*103e46e4SHarish Mahendrakar const mkvparser::SegmentInfo* const segment_info = segment.GetInfo();
277*103e46e4SHarish Mahendrakar if (!segment_info) {
278*103e46e4SHarish Mahendrakar fprintf(stderr, "SegmentInfo was NULL.\n");
279*103e46e4SHarish Mahendrakar return false;
280*103e46e4SHarish Mahendrakar }
281*103e46e4SHarish Mahendrakar
282*103e46e4SHarish Mahendrakar const int64_t timecode_scale = segment_info->GetTimeCodeScale();
283*103e46e4SHarish Mahendrakar const int64_t duration_ns = segment_info->GetDuration();
284*103e46e4SHarish Mahendrakar const wstring title = UTF8ToWideString(segment_info->GetTitleAsUTF8());
285*103e46e4SHarish Mahendrakar const wstring muxing_app =
286*103e46e4SHarish Mahendrakar UTF8ToWideString(segment_info->GetMuxingAppAsUTF8());
287*103e46e4SHarish Mahendrakar const wstring writing_app =
288*103e46e4SHarish Mahendrakar UTF8ToWideString(segment_info->GetWritingAppAsUTF8());
289*103e46e4SHarish Mahendrakar
290*103e46e4SHarish Mahendrakar fprintf(o, "%sSegmentInfo:", indent->indent_str().c_str());
291*103e46e4SHarish Mahendrakar if (options.output_offset)
292*103e46e4SHarish Mahendrakar fprintf(o, " @: %lld", segment_info->m_element_start);
293*103e46e4SHarish Mahendrakar if (options.output_size)
294*103e46e4SHarish Mahendrakar fprintf(o, " size: %lld", segment_info->m_element_size);
295*103e46e4SHarish Mahendrakar fprintf(o, "\n");
296*103e46e4SHarish Mahendrakar
297*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kIncreaseIndent);
298*103e46e4SHarish Mahendrakar fprintf(o, "%sTimecodeScale : %" PRId64 " \n", indent->indent_str().c_str(),
299*103e46e4SHarish Mahendrakar timecode_scale);
300*103e46e4SHarish Mahendrakar if (options.output_seconds)
301*103e46e4SHarish Mahendrakar fprintf(o, "%sDuration(secs): %g\n", indent->indent_str().c_str(),
302*103e46e4SHarish Mahendrakar duration_ns / kNanosecondsPerSecond);
303*103e46e4SHarish Mahendrakar else
304*103e46e4SHarish Mahendrakar fprintf(o, "%sDuration(nano): %" PRId64 "\n", indent->indent_str().c_str(),
305*103e46e4SHarish Mahendrakar duration_ns);
306*103e46e4SHarish Mahendrakar
307*103e46e4SHarish Mahendrakar if (!title.empty())
308*103e46e4SHarish Mahendrakar fprintf(o, "%sTitle : %ls\n", indent->indent_str().c_str(),
309*103e46e4SHarish Mahendrakar title.c_str());
310*103e46e4SHarish Mahendrakar if (!muxing_app.empty())
311*103e46e4SHarish Mahendrakar fprintf(o, "%sMuxingApp : %ls\n", indent->indent_str().c_str(),
312*103e46e4SHarish Mahendrakar muxing_app.c_str());
313*103e46e4SHarish Mahendrakar if (!writing_app.empty())
314*103e46e4SHarish Mahendrakar fprintf(o, "%sWritingApp : %ls\n", indent->indent_str().c_str(),
315*103e46e4SHarish Mahendrakar writing_app.c_str());
316*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kDecreaseIndent);
317*103e46e4SHarish Mahendrakar return true;
318*103e46e4SHarish Mahendrakar }
319*103e46e4SHarish Mahendrakar
OutputTracks(const mkvparser::Segment & segment,const Options & options,FILE * o,Indent * indent)320*103e46e4SHarish Mahendrakar bool OutputTracks(const mkvparser::Segment& segment, const Options& options,
321*103e46e4SHarish Mahendrakar FILE* o, Indent* indent) {
322*103e46e4SHarish Mahendrakar const mkvparser::Tracks* const tracks = segment.GetTracks();
323*103e46e4SHarish Mahendrakar if (!tracks) {
324*103e46e4SHarish Mahendrakar fprintf(stderr, "Tracks was NULL.\n");
325*103e46e4SHarish Mahendrakar return false;
326*103e46e4SHarish Mahendrakar }
327*103e46e4SHarish Mahendrakar
328*103e46e4SHarish Mahendrakar fprintf(o, "%sTracks:", indent->indent_str().c_str());
329*103e46e4SHarish Mahendrakar if (options.output_offset)
330*103e46e4SHarish Mahendrakar fprintf(o, " @: %lld", tracks->m_element_start);
331*103e46e4SHarish Mahendrakar if (options.output_size)
332*103e46e4SHarish Mahendrakar fprintf(o, " size: %lld", tracks->m_element_size);
333*103e46e4SHarish Mahendrakar fprintf(o, "\n");
334*103e46e4SHarish Mahendrakar
335*103e46e4SHarish Mahendrakar unsigned int i = 0;
336*103e46e4SHarish Mahendrakar const unsigned long j = tracks->GetTracksCount();
337*103e46e4SHarish Mahendrakar while (i != j) {
338*103e46e4SHarish Mahendrakar const mkvparser::Track* const track = tracks->GetTrackByIndex(i++);
339*103e46e4SHarish Mahendrakar if (track == NULL)
340*103e46e4SHarish Mahendrakar continue;
341*103e46e4SHarish Mahendrakar
342*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kIncreaseIndent);
343*103e46e4SHarish Mahendrakar fprintf(o, "%sTrack:", indent->indent_str().c_str());
344*103e46e4SHarish Mahendrakar if (options.output_offset)
345*103e46e4SHarish Mahendrakar fprintf(o, " @: %lld", track->m_element_start);
346*103e46e4SHarish Mahendrakar if (options.output_size)
347*103e46e4SHarish Mahendrakar fprintf(o, " size: %lld", track->m_element_size);
348*103e46e4SHarish Mahendrakar fprintf(o, "\n");
349*103e46e4SHarish Mahendrakar
350*103e46e4SHarish Mahendrakar const int64_t track_type = track->GetType();
351*103e46e4SHarish Mahendrakar const int64_t track_number = track->GetNumber();
352*103e46e4SHarish Mahendrakar const wstring track_name = UTF8ToWideString(track->GetNameAsUTF8());
353*103e46e4SHarish Mahendrakar
354*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kIncreaseIndent);
355*103e46e4SHarish Mahendrakar fprintf(o, "%sTrackType : %" PRId64 "\n", indent->indent_str().c_str(),
356*103e46e4SHarish Mahendrakar track_type);
357*103e46e4SHarish Mahendrakar fprintf(o, "%sTrackNumber : %" PRId64 "\n", indent->indent_str().c_str(),
358*103e46e4SHarish Mahendrakar track_number);
359*103e46e4SHarish Mahendrakar if (!track_name.empty())
360*103e46e4SHarish Mahendrakar fprintf(o, "%sName : %ls\n", indent->indent_str().c_str(),
361*103e46e4SHarish Mahendrakar track_name.c_str());
362*103e46e4SHarish Mahendrakar
363*103e46e4SHarish Mahendrakar const char* const codec_id = track->GetCodecId();
364*103e46e4SHarish Mahendrakar if (codec_id)
365*103e46e4SHarish Mahendrakar fprintf(o, "%sCodecID : %s\n", indent->indent_str().c_str(),
366*103e46e4SHarish Mahendrakar codec_id);
367*103e46e4SHarish Mahendrakar
368*103e46e4SHarish Mahendrakar const wstring codec_name = UTF8ToWideString(track->GetCodecNameAsUTF8());
369*103e46e4SHarish Mahendrakar if (!codec_name.empty())
370*103e46e4SHarish Mahendrakar fprintf(o, "%sCodecName : %ls\n", indent->indent_str().c_str(),
371*103e46e4SHarish Mahendrakar codec_name.c_str());
372*103e46e4SHarish Mahendrakar
373*103e46e4SHarish Mahendrakar size_t private_size;
374*103e46e4SHarish Mahendrakar const unsigned char* const private_data =
375*103e46e4SHarish Mahendrakar track->GetCodecPrivate(private_size);
376*103e46e4SHarish Mahendrakar if (private_data) {
377*103e46e4SHarish Mahendrakar fprintf(o, "%sPrivateData(size): %d\n", indent->indent_str().c_str(),
378*103e46e4SHarish Mahendrakar static_cast<int>(private_size));
379*103e46e4SHarish Mahendrakar
380*103e46e4SHarish Mahendrakar if (track_type == mkvparser::Track::kVideo) {
381*103e46e4SHarish Mahendrakar const std::string codec_id = ToString(track->GetCodecId());
382*103e46e4SHarish Mahendrakar const std::string v_vp9 = "V_VP9";
383*103e46e4SHarish Mahendrakar if (codec_id == v_vp9) {
384*103e46e4SHarish Mahendrakar libwebm::Vp9CodecFeatures features;
385*103e46e4SHarish Mahendrakar if (!libwebm::ParseVpxCodecPrivate(private_data,
386*103e46e4SHarish Mahendrakar static_cast<int32_t>(private_size),
387*103e46e4SHarish Mahendrakar &features)) {
388*103e46e4SHarish Mahendrakar fprintf(stderr, "Error parsing VpxCodecPrivate.\n");
389*103e46e4SHarish Mahendrakar return false;
390*103e46e4SHarish Mahendrakar }
391*103e46e4SHarish Mahendrakar if (features.profile != -1)
392*103e46e4SHarish Mahendrakar fprintf(o, "%sVP9 profile : %d\n",
393*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), features.profile);
394*103e46e4SHarish Mahendrakar if (features.level != -1)
395*103e46e4SHarish Mahendrakar fprintf(o, "%sVP9 level : %d\n",
396*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), features.level);
397*103e46e4SHarish Mahendrakar if (features.bit_depth != -1)
398*103e46e4SHarish Mahendrakar fprintf(o, "%sVP9 bit_depth : %d\n",
399*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), features.bit_depth);
400*103e46e4SHarish Mahendrakar if (features.chroma_subsampling != -1)
401*103e46e4SHarish Mahendrakar fprintf(o, "%sVP9 chroma subsampling : %d\n",
402*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), features.chroma_subsampling);
403*103e46e4SHarish Mahendrakar }
404*103e46e4SHarish Mahendrakar }
405*103e46e4SHarish Mahendrakar }
406*103e46e4SHarish Mahendrakar
407*103e46e4SHarish Mahendrakar const uint64_t default_duration = track->GetDefaultDuration();
408*103e46e4SHarish Mahendrakar if (default_duration > 0)
409*103e46e4SHarish Mahendrakar fprintf(o, "%sDefaultDuration: %" PRIu64 "\n",
410*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), default_duration);
411*103e46e4SHarish Mahendrakar
412*103e46e4SHarish Mahendrakar if (track->GetContentEncodingCount() > 0) {
413*103e46e4SHarish Mahendrakar // Only check the first content encoding.
414*103e46e4SHarish Mahendrakar const ContentEncoding* const encoding =
415*103e46e4SHarish Mahendrakar track->GetContentEncodingByIndex(0);
416*103e46e4SHarish Mahendrakar if (!encoding) {
417*103e46e4SHarish Mahendrakar printf("Could not get first ContentEncoding.\n");
418*103e46e4SHarish Mahendrakar return false;
419*103e46e4SHarish Mahendrakar }
420*103e46e4SHarish Mahendrakar
421*103e46e4SHarish Mahendrakar fprintf(o, "%sContentEncodingOrder : %lld\n",
422*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), encoding->encoding_order());
423*103e46e4SHarish Mahendrakar fprintf(o, "%sContentEncodingScope : %lld\n",
424*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), encoding->encoding_scope());
425*103e46e4SHarish Mahendrakar fprintf(o, "%sContentEncodingType : %lld\n",
426*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), encoding->encoding_type());
427*103e46e4SHarish Mahendrakar
428*103e46e4SHarish Mahendrakar if (encoding->GetEncryptionCount() > 0) {
429*103e46e4SHarish Mahendrakar // Only check the first encryption.
430*103e46e4SHarish Mahendrakar const ContentEncoding::ContentEncryption* const encryption =
431*103e46e4SHarish Mahendrakar encoding->GetEncryptionByIndex(0);
432*103e46e4SHarish Mahendrakar if (!encryption) {
433*103e46e4SHarish Mahendrakar printf("Could not get first ContentEncryption.\n");
434*103e46e4SHarish Mahendrakar return false;
435*103e46e4SHarish Mahendrakar }
436*103e46e4SHarish Mahendrakar
437*103e46e4SHarish Mahendrakar fprintf(o, "%sContentEncAlgo : %lld\n",
438*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), encryption->algo);
439*103e46e4SHarish Mahendrakar
440*103e46e4SHarish Mahendrakar if (encryption->key_id_len > 0) {
441*103e46e4SHarish Mahendrakar fprintf(o, "%sContentEncKeyID : ", indent->indent_str().c_str());
442*103e46e4SHarish Mahendrakar for (int k = 0; k < encryption->key_id_len; ++k) {
443*103e46e4SHarish Mahendrakar fprintf(o, "0x%02x, ", encryption->key_id[k]);
444*103e46e4SHarish Mahendrakar }
445*103e46e4SHarish Mahendrakar fprintf(o, "\n");
446*103e46e4SHarish Mahendrakar }
447*103e46e4SHarish Mahendrakar
448*103e46e4SHarish Mahendrakar if (encryption->signature_len > 0) {
449*103e46e4SHarish Mahendrakar fprintf(o, "%sContentSignature : 0x",
450*103e46e4SHarish Mahendrakar indent->indent_str().c_str());
451*103e46e4SHarish Mahendrakar for (int k = 0; k < encryption->signature_len; ++k) {
452*103e46e4SHarish Mahendrakar fprintf(o, "%x", encryption->signature[k]);
453*103e46e4SHarish Mahendrakar }
454*103e46e4SHarish Mahendrakar fprintf(o, "\n");
455*103e46e4SHarish Mahendrakar }
456*103e46e4SHarish Mahendrakar
457*103e46e4SHarish Mahendrakar if (encryption->sig_key_id_len > 0) {
458*103e46e4SHarish Mahendrakar fprintf(o, "%sContentSigKeyID : 0x",
459*103e46e4SHarish Mahendrakar indent->indent_str().c_str());
460*103e46e4SHarish Mahendrakar for (int k = 0; k < encryption->sig_key_id_len; ++k) {
461*103e46e4SHarish Mahendrakar fprintf(o, "%x", encryption->sig_key_id[k]);
462*103e46e4SHarish Mahendrakar }
463*103e46e4SHarish Mahendrakar fprintf(o, "\n");
464*103e46e4SHarish Mahendrakar }
465*103e46e4SHarish Mahendrakar
466*103e46e4SHarish Mahendrakar fprintf(o, "%sContentSigAlgo : %lld\n",
467*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), encryption->sig_algo);
468*103e46e4SHarish Mahendrakar fprintf(o, "%sContentSigHashAlgo : %lld\n",
469*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), encryption->sig_hash_algo);
470*103e46e4SHarish Mahendrakar
471*103e46e4SHarish Mahendrakar const ContentEncoding::ContentEncAESSettings& aes =
472*103e46e4SHarish Mahendrakar encryption->aes_settings;
473*103e46e4SHarish Mahendrakar fprintf(o, "%sCipherMode : %lld\n",
474*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), aes.cipher_mode);
475*103e46e4SHarish Mahendrakar }
476*103e46e4SHarish Mahendrakar }
477*103e46e4SHarish Mahendrakar
478*103e46e4SHarish Mahendrakar if (track_type == mkvparser::Track::kVideo) {
479*103e46e4SHarish Mahendrakar const mkvparser::VideoTrack* const video_track =
480*103e46e4SHarish Mahendrakar static_cast<const mkvparser::VideoTrack*>(track);
481*103e46e4SHarish Mahendrakar const int64_t width = video_track->GetWidth();
482*103e46e4SHarish Mahendrakar const int64_t height = video_track->GetHeight();
483*103e46e4SHarish Mahendrakar const int64_t display_width = video_track->GetDisplayWidth();
484*103e46e4SHarish Mahendrakar const int64_t display_height = video_track->GetDisplayHeight();
485*103e46e4SHarish Mahendrakar const int64_t display_unit = video_track->GetDisplayUnit();
486*103e46e4SHarish Mahendrakar const double frame_rate = video_track->GetFrameRate();
487*103e46e4SHarish Mahendrakar fprintf(o, "%sPixelWidth : %" PRId64 "\n", indent->indent_str().c_str(),
488*103e46e4SHarish Mahendrakar width);
489*103e46e4SHarish Mahendrakar fprintf(o, "%sPixelHeight : %" PRId64 "\n", indent->indent_str().c_str(),
490*103e46e4SHarish Mahendrakar height);
491*103e46e4SHarish Mahendrakar if (frame_rate > 0.0)
492*103e46e4SHarish Mahendrakar fprintf(o, "%sFrameRate : %g\n", indent->indent_str().c_str(),
493*103e46e4SHarish Mahendrakar video_track->GetFrameRate());
494*103e46e4SHarish Mahendrakar if (display_unit > 0 || display_width != width ||
495*103e46e4SHarish Mahendrakar display_height != height) {
496*103e46e4SHarish Mahendrakar fprintf(o, "%sDisplayWidth : %" PRId64 "\n",
497*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), display_width);
498*103e46e4SHarish Mahendrakar fprintf(o, "%sDisplayHeight : %" PRId64 "\n",
499*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), display_height);
500*103e46e4SHarish Mahendrakar fprintf(o, "%sDisplayUnit : %" PRId64 "\n",
501*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), display_unit);
502*103e46e4SHarish Mahendrakar }
503*103e46e4SHarish Mahendrakar
504*103e46e4SHarish Mahendrakar const mkvparser::Colour* const colour = video_track->GetColour();
505*103e46e4SHarish Mahendrakar if (colour) {
506*103e46e4SHarish Mahendrakar // TODO(fgalligan): Add support for Colour's address and size.
507*103e46e4SHarish Mahendrakar fprintf(o, "%sColour:\n", indent->indent_str().c_str());
508*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kIncreaseIndent);
509*103e46e4SHarish Mahendrakar
510*103e46e4SHarish Mahendrakar const int64_t matrix_coefficients = colour->matrix_coefficients;
511*103e46e4SHarish Mahendrakar const int64_t bits_per_channel = colour->bits_per_channel;
512*103e46e4SHarish Mahendrakar const int64_t chroma_subsampling_horz = colour->chroma_subsampling_horz;
513*103e46e4SHarish Mahendrakar const int64_t chroma_subsampling_vert = colour->chroma_subsampling_vert;
514*103e46e4SHarish Mahendrakar const int64_t cb_subsampling_horz = colour->cb_subsampling_horz;
515*103e46e4SHarish Mahendrakar const int64_t cb_subsampling_vert = colour->cb_subsampling_vert;
516*103e46e4SHarish Mahendrakar const int64_t chroma_siting_horz = colour->chroma_siting_horz;
517*103e46e4SHarish Mahendrakar const int64_t chroma_siting_vert = colour->chroma_siting_vert;
518*103e46e4SHarish Mahendrakar const int64_t range = colour->range;
519*103e46e4SHarish Mahendrakar const int64_t transfer_characteristics =
520*103e46e4SHarish Mahendrakar colour->transfer_characteristics;
521*103e46e4SHarish Mahendrakar const int64_t primaries = colour->primaries;
522*103e46e4SHarish Mahendrakar const int64_t max_cll = colour->max_cll;
523*103e46e4SHarish Mahendrakar const int64_t max_fall = colour->max_fall;
524*103e46e4SHarish Mahendrakar if (matrix_coefficients != mkvparser::Colour::kValueNotPresent)
525*103e46e4SHarish Mahendrakar fprintf(o, "%sMatrixCoefficients : %" PRId64 "\n",
526*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), matrix_coefficients);
527*103e46e4SHarish Mahendrakar if (bits_per_channel != mkvparser::Colour::kValueNotPresent)
528*103e46e4SHarish Mahendrakar fprintf(o, "%sBitsPerChannel : %" PRId64 "\n",
529*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), bits_per_channel);
530*103e46e4SHarish Mahendrakar if (chroma_subsampling_horz != mkvparser::Colour::kValueNotPresent)
531*103e46e4SHarish Mahendrakar fprintf(o, "%sChromaSubsamplingHorz : %" PRId64 "\n",
532*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), chroma_subsampling_horz);
533*103e46e4SHarish Mahendrakar if (chroma_subsampling_vert != mkvparser::Colour::kValueNotPresent)
534*103e46e4SHarish Mahendrakar fprintf(o, "%sChromaSubsamplingVert : %" PRId64 "\n",
535*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), chroma_subsampling_vert);
536*103e46e4SHarish Mahendrakar if (cb_subsampling_horz != mkvparser::Colour::kValueNotPresent)
537*103e46e4SHarish Mahendrakar fprintf(o, "%sCbSubsamplingHorz : %" PRId64 "\n",
538*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), cb_subsampling_horz);
539*103e46e4SHarish Mahendrakar if (cb_subsampling_vert != mkvparser::Colour::kValueNotPresent)
540*103e46e4SHarish Mahendrakar fprintf(o, "%sCbSubsamplingVert : %" PRId64 "\n",
541*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), cb_subsampling_vert);
542*103e46e4SHarish Mahendrakar if (chroma_siting_horz != mkvparser::Colour::kValueNotPresent)
543*103e46e4SHarish Mahendrakar fprintf(o, "%sChromaSitingHorz : %" PRId64 "\n",
544*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), chroma_siting_horz);
545*103e46e4SHarish Mahendrakar if (chroma_siting_vert != mkvparser::Colour::kValueNotPresent)
546*103e46e4SHarish Mahendrakar fprintf(o, "%sChromaSitingVert : %" PRId64 "\n",
547*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), chroma_siting_vert);
548*103e46e4SHarish Mahendrakar if (range != mkvparser::Colour::kValueNotPresent)
549*103e46e4SHarish Mahendrakar fprintf(o, "%sRange : %" PRId64 "\n",
550*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), range);
551*103e46e4SHarish Mahendrakar if (transfer_characteristics != mkvparser::Colour::kValueNotPresent)
552*103e46e4SHarish Mahendrakar fprintf(o, "%sTransferCharacteristics : %" PRId64 "\n",
553*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), transfer_characteristics);
554*103e46e4SHarish Mahendrakar if (primaries != mkvparser::Colour::kValueNotPresent)
555*103e46e4SHarish Mahendrakar fprintf(o, "%sPrimaries : %" PRId64 "\n",
556*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), primaries);
557*103e46e4SHarish Mahendrakar if (max_cll != mkvparser::Colour::kValueNotPresent)
558*103e46e4SHarish Mahendrakar fprintf(o, "%sMaxCLL : %" PRId64 "\n",
559*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), max_cll);
560*103e46e4SHarish Mahendrakar if (max_fall != mkvparser::Colour::kValueNotPresent)
561*103e46e4SHarish Mahendrakar fprintf(o, "%sMaxFALL : %" PRId64 "\n",
562*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), max_fall);
563*103e46e4SHarish Mahendrakar
564*103e46e4SHarish Mahendrakar const mkvparser::MasteringMetadata* const metadata =
565*103e46e4SHarish Mahendrakar colour->mastering_metadata;
566*103e46e4SHarish Mahendrakar if (metadata) {
567*103e46e4SHarish Mahendrakar // TODO(fgalligan): Add support for MasteringMetadata's address and
568*103e46e4SHarish Mahendrakar // size.
569*103e46e4SHarish Mahendrakar fprintf(o, "%sMasteringMetadata:\n", indent->indent_str().c_str());
570*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kIncreaseIndent);
571*103e46e4SHarish Mahendrakar
572*103e46e4SHarish Mahendrakar const mkvparser::PrimaryChromaticity* const red = metadata->r;
573*103e46e4SHarish Mahendrakar const mkvparser::PrimaryChromaticity* const green = metadata->g;
574*103e46e4SHarish Mahendrakar const mkvparser::PrimaryChromaticity* const blue = metadata->b;
575*103e46e4SHarish Mahendrakar const mkvparser::PrimaryChromaticity* const white =
576*103e46e4SHarish Mahendrakar metadata->white_point;
577*103e46e4SHarish Mahendrakar const float max = metadata->luminance_max;
578*103e46e4SHarish Mahendrakar const float min = metadata->luminance_min;
579*103e46e4SHarish Mahendrakar if (red) {
580*103e46e4SHarish Mahendrakar fprintf(o, "%sPrimaryRChromaticityX : %g\n",
581*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), red->x);
582*103e46e4SHarish Mahendrakar fprintf(o, "%sPrimaryRChromaticityY : %g\n",
583*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), red->y);
584*103e46e4SHarish Mahendrakar }
585*103e46e4SHarish Mahendrakar if (green) {
586*103e46e4SHarish Mahendrakar fprintf(o, "%sPrimaryGChromaticityX : %g\n",
587*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), green->x);
588*103e46e4SHarish Mahendrakar fprintf(o, "%sPrimaryGChromaticityY : %g\n",
589*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), green->y);
590*103e46e4SHarish Mahendrakar }
591*103e46e4SHarish Mahendrakar if (blue) {
592*103e46e4SHarish Mahendrakar fprintf(o, "%sPrimaryBChromaticityX : %g\n",
593*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), blue->x);
594*103e46e4SHarish Mahendrakar fprintf(o, "%sPrimaryBChromaticityY : %g\n",
595*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), blue->y);
596*103e46e4SHarish Mahendrakar }
597*103e46e4SHarish Mahendrakar if (white) {
598*103e46e4SHarish Mahendrakar fprintf(o, "%sWhitePointChromaticityX : %g\n",
599*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), white->x);
600*103e46e4SHarish Mahendrakar fprintf(o, "%sWhitePointChromaticityY : %g\n",
601*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), white->y);
602*103e46e4SHarish Mahendrakar }
603*103e46e4SHarish Mahendrakar if (max != mkvparser::MasteringMetadata::kValueNotPresent)
604*103e46e4SHarish Mahendrakar fprintf(o, "%sLuminanceMax : %g\n",
605*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), max);
606*103e46e4SHarish Mahendrakar if (min != mkvparser::MasteringMetadata::kValueNotPresent)
607*103e46e4SHarish Mahendrakar fprintf(o, "%sLuminanceMin : %g\n",
608*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), min);
609*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kDecreaseIndent);
610*103e46e4SHarish Mahendrakar }
611*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kDecreaseIndent);
612*103e46e4SHarish Mahendrakar }
613*103e46e4SHarish Mahendrakar
614*103e46e4SHarish Mahendrakar const mkvparser::Projection* const projection =
615*103e46e4SHarish Mahendrakar video_track->GetProjection();
616*103e46e4SHarish Mahendrakar if (projection) {
617*103e46e4SHarish Mahendrakar fprintf(o, "%sProjection:\n", indent->indent_str().c_str());
618*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kIncreaseIndent);
619*103e46e4SHarish Mahendrakar
620*103e46e4SHarish Mahendrakar const int projection_type = static_cast<int>(projection->type);
621*103e46e4SHarish Mahendrakar const int kTypeNotPresent =
622*103e46e4SHarish Mahendrakar static_cast<int>(mkvparser::Projection::kTypeNotPresent);
623*103e46e4SHarish Mahendrakar const float kValueNotPresent = mkvparser::Projection::kValueNotPresent;
624*103e46e4SHarish Mahendrakar if (projection_type != kTypeNotPresent)
625*103e46e4SHarish Mahendrakar fprintf(o, "%sProjectionType : %d\n",
626*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), projection_type);
627*103e46e4SHarish Mahendrakar if (projection->private_data)
628*103e46e4SHarish Mahendrakar fprintf(o, "%sProjectionPrivate(size) : %d\n",
629*103e46e4SHarish Mahendrakar indent->indent_str().c_str(),
630*103e46e4SHarish Mahendrakar static_cast<int>(projection->private_data_length));
631*103e46e4SHarish Mahendrakar if (projection->pose_yaw != kValueNotPresent)
632*103e46e4SHarish Mahendrakar fprintf(o, "%sProjectionPoseYaw : %g\n",
633*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), projection->pose_yaw);
634*103e46e4SHarish Mahendrakar if (projection->pose_pitch != kValueNotPresent)
635*103e46e4SHarish Mahendrakar fprintf(o, "%sProjectionPosePitch : %g\n",
636*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), projection->pose_pitch);
637*103e46e4SHarish Mahendrakar if (projection->pose_roll != kValueNotPresent)
638*103e46e4SHarish Mahendrakar fprintf(o, "%sProjectionPoseRoll : %g\n",
639*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), projection->pose_roll);
640*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kDecreaseIndent);
641*103e46e4SHarish Mahendrakar }
642*103e46e4SHarish Mahendrakar } else if (track_type == mkvparser::Track::kAudio) {
643*103e46e4SHarish Mahendrakar const mkvparser::AudioTrack* const audio_track =
644*103e46e4SHarish Mahendrakar static_cast<const mkvparser::AudioTrack*>(track);
645*103e46e4SHarish Mahendrakar const int64_t channels = audio_track->GetChannels();
646*103e46e4SHarish Mahendrakar const int64_t bit_depth = audio_track->GetBitDepth();
647*103e46e4SHarish Mahendrakar const uint64_t codec_delay = audio_track->GetCodecDelay();
648*103e46e4SHarish Mahendrakar const uint64_t seek_preroll = audio_track->GetSeekPreRoll();
649*103e46e4SHarish Mahendrakar fprintf(o, "%sChannels : %" PRId64 "\n",
650*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), channels);
651*103e46e4SHarish Mahendrakar if (bit_depth > 0)
652*103e46e4SHarish Mahendrakar fprintf(o, "%sBitDepth : %" PRId64 "\n",
653*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), bit_depth);
654*103e46e4SHarish Mahendrakar fprintf(o, "%sSamplingFrequency: %g\n", indent->indent_str().c_str(),
655*103e46e4SHarish Mahendrakar audio_track->GetSamplingRate());
656*103e46e4SHarish Mahendrakar if (codec_delay)
657*103e46e4SHarish Mahendrakar fprintf(o, "%sCodecDelay : %" PRIu64 "\n",
658*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), codec_delay);
659*103e46e4SHarish Mahendrakar if (seek_preroll)
660*103e46e4SHarish Mahendrakar fprintf(o, "%sSeekPreRoll : %" PRIu64 "\n",
661*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), seek_preroll);
662*103e46e4SHarish Mahendrakar }
663*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kDecreaseIndent * 2);
664*103e46e4SHarish Mahendrakar }
665*103e46e4SHarish Mahendrakar
666*103e46e4SHarish Mahendrakar return true;
667*103e46e4SHarish Mahendrakar }
668*103e46e4SHarish Mahendrakar
669*103e46e4SHarish Mahendrakar // libvpx reference: vp9/vp9_dx_iface.c
ParseSuperframeIndex(const uint8_t * data,size_t data_sz,uint32_t sizes[8],int * count)670*103e46e4SHarish Mahendrakar void ParseSuperframeIndex(const uint8_t* data, size_t data_sz,
671*103e46e4SHarish Mahendrakar uint32_t sizes[8], int* count) {
672*103e46e4SHarish Mahendrakar const uint8_t marker = data[data_sz - 1];
673*103e46e4SHarish Mahendrakar *count = 0;
674*103e46e4SHarish Mahendrakar
675*103e46e4SHarish Mahendrakar if ((marker & 0xe0) == 0xc0) {
676*103e46e4SHarish Mahendrakar const int frames = (marker & 0x7) + 1;
677*103e46e4SHarish Mahendrakar const int mag = ((marker >> 3) & 0x3) + 1;
678*103e46e4SHarish Mahendrakar const size_t index_sz = 2 + mag * frames;
679*103e46e4SHarish Mahendrakar
680*103e46e4SHarish Mahendrakar if (data_sz >= index_sz && data[data_sz - index_sz] == marker) {
681*103e46e4SHarish Mahendrakar // found a valid superframe index
682*103e46e4SHarish Mahendrakar const uint8_t* x = data + data_sz - index_sz + 1;
683*103e46e4SHarish Mahendrakar
684*103e46e4SHarish Mahendrakar for (int i = 0; i < frames; ++i) {
685*103e46e4SHarish Mahendrakar uint32_t this_sz = 0;
686*103e46e4SHarish Mahendrakar
687*103e46e4SHarish Mahendrakar for (int j = 0; j < mag; ++j) {
688*103e46e4SHarish Mahendrakar this_sz |= (*x++) << (j * 8);
689*103e46e4SHarish Mahendrakar }
690*103e46e4SHarish Mahendrakar sizes[i] = this_sz;
691*103e46e4SHarish Mahendrakar }
692*103e46e4SHarish Mahendrakar *count = frames;
693*103e46e4SHarish Mahendrakar }
694*103e46e4SHarish Mahendrakar }
695*103e46e4SHarish Mahendrakar }
696*103e46e4SHarish Mahendrakar
PrintVP9Info(const uint8_t * data,int size,FILE * o,int64_t time_ns,FrameStats * stats,vp9_parser::Vp9HeaderParser * parser,vp9_parser::Vp9LevelStats * level_stats)697*103e46e4SHarish Mahendrakar void PrintVP9Info(const uint8_t* data, int size, FILE* o, int64_t time_ns,
698*103e46e4SHarish Mahendrakar FrameStats* stats, vp9_parser::Vp9HeaderParser* parser,
699*103e46e4SHarish Mahendrakar vp9_parser::Vp9LevelStats* level_stats) {
700*103e46e4SHarish Mahendrakar if (size < 1)
701*103e46e4SHarish Mahendrakar return;
702*103e46e4SHarish Mahendrakar
703*103e46e4SHarish Mahendrakar uint32_t sizes[8];
704*103e46e4SHarish Mahendrakar int i = 0, count = 0;
705*103e46e4SHarish Mahendrakar ParseSuperframeIndex(data, size, sizes, &count);
706*103e46e4SHarish Mahendrakar
707*103e46e4SHarish Mahendrakar // Remove all frames that are less than window size.
708*103e46e4SHarish Mahendrakar while (!stats->window.empty() &&
709*103e46e4SHarish Mahendrakar stats->window.front() < (time_ns - (kNanosecondsPerSecondi - 1)))
710*103e46e4SHarish Mahendrakar stats->window.pop();
711*103e46e4SHarish Mahendrakar
712*103e46e4SHarish Mahendrakar do {
713*103e46e4SHarish Mahendrakar const size_t frame_length = (count > 0) ? sizes[i] : size;
714*103e46e4SHarish Mahendrakar if (frame_length > static_cast<size_t>(std::numeric_limits<int>::max()) ||
715*103e46e4SHarish Mahendrakar static_cast<int>(frame_length) > size) {
716*103e46e4SHarish Mahendrakar fprintf(o, " invalid VP9 frame size (%u)\n",
717*103e46e4SHarish Mahendrakar static_cast<uint32_t>(frame_length));
718*103e46e4SHarish Mahendrakar return;
719*103e46e4SHarish Mahendrakar }
720*103e46e4SHarish Mahendrakar if (!parser->ParseUncompressedHeader(data, frame_length))
721*103e46e4SHarish Mahendrakar return;
722*103e46e4SHarish Mahendrakar level_stats->AddFrame(*parser, time_ns);
723*103e46e4SHarish Mahendrakar
724*103e46e4SHarish Mahendrakar // const int frame_marker = (data[0] >> 6) & 0x3;
725*103e46e4SHarish Mahendrakar const int version = parser->profile();
726*103e46e4SHarish Mahendrakar const int key = parser->key();
727*103e46e4SHarish Mahendrakar const int altref_frame = parser->altref();
728*103e46e4SHarish Mahendrakar const int error_resilient_mode = parser->error_resilient_mode();
729*103e46e4SHarish Mahendrakar const int row_tiles = parser->row_tiles();
730*103e46e4SHarish Mahendrakar const int column_tiles = parser->column_tiles();
731*103e46e4SHarish Mahendrakar const int frame_parallel_mode = parser->frame_parallel_mode();
732*103e46e4SHarish Mahendrakar
733*103e46e4SHarish Mahendrakar if (key &&
734*103e46e4SHarish Mahendrakar !(size >= 4 && data[1] == 0x49 && data[2] == 0x83 && data[3] == 0x42)) {
735*103e46e4SHarish Mahendrakar fprintf(o, " invalid VP9 signature");
736*103e46e4SHarish Mahendrakar return;
737*103e46e4SHarish Mahendrakar }
738*103e46e4SHarish Mahendrakar
739*103e46e4SHarish Mahendrakar stats->window.push(time_ns);
740*103e46e4SHarish Mahendrakar ++stats->frames;
741*103e46e4SHarish Mahendrakar
742*103e46e4SHarish Mahendrakar if (altref_frame) {
743*103e46e4SHarish Mahendrakar const int delta_altref = stats->frames_since_last_altref;
744*103e46e4SHarish Mahendrakar if (stats->first_altref) {
745*103e46e4SHarish Mahendrakar stats->first_altref = false;
746*103e46e4SHarish Mahendrakar } else if (delta_altref < stats->minimum_altref_distance) {
747*103e46e4SHarish Mahendrakar stats->minimum_altref_distance = delta_altref;
748*103e46e4SHarish Mahendrakar stats->min_altref_end_ns = time_ns;
749*103e46e4SHarish Mahendrakar }
750*103e46e4SHarish Mahendrakar stats->frames_since_last_altref = 0;
751*103e46e4SHarish Mahendrakar } else {
752*103e46e4SHarish Mahendrakar ++stats->frames_since_last_altref;
753*103e46e4SHarish Mahendrakar ++stats->displayed_frames;
754*103e46e4SHarish Mahendrakar }
755*103e46e4SHarish Mahendrakar
756*103e46e4SHarish Mahendrakar if (count > 0) {
757*103e46e4SHarish Mahendrakar fprintf(o, " packed [%d]: {", i);
758*103e46e4SHarish Mahendrakar }
759*103e46e4SHarish Mahendrakar
760*103e46e4SHarish Mahendrakar fprintf(o, " key:%d v:%d altref:%d errm:%d rt:%d ct:%d fpm:%d", key,
761*103e46e4SHarish Mahendrakar version, altref_frame, error_resilient_mode, row_tiles,
762*103e46e4SHarish Mahendrakar column_tiles, frame_parallel_mode);
763*103e46e4SHarish Mahendrakar
764*103e46e4SHarish Mahendrakar if (key) {
765*103e46e4SHarish Mahendrakar if (size > 4) {
766*103e46e4SHarish Mahendrakar fprintf(o, " cs:%d", parser->color_space());
767*103e46e4SHarish Mahendrakar }
768*103e46e4SHarish Mahendrakar if (parser->display_width() != parser->width() ||
769*103e46e4SHarish Mahendrakar parser->display_height() != parser->height()) {
770*103e46e4SHarish Mahendrakar fprintf(o, " dw:%d dh:%d", parser->display_width(),
771*103e46e4SHarish Mahendrakar parser->display_height());
772*103e46e4SHarish Mahendrakar }
773*103e46e4SHarish Mahendrakar }
774*103e46e4SHarish Mahendrakar
775*103e46e4SHarish Mahendrakar if (count > 0) {
776*103e46e4SHarish Mahendrakar fprintf(o, " size: %u }", sizes[i]);
777*103e46e4SHarish Mahendrakar data += sizes[i];
778*103e46e4SHarish Mahendrakar size -= sizes[i];
779*103e46e4SHarish Mahendrakar }
780*103e46e4SHarish Mahendrakar ++i;
781*103e46e4SHarish Mahendrakar } while (i < count);
782*103e46e4SHarish Mahendrakar
783*103e46e4SHarish Mahendrakar if (stats->max_window_size < static_cast<int64_t>(stats->window.size())) {
784*103e46e4SHarish Mahendrakar stats->max_window_size = stats->window.size();
785*103e46e4SHarish Mahendrakar stats->max_window_end_ns = time_ns;
786*103e46e4SHarish Mahendrakar }
787*103e46e4SHarish Mahendrakar }
788*103e46e4SHarish Mahendrakar
PrintVP8Info(const uint8_t * data,int size,FILE * o)789*103e46e4SHarish Mahendrakar void PrintVP8Info(const uint8_t* data, int size, FILE* o) {
790*103e46e4SHarish Mahendrakar if (size < 3)
791*103e46e4SHarish Mahendrakar return;
792*103e46e4SHarish Mahendrakar
793*103e46e4SHarish Mahendrakar const uint32_t bits = data[0] | (data[1] << 8) | (data[2] << 16);
794*103e46e4SHarish Mahendrakar const int key = !(bits & 0x1);
795*103e46e4SHarish Mahendrakar const int altref_frame = !((bits >> 4) & 0x1);
796*103e46e4SHarish Mahendrakar const int version = (bits >> 1) & 0x7;
797*103e46e4SHarish Mahendrakar const int partition_length = (bits >> 5) & 0x7FFFF;
798*103e46e4SHarish Mahendrakar if (key &&
799*103e46e4SHarish Mahendrakar !(size >= 6 && data[3] == 0x9d && data[4] == 0x01 && data[5] == 0x2a)) {
800*103e46e4SHarish Mahendrakar fprintf(o, " invalid VP8 signature");
801*103e46e4SHarish Mahendrakar return;
802*103e46e4SHarish Mahendrakar }
803*103e46e4SHarish Mahendrakar fprintf(o, " key:%d v:%d altref:%d partition_length:%d", key, version,
804*103e46e4SHarish Mahendrakar altref_frame, partition_length);
805*103e46e4SHarish Mahendrakar }
806*103e46e4SHarish Mahendrakar
807*103e46e4SHarish Mahendrakar // Prints the partition offsets of the sub-sample encryption. |data| must point
808*103e46e4SHarish Mahendrakar // to an encrypted frame just after the signal byte. Returns the number of
809*103e46e4SHarish Mahendrakar // bytes read from the sub-sample partition information.
PrintSubSampleEncryption(const uint8_t * data,int size,FILE * o)810*103e46e4SHarish Mahendrakar int PrintSubSampleEncryption(const uint8_t* data, int size, FILE* o) {
811*103e46e4SHarish Mahendrakar int read_end = sizeof(uint64_t);
812*103e46e4SHarish Mahendrakar
813*103e46e4SHarish Mahendrakar // Skip past IV.
814*103e46e4SHarish Mahendrakar if (size < read_end)
815*103e46e4SHarish Mahendrakar return 0;
816*103e46e4SHarish Mahendrakar data += sizeof(uint64_t);
817*103e46e4SHarish Mahendrakar
818*103e46e4SHarish Mahendrakar // Read number of partitions.
819*103e46e4SHarish Mahendrakar read_end += sizeof(uint8_t);
820*103e46e4SHarish Mahendrakar if (size < read_end)
821*103e46e4SHarish Mahendrakar return 0;
822*103e46e4SHarish Mahendrakar const int num_partitions = data[0];
823*103e46e4SHarish Mahendrakar data += sizeof(uint8_t);
824*103e46e4SHarish Mahendrakar
825*103e46e4SHarish Mahendrakar // Read partitions.
826*103e46e4SHarish Mahendrakar for (int i = 0; i < num_partitions; ++i) {
827*103e46e4SHarish Mahendrakar read_end += sizeof(uint32_t);
828*103e46e4SHarish Mahendrakar if (size < read_end)
829*103e46e4SHarish Mahendrakar return 0;
830*103e46e4SHarish Mahendrakar uint32_t partition_offset;
831*103e46e4SHarish Mahendrakar memcpy(&partition_offset, data, sizeof(partition_offset));
832*103e46e4SHarish Mahendrakar partition_offset = libwebm::bigendian_to_host(partition_offset);
833*103e46e4SHarish Mahendrakar fprintf(o, " off[%d]:%u", i, partition_offset);
834*103e46e4SHarish Mahendrakar data += sizeof(uint32_t);
835*103e46e4SHarish Mahendrakar }
836*103e46e4SHarish Mahendrakar
837*103e46e4SHarish Mahendrakar return read_end;
838*103e46e4SHarish Mahendrakar }
839*103e46e4SHarish Mahendrakar
OutputCluster(const mkvparser::Cluster & cluster,const mkvparser::Tracks & tracks,const Options & options,FILE * o,mkvparser::MkvReader * reader,Indent * indent,int64_t * clusters_size,FrameStats * stats,vp9_parser::Vp9HeaderParser * parser,vp9_parser::Vp9LevelStats * level_stats)840*103e46e4SHarish Mahendrakar bool OutputCluster(const mkvparser::Cluster& cluster,
841*103e46e4SHarish Mahendrakar const mkvparser::Tracks& tracks, const Options& options,
842*103e46e4SHarish Mahendrakar FILE* o, mkvparser::MkvReader* reader, Indent* indent,
843*103e46e4SHarish Mahendrakar int64_t* clusters_size, FrameStats* stats,
844*103e46e4SHarish Mahendrakar vp9_parser::Vp9HeaderParser* parser,
845*103e46e4SHarish Mahendrakar vp9_parser::Vp9LevelStats* level_stats) {
846*103e46e4SHarish Mahendrakar if (clusters_size) {
847*103e46e4SHarish Mahendrakar // Load the Cluster.
848*103e46e4SHarish Mahendrakar const mkvparser::BlockEntry* block_entry;
849*103e46e4SHarish Mahendrakar long status = cluster.GetFirst(block_entry);
850*103e46e4SHarish Mahendrakar if (status) {
851*103e46e4SHarish Mahendrakar fprintf(stderr, "Could not get first Block of Cluster.\n");
852*103e46e4SHarish Mahendrakar return false;
853*103e46e4SHarish Mahendrakar }
854*103e46e4SHarish Mahendrakar
855*103e46e4SHarish Mahendrakar *clusters_size += cluster.GetElementSize();
856*103e46e4SHarish Mahendrakar }
857*103e46e4SHarish Mahendrakar
858*103e46e4SHarish Mahendrakar if (options.output_clusters) {
859*103e46e4SHarish Mahendrakar const int64_t time_ns = cluster.GetTime();
860*103e46e4SHarish Mahendrakar const int64_t duration_ns = cluster.GetLastTime() - cluster.GetFirstTime();
861*103e46e4SHarish Mahendrakar
862*103e46e4SHarish Mahendrakar fprintf(o, "%sCluster:", indent->indent_str().c_str());
863*103e46e4SHarish Mahendrakar if (options.output_offset)
864*103e46e4SHarish Mahendrakar fprintf(o, " @: %lld", cluster.m_element_start);
865*103e46e4SHarish Mahendrakar if (options.output_size)
866*103e46e4SHarish Mahendrakar fprintf(o, " size: %lld", cluster.GetElementSize());
867*103e46e4SHarish Mahendrakar fprintf(o, "\n");
868*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kIncreaseIndent);
869*103e46e4SHarish Mahendrakar if (options.output_seconds)
870*103e46e4SHarish Mahendrakar fprintf(o, "%sTimecode (sec) : %g\n", indent->indent_str().c_str(),
871*103e46e4SHarish Mahendrakar time_ns / kNanosecondsPerSecond);
872*103e46e4SHarish Mahendrakar else
873*103e46e4SHarish Mahendrakar fprintf(o, "%sTimecode (nano): %" PRId64 "\n",
874*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), time_ns);
875*103e46e4SHarish Mahendrakar if (options.output_seconds)
876*103e46e4SHarish Mahendrakar fprintf(o, "%sDuration (sec) : %g\n", indent->indent_str().c_str(),
877*103e46e4SHarish Mahendrakar duration_ns / kNanosecondsPerSecond);
878*103e46e4SHarish Mahendrakar else
879*103e46e4SHarish Mahendrakar fprintf(o, "%sDuration (nano): %" PRId64 "\n",
880*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), duration_ns);
881*103e46e4SHarish Mahendrakar
882*103e46e4SHarish Mahendrakar fprintf(o, "%s# Blocks : %ld\n", indent->indent_str().c_str(),
883*103e46e4SHarish Mahendrakar cluster.GetEntryCount());
884*103e46e4SHarish Mahendrakar }
885*103e46e4SHarish Mahendrakar
886*103e46e4SHarish Mahendrakar if (options.output_blocks) {
887*103e46e4SHarish Mahendrakar const mkvparser::BlockEntry* block_entry;
888*103e46e4SHarish Mahendrakar long status = cluster.GetFirst(block_entry);
889*103e46e4SHarish Mahendrakar if (status) {
890*103e46e4SHarish Mahendrakar fprintf(stderr, "Could not get first Block of Cluster.\n");
891*103e46e4SHarish Mahendrakar return false;
892*103e46e4SHarish Mahendrakar }
893*103e46e4SHarish Mahendrakar
894*103e46e4SHarish Mahendrakar std::vector<unsigned char> vector_data;
895*103e46e4SHarish Mahendrakar while (block_entry != NULL && !block_entry->EOS()) {
896*103e46e4SHarish Mahendrakar const mkvparser::Block* const block = block_entry->GetBlock();
897*103e46e4SHarish Mahendrakar if (!block) {
898*103e46e4SHarish Mahendrakar fprintf(stderr, "Could not getblock entry.\n");
899*103e46e4SHarish Mahendrakar return false;
900*103e46e4SHarish Mahendrakar }
901*103e46e4SHarish Mahendrakar
902*103e46e4SHarish Mahendrakar const unsigned int track_number =
903*103e46e4SHarish Mahendrakar static_cast<unsigned int>(block->GetTrackNumber());
904*103e46e4SHarish Mahendrakar const mkvparser::Track* track = tracks.GetTrackByNumber(track_number);
905*103e46e4SHarish Mahendrakar if (!track) {
906*103e46e4SHarish Mahendrakar fprintf(stderr, "Could not get Track.\n");
907*103e46e4SHarish Mahendrakar return false;
908*103e46e4SHarish Mahendrakar }
909*103e46e4SHarish Mahendrakar
910*103e46e4SHarish Mahendrakar const int64_t track_type = track->GetType();
911*103e46e4SHarish Mahendrakar if ((track_type == mkvparser::Track::kVideo && options.output_video) ||
912*103e46e4SHarish Mahendrakar (track_type == mkvparser::Track::kAudio && options.output_audio)) {
913*103e46e4SHarish Mahendrakar const int64_t time_ns = block->GetTime(&cluster);
914*103e46e4SHarish Mahendrakar const bool is_key = block->IsKey();
915*103e46e4SHarish Mahendrakar
916*103e46e4SHarish Mahendrakar if (block_entry->GetKind() == mkvparser::BlockEntry::kBlockGroup) {
917*103e46e4SHarish Mahendrakar fprintf(o, "%sBlockGroup:\n", indent->indent_str().c_str());
918*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kIncreaseIndent);
919*103e46e4SHarish Mahendrakar }
920*103e46e4SHarish Mahendrakar
921*103e46e4SHarish Mahendrakar fprintf(o, "%sBlock: type:%s frame:%s", indent->indent_str().c_str(),
922*103e46e4SHarish Mahendrakar track_type == mkvparser::Track::kVideo ? "V" : "A",
923*103e46e4SHarish Mahendrakar is_key ? "I" : "P");
924*103e46e4SHarish Mahendrakar if (options.output_seconds)
925*103e46e4SHarish Mahendrakar fprintf(o, " secs:%5g", time_ns / kNanosecondsPerSecond);
926*103e46e4SHarish Mahendrakar else
927*103e46e4SHarish Mahendrakar fprintf(o, " nano:%10" PRId64, time_ns);
928*103e46e4SHarish Mahendrakar
929*103e46e4SHarish Mahendrakar if (options.output_offset)
930*103e46e4SHarish Mahendrakar fprintf(o, " @_payload: %lld", block->m_start);
931*103e46e4SHarish Mahendrakar if (options.output_size)
932*103e46e4SHarish Mahendrakar fprintf(o, " size_payload: %lld", block->m_size);
933*103e46e4SHarish Mahendrakar
934*103e46e4SHarish Mahendrakar const uint8_t KEncryptedBit = 0x1;
935*103e46e4SHarish Mahendrakar const uint8_t kSubSampleBit = 0x2;
936*103e46e4SHarish Mahendrakar const int kSignalByteSize = 1;
937*103e46e4SHarish Mahendrakar bool encrypted_stream = false;
938*103e46e4SHarish Mahendrakar if (options.output_encrypted_info) {
939*103e46e4SHarish Mahendrakar if (track->GetContentEncodingCount() > 0) {
940*103e46e4SHarish Mahendrakar // Only check the first content encoding.
941*103e46e4SHarish Mahendrakar const ContentEncoding* const encoding =
942*103e46e4SHarish Mahendrakar track->GetContentEncodingByIndex(0);
943*103e46e4SHarish Mahendrakar if (encoding) {
944*103e46e4SHarish Mahendrakar if (encoding->GetEncryptionCount() > 0) {
945*103e46e4SHarish Mahendrakar const ContentEncoding::ContentEncryption* const encryption =
946*103e46e4SHarish Mahendrakar encoding->GetEncryptionByIndex(0);
947*103e46e4SHarish Mahendrakar if (encryption) {
948*103e46e4SHarish Mahendrakar const ContentEncoding::ContentEncAESSettings& aes =
949*103e46e4SHarish Mahendrakar encryption->aes_settings;
950*103e46e4SHarish Mahendrakar if (aes.cipher_mode == 1) {
951*103e46e4SHarish Mahendrakar encrypted_stream = true;
952*103e46e4SHarish Mahendrakar }
953*103e46e4SHarish Mahendrakar }
954*103e46e4SHarish Mahendrakar }
955*103e46e4SHarish Mahendrakar }
956*103e46e4SHarish Mahendrakar }
957*103e46e4SHarish Mahendrakar
958*103e46e4SHarish Mahendrakar if (encrypted_stream) {
959*103e46e4SHarish Mahendrakar const mkvparser::Block::Frame& frame = block->GetFrame(0);
960*103e46e4SHarish Mahendrakar if (frame.len > static_cast<int>(vector_data.size())) {
961*103e46e4SHarish Mahendrakar vector_data.resize(frame.len + 1024);
962*103e46e4SHarish Mahendrakar }
963*103e46e4SHarish Mahendrakar
964*103e46e4SHarish Mahendrakar unsigned char* data = &vector_data[0];
965*103e46e4SHarish Mahendrakar if (frame.Read(reader, data) < 0) {
966*103e46e4SHarish Mahendrakar fprintf(stderr, "Could not read frame.\n");
967*103e46e4SHarish Mahendrakar return false;
968*103e46e4SHarish Mahendrakar }
969*103e46e4SHarish Mahendrakar
970*103e46e4SHarish Mahendrakar const bool encrypted_frame = !!(data[0] & KEncryptedBit);
971*103e46e4SHarish Mahendrakar const bool sub_sample_encrypt = !!(data[0] & kSubSampleBit);
972*103e46e4SHarish Mahendrakar fprintf(o, " enc: %d", encrypted_frame ? 1 : 0);
973*103e46e4SHarish Mahendrakar fprintf(o, " sub: %d", sub_sample_encrypt ? 1 : 0);
974*103e46e4SHarish Mahendrakar
975*103e46e4SHarish Mahendrakar if (encrypted_frame) {
976*103e46e4SHarish Mahendrakar uint64_t iv;
977*103e46e4SHarish Mahendrakar memcpy(&iv, data + kSignalByteSize, sizeof(iv));
978*103e46e4SHarish Mahendrakar fprintf(o, " iv: %" PRIx64, iv);
979*103e46e4SHarish Mahendrakar }
980*103e46e4SHarish Mahendrakar }
981*103e46e4SHarish Mahendrakar }
982*103e46e4SHarish Mahendrakar
983*103e46e4SHarish Mahendrakar if (options.output_codec_info) {
984*103e46e4SHarish Mahendrakar const int frame_count = block->GetFrameCount();
985*103e46e4SHarish Mahendrakar
986*103e46e4SHarish Mahendrakar if (frame_count > 1) {
987*103e46e4SHarish Mahendrakar fprintf(o, "\n");
988*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kIncreaseIndent);
989*103e46e4SHarish Mahendrakar }
990*103e46e4SHarish Mahendrakar
991*103e46e4SHarish Mahendrakar for (int i = 0; i < frame_count; ++i) {
992*103e46e4SHarish Mahendrakar if (track_type == mkvparser::Track::kVideo) {
993*103e46e4SHarish Mahendrakar const mkvparser::Block::Frame& frame = block->GetFrame(i);
994*103e46e4SHarish Mahendrakar if (frame.len > static_cast<int>(vector_data.size())) {
995*103e46e4SHarish Mahendrakar vector_data.resize(frame.len + 1024);
996*103e46e4SHarish Mahendrakar }
997*103e46e4SHarish Mahendrakar
998*103e46e4SHarish Mahendrakar unsigned char* data = &vector_data[0];
999*103e46e4SHarish Mahendrakar if (frame.Read(reader, data) < 0) {
1000*103e46e4SHarish Mahendrakar fprintf(stderr, "Could not read frame.\n");
1001*103e46e4SHarish Mahendrakar return false;
1002*103e46e4SHarish Mahendrakar }
1003*103e46e4SHarish Mahendrakar
1004*103e46e4SHarish Mahendrakar if (frame_count > 1)
1005*103e46e4SHarish Mahendrakar fprintf(o, "\n%sVP8 data :", indent->indent_str().c_str());
1006*103e46e4SHarish Mahendrakar
1007*103e46e4SHarish Mahendrakar bool encrypted_frame = false;
1008*103e46e4SHarish Mahendrakar bool sub_sample_encrypt = false;
1009*103e46e4SHarish Mahendrakar int frame_size = static_cast<int>(frame.len);
1010*103e46e4SHarish Mahendrakar
1011*103e46e4SHarish Mahendrakar int frame_offset = 0;
1012*103e46e4SHarish Mahendrakar if (encrypted_stream) {
1013*103e46e4SHarish Mahendrakar if (data[0] & KEncryptedBit) {
1014*103e46e4SHarish Mahendrakar encrypted_frame = true;
1015*103e46e4SHarish Mahendrakar if (data[0] & kSubSampleBit) {
1016*103e46e4SHarish Mahendrakar sub_sample_encrypt = true;
1017*103e46e4SHarish Mahendrakar data += kSignalByteSize;
1018*103e46e4SHarish Mahendrakar frame_size -= kSignalByteSize;
1019*103e46e4SHarish Mahendrakar frame_offset =
1020*103e46e4SHarish Mahendrakar PrintSubSampleEncryption(data, frame_size, o);
1021*103e46e4SHarish Mahendrakar }
1022*103e46e4SHarish Mahendrakar } else {
1023*103e46e4SHarish Mahendrakar frame_offset = kSignalByteSize;
1024*103e46e4SHarish Mahendrakar }
1025*103e46e4SHarish Mahendrakar }
1026*103e46e4SHarish Mahendrakar
1027*103e46e4SHarish Mahendrakar if (!encrypted_frame || sub_sample_encrypt) {
1028*103e46e4SHarish Mahendrakar data += frame_offset;
1029*103e46e4SHarish Mahendrakar frame_size -= frame_offset;
1030*103e46e4SHarish Mahendrakar
1031*103e46e4SHarish Mahendrakar const string codec_id = ToString(track->GetCodecId());
1032*103e46e4SHarish Mahendrakar if (codec_id == "V_VP8") {
1033*103e46e4SHarish Mahendrakar PrintVP8Info(data, frame_size, o);
1034*103e46e4SHarish Mahendrakar } else if (codec_id == "V_VP9") {
1035*103e46e4SHarish Mahendrakar PrintVP9Info(data, frame_size, o, time_ns, stats, parser,
1036*103e46e4SHarish Mahendrakar level_stats);
1037*103e46e4SHarish Mahendrakar }
1038*103e46e4SHarish Mahendrakar }
1039*103e46e4SHarish Mahendrakar }
1040*103e46e4SHarish Mahendrakar }
1041*103e46e4SHarish Mahendrakar
1042*103e46e4SHarish Mahendrakar if (frame_count > 1)
1043*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kDecreaseIndent);
1044*103e46e4SHarish Mahendrakar }
1045*103e46e4SHarish Mahendrakar
1046*103e46e4SHarish Mahendrakar if (block_entry->GetKind() == mkvparser::BlockEntry::kBlockGroup) {
1047*103e46e4SHarish Mahendrakar const int64_t discard_padding = block->GetDiscardPadding();
1048*103e46e4SHarish Mahendrakar if (discard_padding != 0) {
1049*103e46e4SHarish Mahendrakar fprintf(o, "\n%sDiscardPadding: %10" PRId64,
1050*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), discard_padding);
1051*103e46e4SHarish Mahendrakar }
1052*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kDecreaseIndent);
1053*103e46e4SHarish Mahendrakar }
1054*103e46e4SHarish Mahendrakar
1055*103e46e4SHarish Mahendrakar fprintf(o, "\n");
1056*103e46e4SHarish Mahendrakar }
1057*103e46e4SHarish Mahendrakar
1058*103e46e4SHarish Mahendrakar status = cluster.GetNext(block_entry, block_entry);
1059*103e46e4SHarish Mahendrakar if (status) {
1060*103e46e4SHarish Mahendrakar printf("\n Could not get next block of cluster.\n");
1061*103e46e4SHarish Mahendrakar return false;
1062*103e46e4SHarish Mahendrakar }
1063*103e46e4SHarish Mahendrakar }
1064*103e46e4SHarish Mahendrakar }
1065*103e46e4SHarish Mahendrakar
1066*103e46e4SHarish Mahendrakar if (options.output_clusters)
1067*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kDecreaseIndent);
1068*103e46e4SHarish Mahendrakar
1069*103e46e4SHarish Mahendrakar return true;
1070*103e46e4SHarish Mahendrakar }
1071*103e46e4SHarish Mahendrakar
OutputCues(const mkvparser::Segment & segment,const mkvparser::Tracks & tracks,const Options & options,FILE * o,Indent * indent)1072*103e46e4SHarish Mahendrakar bool OutputCues(const mkvparser::Segment& segment,
1073*103e46e4SHarish Mahendrakar const mkvparser::Tracks& tracks, const Options& options,
1074*103e46e4SHarish Mahendrakar FILE* o, Indent* indent) {
1075*103e46e4SHarish Mahendrakar const mkvparser::Cues* const cues = segment.GetCues();
1076*103e46e4SHarish Mahendrakar if (cues == NULL)
1077*103e46e4SHarish Mahendrakar return true;
1078*103e46e4SHarish Mahendrakar
1079*103e46e4SHarish Mahendrakar // Load all of the cue points.
1080*103e46e4SHarish Mahendrakar while (!cues->DoneParsing())
1081*103e46e4SHarish Mahendrakar cues->LoadCuePoint();
1082*103e46e4SHarish Mahendrakar
1083*103e46e4SHarish Mahendrakar // Confirm that the input has cue points.
1084*103e46e4SHarish Mahendrakar const mkvparser::CuePoint* const first_cue = cues->GetFirst();
1085*103e46e4SHarish Mahendrakar if (first_cue == NULL) {
1086*103e46e4SHarish Mahendrakar fprintf(o, "%sNo cue points.\n", indent->indent_str().c_str());
1087*103e46e4SHarish Mahendrakar return true;
1088*103e46e4SHarish Mahendrakar }
1089*103e46e4SHarish Mahendrakar
1090*103e46e4SHarish Mahendrakar // Input has cue points, dump them:
1091*103e46e4SHarish Mahendrakar fprintf(o, "%sCues:", indent->indent_str().c_str());
1092*103e46e4SHarish Mahendrakar if (options.output_offset)
1093*103e46e4SHarish Mahendrakar fprintf(o, " @:%lld", cues->m_element_start);
1094*103e46e4SHarish Mahendrakar if (options.output_size)
1095*103e46e4SHarish Mahendrakar fprintf(o, " size:%lld", cues->m_element_size);
1096*103e46e4SHarish Mahendrakar fprintf(o, "\n");
1097*103e46e4SHarish Mahendrakar
1098*103e46e4SHarish Mahendrakar const mkvparser::CuePoint* cue_point = first_cue;
1099*103e46e4SHarish Mahendrakar int cue_point_num = 1;
1100*103e46e4SHarish Mahendrakar const int num_tracks = static_cast<int>(tracks.GetTracksCount());
1101*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kIncreaseIndent);
1102*103e46e4SHarish Mahendrakar
1103*103e46e4SHarish Mahendrakar do {
1104*103e46e4SHarish Mahendrakar for (int track_num = 0; track_num < num_tracks; ++track_num) {
1105*103e46e4SHarish Mahendrakar const mkvparser::Track* const track = tracks.GetTrackByIndex(track_num);
1106*103e46e4SHarish Mahendrakar const mkvparser::CuePoint::TrackPosition* const track_pos =
1107*103e46e4SHarish Mahendrakar cue_point->Find(track);
1108*103e46e4SHarish Mahendrakar
1109*103e46e4SHarish Mahendrakar if (track_pos != NULL) {
1110*103e46e4SHarish Mahendrakar const char track_type =
1111*103e46e4SHarish Mahendrakar (track->GetType() == mkvparser::Track::kVideo) ? 'V' : 'A';
1112*103e46e4SHarish Mahendrakar fprintf(o, "%sCue Point:%d type:%c track:%d",
1113*103e46e4SHarish Mahendrakar indent->indent_str().c_str(), cue_point_num, track_type,
1114*103e46e4SHarish Mahendrakar static_cast<int>(track->GetNumber()));
1115*103e46e4SHarish Mahendrakar
1116*103e46e4SHarish Mahendrakar if (options.output_seconds) {
1117*103e46e4SHarish Mahendrakar fprintf(o, " secs:%g",
1118*103e46e4SHarish Mahendrakar cue_point->GetTime(&segment) / kNanosecondsPerSecond);
1119*103e46e4SHarish Mahendrakar } else {
1120*103e46e4SHarish Mahendrakar fprintf(o, " nano:%lld", cue_point->GetTime(&segment));
1121*103e46e4SHarish Mahendrakar }
1122*103e46e4SHarish Mahendrakar
1123*103e46e4SHarish Mahendrakar if (options.output_blocks)
1124*103e46e4SHarish Mahendrakar fprintf(o, " block:%lld", track_pos->m_block);
1125*103e46e4SHarish Mahendrakar
1126*103e46e4SHarish Mahendrakar if (options.output_offset)
1127*103e46e4SHarish Mahendrakar fprintf(o, " @:%lld", track_pos->m_pos);
1128*103e46e4SHarish Mahendrakar
1129*103e46e4SHarish Mahendrakar fprintf(o, "\n");
1130*103e46e4SHarish Mahendrakar }
1131*103e46e4SHarish Mahendrakar }
1132*103e46e4SHarish Mahendrakar
1133*103e46e4SHarish Mahendrakar cue_point = cues->GetNext(cue_point);
1134*103e46e4SHarish Mahendrakar ++cue_point_num;
1135*103e46e4SHarish Mahendrakar } while (cue_point != NULL);
1136*103e46e4SHarish Mahendrakar
1137*103e46e4SHarish Mahendrakar indent->Adjust(libwebm::kDecreaseIndent);
1138*103e46e4SHarish Mahendrakar return true;
1139*103e46e4SHarish Mahendrakar }
1140*103e46e4SHarish Mahendrakar
1141*103e46e4SHarish Mahendrakar } // namespace
1142*103e46e4SHarish Mahendrakar
main(int argc,char * argv[])1143*103e46e4SHarish Mahendrakar int main(int argc, char* argv[]) {
1144*103e46e4SHarish Mahendrakar string input;
1145*103e46e4SHarish Mahendrakar Options options;
1146*103e46e4SHarish Mahendrakar
1147*103e46e4SHarish Mahendrakar const int argc_check = argc - 1;
1148*103e46e4SHarish Mahendrakar for (int i = 1; i < argc; ++i) {
1149*103e46e4SHarish Mahendrakar if (!strcmp("-h", argv[i]) || !strcmp("-?", argv[i])) {
1150*103e46e4SHarish Mahendrakar Usage();
1151*103e46e4SHarish Mahendrakar return EXIT_SUCCESS;
1152*103e46e4SHarish Mahendrakar } else if (!strcmp("-v", argv[i])) {
1153*103e46e4SHarish Mahendrakar printf("version: %s\n", VERSION_STRING);
1154*103e46e4SHarish Mahendrakar } else if (!strcmp("-i", argv[i]) && i < argc_check) {
1155*103e46e4SHarish Mahendrakar input = argv[++i];
1156*103e46e4SHarish Mahendrakar } else if (!strcmp("-all", argv[i])) {
1157*103e46e4SHarish Mahendrakar options.SetAll(true);
1158*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("video", argv[i])) {
1159*103e46e4SHarish Mahendrakar options.output_video = !strcmp("-video", argv[i]);
1160*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("audio", argv[i])) {
1161*103e46e4SHarish Mahendrakar options.output_audio = !strcmp("-audio", argv[i]);
1162*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("size", argv[i])) {
1163*103e46e4SHarish Mahendrakar options.output_size = !strcmp("-size", argv[i]);
1164*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("offset", argv[i])) {
1165*103e46e4SHarish Mahendrakar options.output_offset = !strcmp("-offset", argv[i]);
1166*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("times_seconds", argv[i])) {
1167*103e46e4SHarish Mahendrakar options.output_seconds = !strcmp("-times_seconds", argv[i]);
1168*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("ebml_header", argv[i])) {
1169*103e46e4SHarish Mahendrakar options.output_ebml_header = !strcmp("-ebml_header", argv[i]);
1170*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("segment", argv[i])) {
1171*103e46e4SHarish Mahendrakar options.output_segment = !strcmp("-segment", argv[i]);
1172*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("seekhead", argv[i])) {
1173*103e46e4SHarish Mahendrakar options.output_seekhead = !strcmp("-seekhead", argv[i]);
1174*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("segment_info", argv[i])) {
1175*103e46e4SHarish Mahendrakar options.output_segment_info = !strcmp("-segment_info", argv[i]);
1176*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("tracks", argv[i])) {
1177*103e46e4SHarish Mahendrakar options.output_tracks = !strcmp("-tracks", argv[i]);
1178*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("clusters", argv[i])) {
1179*103e46e4SHarish Mahendrakar options.output_clusters = !strcmp("-clusters", argv[i]);
1180*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("blocks", argv[i])) {
1181*103e46e4SHarish Mahendrakar options.output_blocks = !strcmp("-blocks", argv[i]);
1182*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("codec_info", argv[i])) {
1183*103e46e4SHarish Mahendrakar options.output_codec_info = !strcmp("-codec_info", argv[i]);
1184*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("clusters_size", argv[i])) {
1185*103e46e4SHarish Mahendrakar options.output_clusters_size = !strcmp("-clusters_size", argv[i]);
1186*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("encrypted_info", argv[i])) {
1187*103e46e4SHarish Mahendrakar options.output_encrypted_info = !strcmp("-encrypted_info", argv[i]);
1188*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("cues", argv[i])) {
1189*103e46e4SHarish Mahendrakar options.output_cues = !strcmp("-cues", argv[i]);
1190*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("frame_stats", argv[i])) {
1191*103e46e4SHarish Mahendrakar options.output_frame_stats = !strcmp("-frame_stats", argv[i]);
1192*103e46e4SHarish Mahendrakar } else if (Options::MatchesBooleanOption("vp9_level", argv[i])) {
1193*103e46e4SHarish Mahendrakar options.output_vp9_level = !strcmp("-vp9_level", argv[i]);
1194*103e46e4SHarish Mahendrakar }
1195*103e46e4SHarish Mahendrakar }
1196*103e46e4SHarish Mahendrakar
1197*103e46e4SHarish Mahendrakar if (argc < 3 || input.empty()) {
1198*103e46e4SHarish Mahendrakar Usage();
1199*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
1200*103e46e4SHarish Mahendrakar }
1201*103e46e4SHarish Mahendrakar
1202*103e46e4SHarish Mahendrakar std::unique_ptr<mkvparser::MkvReader> reader(
1203*103e46e4SHarish Mahendrakar new (std::nothrow) mkvparser::MkvReader()); // NOLINT
1204*103e46e4SHarish Mahendrakar if (reader->Open(input.c_str())) {
1205*103e46e4SHarish Mahendrakar fprintf(stderr, "Error opening file:%s\n", input.c_str());
1206*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
1207*103e46e4SHarish Mahendrakar }
1208*103e46e4SHarish Mahendrakar
1209*103e46e4SHarish Mahendrakar long long int pos = 0;
1210*103e46e4SHarish Mahendrakar std::unique_ptr<mkvparser::EBMLHeader> ebml_header(
1211*103e46e4SHarish Mahendrakar new (std::nothrow) mkvparser::EBMLHeader()); // NOLINT
1212*103e46e4SHarish Mahendrakar if (ebml_header->Parse(reader.get(), pos) < 0) {
1213*103e46e4SHarish Mahendrakar fprintf(stderr, "Error parsing EBML header.\n");
1214*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
1215*103e46e4SHarish Mahendrakar }
1216*103e46e4SHarish Mahendrakar
1217*103e46e4SHarish Mahendrakar Indent indent(0);
1218*103e46e4SHarish Mahendrakar FILE* out = stdout;
1219*103e46e4SHarish Mahendrakar
1220*103e46e4SHarish Mahendrakar if (options.output_ebml_header)
1221*103e46e4SHarish Mahendrakar OutputEBMLHeader(*ebml_header.get(), out, &indent);
1222*103e46e4SHarish Mahendrakar
1223*103e46e4SHarish Mahendrakar mkvparser::Segment* temp_segment;
1224*103e46e4SHarish Mahendrakar if (mkvparser::Segment::CreateInstance(reader.get(), pos, temp_segment)) {
1225*103e46e4SHarish Mahendrakar fprintf(stderr, "Segment::CreateInstance() failed.\n");
1226*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
1227*103e46e4SHarish Mahendrakar }
1228*103e46e4SHarish Mahendrakar std::unique_ptr<mkvparser::Segment> segment(temp_segment);
1229*103e46e4SHarish Mahendrakar
1230*103e46e4SHarish Mahendrakar if (segment->Load() < 0) {
1231*103e46e4SHarish Mahendrakar fprintf(stderr, "Segment::Load() failed.\n");
1232*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
1233*103e46e4SHarish Mahendrakar }
1234*103e46e4SHarish Mahendrakar
1235*103e46e4SHarish Mahendrakar if (options.output_segment) {
1236*103e46e4SHarish Mahendrakar OutputSegment(*(segment.get()), options, out);
1237*103e46e4SHarish Mahendrakar indent.Adjust(libwebm::kIncreaseIndent);
1238*103e46e4SHarish Mahendrakar }
1239*103e46e4SHarish Mahendrakar
1240*103e46e4SHarish Mahendrakar if (options.output_seekhead)
1241*103e46e4SHarish Mahendrakar if (!OutputSeekHead(*(segment.get()), options, out, &indent))
1242*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
1243*103e46e4SHarish Mahendrakar
1244*103e46e4SHarish Mahendrakar if (options.output_segment_info)
1245*103e46e4SHarish Mahendrakar if (!OutputSegmentInfo(*(segment.get()), options, out, &indent))
1246*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
1247*103e46e4SHarish Mahendrakar
1248*103e46e4SHarish Mahendrakar if (options.output_tracks)
1249*103e46e4SHarish Mahendrakar if (!OutputTracks(*(segment.get()), options, out, &indent))
1250*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
1251*103e46e4SHarish Mahendrakar
1252*103e46e4SHarish Mahendrakar const mkvparser::Tracks* const tracks = segment->GetTracks();
1253*103e46e4SHarish Mahendrakar if (!tracks) {
1254*103e46e4SHarish Mahendrakar fprintf(stderr, "Could not get Tracks.\n");
1255*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
1256*103e46e4SHarish Mahendrakar }
1257*103e46e4SHarish Mahendrakar
1258*103e46e4SHarish Mahendrakar // If Cues are before the clusters output them first.
1259*103e46e4SHarish Mahendrakar if (options.output_cues) {
1260*103e46e4SHarish Mahendrakar const mkvparser::Cluster* cluster = segment->GetFirst();
1261*103e46e4SHarish Mahendrakar const mkvparser::Cues* const cues = segment->GetCues();
1262*103e46e4SHarish Mahendrakar if (cluster != NULL && cues != NULL) {
1263*103e46e4SHarish Mahendrakar if (cues->m_element_start < cluster->m_element_start) {
1264*103e46e4SHarish Mahendrakar if (!OutputCues(*segment, *tracks, options, out, &indent)) {
1265*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
1266*103e46e4SHarish Mahendrakar }
1267*103e46e4SHarish Mahendrakar options.output_cues = false;
1268*103e46e4SHarish Mahendrakar }
1269*103e46e4SHarish Mahendrakar }
1270*103e46e4SHarish Mahendrakar }
1271*103e46e4SHarish Mahendrakar
1272*103e46e4SHarish Mahendrakar if (options.output_clusters)
1273*103e46e4SHarish Mahendrakar fprintf(out, "%sClusters (count):%ld\n", indent.indent_str().c_str(),
1274*103e46e4SHarish Mahendrakar segment->GetCount());
1275*103e46e4SHarish Mahendrakar
1276*103e46e4SHarish Mahendrakar int64_t clusters_size = 0;
1277*103e46e4SHarish Mahendrakar FrameStats stats;
1278*103e46e4SHarish Mahendrakar vp9_parser::Vp9HeaderParser parser;
1279*103e46e4SHarish Mahendrakar vp9_parser::Vp9LevelStats level_stats;
1280*103e46e4SHarish Mahendrakar const mkvparser::Cluster* cluster = segment->GetFirst();
1281*103e46e4SHarish Mahendrakar while (cluster != NULL && !cluster->EOS()) {
1282*103e46e4SHarish Mahendrakar if (!OutputCluster(*cluster, *tracks, options, out, reader.get(), &indent,
1283*103e46e4SHarish Mahendrakar &clusters_size, &stats, &parser, &level_stats))
1284*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
1285*103e46e4SHarish Mahendrakar cluster = segment->GetNext(cluster);
1286*103e46e4SHarish Mahendrakar }
1287*103e46e4SHarish Mahendrakar
1288*103e46e4SHarish Mahendrakar if (options.output_clusters_size)
1289*103e46e4SHarish Mahendrakar fprintf(out, "%sClusters (size):%" PRId64 "\n", indent.indent_str().c_str(),
1290*103e46e4SHarish Mahendrakar clusters_size);
1291*103e46e4SHarish Mahendrakar
1292*103e46e4SHarish Mahendrakar if (options.output_cues)
1293*103e46e4SHarish Mahendrakar if (!OutputCues(*segment, *tracks, options, out, &indent))
1294*103e46e4SHarish Mahendrakar return EXIT_FAILURE;
1295*103e46e4SHarish Mahendrakar
1296*103e46e4SHarish Mahendrakar // TODO(fgalligan): Add support for VP8.
1297*103e46e4SHarish Mahendrakar if (options.output_frame_stats &&
1298*103e46e4SHarish Mahendrakar stats.minimum_altref_distance != std::numeric_limits<int>::max()) {
1299*103e46e4SHarish Mahendrakar const double actual_fps =
1300*103e46e4SHarish Mahendrakar stats.frames /
1301*103e46e4SHarish Mahendrakar (segment->GetInfo()->GetDuration() / kNanosecondsPerSecond);
1302*103e46e4SHarish Mahendrakar const double displayed_fps =
1303*103e46e4SHarish Mahendrakar stats.displayed_frames /
1304*103e46e4SHarish Mahendrakar (segment->GetInfo()->GetDuration() / kNanosecondsPerSecond);
1305*103e46e4SHarish Mahendrakar fprintf(out, "\nActual fps:%g Displayed fps:%g\n", actual_fps,
1306*103e46e4SHarish Mahendrakar displayed_fps);
1307*103e46e4SHarish Mahendrakar
1308*103e46e4SHarish Mahendrakar fprintf(out, "Minimum Altref Distance:%d at:%g seconds\n",
1309*103e46e4SHarish Mahendrakar stats.minimum_altref_distance,
1310*103e46e4SHarish Mahendrakar stats.min_altref_end_ns / kNanosecondsPerSecond);
1311*103e46e4SHarish Mahendrakar
1312*103e46e4SHarish Mahendrakar // TODO(fgalligan): Add support for window duration other than 1 second.
1313*103e46e4SHarish Mahendrakar const double sec_end = stats.max_window_end_ns / kNanosecondsPerSecond;
1314*103e46e4SHarish Mahendrakar const double sec_start =
1315*103e46e4SHarish Mahendrakar stats.max_window_end_ns > kNanosecondsPerSecondi ? sec_end - 1.0 : 0.0;
1316*103e46e4SHarish Mahendrakar fprintf(out, "Maximum Window:%g-%g seconds Window fps:%" PRId64 "\n",
1317*103e46e4SHarish Mahendrakar sec_start, sec_end, stats.max_window_size);
1318*103e46e4SHarish Mahendrakar }
1319*103e46e4SHarish Mahendrakar
1320*103e46e4SHarish Mahendrakar if (options.output_vp9_level) {
1321*103e46e4SHarish Mahendrakar level_stats.set_duration(segment->GetInfo()->GetDuration());
1322*103e46e4SHarish Mahendrakar const vp9_parser::Vp9Level level = level_stats.GetLevel();
1323*103e46e4SHarish Mahendrakar fprintf(out, "VP9 Level:%d\n", level);
1324*103e46e4SHarish Mahendrakar fprintf(
1325*103e46e4SHarish Mahendrakar out,
1326*103e46e4SHarish Mahendrakar "mlsr:%" PRId64 " mlps:%" PRId64 " mlpb:%" PRId64
1327*103e46e4SHarish Mahendrakar " abr:%g mcs:%g cr:%g mct:%d"
1328*103e46e4SHarish Mahendrakar " mad:%d mrf:%d\n",
1329*103e46e4SHarish Mahendrakar level_stats.GetMaxLumaSampleRate(), level_stats.GetMaxLumaPictureSize(),
1330*103e46e4SHarish Mahendrakar level_stats.GetMaxLumaPictureBreadth(), level_stats.GetAverageBitRate(),
1331*103e46e4SHarish Mahendrakar level_stats.GetMaxCpbSize(), level_stats.GetCompressionRatio(),
1332*103e46e4SHarish Mahendrakar level_stats.GetMaxColumnTiles(), level_stats.GetMinimumAltrefDistance(),
1333*103e46e4SHarish Mahendrakar level_stats.GetMaxReferenceFrames());
1334*103e46e4SHarish Mahendrakar }
1335*103e46e4SHarish Mahendrakar return EXIT_SUCCESS;
1336*103e46e4SHarish Mahendrakar }
1337