First draft doxygen documentation for media/mp4.
Change-Id: I13a28245168724a237a4653e298d6b835c24f17b
This commit is contained in:
parent
6046cde3d8
commit
cca3767c25
|
@ -15,50 +15,56 @@ class BitReader;
|
||||||
|
|
||||||
namespace mp4 {
|
namespace mp4 {
|
||||||
|
|
||||||
// This class parses the AAC information from decoder specific information
|
/// This class parses the AAC information from decoder specific information
|
||||||
// embedded in the esds box in an ISO BMFF file.
|
/// embedded in the @b esds box in an ISO BMFF file.
|
||||||
// Please refer to ISO 14496 Part 3 Table 1.13 - Syntax of AudioSpecificConfig
|
/// Please refer to ISO 14496 Part 3 Table 1.13 - Syntax of AudioSpecificConfig
|
||||||
// for more details.
|
/// for more details.
|
||||||
class AACAudioSpecificConfig {
|
class AACAudioSpecificConfig {
|
||||||
public:
|
public:
|
||||||
AACAudioSpecificConfig();
|
AACAudioSpecificConfig();
|
||||||
~AACAudioSpecificConfig();
|
~AACAudioSpecificConfig();
|
||||||
|
|
||||||
// Parse the AAC config from the raw binary data embedded in esds box.
|
/// Parse the AAC config from decoder specific information embedded in an @b
|
||||||
// The function will parse the data and get the ElementaryStreamDescriptor,
|
/// esds box. The function will parse the data and get the
|
||||||
// then it will parse the ElementaryStreamDescriptor to get audio stream
|
/// ElementaryStreamDescriptor, then it will parse the
|
||||||
// configurations.
|
/// ElementaryStreamDescriptor to get audio stream configurations.
|
||||||
|
/// @param data contains decoder specific information from an @b esds box.
|
||||||
|
/// @return true if successful, false otherwise.
|
||||||
bool Parse(const std::vector<uint8>& data);
|
bool Parse(const std::vector<uint8>& data);
|
||||||
|
|
||||||
// Get the output sample rate for the AAC stream.
|
/// @param sbr_in_mimetype indicates whether SBR mode is specified in the
|
||||||
// |sbr_in_mimetype| should be set to true if the SBR mode is
|
/// mimetype, i.e. codecs parameter contains mp4a.40.5.
|
||||||
// signalled in the mimetype. (ie mp4a.40.5 in the codecs parameter).
|
/// @return Output sample rate for the AAC stream.
|
||||||
uint32 GetOutputSamplesPerSecond(bool sbr_in_mimetype) const;
|
uint32 GetOutputSamplesPerSecond(bool sbr_in_mimetype) const;
|
||||||
|
|
||||||
// Get number of channels for the AAC stream.
|
/// @param sbr_in_mimetype indicates whether SBR mode is specified in the
|
||||||
// |sbr_in_mimetype| should be set to true if the SBR mode is
|
/// mimetype, i.e. codecs parameter contains mp4a.40.5.
|
||||||
// signalled in the mimetype. (ie mp4a.40.5 in the codecs parameter).
|
/// @return Number of channels for the AAC stream.
|
||||||
uint8 GetNumChannels(bool sbr_in_mimetype) const;
|
uint8 GetNumChannels(bool sbr_in_mimetype) const;
|
||||||
|
|
||||||
// This function converts a raw AAC frame into an AAC frame with an ADTS
|
/// Convert a raw AAC frame into an AAC frame with an ADTS header.
|
||||||
// header. On success, the function returns true and stores the converted data
|
/// @param[in,out] buffer contains the raw AAC frame on input, and the
|
||||||
// in the buffer. The function returns false on failure and leaves the buffer
|
/// converted frame on output if successful; it is untouched
|
||||||
// unchanged.
|
/// on failure.
|
||||||
|
/// @return true on success, false otherwise.
|
||||||
bool ConvertToADTS(std::vector<uint8>* buffer) const;
|
bool ConvertToADTS(std::vector<uint8>* buffer) const;
|
||||||
|
|
||||||
|
/// @return The audio object type for this AAC config.
|
||||||
uint8 audio_object_type() const {
|
uint8 audio_object_type() const {
|
||||||
return audio_object_type_;
|
return audio_object_type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @return The sampling frequency for this AAC config.
|
||||||
uint32 frequency() const {
|
uint32 frequency() const {
|
||||||
return frequency_;
|
return frequency_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @return Number of channels for this AAC config.
|
||||||
uint8 num_channels() const {
|
uint8 num_channels() const {
|
||||||
return num_channels_;
|
return num_channels_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size in bytes of the ADTS header added by ConvertEsdsToADTS().
|
/// Size in bytes of the ADTS header added by ConvertEsdsToADTS().
|
||||||
static const size_t kADTSHeaderSize = 7;
|
static const size_t kADTSHeaderSize = 7;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -20,32 +20,39 @@ namespace mp4 {
|
||||||
class BoxBuffer;
|
class BoxBuffer;
|
||||||
class BoxReader;
|
class BoxReader;
|
||||||
|
|
||||||
// Defines Box and FullBox, the two base ISO BMFF box objects as defined in
|
/// Defines the base ISO BMFF box objects as defined in ISO 14496-12:2012
|
||||||
// ISO 14496-12:2012 ISO BMFF section 4.2. All ISO BMFF compatible boxes
|
/// ISO BMFF section 4.2. All ISO BMFF compatible boxes inherit from either
|
||||||
// inherits either Box or FullBox.
|
/// Box or FullBox.
|
||||||
struct Box {
|
struct Box {
|
||||||
public:
|
public:
|
||||||
Box();
|
Box();
|
||||||
virtual ~Box();
|
virtual ~Box();
|
||||||
|
/// Parse the mp4 box.
|
||||||
|
/// @param reader points to a BoxReader object which parses the box.
|
||||||
bool Parse(BoxReader* reader);
|
bool Parse(BoxReader* reader);
|
||||||
// Write the box to buffer.
|
/// Write the box to buffer.
|
||||||
// The function calls ComputeSize internally to compute box size.
|
/// This function calls ComputeSize internally to compute box size.
|
||||||
|
/// @param writer points to a BufferWriter object which wraps the buffer for
|
||||||
|
/// writing.
|
||||||
void Write(BufferWriter* writer);
|
void Write(BufferWriter* writer);
|
||||||
// Computer box size.
|
/// Compute the size of this box.
|
||||||
// The calculated size will be saved in |atom_size| for consumption later.
|
/// The calculated size will be saved in |atom_size| for later consumption.
|
||||||
virtual uint32 ComputeSize() = 0;
|
virtual uint32 ComputeSize() = 0;
|
||||||
virtual FourCC BoxType() const = 0;
|
virtual FourCC BoxType() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class BoxBuffer;
|
friend class BoxBuffer;
|
||||||
// Read or write the mp4 box through BoxBuffer.
|
/// Read/write the mp4 box from/to BoxBuffer.
|
||||||
virtual bool ReadWrite(BoxBuffer* buffer);
|
virtual bool ReadWrite(BoxBuffer* buffer);
|
||||||
|
|
||||||
// We don't support 64-bit atom size. 32-bit should be large enough for our
|
/// We don't support 64-bit atom sizes. 32-bit should be large enough for our
|
||||||
// current needs.
|
/// current needs.
|
||||||
uint32 atom_size;
|
uint32 atom_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Defines FullBox, the other base ISO BMFF box objects as defined in
|
||||||
|
/// ISO 14496-12:2012 ISO BMFF section 4.2. All ISO BMFF compatible boxes
|
||||||
|
/// inherit from either Box or FullBox.
|
||||||
struct FullBox : Box {
|
struct FullBox : Box {
|
||||||
public:
|
public:
|
||||||
FullBox();
|
FullBox();
|
||||||
|
|
|
@ -15,45 +15,47 @@
|
||||||
namespace media {
|
namespace media {
|
||||||
namespace mp4 {
|
namespace mp4 {
|
||||||
|
|
||||||
// Defines a wrapper for mp4 box reading/writing, which is symmetric in most
|
/// Class for MP4 box I/O. Box I/O is symmetric and exclusive, so we can define
|
||||||
// cases, i.e. we can use one single routine for the reading and writing.
|
/// a single method to do either reading or writing box objects.
|
||||||
// BoxBuffer wraps either BoxReader for reading or BufferWriter for writing.
|
/// BoxBuffer wraps either BoxReader for reading or BufferWriter for writing.
|
||||||
// Thus it is capable of doing either reading or writing, but not both.
|
/// Thus it is capable of doing either reading or writing, but not both.
|
||||||
class BoxBuffer {
|
class BoxBuffer {
|
||||||
public:
|
public:
|
||||||
// Creates a "reader" version of the BoxBuffer.
|
/// Create a reader version of the BoxBuffer.
|
||||||
// Caller retains |reader| ownership. |reader| should not be NULL.
|
/// @param reader should not be NULL.
|
||||||
explicit BoxBuffer(BoxReader* reader) : reader_(reader), writer_(NULL) {
|
explicit BoxBuffer(BoxReader* reader) : reader_(reader), writer_(NULL) {
|
||||||
DCHECK(reader);
|
DCHECK(reader);
|
||||||
}
|
}
|
||||||
// Creates a "writer" version of the BoxBuffer.
|
/// Create a writer version of the BoxBuffer.
|
||||||
// Caller retains |writer| ownership. |writer| should not be NULL.
|
/// @param writer should not be NULL.
|
||||||
explicit BoxBuffer(BufferWriter* writer) : reader_(NULL), writer_(writer) {
|
explicit BoxBuffer(BufferWriter* writer) : reader_(NULL), writer_(writer) {
|
||||||
DCHECK(writer);
|
DCHECK(writer);
|
||||||
}
|
}
|
||||||
~BoxBuffer() {}
|
~BoxBuffer() {}
|
||||||
|
|
||||||
// Reading or writing?
|
/// @return true for reader, false for writer.
|
||||||
bool Reading() const { return reader_ != NULL; }
|
bool Reading() const { return reader_ != NULL; }
|
||||||
|
|
||||||
// Returns current read/write position. In read mode, this is the current
|
/// @return Current read/write position. In read mode, this is the current
|
||||||
// read position. In write mode, it is the same as Size().
|
/// read position. In write mode, it is the same as Size().
|
||||||
size_t Pos() const {
|
size_t Pos() const {
|
||||||
if (reader_)
|
if (reader_)
|
||||||
return reader_->pos();
|
return reader_->pos();
|
||||||
return writer_->Size();
|
return writer_->Size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns total buffer size.In read mode, it includes data that has already
|
/// @return Total buffer size. In read mode, it includes data that has already
|
||||||
// been read or skipped, and will not change. In write mode, it includes all
|
/// been read or skipped, and will not change. In write mode, it
|
||||||
// data that has been written, and will change as data is written.
|
/// includes all data that has been written, and will change as more
|
||||||
|
/// data is written.
|
||||||
size_t Size() const {
|
size_t Size() const {
|
||||||
if (reader_)
|
if (reader_)
|
||||||
return reader_->size();
|
return reader_->size();
|
||||||
return writer_->Size();
|
return writer_->Size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read/write integers of various size and unsigned/signed.
|
/// @name Read/write integers of various sizes and signedness.
|
||||||
|
/// @{
|
||||||
bool ReadWriteUInt8(uint8* v) {
|
bool ReadWriteUInt8(uint8* v) {
|
||||||
if (reader_)
|
if (reader_)
|
||||||
return reader_->Read1(v);
|
return reader_->Read1(v);
|
||||||
|
@ -96,9 +98,11 @@ class BoxBuffer {
|
||||||
writer_->AppendInt(*v);
|
writer_->AppendInt(*v);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
/// @}
|
||||||
|
|
||||||
// Read/write the least significant |num_bytes| of |v| from/to buffer.
|
/// Read/write the least significant |num_bytes| of |v| from/to the buffer.
|
||||||
// |num_bytes| should not be larger than sizeof(v), i.e. 8.
|
/// @param num_bytes should not be larger than sizeof(v), i.e. 8.
|
||||||
|
/// @return true on success, false otherwise.
|
||||||
bool ReadWriteUInt64NBytes(uint64* v, size_t num_bytes) {
|
bool ReadWriteUInt64NBytes(uint64* v, size_t num_bytes) {
|
||||||
if (reader_)
|
if (reader_)
|
||||||
return reader_->ReadNBytesInto8(v, num_bytes);
|
return reader_->ReadNBytesInto8(v, num_bytes);
|
||||||
|
@ -125,7 +129,8 @@ class BoxBuffer {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare child boxes for read/write.
|
/// Prepare child boxes for reading/writing.
|
||||||
|
/// @return true on success, false otherwise.
|
||||||
bool PrepareChildren() {
|
bool PrepareChildren() {
|
||||||
if (reader_)
|
if (reader_)
|
||||||
return reader_->ScanChildren();
|
return reader_->ScanChildren();
|
||||||
|
@ -133,7 +138,8 @@ class BoxBuffer {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read/write child box.
|
/// Read/write child box.
|
||||||
|
/// @return true on success, false otherwise.
|
||||||
bool ReadWriteChild(Box* box) {
|
bool ReadWriteChild(Box* box) {
|
||||||
if (reader_)
|
if (reader_)
|
||||||
return reader_->ReadChild(box);
|
return reader_->ReadChild(box);
|
||||||
|
@ -143,7 +149,8 @@ class BoxBuffer {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read/write child box if exist.
|
/// Read/write child box if exists.
|
||||||
|
/// @return true on success, false otherwise.
|
||||||
bool TryReadWriteChild(Box* box) {
|
bool TryReadWriteChild(Box* box) {
|
||||||
if (reader_)
|
if (reader_)
|
||||||
return reader_->TryReadChild(box);
|
return reader_->TryReadChild(box);
|
||||||
|
@ -153,7 +160,9 @@ class BoxBuffer {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip |num_bytes| in read mode, otherwise fill with |num_bytes| of '\0'.
|
/// @param num_bytes specifies number of bytes to skip in read mode or number
|
||||||
|
/// of bytes to be padded with zero in write mode.
|
||||||
|
/// @return true on success, false otherwise.
|
||||||
bool IgnoreBytes(size_t num_bytes) {
|
bool IgnoreBytes(size_t num_bytes) {
|
||||||
if (reader_)
|
if (reader_)
|
||||||
return reader_->SkipBytes(num_bytes);
|
return reader_->SkipBytes(num_bytes);
|
||||||
|
@ -162,7 +171,9 @@ class BoxBuffer {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @return A pointer to the inner reader object.
|
||||||
BoxReader* reader() { return reader_; }
|
BoxReader* reader() { return reader_; }
|
||||||
|
/// @return A pointer to the inner writer object.
|
||||||
BufferWriter* writer() { return writer_; }
|
BufferWriter* writer() { return writer_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -19,63 +19,74 @@ namespace mp4 {
|
||||||
|
|
||||||
class Box;
|
class Box;
|
||||||
|
|
||||||
|
/// Class for reading MP4 boxes.
|
||||||
class BoxReader : public BufferReader {
|
class BoxReader : public BufferReader {
|
||||||
public:
|
public:
|
||||||
~BoxReader();
|
~BoxReader();
|
||||||
|
|
||||||
// Create a BoxReader from a buffer. Note that this function may return NULL
|
/// Create a BoxReader from a buffer.
|
||||||
// if an intact, complete box was not available in the buffer. If |*err| is
|
/// @param buf is retained but not owned, and must outlive the BoxReader
|
||||||
// set, there was a stream-level error when creating the box; otherwise, NULL
|
/// instance.
|
||||||
// values are only expected when insufficient data is available.
|
/// @param buf_size indicates the size of the input buffer.
|
||||||
//
|
/// @param[out] err is set to true if there was a stream-level error when
|
||||||
// |buf| is retained but not owned, and must outlive the BoxReader instance.
|
/// reading the box.
|
||||||
|
/// @return New box reader if successful, NULL otherwise.
|
||||||
static BoxReader* ReadTopLevelBox(const uint8* buf,
|
static BoxReader* ReadTopLevelBox(const uint8* buf,
|
||||||
const int buf_size,
|
const int buf_size,
|
||||||
bool* err);
|
bool* err);
|
||||||
|
|
||||||
// Read the box header from the current buffer. This function returns true if
|
/// Read the box header from the current buffer.
|
||||||
// there is enough data to read the header and the header is sane; that is, it
|
/// @param buf is not retained.
|
||||||
// does not check to ensure the entire box is in the buffer before returning
|
/// @param buf_size indicates the size of the input buffer.
|
||||||
// true. The semantics of |*err| are the same as above.
|
/// @param[out] type is filled with the fourcc of the box on success.
|
||||||
//
|
/// @param[out] box_size is filled with the size of the box on success.
|
||||||
// |buf| is not retained.
|
/// @param[out] err is set to true if there was a stream-level error when
|
||||||
|
/// reading the box.
|
||||||
|
/// @return true if there is enough data to read the header and the header is
|
||||||
|
/// sane, which does not imply that the entire box is in the buffer.
|
||||||
static bool StartTopLevelBox(const uint8* buf,
|
static bool StartTopLevelBox(const uint8* buf,
|
||||||
const int buf_size,
|
const int buf_size,
|
||||||
FourCC* type,
|
FourCC* type,
|
||||||
int* box_size,
|
int* box_size,
|
||||||
bool* err) WARN_UNUSED_RESULT;
|
bool* err) WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
// Returns true if |type| is recognized to be a top-level box, false
|
/// @return true if @a type is recognized to be the fourcc of a top-level box,
|
||||||
// otherwise. This returns true for some boxes which we do not parse.
|
/// false otherwise. This returns true for some boxes which we do not
|
||||||
// Helpful in debugging misaligned appends.
|
/// parse.
|
||||||
|
/// This method is helpful for debugging misaligned appends.
|
||||||
static bool IsValidTopLevelBox(const FourCC& type);
|
static bool IsValidTopLevelBox(const FourCC& type);
|
||||||
|
|
||||||
// Scan through all boxes within the current box, starting at the current
|
/// Scan through all boxes within the current box, starting at the current
|
||||||
// buffer position. Must be called before any of the *Child functions work.
|
/// buffer position. Must be called before any of the @b *Child functions
|
||||||
|
/// work.
|
||||||
|
/// @return true on success, false otherwise.
|
||||||
bool ScanChildren() WARN_UNUSED_RESULT;
|
bool ScanChildren() WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
// Return true if child with type |child.BoxType()| exists.
|
/// @return true if child with type @a child.BoxType() exists.
|
||||||
bool ChildExist(Box* child) WARN_UNUSED_RESULT;
|
bool ChildExist(Box* child) WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
// Read exactly one child box from the set of children. The type of the child
|
/// Read exactly one child box from the set of children. The type of the
|
||||||
// will be determined by the BoxType() method of |child|.
|
/// child will be determined by the BoxType() of @a child.
|
||||||
|
/// @return true on success, false otherwise.
|
||||||
bool ReadChild(Box* child) WARN_UNUSED_RESULT;
|
bool ReadChild(Box* child) WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
// Read one child if available. Returns false on error, true on successful
|
/// Read one child if available.
|
||||||
// read or on child absent.
|
/// @return false on error, true on successful read or on child absent.
|
||||||
bool TryReadChild(Box* child) WARN_UNUSED_RESULT;
|
bool TryReadChild(Box* child) WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
// Read at least one child. False means error or no such child present.
|
/// Read at least one child.
|
||||||
|
/// @return false on error or no child of type <T> present.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool ReadChildren(std::vector<T>* children) WARN_UNUSED_RESULT;
|
bool ReadChildren(std::vector<T>* children) WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
// Read any number of children. False means error.
|
/// Read any number of children.
|
||||||
|
/// @return false on error.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool TryReadChildren(std::vector<T>* children) WARN_UNUSED_RESULT;
|
bool TryReadChildren(std::vector<T>* children) WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
// Read all children, regardless of FourCC. This is used from exactly one box,
|
/// Read all children. It expects all children to be of type T.
|
||||||
// corresponding to a rather significant inconsistency in the BMFF spec.
|
/// Note that this method is mutually exclusive with ScanChildren().
|
||||||
// Note that this method is mutually exclusive with ScanChildren().
|
/// @return true on success, false otherwise.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool ReadAllChildren(std::vector<T>* children) WARN_UNUSED_RESULT;
|
bool ReadAllChildren(std::vector<T>* children) WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file or at
|
// license that can be found in the LICENSE file or at
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
//
|
|
||||||
// Implements a wrapper around Sample to Chunk Box (STSC) to iterate through
|
|
||||||
// the compressed table by sample/chunk. This class also provides a convenient
|
|
||||||
// function to query total number of samples from start_chunk to end_chunk.
|
|
||||||
|
|
||||||
#ifndef MEDIA_MP4_CHUNK_INFO_ITERATOR_H_
|
#ifndef MEDIA_MP4_CHUNK_INFO_ITERATOR_H_
|
||||||
#define MEDIA_MP4_CHUNK_INFO_ITERATOR_H_
|
#define MEDIA_MP4_CHUNK_INFO_ITERATOR_H_
|
||||||
|
@ -18,38 +14,42 @@
|
||||||
namespace media {
|
namespace media {
|
||||||
namespace mp4 {
|
namespace mp4 {
|
||||||
|
|
||||||
|
/// Sample to chunk box (STSC) iterator used to iterate through the compressed
|
||||||
|
/// table by sample/chunk. This class also provides a convenient function to
|
||||||
|
/// query total number of samples from start_chunk to end_chunk.
|
||||||
class ChunkInfoIterator {
|
class ChunkInfoIterator {
|
||||||
public:
|
public:
|
||||||
|
/// Create ChunkInfoIterator from sample to chunk box.
|
||||||
explicit ChunkInfoIterator(const SampleToChunk& sample_to_chunk);
|
explicit ChunkInfoIterator(const SampleToChunk& sample_to_chunk);
|
||||||
~ChunkInfoIterator();
|
~ChunkInfoIterator();
|
||||||
|
|
||||||
// Advance the properties to refer to the next chunk. Return status
|
/// Advance to the next chunk.
|
||||||
// indicating whether the chunk is still valid.
|
/// @return true if not past the last chunk, false otherwise.
|
||||||
bool AdvanceChunk();
|
bool AdvanceChunk();
|
||||||
|
|
||||||
// Advance the properties to refer to the next sample. Return status
|
/// Advance to the next sample.
|
||||||
// indicating whether the sample is still valid.
|
/// @return true if not past the last sample, false otherwise.
|
||||||
bool AdvanceSample();
|
bool AdvanceSample();
|
||||||
|
|
||||||
// Return whether the current chunk is valid.
|
/// @return true if not past the last chunk/sample, false otherwise.
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
// Return current chunk.
|
/// @return Current chunk.
|
||||||
uint32 current_chunk() const { return current_chunk_; }
|
uint32 current_chunk() const { return current_chunk_; }
|
||||||
|
|
||||||
// Return samples per chunk for current chunk.
|
/// @return Samples per chunk for current chunk.
|
||||||
uint32 samples_per_chunk() const { return iterator_->samples_per_chunk; }
|
uint32 samples_per_chunk() const { return iterator_->samples_per_chunk; }
|
||||||
|
|
||||||
// Return sample description index for current chunk.
|
/// @return Sample description index for current chunk.
|
||||||
uint32 sample_description_index() const {
|
uint32 sample_description_index() const {
|
||||||
return iterator_->sample_description_index;
|
return iterator_->sample_description_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return number of samples from start_chunk to end_chunk, both 1-based,
|
/// @return Number of samples from start_chunk to end_chunk, both 1-based,
|
||||||
// inclusive.
|
/// inclusive.
|
||||||
uint32 NumSamples(uint32 start_chunk, uint32 end_chunk) const;
|
uint32 NumSamples(uint32 start_chunk, uint32 end_chunk) const;
|
||||||
|
|
||||||
// Return the last first_chunk in chunk_info_table.
|
/// @return The last first_chunk in chunk_info_table.
|
||||||
uint32 LastFirstChunk() const {
|
uint32 LastFirstChunk() const {
|
||||||
return chunk_info_table_.empty() ? 0
|
return chunk_info_table_.empty() ? 0
|
||||||
: chunk_info_table_.back().first_chunk;
|
: chunk_info_table_.back().first_chunk;
|
||||||
|
|
|
@ -3,11 +3,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file or at
|
// license that can be found in the LICENSE file or at
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
//
|
|
||||||
// Implements a wrapper around Composition Time to Sample Box (CTTS) to iterate
|
|
||||||
// through the compressed table. This class also provides convenient functions
|
|
||||||
// to query total number of samples and the composition offset for a particular
|
|
||||||
// sample.
|
|
||||||
|
|
||||||
#ifndef MEDIA_MP4_COMPOSITION_OFFSET_ITERATOR_H_
|
#ifndef MEDIA_MP4_COMPOSITION_OFFSET_ITERATOR_H_
|
||||||
#define MEDIA_MP4_COMPOSITION_OFFSET_ITERATOR_H_
|
#define MEDIA_MP4_COMPOSITION_OFFSET_ITERATOR_H_
|
||||||
|
@ -19,26 +14,31 @@
|
||||||
namespace media {
|
namespace media {
|
||||||
namespace mp4 {
|
namespace mp4 {
|
||||||
|
|
||||||
|
/// Composition time to sample box (CTTS) iterator used to iterate through the
|
||||||
|
/// compressed table. This class also provides convenient functions to query
|
||||||
|
/// total number of samples and the composition offset for a particular sample.
|
||||||
class CompositionOffsetIterator {
|
class CompositionOffsetIterator {
|
||||||
public:
|
public:
|
||||||
|
/// Create CompositionOffsetIterator from composition time to sample box.
|
||||||
explicit CompositionOffsetIterator(
|
explicit CompositionOffsetIterator(
|
||||||
const CompositionTimeToSample& composition_time_to_sample);
|
const CompositionTimeToSample& composition_time_to_sample);
|
||||||
~CompositionOffsetIterator();
|
~CompositionOffsetIterator();
|
||||||
|
|
||||||
// Advance the properties to refer to the next sample. Return status
|
/// Advance the iterator to the next sample.
|
||||||
// indicating whether the sample is still valid.
|
/// @return true if not past the last sample, false otherwise.
|
||||||
bool AdvanceSample();
|
bool AdvanceSample();
|
||||||
|
|
||||||
// Return whether the current sample is valid.
|
/// @return true if the iterator is still valid, false if past the last
|
||||||
|
/// sample.
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
// Return sample offset for current sample.
|
/// @return Sample offset for current sample.
|
||||||
uint32 sample_offset() const { return iterator_->sample_offset; }
|
uint32 sample_offset() const { return iterator_->sample_offset; }
|
||||||
|
|
||||||
// Return sample offset @ sample, 1-based.
|
/// @return Sample offset @a sample, 1-based.
|
||||||
uint32 SampleOffset(uint32 sample) const;
|
uint32 SampleOffset(uint32 sample) const;
|
||||||
|
|
||||||
// Return total number of samples.
|
/// @return Total number of samples.
|
||||||
uint32 NumSamples() const;
|
uint32 NumSamples() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -3,11 +3,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file or at
|
// license that can be found in the LICENSE file or at
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
//
|
|
||||||
// Implements a wrapper around Decoding Time to Sample Box (STTS) to iterate
|
|
||||||
// through the compressed table. This class also provides convenient functions
|
|
||||||
// to query total number of samples and the duration from start_sample to
|
|
||||||
// end_sample.
|
|
||||||
|
|
||||||
#ifndef MEDIA_MP4_DECODING_TIME_ITERATOR_H_
|
#ifndef MEDIA_MP4_DECODING_TIME_ITERATOR_H_
|
||||||
#define MEDIA_MP4_DECODING_TIME_ITERATOR_H_
|
#define MEDIA_MP4_DECODING_TIME_ITERATOR_H_
|
||||||
|
@ -19,26 +14,31 @@
|
||||||
namespace media {
|
namespace media {
|
||||||
namespace mp4 {
|
namespace mp4 {
|
||||||
|
|
||||||
|
/// Decoding time to sample box (STTS) iterator used to iterate through the
|
||||||
|
/// compressed table. This class also provides convenient functions to query
|
||||||
|
/// total number of samples and the duration from start_sample to end_sample.
|
||||||
class DecodingTimeIterator {
|
class DecodingTimeIterator {
|
||||||
public:
|
public:
|
||||||
|
/// Create DecodingTimeIterator from decoding time to sample box.
|
||||||
explicit DecodingTimeIterator(
|
explicit DecodingTimeIterator(
|
||||||
const DecodingTimeToSample& decoding_time_to_sample);
|
const DecodingTimeToSample& decoding_time_to_sample);
|
||||||
~DecodingTimeIterator();
|
~DecodingTimeIterator();
|
||||||
|
|
||||||
// Advance the properties to refer to the next sample. Return status
|
/// Advance to the next sample.
|
||||||
// indicating whether the sample is still valid.
|
/// @return true if not past the last sample, false otherwise.
|
||||||
bool AdvanceSample();
|
bool AdvanceSample();
|
||||||
|
|
||||||
// Return whether the current sample is valid.
|
/// @return true if the iterator is still valid, false if past the last
|
||||||
|
/// sample.
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
// Return sample delta for current sample.
|
/// @return Sample delta for current sample.
|
||||||
uint32 sample_delta() const { return iterator_->sample_delta; }
|
uint32 sample_delta() const { return iterator_->sample_delta; }
|
||||||
|
|
||||||
// Return duration from start_sample to end_sample, both 1-based, inclusive.
|
/// @return Duration from start_sample to end_sample, both 1-based, inclusive.
|
||||||
uint64 Duration(uint32 start_sample, uint32 end_sample) const;
|
uint64 Duration(uint32 start_sample, uint32 end_sample) const;
|
||||||
|
|
||||||
// Return total number of samples in the table.
|
/// @return Total number of samples in the table.
|
||||||
uint32 NumSamples() const;
|
uint32 NumSamples() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -25,9 +25,9 @@ enum ObjectType {
|
||||||
kEAC3 = 0xa6 // Dolby Digital Plus
|
kEAC3 = 0xa6 // Dolby Digital Plus
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class parse object type and decoder specific information from an
|
/// This class parses object type and decoder specific information from an
|
||||||
// elementary stream descriptor, which is usually contained in an esds box.
|
/// elementary stream descriptor, which is usually contained in an esds
|
||||||
// Please refer to ISO 14496 Part 1 7.2.6.5 for more details.
|
/// box. Please refer to ISO 14496 Part 1 7.2.6.5 for more details.
|
||||||
class ESDescriptor {
|
class ESDescriptor {
|
||||||
public:
|
public:
|
||||||
ESDescriptor();
|
ESDescriptor();
|
||||||
|
@ -51,7 +51,7 @@ class ESDescriptor {
|
||||||
decoder_specific_info_ = decoder_specific_info;
|
decoder_specific_info_ = decoder_specific_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the stream is AAC.
|
/// @return true if the stream is AAC.
|
||||||
bool IsAAC() const {
|
bool IsAAC() const {
|
||||||
return object_type_ == kISO_14496_3 || object_type_ == kISO_13818_7_AAC_LC;
|
return object_type_ == kISO_14496_3 || object_type_ == kISO_13818_7_AAC_LC;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file or at
|
// license that can be found in the LICENSE file or at
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
//
|
|
||||||
// MP4Fragmenter is responsible for the generation of MP4 fragments, i.e. traf
|
|
||||||
// and the corresponding mdat. The samples are also encrypted if encryption is
|
|
||||||
// requested.
|
|
||||||
|
|
||||||
#ifndef MEDIA_MP4_MP4_FRAGMENTER_H_
|
#ifndef MEDIA_MP4_MP4_FRAGMENTER_H_
|
||||||
#define MEDIA_MP4_MP4_FRAGMENTER_H_
|
#define MEDIA_MP4_MP4_FRAGMENTER_H_
|
||||||
|
@ -28,13 +24,20 @@ namespace mp4 {
|
||||||
class SegmentReference;
|
class SegmentReference;
|
||||||
class TrackFragment;
|
class TrackFragment;
|
||||||
|
|
||||||
|
/// MP4Fragmenter is responsible for the generation of MP4 fragments, i.e. traf
|
||||||
|
/// box and corresponding mdat box. The samples are also encrypted if encryption
|
||||||
|
/// is requested.
|
||||||
class MP4Fragmenter {
|
class MP4Fragmenter {
|
||||||
public:
|
public:
|
||||||
// Caller retains the ownership of |traf| and transfers ownership of
|
/// @param traf points to a TrackFragment box.
|
||||||
// |encryptor|. |clear_time| specifies clear time in the current track
|
/// @param encryptor handles encryption of the samples. It can be NULL, which
|
||||||
// timescale. |nalu_length_size| specifies NAL unit length size, for
|
/// indicates no encryption is required.
|
||||||
// subsample encryption. |normalize_presentation_timestamp| defines whether
|
/// @param clear_time specifies clear lead duration in units of the current
|
||||||
// PTS should be normalized to start from zero.
|
/// track's timescale.
|
||||||
|
/// @param nalu_length_size NAL unit length size, in bytes, for subsample
|
||||||
|
/// encryption.
|
||||||
|
/// @param normalize_presentation_timestamp defines whether PTS should be
|
||||||
|
/// normalized to start from zero.
|
||||||
MP4Fragmenter(TrackFragment* traf,
|
MP4Fragmenter(TrackFragment* traf,
|
||||||
scoped_ptr<AesCtrEncryptor> encryptor,
|
scoped_ptr<AesCtrEncryptor> encryptor,
|
||||||
int64 clear_time,
|
int64 clear_time,
|
||||||
|
@ -42,15 +45,16 @@ class MP4Fragmenter {
|
||||||
bool normalize_presentation_timestamp);
|
bool normalize_presentation_timestamp);
|
||||||
~MP4Fragmenter();
|
~MP4Fragmenter();
|
||||||
|
|
||||||
|
/// Add a sample to the fragmenter.
|
||||||
virtual Status AddSample(scoped_refptr<MediaSample> sample);
|
virtual Status AddSample(scoped_refptr<MediaSample> sample);
|
||||||
|
|
||||||
// Initialize the fragment with default data.
|
/// Initialize the fragment with default data.
|
||||||
void InitializeFragment();
|
void InitializeFragment();
|
||||||
|
|
||||||
// Finalize and optimize the fragment.
|
/// Finalize and optimize the fragment.
|
||||||
void FinalizeFragment();
|
void FinalizeFragment();
|
||||||
|
|
||||||
// Fill in |reference| with current fragment information.
|
/// Fill @a reference with current fragment information.
|
||||||
void GenerateSegmentReference(SegmentReference* reference);
|
void GenerateSegmentReference(SegmentReference* reference);
|
||||||
|
|
||||||
uint64 fragment_duration() const { return fragment_duration_; }
|
uint64 fragment_duration() const { return fragment_duration_; }
|
||||||
|
|
|
@ -3,20 +3,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file or at
|
// license that can be found in the LICENSE file or at
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
//
|
|
||||||
// Segmenter for MP4 live, main and simple profiles. The generated media file
|
|
||||||
// could contain one to many segments with segment duration defined by
|
|
||||||
// |MuxerOptions.segment_duration|. A segment could contain one to many
|
|
||||||
// subsegments defined by |num_subsegments_per_sidx|. A subsegment could
|
|
||||||
// contain one to many fragments with fragment duration defined by
|
|
||||||
// |MuxerOptions.fragment_duration|. The actual segment or fragment duration
|
|
||||||
// may not match the defined duration exactly but in a best effort basic, i.e.
|
|
||||||
// the segmenter tries to end segment/fragment at the first sample with
|
|
||||||
// overall segment/fragment duration not smaller than defined duration and
|
|
||||||
// yet meet SAP requirements. The generated segments are written into files
|
|
||||||
// defined by |MuxerOptions.segment_template| if it is defined; otherwise,
|
|
||||||
// the segments are appended to the main output file defined by
|
|
||||||
// |MuxerOptions.output_file_name|.
|
|
||||||
|
|
||||||
#ifndef MEDIA_MP4_MP4_GENERAL_SEGMENTER_H_
|
#ifndef MEDIA_MP4_MP4_GENERAL_SEGMENTER_H_
|
||||||
#define MEDIA_MP4_MP4_GENERAL_SEGMENTER_H_
|
#define MEDIA_MP4_MP4_GENERAL_SEGMENTER_H_
|
||||||
|
@ -28,21 +14,35 @@ namespace mp4 {
|
||||||
|
|
||||||
struct SegmentType;
|
struct SegmentType;
|
||||||
|
|
||||||
|
/// Segmenter for MP4 live, main and simple profiles. The generated media file
|
||||||
|
/// can contain one or many segments with segment duration defined by @b
|
||||||
|
/// MuxerOptions.segment_duration. A segment can contain one or many
|
||||||
|
/// subsegments defined by @b num_subsegments_per_sidx. A subsegment can
|
||||||
|
/// contain one or many fragments with fragment duration defined by @b
|
||||||
|
/// MuxerOptions.fragment_duration. The actual segment or fragment duration
|
||||||
|
/// may not match the requested duration exactly, but will be approximated.
|
||||||
|
/// That is, the segmenter tries to end segment/fragment at the first sample
|
||||||
|
/// with overall segment/fragment duration not smaller than defined duration
|
||||||
|
/// and yet meet SAP requirements. The generated segments are written to files
|
||||||
|
/// defined by @b MuxerOptions.segment_template if specified; otherwise,
|
||||||
|
/// the segments are appended to the main output file specified by @b
|
||||||
|
/// MuxerOptions.output_file_name.
|
||||||
class MP4GeneralSegmenter : public MP4Segmenter {
|
class MP4GeneralSegmenter : public MP4Segmenter {
|
||||||
public:
|
public:
|
||||||
// Caller transfers the ownership of |ftyp| and |moov| to this class.
|
|
||||||
MP4GeneralSegmenter(const MuxerOptions& options,
|
MP4GeneralSegmenter(const MuxerOptions& options,
|
||||||
scoped_ptr<FileType> ftyp,
|
scoped_ptr<FileType> ftyp,
|
||||||
scoped_ptr<Movie> moov);
|
scoped_ptr<Movie> moov);
|
||||||
virtual ~MP4GeneralSegmenter();
|
virtual ~MP4GeneralSegmenter();
|
||||||
|
|
||||||
// MP4Segmenter implementations.
|
/// @name MP4Segmenter implementation overrides.
|
||||||
|
/// @{
|
||||||
virtual Status Initialize(EncryptorSource* encryptor_source,
|
virtual Status Initialize(EncryptorSource* encryptor_source,
|
||||||
double clear_lead_in_seconds,
|
double clear_lead_in_seconds,
|
||||||
const std::vector<MediaStream*>& streams) OVERRIDE;
|
const std::vector<MediaStream*>& streams) OVERRIDE;
|
||||||
|
|
||||||
virtual bool GetInitRange(size_t* offset, size_t* size) OVERRIDE;
|
virtual bool GetInitRange(size_t* offset, size_t* size) OVERRIDE;
|
||||||
virtual bool GetIndexRange(size_t* offset, size_t* size) OVERRIDE;
|
virtual bool GetIndexRange(size_t* offset, size_t* size) OVERRIDE;
|
||||||
|
/// @}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual Status FinalizeSegment() OVERRIDE;
|
virtual Status FinalizeSegment() OVERRIDE;
|
||||||
|
|
|
@ -30,10 +30,13 @@ class MP4MediaParser : public MediaParser {
|
||||||
MP4MediaParser();
|
MP4MediaParser();
|
||||||
virtual ~MP4MediaParser();
|
virtual ~MP4MediaParser();
|
||||||
|
|
||||||
|
/// @name MediaParser implementation overrides.
|
||||||
|
/// @{
|
||||||
virtual void Init(const InitCB& init_cb,
|
virtual void Init(const InitCB& init_cb,
|
||||||
const NewSampleCB& new_sample_cb,
|
const NewSampleCB& new_sample_cb,
|
||||||
const NeedKeyCB& need_key_cb) OVERRIDE;
|
const NeedKeyCB& need_key_cb) OVERRIDE;
|
||||||
virtual bool Parse(const uint8* buf, int size) OVERRIDE;
|
virtual bool Parse(const uint8* buf, int size) OVERRIDE;
|
||||||
|
/// @}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum State {
|
enum State {
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file or at
|
// license that can be found in the LICENSE file or at
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
//
|
|
||||||
// Implements MP4 Muxer.
|
|
||||||
|
|
||||||
#ifndef MEDIA_MP4_MP4_MUXER_H_
|
#ifndef MEDIA_MP4_MP4_MUXER_H_
|
||||||
#define MEDIA_MP4_MP4_MUXER_H_
|
#define MEDIA_MP4_MP4_MUXER_H_
|
||||||
|
@ -28,16 +26,21 @@ struct ProtectionSchemeInfo;
|
||||||
struct ProtectionSystemSpecificHeader;
|
struct ProtectionSystemSpecificHeader;
|
||||||
struct Track;
|
struct Track;
|
||||||
|
|
||||||
|
/// Implements MP4 Muxer for ISO-BMFF. Please refer to ISO/IEC 14496-12: ISO
|
||||||
|
/// base media file format for details.
|
||||||
class MP4Muxer : public Muxer {
|
class MP4Muxer : public Muxer {
|
||||||
public:
|
public:
|
||||||
|
/// Create a MP4Muxer object from MuxerOptions.
|
||||||
explicit MP4Muxer(const MuxerOptions& options);
|
explicit MP4Muxer(const MuxerOptions& options);
|
||||||
virtual ~MP4Muxer();
|
virtual ~MP4Muxer();
|
||||||
|
|
||||||
// Muxer implementations.
|
/// @name Muxer implementation overrides.
|
||||||
|
/// @{
|
||||||
virtual Status Initialize() OVERRIDE;
|
virtual Status Initialize() OVERRIDE;
|
||||||
virtual Status Finalize() OVERRIDE;
|
virtual Status Finalize() OVERRIDE;
|
||||||
virtual Status AddSample(const MediaStream* stream,
|
virtual Status AddSample(const MediaStream* stream,
|
||||||
scoped_refptr<MediaSample> sample) OVERRIDE;
|
scoped_refptr<MediaSample> sample) OVERRIDE;
|
||||||
|
/// @}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Generate Audio/Video Track atom.
|
// Generate Audio/Video Track atom.
|
||||||
|
|
|
@ -3,13 +3,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file or at
|
// license that can be found in the LICENSE file or at
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
//
|
|
||||||
// This class defines the MP4 Segmenter which is responsible for organizing
|
|
||||||
// MP4 fragments into segments/subsegments and package into a MP4 file.
|
|
||||||
// Inherited by MP4GeneralSegmenter and MP4VODSegmenter. MP4VODSegmenter defines
|
|
||||||
// the segmenter for DASH Video-On-Demand with a single segment for each media
|
|
||||||
// presentation while MP4GeneralSegmenter handles all other cases including
|
|
||||||
// DASH live profile.
|
|
||||||
|
|
||||||
#ifndef MEDIA_MP4_MP4_SEGMENTER_H_
|
#ifndef MEDIA_MP4_MP4_SEGMENTER_H_
|
||||||
#define MEDIA_MP4_MP4_SEGMENTER_H_
|
#define MEDIA_MP4_MP4_SEGMENTER_H_
|
||||||
|
@ -39,18 +32,24 @@ struct Movie;
|
||||||
struct MovieFragment;
|
struct MovieFragment;
|
||||||
struct SegmentIndex;
|
struct SegmentIndex;
|
||||||
|
|
||||||
|
/// This class defines the MP4 Segmenter which is responsible for organizing
|
||||||
|
/// MP4 fragments into segments/subsegments and package them into a MP4 file.
|
||||||
|
/// Inherited by MP4GeneralSegmenter and MP4VODSegmenter. MP4VODSegmenter
|
||||||
|
/// defines the segmenter for DASH Video-On-Demand with a single segment for
|
||||||
|
/// each media presentation while MP4GeneralSegmenter handles all other cases
|
||||||
|
/// including DASH live profile.
|
||||||
class MP4Segmenter {
|
class MP4Segmenter {
|
||||||
public:
|
public:
|
||||||
// Caller transfers the ownership of |ftyp| and |moov| to this class.
|
|
||||||
MP4Segmenter(const MuxerOptions& options,
|
MP4Segmenter(const MuxerOptions& options,
|
||||||
scoped_ptr<FileType> ftyp,
|
scoped_ptr<FileType> ftyp,
|
||||||
scoped_ptr<Movie> moov);
|
scoped_ptr<Movie> moov);
|
||||||
virtual ~MP4Segmenter();
|
virtual ~MP4Segmenter();
|
||||||
|
|
||||||
// Initialize the segmenter. Caller retains the ownership of
|
/// Initialize the segmenter.
|
||||||
// |encryptor_source|. |encryptor_source| can be NULL.
|
/// Calling other public methods of this class without this method returning
|
||||||
// Calling other public methods of this class without this method returning
|
/// Status::OK, results in an undefined behavior.
|
||||||
// Status::OK, results in an undefined behavior.
|
/// @param encryptor_source can be NULL.
|
||||||
|
/// @return Status::OK on success.
|
||||||
virtual Status Initialize(EncryptorSource* encryptor_source,
|
virtual Status Initialize(EncryptorSource* encryptor_source,
|
||||||
double clear_lead_in_seconds,
|
double clear_lead_in_seconds,
|
||||||
const std::vector<MediaStream*>& streams);
|
const std::vector<MediaStream*>& streams);
|
||||||
|
@ -60,19 +59,17 @@ class MP4Segmenter {
|
||||||
virtual Status AddSample(const MediaStream* stream,
|
virtual Status AddSample(const MediaStream* stream,
|
||||||
scoped_refptr<MediaSample> sample);
|
scoped_refptr<MediaSample> sample);
|
||||||
|
|
||||||
// Returns false if it does not apply.
|
/// @return true if there is an initialization range, while setting @a offset
|
||||||
// If it has an initialization byte range this returns true and set |offset|
|
/// and @a size; or false if initialization range does not apply.
|
||||||
// and |size|, otherwise returns false.
|
|
||||||
virtual bool GetInitRange(size_t* offset, size_t* size) = 0;
|
virtual bool GetInitRange(size_t* offset, size_t* size) = 0;
|
||||||
|
|
||||||
// Returns false if it does not apply.
|
/// @return true if there is an index byte range, while setting @a offset
|
||||||
// If it has an index byte range this returns true and set |offset| and
|
/// and @a size; or false if index byte range does not apply.
|
||||||
// |size|, otherwise returns false.
|
|
||||||
virtual bool GetIndexRange(size_t* offset, size_t* size) = 0;
|
virtual bool GetIndexRange(size_t* offset, size_t* size) = 0;
|
||||||
|
|
||||||
uint32 GetReferenceTimeScale() const;
|
uint32 GetReferenceTimeScale() const;
|
||||||
|
|
||||||
// Returns the total length, in seconds, of segmented media files.
|
/// @return The total length, in seconds, of segmented media files.
|
||||||
double GetDuration() const;
|
double GetDuration() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -3,18 +3,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file or at
|
// license that can be found in the LICENSE file or at
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
//
|
|
||||||
// Segmenter for MP4 Dash Video-On-Demand profile. A single MP4 file with a
|
|
||||||
// single segment is created, i.e. with only one SIDX box. The generated media
|
|
||||||
// file could contain one to many subsegments with subsegment duration
|
|
||||||
// defined by|MuxerOptions.segment_duration|. A subsegment could contain one
|
|
||||||
// to many fragments with fragment duration defined by
|
|
||||||
// |MuxerOptions.fragment_duration|. The actual subsegment or fragment duration
|
|
||||||
// may not match the defined duration exactly but in a best effort basic, i.e.
|
|
||||||
// the segmenter tries to end subsegment/fragment at the first sample with
|
|
||||||
// overall subsegment/fragment duration not smaller than defined duration and
|
|
||||||
// yet meet SAP requirements. VOD segmenter ignores
|
|
||||||
// |MuxerOptions.num_subsegments_per_sidx|.
|
|
||||||
|
|
||||||
#ifndef MEDIA_MP4_MP4_VOD_SEGMENTER_H_
|
#ifndef MEDIA_MP4_MP4_VOD_SEGMENTER_H_
|
||||||
#define MEDIA_MP4_MP4_VOD_SEGMENTER_H_
|
#define MEDIA_MP4_MP4_VOD_SEGMENTER_H_
|
||||||
|
@ -25,15 +13,26 @@
|
||||||
namespace media {
|
namespace media {
|
||||||
namespace mp4 {
|
namespace mp4 {
|
||||||
|
|
||||||
|
/// Segmenter for MP4 Dash Video-On-Demand profile. A single MP4 file with a
|
||||||
|
/// single segment is created, i.e. with only one SIDX box. The generated media
|
||||||
|
/// file can contain one or many subsegments with subsegment duration
|
||||||
|
/// defined by @b MuxerOptions.segment_duration. A subsegment can contain one
|
||||||
|
/// or many fragments with fragment duration defined by @b
|
||||||
|
/// MuxerOptions.fragment_duration. The actual subsegment or fragment duration
|
||||||
|
/// may not match the requested duration exactly, but will be approximated. That
|
||||||
|
/// is, the segmenter tries to end subsegment/fragment at the first sample with
|
||||||
|
/// overall subsegment/fragment duration not smaller than defined duration and
|
||||||
|
/// yet meet SAP requirements. VOD segmenter ignores @b
|
||||||
|
/// MuxerOptions.num_subsegments_per_sidx.
|
||||||
class MP4VODSegmenter : public MP4Segmenter {
|
class MP4VODSegmenter : public MP4Segmenter {
|
||||||
public:
|
public:
|
||||||
// Caller transfers the ownership of |ftyp| and |moov| to this class.
|
|
||||||
MP4VODSegmenter(const MuxerOptions& options,
|
MP4VODSegmenter(const MuxerOptions& options,
|
||||||
scoped_ptr<FileType> ftyp,
|
scoped_ptr<FileType> ftyp,
|
||||||
scoped_ptr<Movie> moov);
|
scoped_ptr<Movie> moov);
|
||||||
virtual ~MP4VODSegmenter();
|
virtual ~MP4VODSegmenter();
|
||||||
|
|
||||||
// MP4Segmenter implementations.
|
/// @name MP4Segmenter implementation overrides.
|
||||||
|
/// @{
|
||||||
virtual Status Initialize(EncryptorSource* encryptor_source,
|
virtual Status Initialize(EncryptorSource* encryptor_source,
|
||||||
double clear_lead_in_seconds,
|
double clear_lead_in_seconds,
|
||||||
const std::vector<MediaStream*>& streams) OVERRIDE;
|
const std::vector<MediaStream*>& streams) OVERRIDE;
|
||||||
|
@ -41,6 +40,7 @@ class MP4VODSegmenter : public MP4Segmenter {
|
||||||
|
|
||||||
virtual bool GetInitRange(size_t* offset, size_t* size) OVERRIDE;
|
virtual bool GetInitRange(size_t* offset, size_t* size) OVERRIDE;
|
||||||
virtual bool GetIndexRange(size_t* offset, size_t* size) OVERRIDE;
|
virtual bool GetIndexRange(size_t* offset, size_t* size) OVERRIDE;
|
||||||
|
/// @}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual Status FinalizeSegment() OVERRIDE;
|
virtual Status FinalizeSegment() OVERRIDE;
|
||||||
|
|
|
@ -10,42 +10,46 @@
|
||||||
|
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
// A wrapper around a ByteQueue which maintains a notion of a
|
/// Wrapper around ByteQueue, which encapsulates the notion of a
|
||||||
// monotonically-increasing offset. All buffer access is done by passing these
|
/// monotonically-increasing byte offset. All buffer access is done by passing
|
||||||
// offsets into this class, going some way towards preventing the proliferation
|
/// these offsets into this class, reducing the proliferation of many different
|
||||||
// of many different meanings of "offset", "head", etc.
|
/// meanings of "offset", "head", etc.
|
||||||
class OffsetByteQueue {
|
class OffsetByteQueue {
|
||||||
public:
|
public:
|
||||||
OffsetByteQueue();
|
OffsetByteQueue();
|
||||||
~OffsetByteQueue();
|
~OffsetByteQueue();
|
||||||
|
|
||||||
// These work like their underlying ByteQueue counterparts.
|
/// @name These work like their underlying ByteQueue counterparts.
|
||||||
|
/// @{
|
||||||
void Reset();
|
void Reset();
|
||||||
void Push(const uint8* buf, int size);
|
void Push(const uint8* buf, int size);
|
||||||
void Peek(const uint8** buf, int* size);
|
void Peek(const uint8** buf, int* size);
|
||||||
void Pop(int count);
|
void Pop(int count);
|
||||||
|
/// @}
|
||||||
|
|
||||||
// Sets |buf| to point at the first buffered byte corresponding to |offset|,
|
/// Set @a buf to point at the first buffered byte corresponding to @a offset,
|
||||||
// and |size| to the number of bytes available starting from that offset.
|
/// and @a size to the number of bytes available starting from that offset.
|
||||||
//
|
///
|
||||||
// It is an error if the offset is before the current head. It's not an error
|
/// It is an error if the offset is before the current head. It's not an error
|
||||||
// if the current offset is beyond tail(), but you will of course get back
|
/// if the current offset is beyond tail(), but you will of course get back
|
||||||
// a null |buf| and a |size| of zero.
|
/// a null @a buf and a @a size of zero.
|
||||||
void PeekAt(int64 offset, const uint8** buf, int* size);
|
void PeekAt(int64 offset, const uint8** buf, int* size);
|
||||||
|
|
||||||
// Marks the bytes up to (but not including) |max_offset| as ready for
|
/// Mark the bytes up to (but not including) @a max_offset as ready for
|
||||||
// deletion. This is relatively inexpensive, but will not necessarily reduce
|
/// deletion. This is relatively inexpensive, but will not necessarily reduce
|
||||||
// the resident buffer size right away (or ever).
|
/// the resident buffer size right away (or ever).
|
||||||
//
|
///
|
||||||
// Returns true if the full range of bytes were successfully trimmed,
|
/// @return true if the full range of bytes were successfully trimmed,
|
||||||
// including the case where |max_offset| is less than the current head.
|
/// including the case where @a max_offset is less than the current
|
||||||
// Returns false if |max_offset| > tail() (although all bytes currently
|
/// head.
|
||||||
// buffered are still cleared).
|
/// @return false if @a max_offset > tail() (although all bytes currently
|
||||||
|
/// buffered are still cleared).
|
||||||
bool Trim(int64 max_offset);
|
bool Trim(int64 max_offset);
|
||||||
|
|
||||||
// The head and tail positions, in terms of the file's absolute offsets.
|
/// @return The head position, in terms of the file's absolute offset.
|
||||||
// tail() is an exclusive bound.
|
|
||||||
int64 head() { return head_; }
|
int64 head() { return head_; }
|
||||||
|
/// @return The tail position (exclusive), in terms of the file's absolute
|
||||||
|
/// offset.
|
||||||
int64 tail() { return head_ + size_; }
|
int64 tail() { return head_ + size_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file or at
|
// license that can be found in the LICENSE file or at
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
//
|
|
||||||
// Implements a wrapper around Sync Sample Box (STSS) to iterate through the
|
|
||||||
// compressed table.
|
|
||||||
|
|
||||||
#ifndef MEDIA_MP4_SYNC_SAMPLE_ITERATOR_H_
|
#ifndef MEDIA_MP4_SYNC_SAMPLE_ITERATOR_H_
|
||||||
#define MEDIA_MP4_SYNC_SAMPLE_ITERATOR_H_
|
#define MEDIA_MP4_SYNC_SAMPLE_ITERATOR_H_
|
||||||
|
@ -17,20 +14,22 @@
|
||||||
namespace media {
|
namespace media {
|
||||||
namespace mp4 {
|
namespace mp4 {
|
||||||
|
|
||||||
// Sample to Chunk Box (STSS) Iterator.
|
/// Sync sample box (STSS) iterator used to iterate through the entries within
|
||||||
|
/// the compressed table.
|
||||||
class SyncSampleIterator {
|
class SyncSampleIterator {
|
||||||
public:
|
public:
|
||||||
|
/// Create a new SyncSampleIterator from sync sample box.
|
||||||
explicit SyncSampleIterator(const SyncSample& sync_sample);
|
explicit SyncSampleIterator(const SyncSample& sync_sample);
|
||||||
~SyncSampleIterator();
|
~SyncSampleIterator();
|
||||||
|
|
||||||
// Advance the properties to refer to the next sample. Return status
|
/// Advance to the next sample.
|
||||||
// indicating whether the sample is still valid.
|
/// @return true if not past the last sample, false otherwise.
|
||||||
bool AdvanceSample();
|
bool AdvanceSample();
|
||||||
|
|
||||||
// Return whether the current sample is a sync sample.
|
/// @return true if the current sample is a sync sample, false otherwise.
|
||||||
bool IsSyncSample() const;
|
bool IsSyncSample() const;
|
||||||
|
|
||||||
// Return whether sample (1-based) is a sync sample.
|
/// @return true if @a sample (1-based) is a sync sample, false otherwise.
|
||||||
bool IsSyncSample(uint32 sample) const;
|
bool IsSyncSample(uint32 sample) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -22,66 +22,82 @@ struct TrackRunInfo;
|
||||||
|
|
||||||
class TrackRunIterator {
|
class TrackRunIterator {
|
||||||
public:
|
public:
|
||||||
// Create a new TrackRunIterator. A reference to |moov| will be retained for
|
/// Create a new TrackRunIterator from movie box.
|
||||||
// the lifetime of this object.
|
/// @param moov should not be NULL.
|
||||||
explicit TrackRunIterator(const Movie* moov);
|
explicit TrackRunIterator(const Movie* moov);
|
||||||
~TrackRunIterator();
|
~TrackRunIterator();
|
||||||
|
|
||||||
// For non-fragmented mp4, moov contains all the chunks information; This
|
/// For non-fragmented mp4, moov contains all the chunk information; This
|
||||||
// function sets up the iterator to handle all the chunks.
|
/// function sets up the iterator to access all the chunks.
|
||||||
// For fragmented mp4, chunk and sample information are generally contained
|
/// For fragmented mp4, chunk and sample information are generally contained
|
||||||
// in moof. This function is a no-op in this case. Init(moof) will be called
|
/// in moof. This function is a no-op in this case. Init(moof) will be called
|
||||||
// later after parsing moof.
|
/// later after parsing moof.
|
||||||
|
/// @return true on success, false otherwise.
|
||||||
bool Init();
|
bool Init();
|
||||||
|
|
||||||
// Sets up the iterator to handle all the runs from the current fragment.
|
/// Set up the iterator to handle all the runs from the current fragment.
|
||||||
|
/// @return true on success, false otherwise.
|
||||||
bool Init(const MovieFragment& moof);
|
bool Init(const MovieFragment& moof);
|
||||||
|
|
||||||
// Returns true if the properties of the current run or sample are valid.
|
/// @return true if the iterator points to a valid run, false if past the
|
||||||
|
/// last run.
|
||||||
bool IsRunValid() const;
|
bool IsRunValid() const;
|
||||||
|
/// @return true if the iterator points to a valid sample, false if past the
|
||||||
|
/// last sample.
|
||||||
bool IsSampleValid() const;
|
bool IsSampleValid() const;
|
||||||
|
|
||||||
// Advance the properties to refer to the next run or sample. Requires that
|
/// Advance iterator to the next run. Require that the iterator point to a
|
||||||
// the current sample be valid.
|
/// valid run.
|
||||||
void AdvanceRun();
|
void AdvanceRun();
|
||||||
|
/// Advance iterator to the next sample. Require that the iterator point to a
|
||||||
|
/// valid sample.
|
||||||
void AdvanceSample();
|
void AdvanceSample();
|
||||||
|
|
||||||
// Returns true if this track run has auxiliary information and has not yet
|
/// @return true if this track run has auxiliary information and has not yet
|
||||||
// been cached. Only valid if IsRunValid().
|
/// been cached. Only valid if IsRunValid().
|
||||||
bool AuxInfoNeedsToBeCached();
|
bool AuxInfoNeedsToBeCached();
|
||||||
|
|
||||||
// Caches the CENC data from the given buffer. |buf| must be a buffer starting
|
/// Caches the CENC data from the given buffer.
|
||||||
// at the offset given by cenc_offset(), with a |size| of at least
|
/// @param buf must be a buffer starting at the offset given by cenc_offset().
|
||||||
// cenc_size(). Returns true on success, false on error.
|
/// @param size must be at least cenc_size().
|
||||||
|
/// @return true on success, false on error.
|
||||||
bool CacheAuxInfo(const uint8* buf, int size);
|
bool CacheAuxInfo(const uint8* buf, int size);
|
||||||
|
|
||||||
// Returns the maximum buffer location at which no data earlier in the stream
|
/// @return the maximum buffer location at which no data earlier in the
|
||||||
// will be required in order to read the current or any subsequent sample. You
|
/// stream will be required in order to read the current or any
|
||||||
// may clear all data up to this offset before reading the current sample
|
/// subsequent sample. You may clear all data up to this offset
|
||||||
// safely. Result is in the same units as offset() (for Media Source this is
|
/// before reading the current sample safely. Result is in the same
|
||||||
// in bytes past the the head of the MOOF box).
|
/// units as offset() (for Media Source this is in bytes past the
|
||||||
|
/// head of the MOOF box).
|
||||||
int64 GetMaxClearOffset();
|
int64 GetMaxClearOffset();
|
||||||
|
|
||||||
// Property of the current run. Only valid if IsRunValid().
|
/// @name Properties of the current run. Only valid if IsRunValid().
|
||||||
|
/// @{
|
||||||
uint32 track_id() const;
|
uint32 track_id() const;
|
||||||
int64 aux_info_offset() const;
|
int64 aux_info_offset() const;
|
||||||
int aux_info_size() const;
|
int aux_info_size() const;
|
||||||
bool is_encrypted() const;
|
bool is_encrypted() const;
|
||||||
bool is_audio() const;
|
bool is_audio() const;
|
||||||
// Only one is valid, based on the value of is_audio().
|
/// @}
|
||||||
|
|
||||||
|
/// @name Only one is valid, based on the value of is_audio().
|
||||||
|
/// @{
|
||||||
const AudioSampleEntry& audio_description() const;
|
const AudioSampleEntry& audio_description() const;
|
||||||
const VideoSampleEntry& video_description() const;
|
const VideoSampleEntry& video_description() const;
|
||||||
|
/// @}
|
||||||
|
|
||||||
// Properties of the current sample. Only valid if IsSampleValid().
|
/// @name Properties of the current sample. Only valid if IsSampleValid().
|
||||||
|
/// @{
|
||||||
int64 sample_offset() const;
|
int64 sample_offset() const;
|
||||||
int sample_size() const;
|
int sample_size() const;
|
||||||
int64 dts() const;
|
int64 dts() const;
|
||||||
int64 cts() const;
|
int64 cts() const;
|
||||||
int64 duration() const;
|
int64 duration() const;
|
||||||
bool is_keyframe() const;
|
bool is_keyframe() const;
|
||||||
|
/// @}
|
||||||
|
|
||||||
// Only call when is_encrypted() is true and AuxInfoNeedsToBeCached() is
|
/// Only call when is_encrypted() is true and AuxInfoNeedsToBeCached() is
|
||||||
// false. Result is owned by caller.
|
/// false. Result is owned by caller.
|
||||||
scoped_ptr<DecryptConfig> GetDecryptConfig();
|
scoped_ptr<DecryptConfig> GetDecryptConfig();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in New Issue