Initial release
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
// 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 INCLUDE_WEBM_BUFFER_READER_H_
|
||||
#define INCLUDE_WEBM_BUFFER_READER_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
|
||||
#include "./reader.h"
|
||||
#include "./status.h"
|
||||
|
||||
/**
|
||||
\file
|
||||
A `Reader` implementation that reads from a `std::vector<std::uint8_t>`.
|
||||
*/
|
||||
|
||||
namespace webm {
|
||||
|
||||
/**
|
||||
\addtogroup PUBLIC_API
|
||||
@{
|
||||
*/
|
||||
|
||||
/**
|
||||
A simple reader that reads data from a buffer of bytes.
|
||||
*/
|
||||
class BufferReader : public Reader {
|
||||
public:
|
||||
/**
|
||||
Constructs a new, empty reader.
|
||||
*/
|
||||
BufferReader() = default;
|
||||
|
||||
/**
|
||||
Constructs a new reader by copying the provided reader into the new reader.
|
||||
|
||||
\param other The source reader to copy.
|
||||
*/
|
||||
BufferReader(const BufferReader& other) = default;
|
||||
|
||||
/**
|
||||
Copies the provided reader into this reader.
|
||||
|
||||
\param other The source reader to copy. May be equal to `*this`, in which
|
||||
case this is a no-op.
|
||||
\return `*this`.
|
||||
*/
|
||||
BufferReader& operator=(const BufferReader& other) = default;
|
||||
|
||||
/**
|
||||
Constructs a new reader by moving the provided reader into the new reader.
|
||||
|
||||
\param other The source reader to move. After moving, it will be reset to an
|
||||
empty stream.
|
||||
*/
|
||||
BufferReader(BufferReader&&);
|
||||
|
||||
/**
|
||||
Moves the provided reader into this reader.
|
||||
|
||||
\param other The source reader to move. After moving, it will be reset to an
|
||||
empty stream. May be equal to `*this`, in which case this is a no-op.
|
||||
\return `*this`.
|
||||
*/
|
||||
BufferReader& operator=(BufferReader&&);
|
||||
|
||||
/**
|
||||
Creates a new `BufferReader` populated with the provided bytes.
|
||||
|
||||
\param bytes Bytes that are assigned to the internal buffer and used as the
|
||||
source which is read from.
|
||||
*/
|
||||
BufferReader(std::initializer_list<std::uint8_t> bytes);
|
||||
|
||||
/**
|
||||
Creates a new `BufferReader` populated with the provided data.
|
||||
|
||||
\param vector A vector of bytes that is copied to the internal buffer and
|
||||
used as the source which is read from.
|
||||
*/
|
||||
explicit BufferReader(const std::vector<std::uint8_t>& vector);
|
||||
|
||||
/**
|
||||
Creates a new `BufferReader` populated with the provided data.
|
||||
|
||||
\param vector A vector of bytes that is moved to the internal buffer and used
|
||||
as the source which is read from.
|
||||
*/
|
||||
explicit BufferReader(std::vector<std::uint8_t>&& vector);
|
||||
|
||||
/**
|
||||
Resets the reader to read from the given list of bytes, starting at the
|
||||
beginning.
|
||||
|
||||
This makes `reader = {1, 2, 3};` effectively equivalent to `reader =
|
||||
BufferReader({1, 2, 3});`.
|
||||
|
||||
\param bytes Bytes that are assigned to the internal buffer and used as the
|
||||
source which is read from.
|
||||
\return `*this`.
|
||||
*/
|
||||
BufferReader& operator=(std::initializer_list<std::uint8_t> bytes);
|
||||
|
||||
Status Read(std::size_t num_to_read, std::uint8_t* buffer,
|
||||
std::uint64_t* num_actually_read) override;
|
||||
|
||||
Status Skip(std::uint64_t num_to_skip,
|
||||
std::uint64_t* num_actually_skipped) override;
|
||||
|
||||
std::uint64_t Position() const override;
|
||||
|
||||
/**
|
||||
Gets the total size of the buffer.
|
||||
*/
|
||||
std::size_t size() const { return data_.size(); }
|
||||
|
||||
private:
|
||||
// Stores the byte buffer from which data is read.
|
||||
std::vector<std::uint8_t> data_;
|
||||
|
||||
// The position of the reader in the byte buffer.
|
||||
std::size_t pos_ = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // INCLUDE_WEBM_BUFFER_READER_H_
|
||||
@@ -0,0 +1,363 @@
|
||||
// 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 INCLUDE_WEBM_CALLBACK_H_
|
||||
#define INCLUDE_WEBM_CALLBACK_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "./dom_types.h"
|
||||
#include "./reader.h"
|
||||
#include "./status.h"
|
||||
|
||||
/**
|
||||
\file
|
||||
The main callback type that receives parsing events.
|
||||
*/
|
||||
|
||||
namespace webm {
|
||||
|
||||
/**
|
||||
\addtogroup PUBLIC_API
|
||||
@{
|
||||
*/
|
||||
|
||||
/**
|
||||
The action to be performed when parsing an element.
|
||||
*/
|
||||
enum class Action {
|
||||
/**
|
||||
Read and parse the element.
|
||||
*/
|
||||
kRead,
|
||||
|
||||
/**
|
||||
Skip the element. Skipped elements are not parsed or stored, and the callback
|
||||
is not given any further notifications regarding the element.
|
||||
*/
|
||||
kSkip,
|
||||
};
|
||||
|
||||
/**
|
||||
A callback that receives parsing events.
|
||||
|
||||
Every method that returns a `Status` should return `Status::kOkCompleted` when
|
||||
the method has completed and parsing should continue. Returning any other value
|
||||
will cause parsing to stop. Parsing may be resumed if the returned status was
|
||||
not a parsing error (see `Status::is_parsing_error()`). When parsing is
|
||||
resumed, the same `Callback` method will be called again.
|
||||
|
||||
Methods that take a `Reader` expect the implementation to consume (either via
|
||||
`Reader::Read()` or `Reader::Skip()`) the specified number of bytes before
|
||||
returning `Status::kOkCompleted`. Default implementations will call
|
||||
`Reader::Skip()` to skip the specified number of bytes and the resulting
|
||||
`Status` will be returned (unless it's `Status::kOkPartial`, in which case
|
||||
`Reader::Skip()` will be called again to skip more data).
|
||||
|
||||
Throwing an exception from the member functions is permitted, though if the
|
||||
exception will be caught and parsing resumed, then the reader should not
|
||||
advance its position (for methods that take a `Reader`) before the exception is
|
||||
thrown. When parsing is resumed, the same `Callback` method will be called
|
||||
again.
|
||||
|
||||
Users should derive from this class and override member methods as needed.
|
||||
*/
|
||||
class Callback {
|
||||
public:
|
||||
virtual ~Callback() = default;
|
||||
|
||||
/**
|
||||
Called when the parser starts a new element. This is called after the
|
||||
elements ID and size has been parsed, but before any of its body has been
|
||||
read (or validated).
|
||||
|
||||
Defaults to `Action::kRead` and returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element that has just been encountered.
|
||||
\param[out] action The action that should be taken when handling this
|
||||
element. Will not be null.
|
||||
*/
|
||||
virtual Status OnElementBegin(const ElementMetadata& metadata,
|
||||
Action* action);
|
||||
|
||||
/**
|
||||
Called when the parser encounters an unknown element.
|
||||
|
||||
Defaults to calling (and returning the result of) `Reader::Skip()`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param reader The reader that should be used to consume data. Will not be
|
||||
null.
|
||||
\param[in,out] bytes_remaining The number of remaining bytes that need to be
|
||||
consumed for the element. Will not be null.
|
||||
\return `Status::kOkCompleted` when the element has been fully consumed and
|
||||
`bytes_remaining` is now zero.
|
||||
*/
|
||||
virtual Status OnUnknownElement(const ElementMetadata& metadata,
|
||||
Reader* reader,
|
||||
std::uint64_t* bytes_remaining);
|
||||
|
||||
/**
|
||||
Called when the parser encounters an `Id::kEbml` element and it has been
|
||||
fully parsed.
|
||||
|
||||
Defaults to returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param ebml The parsed element.
|
||||
*/
|
||||
virtual Status OnEbml(const ElementMetadata& metadata, const Ebml& ebml);
|
||||
|
||||
/**
|
||||
Called when the parser encounters an Id::kVoid element.
|
||||
|
||||
Defaults to calling (and returning the result of) Reader::Skip.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param reader The reader that should be used to consume data. Will not be
|
||||
null.
|
||||
\param[in,out] bytes_remaining The number of remaining bytes that need to be
|
||||
consumed for the element. Will not be null.
|
||||
\return `Status::kOkCompleted` when the element has been fully consumed and
|
||||
`bytes_remaining` is now zero.
|
||||
*/
|
||||
virtual Status OnVoid(const ElementMetadata& metadata, Reader* reader,
|
||||
std::uint64_t* bytes_remaining);
|
||||
|
||||
/**
|
||||
Called when the parser starts an `Id::kSegment` element.
|
||||
|
||||
Defaults to `Action::kRead` and returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element that has just been encountered.
|
||||
\param[out] action The action that should be taken when handling this
|
||||
element. Will not be null.
|
||||
*/
|
||||
virtual Status OnSegmentBegin(const ElementMetadata& metadata,
|
||||
Action* action);
|
||||
|
||||
/**
|
||||
Called when the parser encounters an `Id::kSeek` element and it has been
|
||||
fully parsed.
|
||||
|
||||
Defaults to returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param seek The parsed element.
|
||||
*/
|
||||
virtual Status OnSeek(const ElementMetadata& metadata, const Seek& seek);
|
||||
|
||||
/**
|
||||
Called when the parser encounters an `Id::kInfo` element and it has been
|
||||
fully parsed.
|
||||
|
||||
Defaults to returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param info The parsed element.
|
||||
*/
|
||||
virtual Status OnInfo(const ElementMetadata& metadata, const Info& info);
|
||||
|
||||
/**
|
||||
Called when the parser starts an `Id::kCluster` element.
|
||||
|
||||
Because Cluster elements should start with a Timecode (and optionally
|
||||
PrevSize) child, this method is not invoked until a child BlockGroup or
|
||||
SimpleBlock element is encountered (or the Cluster ends if no such child
|
||||
exists).
|
||||
|
||||
Defaults to `Action::kRead` and returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param cluster The element, as it has currently been parsed.
|
||||
\param[out] action The action that should be taken when handling this
|
||||
element. Will not be null.
|
||||
*/
|
||||
virtual Status OnClusterBegin(const ElementMetadata& metadata,
|
||||
const Cluster& cluster, Action* action);
|
||||
|
||||
/**
|
||||
Called when the parser starts an `Id::kSimpleBlock` element.
|
||||
|
||||
Defaults to `Action::kRead` and returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param simple_block The parsed SimpleBlock header.
|
||||
\param[out] action The action that should be taken when handling this
|
||||
element. Will not be null.
|
||||
*/
|
||||
virtual Status OnSimpleBlockBegin(const ElementMetadata& metadata,
|
||||
const SimpleBlock& simple_block,
|
||||
Action* action);
|
||||
|
||||
/**
|
||||
Called when the parser finishes an `Id::kSimpleBlock` element.
|
||||
|
||||
Defaults to returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param simple_block The parsed SimpleBlock header.
|
||||
*/
|
||||
virtual Status OnSimpleBlockEnd(const ElementMetadata& metadata,
|
||||
const SimpleBlock& simple_block);
|
||||
|
||||
/**
|
||||
Called when the parser starts an `Id::kBlockGroup` element.
|
||||
|
||||
Defaults to `Action::kRead` and returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param[out] action The action that should be taken when handling this
|
||||
element. Will not be null.
|
||||
*/
|
||||
virtual Status OnBlockGroupBegin(const ElementMetadata& metadata,
|
||||
Action* action);
|
||||
|
||||
/**
|
||||
Called when the parser starts an `Id::kBlock` element.
|
||||
|
||||
Defaults to `Action::kRead` and returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param block The parsed Block header.
|
||||
\param[out] action The action that should be taken when handling this
|
||||
element. Will not be null.
|
||||
*/
|
||||
virtual Status OnBlockBegin(const ElementMetadata& metadata,
|
||||
const Block& block, Action* action);
|
||||
|
||||
/**
|
||||
Called when the parser finishes an `Id::Block` element.
|
||||
|
||||
Defaults to returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param block The parsed Block header.
|
||||
*/
|
||||
virtual Status OnBlockEnd(const ElementMetadata& metadata,
|
||||
const Block& block);
|
||||
|
||||
/**
|
||||
Called when the parser finishes an `Id::kBlockGroup` element.
|
||||
|
||||
Defaults to returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param block_group The parsed element.
|
||||
*/
|
||||
virtual Status OnBlockGroupEnd(const ElementMetadata& metadata,
|
||||
const BlockGroup& block_group);
|
||||
|
||||
/**
|
||||
Called when the parser encounters a frame within a `Id::kBlock` or
|
||||
`Id::kSimpleBlock` element.
|
||||
|
||||
Defaults to calling (and returning the result of) `Reader::Skip`.
|
||||
|
||||
\param metadata Metadata about the frame.
|
||||
\param reader The reader that should be used to consume data. Will not be
|
||||
null.
|
||||
\param[in,out] bytes_remaining The number of remaining bytes that need to be
|
||||
consumed for the frame. Will not be null.
|
||||
\return `Status::kOkCompleted` when the frame has been fully consumed and
|
||||
`bytes_remaining` is now zero.
|
||||
*/
|
||||
virtual Status OnFrame(const FrameMetadata& metadata, Reader* reader,
|
||||
std::uint64_t* bytes_remaining);
|
||||
|
||||
/**
|
||||
Called when the parser finishes an `Id::kCluster` element.
|
||||
|
||||
Defaults to returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param cluster The parsed element.
|
||||
*/
|
||||
virtual Status OnClusterEnd(const ElementMetadata& metadata,
|
||||
const Cluster& cluster);
|
||||
|
||||
/**
|
||||
Called when the parser starts an `Id::kTrackEntry` element.
|
||||
|
||||
Defaults to returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param track_entry The parsed element.
|
||||
*/
|
||||
virtual Status OnTrackEntry(const ElementMetadata& metadata,
|
||||
const TrackEntry& track_entry);
|
||||
|
||||
/**
|
||||
Called when the parser encounters an `Id::kCuePoint` element and it has been
|
||||
fully parsed.
|
||||
|
||||
Defaults to returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param cue_point The parsed element.
|
||||
*/
|
||||
virtual Status OnCuePoint(const ElementMetadata& metadata,
|
||||
const CuePoint& cue_point);
|
||||
|
||||
/**
|
||||
Called when the parser encounters an `Id::kEditionEntry` element and it has
|
||||
been fully parsed.
|
||||
|
||||
Defaults to returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param edition_entry The parsed element.
|
||||
*/
|
||||
virtual Status OnEditionEntry(const ElementMetadata& metadata,
|
||||
const EditionEntry& edition_entry);
|
||||
|
||||
/**
|
||||
Called when the parser encounters an `Id::kTag` element and it has been fully
|
||||
parsed.
|
||||
|
||||
Defaults to returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
\param tag The parsed element.
|
||||
*/
|
||||
virtual Status OnTag(const ElementMetadata& metadata, const Tag& tag);
|
||||
|
||||
/**
|
||||
Called when the parser finishes an `Id::kSegment` element.
|
||||
|
||||
Defaults to returning `Status::kOkCompleted`.
|
||||
|
||||
\param metadata Metadata about the element.
|
||||
*/
|
||||
virtual Status OnSegmentEnd(const ElementMetadata& metadata);
|
||||
|
||||
protected:
|
||||
/**
|
||||
Calls (and returns the result of) `Reader::Skip()`, skipping (up to) the
|
||||
requested number of bytes.
|
||||
|
||||
Unlike `Reader::Skip()`, this method may be called with `*bytes_remaining ==
|
||||
0`, which will result in `Status::kOkCompleted`. `Reader::Skip()` will be
|
||||
called multiple times if it returns `Status::kOkPartial` until it returns a
|
||||
different status (indicating the requested number of bytes has been fully
|
||||
skipped or some error occurred).
|
||||
|
||||
\param reader The reader that should be used to skip data. Must not be null.
|
||||
\param[in,out] bytes_remaining The number of remaining bytes that need to be
|
||||
skipped. Must not be null. May be zero.
|
||||
\return The result of `Reader::Skip()`.
|
||||
*/
|
||||
static Status Skip(Reader* reader, std::uint64_t* bytes_remaining);
|
||||
};
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // INCLUDE_WEBM_CALLBACK_H_
|
||||
+1781
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,208 @@
|
||||
// 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 INCLUDE_WEBM_ELEMENT_H_
|
||||
#define INCLUDE_WEBM_ELEMENT_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include "./id.h"
|
||||
|
||||
/**
|
||||
\file
|
||||
A wrapper around an object that represents a WebM element, including its parsed
|
||||
metadata.
|
||||
*/
|
||||
|
||||
namespace webm {
|
||||
|
||||
/**
|
||||
\addtogroup PUBLIC_API
|
||||
@{
|
||||
*/
|
||||
|
||||
/**
|
||||
A wrapper around an object that represents a WebM element.
|
||||
|
||||
Since some elements may be absent, this wrapper is used to indicate the
|
||||
presence (or lack thereof) of an element in a WebM document. If the element is
|
||||
encoded in the file and it has been parsed, `is_present()` will return true.
|
||||
Otherwise it will return false since the element was ommitted or skipped when
|
||||
parsing.
|
||||
*/
|
||||
template <typename T>
|
||||
class Element {
|
||||
public:
|
||||
/**
|
||||
Value-initializes the element's value and makes `is_present()` false.
|
||||
*/
|
||||
constexpr Element() = default;
|
||||
|
||||
/**
|
||||
Creates an element with the given value and makes `is_present()` false.
|
||||
|
||||
\param value The value of the element.
|
||||
*/
|
||||
explicit constexpr Element(const T& value) : value_(value) {}
|
||||
|
||||
/**
|
||||
Creates an element with the given value and makes `is_present()` false.
|
||||
|
||||
\param value The value of the element.
|
||||
*/
|
||||
explicit constexpr Element(T&& value) : value_(std::move(value)) {}
|
||||
|
||||
/**
|
||||
Creates an element with the given value and presence state.
|
||||
|
||||
\param value The value of the element.
|
||||
\param is_present True if the element is present, false if it is absent.
|
||||
*/
|
||||
constexpr Element(const T& value, bool is_present)
|
||||
: value_(value), is_present_(is_present) {}
|
||||
|
||||
/**
|
||||
Creates an element with the given value and presence state.
|
||||
|
||||
\param value The value of the element.
|
||||
\param is_present True if the element is present, false if it is absent.
|
||||
*/
|
||||
constexpr Element(T&& value, bool is_present)
|
||||
: value_(std::move(value)), is_present_(is_present) {}
|
||||
|
||||
constexpr Element(const Element<T>& other) = default;
|
||||
constexpr Element(Element<T>&& other) = default;
|
||||
|
||||
~Element() = default;
|
||||
|
||||
Element<T>& operator=(const Element<T>& other) = default;
|
||||
Element<T>& operator=(Element<T>&& other) = default;
|
||||
|
||||
/**
|
||||
Sets the element's value and state.
|
||||
|
||||
\param value The new value for the element.
|
||||
\param is_present The new presence state for the element.
|
||||
*/
|
||||
void Set(const T& value, bool is_present) {
|
||||
value_ = value;
|
||||
is_present_ = is_present;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the element's value and state.
|
||||
|
||||
\param value The new value for the element.
|
||||
\param is_present The new presence state for the element.
|
||||
*/
|
||||
void Set(T&& value, bool is_present) {
|
||||
value_ = std::move(value);
|
||||
is_present_ = is_present;
|
||||
}
|
||||
|
||||
/**
|
||||
Gets the element's value.
|
||||
*/
|
||||
constexpr const T& value() const { return value_; }
|
||||
|
||||
/**
|
||||
Gets a mutuable pointer to the element's value (will never be null).
|
||||
*/
|
||||
T* mutable_value() { return &value_; }
|
||||
|
||||
/**
|
||||
Returns true if the element is present, false otherwise.
|
||||
*/
|
||||
constexpr bool is_present() const { return is_present_; }
|
||||
|
||||
bool operator==(const Element<T>& other) const {
|
||||
return is_present_ == other.is_present_ && value_ == other.value_;
|
||||
}
|
||||
|
||||
private:
|
||||
T value_{};
|
||||
bool is_present_ = false;
|
||||
};
|
||||
|
||||
/**
|
||||
Metadata for WebM elements that are encountered when parsing.
|
||||
*/
|
||||
struct ElementMetadata {
|
||||
/**
|
||||
The EBML ID of the element.
|
||||
*/
|
||||
Id id;
|
||||
|
||||
/**
|
||||
The number of bytes that were used to encode the EBML ID and element size.
|
||||
|
||||
If the size of the header is unknown (which is only the case if a seek was
|
||||
performed to the middle of an element, so its header was not parsed), this
|
||||
will be the value `kUnknownHeaderSize`.
|
||||
*/
|
||||
std::uint32_t header_size;
|
||||
|
||||
/**
|
||||
The size of the element.
|
||||
|
||||
This is number of bytes in the element's body, which excludes the header
|
||||
bytes.
|
||||
|
||||
If the size of the element's body is unknown, this will be the value
|
||||
`kUnknownElementSize`.
|
||||
*/
|
||||
std::uint64_t size;
|
||||
|
||||
/**
|
||||
The absolute byte position of the element, starting at the first byte of the
|
||||
element's header.
|
||||
|
||||
If the position of the element is unknown (which is only the case if a seek
|
||||
was performed to the middle of an element), this will be the value
|
||||
`kUnknownElementPosition`.
|
||||
*/
|
||||
std::uint64_t position;
|
||||
|
||||
/**
|
||||
Returns true if every member within the two objects are equal.
|
||||
*/
|
||||
bool operator==(const ElementMetadata& other) const {
|
||||
return id == other.id && header_size == other.header_size &&
|
||||
size == other.size && position == other.position;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
A special value for `ElementMetadata::header_size` indicating the header size
|
||||
is not known.
|
||||
*/
|
||||
constexpr std::uint64_t kUnknownHeaderSize =
|
||||
std::numeric_limits<std::uint32_t>::max();
|
||||
|
||||
/**
|
||||
A special value for `ElementMetadata::size` indicating the element's size is
|
||||
not known.
|
||||
*/
|
||||
constexpr std::uint64_t kUnknownElementSize =
|
||||
std::numeric_limits<std::uint64_t>::max();
|
||||
|
||||
/**
|
||||
A special value for `ElementMetadata::position` indicating the element's
|
||||
position is not known.
|
||||
*/
|
||||
constexpr std::uint64_t kUnknownElementPosition =
|
||||
std::numeric_limits<std::uint64_t>::max();
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // INCLUDE_WEBM_ELEMENT_H_
|
||||
@@ -0,0 +1,103 @@
|
||||
// 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 INCLUDE_WEBM_FILE_READER_H_
|
||||
#define INCLUDE_WEBM_FILE_READER_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
|
||||
#include "./reader.h"
|
||||
#include "./status.h"
|
||||
|
||||
/**
|
||||
\file
|
||||
A `Reader` implementation that reads from a `FILE*`.
|
||||
*/
|
||||
|
||||
namespace webm {
|
||||
|
||||
/**
|
||||
A `Reader` implementation that can read from `FILE*` resources.
|
||||
*/
|
||||
class FileReader : public Reader {
|
||||
public:
|
||||
/**
|
||||
Constructs a new, empty reader.
|
||||
*/
|
||||
FileReader() = default;
|
||||
|
||||
/**
|
||||
Constructs a new reader, using the provided file as the data source.
|
||||
|
||||
Ownership of the file is taken, and `std::fclose()` will be called when the
|
||||
object is destroyed.
|
||||
|
||||
\param file The file to use as a data source. Must not be null. The file will
|
||||
be closed (via `std::fclose()`) when the `FileReader`'s destructor runs.
|
||||
*/
|
||||
explicit FileReader(FILE* file);
|
||||
|
||||
/**
|
||||
Constructs a new reader by moving the provided reader into the new reader.
|
||||
|
||||
\param other The source reader to move. After moving, it will be reset to an
|
||||
empty stream.
|
||||
*/
|
||||
FileReader(FileReader&& other);
|
||||
|
||||
/**
|
||||
Moves the provided reader into this reader.
|
||||
|
||||
\param other The source reader to move. After moving, it will be reset to an
|
||||
empty stream. May be equal to `*this`, in which case this is a no-op.
|
||||
\return `*this`.
|
||||
*/
|
||||
FileReader& operator=(FileReader&& other);
|
||||
|
||||
Status Read(std::size_t num_to_read, std::uint8_t* buffer,
|
||||
std::uint64_t* num_actually_read) override;
|
||||
|
||||
Status Skip(std::uint64_t num_to_skip,
|
||||
std::uint64_t* num_actually_skipped) override;
|
||||
|
||||
/**
|
||||
Moves the reader to a new absolute byte position in the file.
|
||||
|
||||
It is required to call DidSeek() on the parser after successfully seeking.
|
||||
Seeking will only work on actual files, not stdin or pipes.
|
||||
|
||||
\param seek_position The new absolute byte position in the file.
|
||||
\return `Status::kOkCompleted` if reader position is now `seek_position`.
|
||||
`Status::kSeekFailed` if the reader was unable to seek to `seek_position`
|
||||
such as when the file is stdin.
|
||||
*/
|
||||
Status Seek(std::uint64_t seek_position);
|
||||
|
||||
std::uint64_t Position() const override;
|
||||
|
||||
private:
|
||||
struct FileCloseFunctor {
|
||||
void operator()(FILE* file) const {
|
||||
if (file)
|
||||
std::fclose(file);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<FILE, FileCloseFunctor> file_;
|
||||
|
||||
// We can't rely on ftell() for the position (since it only returns long, and
|
||||
// doesn't work on things like pipes); we need to manually track the reading
|
||||
// position.
|
||||
std::uint64_t position_ = 0;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // INCLUDE_WEBM_FILE_READER_H_
|
||||
+1085
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,99 @@
|
||||
// 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 INCLUDE_WEBM_ISTREAM_READER_H_
|
||||
#define INCLUDE_WEBM_ISTREAM_READER_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "./reader.h"
|
||||
#include "./status.h"
|
||||
|
||||
/**
|
||||
\file
|
||||
A `Reader` implementation that reads from a `std::istream`.
|
||||
*/
|
||||
|
||||
namespace webm {
|
||||
|
||||
/**
|
||||
A `Reader` implementation that can read from `std::istream`-based resources.
|
||||
*/
|
||||
class IstreamReader : public Reader {
|
||||
public:
|
||||
/**
|
||||
Constructs a new, empty reader.
|
||||
*/
|
||||
IstreamReader() = default;
|
||||
|
||||
/**
|
||||
Constructs a new reader, using the provided `std::istream` as the data
|
||||
source.
|
||||
|
||||
Ownership of the stream is taken, and it will be moved into a new internal
|
||||
instance.
|
||||
|
||||
\param istream The stream to use as a data source. Must be an rvalue
|
||||
reference derived from `std::istream`.
|
||||
*/
|
||||
template <typename T>
|
||||
explicit IstreamReader(T&& istream) : istream_(new T(std::move(istream))) {}
|
||||
|
||||
/**
|
||||
Constructs a new reader by moving the provided reader into the new reader.
|
||||
|
||||
\param other The source reader to move. After moving, it will be reset to an
|
||||
empty stream.
|
||||
*/
|
||||
IstreamReader(IstreamReader&& other);
|
||||
|
||||
/**
|
||||
Moves the provided reader into this reader.
|
||||
|
||||
\param other The source reader to move. After moving, it will be reset to an
|
||||
empty stream. May be equal to `*this`, in which case this is a no-op.
|
||||
\return `*this`.
|
||||
*/
|
||||
IstreamReader& operator=(IstreamReader&& other);
|
||||
|
||||
Status Read(std::size_t num_to_read, std::uint8_t* buffer,
|
||||
std::uint64_t* num_actually_read) override;
|
||||
|
||||
Status Skip(std::uint64_t num_to_skip,
|
||||
std::uint64_t* num_actually_skipped) override;
|
||||
|
||||
std::uint64_t Position() const override;
|
||||
|
||||
/**
|
||||
Constructs a new reader and its data source in place.
|
||||
|
||||
`T` must be derived from `std::istream` and constructible from the provided
|
||||
arguments.
|
||||
|
||||
\param args Arguments that will be forwarded to the `T`'s constructor.
|
||||
\return A new `IstreamReader` backed by the underlying data source equivalent
|
||||
to `T(std::forward<Args>(args)...`.
|
||||
*/
|
||||
template <typename T, typename... Args>
|
||||
static IstreamReader Emplace(Args&&... args) {
|
||||
IstreamReader reader;
|
||||
reader.istream_.reset(new T(std::forward<Args>(args)...));
|
||||
return reader;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<std::istream> istream_;
|
||||
std::uint64_t position_ = 0;
|
||||
};
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // INCLUDE_WEBM_ISTREAM_READER_H_
|
||||
@@ -0,0 +1,94 @@
|
||||
// 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 INCLUDE_WEBM_READER_H_
|
||||
#define INCLUDE_WEBM_READER_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "./status.h"
|
||||
|
||||
/**
|
||||
\file
|
||||
An interface that acts as a data source for the parser to read from.
|
||||
*/
|
||||
|
||||
namespace webm {
|
||||
|
||||
/**
|
||||
\addtogroup PUBLIC_API
|
||||
@{
|
||||
*/
|
||||
|
||||
/**
|
||||
A generic interface for reading from a data source.
|
||||
|
||||
Throwing an exception from the member functions is permitted, though if the
|
||||
exception will be caught and parsing resumed, then the reader should not
|
||||
advance its position before throwing the exception.
|
||||
*/
|
||||
class Reader {
|
||||
public:
|
||||
virtual ~Reader() = default;
|
||||
|
||||
/**
|
||||
Reads data from the source and advances the reader's position by the number
|
||||
of bytes read.
|
||||
|
||||
Short reads are permitted, as is reading no data.
|
||||
|
||||
\param num_to_read The number of bytes that should be read. Must not be 0.
|
||||
\param buffer The buffer to store the read bytes. Must be large enough to
|
||||
store at least `num_to_read` bytes. Must not be null.
|
||||
\param[out] num_actually_read The number of bytes that were actually read is
|
||||
stored in this integer. Must not be null.
|
||||
\return `Status::kOkCompleted` if `num_to_read` bytes were read.
|
||||
`Status::kOkPartial` if the number of bytes read is > 0 and < `num_to_read`.
|
||||
If no bytes are read, then some status other than `Status::kOkCompleted` and
|
||||
`Status::kOkPartial` must be returned and `num_actually_read` must be set to
|
||||
0.
|
||||
*/
|
||||
virtual Status Read(std::size_t num_to_read, std::uint8_t* buffer,
|
||||
std::uint64_t* num_actually_read) = 0;
|
||||
|
||||
/**
|
||||
Skips data from the source and advances the reader's position by the number
|
||||
of bytes skipped.
|
||||
|
||||
Short skips are permitted, as is skipping no data. This is similar to the
|
||||
`Read()` method, but does not store data in an output buffer.
|
||||
|
||||
\param num_to_skip The number of bytes that should be skipped. Must not be 0.
|
||||
\param[out] num_actually_skipped The number of bytes that were actually
|
||||
skipped is stored in this integer. Must not be null.
|
||||
\return `Status::kOkCompleted` if `num_to_skip` bytes were skipped.
|
||||
`Status::kOkPartial` if the number of bytes skipped is > 0 and <
|
||||
`num_to_skip`. If no bytes are skipped, then some status other than
|
||||
`Status::kOkCompleted` and `Status::kOkPartial` must be returned and
|
||||
`num_actually_skipped` must be set to 0.
|
||||
*/
|
||||
virtual Status Skip(std::uint64_t num_to_skip,
|
||||
std::uint64_t* num_actually_skipped) = 0;
|
||||
|
||||
/**
|
||||
Gets the Reader's current absolute byte position in the stream.
|
||||
|
||||
Implementations don't necessarily need to start from 0 (which might be the
|
||||
case if parsing is starting in the middle of a data source). The value
|
||||
`kUnknownElementPosition` must not be returned.
|
||||
*/
|
||||
virtual std::uint64_t Position() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // INCLUDE_WEBM_READER_H_
|
||||
@@ -0,0 +1,166 @@
|
||||
// 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 INCLUDE_WEBM_STATUS_H_
|
||||
#define INCLUDE_WEBM_STATUS_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
\file
|
||||
Status information that represents success, failure, etc. for operations
|
||||
throughout the API.
|
||||
*/
|
||||
|
||||
namespace webm {
|
||||
|
||||
/**
|
||||
\addtogroup PUBLIC_API
|
||||
@{
|
||||
*/
|
||||
|
||||
/**
|
||||
An object used to represent the resulting status of various operations,
|
||||
indicating success, failure, or some other result.
|
||||
*/
|
||||
struct Status {
|
||||
/**
|
||||
A list of generic status codes used by the parser. Users are encouraged to
|
||||
reuse these values as needed in the derivations of `Callback`. These values
|
||||
will always be <= 0.
|
||||
*/
|
||||
enum Code : std::int32_t {
|
||||
// General status codes. Range: 0 to -1024.
|
||||
/**
|
||||
The operation successfully completed.
|
||||
*/
|
||||
kOkCompleted = 0,
|
||||
|
||||
/**
|
||||
The operation was successful but only partially completed (for example, a
|
||||
read that resulted in fewer bytes than requested).
|
||||
*/
|
||||
kOkPartial = -1,
|
||||
|
||||
/**
|
||||
The operation would block, and should be tried again later.
|
||||
*/
|
||||
kWouldBlock = -2,
|
||||
|
||||
/**
|
||||
More data was requested but the file has ended.
|
||||
*/
|
||||
kEndOfFile = -3,
|
||||
|
||||
/**
|
||||
The reader was unable to seek to the requested location.
|
||||
*/
|
||||
kSeekFailed = -4,
|
||||
|
||||
// Parsing errors. Range: -1025 to -2048.
|
||||
/**
|
||||
An element's ID is malformed.
|
||||
*/
|
||||
kInvalidElementId = -1025,
|
||||
|
||||
/**
|
||||
An element's size is malformed.
|
||||
*/
|
||||
kInvalidElementSize = -1026,
|
||||
|
||||
/**
|
||||
An unknown element has unknown size.
|
||||
*/
|
||||
kIndefiniteUnknownElement = -1027,
|
||||
|
||||
/**
|
||||
A child element overflowed the parent element's bounds.
|
||||
*/
|
||||
kElementOverflow = -1028,
|
||||
|
||||
/**
|
||||
An element's size exceeds the system's memory limits.
|
||||
*/
|
||||
kNotEnoughMemory = -1029,
|
||||
|
||||
/**
|
||||
An element's value is illegal/malformed.
|
||||
*/
|
||||
kInvalidElementValue = -1030,
|
||||
|
||||
/**
|
||||
A recursive element was so deeply nested that exceeded the parser's limit.
|
||||
*/
|
||||
kExceededRecursionDepthLimit = -1031,
|
||||
|
||||
// The following codes are internal-only and should not be used by users.
|
||||
// Additionally, these codes should never be returned to the user; doing so
|
||||
// is considered a bug.
|
||||
/**
|
||||
\internal Parsing should switch from reading to skipping elements.
|
||||
*/
|
||||
kSwitchToSkip = INT32_MIN,
|
||||
};
|
||||
|
||||
/**
|
||||
Status codes <= 0 are reserved by the parsing library. User error codes
|
||||
should be positive (> 0). Users are encouraged to use codes from the `Code`
|
||||
enum, but may use a positive error code if some application-specific error is
|
||||
encountered.
|
||||
*/
|
||||
std::int32_t code;
|
||||
|
||||
Status() = default;
|
||||
Status(const Status&) = default;
|
||||
Status(Status&&) = default;
|
||||
Status& operator=(const Status&) = default;
|
||||
Status& operator=(Status&&) = default;
|
||||
|
||||
/**
|
||||
Creates a new `Status` object with the given status code.
|
||||
|
||||
\param code The status code which will be used to set the `code` member.
|
||||
*/
|
||||
constexpr explicit Status(Code code) : code(code) {}
|
||||
|
||||
/**
|
||||
Creates a new `Status` object with the given status code.
|
||||
|
||||
\param code The status code which will be used to set the `code` member.
|
||||
*/
|
||||
constexpr explicit Status(std::int32_t code) : code(code) {}
|
||||
|
||||
/**
|
||||
Returns true if the status code is either `kOkCompleted` or `kOkPartial`.
|
||||
Provided for convenience.
|
||||
*/
|
||||
constexpr bool ok() const {
|
||||
return code == kOkCompleted || code == kOkPartial;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns true if the status code is `kOkCompleted`. Provided for convenience.
|
||||
*/
|
||||
constexpr bool completed_ok() const { return code == kOkCompleted; }
|
||||
|
||||
/**
|
||||
Returns true if the status is considered a parsing error. Parsing errors
|
||||
represent unrecoverable errors due to malformed data. Only status codes in
|
||||
the range -2048 to -1025 (inclusive) are considered parsing errors.
|
||||
*/
|
||||
constexpr bool is_parsing_error() const {
|
||||
return -2048 <= code && code <= -1025;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // INCLUDE_WEBM_STATUS_H_
|
||||
@@ -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.
|
||||
#ifndef INCLUDE_WEBM_WEBM_PARSER_H_
|
||||
#define INCLUDE_WEBM_WEBM_PARSER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "./callback.h"
|
||||
#include "./reader.h"
|
||||
#include "./status.h"
|
||||
|
||||
/**
|
||||
\file
|
||||
The main parser class for parsing WebM files.
|
||||
*/
|
||||
|
||||
namespace webm {
|
||||
|
||||
/**
|
||||
\defgroup PUBLIC_API Public API
|
||||
Public types and header files intended for use by users.
|
||||
*/
|
||||
|
||||
/**
|
||||
\addtogroup PUBLIC_API
|
||||
@{
|
||||
*/
|
||||
|
||||
/**
|
||||
Incrementally parses a WebM document encoded in a byte stream.
|
||||
|
||||
It is expected that the parsing will begin at the start of the WebM
|
||||
file/document. Otherwise, the `DidSeek()` method should be used to inform the
|
||||
parser that reading may not necessarily begin at the beginning of the document
|
||||
and the parser should be prepared to handle data at an arbitrary point in the
|
||||
document.
|
||||
|
||||
WebM files are mostly a subset of Matroska, with a few small modifications.
|
||||
Matroska is a format built on top of EBML.
|
||||
*/
|
||||
// Spec references:
|
||||
// http://www.webmproject.org/docs/container/
|
||||
// https://matroska.org/technical/specs/index.html
|
||||
// https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown
|
||||
class WebmParser {
|
||||
public:
|
||||
/**
|
||||
Constructs the object and prepares it for parsing.
|
||||
*/
|
||||
WebmParser();
|
||||
|
||||
/*
|
||||
Cleans up the parser. No further cleanup is required from the user.
|
||||
*/
|
||||
~WebmParser();
|
||||
|
||||
// Non-copyable and non-movable.
|
||||
WebmParser(const WebmParser&) = delete;
|
||||
WebmParser& operator=(const WebmParser&) = delete;
|
||||
|
||||
/**
|
||||
Resets the parser after a seek was performed on the reader, which prepares
|
||||
the parser for starting at an arbitrary point in the stream.
|
||||
|
||||
The seek must be to the start of an element (that is, it can't be any random
|
||||
byte) or parsing will fail.
|
||||
*/
|
||||
void DidSeek();
|
||||
|
||||
/**
|
||||
Feeds data into the parser from the provided reader.
|
||||
|
||||
If a parsing error code has been returned (which indicates a malformed
|
||||
document), calling Feed() again will just result in the same error; parsing
|
||||
has already failed at that point and further progress can't be made.
|
||||
|
||||
\param callback The callback which receives parsing events. No internal
|
||||
references are maintained to `callback`, so it may be modified or freed after
|
||||
this method returns.
|
||||
\param reader The reader the parser will use to request data. No internal
|
||||
references are maintained to `reader`, so it may be modified or freed after
|
||||
this method returns.
|
||||
\return `Status::kOkCompleted` when parsing completes successfully.
|
||||
`Status::kOkPartial` or another non-parsing error code (see status.h for
|
||||
error codes classified as parsing errors) will be returned if parsing has
|
||||
only partially completed, and Feed() should be called again to resume
|
||||
parsing.
|
||||
*/
|
||||
Status Feed(Callback* callback, Reader* reader);
|
||||
|
||||
/**
|
||||
Swaps this parser and the provided parser.
|
||||
|
||||
\param other The parser to swap values/states with. Must not be null.
|
||||
*/
|
||||
void Swap(WebmParser* other);
|
||||
|
||||
private:
|
||||
// This header can only rely on sources in the public API.
|
||||
class DocumentParser;
|
||||
|
||||
// The internal implementation of the parser.
|
||||
std::unique_ptr<DocumentParser> parser_;
|
||||
|
||||
// The status of the parser, used to prevent further progress if an
|
||||
// unrecoverable parsing error has already been encountered.
|
||||
Status parsing_status_ = Status(Status::kOkPartial);
|
||||
};
|
||||
|
||||
/**
|
||||
Swaps the two parsers.
|
||||
|
||||
This is provided so code can use argument dependent lookup in an idiomatic way
|
||||
when swapping (especially since `std::swap` won't work since the parser is
|
||||
non-movable).
|
||||
|
||||
\param left The first parser to swap.
|
||||
\param right The second parser to swap.
|
||||
*/
|
||||
void swap(WebmParser& left, WebmParser& right);
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
} // namespace webm
|
||||
|
||||
#endif // INCLUDE_WEBM_WEBM_PARSER_H_
|
||||
Reference in New Issue
Block a user