webm/webm_parser/demo/demo.cc
Tom Finegan d518128266 webm_parser: Enable usage of werror.
Mass warning clean up. Mainly:
- Explicit casts of numeric literals to avoid signed/unsigned compare
  warnings.
- Commenting out of unused function arg names.

Change-Id: I0e70393a5743ae984035d43712c724d4ccd12f9d
2016-08-10 08:56:57 -07:00

1126 lines
41 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#include <cstdio>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include "webm/callback.h"
#include "webm/file_reader.h"
#include "webm/status.h"
#include "webm/webm_parser.h"
// We use pretty much everything in the webm namespace. Just pull
// it all in.
using namespace webm; // NOLINT
template <typename T>
std::ostream& PrintUnknownEnumValue(std::ostream& os, T value) {
return os << std::to_string(static_cast<std::uint64_t>(value)) << " (?)";
}
// Overloads for operator<< for pretty printing enums.
std::ostream& operator<<(std::ostream& os, Id id) {
switch (id) {
case Id::kEbml:
return os << "EBML";
case Id::kEbmlVersion:
return os << "EBMLVersion";
case Id::kEbmlReadVersion:
return os << "EBMLReadVersion";
case Id::kEbmlMaxIdLength:
return os << "EBMLMaxIDLength";
case Id::kEbmlMaxSizeLength:
return os << "EBMLMaxSizeLength";
case Id::kDocType:
return os << "DocType";
case Id::kDocTypeVersion:
return os << "DocTypeVersion";
case Id::kDocTypeReadVersion:
return os << "DocTypeReadVersion";
case Id::kVoid:
return os << "Void";
case Id::kSegment:
return os << "Segment";
case Id::kSeekHead:
return os << "SeekHead";
case Id::kSeek:
return os << "Seek";
case Id::kSeekId:
return os << "SeekID";
case Id::kSeekPosition:
return os << "SeekPosition";
case Id::kInfo:
return os << "Info";
case Id::kTimecodeScale:
return os << "TimecodeScale";
case Id::kDuration:
return os << "Duration";
case Id::kDateUtc:
return os << "DateUTC";
case Id::kTitle:
return os << "Title";
case Id::kMuxingApp:
return os << "MuxingApp";
case Id::kWritingApp:
return os << "WritingApp";
case Id::kCluster:
return os << "Cluster";
case Id::kTimecode:
return os << "Timecode";
case Id::kPrevSize:
return os << "PrevSize";
case Id::kSimpleBlock:
return os << "SimpleBlock";
case Id::kBlockGroup:
return os << "BlockGroup";
case Id::kBlock:
return os << "Block";
case Id::kBlockVirtual:
return os << "BlockVirtual";
case Id::kBlockAdditions:
return os << "BlockAdditions";
case Id::kBlockMore:
return os << "BlockMore";
case Id::kBlockAddId:
return os << "BlockAddID";
case Id::kBlockAdditional:
return os << "BlockAdditional";
case Id::kBlockDuration:
return os << "BlockDuration";
case Id::kReferenceBlock:
return os << "ReferenceBlock";
case Id::kDiscardPadding:
return os << "DiscardPadding";
case Id::kSlices:
return os << "Slices";
case Id::kTimeSlice:
return os << "TimeSlice";
case Id::kLaceNumber:
return os << "LaceNumber";
case Id::kTracks:
return os << "Tracks";
case Id::kTrackEntry:
return os << "TrackEntry";
case Id::kTrackNumber:
return os << "TrackNumber";
case Id::kTrackUid:
return os << "TrackUID";
case Id::kTrackType:
return os << "TrackType";
case Id::kFlagEnabled:
return os << "FlagEnabled";
case Id::kFlagDefault:
return os << "FlagDefault";
case Id::kFlagForced:
return os << "FlagForced";
case Id::kFlagLacing:
return os << "FlagLacing";
case Id::kDefaultDuration:
return os << "DefaultDuration";
case Id::kName:
return os << "Name";
case Id::kLanguage:
return os << "Language";
case Id::kCodecId:
return os << "CodecID";
case Id::kCodecPrivate:
return os << "CodecPrivate";
case Id::kCodecName:
return os << "CodecName";
case Id::kCodecDelay:
return os << "CodecDelay";
case Id::kSeekPreRoll:
return os << "SeekPreRoll";
case Id::kVideo:
return os << "Video";
case Id::kFlagInterlaced:
return os << "FlagInterlaced";
case Id::kStereoMode:
return os << "StereoMode";
case Id::kAlphaMode:
return os << "AlphaMode";
case Id::kPixelWidth:
return os << "PixelWidth";
case Id::kPixelHeight:
return os << "PixelHeight";
case Id::kPixelCropBottom:
return os << "PixelCropBottom";
case Id::kPixelCropTop:
return os << "PixelCropTop";
case Id::kPixelCropLeft:
return os << "PixelCropLeft";
case Id::kPixelCropRight:
return os << "PixelCropRight";
case Id::kDisplayWidth:
return os << "DisplayWidth";
case Id::kDisplayHeight:
return os << "DisplayHeight";
case Id::kDisplayUnit:
return os << "DisplayUnit";
case Id::kAspectRatioType:
return os << "AspectRatioType";
case Id::kFrameRate:
return os << "FrameRate";
case Id::kColour:
return os << "Colour";
case Id::kMatrixCoefficients:
return os << "MatrixCoefficients";
case Id::kBitsPerChannel:
return os << "BitsPerChannel";
case Id::kChromaSubsamplingHorz:
return os << "ChromaSubsamplingHorz";
case Id::kChromaSubsamplingVert:
return os << "ChromaSubsamplingVert";
case Id::kCbSubsamplingHorz:
return os << "CbSubsamplingHorz";
case Id::kCbSubsamplingVert:
return os << "CbSubsamplingVert";
case Id::kChromaSitingHorz:
return os << "ChromaSitingHorz";
case Id::kChromaSitingVert:
return os << "ChromaSitingVert";
case Id::kRange:
return os << "Range";
case Id::kTransferCharacteristics:
return os << "TransferCharacteristics";
case Id::kPrimaries:
return os << "Primaries";
case Id::kMaxCll:
return os << "MaxCLL";
case Id::kMaxFall:
return os << "MaxFALL";
case Id::kMasteringMetadata:
return os << "MasteringMetadata";
case Id::kPrimaryRChromaticityX:
return os << "PrimaryRChromaticityX";
case Id::kPrimaryRChromaticityY:
return os << "PrimaryRChromaticityY";
case Id::kPrimaryGChromaticityX:
return os << "PrimaryGChromaticityX";
case Id::kPrimaryGChromaticityY:
return os << "PrimaryGChromaticityY";
case Id::kPrimaryBChromaticityX:
return os << "PrimaryBChromaticityX";
case Id::kPrimaryBChromaticityY:
return os << "PrimaryBChromaticityY";
case Id::kWhitePointChromaticityX:
return os << "WhitePointChromaticityX";
case Id::kWhitePointChromaticityY:
return os << "WhitePointChromaticityY";
case Id::kLuminanceMax:
return os << "LuminanceMax";
case Id::kLuminanceMin:
return os << "LuminanceMin";
case Id::kAudio:
return os << "Audio";
case Id::kSamplingFrequency:
return os << "SamplingFrequency";
case Id::kOutputSamplingFrequency:
return os << "OutputSamplingFrequency";
case Id::kChannels:
return os << "Channels";
case Id::kBitDepth:
return os << "BitDepth";
case Id::kContentEncodings:
return os << "ContentEncodings";
case Id::kContentEncoding:
return os << "ContentEncoding";
case Id::kContentEncodingOrder:
return os << "ContentEncodingOrder";
case Id::kContentEncodingScope:
return os << "ContentEncodingScope";
case Id::kContentEncodingType:
return os << "ContentEncodingType";
case Id::kContentEncryption:
return os << "ContentEncryption";
case Id::kContentEncAlgo:
return os << "ContentEncAlgo";
case Id::kContentEncKeyId:
return os << "ContentEncKeyID";
case Id::kContentEncAesSettings:
return os << "ContentEncAESSettings";
case Id::kAesSettingsCipherMode:
return os << "AESSettingsCipherMode";
case Id::kCues:
return os << "Cues";
case Id::kCuePoint:
return os << "CuePoint";
case Id::kCueTime:
return os << "CueTime";
case Id::kCueTrackPositions:
return os << "CueTrackPositions";
case Id::kCueTrack:
return os << "CueTrack";
case Id::kCueClusterPosition:
return os << "CueClusterPosition";
case Id::kCueRelativePosition:
return os << "CueRelativePosition";
case Id::kCueDuration:
return os << "CueDuration";
case Id::kCueBlockNumber:
return os << "CueBlockNumber";
case Id::kChapters:
return os << "Chapters";
case Id::kEditionEntry:
return os << "EditionEntry";
case Id::kChapterAtom:
return os << "ChapterAtom";
case Id::kChapterUid:
return os << "ChapterUID";
case Id::kChapterStringUid:
return os << "ChapterStringUID";
case Id::kChapterTimeStart:
return os << "ChapterTimeStart";
case Id::kChapterTimeEnd:
return os << "ChapterTimeEnd";
case Id::kChapterDisplay:
return os << "ChapterDisplay";
case Id::kChapString:
return os << "ChapString";
case Id::kChapLanguage:
return os << "ChapLanguage";
case Id::kChapCountry:
return os << "ChapCountry";
case Id::kTags:
return os << "Tags";
case Id::kTag:
return os << "Tag";
case Id::kTargets:
return os << "Targets";
case Id::kTargetTypeValue:
return os << "TargetTypeValue";
case Id::kTargetType:
return os << "TargetType";
case Id::kTagTrackUid:
return os << "TagTrackUID";
case Id::kSimpleTag:
return os << "SimpleTag";
case Id::kTagName:
return os << "TagName";
case Id::kTagLanguage:
return os << "TagLanguage";
case Id::kTagDefault:
return os << "TagDefault";
case Id::kTagString:
return os << "TagString";
case Id::kTagBinary:
return os << "TagBinary";
default:
return PrintUnknownEnumValue(os, id);
}
}
std::ostream& operator<<(std::ostream& os, Lacing value) {
switch (value) {
case Lacing::kNone:
return os << "0 (none)";
case Lacing::kXiph:
return os << "2 (Xiph)";
case Lacing::kFixed:
return os << "4 (fixed)";
case Lacing::kEbml:
return os << "6 (EBML)";
default:
return PrintUnknownEnumValue(os, value);
}
}
std::ostream& operator<<(std::ostream& os, MatrixCoefficients value) {
switch (value) {
case MatrixCoefficients::kRgb:
return os << "0 (identity, RGB/XYZ)";
case MatrixCoefficients::kBt709:
return os << "1 (Rec. ITU-R BT.709-5)";
case MatrixCoefficients::kUnspecified:
return os << "2 (unspecified)";
case MatrixCoefficients::kFcc:
return os << "4 (US FCC)";
case MatrixCoefficients::kBt470Bg:
return os << "5 (Rec. ITU-R BT.470-6 System B, G)";
case MatrixCoefficients::kSmpte170M:
return os << "6 (SMPTE 170M)";
case MatrixCoefficients::kSmpte240M:
return os << "7 (SMPTE 240M)";
case MatrixCoefficients::kYCgCo:
return os << "8 (YCgCo)";
case MatrixCoefficients::kBt2020NonconstantLuminance:
return os << "9 (Rec. ITU-R BT.2020, non-constant luma)";
case MatrixCoefficients::kBt2020ConstantLuminance:
return os << "10 (Rec. ITU-R BT.2020 , constant luma)";
default:
return PrintUnknownEnumValue(os, value);
}
}
std::ostream& operator<<(std::ostream& os, Range value) {
switch (value) {
case Range::kUnspecified:
return os << "0 (unspecified)";
case Range::kBroadcast:
return os << "1 (broadcast)";
case Range::kFull:
return os << "2 (full)";
case Range::kDerived:
return os << "3 (defined by MatrixCoefficients/TransferCharacteristics)";
default:
return PrintUnknownEnumValue(os, value);
}
}
std::ostream& operator<<(std::ostream& os, TransferCharacteristics value) {
switch (value) {
case TransferCharacteristics::kBt709:
return os << "1 (Rec. ITU-R BT.709-6)";
case TransferCharacteristics::kUnspecified:
return os << "2 (unspecified)";
case TransferCharacteristics::kGamma22curve:
return os << "4 (gamma 2.2, Rec. ITUR BT.4706 System M)";
case TransferCharacteristics::kGamma28curve:
return os << "5 (gamma 2.8, Rec. ITUR BT.470-6 System B, G)";
case TransferCharacteristics::kSmpte170M:
return os << "6 (SMPTE 170M)";
case TransferCharacteristics::kSmpte240M:
return os << "7 (SMPTE 240M)";
case TransferCharacteristics::kLinear:
return os << "8 (linear)";
case TransferCharacteristics::kLog:
return os << "9 (log, 100:1 range)";
case TransferCharacteristics::kLogSqrt:
return os << "10 (log, 316.2:1 range)";
case TransferCharacteristics::kIec6196624:
return os << "11 (IEC 61966-2-4)";
case TransferCharacteristics::kBt1361ExtendedColourGamut:
return os << "12 (Rec. ITU-R BT.1361, extended colour gamut)";
case TransferCharacteristics::kIec6196621:
return os << "13 (IEC 61966-2-1, sRGB or sYCC)";
case TransferCharacteristics::k10BitBt2020:
return os << "14 (Rec. ITU-R BT.2020-2, 10-bit)";
case TransferCharacteristics::k12BitBt2020:
return os << "15 (Rec. ITU-R BT.2020-2, 12-bit)";
case TransferCharacteristics::kSmpteSt2084:
return os << "16 (SMPTE ST 2084)";
case TransferCharacteristics::kSmpteSt4281:
return os << "17 (SMPTE ST 428-1)";
case TransferCharacteristics::kAribStdB67Hlg:
return os << "18 (ARIB STD-B67/Rec. ITU-R BT.[HDR-TV] HLG)";
default:
return PrintUnknownEnumValue(os, value);
}
}
std::ostream& operator<<(std::ostream& os, Primaries value) {
switch (value) {
case Primaries::kBt709:
return os << "1 (Rec. ITUR BT.709-6)";
case Primaries::kUnspecified:
return os << "2 (unspecified)";
case Primaries::kBt470M:
return os << "4 (Rec. ITUR BT.4706 System M)";
case Primaries::kBt470Bg:
return os << "5 (Rec. ITUR BT.4706 System B, G)";
case Primaries::kSmpte170M:
return os << "6 (SMPTE 170M)";
case Primaries::kSmpte240M:
return os << "7 (SMPTE 240M)";
case Primaries::kFilm:
return os << "8 (generic film)";
case Primaries::kBt2020:
return os << "9 (Rec. ITU-R BT.2020-2)";
case Primaries::kSmpteSt4281:
return os << "10 (SMPTE ST 428-1)";
case Primaries::kJedecP22Phosphors:
return os << "22 (EBU Tech. 3213-E/JEDEC P22 phosphors)";
default:
return PrintUnknownEnumValue(os, value);
}
}
std::ostream& operator<<(std::ostream& os, FlagInterlaced value) {
switch (value) {
case FlagInterlaced::kUnspecified:
return os << "0 (unspecified)";
case FlagInterlaced::kInterlaced:
return os << "1 (interlaced)";
case FlagInterlaced::kProgressive:
return os << "2 (progressive)";
default:
return PrintUnknownEnumValue(os, value);
}
}
std::ostream& operator<<(std::ostream& os, StereoMode value) {
switch (value) {
case StereoMode::kMono:
return os << "0 (mono)";
case StereoMode::kSideBySideLeftFirst:
return os << "1 (side-by-side, left eye first)";
case StereoMode::kTopBottomRightFirst:
return os << "2 (top-bottom, right eye first)";
case StereoMode::kTopBottomLeftFirst:
return os << "3 (top-bottom, left eye first)";
case StereoMode::kCheckboardRightFirst:
return os << "4 (checkboard, right eye first)";
case StereoMode::kCheckboardLeftFirst:
return os << "5 (checkboard, left eye first)";
case StereoMode::kRowInterleavedRightFirst:
return os << "6 (row interleaved, right eye first)";
case StereoMode::kRowInterleavedLeftFirst:
return os << "7 (row interleaved, left eye first)";
case StereoMode::kColumnInterleavedRightFirst:
return os << "8 (column interleaved, right eye first)";
case StereoMode::kColumnInterleavedLeftFirst:
return os << "9 (column interleaved, left eye first)";
case StereoMode::kAnaglyphCyanRed:
return os << "10 (anaglyph, cyan/red)";
case StereoMode::kSideBySideRightFirst:
return os << "11 (side-by-side, right eye first)";
case StereoMode::kAnaglyphGreenMagenta:
return os << "12 (anaglyph, green/magenta)";
case StereoMode::kBlockLacedLeftFirst:
return os << "13 (block laced, left eye first)";
case StereoMode::kBlockLacedRightFirst:
return os << "14 (block laced, right eye first)";
default:
return PrintUnknownEnumValue(os, value);
}
}
std::ostream& operator<<(std::ostream& os, DisplayUnit value) {
switch (value) {
case DisplayUnit::kPixels:
return os << "0 (pixels)";
case DisplayUnit::kCentimeters:
return os << "1 (centimeters)";
case DisplayUnit::kInches:
return os << "2 (inches)";
case DisplayUnit::kDisplayAspectRatio:
return os << "3 (display aspect ratio)";
default:
return PrintUnknownEnumValue(os, value);
}
}
std::ostream& operator<<(std::ostream& os, AspectRatioType value) {
switch (value) {
case AspectRatioType::kFreeResizing:
return os << "0 (free resizing)";
case AspectRatioType::kKeep:
return os << "1 (keep aspect ratio)";
case AspectRatioType::kFixed:
return os << "2 (fixed)";
default:
return PrintUnknownEnumValue(os, value);
}
}
std::ostream& operator<<(std::ostream& os, AesSettingsCipherMode value) {
switch (value) {
case AesSettingsCipherMode::kCtr:
return os << "1 (CTR)";
default:
return PrintUnknownEnumValue(os, value);
}
}
std::ostream& operator<<(std::ostream& os, ContentEncAlgo value) {
switch (value) {
case ContentEncAlgo::kOnlySigned:
return os << "0 (only signed, not encrypted)";
case ContentEncAlgo::kDes:
return os << "1 (DES)";
case ContentEncAlgo::k3Des:
return os << "2 (3DES)";
case ContentEncAlgo::kTwofish:
return os << "3 (Twofish)";
case ContentEncAlgo::kBlowfish:
return os << "4 (Blowfish)";
case ContentEncAlgo::kAes:
return os << "5 (AES)";
default:
return PrintUnknownEnumValue(os, value);
}
}
std::ostream& operator<<(std::ostream& os, ContentEncodingType value) {
switch (value) {
case ContentEncodingType::kCompression:
return os << "0 (compression)";
case ContentEncodingType::kEncryption:
return os << "1 (encryption)";
default:
return PrintUnknownEnumValue(os, value);
}
}
std::ostream& operator<<(std::ostream& os, TrackType value) {
switch (value) {
case TrackType::kVideo:
return os << "1 (video)";
case TrackType::kAudio:
return os << "2 (audio)";
case TrackType::kComplex:
return os << "3 (complex)";
case TrackType::kLogo:
return os << "16 (logo)";
case TrackType::kSubtitle:
return os << "17 (subtitle)";
case TrackType::kButtons:
return os << "18 (buttons)";
case TrackType::kControl:
return os << "32 (control)";
default:
return PrintUnknownEnumValue(os, value);
}
}
// For binary elements, just print out its size.
std::ostream& operator<<(std::ostream& os,
const std::vector<std::uint8_t>& value) {
return os << '<' << value.size() << " bytes>";
}
class DemoCallback : public Callback {
public:
int indent = 0;
int spaces_per_indent = 2;
void PrintElementMetadata(const std::string& name,
const ElementMetadata& metadata) {
// Since we aren't doing any seeking in this demo, we don't have to worry
// about kUnknownHeaderSize or kUnknownElementPosition when adding the
// position and sizes.
const std::uint64_t header_start = metadata.position;
const std::uint64_t header_end = header_start + metadata.header_size;
const std::uint64_t body_start = header_end;
std::cout << std::string(indent * spaces_per_indent, ' ') << name;
// The ContentEncAESSettings element has the longest name (out of all other
// master elements) at 21 characters. It's also the deepest master element
// at a level of 6. Insert enough whitespace so there's room for it.
std::cout << std::string(21 + 6 * spaces_per_indent -
indent * spaces_per_indent - name.size(),
' ')
<< " header: [" << header_start << ", " << header_end
<< ") body: [" << body_start << ", ";
if (metadata.size != kUnknownElementSize) {
const std::uint64_t body_end = body_start + metadata.size;
std::cout << body_end;
} else {
std::cout << '?';
}
std::cout << ")\n";
}
template <typename T>
void PrintMandatoryElement(const std::string& name,
const Element<T>& element) {
std::cout << std::string(indent * spaces_per_indent, ' ') << name;
if (!element.is_present()) {
std::cout << " (implicit)";
}
std::cout << ": " << element.value() << '\n';
}
template <typename T>
void PrintMandatoryElement(const std::string& name,
const std::vector<Element<T>>& elements) {
for (const Element<T>& element : elements) {
PrintMandatoryElement(name, element);
}
}
template <typename T>
void PrintOptionalElement(const std::string& name,
const Element<T>& element) {
if (element.is_present()) {
std::cout << std::string(indent * spaces_per_indent, ' ') << name << ": "
<< element.value() << '\n';
}
}
template <typename T>
void PrintOptionalElement(const std::string& name,
const std::vector<Element<T>>& elements) {
for (const Element<T>& element : elements) {
PrintOptionalElement(name, element);
}
}
void PrintMasterElement(const BlockAdditions& block_additions) {
PrintMasterElement("BlockMore", block_additions.block_mores);
}
void PrintMasterElement(const BlockMore& block_more) {
PrintMandatoryElement("BlockAddID", block_more.id);
PrintMandatoryElement("BlockAdditional", block_more.data);
}
void PrintMasterElement(const Slices& slices) {
PrintMasterElement("TimeSlice", slices.slices);
}
void PrintMasterElement(const TimeSlice& time_slice) {
PrintOptionalElement("LaceNumber", time_slice.lace_number);
}
void PrintMasterElement(const Video& video) {
PrintMandatoryElement("FlagInterlaced", video.interlaced);
PrintOptionalElement("StereoMode", video.stereo_mode);
PrintOptionalElement("AlphaMode", video.alpha_mode);
PrintMandatoryElement("PixelWidth", video.pixel_width);
PrintMandatoryElement("PixelHeight", video.pixel_height);
PrintOptionalElement("PixelCropBottom", video.pixel_crop_bottom);
PrintOptionalElement("PixelCropTop", video.pixel_crop_top);
PrintOptionalElement("PixelCropLeft", video.pixel_crop_left);
PrintOptionalElement("PixelCropRight", video.pixel_crop_right);
PrintOptionalElement("DisplayWidth", video.display_width);
PrintOptionalElement("DisplayHeight", video.display_height);
PrintOptionalElement("DisplayUnit", video.display_unit);
PrintOptionalElement("AspectRatioType", video.aspect_ratio_type);
PrintOptionalElement("FrameRate", video.frame_rate);
PrintMasterElement("Colour", video.colour);
}
void PrintMasterElement(const Colour& colour) {
PrintOptionalElement("MatrixCoefficients", colour.matrix_coefficients);
PrintOptionalElement("BitsPerChannel", colour.bits_per_channel);
PrintOptionalElement("ChromaSubsamplingHorz", colour.chroma_subsampling_x);
PrintOptionalElement("ChromaSubsamplingVert", colour.chroma_subsampling_y);
PrintOptionalElement("CbSubsamplingHorz", colour.cb_subsampling_x);
PrintOptionalElement("CbSubsamplingVert", colour.cb_subsampling_y);
PrintOptionalElement("ChromaSitingHorz", colour.chroma_siting_x);
PrintOptionalElement("ChromaSitingVert", colour.chroma_siting_y);
PrintOptionalElement("Range", colour.range);
PrintOptionalElement("TransferCharacteristics",
colour.transfer_characteristics);
PrintOptionalElement("Primaries", colour.primaries);
PrintOptionalElement("MaxCLL", colour.max_cll);
PrintOptionalElement("MaxFALL", colour.max_fall);
PrintMasterElement("MasteringMetadata", colour.mastering_metadata);
}
void PrintMasterElement(const MasteringMetadata& mastering_metadata) {
PrintOptionalElement("PrimaryRChromaticityX",
mastering_metadata.primary_r_chromaticity_x);
PrintOptionalElement("PrimaryRChromaticityY",
mastering_metadata.primary_r_chromaticity_y);
PrintOptionalElement("PrimaryGChromaticityX",
mastering_metadata.primary_g_chromaticity_x);
PrintOptionalElement("PrimaryGChromaticityY",
mastering_metadata.primary_g_chromaticity_y);
PrintOptionalElement("PrimaryBChromaticityX",
mastering_metadata.primary_b_chromaticity_x);
PrintOptionalElement("PrimaryBChromaticityY",
mastering_metadata.primary_b_chromaticity_y);
PrintOptionalElement("WhitePointChromaticityX",
mastering_metadata.white_point_chromaticity_x);
PrintOptionalElement("WhitePointChromaticityY",
mastering_metadata.white_point_chromaticity_y);
PrintOptionalElement("LuminanceMax", mastering_metadata.luminance_max);
PrintOptionalElement("LuminanceMin", mastering_metadata.luminance_min);
}
void PrintMasterElement(const Audio& audio) {
PrintMandatoryElement("SamplingFrequency", audio.sampling_frequency);
PrintOptionalElement("OutputSamplingFrequency", audio.output_frequency);
PrintMandatoryElement("Channels", audio.channels);
PrintOptionalElement("BitDepth", audio.bit_depth);
}
void PrintMasterElement(const ContentEncodings& content_encodings) {
PrintMasterElement("ContentEncoding", content_encodings.encodings);
}
void PrintMasterElement(const ContentEncoding& content_encoding) {
PrintMandatoryElement("ContentEncodingOrder", content_encoding.order);
PrintMandatoryElement("ContentEncodingScope", content_encoding.scope);
PrintMandatoryElement("ContentEncodingType", content_encoding.type);
PrintMasterElement("ContentEncryption", content_encoding.encryption);
}
void PrintMasterElement(const ContentEncryption& content_encryption) {
PrintOptionalElement("ContentEncAlgo", content_encryption.algorithm);
PrintOptionalElement("ContentEncKeyID", content_encryption.key_id);
PrintMasterElement("ContentEncAESSettings",
content_encryption.aes_settings);
}
void PrintMasterElement(
const ContentEncAesSettings& content_enc_aes_settings) {
PrintMandatoryElement("AESSettingsCipherMode",
content_enc_aes_settings.aes_settings_cipher_mode);
}
void PrintMasterElement(const CueTrackPositions& cue_track_positions) {
PrintMandatoryElement("CueTrack", cue_track_positions.track);
PrintMandatoryElement("CueClusterPosition",
cue_track_positions.cluster_position);
PrintOptionalElement("CueRelativePosition",
cue_track_positions.relative_position);
PrintOptionalElement("CueDuration", cue_track_positions.duration);
PrintOptionalElement("CueBlockNumber", cue_track_positions.block_number);
}
void PrintMasterElement(const ChapterAtom& chapter_atom) {
PrintMandatoryElement("ChapterUID", chapter_atom.uid);
PrintOptionalElement("ChapterStringUID", chapter_atom.string_uid);
PrintMandatoryElement("ChapterTimeStart", chapter_atom.time_start);
PrintOptionalElement("ChapterTimeEnd", chapter_atom.time_end);
PrintMasterElement("ChapterDisplay", chapter_atom.displays);
PrintMasterElement("ChapterAtom", chapter_atom.atoms);
}
void PrintMasterElement(const ChapterDisplay& chapter_display) {
PrintMandatoryElement("ChapString", chapter_display.string);
PrintMandatoryElement("ChapLanguage", chapter_display.languages);
PrintOptionalElement("ChapCountry", chapter_display.countries);
}
void PrintMasterElement(const Targets& targets) {
PrintOptionalElement("TargetTypeValue", targets.type_value);
PrintOptionalElement("TargetType", targets.type);
PrintMandatoryElement("TagTrackUID", targets.track_uids);
}
void PrintMasterElement(const SimpleTag& simple_tag) {
PrintMandatoryElement("TagName", simple_tag.name);
PrintMandatoryElement("TagLanguage", simple_tag.language);
PrintMandatoryElement("TagDefault", simple_tag.is_default);
PrintOptionalElement("TagString", simple_tag.string);
PrintOptionalElement("TagBinary", simple_tag.binary);
PrintMasterElement("SimpleTag", simple_tag.tags);
}
// When printing a master element that's wrapped in Element<>, peel off the
// Element<> wrapper and print the underlying master element if it's present.
template <typename T>
void PrintMasterElement(const std::string& name, const Element<T>& element) {
if (element.is_present()) {
std::cout << std::string(indent * spaces_per_indent, ' ') << name << "\n";
++indent;
PrintMasterElement(element.value());
--indent;
}
}
template <typename T>
void PrintMasterElement(const std::string& name,
const std::vector<Element<T>>& elements) {
for (const Element<T>& element : elements) {
PrintMasterElement(name, element);
}
}
template <typename T>
void PrintValue(const std::string& name, const T& value) {
std::cout << std::string(indent * spaces_per_indent, ' ') << name << ": "
<< value << '\n';
}
Status OnElementBegin(const ElementMetadata& metadata,
Action* action) override {
// Print out metadata for some level 1 elements that don't have explicit
// callbacks.
switch (metadata.id) {
case Id::kSeekHead:
indent = 1;
PrintElementMetadata("SeekHead", metadata);
break;
case Id::kTracks:
indent = 1;
PrintElementMetadata("Tracks", metadata);
break;
case Id::kCues:
indent = 1;
PrintElementMetadata("Cues", metadata);
break;
case Id::kChapters:
indent = 1;
PrintElementMetadata("Chapters", metadata);
break;
case Id::kTags:
indent = 1;
PrintElementMetadata("Tags", metadata);
break;
default:
break;
}
*action = Action::kRead;
return Status(Status::kOkCompleted);
}
Status OnUnknownElement(const ElementMetadata& metadata, Reader* reader,
std::uint64_t* bytes_remaining) override {
// Output unknown elements without any indentation because we aren't
// tracking which element contains them.
int original_indent = indent;
indent = 0;
PrintElementMetadata("UNKNOWN_ELEMENT!", metadata);
indent = original_indent;
// The base class's implementation will just skip the element via
// Reader::Skip().
return Callback::OnUnknownElement(metadata, reader, bytes_remaining);
}
Status OnEbml(const ElementMetadata& metadata, const Ebml& ebml) override {
indent = 0;
PrintElementMetadata("EBML", metadata);
indent = 1;
PrintMandatoryElement("EBMLVersion", ebml.ebml_version);
PrintMandatoryElement("EBMLReadVersion", ebml.ebml_read_version);
PrintMandatoryElement("EBMLMaxIDLength", ebml.ebml_max_id_length);
PrintMandatoryElement("EBMLMaxSizeLength", ebml.ebml_max_size_length);
PrintMandatoryElement("DocType", ebml.doc_type);
PrintMandatoryElement("DocTypeVersion", ebml.doc_type_version);
PrintMandatoryElement("DocTypeReadVersion", ebml.doc_type_read_version);
return Status(Status::kOkCompleted);
}
Status OnVoid(const ElementMetadata& metadata, Reader* reader,
std::uint64_t* bytes_remaining) override {
// Output Void elements without any indentation because we aren't tracking
// which element contains them.
int original_indent = indent;
indent = 0;
PrintElementMetadata("Void", metadata);
indent = original_indent;
// The base class's implementation will just skip the element via
// Reader::Skip().
return Callback::OnVoid(metadata, reader, bytes_remaining);
}
Status OnSegmentBegin(const ElementMetadata& metadata,
Action* action) override {
indent = 0;
PrintElementMetadata("Segment", metadata);
indent = 1;
*action = Action::kRead;
return Status(Status::kOkCompleted);
}
Status OnSeek(const ElementMetadata& metadata, const Seek& seek) override {
indent = 2;
PrintElementMetadata("Seek", metadata);
indent = 3;
PrintMandatoryElement("SeekID", seek.id);
PrintMandatoryElement("SeekPosition", seek.position);
return Status(Status::kOkCompleted);
}
Status OnInfo(const ElementMetadata& metadata, const Info& info) override {
indent = 1;
PrintElementMetadata("Info", metadata);
indent = 2;
PrintMandatoryElement("TimecodeScale", info.timecode_scale);
PrintOptionalElement("Duration", info.duration);
PrintOptionalElement("DateUTC", info.date_utc);
PrintOptionalElement("Title", info.title);
PrintOptionalElement("MuxingApp", info.muxing_app);
PrintOptionalElement("WritingApp", info.writing_app);
return Status(Status::kOkCompleted);
}
Status OnClusterBegin(const ElementMetadata& metadata, const Cluster& cluster,
Action* action) override {
indent = 1;
PrintElementMetadata("Cluster", metadata);
// A properly muxed file will have Timecode and PrevSize first before any
// SimpleBlock or BlockGroups. The parser takes advantage of this and delays
// calling OnClusterBegin() until it hits the first SimpleBlock or
// BlockGroup child (or the Cluster ends if it's empty). It's possible for
// an improperly muxed file to have Timecode or PrevSize after the first
// block, in which case they'll be absent here and may be accessed in
// OnClusterEnd() when the Cluster and all its children have been fully
// parsed. In this demo we assume the file has been properly muxed.
indent = 2;
PrintMandatoryElement("Timecode", cluster.timecode);
PrintOptionalElement("PrevSize", cluster.previous_size);
*action = Action::kRead;
return Status(Status::kOkCompleted);
}
Status OnSimpleBlockBegin(const ElementMetadata& metadata,
const SimpleBlock& simple_block,
Action* action) override {
indent = 2;
PrintElementMetadata("SimpleBlock", metadata);
indent = 3;
PrintValue("track number", simple_block.track_number);
PrintValue("frames", simple_block.num_frames);
PrintValue("timecode", simple_block.timecode);
PrintValue("lacing", simple_block.lacing);
std::string flags = (simple_block.is_visible) ? "visible" : "invisible";
if (simple_block.is_key_frame)
flags += ", key frame";
if (simple_block.is_discardable)
flags += ", discardable";
PrintValue("flags", flags);
*action = Action::kRead;
return Status(Status::kOkCompleted);
}
Status OnSimpleBlockEnd(const ElementMetadata& /* metadata */,
const SimpleBlock& /* simple_block */) override {
return Status(Status::kOkCompleted);
}
Status OnBlockGroupBegin(const ElementMetadata& metadata,
Action* /* action */) override {
indent = 2;
PrintElementMetadata("BlockGroup", metadata);
return Status(Status::kOkCompleted);
}
Status OnBlockBegin(const ElementMetadata& metadata, const Block& block,
Action* action) override {
indent = 3;
PrintElementMetadata("Block", metadata);
indent = 4;
PrintValue("track number", block.track_number);
PrintValue("frames", block.num_frames);
PrintValue("timecode", block.timecode);
PrintValue("lacing", block.lacing);
PrintValue("flags", (block.is_visible) ? "visible" : "invisible");
*action = Action::kRead;
return Status(Status::kOkCompleted);
}
Status OnBlockEnd(const ElementMetadata& /* metadata */,
const Block& /* block */) override {
return Status(Status::kOkCompleted);
}
Status OnBlockGroupEnd(const ElementMetadata& /* metadata */,
const BlockGroup& block_group) override {
if (block_group.virtual_block.is_present()) {
std::cout << std::string(indent * spaces_per_indent, ' ')
<< "BlockVirtual\n";
indent = 4;
PrintValue("track number",
block_group.virtual_block.value().track_number);
PrintValue("timecode", block_group.virtual_block.value().timecode);
}
indent = 3;
PrintMasterElement("BlockAdditions", block_group.additions);
PrintOptionalElement("BlockDuration", block_group.duration);
PrintOptionalElement("ReferenceBlock", block_group.references);
PrintOptionalElement("DiscardPadding", block_group.discard_padding);
PrintMasterElement("Slices", block_group.slices);
// BlockGroup::block has been set, but we've already printed it in
// OnBlockBegin().
return Status(Status::kOkCompleted);
}
Status OnFrame(const FrameMetadata& metadata, Reader* reader,
std::uint64_t* bytes_remaining) override {
PrintValue("frame byte range",
'[' + std::to_string(metadata.position) + ", " +
std::to_string(metadata.position + metadata.size) + ')');
// The base class's implementation will just skip the frame via
// Reader::Skip().
return Callback::OnFrame(metadata, reader, bytes_remaining);
}
Status OnClusterEnd(const ElementMetadata& /* metadata */,
const Cluster& /* cluster */) override {
// The Cluster and all its children have been fully parsed at this point. If
// the file wasn't properly muxed and Timecode or PrevSize were missing in
// OnClusterBegin(), they'll be set here (if the Cluster contained them). In
// this demo we already handled them, though.
return Status(Status::kOkCompleted);
}
Status OnTrackEntry(const ElementMetadata& metadata,
const TrackEntry& track_entry) override {
indent = 2;
PrintElementMetadata("TrackEntry", metadata);
indent = 3;
PrintMandatoryElement("TrackNumber", track_entry.track_number);
PrintMandatoryElement("TrackUID", track_entry.track_uid);
PrintMandatoryElement("TrackType", track_entry.track_type);
PrintMandatoryElement("FlagEnabled", track_entry.is_enabled);
PrintMandatoryElement("FlagDefault", track_entry.is_default);
PrintMandatoryElement("FlagForced", track_entry.is_forced);
PrintMandatoryElement("FlagLacing", track_entry.uses_lacing);
PrintOptionalElement("DefaultDuration", track_entry.default_duration);
PrintOptionalElement("Name", track_entry.name);
PrintOptionalElement("Language", track_entry.language);
PrintMandatoryElement("CodecID", track_entry.codec_id);
PrintOptionalElement("CodecPrivate", track_entry.codec_private);
PrintOptionalElement("CodecName", track_entry.codec_name);
PrintOptionalElement("CodecDelay", track_entry.codec_delay);
PrintMandatoryElement("SeekPreRoll", track_entry.seek_pre_roll);
PrintMasterElement("Video", track_entry.video);
PrintMasterElement("Audio", track_entry.audio);
PrintMasterElement("ContentEncodings", track_entry.content_encodings);
return Status(Status::kOkCompleted);
}
Status OnCuePoint(const ElementMetadata& metadata,
const CuePoint& cue_point) override {
indent = 2;
PrintElementMetadata("CuePoint", metadata);
indent = 3;
PrintMandatoryElement("CueTime", cue_point.time);
PrintMasterElement("CueTrackPositions", cue_point.cue_track_positions);
return Status(Status::kOkCompleted);
}
Status OnEditionEntry(const ElementMetadata& metadata,
const EditionEntry& edition_entry) override {
indent = 2;
PrintElementMetadata("EditionEntry", metadata);
indent = 3;
PrintMasterElement("ChapterAtom", edition_entry.atoms);
return Status(Status::kOkCompleted);
}
Status OnTag(const ElementMetadata& metadata, const Tag& tag) override {
indent = 2;
PrintElementMetadata("Tag", metadata);
indent = 3;
PrintMasterElement("Targets", tag.targets);
PrintMasterElement("SimpleTag", tag.tags);
return Status(Status::kOkCompleted);
}
Status OnSegmentEnd(const ElementMetadata& /* metadata */) override {
return Status(Status::kOkCompleted);
}
};
int main(int argc, char* argv[]) {
if ((argc != 1 && argc != 2) ||
(argc == 2 && argv[1] == std::string("--help"))) {
std::cerr << "Usage:\n" << argv[0] << " [path-to-webm-file]\n\n"
<< "Prints info for the WebM file specified in the command line. "
"If no file is\n"
<< "specified, stdin is used as input.\n";
return EXIT_FAILURE;
}
FILE* file = (argc == 2) ? std::fopen(argv[1], "rb") :
std::freopen(nullptr, "rb", stdin);
if (!file) {
std::cerr << "File cannot be opened\n";
return EXIT_FAILURE;
}
FileReader reader(file);
DemoCallback callback;
WebmParser parser;
Status status = parser.Feed(&callback, &reader);
if (!status.completed_ok()) {
std::cerr << "Parsing error; status code: " << status.code << '\n';
return EXIT_FAILURE;
}
return 0;
}