blob: 554d5cb58b28dcc26d89f5901503a023baba4d33 [file] [log] [blame]
// 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::kProjection:
return os << "Projection";
case Id::kProjectionType:
return os << "kProjectionType";
case Id::kProjectionPrivate:
return os << "kProjectionPrivate";
case Id::kProjectionPoseYaw:
return os << "kProjectionPoseYaw";
case Id::kProjectionPosePitch:
return os << "kProjectionPosePitch";
case Id::kProjectionPoseRoll:
return os << "ProjectionPoseRoll";
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. ITU‑R BT.470‑6 System M)";
case TransferCharacteristics::kGamma28curve:
return os << "5 (gamma 2.8, Rec. ITU‑R 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. ITU‑R BT.709-6)";
case Primaries::kUnspecified:
return os << "2 (unspecified)";
case Primaries::kBt470M:
return os << "4 (Rec. ITU‑R BT.470‑6 System M)";
case Primaries::kBt470Bg:
return os << "5 (Rec. ITU‑R BT.470‑6 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, ProjectionType value) {
switch (value) {
case ProjectionType::kRectangular:
return os << "0 (rectangular)";
case ProjectionType::kEquirectangular:
return os << "1 (equirectangular)";
case ProjectionType::kCubeMap:
return os << "2 (cube map)";
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);
PrintMasterElement("Projection", video.projection);
}
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 Projection& projection) {
PrintMandatoryElement("ProjectionType", projection.type);
PrintOptionalElement("ProjectionPrivate", projection.projection_private);
PrintMandatoryElement("ProjectionPoseYaw", projection.pose_yaw);
PrintMandatoryElement("ProjectionPosePitch", projection.pose_pitch);
PrintMandatoryElement("ProjectionPoseRoll", projection.pose_roll);
}
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);
*action = Action::kRead;
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;
}