Add a new incremental parsing API
Change-Id: I6b921766836d58df0281fb23b2add3f62a478e14
This commit is contained in:
316
webm_parser/src/ancestory.cc
Normal file
316
webm_parser/src/ancestory.cc
Normal file
@@ -0,0 +1,316 @@
|
||||
// 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 "src/ancestory.h"
|
||||
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
bool Ancestory::ById(Id id, Ancestory* ancestory) {
|
||||
// These lists of IDs were generated and must match the switch statement and
|
||||
// have static storage duration. They were generated as follows:
|
||||
//
|
||||
// 1. List all the master elements:
|
||||
// kEbml
|
||||
// kSegment
|
||||
// kSeekHead
|
||||
// kSeek
|
||||
// kInfo
|
||||
// kCluster
|
||||
// kBlockGroup
|
||||
// kBlockAdditions
|
||||
// kBlockMore
|
||||
// kSlices
|
||||
// kTimeSlice
|
||||
// etc.
|
||||
//
|
||||
// 2. Now prefix each entry with its full ancestory:
|
||||
// kEbml
|
||||
// kSegment
|
||||
// kSegment, kSeekHead
|
||||
// kSegment, kSeekHead, kSeek
|
||||
// kSegment, kInfo
|
||||
// kSegment, kCluster
|
||||
// kSegment, kCluster, kBlockGroup
|
||||
// kSegment, kCluster, kBlockGroup, kBlockAdditions
|
||||
// kSegment, kCluster, kBlockGroup, kBlockAdditions, kBlockMore
|
||||
// kSegment, kCluster, kBlockGroup, kSlices
|
||||
// kSegment, kCluster, kBlockGroup, kSlices, kTimeSlice
|
||||
// etc.
|
||||
//
|
||||
// 3. Now remove entries that are just subsets of others:
|
||||
// kEbml
|
||||
// kSegment, kSeekHead, kSeek
|
||||
// kSegment, kInfo
|
||||
// kSegment, kCluster, kBlockGroup, kBlockAdditions, kBlockMore
|
||||
// kSegment, kCluster, kBlockGroup, kSlices, kTimeSlice
|
||||
// etc.
|
||||
static constexpr Id kEbmlAncestory[] = {
|
||||
Id::kEbml,
|
||||
};
|
||||
static constexpr Id kSeekAncestory[] = {
|
||||
Id::kSegment, Id::kSeekHead, Id::kSeek,
|
||||
};
|
||||
static constexpr Id kInfoAncestory[] = {
|
||||
Id::kSegment, Id::kInfo,
|
||||
};
|
||||
static constexpr Id kBlockMoreAncestory[] = {
|
||||
Id::kSegment, Id::kCluster, Id::kBlockGroup,
|
||||
Id::kBlockAdditions, Id::kBlockMore,
|
||||
};
|
||||
static constexpr Id kTimeSliceAncestory[] = {
|
||||
Id::kSegment, Id::kCluster, Id::kBlockGroup, Id::kSlices, Id::kTimeSlice,
|
||||
};
|
||||
static constexpr Id kVideoAncestory[] = {
|
||||
Id::kSegment, Id::kTracks, Id::kTrackEntry, Id::kVideo,
|
||||
};
|
||||
static constexpr Id kAudioAncestory[] = {
|
||||
Id::kSegment, Id::kTracks, Id::kTrackEntry, Id::kAudio,
|
||||
};
|
||||
static constexpr Id kContentEncAesSettingsAncestory[] = {
|
||||
Id::kSegment,
|
||||
Id::kTracks,
|
||||
Id::kTrackEntry,
|
||||
Id::kContentEncodings,
|
||||
Id::kContentEncoding,
|
||||
Id::kContentEncryption,
|
||||
Id::kContentEncAesSettings,
|
||||
};
|
||||
static constexpr Id kCueTrackPositionsAncestory[] = {
|
||||
Id::kSegment, Id::kCues, Id::kCuePoint, Id::kCueTrackPositions,
|
||||
};
|
||||
static constexpr Id kChapterDisplayAncestory[] = {
|
||||
Id::kSegment, Id::kChapters, Id::kEditionEntry,
|
||||
Id::kChapterAtom, Id::kChapterDisplay,
|
||||
};
|
||||
static constexpr Id kTargetsAncestory[] = {
|
||||
Id::kSegment, Id::kTags, Id::kTag, Id::kTargets,
|
||||
};
|
||||
static constexpr Id kSimpleTagAncestory[] = {
|
||||
Id::kSegment, Id::kTags, Id::kTag, Id::kSimpleTag,
|
||||
};
|
||||
|
||||
switch (id) {
|
||||
case Id::kEbmlVersion:
|
||||
case Id::kEbmlReadVersion:
|
||||
case Id::kEbmlMaxIdLength:
|
||||
case Id::kEbmlMaxSizeLength:
|
||||
case Id::kDocType:
|
||||
case Id::kDocTypeVersion:
|
||||
case Id::kDocTypeReadVersion:
|
||||
*ancestory = Ancestory(kEbmlAncestory, 1);
|
||||
return true;
|
||||
|
||||
case Id::kSeekHead:
|
||||
case Id::kInfo:
|
||||
case Id::kCluster:
|
||||
case Id::kTracks:
|
||||
case Id::kCues:
|
||||
case Id::kChapters:
|
||||
case Id::kTags:
|
||||
*ancestory = Ancestory(kSeekAncestory, 1);
|
||||
return true;
|
||||
|
||||
case Id::kSeek:
|
||||
*ancestory = Ancestory(kSeekAncestory, 2);
|
||||
return true;
|
||||
|
||||
case Id::kSeekId:
|
||||
case Id::kSeekPosition:
|
||||
*ancestory = Ancestory(kSeekAncestory, 3);
|
||||
return true;
|
||||
|
||||
case Id::kTimecodeScale:
|
||||
case Id::kDuration:
|
||||
case Id::kDateUtc:
|
||||
case Id::kTitle:
|
||||
case Id::kMuxingApp:
|
||||
case Id::kWritingApp:
|
||||
*ancestory = Ancestory(kInfoAncestory, 2);
|
||||
return true;
|
||||
|
||||
case Id::kTimecode:
|
||||
case Id::kPrevSize:
|
||||
case Id::kSimpleBlock:
|
||||
case Id::kBlockGroup:
|
||||
*ancestory = Ancestory(kBlockMoreAncestory, 2);
|
||||
return true;
|
||||
|
||||
case Id::kBlock:
|
||||
case Id::kBlockVirtual:
|
||||
case Id::kBlockAdditions:
|
||||
case Id::kBlockDuration:
|
||||
case Id::kReferenceBlock:
|
||||
case Id::kDiscardPadding:
|
||||
case Id::kSlices:
|
||||
*ancestory = Ancestory(kBlockMoreAncestory, 3);
|
||||
return true;
|
||||
|
||||
case Id::kBlockMore:
|
||||
*ancestory = Ancestory(kBlockMoreAncestory, 4);
|
||||
return true;
|
||||
|
||||
case Id::kBlockAddId:
|
||||
case Id::kBlockAdditional:
|
||||
*ancestory = Ancestory(kBlockMoreAncestory, 5);
|
||||
return true;
|
||||
|
||||
case Id::kTimeSlice:
|
||||
*ancestory = Ancestory(kTimeSliceAncestory, 4);
|
||||
return true;
|
||||
|
||||
case Id::kLaceNumber:
|
||||
*ancestory = Ancestory(kTimeSliceAncestory, 5);
|
||||
return true;
|
||||
|
||||
case Id::kTrackEntry:
|
||||
*ancestory = Ancestory(kVideoAncestory, 2);
|
||||
return true;
|
||||
|
||||
case Id::kTrackNumber:
|
||||
case Id::kTrackUid:
|
||||
case Id::kTrackType:
|
||||
case Id::kFlagEnabled:
|
||||
case Id::kFlagDefault:
|
||||
case Id::kFlagForced:
|
||||
case Id::kFlagLacing:
|
||||
case Id::kDefaultDuration:
|
||||
case Id::kName:
|
||||
case Id::kLanguage:
|
||||
case Id::kCodecId:
|
||||
case Id::kCodecPrivate:
|
||||
case Id::kCodecName:
|
||||
case Id::kCodecDelay:
|
||||
case Id::kSeekPreRoll:
|
||||
case Id::kVideo:
|
||||
case Id::kAudio:
|
||||
case Id::kContentEncodings:
|
||||
*ancestory = Ancestory(kVideoAncestory, 3);
|
||||
return true;
|
||||
|
||||
case Id::kFlagInterlaced:
|
||||
case Id::kStereoMode:
|
||||
case Id::kAlphaMode:
|
||||
case Id::kPixelWidth:
|
||||
case Id::kPixelHeight:
|
||||
case Id::kPixelCropBottom:
|
||||
case Id::kPixelCropTop:
|
||||
case Id::kPixelCropLeft:
|
||||
case Id::kPixelCropRight:
|
||||
case Id::kDisplayWidth:
|
||||
case Id::kDisplayHeight:
|
||||
case Id::kDisplayUnit:
|
||||
case Id::kAspectRatioType:
|
||||
case Id::kFrameRate:
|
||||
*ancestory = Ancestory(kVideoAncestory, 4);
|
||||
return true;
|
||||
|
||||
case Id::kSamplingFrequency:
|
||||
case Id::kOutputSamplingFrequency:
|
||||
case Id::kChannels:
|
||||
case Id::kBitDepth:
|
||||
*ancestory = Ancestory(kAudioAncestory, 4);
|
||||
return true;
|
||||
|
||||
case Id::kContentEncoding:
|
||||
*ancestory = Ancestory(kContentEncAesSettingsAncestory, 4);
|
||||
return true;
|
||||
|
||||
case Id::kContentEncodingOrder:
|
||||
case Id::kContentEncodingScope:
|
||||
case Id::kContentEncodingType:
|
||||
case Id::kContentEncryption:
|
||||
*ancestory = Ancestory(kContentEncAesSettingsAncestory, 5);
|
||||
return true;
|
||||
|
||||
case Id::kContentEncAlgo:
|
||||
case Id::kContentEncKeyId:
|
||||
case Id::kContentEncAesSettings:
|
||||
*ancestory = Ancestory(kContentEncAesSettingsAncestory, 6);
|
||||
return true;
|
||||
|
||||
case Id::kAesSettingsCipherMode:
|
||||
*ancestory = Ancestory(kContentEncAesSettingsAncestory, 7);
|
||||
return true;
|
||||
|
||||
case Id::kCuePoint:
|
||||
*ancestory = Ancestory(kCueTrackPositionsAncestory, 2);
|
||||
return true;
|
||||
|
||||
case Id::kCueTime:
|
||||
case Id::kCueTrackPositions:
|
||||
*ancestory = Ancestory(kCueTrackPositionsAncestory, 3);
|
||||
return true;
|
||||
|
||||
case Id::kCueTrack:
|
||||
case Id::kCueClusterPosition:
|
||||
case Id::kCueRelativePosition:
|
||||
case Id::kCueDuration:
|
||||
case Id::kCueBlockNumber:
|
||||
*ancestory = Ancestory(kCueTrackPositionsAncestory, 4);
|
||||
return true;
|
||||
|
||||
case Id::kEditionEntry:
|
||||
*ancestory = Ancestory(kChapterDisplayAncestory, 2);
|
||||
return true;
|
||||
|
||||
case Id::kChapterAtom:
|
||||
*ancestory = Ancestory(kChapterDisplayAncestory, 3);
|
||||
return true;
|
||||
|
||||
case Id::kChapterUid:
|
||||
case Id::kChapterStringUid:
|
||||
case Id::kChapterTimeStart:
|
||||
case Id::kChapterTimeEnd:
|
||||
case Id::kChapterDisplay:
|
||||
*ancestory = Ancestory(kChapterDisplayAncestory, 4);
|
||||
return true;
|
||||
|
||||
case Id::kChapString:
|
||||
case Id::kChapLanguage:
|
||||
case Id::kChapCountry:
|
||||
*ancestory = Ancestory(kChapterDisplayAncestory, 5);
|
||||
return true;
|
||||
|
||||
case Id::kTag:
|
||||
*ancestory = Ancestory(kTargetsAncestory, 2);
|
||||
return true;
|
||||
|
||||
case Id::kTargets:
|
||||
case Id::kSimpleTag:
|
||||
*ancestory = Ancestory(kTargetsAncestory, 3);
|
||||
return true;
|
||||
|
||||
case Id::kTargetTypeValue:
|
||||
case Id::kTargetType:
|
||||
case Id::kTagTrackUid:
|
||||
*ancestory = Ancestory(kTargetsAncestory, 4);
|
||||
return true;
|
||||
|
||||
case Id::kTagName:
|
||||
case Id::kTagLanguage:
|
||||
case Id::kTagDefault:
|
||||
case Id::kTagString:
|
||||
case Id::kTagBinary:
|
||||
*ancestory = Ancestory(kSimpleTagAncestory, 4);
|
||||
return true;
|
||||
|
||||
case Id::kEbml:
|
||||
case Id::kSegment:
|
||||
*ancestory = {};
|
||||
return true;
|
||||
|
||||
default:
|
||||
// This is an unknown element or a global element (i.e. Void); its
|
||||
// ancestory cannot be deduced.
|
||||
*ancestory = {};
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
83
webm_parser/src/ancestory.h
Normal file
83
webm_parser/src/ancestory.h
Normal file
@@ -0,0 +1,83 @@
|
||||
// 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.
|
||||
#ifndef SRC_ANCESTORY_H_
|
||||
#define SRC_ANCESTORY_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Represents an element's ancestory in descending order. For example, the
|
||||
// Id::kTrackNumber element has an ancestory of {Id::kSegment, Id::kTracks,
|
||||
// Id::kTrackEntry}.
|
||||
class Ancestory {
|
||||
public:
|
||||
// Constructs an empty ancestory.
|
||||
Ancestory() = default;
|
||||
|
||||
Ancestory(const Ancestory&) = default;
|
||||
Ancestory(Ancestory&&) = default;
|
||||
Ancestory& operator=(const Ancestory&) = default;
|
||||
Ancestory& operator=(Ancestory&&) = default;
|
||||
|
||||
// Returns the ancestory with the top-level parent removed. For example, if
|
||||
// the current ancestory is {Id::kSegment, Id::kTracks, Id::kTrackEntry}, next
|
||||
// will return {Id::kTracks, Id::kTrackEntry}. This must not be called if the
|
||||
// ancestory is empty.
|
||||
Ancestory next() const {
|
||||
assert(begin_ < end_);
|
||||
Ancestory copy = *this;
|
||||
++copy.begin_;
|
||||
return copy;
|
||||
}
|
||||
|
||||
// Gets the Id of the top-level parent. For example, if the current ancestory
|
||||
// is {Id::kSegment, Id::kTracks, Id::kTrackEntry}, id will return
|
||||
// Id::kSegment. This must not be called if the ancestory is empty.
|
||||
Id id() const {
|
||||
assert(begin_ < end_);
|
||||
return *begin_;
|
||||
}
|
||||
|
||||
// Returns true if the ancestory is empty.
|
||||
bool empty() const { return begin_ == end_; }
|
||||
|
||||
// Looks up the ancestory of the given id. Returns true and sets ancestory if
|
||||
// the element's ancestory could be deduced. Global elements (i.e. Id::kVoid)
|
||||
// and unknown elements can't have their ancestory deduced.
|
||||
static bool ById(Id id, Ancestory* ancestory);
|
||||
|
||||
private:
|
||||
// Constructs an Ancestory using the first count elements of ancestory.
|
||||
// ancestory must have static storage duration.
|
||||
template <std::size_t N>
|
||||
Ancestory(const Id (&ancestory)[N], std::size_t count)
|
||||
: begin_(ancestory), end_(ancestory + count) {
|
||||
assert(count <= N);
|
||||
}
|
||||
|
||||
// The following invariants apply to begin_ and end_:
|
||||
// begin_ <= end_
|
||||
// (begin_ == end_) || (std::begin(kIds) <= begin_ && end_ <= std::end(kIds))
|
||||
|
||||
// The beginning (inclusive) of the sequence of IDs in kIds that defines the
|
||||
// ancestory.
|
||||
const Id* begin_ = nullptr;
|
||||
|
||||
// The ending (exclusive) of the sequence of IDs in kIds that defines the
|
||||
// ancestory.
|
||||
const Id* end_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_ANCESTORY_H_
|
||||
84
webm_parser/src/audio_parser.h
Normal file
84
webm_parser/src/audio_parser.h
Normal file
@@ -0,0 +1,84 @@
|
||||
// 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.
|
||||
#ifndef SRC_AUDIO_PARSER_H_
|
||||
#define SRC_AUDIO_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/float_parser.h"
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Audio
|
||||
// http://www.webmproject.org/docs/container/#Audio
|
||||
class AudioParser : public MasterValueParser<Audio> {
|
||||
public:
|
||||
AudioParser()
|
||||
: MasterValueParser<Audio>(
|
||||
MakeChild<FloatParser>(Id::kSamplingFrequency,
|
||||
&Audio::sampling_frequency),
|
||||
MakeChild<FloatParser>(Id::kOutputSamplingFrequency,
|
||||
&Audio::output_frequency)
|
||||
.NotifyOnParseComplete(),
|
||||
MakeChild<UnsignedIntParser>(Id::kChannels, &Audio::channels),
|
||||
MakeChild<UnsignedIntParser>(Id::kBitDepth, &Audio::bit_depth)) {}
|
||||
|
||||
Status Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) override {
|
||||
output_frequency_has_value_ = false;
|
||||
|
||||
return MasterValueParser::Init(metadata, max_size);
|
||||
}
|
||||
|
||||
void InitAfterSeek(const Ancestory& child_ancestory,
|
||||
const ElementMetadata& child_metadata) override {
|
||||
output_frequency_has_value_ = false;
|
||||
|
||||
return MasterValueParser::InitAfterSeek(child_ancestory, child_metadata);
|
||||
}
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override {
|
||||
const Status status =
|
||||
MasterValueParser::Feed(callback, reader, num_bytes_read);
|
||||
if (status.completed_ok()) {
|
||||
FixMissingOutputFrequency();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
protected:
|
||||
void OnChildParsed(const ElementMetadata& metadata) override {
|
||||
assert(metadata.id == Id::kOutputSamplingFrequency);
|
||||
|
||||
output_frequency_has_value_ = metadata.size > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
bool output_frequency_has_value_;
|
||||
|
||||
void FixMissingOutputFrequency() {
|
||||
if (!output_frequency_has_value_) {
|
||||
*mutable_value()->output_frequency.mutable_value() =
|
||||
value().sampling_frequency.value();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_AUDIO_PARSER_H_
|
||||
25
webm_parser/src/bit_utils.cc
Normal file
25
webm_parser/src/bit_utils.cc
Normal file
@@ -0,0 +1,25 @@
|
||||
// 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 "src/bit_utils.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace webm {
|
||||
|
||||
std::uint8_t CountLeadingZeros(std::uint8_t value) {
|
||||
// Special case for 0 since we can't shift by sizeof(T) * 8 bytes.
|
||||
if (value == 0) return 8;
|
||||
|
||||
std::uint8_t count = 0;
|
||||
while (!(value & (0x80 >> count))) {
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
24
webm_parser/src/bit_utils.h
Normal file
24
webm_parser/src/bit_utils.h
Normal file
@@ -0,0 +1,24 @@
|
||||
// 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.
|
||||
#ifndef SRC_BIT_UTILS_H_
|
||||
#define SRC_BIT_UTILS_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Counts the number of leading zero bits.
|
||||
// For example:
|
||||
// assert(8 == CountLeadingZeros(0x00));
|
||||
// assert(4 == CountLeadingZeros(0x0f));
|
||||
// assert(0 == CountLeadingZeros(0xf0));
|
||||
std::uint8_t CountLeadingZeros(std::uint8_t value);
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_BIT_UTILS_H_
|
||||
30
webm_parser/src/block_additions_parser.h
Normal file
30
webm_parser/src/block_additions_parser.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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.
|
||||
#ifndef SRC_BLOCK_ADDITIONS_PARSER_H_
|
||||
#define SRC_BLOCK_ADDITIONS_PARSER_H_
|
||||
|
||||
#include "src/block_more_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#BlockAdditions
|
||||
// http://www.webmproject.org/docs/container/#BlockAdditions
|
||||
class BlockAdditionsParser : public MasterValueParser<BlockAdditions> {
|
||||
public:
|
||||
BlockAdditionsParser()
|
||||
: MasterValueParser<BlockAdditions>(MakeChild<BlockMoreParser>(
|
||||
Id::kBlockMore, &BlockAdditions::block_mores)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_BLOCK_ADDITIONS_PARSER_H_
|
||||
71
webm_parser/src/block_group_parser.h
Normal file
71
webm_parser/src/block_group_parser.h
Normal file
@@ -0,0 +1,71 @@
|
||||
// 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.
|
||||
#ifndef SRC_BLOCK_GROUP_PARSER_H_
|
||||
#define SRC_BLOCK_GROUP_PARSER_H_
|
||||
|
||||
#include "src/block_additions_parser.h"
|
||||
#include "src/block_parser.h"
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "src/slices_parser.h"
|
||||
#include "src/virtual_block_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#BlockGroup
|
||||
// http://www.webmproject.org/docs/container/#BlockGroup
|
||||
class BlockGroupParser : public MasterValueParser<BlockGroup> {
|
||||
public:
|
||||
BlockGroupParser()
|
||||
: MasterValueParser<BlockGroup>(
|
||||
MakeChild<BlockParser>(Id::kBlock, &BlockGroup::block),
|
||||
MakeChild<VirtualBlockParser>(Id::kBlockVirtual,
|
||||
&BlockGroup::virtual_block),
|
||||
MakeChild<BlockAdditionsParser>(Id::kBlockAdditions,
|
||||
&BlockGroup::additions),
|
||||
MakeChild<UnsignedIntParser>(Id::kBlockDuration,
|
||||
&BlockGroup::duration),
|
||||
MakeChild<SignedIntParser>(Id::kReferenceBlock,
|
||||
&BlockGroup::references),
|
||||
MakeChild<SignedIntParser>(Id::kDiscardPadding,
|
||||
&BlockGroup::discard_padding),
|
||||
MakeChild<SlicesParser>(Id::kSlices, &BlockGroup::slices)) {}
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override {
|
||||
*num_bytes_read = 0;
|
||||
|
||||
if (!parse_started_event_completed()) {
|
||||
Action action;
|
||||
Status status = OnParseStarted(callback, &action);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
set_parse_started_event_completed_with_action(action);
|
||||
}
|
||||
|
||||
return MasterValueParser::Feed(callback, reader, num_bytes_read);
|
||||
}
|
||||
|
||||
protected:
|
||||
Status OnParseStarted(Callback* callback, Action* action) override {
|
||||
return callback->OnBlockGroupBegin(metadata(Id::kBlockGroup), action);
|
||||
}
|
||||
|
||||
Status OnParseCompleted(Callback* callback) override {
|
||||
return callback->OnBlockGroupEnd(metadata(Id::kBlockGroup), value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_BLOCK_GROUP_PARSER_H_
|
||||
76
webm_parser/src/block_header_parser.cc
Normal file
76
webm_parser/src/block_header_parser.cc
Normal file
@@ -0,0 +1,76 @@
|
||||
// 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 "src/block_header_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/parser_utils.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#block_structure
|
||||
// http://matroska.org/technical/specs/index.html#simpleblock_structure
|
||||
// http://matroska.org/technical/specs/index.html#block_virtual
|
||||
Status BlockHeaderParser::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
*num_bytes_read = 0;
|
||||
|
||||
Status status;
|
||||
std::uint64_t local_num_bytes_read;
|
||||
|
||||
while (true) {
|
||||
switch (state_) {
|
||||
case State::kReadingTrackNumber: {
|
||||
status = uint_parser_.Feed(callback, reader, &local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
value_.track_number = uint_parser_.value();
|
||||
state_ = State::kReadingTimecode;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kReadingTimecode: {
|
||||
status =
|
||||
AccumulateIntegerBytes(timecode_bytes_remaining_, reader,
|
||||
&value_.timecode, &local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
timecode_bytes_remaining_ -= static_cast<int>(local_num_bytes_read);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
state_ = State::kReadingFlags;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kReadingFlags: {
|
||||
assert(timecode_bytes_remaining_ == 0);
|
||||
status = ReadByte(reader, &value_.flags);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
++*num_bytes_read;
|
||||
state_ = State::kDone;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kDone: {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
63
webm_parser/src/block_header_parser.h
Normal file
63
webm_parser/src/block_header_parser.h
Normal file
@@ -0,0 +1,63 @@
|
||||
// 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.
|
||||
#ifndef SRC_BLOCK_HEADER_PARSER_H_
|
||||
#define SRC_BLOCK_HEADER_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/parser.h"
|
||||
#include "src/var_int_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
struct BlockHeader {
|
||||
std::uint64_t track_number;
|
||||
std::int16_t timecode;
|
||||
std::uint8_t flags;
|
||||
|
||||
bool operator==(const BlockHeader& other) const {
|
||||
return track_number == other.track_number && timecode == other.timecode &&
|
||||
flags == other.flags;
|
||||
}
|
||||
};
|
||||
|
||||
class BlockHeaderParser : public Parser {
|
||||
public:
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
// Gets the parsed block header information. This must not be called until the
|
||||
// parse has been successfully completed.
|
||||
const BlockHeader& value() const {
|
||||
assert(state_ == State::kDone);
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
BlockHeader value_;
|
||||
|
||||
VarIntParser uint_parser_;
|
||||
|
||||
int timecode_bytes_remaining_ = 2;
|
||||
|
||||
enum class State {
|
||||
// State Transitions to state When
|
||||
kReadingTrackNumber, // kReadingTimecode track parsed
|
||||
kReadingTimecode, // kReadingFlags timecode parsed
|
||||
kReadingFlags, // kDone flags parsed
|
||||
kDone, // No transitions from here (must call Init)
|
||||
} state_ = State::kReadingTrackNumber;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_BLOCK_HEADER_PARSER_H_
|
||||
32
webm_parser/src/block_more_parser.h
Normal file
32
webm_parser/src/block_more_parser.h
Normal file
@@ -0,0 +1,32 @@
|
||||
// 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.
|
||||
#ifndef SRC_BLOCK_MORE_PARSER_H_
|
||||
#define SRC_BLOCK_MORE_PARSER_H_
|
||||
|
||||
#include "src/byte_parser.h"
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#BlockMore
|
||||
// http://www.webmproject.org/docs/container/#BlockMore
|
||||
class BlockMoreParser : public MasterValueParser<BlockMore> {
|
||||
public:
|
||||
BlockMoreParser()
|
||||
: MasterValueParser<BlockMore>(
|
||||
MakeChild<UnsignedIntParser>(Id::kBlockAddId, &BlockMore::id),
|
||||
MakeChild<BinaryParser>(Id::kBlockAdditional, &BlockMore::data)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_BLOCK_MORE_PARSER_H_
|
||||
284
webm_parser/src/block_parser.cc
Normal file
284
webm_parser/src/block_parser.cc
Normal file
@@ -0,0 +1,284 @@
|
||||
// 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 "src/block_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "src/parser_utils.h"
|
||||
#include "webm/element.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
namespace {
|
||||
|
||||
// The ParseBasicBlockFlags functions parse extra flag bits into the block,
|
||||
// depending on the type of block that is being parsed.
|
||||
void ParseBasicBlockFlags(std::uint8_t flags, Block* block) {
|
||||
// Block has no extra flags that aren't already handled.
|
||||
}
|
||||
|
||||
void ParseBasicBlockFlags(std::uint8_t flags, SimpleBlock* block) {
|
||||
block->is_key_frame = (0x80 & flags) != 0;
|
||||
block->is_discardable = (0x01 & flags) != 0;
|
||||
}
|
||||
|
||||
// The BasicBlockBegin functions call the Callback event handler and get the
|
||||
// correct action for the parser, depending on the type of block that is being
|
||||
// parsed.
|
||||
Status BasicBlockBegin(const ElementMetadata& metadata, const Block& block,
|
||||
Callback* callback, Action* action) {
|
||||
return callback->OnBlockBegin(metadata, block, action);
|
||||
}
|
||||
|
||||
Status BasicBlockBegin(const ElementMetadata& metadata,
|
||||
const SimpleBlock& block, Callback* callback,
|
||||
Action* action) {
|
||||
return callback->OnSimpleBlockBegin(metadata, block, action);
|
||||
}
|
||||
|
||||
// The BasicBlockEnd functions call the Callback event handler depending on the
|
||||
// type of block that is being parsed.
|
||||
Status BasicBlockEnd(const ElementMetadata& metadata, const Block& block,
|
||||
Callback* callback) {
|
||||
return callback->OnBlockEnd(metadata, block);
|
||||
}
|
||||
|
||||
Status BasicBlockEnd(const ElementMetadata& metadata, const SimpleBlock& block,
|
||||
Callback* callback) {
|
||||
return callback->OnSimpleBlockEnd(metadata, block);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <typename T>
|
||||
Status BasicBlockParser<T>::Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
if (metadata.size == kUnknownElementSize || metadata.size < 5) {
|
||||
return Status(Status::kInvalidElementSize);
|
||||
}
|
||||
|
||||
*this = {};
|
||||
frame_metadata_.parent_element = metadata;
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Status BasicBlockParser<T>::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
*num_bytes_read = 0;
|
||||
|
||||
Status status;
|
||||
std::uint64_t local_num_bytes_read;
|
||||
|
||||
while (true) {
|
||||
switch (state_) {
|
||||
case State::kReadingHeader: {
|
||||
status = header_parser_.Feed(callback, reader, &local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
header_bytes_read_ += local_num_bytes_read;
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
value_.track_number = header_parser_.value().track_number;
|
||||
value_.timecode = header_parser_.value().timecode;
|
||||
|
||||
std::uint8_t flags = header_parser_.value().flags;
|
||||
value_.is_visible = (0x08 & flags) == 0;
|
||||
value_.lacing = static_cast<Lacing>(flags & 0x06);
|
||||
ParseBasicBlockFlags(flags, &value_);
|
||||
|
||||
if (value_.lacing == Lacing::kNone) {
|
||||
value_.num_frames = 1;
|
||||
state_ = State::kGettingAction;
|
||||
} else {
|
||||
state_ = State::kReadingLaceCount;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kReadingLaceCount: {
|
||||
assert(lace_sizes_.empty());
|
||||
std::uint8_t lace_count;
|
||||
status = ReadByte(reader, &lace_count);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
++*num_bytes_read;
|
||||
++header_bytes_read_;
|
||||
// Lace count is stored as (count - 1).
|
||||
value_.num_frames = lace_count + 1;
|
||||
state_ = State::kGettingAction;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kGettingAction: {
|
||||
Action action;
|
||||
status = BasicBlockBegin(frame_metadata_.parent_element, value_,
|
||||
callback, &action);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
if (action == Action::kSkip) {
|
||||
state_ = State::kSkipping;
|
||||
} else if (value_.lacing == Lacing::kNone || value_.num_frames == 1) {
|
||||
state_ = State::kValidatingSize;
|
||||
} else if (value_.lacing == Lacing::kXiph) {
|
||||
state_ = State::kReadingXiphLaceSizes;
|
||||
} else if (value_.lacing == Lacing::kEbml) {
|
||||
state_ = State::kReadingFirstEbmlLaceSize;
|
||||
} else {
|
||||
state_ = State::kCalculatingFixedLaceSizes;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kReadingXiphLaceSizes:
|
||||
assert(value_.num_frames > 0);
|
||||
while (lace_sizes_.size() < value_.num_frames - 1) {
|
||||
std::uint8_t byte;
|
||||
do {
|
||||
status = ReadByte(reader, &byte);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
++*num_bytes_read;
|
||||
++header_bytes_read_;
|
||||
xiph_lace_size_ += byte;
|
||||
} while (byte == 255);
|
||||
|
||||
lace_sizes_.push_back(xiph_lace_size_);
|
||||
xiph_lace_size_ = 0;
|
||||
}
|
||||
state_ = State::kValidatingSize;
|
||||
continue;
|
||||
|
||||
case State::kReadingFirstEbmlLaceSize:
|
||||
assert(value_.num_frames > 0);
|
||||
assert(lace_sizes_.empty());
|
||||
status = uint_parser_.Feed(callback, reader, &local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
header_bytes_read_ += local_num_bytes_read;
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
lace_sizes_.push_back(uint_parser_.value());
|
||||
uint_parser_ = {};
|
||||
state_ = State::kReadingEbmlLaceSizes;
|
||||
continue;
|
||||
|
||||
case State::kReadingEbmlLaceSizes:
|
||||
assert(value_.num_frames > 0);
|
||||
assert(!lace_sizes_.empty());
|
||||
while (lace_sizes_.size() < value_.num_frames - 1) {
|
||||
status = uint_parser_.Feed(callback, reader, &local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
header_bytes_read_ += local_num_bytes_read;
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
constexpr std::uint64_t one = 1; // Prettier than a static_cast.
|
||||
std::uint64_t offset =
|
||||
(one << (uint_parser_.encoded_length() * 7 - 1)) - 1;
|
||||
lace_sizes_.push_back(lace_sizes_.back() + uint_parser_.value() -
|
||||
offset);
|
||||
uint_parser_ = {};
|
||||
}
|
||||
state_ = State::kValidatingSize;
|
||||
continue;
|
||||
|
||||
case State::kCalculatingFixedLaceSizes: {
|
||||
assert(value_.num_frames > 0);
|
||||
assert(lace_sizes_.empty());
|
||||
if (header_bytes_read_ >= frame_metadata_.parent_element.size) {
|
||||
return Status(Status::kInvalidElementValue);
|
||||
}
|
||||
std::uint64_t laced_data_size =
|
||||
frame_metadata_.parent_element.size - header_bytes_read_;
|
||||
std::uint64_t frame_size = laced_data_size / value_.num_frames;
|
||||
if (laced_data_size % value_.num_frames != 0) {
|
||||
return Status(Status::kInvalidElementValue);
|
||||
}
|
||||
lace_sizes_.resize(value_.num_frames, frame_size);
|
||||
frame_metadata_.position =
|
||||
frame_metadata_.parent_element.position + header_bytes_read_;
|
||||
frame_metadata_.size = frame_size;
|
||||
state_ = State::kReadingFrames;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kValidatingSize: {
|
||||
std::uint64_t sum = std::accumulate(
|
||||
lace_sizes_.begin(), lace_sizes_.end(), header_bytes_read_);
|
||||
if (sum >= frame_metadata_.parent_element.size) {
|
||||
return Status(Status::kInvalidElementValue);
|
||||
}
|
||||
lace_sizes_.push_back(frame_metadata_.parent_element.size - sum);
|
||||
frame_metadata_.position = frame_metadata_.parent_element.position +
|
||||
frame_metadata_.parent_element.header_size +
|
||||
header_bytes_read_;
|
||||
frame_metadata_.size = lace_sizes_[0];
|
||||
state_ = State::kReadingFrames;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kSkipping:
|
||||
do {
|
||||
// Skip the remaining part of the header and all of the frames.
|
||||
status = reader->Skip(
|
||||
frame_metadata_.parent_element.size - header_bytes_read_,
|
||||
&local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
header_bytes_read_ += local_num_bytes_read;
|
||||
} while (status.code == Status::kOkPartial);
|
||||
return status;
|
||||
|
||||
case State::kReadingFrames:
|
||||
assert(value_.num_frames > 0);
|
||||
assert(lace_sizes_.size() == value_.num_frames);
|
||||
for (; current_lace_ < lace_sizes_.size(); ++current_lace_) {
|
||||
const std::uint64_t original = lace_sizes_[current_lace_];
|
||||
status = callback->OnFrame(frame_metadata_, reader,
|
||||
&lace_sizes_[current_lace_]);
|
||||
*num_bytes_read += original - lace_sizes_[current_lace_];
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
assert(lace_sizes_[current_lace_] == 0);
|
||||
if (current_lace_ + 1 < lace_sizes_.size()) {
|
||||
frame_metadata_.position += frame_metadata_.size;
|
||||
frame_metadata_.size = lace_sizes_[current_lace_ + 1];
|
||||
}
|
||||
}
|
||||
state_ = State::kDone;
|
||||
continue;
|
||||
|
||||
case State::kDone:
|
||||
return BasicBlockEnd(frame_metadata_.parent_element, value_, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> bool BasicBlockParser<T>::WasSkipped() const {
|
||||
return state_ == State::kSkipping;
|
||||
}
|
||||
|
||||
template class BasicBlockParser<Block>;
|
||||
template class BasicBlockParser<SimpleBlock>;
|
||||
|
||||
} // namespace webm
|
||||
123
webm_parser/src/block_parser.h
Normal file
123
webm_parser/src/block_parser.h
Normal file
@@ -0,0 +1,123 @@
|
||||
// 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.
|
||||
#ifndef SRC_BLOCK_PARSER_H_
|
||||
#define SRC_BLOCK_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "src/block_header_parser.h"
|
||||
#include "src/element_parser.h"
|
||||
#include "src/var_int_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Parses Block and SimpleBlock elements. It is recommended to use the
|
||||
// BlockParser and SimpleBlockParser aliases.
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Block
|
||||
// http://matroska.org/technical/specs/index.html#SimpleBlock
|
||||
// http://www.webmproject.org/docs/container/#SimpleBlock
|
||||
// http://www.webmproject.org/docs/container/#Block
|
||||
// http://matroska.org/technical/specs/index.html#block_structure
|
||||
// http://matroska.org/technical/specs/index.html#simpleblock_structure
|
||||
template <typename T> class BasicBlockParser : public ElementParser {
|
||||
static_assert(std::is_same<T, Block>::value ||
|
||||
std::is_same<T, SimpleBlock>::value,
|
||||
"T must be Block or SimpleBlock");
|
||||
|
||||
public:
|
||||
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
bool WasSkipped() const override;
|
||||
|
||||
// Gets the parsed block header information. The frames are not included. This
|
||||
// must not be called until the parse has been successfully completed.
|
||||
const T& value() const {
|
||||
assert(state_ == State::kDone);
|
||||
return value_;
|
||||
}
|
||||
|
||||
// Gets the parsed block header information. The frames are not included. This
|
||||
// must not be called until the parse has been successfully completed.
|
||||
T* mutable_value() {
|
||||
assert(state_ == State::kDone);
|
||||
return &value_;
|
||||
}
|
||||
|
||||
private:
|
||||
// The number of header bytes read (header meaning everything before the
|
||||
// frames).
|
||||
std::uint64_t header_bytes_read_ = 0;
|
||||
|
||||
// The parsed header value for the element.
|
||||
T value_{};
|
||||
|
||||
// Metadata for the frame that is currently being read.
|
||||
FrameMetadata frame_metadata_;
|
||||
|
||||
// Parser for parsing header metadata that is common between Block and
|
||||
// SimpleBlock.
|
||||
BlockHeaderParser header_parser_;
|
||||
|
||||
// Parser for parsing unsigned EBML variable-sized integers.
|
||||
VarIntParser uint_parser_;
|
||||
|
||||
// The current lace size when parsing Xiph lace sizes.
|
||||
std::uint64_t xiph_lace_size_ = 0;
|
||||
|
||||
// Lace (frame) sizes, where each entry represents the size of a frame.
|
||||
std::vector<std::uint64_t> lace_sizes_;
|
||||
|
||||
// The current index into lace_sizes_ for the current frame being read.
|
||||
std::size_t current_lace_ = 0;
|
||||
|
||||
// Parsing states for the finite-state machine.
|
||||
enum class State {
|
||||
// State Transitions to state When
|
||||
kReadingHeader, // kGettingAction no lacing
|
||||
// kReadingLaceCount yes lacing
|
||||
kReadingLaceCount, // kGettingAction no errors
|
||||
kGettingAction, // kSkipping action == skip
|
||||
// kValidatingSize no lacing
|
||||
// kReadingXiphLaceSizes xiph lacing
|
||||
// kReadingFirstEbmlLaceSize ebml lacing
|
||||
// kCalculatingFixedLaceSizes fixed lacing
|
||||
kReadingXiphLaceSizes, // kValidatingSize all sizes read
|
||||
kReadingFirstEbmlLaceSize, // kReadingEbmlLaceSizes first size read
|
||||
kReadingEbmlLaceSizes, // kValidatingSize all sizes read
|
||||
kCalculatingFixedLaceSizes, // kReadingFrames no errors
|
||||
kValidatingSize, // kReadingFrames no errors
|
||||
kSkipping, // No transitions from here (must call Init)
|
||||
kReadingFrames, // kDone all frames read
|
||||
kDone, // No transitions from here (must call Init)
|
||||
};
|
||||
|
||||
// The current state of the parser.
|
||||
State state_ = State::kReadingHeader;
|
||||
};
|
||||
|
||||
extern template class BasicBlockParser<Block>;
|
||||
extern template class BasicBlockParser<SimpleBlock>;
|
||||
|
||||
using BlockParser = BasicBlockParser<Block>;
|
||||
using SimpleBlockParser = BasicBlockParser<SimpleBlock>;
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_BLOCK_PARSER_H_
|
||||
95
webm_parser/src/bool_parser.h
Normal file
95
webm_parser/src/bool_parser.h
Normal file
@@ -0,0 +1,95 @@
|
||||
// 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.
|
||||
#ifndef SRC_BOOL_PARSER_H_
|
||||
#define SRC_BOOL_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/element_parser.h"
|
||||
#include "src/parser_utils.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Parses a boolean from a byte stream. EBML does not have a boolean type, but
|
||||
// the Matroska spec defines some unsigned integer elements that have a range of
|
||||
// [0, 1]. The BoolParser parses these unsigned integer elements into
|
||||
// true/false, and reports a Status::kInvalidElementValue error if the integer
|
||||
// is outside of its permitted range.
|
||||
class BoolParser : public ElementParser {
|
||||
public:
|
||||
explicit BoolParser(bool default_value = false)
|
||||
: default_value_(default_value) {}
|
||||
|
||||
Status Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) override {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
// Booleans are really just unsigned integers with a range limit of 0-1.
|
||||
// Unsigned integers can't be encoded with more than 8 bytes.
|
||||
if (metadata.size > 8) {
|
||||
return Status(Status::kInvalidElementSize);
|
||||
}
|
||||
|
||||
size_ = num_bytes_remaining_ = static_cast<int>(metadata.size);
|
||||
value_ = default_value_;
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
std::uint64_t uint_value = 0;
|
||||
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
|
||||
&uint_value, num_bytes_read);
|
||||
num_bytes_remaining_ -= static_cast<int>(*num_bytes_read);
|
||||
|
||||
// Only the last byte should have a value, and it should only be 0 or 1.
|
||||
if ((num_bytes_remaining_ != 0 && uint_value != 0) || uint_value > 1) {
|
||||
return Status(Status::kInvalidElementValue);
|
||||
}
|
||||
|
||||
if (size_ > 0) {
|
||||
value_ = uint_value == 1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Gets the parsed bool. This must not be called until the parse had been
|
||||
// successfully completed.
|
||||
bool value() const {
|
||||
assert(num_bytes_remaining_ == 0);
|
||||
return value_;
|
||||
}
|
||||
|
||||
// Gets the parsed bool. This must not be called until the parse had been
|
||||
// successfully completed.
|
||||
bool* mutable_value() {
|
||||
assert(num_bytes_remaining_ == 0);
|
||||
return &value_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool value_;
|
||||
bool default_value_;
|
||||
int num_bytes_remaining_ = -1;
|
||||
int size_;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_BOOL_PARSER_H_
|
||||
110
webm_parser/src/buffer_reader.cc
Normal file
110
webm_parser/src/buffer_reader.cc
Normal file
@@ -0,0 +1,110 @@
|
||||
// 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 "webm/buffer_reader.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
BufferReader::BufferReader(std::initializer_list<std::uint8_t> bytes)
|
||||
: data_(bytes) {}
|
||||
|
||||
BufferReader::BufferReader(const std::vector<std::uint8_t>& vector)
|
||||
: data_(vector) {}
|
||||
|
||||
BufferReader::BufferReader(std::vector<std::uint8_t>&& vector)
|
||||
: data_(std::move(vector)) {}
|
||||
|
||||
BufferReader::BufferReader(BufferReader&& other)
|
||||
: data_(std::move(other.data_)), pos_(other.pos_) {
|
||||
other.pos_ = 0;
|
||||
}
|
||||
|
||||
BufferReader& BufferReader::operator=(BufferReader&& other) {
|
||||
if (this != &other) {
|
||||
data_ = std::move(other.data_);
|
||||
pos_ = other.pos_;
|
||||
other.pos_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
BufferReader& BufferReader::operator=(
|
||||
std::initializer_list<std::uint8_t> bytes) {
|
||||
data_ = std::vector<std::uint8_t>(bytes);
|
||||
pos_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Status BufferReader::Read(std::size_t num_to_read, std::uint8_t* buffer,
|
||||
std::uint64_t* num_actually_read) {
|
||||
assert(num_to_read > 0);
|
||||
assert(buffer != nullptr);
|
||||
assert(num_actually_read != nullptr);
|
||||
|
||||
*num_actually_read = 0;
|
||||
std::size_t expected = num_to_read;
|
||||
|
||||
std::size_t num_remaining = data_.size() - pos_;
|
||||
if (num_remaining == 0) {
|
||||
return Status(Status::kEndOfFile);
|
||||
}
|
||||
|
||||
if (num_to_read > num_remaining) {
|
||||
num_to_read = static_cast<std::size_t>(num_remaining);
|
||||
}
|
||||
|
||||
std::copy_n(data_.data() + pos_, num_to_read, buffer);
|
||||
*num_actually_read = num_to_read;
|
||||
pos_ += num_to_read;
|
||||
|
||||
if (*num_actually_read != expected) {
|
||||
return Status(Status::kOkPartial);
|
||||
}
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status BufferReader::Skip(std::uint64_t num_to_skip,
|
||||
std::uint64_t* num_actually_skipped) {
|
||||
assert(num_to_skip > 0);
|
||||
assert(num_actually_skipped != nullptr);
|
||||
|
||||
*num_actually_skipped = 0;
|
||||
std::uint64_t expected = num_to_skip;
|
||||
|
||||
std::size_t num_remaining = data_.size() - pos_;
|
||||
if (num_remaining == 0) {
|
||||
return Status(Status::kEndOfFile);
|
||||
}
|
||||
|
||||
if (num_to_skip > num_remaining) {
|
||||
num_to_skip = static_cast<std::uint64_t>(num_remaining);
|
||||
}
|
||||
|
||||
*num_actually_skipped = num_to_skip;
|
||||
pos_ += num_to_skip;
|
||||
|
||||
if (*num_actually_skipped != expected) {
|
||||
return Status(Status::kOkPartial);
|
||||
}
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
std::uint64_t BufferReader::Position() const { return pos_; }
|
||||
|
||||
} // namespace webm
|
||||
143
webm_parser/src/byte_parser.h
Normal file
143
webm_parser/src/byte_parser.h
Normal file
@@ -0,0 +1,143 @@
|
||||
// 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.
|
||||
#ifndef SRC_BYTE_PARSER_H_
|
||||
#define SRC_BYTE_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "src/element_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Parses an EBML string (UTF-8 and ASCII) or binary element from a byte stream.
|
||||
// Spec reference for string/binary elements:
|
||||
// http://matroska.org/technical/specs/index.html#EBML_ex
|
||||
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#ebml-element-types
|
||||
template <typename T> class ByteParser : public ElementParser {
|
||||
public:
|
||||
static_assert(std::is_same<T, std::vector<std::uint8_t>>::value ||
|
||||
std::is_same<T, std::string>::value,
|
||||
"T must be std::vector<std::uint8_t> or std::string");
|
||||
|
||||
// Constructs a new parser which will use the given default_value as the
|
||||
// value for the element if its size is zero. Defaults to the empty string
|
||||
// or empty binary element (as the EBML spec indicates).
|
||||
explicit ByteParser(T default_value = {})
|
||||
: default_value_(std::move(default_value)) {}
|
||||
|
||||
ByteParser(ByteParser&&) = default;
|
||||
ByteParser& operator=(ByteParser&&) = default;
|
||||
|
||||
ByteParser(const ByteParser&) = delete;
|
||||
ByteParser& operator=(const ByteParser&) = delete;
|
||||
|
||||
Status Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) override {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
if (metadata.size == kUnknownElementSize) {
|
||||
return Status(Status::kInvalidElementSize);
|
||||
}
|
||||
|
||||
if (metadata.size > std::numeric_limits<std::size_t>::max() ||
|
||||
metadata.size > value_.max_size()) {
|
||||
return Status(Status::kNotEnoughMemory);
|
||||
}
|
||||
|
||||
#if WEBM_FUZZER_BYTE_ELEMENT_SIZE_LIMIT
|
||||
// AFL and ASan just kill the process if too much memory is allocated, so
|
||||
// let's cap the maximum size of the element. It's too easy for the fuzzer
|
||||
// to make an element with a ridiculously huge size, and that just creates
|
||||
// uninteresting false positives.
|
||||
if (metadata.size > WEBM_FUZZER_BYTE_ELEMENT_SIZE_LIMIT) {
|
||||
return Status(Status::kNotEnoughMemory);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (metadata.size == 0) {
|
||||
value_ = default_value_;
|
||||
total_read_ = default_value_.size();
|
||||
} else {
|
||||
value_.resize(static_cast<std::size_t>(metadata.size));
|
||||
total_read_ = 0;
|
||||
}
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
*num_bytes_read = 0;
|
||||
|
||||
if (total_read_ == value_.size()) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status status;
|
||||
do {
|
||||
std::uint64_t local_num_bytes_read = 0;
|
||||
std::uint8_t* buffer =
|
||||
reinterpret_cast<std::uint8_t*>(&value_.front()) + total_read_;
|
||||
std::size_t buffer_size = value_.size() - total_read_;
|
||||
status = reader->Read(buffer_size, buffer, &local_num_bytes_read);
|
||||
assert((status.completed_ok() && local_num_bytes_read == buffer_size) ||
|
||||
(status.ok() && local_num_bytes_read < buffer_size) ||
|
||||
(!status.ok() && local_num_bytes_read == 0));
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
total_read_ += static_cast<std::size_t>(local_num_bytes_read);
|
||||
} while (status.code == Status::kOkPartial);
|
||||
|
||||
// UTF-8 and ASCII string elements can be padded with NUL characters at the
|
||||
// end, which should be ignored.
|
||||
if (std::is_same<T, std::string>::value && status.completed_ok()) {
|
||||
while (!value_.empty() && value_.back() == '\0') {
|
||||
value_.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Gets the parsed value. This must not be called until the parse has been
|
||||
// successfully completed.
|
||||
const T& value() const {
|
||||
assert(total_read_ >= value_.size());
|
||||
return value_;
|
||||
}
|
||||
|
||||
// Gets the parsed value. This must not be called until the parse has been
|
||||
// successfully completed.
|
||||
T* mutable_value() {
|
||||
assert(total_read_ >= value_.size());
|
||||
return &value_;
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
T default_value_;
|
||||
std::size_t total_read_;
|
||||
};
|
||||
|
||||
using StringParser = ByteParser<std::string>;
|
||||
using BinaryParser = ByteParser<std::vector<std::uint8_t>>;
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_BYTE_PARSER_H_
|
||||
150
webm_parser/src/callback.cc
Normal file
150
webm_parser/src/callback.cc
Normal file
@@ -0,0 +1,150 @@
|
||||
// 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 "webm/callback.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace webm {
|
||||
|
||||
Status Callback::OnElementBegin(const ElementMetadata& metadata,
|
||||
Action* action) {
|
||||
assert(action != nullptr);
|
||||
*action = Action::kRead;
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnUnknownElement(const ElementMetadata& metadata,
|
||||
Reader* reader,
|
||||
std::uint64_t* bytes_remaining) {
|
||||
assert(reader != nullptr);
|
||||
assert(bytes_remaining != nullptr);
|
||||
return Skip(reader, bytes_remaining);
|
||||
}
|
||||
|
||||
Status Callback::OnEbml(const ElementMetadata& metadata, const Ebml& ebml) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnVoid(const ElementMetadata& metadata, Reader* reader,
|
||||
std::uint64_t* bytes_remaining) {
|
||||
assert(reader != nullptr);
|
||||
assert(bytes_remaining != nullptr);
|
||||
return Skip(reader, bytes_remaining);
|
||||
}
|
||||
|
||||
Status Callback::OnSegmentBegin(const ElementMetadata& metadata,
|
||||
Action* action) {
|
||||
assert(action != nullptr);
|
||||
*action = Action::kRead;
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnSeek(const ElementMetadata& metadata, const Seek& seek) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnInfo(const ElementMetadata& metadata, const Info& info) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnClusterBegin(const ElementMetadata& metadata,
|
||||
const Cluster& cluster, Action* action) {
|
||||
assert(action != nullptr);
|
||||
*action = Action::kRead;
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnSimpleBlockBegin(const ElementMetadata& metadata,
|
||||
const SimpleBlock& simple_block,
|
||||
Action* action) {
|
||||
assert(action != nullptr);
|
||||
*action = Action::kRead;
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnSimpleBlockEnd(const ElementMetadata& metadata,
|
||||
const SimpleBlock& simple_block) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnBlockGroupBegin(const ElementMetadata& metadata,
|
||||
Action* action) {
|
||||
assert(action != nullptr);
|
||||
*action = Action::kRead;
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnBlockBegin(const ElementMetadata& metadata,
|
||||
const Block& block, Action* action) {
|
||||
assert(action != nullptr);
|
||||
*action = Action::kRead;
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnBlockEnd(const ElementMetadata& metadata,
|
||||
const Block& block) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnBlockGroupEnd(const ElementMetadata& metadata,
|
||||
const BlockGroup& block_group) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnFrame(const FrameMetadata& metadata, Reader* reader,
|
||||
std::uint64_t* bytes_remaining) {
|
||||
assert(reader != nullptr);
|
||||
assert(bytes_remaining != nullptr);
|
||||
return Skip(reader, bytes_remaining);
|
||||
}
|
||||
|
||||
Status Callback::OnClusterEnd(const ElementMetadata& metadata,
|
||||
const Cluster& cluster) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnTrackEntry(const ElementMetadata& metadata,
|
||||
const TrackEntry& track_entry) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnCuePoint(const ElementMetadata& metadata,
|
||||
const CuePoint& cue_point) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnEditionEntry(const ElementMetadata& metadata,
|
||||
const EditionEntry& edition_entry) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnTag(const ElementMetadata& metadata, const Tag& tag) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::OnSegmentEnd(const ElementMetadata& metadata) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Callback::Skip(Reader* reader, std::uint64_t* bytes_remaining) {
|
||||
assert(reader != nullptr);
|
||||
assert(bytes_remaining != nullptr);
|
||||
|
||||
if (*bytes_remaining == 0) return Status(Status::kOkCompleted);
|
||||
|
||||
Status status;
|
||||
do {
|
||||
std::uint64_t num_actually_skipped;
|
||||
status = reader->Skip(*bytes_remaining, &num_actually_skipped);
|
||||
*bytes_remaining -= num_actually_skipped;
|
||||
} while (status.code == Status::kOkPartial);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
43
webm_parser/src/chapter_atom_parser.h
Normal file
43
webm_parser/src/chapter_atom_parser.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// 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.
|
||||
#ifndef SRC_CHAPTER_ATOM_PARSER_H_
|
||||
#define SRC_CHAPTER_ATOM_PARSER_H_
|
||||
|
||||
#include "src/byte_parser.h"
|
||||
#include "src/chapter_display_parser.h"
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "src/recursive_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#ChapterAtom
|
||||
// http://www.webmproject.org/docs/container/#ChapterAtom
|
||||
class ChapterAtomParser : public MasterValueParser<ChapterAtom> {
|
||||
public:
|
||||
ChapterAtomParser()
|
||||
: MasterValueParser<ChapterAtom>(
|
||||
MakeChild<UnsignedIntParser>(Id::kChapterUid, &ChapterAtom::uid),
|
||||
MakeChild<StringParser>(Id::kChapterStringUid,
|
||||
&ChapterAtom::string_uid),
|
||||
MakeChild<UnsignedIntParser>(Id::kChapterTimeStart,
|
||||
&ChapterAtom::time_start),
|
||||
MakeChild<UnsignedIntParser>(Id::kChapterTimeEnd,
|
||||
&ChapterAtom::time_end),
|
||||
MakeChild<ChapterDisplayParser>(Id::kChapterDisplay,
|
||||
&ChapterAtom::displays),
|
||||
MakeChild<RecursiveParser<ChapterAtomParser>>(
|
||||
Id::kChapterAtom, &ChapterAtom::atoms)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_CHAPTER_ATOM_PARSER_H_
|
||||
34
webm_parser/src/chapter_display_parser.h
Normal file
34
webm_parser/src/chapter_display_parser.h
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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.
|
||||
#ifndef SRC_CHAPTER_DISPLAY_PARSER_H_
|
||||
#define SRC_CHAPTER_DISPLAY_PARSER_H_
|
||||
|
||||
#include "src/byte_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#ChapterDisplay
|
||||
// http://www.webmproject.org/docs/container/#ChapterDisplay
|
||||
class ChapterDisplayParser : public MasterValueParser<ChapterDisplay> {
|
||||
public:
|
||||
ChapterDisplayParser()
|
||||
: MasterValueParser<ChapterDisplay>(
|
||||
MakeChild<StringParser>(Id::kChapString, &ChapterDisplay::string),
|
||||
MakeChild<StringParser>(Id::kChapLanguage,
|
||||
&ChapterDisplay::languages),
|
||||
MakeChild<StringParser>(Id::kChapCountry,
|
||||
&ChapterDisplay::countries)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_CHAPTER_DISPLAY_PARSER_H_
|
||||
28
webm_parser/src/chapters_parser.h
Normal file
28
webm_parser/src/chapters_parser.h
Normal file
@@ -0,0 +1,28 @@
|
||||
// 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.
|
||||
#ifndef SRC_CHAPTERS_PARSER_H_
|
||||
#define SRC_CHAPTERS_PARSER_H_
|
||||
|
||||
#include "src/edition_entry_parser.h"
|
||||
#include "src/master_parser.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Chapters
|
||||
// http://www.webmproject.org/docs/container/#Chapters
|
||||
class ChaptersParser : public MasterParser {
|
||||
public:
|
||||
ChaptersParser()
|
||||
: MasterParser(MakeChild<EditionEntryParser>(Id::kEditionEntry)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_CHAPTERS_PARSER_H_
|
||||
48
webm_parser/src/cluster_parser.h
Normal file
48
webm_parser/src/cluster_parser.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// 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.
|
||||
#ifndef SRC_CLUSTER_PARSER_H_
|
||||
#define SRC_CLUSTER_PARSER_H_
|
||||
|
||||
#include "src/block_group_parser.h"
|
||||
#include "src/block_parser.h"
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Cluster
|
||||
// http://www.webmproject.org/docs/container/#Cluster
|
||||
class ClusterParser : public MasterValueParser<Cluster> {
|
||||
public:
|
||||
ClusterParser()
|
||||
: MasterValueParser<Cluster>(
|
||||
MakeChild<UnsignedIntParser>(Id::kTimecode, &Cluster::timecode),
|
||||
MakeChild<UnsignedIntParser>(Id::kPrevSize,
|
||||
&Cluster::previous_size),
|
||||
MakeChild<SimpleBlockParser>(Id::kSimpleBlock,
|
||||
&Cluster::simple_blocks)
|
||||
.UseAsStartEvent(),
|
||||
MakeChild<BlockGroupParser>(Id::kBlockGroup, &Cluster::block_groups)
|
||||
.UseAsStartEvent()) {}
|
||||
|
||||
protected:
|
||||
Status OnParseStarted(Callback* callback, Action* action) override {
|
||||
return callback->OnClusterBegin(metadata(Id::kCluster), value(), action);
|
||||
}
|
||||
|
||||
Status OnParseCompleted(Callback* callback) override {
|
||||
return callback->OnClusterEnd(metadata(Id::kCluster), value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_CLUSTER_PARSER_H_
|
||||
55
webm_parser/src/colour_parser.h
Normal file
55
webm_parser/src/colour_parser.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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.
|
||||
#ifndef SRC_COLOUR_PARSER_H_
|
||||
#define SRC_COLOUR_PARSER_H_
|
||||
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "src/mastering_metadata_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Colour
|
||||
// http://www.webmproject.org/docs/container/#Colour
|
||||
class ColourParser : public MasterValueParser<Colour> {
|
||||
public:
|
||||
ColourParser()
|
||||
: MasterValueParser<Colour>(
|
||||
MakeChild<IntParser<MatrixCoefficients>>(
|
||||
Id::kMatrixCoefficients, &Colour::matrix_coefficients),
|
||||
MakeChild<UnsignedIntParser>(Id::kBitsPerChannel,
|
||||
&Colour::bits_per_channel),
|
||||
MakeChild<UnsignedIntParser>(Id::kChromaSubsamplingHorz,
|
||||
&Colour::chroma_subsampling_x),
|
||||
MakeChild<UnsignedIntParser>(Id::kChromaSubsamplingVert,
|
||||
&Colour::chroma_subsampling_y),
|
||||
MakeChild<UnsignedIntParser>(Id::kCbSubsamplingHorz,
|
||||
&Colour::cb_subsampling_x),
|
||||
MakeChild<UnsignedIntParser>(Id::kCbSubsamplingVert,
|
||||
&Colour::cb_subsampling_y),
|
||||
MakeChild<UnsignedIntParser>(Id::kChromaSitingHorz,
|
||||
&Colour::chroma_siting_x),
|
||||
MakeChild<UnsignedIntParser>(Id::kChromaSitingVert,
|
||||
&Colour::chroma_siting_y),
|
||||
MakeChild<IntParser<Range>>(Id::kRange, &Colour::range),
|
||||
MakeChild<IntParser<TransferCharacteristics>>(
|
||||
Id::kTransferCharacteristics,
|
||||
&Colour::transfer_characteristics),
|
||||
MakeChild<IntParser<Primaries>>(Id::kPrimaries, &Colour::primaries),
|
||||
MakeChild<UnsignedIntParser>(Id::kMaxCll, &Colour::max_cll),
|
||||
MakeChild<UnsignedIntParser>(Id::kMaxFall, &Colour::max_fall),
|
||||
MakeChild<MasteringMetadataParser>(Id::kMasteringMetadata,
|
||||
&Colour::mastering_metadata)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_COLOUR_PARSER_H_
|
||||
32
webm_parser/src/content_enc_aes_settings_parser.h
Normal file
32
webm_parser/src/content_enc_aes_settings_parser.h
Normal file
@@ -0,0 +1,32 @@
|
||||
// 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.
|
||||
#ifndef SRC_CONTENT_ENC_AES_SETTINGS_PARSER_H_
|
||||
#define SRC_CONTENT_ENC_AES_SETTINGS_PARSER_H_
|
||||
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://www.webmproject.org/docs/webm-encryption/#42-new-matroskawebm-elements
|
||||
class ContentEncAesSettingsParser
|
||||
: public MasterValueParser<ContentEncAesSettings> {
|
||||
public:
|
||||
ContentEncAesSettingsParser()
|
||||
: MasterValueParser<ContentEncAesSettings>(
|
||||
MakeChild<IntParser<AesSettingsCipherMode>>(
|
||||
Id::kAesSettingsCipherMode,
|
||||
&ContentEncAesSettings::aes_settings_cipher_mode)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_CONTENT_ENC_AES_SETTINGS_PARSER_H_
|
||||
38
webm_parser/src/content_encoding_parser.h
Normal file
38
webm_parser/src/content_encoding_parser.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// 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.
|
||||
#ifndef SRC_CONTENT_ENCODING_PARSER_H_
|
||||
#define SRC_CONTENT_ENCODING_PARSER_H_
|
||||
|
||||
#include "src/content_encryption_parser.h"
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#ContentEncoding
|
||||
// http://www.webmproject.org/docs/container/#ContentEncoding
|
||||
class ContentEncodingParser : public MasterValueParser<ContentEncoding> {
|
||||
public:
|
||||
ContentEncodingParser()
|
||||
: MasterValueParser<ContentEncoding>(
|
||||
MakeChild<UnsignedIntParser>(Id::kContentEncodingOrder,
|
||||
&ContentEncoding::order),
|
||||
MakeChild<UnsignedIntParser>(Id::kContentEncodingScope,
|
||||
&ContentEncoding::scope),
|
||||
MakeChild<IntParser<ContentEncodingType>>(Id::kContentEncodingType,
|
||||
&ContentEncoding::type),
|
||||
MakeChild<ContentEncryptionParser>(Id::kContentEncryption,
|
||||
&ContentEncoding::encryption)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_CONTENT_ENCODING_PARSER_H_
|
||||
30
webm_parser/src/content_encodings_parser.h
Normal file
30
webm_parser/src/content_encodings_parser.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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.
|
||||
#ifndef SRC_CONTENT_ENCODINGS_PARSER_H_
|
||||
#define SRC_CONTENT_ENCODINGS_PARSER_H_
|
||||
|
||||
#include "src/content_encoding_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#ContentEncodings
|
||||
// http://www.webmproject.org/docs/container/#ContentEncodings
|
||||
class ContentEncodingsParser : public MasterValueParser<ContentEncodings> {
|
||||
public:
|
||||
ContentEncodingsParser()
|
||||
: MasterValueParser<ContentEncodings>(MakeChild<ContentEncodingParser>(
|
||||
Id::kContentEncoding, &ContentEncodings::encodings)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_CONTENT_ENCODINGS_PARSER_H_
|
||||
37
webm_parser/src/content_encryption_parser.h
Normal file
37
webm_parser/src/content_encryption_parser.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// 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.
|
||||
#ifndef SRC_CONTENT_ENCRYPTION_PARSER_H_
|
||||
#define SRC_CONTENT_ENCRYPTION_PARSER_H_
|
||||
|
||||
#include "src/byte_parser.h"
|
||||
#include "src/content_enc_aes_settings_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#ContentEncryption
|
||||
// http://www.webmproject.org/docs/container/#ContentEncryption
|
||||
class ContentEncryptionParser : public MasterValueParser<ContentEncryption> {
|
||||
public:
|
||||
ContentEncryptionParser()
|
||||
: MasterValueParser<ContentEncryption>(
|
||||
MakeChild<IntParser<ContentEncAlgo>>(Id::kContentEncAlgo,
|
||||
&ContentEncryption::algorithm),
|
||||
MakeChild<BinaryParser>(Id::kContentEncKeyId,
|
||||
&ContentEncryption::key_id),
|
||||
MakeChild<ContentEncAesSettingsParser>(
|
||||
Id::kContentEncAesSettings, &ContentEncryption::aes_settings)) {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_CONTENT_ENCRYPTION_PARSER_H_
|
||||
38
webm_parser/src/cue_point_parser.h
Normal file
38
webm_parser/src/cue_point_parser.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// 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.
|
||||
#ifndef SRC_CUE_POINT_PARSER_H_
|
||||
#define SRC_CUE_POINT_PARSER_H_
|
||||
|
||||
#include "src/cue_track_positions_parser.h"
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#CuePoint
|
||||
// http://www.webmproject.org/docs/container/#CuePoint
|
||||
class CuePointParser : public MasterValueParser<CuePoint> {
|
||||
public:
|
||||
CuePointParser()
|
||||
: MasterValueParser<CuePoint>(
|
||||
MakeChild<UnsignedIntParser>(Id::kCueTime, &CuePoint::time),
|
||||
MakeChild<CueTrackPositionsParser>(
|
||||
Id::kCueTrackPositions, &CuePoint::cue_track_positions)) {}
|
||||
|
||||
protected:
|
||||
Status OnParseCompleted(Callback* callback) override {
|
||||
return callback->OnCuePoint(metadata(Id::kCuePoint), value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_CUE_POINT_PARSER_H_
|
||||
39
webm_parser/src/cue_track_positions_parser.h
Normal file
39
webm_parser/src/cue_track_positions_parser.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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.
|
||||
#ifndef SRC_CUE_TRACK_POSITIONS_PARSER_H_
|
||||
#define SRC_CUE_TRACK_POSITIONS_PARSER_H_
|
||||
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#CueTrackPositions
|
||||
// http://www.webmproject.org/docs/container/#CueTrackPositions
|
||||
class CueTrackPositionsParser : public MasterValueParser<CueTrackPositions> {
|
||||
public:
|
||||
CueTrackPositionsParser()
|
||||
: MasterValueParser<CueTrackPositions>(
|
||||
MakeChild<UnsignedIntParser>(Id::kCueTrack,
|
||||
&CueTrackPositions::track),
|
||||
MakeChild<UnsignedIntParser>(Id::kCueClusterPosition,
|
||||
&CueTrackPositions::cluster_position),
|
||||
MakeChild<UnsignedIntParser>(Id::kCueRelativePosition,
|
||||
&CueTrackPositions::relative_position),
|
||||
MakeChild<UnsignedIntParser>(Id::kCueDuration,
|
||||
&CueTrackPositions::duration),
|
||||
MakeChild<UnsignedIntParser>(Id::kCueBlockNumber,
|
||||
&CueTrackPositions::block_number)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_CUE_TRACK_POSITIONS_PARSER_H_
|
||||
27
webm_parser/src/cues_parser.h
Normal file
27
webm_parser/src/cues_parser.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// 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.
|
||||
#ifndef SRC_CUES_PARSER_H_
|
||||
#define SRC_CUES_PARSER_H_
|
||||
|
||||
#include "src/cue_point_parser.h"
|
||||
#include "src/master_parser.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Cues
|
||||
// http://www.webmproject.org/docs/container/#Cues
|
||||
class CuesParser : public MasterParser {
|
||||
public:
|
||||
CuesParser() : MasterParser(MakeChild<CuePointParser>(Id::kCuePoint)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_CUES_PARSER_H_
|
||||
72
webm_parser/src/date_parser.cc
Normal file
72
webm_parser/src/date_parser.cc
Normal file
@@ -0,0 +1,72 @@
|
||||
// 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 "src/date_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#include "src/parser_utils.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#EBML_ex
|
||||
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#ebml-element-types
|
||||
DateParser::DateParser(std::int64_t default_value)
|
||||
: default_value_(default_value) {}
|
||||
|
||||
Status DateParser::Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
if (metadata.size != 0 && metadata.size != 8) {
|
||||
return Status(Status::kInvalidElementSize);
|
||||
}
|
||||
|
||||
num_bytes_remaining_ = static_cast<int>(metadata.size);
|
||||
|
||||
// The meaning of a 0-byte element is still being debated. EBML says the value
|
||||
// is zero; Matroska says it's the default according to whatever the document
|
||||
// spec says. Neither specifies what a 0-byte mandatory element means. I've
|
||||
// asked about this on the Matroska mailing list. I'm going to assume a 0-byte
|
||||
// mandatory element should be treated the same as a 0-byte optional element,
|
||||
// meaning that they both get their default value (which may be some value
|
||||
// other than zero). This applies to all non-master-elements (not just dates).
|
||||
// This parser is an EBML-level parser, and so will default to a value of
|
||||
// zero. The Matroska-level parser can reset this default value to something
|
||||
// else after parsing (as needed).
|
||||
// See:
|
||||
// https://github.com/Matroska-Org/ebml-specification/pull/17
|
||||
// http://lists.matroska.org/pipermail/matroska-devel/2015-October/004866.html
|
||||
if (metadata.size == 0) {
|
||||
value_ = default_value_;
|
||||
} else {
|
||||
value_ = 0;
|
||||
}
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status DateParser::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
|
||||
&value_, num_bytes_read);
|
||||
num_bytes_remaining_ -= static_cast<int>(*num_bytes_read);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
64
webm_parser/src/date_parser.h
Normal file
64
webm_parser/src/date_parser.h
Normal file
@@ -0,0 +1,64 @@
|
||||
// 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.
|
||||
#ifndef SRC_DATE_PARSER_H_
|
||||
#define SRC_DATE_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/element_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Parses an EBML date from a byte stream. EBML dates are signed integer values
|
||||
// that represent the offset, in nanoseconds, from 2001-01-01T00:00:00.00 UTC.
|
||||
class DateParser : public ElementParser {
|
||||
public:
|
||||
// Constructs a new parser which will use the given default_value as the
|
||||
// value for the element if its size is zero. Defaults to the value zero (as
|
||||
// the EBML spec indicates).
|
||||
explicit DateParser(std::int64_t default_value = 0);
|
||||
|
||||
DateParser(DateParser&&) = default;
|
||||
DateParser& operator=(DateParser&&) = default;
|
||||
|
||||
DateParser(const DateParser&) = delete;
|
||||
DateParser& operator=(const DateParser&) = delete;
|
||||
|
||||
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
// Gets the parsed date. This must not be called until the parse had been
|
||||
// successfully completed.
|
||||
std::int64_t value() const {
|
||||
assert(num_bytes_remaining_ == 0);
|
||||
return value_;
|
||||
}
|
||||
|
||||
// Gets the parsed date. This must not be called until the parse had been
|
||||
// successfully completed.
|
||||
std::int64_t* mutable_value() {
|
||||
assert(num_bytes_remaining_ == 0);
|
||||
return &value_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::int64_t value_;
|
||||
std::int64_t default_value_;
|
||||
int num_bytes_remaining_ = -1;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_DATE_PARSER_H_
|
||||
48
webm_parser/src/ebml_parser.h
Normal file
48
webm_parser/src/ebml_parser.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// 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.
|
||||
#ifndef SRC_EBML_PARSER_H_
|
||||
#define SRC_EBML_PARSER_H_
|
||||
|
||||
#include "src/byte_parser.h"
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec references:
|
||||
// http://matroska.org/technical/specs/index.html#EBML
|
||||
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#ebml-header-elements
|
||||
// http://www.webmproject.org/docs/container/#EBML
|
||||
class EbmlParser : public MasterValueParser<Ebml> {
|
||||
public:
|
||||
EbmlParser()
|
||||
: MasterValueParser<Ebml>(
|
||||
MakeChild<UnsignedIntParser>(Id::kEbmlVersion, &Ebml::ebml_version),
|
||||
MakeChild<UnsignedIntParser>(Id::kEbmlReadVersion,
|
||||
&Ebml::ebml_read_version),
|
||||
MakeChild<UnsignedIntParser>(Id::kEbmlMaxIdLength,
|
||||
&Ebml::ebml_max_id_length),
|
||||
MakeChild<UnsignedIntParser>(Id::kEbmlMaxSizeLength,
|
||||
&Ebml::ebml_max_size_length),
|
||||
MakeChild<StringParser>(Id::kDocType, &Ebml::doc_type),
|
||||
MakeChild<UnsignedIntParser>(Id::kDocTypeVersion,
|
||||
&Ebml::doc_type_version),
|
||||
MakeChild<UnsignedIntParser>(Id::kDocTypeReadVersion,
|
||||
&Ebml::doc_type_read_version)) {}
|
||||
|
||||
protected:
|
||||
Status OnParseCompleted(Callback* callback) override {
|
||||
return callback->OnEbml(metadata(Id::kEbml), value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_EBML_PARSER_H_
|
||||
35
webm_parser/src/edition_entry_parser.h
Normal file
35
webm_parser/src/edition_entry_parser.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// 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.
|
||||
#ifndef SRC_EDITION_ENTRY_PARSER_H_
|
||||
#define SRC_EDITION_ENTRY_PARSER_H_
|
||||
|
||||
#include "src/chapter_atom_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#EditionEntry
|
||||
// http://www.webmproject.org/docs/container/#EditionEntry
|
||||
class EditionEntryParser : public MasterValueParser<EditionEntry> {
|
||||
public:
|
||||
EditionEntryParser()
|
||||
: MasterValueParser<EditionEntry>(MakeChild<ChapterAtomParser>(
|
||||
Id::kChapterAtom, &EditionEntry::atoms)) {}
|
||||
|
||||
protected:
|
||||
Status OnParseCompleted(Callback* callback) override {
|
||||
return callback->OnEditionEntry(metadata(Id::kEditionEntry), value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_EDITION_ENTRY_PARSER_H_
|
||||
102
webm_parser/src/element_parser.h
Normal file
102
webm_parser/src/element_parser.h
Normal file
@@ -0,0 +1,102 @@
|
||||
// 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.
|
||||
#ifndef SRC_ELEMENT_PARSER_H_
|
||||
#define SRC_ELEMENT_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/ancestory.h"
|
||||
#include "src/parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/element.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Parses an element from a WebM byte stream. Objects that implement this
|
||||
// interface are expected to be used as follows in order to parse the specific
|
||||
// WebM element that they are designed to handle.
|
||||
//
|
||||
// Reader* reader = ...; // Create some Reader.
|
||||
// Callback* callback = ...; // Create some Callback.
|
||||
//
|
||||
// ElementMetadata metadata = {
|
||||
// id, // Element parsed from the reader.
|
||||
// header_size, // The number of bytes used to encode the id and size.
|
||||
// size_in_bytes, // The number of bytes in the element body.
|
||||
// position, // The position of the element (starting at the ID).
|
||||
// };
|
||||
//
|
||||
// std::uint64_t max_size = ...; // Some upper bound on this element's size.
|
||||
// ElementParser* parser = ...; // Create some parser capable of handling
|
||||
// // elements that match id.
|
||||
//
|
||||
// Status status = parser->Init(metadata, max_size);
|
||||
// if (!status.completed_ok()) {
|
||||
// // An error occurred. See status.code for the reason.
|
||||
// } else {
|
||||
// do {
|
||||
// std::uint64_t num_bytes_read = 0;
|
||||
// status = parser->Feed(callback, reader, &num_bytes_read);
|
||||
// } while (status.code == Status::kOkPartial);
|
||||
//
|
||||
// if (status.completed_ok()) {
|
||||
// // Parsing successfully completed.
|
||||
// } else {
|
||||
// // An error occurred. If status.code is a parsing error (see status.h for
|
||||
// // errors that are considered parsing errors), do not call Feed again;
|
||||
// // parsing has already failed and further progress can't be made. If
|
||||
// // status.code is not a parsing error (i.e. Status::kWouldBlock), then
|
||||
// // Feed may be called again to attempt resuming parsing.
|
||||
// }
|
||||
// }
|
||||
class ElementParser : public Parser {
|
||||
public:
|
||||
// Initializes the parser and prepares it for parsing its element. Returns
|
||||
// Status::kOkCompleted if successful. Must not return Status::kOkPartial (it
|
||||
// is not resumable). metadata is the metadata associated with this element.
|
||||
// max_size must be <= metadata.size (unless metadata.size is
|
||||
// kUnknownElementSize).
|
||||
virtual Status Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) = 0;
|
||||
|
||||
// Initializes the parser after a seek was done and prepares it for parsing.
|
||||
// The reader is now at the position of the child element indicated by
|
||||
// child_metadata, whose ancestory is child_ancestory. The child element for
|
||||
// this parser is the first element in child_ancestory, or if that is empty,
|
||||
// then child_metadata itself. If the child is not a valid child of this
|
||||
// parser, then a debug assertion is made (because that indicates a bug).
|
||||
virtual void InitAfterSeek(const Ancestory& child_ancestory,
|
||||
const ElementMetadata& child_metadata) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// Returns true and sets metadata if this parser read too far and read the
|
||||
// element metadata for an element that is not its child. This may happen, for
|
||||
// example, when an element with unknown size is being read (because its end
|
||||
// is considered the first element that is not a valid child, so it must read
|
||||
// further to detect this). If this did not happen and false is returned, then
|
||||
// metadata will not be modified. metadata must not be null.
|
||||
virtual bool GetCachedMetadata(ElementMetadata* metadata) {
|
||||
assert(metadata != nullptr);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if this parser skipped the element instead of fully parsing
|
||||
// it. This will be true if the user requested a kSkip action from the
|
||||
// Callback in Feed(). This method should only be called after Feed() has
|
||||
// returned kOkCompleted. If the element was skipped, do not try to access its
|
||||
// value; it has no meaningful value and doing so will likely result in an
|
||||
// assertion failing.
|
||||
virtual bool WasSkipped() const { return false; }
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_ELEMENT_PARSER_H_
|
||||
122
webm_parser/src/file_reader.cc
Normal file
122
webm_parser/src/file_reader.cc
Normal file
@@ -0,0 +1,122 @@
|
||||
// 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 "webm/file_reader.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
FileReader::FileReader(FILE* file) : file_(file) { assert(file); }
|
||||
|
||||
FileReader::FileReader(FileReader&& other)
|
||||
: file_(std::move(other.file_)), position_(other.position_) {
|
||||
other.position_ = 0;
|
||||
}
|
||||
|
||||
FileReader& FileReader::operator=(FileReader&& other) {
|
||||
if (this != &other) {
|
||||
file_ = std::move(other.file_);
|
||||
position_ = other.position_;
|
||||
other.position_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Status FileReader::Read(std::size_t num_to_read, std::uint8_t* buffer,
|
||||
std::uint64_t* num_actually_read) {
|
||||
assert(num_to_read > 0);
|
||||
assert(buffer != nullptr);
|
||||
assert(num_actually_read != nullptr);
|
||||
|
||||
if (file_ == nullptr) {
|
||||
*num_actually_read = 0;
|
||||
return Status(Status::kEndOfFile);
|
||||
}
|
||||
|
||||
std::size_t actual =
|
||||
std::fread(static_cast<void*>(buffer), 1, num_to_read, file_.get());
|
||||
*num_actually_read = static_cast<std::uint64_t>(actual);
|
||||
position_ += *num_actually_read;
|
||||
|
||||
if (actual == 0) {
|
||||
return Status(Status::kEndOfFile);
|
||||
}
|
||||
|
||||
if (actual == num_to_read) {
|
||||
return Status(Status::kOkCompleted);
|
||||
} else {
|
||||
return Status(Status::kOkPartial);
|
||||
}
|
||||
}
|
||||
|
||||
Status FileReader::Skip(std::uint64_t num_to_skip,
|
||||
std::uint64_t* num_actually_skipped) {
|
||||
assert(num_to_skip > 0);
|
||||
assert(num_actually_skipped != nullptr);
|
||||
|
||||
*num_actually_skipped = 0;
|
||||
|
||||
if (file_ == nullptr) {
|
||||
return Status(Status::kEndOfFile);
|
||||
}
|
||||
|
||||
// Try seeking forward first.
|
||||
long seek_offset = std::numeric_limits<long>::max(); // NOLINT
|
||||
if (num_to_skip < static_cast<unsigned long>(seek_offset)) { // NOLINT
|
||||
seek_offset = static_cast<long>(num_to_skip); // NOLINT
|
||||
}
|
||||
// TODO(mjbshaw): Use fseeko64/_fseeki64 if available.
|
||||
if (!std::fseek(file_.get(), seek_offset, SEEK_CUR)) {
|
||||
*num_actually_skipped = static_cast<std::uint64_t>(seek_offset);
|
||||
position_ += static_cast<std::uint64_t>(seek_offset);
|
||||
if (static_cast<unsigned long>(seek_offset) == num_to_skip) { // NOLINT
|
||||
return Status(Status::kOkCompleted);
|
||||
} else {
|
||||
return Status(Status::kOkPartial);
|
||||
}
|
||||
}
|
||||
std::clearerr(file_.get());
|
||||
|
||||
// Seeking doesn't work on things like pipes, so if seeking failed then fall
|
||||
// back to reading the data into a junk buffer.
|
||||
std::size_t actual = 0;
|
||||
do {
|
||||
std::uint8_t junk[1024];
|
||||
std::size_t num_to_read = sizeof(junk);
|
||||
if (num_to_skip < num_to_read) {
|
||||
num_to_read = static_cast<std::size_t>(num_to_skip);
|
||||
}
|
||||
|
||||
std::size_t actual =
|
||||
std::fread(static_cast<void*>(junk), 1, num_to_read, file_.get());
|
||||
*num_actually_skipped += static_cast<std::uint64_t>(actual);
|
||||
position_ += static_cast<std::uint64_t>(actual);
|
||||
num_to_skip -= static_cast<std::uint64_t>(actual);
|
||||
} while (actual > 0 && num_to_skip > 0);
|
||||
|
||||
if (*num_actually_skipped == 0) {
|
||||
return Status(Status::kEndOfFile);
|
||||
}
|
||||
|
||||
if (num_to_skip == 0) {
|
||||
return Status(Status::kOkCompleted);
|
||||
} else {
|
||||
return Status(Status::kOkPartial);
|
||||
}
|
||||
}
|
||||
|
||||
std::uint64_t FileReader::Position() const { return position_; }
|
||||
|
||||
} // namespace webm
|
||||
77
webm_parser/src/float_parser.cc
Normal file
77
webm_parser/src/float_parser.cc
Normal file
@@ -0,0 +1,77 @@
|
||||
// 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 "src/float_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
|
||||
#include "src/parser_utils.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
FloatParser::FloatParser(double default_value)
|
||||
: default_value_(default_value) {}
|
||||
|
||||
Status FloatParser::Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
if (metadata.size == 0) {
|
||||
value_ = default_value_;
|
||||
} else if (metadata.size == 4 || metadata.size == 8) {
|
||||
uint64_value_ = 0;
|
||||
} else {
|
||||
return Status(Status::kInvalidElementSize);
|
||||
}
|
||||
|
||||
num_bytes_remaining_ = static_cast<int>(metadata.size);
|
||||
use_32_bits_ = metadata.size == 4;
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status FloatParser::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
if (num_bytes_remaining_ == 0) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
|
||||
&uint64_value_, num_bytes_read);
|
||||
num_bytes_remaining_ -= static_cast<int>(*num_bytes_read);
|
||||
|
||||
if (num_bytes_remaining_ == 0) {
|
||||
if (use_32_bits_) {
|
||||
static_assert(std::numeric_limits<float>::is_iec559,
|
||||
"Your compiler does not support 32-bit IEC 559/IEEE 754 "
|
||||
"floating point types");
|
||||
std::uint32_t uint32_value = static_cast<std::uint32_t>(uint64_value_);
|
||||
float float32_value;
|
||||
std::memcpy(&float32_value, &uint32_value, 4);
|
||||
value_ = float32_value;
|
||||
} else {
|
||||
static_assert(std::numeric_limits<double>::is_iec559,
|
||||
"Your compiler does not support 64-bit IEC 559/IEEE 754 "
|
||||
"floating point types");
|
||||
std::memcpy(&value_, &uint64_value_, 8);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
65
webm_parser/src/float_parser.h
Normal file
65
webm_parser/src/float_parser.h
Normal file
@@ -0,0 +1,65 @@
|
||||
// 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.
|
||||
#ifndef SRC_FLOAT_PARSER_H_
|
||||
#define SRC_FLOAT_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/element_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Parses an EBML float from a byte stream.
|
||||
class FloatParser : public ElementParser {
|
||||
public:
|
||||
// Constructs a new parser which will use the given default_value as the
|
||||
// value for the element if its size is zero. Defaults to the value zero (as
|
||||
// the EBML spec indicates).
|
||||
explicit FloatParser(double default_value = 0.0);
|
||||
|
||||
FloatParser(FloatParser&&) = default;
|
||||
FloatParser& operator=(FloatParser&&) = default;
|
||||
|
||||
FloatParser(const FloatParser&) = delete;
|
||||
FloatParser& operator=(const FloatParser&) = delete;
|
||||
|
||||
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
// Gets the parsed float. This must not be called until the parse had been
|
||||
// successfully completed.
|
||||
double value() const {
|
||||
assert(num_bytes_remaining_ == 0);
|
||||
return value_;
|
||||
}
|
||||
|
||||
// Gets the parsed float. This must not be called until the parse had been
|
||||
// successfully completed.
|
||||
double* mutable_value() {
|
||||
assert(num_bytes_remaining_ == 0);
|
||||
return &value_;
|
||||
}
|
||||
|
||||
private:
|
||||
double value_;
|
||||
double default_value_;
|
||||
std::uint64_t uint64_value_;
|
||||
int num_bytes_remaining_ = -1;
|
||||
bool use_32_bits_;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_FLOAT_PARSER_H_
|
||||
49
webm_parser/src/id_element_parser.cc
Normal file
49
webm_parser/src/id_element_parser.cc
Normal file
@@ -0,0 +1,49 @@
|
||||
// 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 "src/id_element_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/element_parser.h"
|
||||
#include "src/parser_utils.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
Status IdElementParser::Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
if (metadata.size == 0 || metadata.size > 4) {
|
||||
return Status(Status::kInvalidElementSize);
|
||||
}
|
||||
|
||||
num_bytes_remaining_ = static_cast<int>(metadata.size);
|
||||
value_ = static_cast<Id>(0);
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status IdElementParser::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
|
||||
&value_, num_bytes_read);
|
||||
num_bytes_remaining_ -= static_cast<int>(*num_bytes_read);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
56
webm_parser/src/id_element_parser.h
Normal file
56
webm_parser/src/id_element_parser.h
Normal file
@@ -0,0 +1,56 @@
|
||||
// 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.
|
||||
#ifndef SRC_ID_ELEMENT_PARSER_H_
|
||||
#define SRC_ID_ELEMENT_PARSER_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/element_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
class IdElementParser : public ElementParser {
|
||||
public:
|
||||
IdElementParser() = default;
|
||||
|
||||
IdElementParser(IdElementParser&&) = default;
|
||||
IdElementParser& operator=(IdElementParser&&) = default;
|
||||
|
||||
IdElementParser(const IdElementParser&) = delete;
|
||||
IdElementParser& operator=(const IdElementParser&) = delete;
|
||||
|
||||
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
// Gets the parsed Id. This must not be called until the parse had been
|
||||
// successfully completed.
|
||||
Id value() const {
|
||||
assert(num_bytes_remaining_ == 0);
|
||||
return value_;
|
||||
}
|
||||
|
||||
// Gets the parsed Id. This must not be called until the parse had been
|
||||
// successfully completed.
|
||||
Id* mutable_value() {
|
||||
assert(num_bytes_remaining_ == 0);
|
||||
return &value_;
|
||||
}
|
||||
|
||||
private:
|
||||
Id value_;
|
||||
int num_bytes_remaining_ = -1;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_ID_ELEMENT_PARSER_H_
|
||||
75
webm_parser/src/id_parser.cc
Normal file
75
webm_parser/src/id_parser.cc
Normal file
@@ -0,0 +1,75 @@
|
||||
// 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 "src/id_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/bit_utils.h"
|
||||
#include "src/parser_utils.h"
|
||||
#include "webm/id.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
Status IdParser::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
assert(num_bytes_remaining_ != 0);
|
||||
|
||||
*num_bytes_read = 0;
|
||||
|
||||
// Spec references:
|
||||
// http://matroska.org/technical/specs/index.html#EBML_ex
|
||||
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#variable-size-integer
|
||||
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#element-id
|
||||
|
||||
// IDs are encoded like so (big-endian):
|
||||
// 0b1xxx xxxx
|
||||
// 0b01xx xxxx xxxx xxxx
|
||||
// 0b001x xxxx xxxx xxxx xxxx xxxx
|
||||
// 0b0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx
|
||||
|
||||
if (num_bytes_remaining_ == -1) {
|
||||
std::uint8_t first_byte;
|
||||
const Status status = ReadByte(reader, &first_byte);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
++*num_bytes_read;
|
||||
|
||||
// The marker bit is the first 1-bit. It indicates the length of the ID.
|
||||
// If there is no marker bit in the first half-octet, this isn't a valid
|
||||
// ID, since IDs can't be more than 4 octets in MKV/WebM.
|
||||
if (!(first_byte & 0xf0)) {
|
||||
return Status(Status::kInvalidElementId);
|
||||
}
|
||||
|
||||
num_bytes_remaining_ = CountLeadingZeros(first_byte);
|
||||
|
||||
id_ = static_cast<Id>(first_byte);
|
||||
}
|
||||
|
||||
std::uint64_t local_num_bytes_read;
|
||||
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
|
||||
&id_, &local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
num_bytes_remaining_ -= static_cast<int>(local_num_bytes_read);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
Id IdParser::id() const {
|
||||
assert(num_bytes_remaining_ == 0);
|
||||
return id_;
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
45
webm_parser/src/id_parser.h
Normal file
45
webm_parser/src/id_parser.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// 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.
|
||||
#ifndef SRC_ID_PARSER_H_
|
||||
#define SRC_ID_PARSER_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/id.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Parses an EBML ID from a byte stream.
|
||||
class IdParser : public Parser {
|
||||
public:
|
||||
IdParser() = default;
|
||||
IdParser(IdParser&&) = default;
|
||||
IdParser& operator=(IdParser&&) = default;
|
||||
|
||||
IdParser(const IdParser&) = delete;
|
||||
IdParser& operator=(const IdParser&) = delete;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
// Gets the parsed ID. This must not be called until the parse had been
|
||||
// successfully completed.
|
||||
Id id() const;
|
||||
|
||||
private:
|
||||
int num_bytes_remaining_ = -1;
|
||||
Id id_;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_ID_PARSER_H_
|
||||
44
webm_parser/src/info_parser.h
Normal file
44
webm_parser/src/info_parser.h
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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.
|
||||
#ifndef SRC_INFO_PARSER_H_
|
||||
#define SRC_INFO_PARSER_H_
|
||||
|
||||
#include "src/byte_parser.h"
|
||||
#include "src/date_parser.h"
|
||||
#include "src/float_parser.h"
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Info
|
||||
// http://www.webmproject.org/docs/container/#Info
|
||||
class InfoParser : public MasterValueParser<Info> {
|
||||
public:
|
||||
InfoParser()
|
||||
: MasterValueParser<Info>(
|
||||
MakeChild<UnsignedIntParser>(Id::kTimecodeScale,
|
||||
&Info::timecode_scale),
|
||||
MakeChild<FloatParser>(Id::kDuration, &Info::duration),
|
||||
MakeChild<DateParser>(Id::kDateUtc, &Info::date_utc),
|
||||
MakeChild<StringParser>(Id::kTitle, &Info::title),
|
||||
MakeChild<StringParser>(Id::kMuxingApp, &Info::muxing_app),
|
||||
MakeChild<StringParser>(Id::kWritingApp, &Info::writing_app)) {}
|
||||
|
||||
protected:
|
||||
Status OnParseCompleted(Callback* callback) override {
|
||||
return callback->OnInfo(metadata(Id::kInfo), value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_INFO_PARSER_H_
|
||||
120
webm_parser/src/int_parser.h
Normal file
120
webm_parser/src/int_parser.h
Normal file
@@ -0,0 +1,120 @@
|
||||
// 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.
|
||||
#ifndef SRC_INT_PARSER_H_
|
||||
#define SRC_INT_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include "src/element_parser.h"
|
||||
#include "src/parser_utils.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Parses an EBML signed/unsigned int from a byte stream.
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#EBML_ex
|
||||
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#element-data-size
|
||||
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#ebml-element-types
|
||||
template <typename T> class IntParser : public ElementParser {
|
||||
public:
|
||||
static_assert(
|
||||
std::is_same<T, std::int64_t>::value ||
|
||||
std::is_same<T, std::uint64_t>::value ||
|
||||
(std::is_enum<T>::value && sizeof(T) == 8),
|
||||
"T must be either std::int64_t, std::uint64_t, or a 64-bit enum");
|
||||
|
||||
// Constructs a new parser which will use the given default_value as the
|
||||
// value for the element if its size is zero. Defaults to the value zero (as
|
||||
// the EBML spec indicates).
|
||||
explicit IntParser(T default_value = {}) : default_value_(default_value) {}
|
||||
|
||||
IntParser(IntParser&&) = default;
|
||||
IntParser& operator=(IntParser&&) = default;
|
||||
|
||||
IntParser(const IntParser&) = delete;
|
||||
IntParser& operator=(const IntParser&) = delete;
|
||||
|
||||
Status Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) override {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
// Matroska requires integers to be 0-8 bytes in size.
|
||||
if (metadata.size > 8) {
|
||||
return Status(Status::kInvalidElementSize);
|
||||
}
|
||||
|
||||
size_ = num_bytes_remaining_ = static_cast<int>(metadata.size);
|
||||
|
||||
if (metadata.size == 0) {
|
||||
value_ = default_value_;
|
||||
} else {
|
||||
value_ = {};
|
||||
}
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
|
||||
&value_, num_bytes_read);
|
||||
num_bytes_remaining_ -= static_cast<int>(*num_bytes_read);
|
||||
|
||||
// Sign extend the integer if it's a negative value. EBML allows for
|
||||
// negative integers to drop superfluous sign bytes (i.e. -1 can be encoded
|
||||
// as 0xFF instead of 0xFFFFFFFFFFFFFFFF).
|
||||
if (std::is_signed<T>::value && num_bytes_remaining_ == 0 && size_ > 0) {
|
||||
std::uint64_t sign_bits = std::numeric_limits<std::uint64_t>::max()
|
||||
<< (8 * size_ - 1);
|
||||
std::uint64_t unsigned_value = static_cast<std::uint64_t>(value_);
|
||||
if (unsigned_value & sign_bits) {
|
||||
value_ = static_cast<T>(unsigned_value | sign_bits);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Gets the parsed int. This must not be called until the parse had been
|
||||
// successfully completed.
|
||||
T value() const {
|
||||
assert(num_bytes_remaining_ == 0);
|
||||
return value_;
|
||||
}
|
||||
|
||||
// Gets the parsed int. This must not be called until the parse had been
|
||||
// successfully completed.
|
||||
T* mutable_value() {
|
||||
assert(num_bytes_remaining_ == 0);
|
||||
return &value_;
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
T default_value_;
|
||||
int num_bytes_remaining_ = -1;
|
||||
int size_;
|
||||
};
|
||||
|
||||
using SignedIntParser = IntParser<std::int64_t>;
|
||||
using UnsignedIntParser = IntParser<std::uint64_t>;
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_INT_PARSER_H_
|
||||
133
webm_parser/src/istream_reader.cc
Normal file
133
webm_parser/src/istream_reader.cc
Normal file
@@ -0,0 +1,133 @@
|
||||
// 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 "webm/istream_reader.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
IstreamReader::IstreamReader(IstreamReader&& other)
|
||||
: istream_(std::move(other.istream_)), position_(other.position_) {
|
||||
other.position_ = 0;
|
||||
}
|
||||
|
||||
IstreamReader& IstreamReader::operator=(IstreamReader&& other) {
|
||||
if (this != &other) {
|
||||
istream_ = std::move(other.istream_);
|
||||
position_ = other.position_;
|
||||
other.position_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Status IstreamReader::Read(std::size_t num_to_read, std::uint8_t* buffer,
|
||||
std::uint64_t* num_actually_read) {
|
||||
assert(num_to_read > 0);
|
||||
assert(buffer != nullptr);
|
||||
assert(num_actually_read != nullptr);
|
||||
|
||||
if (istream_ == nullptr) {
|
||||
*num_actually_read = 0;
|
||||
return Status(Status::kEndOfFile);
|
||||
}
|
||||
|
||||
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
|
||||
constexpr std::streamsize streamsize_max =
|
||||
std::numeric_limits<std::streamsize>::max();
|
||||
std::streamsize limited_num_to_read;
|
||||
if (num_to_read > static_cast<unsigned_streamsize>(streamsize_max)) {
|
||||
limited_num_to_read = streamsize_max;
|
||||
} else {
|
||||
limited_num_to_read = static_cast<std::streamsize>(num_to_read);
|
||||
}
|
||||
|
||||
istream_->read(reinterpret_cast<char*>(buffer), limited_num_to_read);
|
||||
std::streamsize actual = istream_->gcount();
|
||||
*num_actually_read = static_cast<std::uint64_t>(actual);
|
||||
position_ += *num_actually_read;
|
||||
|
||||
if (actual == 0) {
|
||||
return Status(Status::kEndOfFile);
|
||||
}
|
||||
|
||||
if (actual == num_to_read) {
|
||||
return Status(Status::kOkCompleted);
|
||||
} else {
|
||||
return Status(Status::kOkPartial);
|
||||
}
|
||||
}
|
||||
|
||||
Status IstreamReader::Skip(std::uint64_t num_to_skip,
|
||||
std::uint64_t* num_actually_skipped) {
|
||||
assert(num_to_skip > 0);
|
||||
assert(num_actually_skipped != nullptr);
|
||||
|
||||
*num_actually_skipped = 0;
|
||||
if (istream_ == nullptr || !istream_->good()) {
|
||||
return Status(Status::kEndOfFile);
|
||||
}
|
||||
|
||||
// Try seeking forward first.
|
||||
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
|
||||
constexpr std::streamsize streamsize_max =
|
||||
std::numeric_limits<std::streamsize>::max();
|
||||
std::streamsize seek_offset;
|
||||
if (num_to_skip > static_cast<unsigned_streamsize>(streamsize_max)) {
|
||||
seek_offset = streamsize_max;
|
||||
} else {
|
||||
seek_offset = static_cast<std::streamsize>(num_to_skip);
|
||||
}
|
||||
if (istream_->seekg(seek_offset, std::ios_base::cur)) {
|
||||
*num_actually_skipped = static_cast<std::uint64_t>(seek_offset);
|
||||
position_ += static_cast<std::uint64_t>(seek_offset);
|
||||
if (static_cast<std::uint64_t>(seek_offset) == num_to_skip) {
|
||||
return Status(Status::kOkCompleted);
|
||||
} else {
|
||||
return Status(Status::kOkPartial);
|
||||
}
|
||||
}
|
||||
istream_->clear();
|
||||
|
||||
// Seeking doesn't work on things like pipes, so if seeking failed then fall
|
||||
// back to reading the data into a junk buffer.
|
||||
std::size_t actual = 0;
|
||||
do {
|
||||
char junk[1024];
|
||||
std::streamsize num_to_read = static_cast<std::streamsize>(sizeof(junk));
|
||||
if (num_to_skip < static_cast<std::uint64_t>(num_to_read)) {
|
||||
num_to_read = static_cast<std::streamsize>(num_to_skip);
|
||||
}
|
||||
|
||||
istream_->read(junk, num_to_read);
|
||||
std::streamsize actual = istream_->gcount();
|
||||
*num_actually_skipped += static_cast<std::uint64_t>(actual);
|
||||
position_ += static_cast<std::uint64_t>(actual);
|
||||
num_to_skip -= static_cast<std::uint64_t>(actual);
|
||||
} while (actual > 0 && num_to_skip > 0);
|
||||
|
||||
if (*num_actually_skipped == 0) {
|
||||
return Status(Status::kEndOfFile);
|
||||
}
|
||||
|
||||
if (num_to_skip == 0) {
|
||||
return Status(Status::kOkCompleted);
|
||||
} else {
|
||||
return Status(Status::kOkPartial);
|
||||
}
|
||||
}
|
||||
|
||||
std::uint64_t IstreamReader::Position() const { return position_; }
|
||||
|
||||
} // namespace webm
|
||||
298
webm_parser/src/master_parser.cc
Normal file
298
webm_parser/src/master_parser.cc
Normal file
@@ -0,0 +1,298 @@
|
||||
// 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 "src/master_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#include "src/element_parser.h"
|
||||
#include "src/skip_callback.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/id.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#EBML_ex
|
||||
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown
|
||||
Status MasterParser::Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
InitSetup(metadata.header_size, metadata.size, metadata.position);
|
||||
|
||||
if (metadata.size != kUnknownElementSize) {
|
||||
max_size_ = metadata.size;
|
||||
} else {
|
||||
max_size_ = max_size;
|
||||
}
|
||||
|
||||
if (metadata.size == 0) {
|
||||
state_ = State::kEndReached;
|
||||
} else {
|
||||
state_ = State::kFirstReadOfChildId;
|
||||
}
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
void MasterParser::InitAfterSeek(const Ancestory& child_ancestory,
|
||||
const ElementMetadata& child_metadata) {
|
||||
InitSetup(kUnknownHeaderSize, kUnknownElementSize, kUnknownElementPosition);
|
||||
max_size_ = std::numeric_limits<std::uint64_t>::max();
|
||||
|
||||
if (child_ancestory.empty()) {
|
||||
child_metadata_ = child_metadata;
|
||||
auto iter = parsers_.find(child_metadata_.id);
|
||||
assert(iter != parsers_.end());
|
||||
child_parser_ = iter->second.get();
|
||||
state_ = State::kGettingAction;
|
||||
} else {
|
||||
child_metadata_.id = child_ancestory.id();
|
||||
child_metadata_.header_size = kUnknownHeaderSize;
|
||||
child_metadata_.size = kUnknownElementSize;
|
||||
child_metadata_.position = kUnknownElementPosition;
|
||||
|
||||
auto iter = parsers_.find(child_metadata_.id);
|
||||
assert(iter != parsers_.end());
|
||||
child_parser_ = iter->second.get();
|
||||
child_parser_->InitAfterSeek(child_ancestory.next(), child_metadata);
|
||||
state_ = State::kReadingChildBody;
|
||||
}
|
||||
}
|
||||
|
||||
Status MasterParser::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
*num_bytes_read = 0;
|
||||
|
||||
Callback* const original_callback = callback;
|
||||
|
||||
SkipCallback skip_callback;
|
||||
if (action_ == Action::kSkip) {
|
||||
callback = &skip_callback;
|
||||
}
|
||||
|
||||
Status status;
|
||||
std::uint64_t local_num_bytes_read;
|
||||
while (true) {
|
||||
switch (state_) {
|
||||
case State::kFirstReadOfChildId: {
|
||||
// This separate case for the first read of the child ID is needed to
|
||||
// avoid potential bugs where calling Feed() twice in a row on an
|
||||
// unsized element at the end of the stream would return
|
||||
// Status::kOkCompleted instead of Status::kEndOfFile (since we convert
|
||||
// Status::kEndOfFile to Status::kOkCompleted when EOF is hit for an
|
||||
// unsized element after its children have been fully parsed). Once
|
||||
// the ID parser consumes > 0 bytes, this state must be exited.
|
||||
assert(child_parser_ == nullptr);
|
||||
assert(my_size_ == kUnknownElementSize || total_bytes_read_ < my_size_);
|
||||
child_metadata_.position = reader->Position();
|
||||
child_metadata_.header_size = 0;
|
||||
status = id_parser_.Feed(callback, reader, &local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
total_bytes_read_ += local_num_bytes_read;
|
||||
child_metadata_.header_size +=
|
||||
static_cast<std::uint32_t>(local_num_bytes_read);
|
||||
if (status.code == Status::kEndOfFile &&
|
||||
my_size_ == kUnknownElementSize && local_num_bytes_read == 0) {
|
||||
state_ = State::kEndReached;
|
||||
} else if (!status.ok()) {
|
||||
if (local_num_bytes_read > 0) {
|
||||
state_ = State::kFinishingReadingChildId;
|
||||
}
|
||||
return status;
|
||||
} else if (status.completed_ok()) {
|
||||
state_ = State::kReadingChildSize;
|
||||
} else {
|
||||
state_ = State::kFinishingReadingChildId;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kFinishingReadingChildId: {
|
||||
assert(child_parser_ == nullptr);
|
||||
assert(my_size_ == kUnknownElementSize || total_bytes_read_ < my_size_);
|
||||
status = id_parser_.Feed(callback, reader, &local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
total_bytes_read_ += local_num_bytes_read;
|
||||
child_metadata_.header_size +=
|
||||
static_cast<std::uint32_t>(local_num_bytes_read);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
state_ = State::kReadingChildSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kReadingChildSize: {
|
||||
assert(child_parser_ == nullptr);
|
||||
assert(total_bytes_read_ > 0);
|
||||
status = size_parser_.Feed(callback, reader, &local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
total_bytes_read_ += local_num_bytes_read;
|
||||
child_metadata_.header_size +=
|
||||
static_cast<std::uint32_t>(local_num_bytes_read);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
child_metadata_.id = id_parser_.id();
|
||||
child_metadata_.size = size_parser_.size();
|
||||
state_ = State::kValidatingChildSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kValidatingChildSize: {
|
||||
assert(child_parser_ == nullptr);
|
||||
|
||||
std::uint64_t byte_count = total_bytes_read_;
|
||||
if (child_metadata_.size != kUnknownElementSize) {
|
||||
byte_count += child_metadata_.size;
|
||||
}
|
||||
|
||||
std::uint64_t byte_cap = max_size_;
|
||||
// my_size_ is <= max_size_ if it's known, so pick the smaller value.
|
||||
if (my_size_ != kUnknownElementSize) {
|
||||
byte_cap = my_size_;
|
||||
}
|
||||
|
||||
if (byte_count > byte_cap) {
|
||||
return Status(Status::kElementOverflow);
|
||||
}
|
||||
|
||||
auto iter = parsers_.find(child_metadata_.id);
|
||||
bool unknown_child = iter == parsers_.end();
|
||||
|
||||
if (my_size_ == kUnknownElementSize && unknown_child) {
|
||||
// The end of an unsized master element is considered to be the first
|
||||
// instance of an element that isn't a known/valid child element.
|
||||
has_cached_metadata_ = true;
|
||||
state_ = State::kEndReached;
|
||||
continue;
|
||||
} else if (unknown_child &&
|
||||
child_metadata_.size == kUnknownElementSize) {
|
||||
// We can't skip or otherwise handle unknown elements with an unknown
|
||||
// size.
|
||||
return Status(Status::kIndefiniteUnknownElement);
|
||||
}
|
||||
if (unknown_child) {
|
||||
child_parser_ = &unknown_parser_;
|
||||
} else {
|
||||
child_parser_ = iter->second.get();
|
||||
}
|
||||
state_ = State::kGettingAction;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kGettingAction: {
|
||||
assert(child_parser_ != nullptr);
|
||||
status = callback->OnElementBegin(child_metadata_, &action_);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (action_ == Action::kSkip) {
|
||||
callback = &skip_callback;
|
||||
if (child_metadata_.size != kUnknownElementSize) {
|
||||
child_parser_ = &skip_parser_;
|
||||
}
|
||||
}
|
||||
state_ = State::kInitializingChildParser;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kInitializingChildParser: {
|
||||
assert(child_parser_ != nullptr);
|
||||
status =
|
||||
child_parser_->Init(child_metadata_, max_size_ - total_bytes_read_);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
state_ = State::kReadingChildBody;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kReadingChildBody: {
|
||||
assert(child_parser_ != nullptr);
|
||||
status = child_parser_->Feed(callback, reader, &local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
total_bytes_read_ += local_num_bytes_read;
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
state_ = State::kChildFullyParsed;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kChildFullyParsed: {
|
||||
assert(child_parser_ != nullptr);
|
||||
std::uint64_t byte_cap = max_size_;
|
||||
// my_size_ is <= max_size_ if it's known, so pick the smaller value.
|
||||
if (my_size_ != kUnknownElementSize) {
|
||||
byte_cap = my_size_;
|
||||
}
|
||||
|
||||
if (total_bytes_read_ > byte_cap) {
|
||||
return Status(Status::kElementOverflow);
|
||||
} else if (total_bytes_read_ == byte_cap) {
|
||||
state_ = State::kEndReached;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (child_parser_->GetCachedMetadata(&child_metadata_)) {
|
||||
state_ = State::kValidatingChildSize;
|
||||
} else {
|
||||
state_ = State::kFirstReadOfChildId;
|
||||
}
|
||||
PrepareForNextChild();
|
||||
callback = original_callback;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kEndReached: {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MasterParser::GetCachedMetadata(ElementMetadata* metadata) {
|
||||
assert(metadata != nullptr);
|
||||
|
||||
if (has_cached_metadata_) {
|
||||
*metadata = child_metadata_;
|
||||
}
|
||||
return has_cached_metadata_;
|
||||
}
|
||||
|
||||
void MasterParser::InitSetup(std::uint32_t header_size,
|
||||
std::uint64_t size_in_bytes,
|
||||
std::uint64_t position) {
|
||||
PrepareForNextChild();
|
||||
header_size_ = header_size;
|
||||
my_size_ = size_in_bytes;
|
||||
my_position_ = position;
|
||||
total_bytes_read_ = 0;
|
||||
has_cached_metadata_ = false;
|
||||
}
|
||||
|
||||
void MasterParser::PrepareForNextChild() {
|
||||
// Do not reset child_metadata_ here.
|
||||
id_parser_ = {};
|
||||
size_parser_ = {};
|
||||
child_parser_ = nullptr;
|
||||
action_ = Action::kRead;
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
223
webm_parser/src/master_parser.h
Normal file
223
webm_parser/src/master_parser.h
Normal file
@@ -0,0 +1,223 @@
|
||||
// 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.
|
||||
#ifndef SRC_MASTER_PARSER_H_
|
||||
#define SRC_MASTER_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "src/element_parser.h"
|
||||
#include "src/id_parser.h"
|
||||
#include "src/size_parser.h"
|
||||
#include "src/skip_parser.h"
|
||||
#include "src/unknown_parser.h"
|
||||
#include "src/void_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/id.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// A general purpose parser for EBML master elements.
|
||||
//
|
||||
// For example, if a document specification defines a Foo master element that
|
||||
// has two boolean children (Bar and Baz), then a FooParser capable of parsing
|
||||
// the Foo master element could be defined as follows:
|
||||
//
|
||||
// struct FooParser : public MasterParser {
|
||||
// FooParser()
|
||||
// : MasterParser(MakeChild<BoolParser>(Id::kBar),
|
||||
// MakeChild<BoolParser>(Id::kBaz)) {}
|
||||
// };
|
||||
//
|
||||
// See the MasterValueParser for an alternative class for parsing master
|
||||
// elements into a data structure.
|
||||
class MasterParser : public ElementParser {
|
||||
public:
|
||||
// Constructs a new MasterParser that uses the given
|
||||
// {Id, std::unique_ptr<ElementParser>} pairs to map child IDs to the
|
||||
// appropriate parser/handler. Each argument must be of type
|
||||
// std::pair<Id, std::unique_ptr<ElementParser>>. If a parser is not
|
||||
// explicitly provided for Id::kVoid, a VoidParser will automatically be used
|
||||
// for it.
|
||||
//
|
||||
// Initializer lists don't support move-only types (i.e. std::unique_ptr), so
|
||||
// instead a variadic template is used.
|
||||
template <typename... T> explicit MasterParser(T&&... parser_pairs) {
|
||||
// Prefer an odd reserve size. This makes libc++ use a prime number for the
|
||||
// bucket count. Otherwise, if it happens to be a power of 2, then libc++
|
||||
// will use a power-of-2 bucket count (and since Matroska EBML IDs have low
|
||||
// entropy in the low bits, there will be a lot of collisions). libstdc++
|
||||
// always prefers a prime bucket count. I'm not sure how MSVC or others are
|
||||
// implemented, but this shouldn't adversely affect them even if they are
|
||||
// implemented differently. Add one to the count because we'll likely need
|
||||
// to insert a parser for Id::kVoid.
|
||||
parsers_.reserve((sizeof...(T) + 1) | 1);
|
||||
|
||||
// This dummy initializer list is just used to force the parameter pack to
|
||||
// be expanded, which turns the expression into a for-each "loop" that
|
||||
// inserts each argument into the map.
|
||||
auto dummy = {0, (InsertParser(std::forward<T>(parser_pairs)), 0)...};
|
||||
(void)dummy; // Silence unused variable warning.
|
||||
|
||||
if (parsers_.find(Id::kVoid) == parsers_.end()) {
|
||||
InsertParser(MakeChild<VoidParser>(Id::kVoid));
|
||||
}
|
||||
}
|
||||
|
||||
MasterParser(const MasterParser&) = delete;
|
||||
MasterParser& operator=(const MasterParser&) = delete;
|
||||
|
||||
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
|
||||
|
||||
void InitAfterSeek(const Ancestory& child_ancestory,
|
||||
const ElementMetadata& child_metadata) override;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
bool GetCachedMetadata(ElementMetadata* metadata) override;
|
||||
|
||||
std::uint32_t header_size() const { return header_size_; }
|
||||
|
||||
// Gets the size of this element. May be called before the parse is fully
|
||||
// complete (but only after Init() has already been called and successfully
|
||||
// returned).
|
||||
std::uint64_t size() const { return my_size_; }
|
||||
|
||||
// Gets absolute byte position of the start of the element in the byte stream.
|
||||
// May be called before the parse is fully complete (but only after Init() has
|
||||
// already been called and successfully returned).
|
||||
std::uint64_t position() const { return my_position_; }
|
||||
|
||||
// Gets the metadata for the child that is currently being parsed. This may
|
||||
// only be called while the child's body (not its header information like ID
|
||||
// and size) is being parsed.
|
||||
const ElementMetadata& child_metadata() const {
|
||||
assert(state_ == State::kValidatingChildSize ||
|
||||
state_ == State::kGettingAction ||
|
||||
state_ == State::kInitializingChildParser ||
|
||||
state_ == State::kReadingChildBody);
|
||||
return child_metadata_;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Allocates a new parser of type T, forwarding args to the constructor, and
|
||||
// creates a std::pair<Id, std::unique_ptr<ElementParser>> using the given id
|
||||
// and the allocated parser.
|
||||
template <typename T, typename... Args>
|
||||
static std::pair<Id, std::unique_ptr<ElementParser>> MakeChild(
|
||||
Id id, Args&&... args) {
|
||||
std::unique_ptr<ElementParser> ptr(new T(std::forward<Args>(args)...));
|
||||
return std::pair<Id, std::unique_ptr<ElementParser>>(id, std::move(ptr));
|
||||
}
|
||||
|
||||
private:
|
||||
// Parsing states for the finite-state machine.
|
||||
enum class State {
|
||||
// State Transitions to state When
|
||||
kFirstReadOfChildId, // kFinishingReadingChildId size(id) > 1
|
||||
// kReadingChildSize size(id) == 1
|
||||
// kEndReached EOF
|
||||
kFinishingReadingChildId, // kReadingChildSize done
|
||||
kReadingChildSize, // kValidatingChildSize done
|
||||
kValidatingChildSize, // kGettingAction done
|
||||
// kEndReached unknown id & unsized
|
||||
kGettingAction, // kInitializingChildParser done
|
||||
kInitializingChildParser, // kReadingChildBody done
|
||||
kReadingChildBody, // kChildFullyParsed child parse done
|
||||
kChildFullyParsed, // kValidatingChildSize cached metadata
|
||||
// kFirstReadOfChildId read < my_size_
|
||||
// kEndReached read == my_size_
|
||||
kEndReached, // No transitions from here (must call Init)
|
||||
};
|
||||
|
||||
using StdHashId = std::hash<std::underlying_type<Id>::type>;
|
||||
|
||||
// Hash functor for hashing Id enums for storage in std::unordered_map.
|
||||
struct IdHash : StdHashId {
|
||||
// Type aliases for conforming to the std::hash interface.
|
||||
using argument_type = Id;
|
||||
using result_type = StdHashId::result_type;
|
||||
|
||||
// Returns the hash of the given id.
|
||||
result_type operator()(argument_type id) const {
|
||||
return StdHashId::operator()(static_cast<StdHashId::argument_type>(id));
|
||||
}
|
||||
};
|
||||
|
||||
// The parser for parsing element Ids.
|
||||
IdParser id_parser_;
|
||||
|
||||
// The parser for parsing element sizes.
|
||||
SizeParser size_parser_;
|
||||
|
||||
// Metadata for the child element that is currently being parsed.
|
||||
ElementMetadata child_metadata_;
|
||||
|
||||
// Maps child IDs to the appropriate parser that can handle that child.
|
||||
std::unordered_map<Id, std::unique_ptr<ElementParser>, IdHash> parsers_;
|
||||
|
||||
// The parser that is used to parse unknown children.
|
||||
UnknownParser unknown_parser_;
|
||||
|
||||
// The parser that is used to skip over children.
|
||||
SkipParser skip_parser_;
|
||||
|
||||
// The parser that is being used to parse the current child. This must be null
|
||||
// or a pointer in parsers_.
|
||||
ElementParser* child_parser_;
|
||||
|
||||
// The current parsing action for the child that is currently being parsed.
|
||||
Action action_;
|
||||
|
||||
// The current state of the parser.
|
||||
State state_;
|
||||
|
||||
std::uint32_t header_size_;
|
||||
|
||||
// The size of this element.
|
||||
std::uint64_t my_size_;
|
||||
|
||||
std::uint64_t my_position_;
|
||||
|
||||
std::uint64_t max_size_;
|
||||
|
||||
// The total number of bytes read by this parser.
|
||||
std::uint64_t total_bytes_read_;
|
||||
|
||||
// Set to true if parsing has completed and this parser consumed an extra
|
||||
// element header (ID and size) that wasn't from a child.
|
||||
bool has_cached_metadata_ = false;
|
||||
|
||||
// Inserts the parser into the parsers_ map and asserts it is the only parser
|
||||
// registers to parse the corresponding Id.
|
||||
template <typename T> void InsertParser(T&& parser) {
|
||||
bool inserted = parsers_.insert(std::forward<T>(parser)).second;
|
||||
(void)inserted; // Silence unused variable warning.
|
||||
assert(inserted); // Make sure there aren't duplicates.
|
||||
}
|
||||
|
||||
// Common initialization logic for Init/InitAfterseek.
|
||||
void InitSetup(std::uint32_t header_size, std::uint64_t size_in_bytes,
|
||||
std::uint64_t position);
|
||||
|
||||
// Resets the internal parsers in preparation for parsing the next child.
|
||||
void PrepareForNextChild();
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_MASTER_PARSER_H_
|
||||
465
webm_parser/src/master_value_parser.h
Normal file
465
webm_parser/src/master_value_parser.h
Normal file
@@ -0,0 +1,465 @@
|
||||
// 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.
|
||||
#ifndef SRC_MASTER_VALUE_PARSER_H_
|
||||
#define SRC_MASTER_VALUE_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "src/master_parser.h"
|
||||
#include "src/skip_callback.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/id.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Parses Master elements from an EBML stream, storing child values in a
|
||||
// structure of type T. This class differs from MasterParser in that
|
||||
// MasterParser does not collect the parsed data into an object that can then be
|
||||
// retrieved.
|
||||
//
|
||||
// For example, consider the following Foo object, which represents a master
|
||||
// element that contains two booleans:
|
||||
//
|
||||
// struct Foo {
|
||||
// Element<bool> bar;
|
||||
// Element<bool> baz;
|
||||
// };
|
||||
//
|
||||
// A FooParser implemented via MasterParser, like below, could be used to parse
|
||||
// the master element and the boolean children, but the boolean values could not
|
||||
// be retrieved from the parser.
|
||||
//
|
||||
// struct FooParser : public MasterParser {
|
||||
// FooParser()
|
||||
// : MasterParser({Id::kBar, new BoolParser}, // std::pair<*> types
|
||||
// {Id::kBaz, new BoolParser}) {} // omitted for brevity.
|
||||
// };
|
||||
//
|
||||
// However, if FooParser is implemented via MasterValueParser<Foo>, then the
|
||||
// boolean values will be parsed into a Foo object that can be retrieved from
|
||||
// FooParser via its value() and mutable_value() methods.
|
||||
//
|
||||
// struct FooParser : public MasterValueParser<Foo> {
|
||||
// FooParser()
|
||||
// : MasterValueParser(MakeChild<BoolParser>(Id::kBar, &Foo::bar),
|
||||
// MakeChild<BoolParser>(Id::kBaz, &Foo::baz)) {}
|
||||
// };
|
||||
template <typename T> class MasterValueParser : public ElementParser {
|
||||
public:
|
||||
Status Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) override {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
PreInit();
|
||||
|
||||
const Status status = master_parser_.Init(metadata, max_size);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void InitAfterSeek(const Ancestory& child_ancestory,
|
||||
const ElementMetadata& child_metadata) override {
|
||||
PreInit();
|
||||
started_done_ = true;
|
||||
master_parser_.InitAfterSeek(child_ancestory, child_metadata);
|
||||
}
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
*num_bytes_read = 0;
|
||||
|
||||
if (!parse_complete_) {
|
||||
// TODO(mjbshaw): just call Reader::Skip if element's size is known and
|
||||
// action is skip.
|
||||
SkipCallback skip_callback;
|
||||
if (action_ == Action::kSkip) {
|
||||
callback = &skip_callback;
|
||||
}
|
||||
|
||||
Status status = master_parser_.Feed(callback, reader, num_bytes_read);
|
||||
// Check if we've artificially injected an error code, and if so, switch
|
||||
// into skipping mode.
|
||||
if (status.code == Status::kSwitchToSkip) {
|
||||
assert(started_done_);
|
||||
assert(action_ == Action::kSkip);
|
||||
callback = &skip_callback;
|
||||
std::uint64_t local_num_bytes_read;
|
||||
status = master_parser_.Feed(callback, reader, &local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
}
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
parse_complete_ = true;
|
||||
}
|
||||
|
||||
if (!started_done_) {
|
||||
Status status = OnParseStarted(callback, &action_);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
started_done_ = true;
|
||||
}
|
||||
|
||||
if (action_ != Action::kSkip) {
|
||||
return OnParseCompleted(callback);
|
||||
}
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
bool GetCachedMetadata(ElementMetadata* metadata) override {
|
||||
return master_parser_.GetCachedMetadata(metadata);
|
||||
}
|
||||
|
||||
bool WasSkipped() const override { return action_ == Action::kSkip; }
|
||||
|
||||
const T& value() const { return value_; }
|
||||
|
||||
T* mutable_value() { return &value_; }
|
||||
|
||||
protected:
|
||||
// Users and subclasses are not meant to use the Tag* classes; they're an
|
||||
// internal implementation detail.
|
||||
// A tag that will cause the internal ChildParser to use the parsed child as a
|
||||
// start event.
|
||||
struct TagUseAsStart {};
|
||||
// A tag that will cause the internal ChildParser to call OnChildParsed once
|
||||
// it has been fully parsed.
|
||||
struct TagNotifyOnParseComplete {};
|
||||
|
||||
// A factory that will create a std::pair<Id, std::unique_ptr<ElementParser>>.
|
||||
// Users and subclasses are not meant to use this class directly, as it is an
|
||||
// internal implementation detail of this class. Subclasses should use
|
||||
// MakeChild instead of using this class directly.
|
||||
template <typename Parser, typename Value, typename... Tags>
|
||||
class SingleChildFactory {
|
||||
public:
|
||||
constexpr SingleChildFactory(Id id, Element<Value> T::*member)
|
||||
: id_(id), member_(member) {}
|
||||
|
||||
// Builds a std::pair<Id, std::unique_ptr<ElementParser>>. The parent
|
||||
// pointer must be a pointer to the MasterValueParser that is being
|
||||
// constructed. The given value pointer must be the pointer to the fully
|
||||
// constructed MasterValueParser::value_ object.
|
||||
std::pair<Id, std::unique_ptr<ElementParser>> BuildParser(
|
||||
MasterValueParser* parent, T* value) {
|
||||
assert(parent != nullptr);
|
||||
assert(value != nullptr);
|
||||
|
||||
Element<Value>* child_member = &(value->*member_);
|
||||
auto lambda = [child_member](Parser* parser) {
|
||||
child_member->Set(std::move(*parser->mutable_value()), true);
|
||||
};
|
||||
return {id_, MakeChildParser<Parser, Value, Tags...>(
|
||||
parent, std::move(lambda), child_member)};
|
||||
}
|
||||
|
||||
// If called, OnParseStarted will be called on the parent element when this
|
||||
// particular element is encountered.
|
||||
constexpr SingleChildFactory<Parser, Value, TagUseAsStart, Tags...>
|
||||
UseAsStartEvent() const {
|
||||
return {id_, member_};
|
||||
}
|
||||
|
||||
// If called, OnChildParsed will be called on the parent element when this
|
||||
// particular element is fully parsed.
|
||||
constexpr SingleChildFactory<Parser, Value, TagNotifyOnParseComplete,
|
||||
Tags...>
|
||||
NotifyOnParseComplete() const {
|
||||
return {id_, member_};
|
||||
}
|
||||
|
||||
private:
|
||||
Id id_;
|
||||
Element<Value> T::*member_;
|
||||
};
|
||||
|
||||
template <typename Parser, typename Value, typename... Tags>
|
||||
class RepeatedChildFactory {
|
||||
public:
|
||||
constexpr RepeatedChildFactory(Id id,
|
||||
std::vector<Element<Value>> T::*member)
|
||||
: id_(id), member_(member) {}
|
||||
|
||||
// Builds a std::pair<Id, std::unique_ptr<ElementParser>>. The parent
|
||||
// pointer must be a pointer to the MasterValueParser that is being
|
||||
// constructed. The given value pointer must be the pointer to the fully
|
||||
// constructed MasterValueParser::value_ object.
|
||||
std::pair<Id, std::unique_ptr<ElementParser>> BuildParser(
|
||||
MasterValueParser* parent, T* value) {
|
||||
assert(parent != nullptr);
|
||||
assert(value != nullptr);
|
||||
|
||||
std::vector<Element<Value>>* child_member = &(value->*member_);
|
||||
auto lambda = [child_member](Parser* parser) {
|
||||
if (child_member->size() == 1 && !child_member->front().is_present()) {
|
||||
child_member->clear();
|
||||
}
|
||||
child_member->emplace_back(std::move(*parser->mutable_value()), true);
|
||||
};
|
||||
return {id_, MakeChildParser<Parser, Value, Tags...>(
|
||||
parent, std::move(lambda), child_member)};
|
||||
}
|
||||
|
||||
// If called, OnParseStarted will be called on the parent element when this
|
||||
// particular element is encountered.
|
||||
constexpr RepeatedChildFactory<Parser, Value, TagUseAsStart, Tags...>
|
||||
UseAsStartEvent() const {
|
||||
return {id_, member_};
|
||||
}
|
||||
|
||||
// If called, OnChildParsed will be called on the parent element when this
|
||||
// particular element is fully parsed.
|
||||
constexpr RepeatedChildFactory<Parser, Value, TagNotifyOnParseComplete,
|
||||
Tags...>
|
||||
NotifyOnParseComplete() const {
|
||||
return {id_, member_};
|
||||
}
|
||||
|
||||
private:
|
||||
Id id_;
|
||||
std::vector<Element<Value>> T::*member_;
|
||||
};
|
||||
|
||||
// Constructs a new parser. Each argument must be a *ChildFactory, constructed
|
||||
// from the MakeChild method.
|
||||
template <typename... Args>
|
||||
explicit MasterValueParser(Args&&... args)
|
||||
: master_parser_(args.BuildParser(this, &value_)...) {}
|
||||
|
||||
// Returns a factory that will produce a
|
||||
// std::pair<Id, std::unique_ptr<ElementParser>>. When a child element of the
|
||||
// given ID is encountered, a parser of type Parser will be used to parse it,
|
||||
// and store its value in the member pointer when the parse is complete. The
|
||||
// given default value will be used in the event that the child element has a
|
||||
// zero size. This method is only meant to be used by subclasses to provide
|
||||
// the necessary factories to the constructor.
|
||||
template <typename Parser, typename Value>
|
||||
static SingleChildFactory<Parser, Value> MakeChild(
|
||||
Id id, Element<Value> T::*member) {
|
||||
static_assert(std::is_base_of<ElementParser, Parser>::value,
|
||||
"Parser must derive from ElementParser");
|
||||
return SingleChildFactory<Parser, Value>(id, member);
|
||||
}
|
||||
|
||||
template <typename Parser, typename Value>
|
||||
static RepeatedChildFactory<Parser, Value> MakeChild(
|
||||
Id id, std::vector<Element<Value>> T::*member) {
|
||||
static_assert(std::is_base_of<ElementParser, Parser>::value,
|
||||
"Parser must derive from ElementParser");
|
||||
return RepeatedChildFactory<Parser, Value>(id, member);
|
||||
}
|
||||
|
||||
// Gets the metadata for this element, setting the EBML element ID to id. Only
|
||||
// call after Init() has been called.
|
||||
ElementMetadata metadata(Id id) const {
|
||||
return {id, master_parser_.header_size(), master_parser_.size(),
|
||||
master_parser_.position()};
|
||||
}
|
||||
|
||||
// This method will be called once the element has been fully parsed, or a
|
||||
// particular child element of interest (see UseAsStartEvent()) is
|
||||
// encountered. By default it just sets *action to Action::kRead and returns
|
||||
// Status::kOkCompleted. May be overridden (i.e. in order to call a Callback
|
||||
// method). Returning anything other than Status::kOkCompleted will stop
|
||||
// parsing and the status to be returned by Init or Feed (whichever originated
|
||||
// the call to this method). In this case, resuming parsing will result in
|
||||
// this method being called again.
|
||||
virtual Status OnParseStarted(Callback* callback, Action* action) {
|
||||
assert(callback != nullptr);
|
||||
assert(action != nullptr);
|
||||
*action = Action::kRead;
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
// This method is the companion to OnParseStarted, and will only be called
|
||||
// after OnParseStarted has already been called and parsing has completed.
|
||||
// This will not be called if OnParseStarted set the action to Action::kSkip.
|
||||
// By default it just returns Status::kOkCompleted. Returning anything other
|
||||
// than Status::kOkCompleted will stop parsing and the status to be returned
|
||||
// by Init or Feed (whichever originated the call to this method). In this
|
||||
// case, resuming parsing will result in this method being called again.
|
||||
virtual Status OnParseCompleted(Callback* callback) {
|
||||
assert(callback != nullptr);
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
// Returns true if the OnParseStarted method has already been called and has
|
||||
// completed.
|
||||
bool parse_started_event_completed() const { return started_done_; }
|
||||
|
||||
// Derived classes may manually call OnParseStarted before calling Feed, in
|
||||
// which case this method should be called to inform this class that
|
||||
// OnParseStarted has already been called and it should not be called again.
|
||||
void set_parse_started_event_completed_with_action(Action action) {
|
||||
assert(!started_done_);
|
||||
|
||||
action_ = action;
|
||||
started_done_ = true;
|
||||
}
|
||||
|
||||
// This method will be called for each child element that has been fully
|
||||
// parsed for which NotifyOnParseComplete() was requested. The provided
|
||||
// metadata is for the child element that has just completed parsing. By
|
||||
// default this method does nothing.
|
||||
virtual void OnChildParsed(const ElementMetadata& metadata) {}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
Action action_;
|
||||
bool parse_complete_;
|
||||
bool started_done_;
|
||||
// master_parser_ must be after value_ to ensure correct initialization order.
|
||||
MasterParser master_parser_;
|
||||
|
||||
const ElementMetadata& child_metadata() const {
|
||||
return master_parser_.child_metadata();
|
||||
}
|
||||
|
||||
// Helper struct that will be std::true_type if Tag is in Tags, or
|
||||
// std::false_type otherwise.
|
||||
template <typename Tag, typename... Tags> struct HasTag;
|
||||
|
||||
// Base condition: Tags is empty, so it trivially does not contain Tag.
|
||||
template <typename Tag> struct HasTag<Tag> : std::false_type {};
|
||||
|
||||
// If the head of the Tags list is a different tag, skip it and check the
|
||||
// remaining tags.
|
||||
template <typename Tag, typename DifferentTag, typename... Tags>
|
||||
struct HasTag<Tag, DifferentTag, Tags...> : HasTag<Tag, Tags...> {};
|
||||
|
||||
// If the head of the Tags list is the same as Tag, then we're done.
|
||||
template <typename Tag, typename... Tags>
|
||||
struct HasTag<Tag, Tag, Tags...> : std::true_type {};
|
||||
|
||||
template <typename Base, typename F, typename... Tags>
|
||||
class ChildParser : public Base {
|
||||
public:
|
||||
using Base::WasSkipped;
|
||||
|
||||
template <typename... Args>
|
||||
explicit ChildParser(MasterValueParser* parent, F consume_element_value,
|
||||
Args&&... base_args)
|
||||
: Base(std::forward<Args>(base_args)...),
|
||||
parent_(parent),
|
||||
consume_element_value_(std::move(consume_element_value)) {}
|
||||
|
||||
ChildParser() = delete;
|
||||
ChildParser(const ChildParser&) = delete;
|
||||
ChildParser& operator=(const ChildParser&) = delete;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override {
|
||||
*num_bytes_read = 0;
|
||||
|
||||
Status status = Prepare(callback);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = Base::Feed(callback, reader, num_bytes_read);
|
||||
if (status.completed_ok() && parent_->action_ != Action::kSkip &&
|
||||
!WasSkipped()) {
|
||||
consume_element_value_(this);
|
||||
if (has_tag<TagNotifyOnParseComplete>()) {
|
||||
parent_->OnChildParsed(parent_->child_metadata());
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
private:
|
||||
MasterValueParser* parent_;
|
||||
F consume_element_value_;
|
||||
|
||||
Status Prepare(Callback* callback) {
|
||||
if (has_tag<TagUseAsStart>() && !parent_->started_done_) {
|
||||
const Status status =
|
||||
parent_->OnParseStarted(callback, &parent_->action_);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
parent_->started_done_ = true;
|
||||
if (parent_->action_ == Action::kSkip) {
|
||||
return Status(Status::kSwitchToSkip);
|
||||
}
|
||||
}
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
template <typename Tag> constexpr static bool has_tag() {
|
||||
return HasTag<Tag, Tags...>::value;
|
||||
}
|
||||
};
|
||||
|
||||
// Returns a std::unique_ptr<ElementParser> that points to a ChildParser
|
||||
// when the Parser's constructor does not take a Value parameter.
|
||||
template <typename Parser, typename Value, typename... Tags, typename F>
|
||||
static typename std::enable_if<!std::is_constructible<Parser, Value>::value,
|
||||
std::unique_ptr<ElementParser>>::type
|
||||
MakeChildParser(MasterValueParser* parent, F consume_element_value, ...) {
|
||||
return std::unique_ptr<ElementParser>(new ChildParser<Parser, F, Tags...>(
|
||||
parent, std::move(consume_element_value)));
|
||||
}
|
||||
|
||||
// Returns a std::unique_ptr<ElementParser> that points to a ChildParser
|
||||
// when the Parser's constructor does take a Value parameter.
|
||||
template <typename Parser, typename Value, typename... Tags, typename F>
|
||||
static typename std::enable_if<std::is_constructible<Parser, Value>::value,
|
||||
std::unique_ptr<ElementParser>>::type
|
||||
MakeChildParser(MasterValueParser* parent, F consume_element_value,
|
||||
const Element<Value>* default_value) {
|
||||
return std::unique_ptr<ElementParser>(new ChildParser<Parser, F, Tags...>(
|
||||
parent, std::move(consume_element_value), default_value->value()));
|
||||
}
|
||||
|
||||
// Returns a std::unique_ptr<ElementParser> that points to a ChildParser
|
||||
// when the Parser's constructor does take a Value parameter.
|
||||
template <typename Parser, typename Value, typename... Tags, typename F>
|
||||
static typename std::enable_if<std::is_constructible<Parser, Value>::value,
|
||||
std::unique_ptr<ElementParser>>::type
|
||||
MakeChildParser(MasterValueParser* parent, F consume_element_value,
|
||||
const std::vector<Element<Value>>* member) {
|
||||
Value default_value{};
|
||||
if (!member->empty()) {
|
||||
default_value = member->front().value();
|
||||
}
|
||||
return std::unique_ptr<ElementParser>(new ChildParser<Parser, F, Tags...>(
|
||||
parent, std::move(consume_element_value), std::move(default_value)));
|
||||
}
|
||||
|
||||
// Initializes object state. Call immediately before initializing
|
||||
// master_parser_.
|
||||
void PreInit() {
|
||||
value_ = {};
|
||||
action_ = Action::kRead;
|
||||
parse_complete_ = false;
|
||||
started_done_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_MASTER_VALUE_PARSER_H_
|
||||
57
webm_parser/src/mastering_metadata_parser.h
Normal file
57
webm_parser/src/mastering_metadata_parser.h
Normal file
@@ -0,0 +1,57 @@
|
||||
// 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.
|
||||
#ifndef SRC_MASTERING_METADATA_PARSER_H_
|
||||
#define SRC_MASTERING_METADATA_PARSER_H_
|
||||
|
||||
#include "src/float_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#MasteringMetadata
|
||||
// http://www.webmproject.org/docs/container/#MasteringMetadata
|
||||
class MasteringMetadataParser : public MasterValueParser<MasteringMetadata> {
|
||||
public:
|
||||
MasteringMetadataParser()
|
||||
: MasterValueParser<MasteringMetadata>(
|
||||
MakeChild<FloatParser>(
|
||||
Id::kPrimaryRChromaticityX,
|
||||
&MasteringMetadata::primary_r_chromaticity_x),
|
||||
MakeChild<FloatParser>(
|
||||
Id::kPrimaryRChromaticityY,
|
||||
&MasteringMetadata::primary_r_chromaticity_y),
|
||||
MakeChild<FloatParser>(
|
||||
Id::kPrimaryGChromaticityX,
|
||||
&MasteringMetadata::primary_g_chromaticity_x),
|
||||
MakeChild<FloatParser>(
|
||||
Id::kPrimaryGChromaticityY,
|
||||
&MasteringMetadata::primary_g_chromaticity_y),
|
||||
MakeChild<FloatParser>(
|
||||
Id::kPrimaryBChromaticityX,
|
||||
&MasteringMetadata::primary_b_chromaticity_x),
|
||||
MakeChild<FloatParser>(
|
||||
Id::kPrimaryBChromaticityY,
|
||||
&MasteringMetadata::primary_b_chromaticity_y),
|
||||
MakeChild<FloatParser>(
|
||||
Id::kWhitePointChromaticityX,
|
||||
&MasteringMetadata::white_point_chromaticity_x),
|
||||
MakeChild<FloatParser>(
|
||||
Id::kWhitePointChromaticityY,
|
||||
&MasteringMetadata::white_point_chromaticity_y),
|
||||
MakeChild<FloatParser>(Id::kLuminanceMax,
|
||||
&MasteringMetadata::luminance_max),
|
||||
MakeChild<FloatParser>(Id::kLuminanceMin,
|
||||
&MasteringMetadata::luminance_min)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_MASTERING_METADATA_PARSER_H_
|
||||
34
webm_parser/src/parser.h
Normal file
34
webm_parser/src/parser.h
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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.
|
||||
#ifndef SRC_PARSER_H_
|
||||
#define SRC_PARSER_H_
|
||||
|
||||
#include "webm/callback.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
class Parser {
|
||||
public:
|
||||
virtual ~Parser() = default;
|
||||
|
||||
// Feeds data into the parser, with the number of bytes read from the reader
|
||||
// returned in num_bytes_read. Returns Status::kOkCompleted when parsing is
|
||||
// complete, or an appropriate error code if the data is malformed and cannot
|
||||
// be parsed. Otherwise, the status of Reader::Read is returned if only a
|
||||
// partial parse could be done because the reader couldn't immediately provide
|
||||
// all the needed data. reader and num_bytes_read must not be null. Do not
|
||||
// call again once the parse is complete.
|
||||
virtual Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) = 0;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_PARSER_H_
|
||||
34
webm_parser/src/parser_utils.cc
Normal file
34
webm_parser/src/parser_utils.cc
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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 "src/parser_utils.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
Status ReadByte(Reader* reader, std::uint8_t* byte) {
|
||||
assert(reader != nullptr);
|
||||
assert(byte != nullptr);
|
||||
|
||||
std::uint64_t num_bytes_read;
|
||||
const Status status = reader->Read(1, byte, &num_bytes_read);
|
||||
|
||||
if (!status.completed_ok()) {
|
||||
assert(num_bytes_read == 0);
|
||||
} else {
|
||||
assert(num_bytes_read == 1);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
64
webm_parser/src/parser_utils.h
Normal file
64
webm_parser/src/parser_utils.h
Normal file
@@ -0,0 +1,64 @@
|
||||
// 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.
|
||||
#ifndef SRC_PARSER_UTILS_H_
|
||||
#define SRC_PARSER_UTILS_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Reads a single byte from the reader, and returns the status of the read. If
|
||||
// the status is not Status::kOkCompleted, then no data was read.
|
||||
Status ReadByte(Reader* reader, std::uint8_t* byte);
|
||||
|
||||
// Accumulates bytes from the reader into the integer. The integer will be
|
||||
// extracted as a big-endian integer and stored with the native
|
||||
// host-endianness. num_bytes_remaining is the number of bytes to
|
||||
template <typename T>
|
||||
Status AccumulateIntegerBytes(int num_to_read, Reader* reader, T* integer,
|
||||
std::uint64_t* num_actually_read) {
|
||||
static_assert(std::is_integral<T>::value || std::is_enum<T>::value,
|
||||
"T must be an integer or enum type");
|
||||
// Use unsigned integers for bitwise arithmetic because it's well-defined (as
|
||||
// opposed to signed integers, where left shifting a negative integer is
|
||||
// undefined, for example).
|
||||
using UnsignedT = typename std::make_unsigned<T>::type;
|
||||
|
||||
assert(reader != nullptr);
|
||||
assert(integer != nullptr);
|
||||
assert(num_actually_read != nullptr);
|
||||
assert(num_to_read >= 0);
|
||||
assert(num_to_read <= sizeof(T));
|
||||
|
||||
*num_actually_read = 0;
|
||||
|
||||
if (num_to_read < 0 || num_to_read > sizeof(T)) {
|
||||
return Status(Status::kInvalidElementSize);
|
||||
}
|
||||
|
||||
for (; num_to_read > 0; --num_to_read) {
|
||||
std::uint8_t byte;
|
||||
const Status status = ReadByte(reader, &byte);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
++*num_actually_read;
|
||||
*integer = static_cast<T>((static_cast<UnsignedT>(*integer) << 8) | byte);
|
||||
}
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_PARSER_UTILS_H_
|
||||
85
webm_parser/src/recursive_parser.h
Normal file
85
webm_parser/src/recursive_parser.h
Normal file
@@ -0,0 +1,85 @@
|
||||
// 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.
|
||||
#ifndef SRC_RECURSIVE_PARSER_H_
|
||||
#define SRC_RECURSIVE_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "src/element_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Lazily instantiates a parser of type T, and uses that parser to handle all
|
||||
// parsing operations. The parser is allocated when Init is called. This class
|
||||
// is intended to be used with recursive elements, where a parser needs to
|
||||
// recursively instantiate parsers of the same type.
|
||||
template <typename T> class RecursiveParser : public ElementParser {
|
||||
public:
|
||||
RecursiveParser() = default;
|
||||
|
||||
RecursiveParser(RecursiveParser&&) = default;
|
||||
RecursiveParser& operator=(RecursiveParser&&) = default;
|
||||
|
||||
RecursiveParser(const RecursiveParser&) = delete;
|
||||
RecursiveParser& operator=(const RecursiveParser&) = delete;
|
||||
|
||||
Status Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) override {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
if (!impl_) {
|
||||
impl_.reset(new T);
|
||||
}
|
||||
|
||||
return impl_->Init(metadata, max_size);
|
||||
}
|
||||
|
||||
void InitAfterSeek(const Ancestory& child_ancestory,
|
||||
const ElementMetadata& child_metadata) override {
|
||||
if (!impl_) {
|
||||
impl_.reset(new T);
|
||||
}
|
||||
|
||||
impl_->InitAfterSeek(child_ancestory, child_metadata);
|
||||
}
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
assert(impl_ != nullptr);
|
||||
|
||||
return impl_->Feed(callback, reader, num_bytes_read);
|
||||
}
|
||||
|
||||
decltype(std::declval<T>().value()) value() const {
|
||||
assert(impl_ != nullptr);
|
||||
|
||||
return impl_->value();
|
||||
}
|
||||
|
||||
decltype(std::declval<T>().mutable_value()) mutable_value() {
|
||||
assert(impl_ != nullptr);
|
||||
|
||||
return impl_->mutable_value();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<T> impl_;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_RECURSIVE_PARSER_H_
|
||||
27
webm_parser/src/seek_head_parser.h
Normal file
27
webm_parser/src/seek_head_parser.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// 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.
|
||||
#ifndef SRC_SEEK_HEAD_PARSER_H_
|
||||
#define SRC_SEEK_HEAD_PARSER_H_
|
||||
|
||||
#include "src/master_parser.h"
|
||||
#include "src/seek_parser.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#SeekHead
|
||||
// http://www.webmproject.org/docs/container/#SeekHead
|
||||
class SeekHeadParser : public MasterParser {
|
||||
public:
|
||||
SeekHeadParser() : MasterParser(MakeChild<SeekParser>(Id::kSeek)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_SEEK_HEAD_PARSER_H_
|
||||
37
webm_parser/src/seek_parser.h
Normal file
37
webm_parser/src/seek_parser.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// 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.
|
||||
#ifndef SRC_SEEK_PARSER_H_
|
||||
#define SRC_SEEK_PARSER_H_
|
||||
|
||||
#include "src/id_element_parser.h"
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Seek
|
||||
// http://www.webmproject.org/docs/container/#Seek
|
||||
class SeekParser : public MasterValueParser<Seek> {
|
||||
public:
|
||||
SeekParser()
|
||||
: MasterValueParser<Seek>(
|
||||
MakeChild<IdElementParser>(Id::kSeekId, &Seek::id),
|
||||
MakeChild<UnsignedIntParser>(Id::kSeekPosition, &Seek::position)) {}
|
||||
|
||||
protected:
|
||||
Status OnParseCompleted(Callback* callback) override {
|
||||
return callback->OnSeek(metadata(Id::kSeek), value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_SEEK_PARSER_H_
|
||||
86
webm_parser/src/segment_parser.cc
Normal file
86
webm_parser/src/segment_parser.cc
Normal file
@@ -0,0 +1,86 @@
|
||||
// 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 "src/segment_parser.h"
|
||||
|
||||
#include "src/chapters_parser.h"
|
||||
#include "src/cluster_parser.h"
|
||||
#include "src/cues_parser.h"
|
||||
#include "src/info_parser.h"
|
||||
#include "src/seek_head_parser.h"
|
||||
#include "src/skip_callback.h"
|
||||
#include "src/tags_parser.h"
|
||||
#include "src/tracks_parser.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
SegmentParser::SegmentParser()
|
||||
: MasterParser(MakeChild<ChaptersParser>(Id::kChapters),
|
||||
MakeChild<ClusterParser>(Id::kCluster),
|
||||
MakeChild<CuesParser>(Id::kCues),
|
||||
MakeChild<InfoParser>(Id::kInfo),
|
||||
MakeChild<SeekHeadParser>(Id::kSeekHead),
|
||||
MakeChild<TagsParser>(Id::kTags),
|
||||
MakeChild<TracksParser>(Id::kTracks)) {}
|
||||
|
||||
Status SegmentParser::Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
begin_done_ = false;
|
||||
parse_completed_ = false;
|
||||
return MasterParser::Init(metadata, max_size);
|
||||
}
|
||||
|
||||
void SegmentParser::InitAfterSeek(const Ancestory& child_ancestory,
|
||||
const ElementMetadata& child_metadata) {
|
||||
MasterParser::InitAfterSeek(child_ancestory, child_metadata);
|
||||
|
||||
begin_done_ = true;
|
||||
parse_completed_ = false;
|
||||
action_ = Action::kRead;
|
||||
}
|
||||
|
||||
Status SegmentParser::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
*num_bytes_read = 0;
|
||||
|
||||
if (!begin_done_) {
|
||||
const ElementMetadata metadata{Id::kSegment, header_size(), size(),
|
||||
position()};
|
||||
const Status status = callback->OnSegmentBegin(metadata, &action_);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
begin_done_ = true;
|
||||
}
|
||||
|
||||
SkipCallback skip_callback;
|
||||
if (action_ == Action::kSkip) {
|
||||
callback = &skip_callback;
|
||||
}
|
||||
|
||||
if (!parse_completed_) {
|
||||
const Status status = MasterParser::Feed(callback, reader, num_bytes_read);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
parse_completed_ = true;
|
||||
}
|
||||
|
||||
return callback->OnSegmentEnd(
|
||||
{Id::kSegment, header_size(), size(), position()});
|
||||
}
|
||||
|
||||
bool SegmentParser::WasSkipped() const { return action_ == Action::kSkip; }
|
||||
|
||||
} // namespace webm
|
||||
53
webm_parser/src/segment_parser.h
Normal file
53
webm_parser/src/segment_parser.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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.
|
||||
#ifndef SRC_SEGMENT_PARSER_H_
|
||||
#define SRC_SEGMENT_PARSER_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/master_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Parses Segment elements from a WebM byte stream. This class adheres to the
|
||||
// ElementParser interface; see element_parser.h for further documentation on
|
||||
// how it should be used.
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Segment
|
||||
// http://www.webmproject.org/docs/container/#Segment
|
||||
class SegmentParser : public MasterParser {
|
||||
public:
|
||||
SegmentParser();
|
||||
|
||||
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
|
||||
|
||||
void InitAfterSeek(const Ancestory& child_ancestory,
|
||||
const ElementMetadata& child_metadata) override;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
bool WasSkipped() const override;
|
||||
|
||||
private:
|
||||
// Set to true iff Callback::OnSegmentBegin has completed.
|
||||
bool begin_done_;
|
||||
|
||||
// Set to true iff the base class has completed parsing.
|
||||
bool parse_completed_;
|
||||
|
||||
// The action requested by Callback::OnSegmentBegin.
|
||||
Action action_;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_SEGMENT_PARSER_H_
|
||||
38
webm_parser/src/simple_tag_parser.h
Normal file
38
webm_parser/src/simple_tag_parser.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// 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.
|
||||
#ifndef SRC_SIMPLE_TAG_PARSER_H_
|
||||
#define SRC_SIMPLE_TAG_PARSER_H_
|
||||
|
||||
#include "src/bool_parser.h"
|
||||
#include "src/byte_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "src/recursive_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#SimpleTag
|
||||
// http://www.webmproject.org/docs/container/#SimpleTag
|
||||
class SimpleTagParser : public MasterValueParser<SimpleTag> {
|
||||
public:
|
||||
SimpleTagParser()
|
||||
: MasterValueParser<SimpleTag>(
|
||||
MakeChild<StringParser>(Id::kTagName, &SimpleTag::name),
|
||||
MakeChild<StringParser>(Id::kTagLanguage, &SimpleTag::language),
|
||||
MakeChild<BoolParser>(Id::kTagDefault, &SimpleTag::is_default),
|
||||
MakeChild<StringParser>(Id::kTagString, &SimpleTag::string),
|
||||
MakeChild<BinaryParser>(Id::kTagBinary, &SimpleTag::binary),
|
||||
MakeChild<RecursiveParser<SimpleTagParser>>(Id::kSimpleTag,
|
||||
&SimpleTag::tags)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_SIMPLE_TAG_PARSER_H_
|
||||
56
webm_parser/src/size_parser.cc
Normal file
56
webm_parser/src/size_parser.cc
Normal file
@@ -0,0 +1,56 @@
|
||||
// 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 "src/size_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#include "src/bit_utils.h"
|
||||
#include "src/parser_utils.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec references:
|
||||
// http://matroska.org/technical/specs/index.html#EBML_ex
|
||||
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#element-data-size
|
||||
Status SizeParser::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
// Within the EBML header, the size can be encoded with 1-4 octets. After
|
||||
// the EBML header, the size can be encoded with 1-8 octets (though not more
|
||||
// than EBMLMaxSizeLength).
|
||||
|
||||
Status status = uint_parser_.Feed(callback, reader, num_bytes_read);
|
||||
|
||||
if (status.code == Status::kInvalidElementValue) {
|
||||
status.code = Status::kInvalidElementSize;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
std::uint64_t SizeParser::size() const {
|
||||
// If all data bits are set, then it represents an unknown element size.
|
||||
const std::uint64_t data_bits =
|
||||
std::numeric_limits<std::uint64_t>::max() >>
|
||||
(57 - 7 * (uint_parser_.encoded_length() - 1));
|
||||
if (uint_parser_.value() == data_bits) {
|
||||
return kUnknownElementSize;
|
||||
}
|
||||
|
||||
return uint_parser_.value();
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
43
webm_parser/src/size_parser.h
Normal file
43
webm_parser/src/size_parser.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// 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.
|
||||
#ifndef SRC_SIZE_PARSER_H_
|
||||
#define SRC_SIZE_PARSER_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/parser.h"
|
||||
#include "src/var_int_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
class SizeParser : public Parser {
|
||||
public:
|
||||
SizeParser() = default;
|
||||
SizeParser(SizeParser&&) = default;
|
||||
SizeParser& operator=(SizeParser&&) = default;
|
||||
|
||||
SizeParser(const SizeParser&) = delete;
|
||||
SizeParser& operator=(const SizeParser&) = delete;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
// Gets the parsed size. This must not be called until the parse had been
|
||||
// successfully completed.
|
||||
std::uint64_t size() const;
|
||||
|
||||
private:
|
||||
VarIntParser uint_parser_;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_SIZE_PARSER_H_
|
||||
63
webm_parser/src/skip_callback.h
Normal file
63
webm_parser/src/skip_callback.h
Normal file
@@ -0,0 +1,63 @@
|
||||
// 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.
|
||||
#ifndef SRC_SKIP_CALLBACK_H_
|
||||
#define SRC_SKIP_CALLBACK_H_
|
||||
|
||||
#include "webm/callback.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// An implementation of Callback that skips all elements. Every method that
|
||||
// yields an action will yield Action::kSkip, and Reader::Skip will be called
|
||||
// if the callback ever needs to process data from the byte stream.
|
||||
class SkipCallback : public Callback {
|
||||
public:
|
||||
Status OnElementBegin(const ElementMetadata& metadata,
|
||||
Action* action) override {
|
||||
*action = Action::kSkip;
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status OnSegmentBegin(const ElementMetadata& metadata,
|
||||
Action* action) override {
|
||||
*action = Action::kSkip;
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status OnClusterBegin(const ElementMetadata& metadata, const Cluster& cluster,
|
||||
Action* action) override {
|
||||
*action = Action::kSkip;
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status OnSimpleBlockBegin(const ElementMetadata& metadata,
|
||||
const SimpleBlock& simple_block,
|
||||
Action* action) override {
|
||||
*action = Action::kSkip;
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status OnBlockGroupBegin(const ElementMetadata& metadata,
|
||||
Action* action) override {
|
||||
*action = Action::kSkip;
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status OnBlockBegin(const ElementMetadata& metadata, const Block& block,
|
||||
Action* action) override {
|
||||
*action = Action::kSkip;
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_SKIP_CALLBACK_H_
|
||||
59
webm_parser/src/skip_parser.cc
Normal file
59
webm_parser/src/skip_parser.cc
Normal file
@@ -0,0 +1,59 @@
|
||||
// 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 "src/skip_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "webm/element.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
Status SkipParser::Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
if (metadata.size == kUnknownElementSize) {
|
||||
return Status(Status::kInvalidElementSize);
|
||||
}
|
||||
|
||||
num_bytes_remaining_ = metadata.size;
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status SkipParser::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
*num_bytes_read = 0;
|
||||
|
||||
if (num_bytes_remaining_ == 0) {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status status;
|
||||
do {
|
||||
std::uint64_t local_num_bytes_read = 0;
|
||||
status = reader->Skip(num_bytes_remaining_, &local_num_bytes_read);
|
||||
assert((status.completed_ok() &&
|
||||
local_num_bytes_read == num_bytes_remaining_) ||
|
||||
(status.ok() && local_num_bytes_read < num_bytes_remaining_) ||
|
||||
(!status.ok() && local_num_bytes_read == 0));
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
num_bytes_remaining_ -= local_num_bytes_read;
|
||||
} while (status.code == Status::kOkPartial);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
35
webm_parser/src/skip_parser.h
Normal file
35
webm_parser/src/skip_parser.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// 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.
|
||||
#ifndef SRC_SKIP_PARSER_H_
|
||||
#define SRC_SKIP_PARSER_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/element_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// A simple parser that merely skips (via Reader::Skip) ahead in the stream
|
||||
// until the element has been fully skipped.
|
||||
class SkipParser : public ElementParser {
|
||||
public:
|
||||
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
private:
|
||||
std::uint64_t num_bytes_remaining_;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_SKIP_PARSER_H_
|
||||
30
webm_parser/src/slices_parser.h
Normal file
30
webm_parser/src/slices_parser.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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.
|
||||
#ifndef SRC_SLICES_PARSER_H_
|
||||
#define SRC_SLICES_PARSER_H_
|
||||
|
||||
#include "src/master_value_parser.h"
|
||||
#include "src/time_slice_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Slices
|
||||
// http://www.webmproject.org/docs/container/#Slices
|
||||
class SlicesParser : public MasterValueParser<Slices> {
|
||||
public:
|
||||
SlicesParser()
|
||||
: MasterValueParser<Slices>(
|
||||
MakeChild<TimeSliceParser>(Id::kTimeSlice, &Slices::slices)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_SLICES_PARSER_H_
|
||||
37
webm_parser/src/tag_parser.h
Normal file
37
webm_parser/src/tag_parser.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// 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.
|
||||
#ifndef SRC_TAG_PARSER_H_
|
||||
#define SRC_TAG_PARSER_H_
|
||||
|
||||
#include "src/master_value_parser.h"
|
||||
#include "src/simple_tag_parser.h"
|
||||
#include "src/targets_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Tag
|
||||
// http://www.webmproject.org/docs/container/#Tag
|
||||
class TagParser : public MasterValueParser<Tag> {
|
||||
public:
|
||||
TagParser()
|
||||
: MasterValueParser<Tag>(
|
||||
MakeChild<TargetsParser>(Id::kTargets, &Tag::targets),
|
||||
MakeChild<SimpleTagParser>(Id::kSimpleTag, &Tag::tags)) {}
|
||||
|
||||
protected:
|
||||
Status OnParseCompleted(Callback* callback) override {
|
||||
return callback->OnTag(metadata(Id::kTag), value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_TAG_PARSER_H_
|
||||
27
webm_parser/src/tags_parser.h
Normal file
27
webm_parser/src/tags_parser.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// 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.
|
||||
#ifndef SRC_TAGS_PARSER_H_
|
||||
#define SRC_TAGS_PARSER_H_
|
||||
|
||||
#include "src/master_parser.h"
|
||||
#include "src/tag_parser.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Tags
|
||||
// http://www.webmproject.org/docs/container/#Tags
|
||||
class TagsParser : public MasterParser {
|
||||
public:
|
||||
TagsParser() : MasterParser(MakeChild<TagParser>(Id::kTag)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_TAGS_PARSER_H_
|
||||
35
webm_parser/src/targets_parser.h
Normal file
35
webm_parser/src/targets_parser.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// 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.
|
||||
#ifndef SRC_TARGETS_PARSER_H_
|
||||
#define SRC_TARGETS_PARSER_H_
|
||||
|
||||
#include "src/byte_parser.h"
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Targets
|
||||
// http://www.webmproject.org/docs/container/#Targets
|
||||
class TargetsParser : public MasterValueParser<Targets> {
|
||||
public:
|
||||
TargetsParser()
|
||||
: MasterValueParser<Targets>(
|
||||
MakeChild<UnsignedIntParser>(Id::kTargetTypeValue,
|
||||
&Targets::type_value),
|
||||
MakeChild<StringParser>(Id::kTargetType, &Targets::type),
|
||||
MakeChild<UnsignedIntParser>(Id::kTagTrackUid,
|
||||
&Targets::track_uids)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_TARGETS_PARSER_H_
|
||||
30
webm_parser/src/time_slice_parser.h
Normal file
30
webm_parser/src/time_slice_parser.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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.
|
||||
#ifndef SRC_TIME_SLICE_PARSER_H_
|
||||
#define SRC_TIME_SLICE_PARSER_H_
|
||||
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#TimeSlice
|
||||
// http://www.webmproject.org/docs/container/#TimeSlice
|
||||
class TimeSliceParser : public MasterValueParser<TimeSlice> {
|
||||
public:
|
||||
TimeSliceParser()
|
||||
: MasterValueParser<TimeSlice>(MakeChild<UnsignedIntParser>(
|
||||
Id::kLaceNumber, &TimeSlice::lace_number)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_TIME_SLICE_PARSER_H_
|
||||
65
webm_parser/src/track_entry_parser.h
Normal file
65
webm_parser/src/track_entry_parser.h
Normal file
@@ -0,0 +1,65 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SRC_TRACK_ENTRY_PARSER_H_
|
||||
#define SRC_TRACK_ENTRY_PARSER_H_
|
||||
|
||||
#include "src/audio_parser.h"
|
||||
#include "src/bool_parser.h"
|
||||
#include "src/byte_parser.h"
|
||||
#include "src/content_encodings_parser.h"
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "src/video_parser.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#TrackEntry
|
||||
// http://www.webmproject.org/docs/container/#TrackEntry
|
||||
class TrackEntryParser : public MasterValueParser<TrackEntry> {
|
||||
public:
|
||||
TrackEntryParser()
|
||||
: MasterValueParser<TrackEntry>(
|
||||
MakeChild<UnsignedIntParser>(Id::kTrackNumber,
|
||||
&TrackEntry::track_number),
|
||||
MakeChild<UnsignedIntParser>(Id::kTrackUid, &TrackEntry::track_uid),
|
||||
MakeChild<IntParser<TrackType>>(Id::kTrackType,
|
||||
&TrackEntry::track_type),
|
||||
MakeChild<BoolParser>(Id::kFlagEnabled, &TrackEntry::is_enabled),
|
||||
MakeChild<BoolParser>(Id::kFlagDefault, &TrackEntry::is_default),
|
||||
MakeChild<BoolParser>(Id::kFlagForced, &TrackEntry::is_forced),
|
||||
MakeChild<BoolParser>(Id::kFlagLacing, &TrackEntry::uses_lacing),
|
||||
MakeChild<UnsignedIntParser>(Id::kDefaultDuration,
|
||||
&TrackEntry::default_duration),
|
||||
MakeChild<StringParser>(Id::kName, &TrackEntry::name),
|
||||
MakeChild<StringParser>(Id::kLanguage, &TrackEntry::language),
|
||||
MakeChild<StringParser>(Id::kCodecId, &TrackEntry::codec_id),
|
||||
MakeChild<BinaryParser>(Id::kCodecPrivate,
|
||||
&TrackEntry::codec_private),
|
||||
MakeChild<StringParser>(Id::kCodecName, &TrackEntry::codec_name),
|
||||
MakeChild<UnsignedIntParser>(Id::kCodecDelay,
|
||||
&TrackEntry::codec_delay),
|
||||
MakeChild<UnsignedIntParser>(Id::kSeekPreRoll,
|
||||
&TrackEntry::seek_pre_roll),
|
||||
MakeChild<VideoParser>(Id::kVideo, &TrackEntry::video),
|
||||
MakeChild<AudioParser>(Id::kAudio, &TrackEntry::audio),
|
||||
MakeChild<ContentEncodingsParser>(
|
||||
Id::kContentEncodings, &TrackEntry::content_encodings)) {}
|
||||
|
||||
protected:
|
||||
Status OnParseCompleted(Callback* callback) override {
|
||||
return callback->OnTrackEntry(metadata(Id::kTrackEntry), value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_TRACK_ENTRY_PARSER_H_
|
||||
27
webm_parser/src/tracks_parser.h
Normal file
27
webm_parser/src/tracks_parser.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// 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.
|
||||
#ifndef SRC_TRACKS_PARSER_H_
|
||||
#define SRC_TRACKS_PARSER_H_
|
||||
|
||||
#include "src/master_parser.h"
|
||||
#include "src/track_entry_parser.h"
|
||||
#include "webm/id.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Tracks
|
||||
// http://www.webmproject.org/docs/container/#Tracks
|
||||
class TracksParser : public MasterParser {
|
||||
public:
|
||||
TracksParser() : MasterParser(MakeChild<TrackEntryParser>(Id::kTrackEntry)) {}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_TRACKS_PARSER_H_
|
||||
49
webm_parser/src/unknown_parser.cc
Normal file
49
webm_parser/src/unknown_parser.cc
Normal file
@@ -0,0 +1,49 @@
|
||||
// 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 "src/unknown_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "webm/element.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
Status UnknownParser::Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
if (metadata.size == kUnknownElementSize) {
|
||||
return Status(Status::kIndefiniteUnknownElement);
|
||||
}
|
||||
|
||||
metadata_ = metadata;
|
||||
bytes_remaining_ = metadata.size;
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status UnknownParser::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
const std::uint64_t original_bytes_remaining = bytes_remaining_;
|
||||
const Status status =
|
||||
callback->OnUnknownElement(metadata_, reader, &bytes_remaining_);
|
||||
assert(bytes_remaining_ <= original_bytes_remaining);
|
||||
|
||||
*num_bytes_read = original_bytes_remaining - bytes_remaining_;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
38
webm_parser/src/unknown_parser.h
Normal file
38
webm_parser/src/unknown_parser.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// 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.
|
||||
#ifndef SRC_UNKNOWN_PARSER_H_
|
||||
#define SRC_UNKNOWN_PARSER_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/element_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Parses unknown elements by delegating to Callback::OnUnknownElement.
|
||||
class UnknownParser : public ElementParser {
|
||||
public:
|
||||
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
private:
|
||||
// The metadata for this element.
|
||||
ElementMetadata metadata_;
|
||||
|
||||
// The number of bytes remaining that have not been read in the element.
|
||||
std::uint64_t bytes_remaining_;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_UNKNOWN_PARSER_H_
|
||||
71
webm_parser/src/var_int_parser.cc
Normal file
71
webm_parser/src/var_int_parser.cc
Normal file
@@ -0,0 +1,71 @@
|
||||
// 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 "src/var_int_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#include "src/bit_utils.h"
|
||||
#include "src/parser_utils.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec references:
|
||||
// http://matroska.org/technical/specs/index.html#EBML_ex
|
||||
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#variable-size-integer
|
||||
Status VarIntParser::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
assert(num_bytes_remaining_ != 0);
|
||||
|
||||
*num_bytes_read = 0;
|
||||
|
||||
if (num_bytes_remaining_ == -1) {
|
||||
std::uint8_t first_byte;
|
||||
const Status status = ReadByte(reader, &first_byte);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
++*num_bytes_read;
|
||||
|
||||
// The first byte must have a marker bit set to indicate how many octets are
|
||||
// used.
|
||||
if (first_byte == 0) {
|
||||
return Status(Status::kInvalidElementValue);
|
||||
}
|
||||
|
||||
total_data_bytes_ = CountLeadingZeros(first_byte);
|
||||
num_bytes_remaining_ = total_data_bytes_;
|
||||
|
||||
value_ = first_byte;
|
||||
}
|
||||
|
||||
std::uint64_t local_num_bytes_read;
|
||||
const Status status = AccumulateIntegerBytes(num_bytes_remaining_, reader,
|
||||
&value_, &local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
num_bytes_remaining_ -= static_cast<int>(local_num_bytes_read);
|
||||
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Clear the marker bit.
|
||||
constexpr std::uint64_t all_bits = std::numeric_limits<std::uint64_t>::max();
|
||||
const std::uint64_t data_bits = all_bits >> (57 - 7 * total_data_bytes_);
|
||||
value_ &= data_bits;
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
56
webm_parser/src/var_int_parser.h
Normal file
56
webm_parser/src/var_int_parser.h
Normal file
@@ -0,0 +1,56 @@
|
||||
// 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.
|
||||
#ifndef SRC_VAR_INT_PARSER_H_
|
||||
#define SRC_VAR_INT_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
class VarIntParser : public Parser {
|
||||
public:
|
||||
VarIntParser() = default;
|
||||
VarIntParser(VarIntParser&&) = default;
|
||||
VarIntParser& operator=(VarIntParser&&) = default;
|
||||
|
||||
VarIntParser(const VarIntParser&) = delete;
|
||||
VarIntParser& operator=(const VarIntParser&) = delete;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
// Gets the parsed value. This must not be called until the parse had been
|
||||
// successfully completed.
|
||||
std::uint64_t value() const {
|
||||
assert(num_bytes_remaining_ == 0);
|
||||
return value_;
|
||||
}
|
||||
|
||||
// Gets the number of bytes which were used to encode the integer value in the
|
||||
// byte stream. This must not be called until the parse had been successfully
|
||||
// completed.
|
||||
int encoded_length() const {
|
||||
assert(num_bytes_remaining_ == 0);
|
||||
return total_data_bytes_ + 1;
|
||||
}
|
||||
|
||||
private:
|
||||
int num_bytes_remaining_ = -1;
|
||||
int total_data_bytes_;
|
||||
std::uint64_t value_;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_VAR_INT_PARSER_H_
|
||||
120
webm_parser/src/video_parser.h
Normal file
120
webm_parser/src/video_parser.h
Normal file
@@ -0,0 +1,120 @@
|
||||
// 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.
|
||||
#ifndef SRC_VIDEO_PARSER_H_
|
||||
#define SRC_VIDEO_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/bool_parser.h"
|
||||
#include "src/colour_parser.h"
|
||||
#include "src/float_parser.h"
|
||||
#include "src/int_parser.h"
|
||||
#include "src/master_value_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/id.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Video
|
||||
// http://www.webmproject.org/docs/container/#Video
|
||||
class VideoParser : public MasterValueParser<Video> {
|
||||
public:
|
||||
VideoParser()
|
||||
: MasterValueParser<Video>(
|
||||
MakeChild<IntParser<FlagInterlaced>>(Id::kFlagInterlaced,
|
||||
&Video::interlaced),
|
||||
MakeChild<IntParser<StereoMode>>(Id::kStereoMode,
|
||||
&Video::stereo_mode),
|
||||
MakeChild<UnsignedIntParser>(Id::kAlphaMode, &Video::alpha_mode),
|
||||
MakeChild<UnsignedIntParser>(Id::kPixelWidth, &Video::pixel_width),
|
||||
MakeChild<UnsignedIntParser>(Id::kPixelHeight,
|
||||
&Video::pixel_height),
|
||||
MakeChild<UnsignedIntParser>(Id::kPixelCropBottom,
|
||||
&Video::pixel_crop_bottom),
|
||||
MakeChild<UnsignedIntParser>(Id::kPixelCropTop,
|
||||
&Video::pixel_crop_top),
|
||||
MakeChild<UnsignedIntParser>(Id::kPixelCropLeft,
|
||||
&Video::pixel_crop_left),
|
||||
MakeChild<UnsignedIntParser>(Id::kPixelCropRight,
|
||||
&Video::pixel_crop_right),
|
||||
MakeChild<UnsignedIntParser>(Id::kDisplayWidth,
|
||||
&Video::display_width)
|
||||
.NotifyOnParseComplete(),
|
||||
MakeChild<UnsignedIntParser>(Id::kDisplayHeight,
|
||||
&Video::display_height)
|
||||
.NotifyOnParseComplete(),
|
||||
MakeChild<IntParser<DisplayUnit>>(Id::kDisplayUnit,
|
||||
&Video::display_unit),
|
||||
MakeChild<IntParser<AspectRatioType>>(Id::kAspectRatioType,
|
||||
&Video::aspect_ratio_type),
|
||||
MakeChild<FloatParser>(Id::kFrameRate, &Video::frame_rate),
|
||||
MakeChild<ColourParser>(Id::kColour, &Video::colour)) {}
|
||||
|
||||
Status Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) override {
|
||||
display_width_has_value_ = false;
|
||||
display_height_has_value_ = false;
|
||||
|
||||
return MasterValueParser::Init(metadata, max_size);
|
||||
}
|
||||
|
||||
void InitAfterSeek(const Ancestory& child_ancestory,
|
||||
const ElementMetadata& child_metadata) override {
|
||||
display_width_has_value_ = false;
|
||||
display_height_has_value_ = false;
|
||||
|
||||
return MasterValueParser::InitAfterSeek(child_ancestory, child_metadata);
|
||||
}
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override {
|
||||
const Status status =
|
||||
MasterValueParser::Feed(callback, reader, num_bytes_read);
|
||||
if (status.completed_ok()) {
|
||||
FixMissingDisplaySize();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
protected:
|
||||
void OnChildParsed(const ElementMetadata& metadata) override {
|
||||
assert(metadata.id == Id::kDisplayWidth ||
|
||||
metadata.id == Id::kDisplayHeight);
|
||||
|
||||
if (metadata.id == Id::kDisplayWidth) {
|
||||
display_width_has_value_ = metadata.size > 0;
|
||||
} else {
|
||||
display_height_has_value_ = metadata.size > 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool display_width_has_value_;
|
||||
bool display_height_has_value_;
|
||||
|
||||
void FixMissingDisplaySize() {
|
||||
if (!display_width_has_value_) {
|
||||
*mutable_value()->display_width.mutable_value() =
|
||||
value().pixel_width.value();
|
||||
}
|
||||
|
||||
if (!display_height_has_value_) {
|
||||
*mutable_value()->display_height.mutable_value() =
|
||||
value().pixel_height.value();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_VIDEO_PARSER_H_
|
||||
72
webm_parser/src/virtual_block_parser.cc
Normal file
72
webm_parser/src/virtual_block_parser.cc
Normal file
@@ -0,0 +1,72 @@
|
||||
// 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 "src/virtual_block_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "webm/element.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
Status VirtualBlockParser::Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
if (metadata.size == kUnknownElementSize || metadata.size < 4) {
|
||||
return Status(Status::kInvalidElementSize);
|
||||
}
|
||||
|
||||
*this = {};
|
||||
my_size_ = metadata.size;
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status VirtualBlockParser::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
*num_bytes_read = 0;
|
||||
|
||||
Status status;
|
||||
std::uint64_t local_num_bytes_read;
|
||||
|
||||
while (true) {
|
||||
switch (state_) {
|
||||
case State::kReadingHeader: {
|
||||
status = parser_.Feed(callback, reader, &local_num_bytes_read);
|
||||
*num_bytes_read += local_num_bytes_read;
|
||||
total_bytes_read_ += local_num_bytes_read;
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
value_.track_number = parser_.value().track_number;
|
||||
value_.timecode = parser_.value().timecode;
|
||||
state_ = State::kValidatingSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kValidatingSize: {
|
||||
if (my_size_ < total_bytes_read_) {
|
||||
return Status(Status::kInvalidElementValue);
|
||||
}
|
||||
state_ = State::kDone;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kDone: {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
67
webm_parser/src/virtual_block_parser.h
Normal file
67
webm_parser/src/virtual_block_parser.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// 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.
|
||||
#ifndef SRC_VIRTUAL_BLOCK_PARSER_H_
|
||||
#define SRC_VIRTUAL_BLOCK_PARSER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/block_header_parser.h"
|
||||
#include "src/element_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/dom_types.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#BlockVirtual
|
||||
// http://www.webmproject.org/docs/container/#BlockVirtual
|
||||
// http://matroska.org/technical/specs/index.html#block_virtual
|
||||
class VirtualBlockParser : public ElementParser {
|
||||
public:
|
||||
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
// Gets the parsed block header information. This must not be called until the
|
||||
// parse has been successfully completed.
|
||||
const VirtualBlock& value() const {
|
||||
assert(state_ == State::kDone);
|
||||
return value_;
|
||||
}
|
||||
|
||||
// Gets the parsed block header information. This must not be called until the
|
||||
// parse has been successfully completed.
|
||||
VirtualBlock* mutable_value() {
|
||||
assert(state_ == State::kDone);
|
||||
return &value_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::uint64_t my_size_;
|
||||
std::uint64_t total_bytes_read_ = 0;
|
||||
|
||||
VirtualBlock value_{};
|
||||
|
||||
BlockHeaderParser parser_;
|
||||
|
||||
enum class State {
|
||||
// State Transitions to state When
|
||||
kReadingHeader, // kValidatingSize header parsed
|
||||
kValidatingSize, // kDone no errors
|
||||
kDone, // No transitions from here (must call Init)
|
||||
} state_ = State::kReadingHeader;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_VIRTUAL_BLOCK_PARSER_H_
|
||||
49
webm_parser/src/void_parser.cc
Normal file
49
webm_parser/src/void_parser.cc
Normal file
@@ -0,0 +1,49 @@
|
||||
// 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 "src/void_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "webm/callback.h"
|
||||
#include "webm/element.h"
|
||||
#include "webm/id.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
Status VoidParser::Init(const ElementMetadata& metadata,
|
||||
std::uint64_t max_size) {
|
||||
assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
|
||||
|
||||
if (metadata.size == kUnknownElementSize) {
|
||||
return Status(Status::kInvalidElementSize);
|
||||
}
|
||||
|
||||
metadata_ = metadata;
|
||||
bytes_remaining_ = metadata.size;
|
||||
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
|
||||
Status VoidParser::Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
assert(num_bytes_read != nullptr);
|
||||
|
||||
const std::uint64_t original_bytes_remaining = bytes_remaining_;
|
||||
const Status status = callback->OnVoid(metadata_, reader, &bytes_remaining_);
|
||||
assert(bytes_remaining_ <= original_bytes_remaining);
|
||||
|
||||
*num_bytes_read = original_bytes_remaining - bytes_remaining_;
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace webm
|
||||
41
webm_parser/src/void_parser.h
Normal file
41
webm_parser/src/void_parser.h
Normal file
@@ -0,0 +1,41 @@
|
||||
// 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.
|
||||
#ifndef SRC_VOID_PARSER_H_
|
||||
#define SRC_VOID_PARSER_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/element_parser.h"
|
||||
#include "webm/callback.h"
|
||||
#include "webm/reader.h"
|
||||
#include "webm/status.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Parses a Void element by delegating to Callback::OnVoid.
|
||||
// Spec reference:
|
||||
// http://matroska.org/technical/specs/index.html#Void
|
||||
// http://www.webmproject.org/docs/container/#Void
|
||||
class VoidParser : public ElementParser {
|
||||
public:
|
||||
Status Init(const ElementMetadata& metadata, std::uint64_t max_size) override;
|
||||
|
||||
Status Feed(Callback* callback, Reader* reader,
|
||||
std::uint64_t* num_bytes_read) override;
|
||||
|
||||
private:
|
||||
// The metadata for this element.
|
||||
ElementMetadata metadata_;
|
||||
|
||||
// The number of bytes remaining that have not been read in the element.
|
||||
std::uint64_t bytes_remaining_ = 0;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // SRC_VOID_PARSER_H_
|
||||
276
webm_parser/src/webm_parser.cc
Normal file
276
webm_parser/src/webm_parser.cc
Normal file
@@ -0,0 +1,276 @@
|
||||
// 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 "webm/webm_parser.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/ebml_parser.h"
|
||||
#include "src/master_parser.h"
|
||||
#include "src/segment_parser.h"
|
||||
#include "webm/element.h"
|
||||
|
||||
namespace webm {
|
||||
|
||||
// Parses WebM EBML documents (i.e. level-0 WebM elements).
|
||||
class WebmParser::DocumentParser {
|
||||
public:
|
||||
// Resets the parser after a seek to a new position in the reader.
|
||||
void DidSeek() {
|
||||
PrepareForNextChild();
|
||||
did_seek_ = true;
|
||||
state_ = State::kBegin;
|
||||
}
|
||||
|
||||
// Feeds the parser; will return Status::kOkCompleted when the reader returns
|
||||
// Status::kEndOfFile, but only if the parser has already completed parsing
|
||||
// its child elements.
|
||||
Status Feed(Callback* callback, Reader* reader) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
|
||||
Callback* const original_callback = callback;
|
||||
if (action_ == Action::kSkip) {
|
||||
callback = &skip_callback_;
|
||||
}
|
||||
|
||||
Status status;
|
||||
std::uint64_t num_bytes_read;
|
||||
while (true) {
|
||||
switch (state_) {
|
||||
case State::kBegin: {
|
||||
child_metadata_.header_size = 0;
|
||||
child_metadata_.position = reader->Position();
|
||||
state_ = State::kReadingChildId;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kReadingChildId: {
|
||||
assert(child_parser_ == nullptr);
|
||||
status = id_parser_.Feed(callback, reader, &num_bytes_read);
|
||||
child_metadata_.header_size += num_bytes_read;
|
||||
if (!status.completed_ok()) {
|
||||
if (status.code == Status::kEndOfFile &&
|
||||
reader->Position() == child_metadata_.position) {
|
||||
state_ = State::kEndReached;
|
||||
continue;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
state_ = State::kReadingChildSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kReadingChildSize: {
|
||||
assert(child_parser_ == nullptr);
|
||||
status = size_parser_.Feed(callback, reader, &num_bytes_read);
|
||||
child_metadata_.header_size += num_bytes_read;
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
child_metadata_.id = id_parser_.id();
|
||||
child_metadata_.size = size_parser_.size();
|
||||
state_ = State::kValidatingChildSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kValidatingChildSize: {
|
||||
assert(child_parser_ == nullptr);
|
||||
|
||||
if (child_metadata_.id == Id::kSegment) {
|
||||
child_parser_ = &segment_parser_;
|
||||
did_seek_ = false;
|
||||
state_ = State::kGettingAction;
|
||||
continue;
|
||||
} else if (child_metadata_.id == Id::kEbml) {
|
||||
child_parser_ = &ebml_parser_;
|
||||
did_seek_ = false;
|
||||
state_ = State::kGettingAction;
|
||||
continue;
|
||||
}
|
||||
|
||||
Ancestory ancestory;
|
||||
if (did_seek_ && Ancestory::ById(child_metadata_.id, &ancestory)) {
|
||||
assert(!ancestory.empty());
|
||||
assert(ancestory.id() == Id::kSegment ||
|
||||
ancestory.id() == Id::kEbml);
|
||||
|
||||
if (ancestory.id() == Id::kSegment) {
|
||||
child_parser_ = &segment_parser_;
|
||||
} else {
|
||||
child_parser_ = &ebml_parser_;
|
||||
}
|
||||
|
||||
child_parser_->InitAfterSeek(ancestory.next(), child_metadata_);
|
||||
child_metadata_.id = ancestory.id();
|
||||
child_metadata_.header_size = kUnknownHeaderSize;
|
||||
child_metadata_.size = kUnknownElementSize;
|
||||
child_metadata_.position = kUnknownElementPosition;
|
||||
did_seek_ = false;
|
||||
action_ = Action::kRead;
|
||||
state_ = State::kReadingChildBody;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (child_metadata_.id == Id::kVoid) {
|
||||
child_parser_ = &void_parser_;
|
||||
} else {
|
||||
if (child_metadata_.size == kUnknownElementSize) {
|
||||
return Status(Status::kIndefiniteUnknownElement);
|
||||
}
|
||||
child_parser_ = &skip_parser_;
|
||||
}
|
||||
state_ = State::kGettingAction;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kGettingAction: {
|
||||
assert(child_parser_ != nullptr);
|
||||
status = callback->OnElementBegin(child_metadata_, &action_);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (action_ == Action::kSkip) {
|
||||
callback = &skip_callback_;
|
||||
if (child_metadata_.size != kUnknownElementSize) {
|
||||
child_parser_ = &skip_parser_;
|
||||
}
|
||||
}
|
||||
state_ = State::kInitializingChildParser;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kInitializingChildParser: {
|
||||
assert(child_parser_ != nullptr);
|
||||
status = child_parser_->Init(child_metadata_, child_metadata_.size);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
state_ = State::kReadingChildBody;
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kReadingChildBody: {
|
||||
assert(child_parser_ != nullptr);
|
||||
status = child_parser_->Feed(callback, reader, &num_bytes_read);
|
||||
if (!status.completed_ok()) {
|
||||
return status;
|
||||
}
|
||||
if (child_parser_->GetCachedMetadata(&child_metadata_)) {
|
||||
state_ = State::kValidatingChildSize;
|
||||
} else {
|
||||
child_metadata_.header_size = 0;
|
||||
state_ = State::kReadingChildId;
|
||||
}
|
||||
PrepareForNextChild();
|
||||
callback = original_callback;
|
||||
child_metadata_.position = reader->Position();
|
||||
continue;
|
||||
}
|
||||
|
||||
case State::kEndReached: {
|
||||
return Status(Status::kOkCompleted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Parsing states for the finite-state machine.
|
||||
enum class State {
|
||||
// State Transitions to state When
|
||||
kBegin, // kReadingChildId done
|
||||
kReadingChildId, // kReadingChildSize done
|
||||
// kEndReached EOF
|
||||
kReadingChildSize, // kValidatingChildSize done
|
||||
kValidatingChildSize, // kGettingAction done
|
||||
kGettingAction, // kInitializingChildParser done
|
||||
kInitializingChildParser, // kReadingChildBody done
|
||||
kReadingChildBody, // kValidatingChildSize cached metadata
|
||||
// kReadingChildId otherwise
|
||||
kEndReached, // No transitions from here
|
||||
};
|
||||
|
||||
// The parser for parsing child element Ids.
|
||||
IdParser id_parser_;
|
||||
|
||||
// The parser for parsing child element sizes.
|
||||
SizeParser size_parser_;
|
||||
|
||||
// The parser for Id::kEbml elements.
|
||||
EbmlParser ebml_parser_;
|
||||
|
||||
// The parser for Id::kSegment child elements.
|
||||
SegmentParser segment_parser_;
|
||||
|
||||
// The parser for Id::kVoid child elements.
|
||||
VoidParser void_parser_;
|
||||
|
||||
// The parser used when skipping elements (if the element's size is known).
|
||||
SkipParser skip_parser_;
|
||||
|
||||
// The callback used when skipping elements.
|
||||
SkipCallback skip_callback_;
|
||||
|
||||
// The parser that is parsing the current child element.
|
||||
ElementParser* child_parser_ = nullptr;
|
||||
|
||||
// Metadata for the current child being parsed.
|
||||
ElementMetadata child_metadata_ = {};
|
||||
|
||||
// Action for the current child being parsed.
|
||||
Action action_ = Action::kRead;
|
||||
|
||||
// True if a seek was performed and the parser needs to handle it.
|
||||
bool did_seek_ = false;
|
||||
|
||||
// The current state of the finite state machine.
|
||||
State state_ = State::kBegin;
|
||||
|
||||
// Resets state in preparation for parsing a child element.
|
||||
void PrepareForNextChild() {
|
||||
id_parser_ = {};
|
||||
size_parser_ = {};
|
||||
child_parser_ = nullptr;
|
||||
action_ = Action::kRead;
|
||||
}
|
||||
};
|
||||
|
||||
// We have to explicitly declare a destructor (even if it's just defaulted)
|
||||
// because using the pimpl idiom with std::unique_ptr requires it. See Herb
|
||||
// Sutter's GotW #100 for further explanation.
|
||||
WebmParser::~WebmParser() = default;
|
||||
|
||||
WebmParser::WebmParser() : parser_(new DocumentParser) {}
|
||||
|
||||
void WebmParser::DidSeek() {
|
||||
parser_->DidSeek();
|
||||
parsing_status_ = Status(Status::kOkPartial);
|
||||
}
|
||||
|
||||
Status WebmParser::Feed(Callback* callback, Reader* reader) {
|
||||
assert(callback != nullptr);
|
||||
assert(reader != nullptr);
|
||||
|
||||
if (parsing_status_.is_parsing_error()) {
|
||||
return parsing_status_;
|
||||
}
|
||||
parsing_status_ = parser_->Feed(callback, reader);
|
||||
return parsing_status_;
|
||||
}
|
||||
|
||||
void WebmParser::Swap(WebmParser* other) {
|
||||
assert(other != nullptr);
|
||||
parser_.swap(other->parser_);
|
||||
std::swap(parsing_status_, other->parsing_status_);
|
||||
}
|
||||
|
||||
void swap(WebmParser& left, WebmParser& right) { left.Swap(&right); }
|
||||
|
||||
} // namespace webm
|
||||
Reference in New Issue
Block a user