For #821, support parse dash video segment

pull/908/head
winlin 8 years ago
parent 8cc3ab2fa2
commit baed1cc043

@ -409,6 +409,13 @@ int SrsMp4Box::discovery(SrsBuffer* buf, SrsMp4Box** ppbox)
case SrsMp4BoxTypeUDTA: box = new SrsMp4UserDataBox(); break;
case SrsMp4BoxTypeMVEX: box = new SrsMp4MovieExtendsBox(); break;
case SrsMp4BoxTypeTREX: box = new SrsMp4TrackExtendsBox(); break;
case SrsMp4BoxTypeSTYP: box = new SrsMp4SegmentTypeBox(); break;
case SrsMp4BoxTypeMOOF: box = new SrsMp4MovieFragmentBox(); break;
case SrsMp4BoxTypeMFHD: box = new SrsMp4MovieFragmentHeaderBox(); break;
case SrsMp4BoxTypeTRAF: box = new SrsMp4TrackFragmentBox(); break;
case SrsMp4BoxTypeTFHD: box = new SrsMp4TrackFragmentHeaderBox(); break;
case SrsMp4BoxTypeTFDT: box = new SrsMp4TrackFragmentDecodeTimeBox(); break;
case SrsMp4BoxTypeTRUN: box = new SrsMp4TrackFragmentRunBox(); break;
// Skip some unknown boxes.
case SrsMp4BoxTypeFREE: case SrsMp4BoxTypeSKIP: case SrsMp4BoxTypePASP:
box = new SrsMp4FreeSpaceBox(type); break;
@ -810,6 +817,478 @@ stringstream& SrsMp4FileTypeBox::dumps_detail(stringstream& ss, SrsMp4DumpContex
return ss;
}
SrsMp4SegmentTypeBox::SrsMp4SegmentTypeBox()
{
type = SrsMp4BoxTypeSTYP;
}
SrsMp4SegmentTypeBox::~SrsMp4SegmentTypeBox()
{
}
SrsMp4MovieFragmentBox::SrsMp4MovieFragmentBox()
{
type = SrsMp4BoxTypeMOOF;
}
SrsMp4MovieFragmentBox::~SrsMp4MovieFragmentBox()
{
}
SrsMp4MovieFragmentHeaderBox::SrsMp4MovieFragmentHeaderBox()
{
type = SrsMp4BoxTypeMFHD;
sequence_number = 0;
}
SrsMp4MovieFragmentHeaderBox::~SrsMp4MovieFragmentHeaderBox()
{
}
int SrsMp4MovieFragmentHeaderBox::nb_header()
{
return SrsMp4FullBox::nb_header() + 4;
}
int SrsMp4MovieFragmentHeaderBox::encode_header(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
buf->write_4bytes(sequence_number);
return ret;
}
int SrsMp4MovieFragmentHeaderBox::decode_header(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
sequence_number = buf->read_4bytes();
return ret;
}
stringstream& SrsMp4MovieFragmentHeaderBox::dumps_detail(stringstream& ss, SrsMp4DumpContext dc)
{
SrsMp4FullBox::dumps_detail(ss, dc);
ss << ", sequence=" << sequence_number;
return ss;
}
SrsMp4TrackFragmentBox::SrsMp4TrackFragmentBox()
{
type = SrsMp4BoxTypeTRAF;
}
SrsMp4TrackFragmentBox::~SrsMp4TrackFragmentBox()
{
}
SrsMp4TrackFragmentHeaderBox::SrsMp4TrackFragmentHeaderBox()
{
type = SrsMp4BoxTypeTFHD;
flags = 0;
base_data_offset = 0;
track_id = sample_description_index = 0;
default_sample_duration = default_sample_size = 0;
default_sample_flags = 0;
}
SrsMp4TrackFragmentHeaderBox::~SrsMp4TrackFragmentHeaderBox()
{
}
int SrsMp4TrackFragmentHeaderBox::nb_header()
{
int size = SrsMp4FullBox::nb_header() + 4;
if ((flags&SrsMp4TfhdFlagsBaseDataOffset) == SrsMp4TfhdFlagsBaseDataOffset) {
size += 8;
}
if ((flags&SrsMp4TfhdFlagsSampleDescriptionIndex) == SrsMp4TfhdFlagsSampleDescriptionIndex) {
size += 4;
}
if ((flags&SrsMp4TfhdFlagsDefaultSampleDuration) == SrsMp4TfhdFlagsDefaultSampleDuration) {
size += 4;
}
if ((flags&SrsMp4TfhdFlagsDefautlSampleSize) == SrsMp4TfhdFlagsDefautlSampleSize) {
size += 4;
}
if ((flags&SrsMp4TfhdFlagsDefaultSampleFlags) == SrsMp4TfhdFlagsDefaultSampleFlags) {
size += 4;
}
return size;
}
int SrsMp4TrackFragmentHeaderBox::encode_header(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
buf->write_4bytes(track_id);
if ((flags&SrsMp4TfhdFlagsBaseDataOffset) == SrsMp4TfhdFlagsBaseDataOffset) {
buf->write_8bytes(base_data_offset);
}
if ((flags&SrsMp4TfhdFlagsSampleDescriptionIndex) == SrsMp4TfhdFlagsSampleDescriptionIndex) {
buf->write_4bytes(sample_description_index);
}
if ((flags&SrsMp4TfhdFlagsDefaultSampleDuration) == SrsMp4TfhdFlagsDefaultSampleDuration) {
buf->write_4bytes(default_sample_duration);
}
if ((flags&SrsMp4TfhdFlagsDefautlSampleSize) == SrsMp4TfhdFlagsDefautlSampleSize) {
buf->write_4bytes(default_sample_size);
}
if ((flags&SrsMp4TfhdFlagsDefaultSampleFlags) == SrsMp4TfhdFlagsDefaultSampleFlags) {
buf->write_4bytes(default_sample_flags);
}
return ret;
}
int SrsMp4TrackFragmentHeaderBox::decode_header(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
track_id = buf->read_4bytes();
if ((flags&SrsMp4TfhdFlagsBaseDataOffset) == SrsMp4TfhdFlagsBaseDataOffset) {
base_data_offset = buf->read_8bytes();
}
if ((flags&SrsMp4TfhdFlagsSampleDescriptionIndex) == SrsMp4TfhdFlagsSampleDescriptionIndex) {
sample_description_index = buf->read_4bytes();
}
if ((flags&SrsMp4TfhdFlagsDefaultSampleDuration) == SrsMp4TfhdFlagsDefaultSampleDuration) {
default_sample_duration = buf->read_4bytes();
}
if ((flags&SrsMp4TfhdFlagsDefautlSampleSize) == SrsMp4TfhdFlagsDefautlSampleSize) {
default_sample_size = buf->read_4bytes();
}
if ((flags&SrsMp4TfhdFlagsDefaultSampleFlags) == SrsMp4TfhdFlagsDefaultSampleFlags) {
default_sample_flags = buf->read_4bytes();
}
return ret;
}
stringstream& SrsMp4TrackFragmentHeaderBox::dumps_detail(stringstream& ss, SrsMp4DumpContext dc)
{
SrsMp4FullBox::dumps_detail(ss, dc);
ss << ", track=" << track_id;
if ((flags&SrsMp4TfhdFlagsBaseDataOffset) == SrsMp4TfhdFlagsBaseDataOffset) {
ss << ", bdo=" << base_data_offset;
}
if ((flags&SrsMp4TfhdFlagsSampleDescriptionIndex) == SrsMp4TfhdFlagsSampleDescriptionIndex) {
ss << ", sdi=" << sample_description_index;
}
if ((flags&SrsMp4TfhdFlagsDefaultSampleDuration) == SrsMp4TfhdFlagsDefaultSampleDuration) {
ss << ", dsu=" << default_sample_duration;
}
if ((flags&SrsMp4TfhdFlagsDefautlSampleSize) == SrsMp4TfhdFlagsDefautlSampleSize) {
ss << ", dss=" << default_sample_size;
}
if ((flags&SrsMp4TfhdFlagsDefaultSampleFlags) == SrsMp4TfhdFlagsDefaultSampleFlags) {
ss << ", dsf=" << default_sample_flags;
}
return ss;
}
SrsMp4TrackFragmentDecodeTimeBox::SrsMp4TrackFragmentDecodeTimeBox()
{
type = SrsMp4BoxTypeTFDT;
base_media_decode_time = 0;
}
SrsMp4TrackFragmentDecodeTimeBox::~SrsMp4TrackFragmentDecodeTimeBox()
{
}
int SrsMp4TrackFragmentDecodeTimeBox::nb_header()
{
return SrsMp4FullBox::nb_header() + (version? 8:4);
}
int SrsMp4TrackFragmentDecodeTimeBox::encode_header(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
if (version) {
buf->write_8bytes(base_media_decode_time);
} else {
buf->write_4bytes((uint32_t)base_media_decode_time);
}
return ret;
}
int SrsMp4TrackFragmentDecodeTimeBox::decode_header(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
if (version) {
base_media_decode_time = buf->read_8bytes();
} else {
base_media_decode_time = buf->read_4bytes();
}
return ret;
}
stringstream& SrsMp4TrackFragmentDecodeTimeBox::dumps_detail(stringstream& ss, SrsMp4DumpContext dc)
{
SrsMp4FullBox::dumps_detail(ss, dc);
ss << ", bmdt=" << base_media_decode_time;
return ss;
}
SrsMp4TrunEntry::SrsMp4TrunEntry(uint8_t v, uint32_t f)
{
flags = f;
version = v;
sample_duration = sample_size = sample_flags = 0;
sample_composition_time_offset = 0;
}
SrsMp4TrunEntry::~SrsMp4TrunEntry()
{
}
int SrsMp4TrunEntry::nb_header()
{
int size = 0;
if ((flags&SrsMp4TrunFlagsSampleDuration) == SrsMp4TrunFlagsSampleDuration) {
size += 4;
}
if ((flags&SrsMp4TrunFlagsSampleSize) == SrsMp4TrunFlagsSampleSize) {
size += 4;
}
if ((flags&SrsMp4TrunFlagsSampleFlag) == SrsMp4TrunFlagsSampleFlag) {
size += 4;
}
if ((flags&SrsMp4TrunFlagsSampleCtsOffset) == SrsMp4TrunFlagsSampleCtsOffset) {
size += 4;
}
return size;
}
int SrsMp4TrunEntry::encode_header(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
if ((flags&SrsMp4TrunFlagsSampleDuration) == SrsMp4TrunFlagsSampleDuration) {
buf->write_4bytes(sample_duration);
}
if ((flags&SrsMp4TrunFlagsSampleSize) == SrsMp4TrunFlagsSampleSize) {
buf->write_4bytes(sample_size);
}
if ((flags&SrsMp4TrunFlagsSampleFlag) == SrsMp4TrunFlagsSampleFlag) {
buf->write_4bytes(sample_flags);
}
if ((flags&SrsMp4TrunFlagsSampleCtsOffset) == SrsMp4TrunFlagsSampleCtsOffset) {
if (!version) {
uint32_t v = (uint32_t)sample_composition_time_offset;
buf->write_4bytes(v);
} else {
int32_t v = (int32_t)sample_composition_time_offset;
buf->write_4bytes(v);
}
}
return ret;
}
int SrsMp4TrunEntry::decode_header(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
if ((flags&SrsMp4TrunFlagsSampleDuration) == SrsMp4TrunFlagsSampleDuration) {
sample_duration = buf->read_4bytes();
}
if ((flags&SrsMp4TrunFlagsSampleSize) == SrsMp4TrunFlagsSampleSize) {
sample_size = buf->read_4bytes();
}
if ((flags&SrsMp4TrunFlagsSampleFlag) == SrsMp4TrunFlagsSampleFlag) {
sample_flags = buf->read_4bytes();
}
if ((flags&SrsMp4TrunFlagsSampleCtsOffset) == SrsMp4TrunFlagsSampleCtsOffset) {
if (!version) {
uint32_t v = buf->read_4bytes();
sample_composition_time_offset = v;
} else {
int32_t v = buf->read_4bytes();
sample_composition_time_offset = v;
}
}
return ret;
}
stringstream& SrsMp4TrunEntry::dumps_detail(stringstream& ss, SrsMp4DumpContext dc)
{
if ((flags&SrsMp4TrunFlagsSampleDuration) == SrsMp4TrunFlagsSampleDuration) {
ss << "duration=" << sample_duration;
}
if ((flags&SrsMp4TrunFlagsSampleSize) == SrsMp4TrunFlagsSampleSize) {
ss << ", size=" << sample_size;
}
if ((flags&SrsMp4TrunFlagsSampleFlag) == SrsMp4TrunFlagsSampleFlag) {
ss << ", flags=" << sample_flags;
}
if ((flags&SrsMp4TrunFlagsSampleCtsOffset) == SrsMp4TrunFlagsSampleCtsOffset) {
ss << ", cts-offset=" << sample_composition_time_offset;
}
return ss;
}
SrsMp4TrackFragmentRunBox::SrsMp4TrackFragmentRunBox()
{
type = SrsMp4BoxTypeTRUN;
sample_count = first_sample_flags = 0;
data_offset = 0;
}
SrsMp4TrackFragmentRunBox::~SrsMp4TrackFragmentRunBox()
{
vector<SrsMp4TrunEntry*>::iterator it;
for (it = entries.begin(); it != entries.end(); ++it) {
SrsMp4TrunEntry* entry = *it;
srs_freep(entry);
}
}
int SrsMp4TrackFragmentRunBox::nb_header()
{
int size = SrsMp4FullBox::nb_header() + 4;
if ((flags&SrsMp4TrunFlagsDataOffset) == SrsMp4TrunFlagsDataOffset) {
size += 4;
}
if ((flags&SrsMp4TrunFlagsFirstSample) == SrsMp4TrunFlagsFirstSample) {
size += 4;
}
vector<SrsMp4TrunEntry*>::iterator it;
for (it = entries.begin(); it != entries.end(); ++it) {
SrsMp4TrunEntry* entry = *it;
size += entry->nb_header();
}
return size;
}
int SrsMp4TrackFragmentRunBox::encode_header(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
buf->write_4bytes(sample_count);
if ((flags&SrsMp4TrunFlagsDataOffset) == SrsMp4TrunFlagsDataOffset) {
buf->write_4bytes(data_offset);
}
if ((flags&SrsMp4TrunFlagsFirstSample) == SrsMp4TrunFlagsFirstSample) {
buf->write_4bytes(first_sample_flags);
}
vector<SrsMp4TrunEntry*>::iterator it;
for (it = entries.begin(); it != entries.end(); ++it) {
SrsMp4TrunEntry* entry = *it;
if ((ret = entry->encode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
}
return ret;
}
int SrsMp4TrackFragmentRunBox::decode_header(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
sample_count = buf->read_4bytes();
if ((flags&SrsMp4TrunFlagsDataOffset) == SrsMp4TrunFlagsDataOffset) {
data_offset = buf->read_4bytes();
}
if ((flags&SrsMp4TrunFlagsFirstSample) == SrsMp4TrunFlagsFirstSample) {
first_sample_flags = buf->read_4bytes();
}
for (int i = 0; i < sample_count; i++) {
SrsMp4TrunEntry* entry = new SrsMp4TrunEntry(version, flags);
entries.push_back(entry);
if ((ret = entry->decode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
}
return ret;
}
stringstream& SrsMp4TrackFragmentRunBox::dumps_detail(stringstream& ss, SrsMp4DumpContext dc)
{
SrsMp4FullBox::dumps_detail(ss, dc);
ss << ", samples=" << sample_count;
if ((flags&SrsMp4TrunFlagsDataOffset) == SrsMp4TrunFlagsDataOffset) {
ss << ", do" << data_offset;
}
if ((flags&SrsMp4TrunFlagsFirstSample) == SrsMp4TrunFlagsFirstSample) {
ss << ", fsf=" << first_sample_flags;
}
if (sample_count > 0) {
ss << endl;
srs_padding(ss, dc.indent());
srs_dumps_array(entries, ss, dc.indent(), srs_pfn_pdetail, srs_delimiter_newline);
}
return ss;
}
SrsMp4MediaDataBox::SrsMp4MediaDataBox()
{
type = SrsMp4BoxTypeMDAT;

@ -111,8 +111,14 @@ enum SrsMp4BoxType
SrsMp4BoxTypeUDTA = 0x75647461, // 'udta'
SrsMp4BoxTypeMVEX = 0x6d766578, // 'mvex'
SrsMp4BoxTypeTREX = 0x74726578, // 'trex'
SrsMp4BoxTypePASP = 0x70617370, // 'pasp'
SrsMp4BoxTypeSTYP = 0x73747970, // 'styp'
SrsMp4BoxTypeMOOF = 0x6d6f6f66, // 'moof'
SrsMp4BoxTypeMFHD = 0x6d666864, // 'mfhd'
SrsMp4BoxTypeTRAF = 0x74726166, // 'traf'
SrsMp4BoxTypeTFHD = 0x74666864, // 'tfhd'
SrsMp4BoxTypeTFDT = 0x74666474, // 'tfdt'
SrsMp4BoxTypeTRUN = 0x7472756e, // 'trun'
};
/**
@ -290,6 +296,245 @@ public:
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
};
/**
* 8.16.2 Segment Type Box (styp)
* ISO_IEC_14496-12-base-format-2012.pdf, page 105
* If segments are stored in separate files (e.g. on a standard HTTP server) it is recommended that these
* 'segment files' contain a segment-type box, which must be first if present, to enable identification of those files,
* and declaration of the specifications with which they are compliant.
*/
class SrsMp4SegmentTypeBox : public SrsMp4FileTypeBox
{
public:
SrsMp4SegmentTypeBox();
virtual ~SrsMp4SegmentTypeBox();
};
/**
* 8.8.4 Movie Fragment Box (moof)
* ISO_IEC_14496-12-base-format-2012.pdf, page 66
* The movie fragments extend the presentation in time. They provide the information that would previously have
* been in the Movie Box. The actual samples are in Media Data Boxes, as usual, if they are in the same file.
* The data reference index is in the sample description, so it is possible to build incremental presentations
* where the media data is in files other than the file containing the Movie Box.
*/
class SrsMp4MovieFragmentBox : public SrsMp4Box
{
public:
SrsMp4MovieFragmentBox();
virtual ~SrsMp4MovieFragmentBox();
};
/**
* 8.8.5 Movie Fragment Header Box (mfhd)
* ISO_IEC_14496-12-base-format-2012.pdf, page 67
* The movie fragment header contains a sequence number, as a safety check. The sequence number usually
* starts at 1 and must increase for each movie fragment in the file, in the order in which they occur. This allows
* readers to verify integrity of the sequence; it is an error to construct a file where the fragments are out of
* sequence.
*/
class SrsMp4MovieFragmentHeaderBox : public SrsMp4FullBox
{
public:
// the ordinal number of this fragment, in increasing order
uint32_t sequence_number;
public:
SrsMp4MovieFragmentHeaderBox();
virtual ~SrsMp4MovieFragmentHeaderBox();
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
virtual int decode_header(SrsBuffer* buf);
public:
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
};
/**
* 8.8.6 Track Fragment Box (traf)
* ISO_IEC_14496-12-base-format-2012.pdf, page 67
* Within the movie fragment there is a set of track fragments, zero or more per track. The track fragments in
* turn contain zero or more track runs, each of which document a contiguous run of samples for that track.
* Within these structures, many fields are optional and can be defaulted.
*/
class SrsMp4TrackFragmentBox : public SrsMp4Box
{
public:
SrsMp4TrackFragmentBox();
virtual ~SrsMp4TrackFragmentBox();
};
/**
* The tf_flags of tfhd.
* ISO_IEC_14496-12-base-format-2012.pdf, page 68
*/
enum SrsMp4TfhdFlags
{
/**
* indicates the presence of the base-data-offset field. This provides
* an explicit anchor for the data offsets in each track run (see below). If not provided, the base-data-
* offset for the first track in the movie fragment is the position of the first byte of the enclosing Movie
* Fragment Box, and for second and subsequent track fragments, the default is the end of the data
* defined by the preceding fragment. Fragments 'inheriting' their offset in this way must all use
* the same data-reference (i.e., the data for these tracks must be in the same file).
*/
SrsMp4TfhdFlagsBaseDataOffset = 0x000001,
/**
* indicates the presence of this field, which over-rides, in this
* fragment, the default set up in the Track Extends Box.
*/
SrsMp4TfhdFlagsSampleDescriptionIndex = 0x000002,
SrsMp4TfhdFlagsDefaultSampleDuration = 0x000008,
SrsMp4TfhdFlagsDefautlSampleSize = 0x000010,
SrsMp4TfhdFlagsDefaultSampleFlags = 0x000020,
/**
* this indicates that the duration provided in either default-sample-duration,
* or by the default-duration in the Track Extends Box, is empty, i.e. that there are no samples for this
* time interval. It is an error to make a presentation that has both edit lists in the Movie Box, and empty-
* duration fragments.
*/
SrsMp4TfhdFlagsDurationIsEmpty = 0x010000,
/**
* if base-data-offset-present is zero, this indicates that the base-data-
* offset for this track fragment is the position of the first byte of the enclosing Movie Fragment Box.
* Support for the default-base-is-moof flag is required under the iso5 brand, and it shall not be used in
* brands or compatible brands earlier than iso5.
*/
SrsMp4TfhdFlagsDefaultBaseIsMoof = 0x020000,
};
/**
* 8.8.7 Track Fragment Header Box (tfhd)
* ISO_IEC_14496-12-base-format-2012.pdf, page 68
* Each movie fragment can add zero or more fragments to each track; and a track fragment can add zero or
* more contiguous runs of samples. The track fragment header sets up information and defaults used for those
* runs of samples.
*/
class SrsMp4TrackFragmentHeaderBox : public SrsMp4FullBox
{
public:
uint32_t track_id;
// all the following are optional fields
public:
// the base offset to use when calculating data offsets
uint64_t base_data_offset;
uint32_t sample_description_index;
uint32_t default_sample_duration;
uint32_t default_sample_size;
uint32_t default_sample_flags;
public:
SrsMp4TrackFragmentHeaderBox();
virtual ~SrsMp4TrackFragmentHeaderBox();
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
virtual int decode_header(SrsBuffer* buf);
public:
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
};
/**
* 8.8.12 Track fragment decode time (tfdt)
* ISO_IEC_14496-12-base-format-2012.pdf, page 72
* The Track Fragment Base Media Decode Time Box provides the absolute decode time, measured on
* the media timeline, of the first sample in decode order in the track fragment. This can be useful, for example,
* when performing random access in a file; it is not necessary to sum the sample durations of all preceding
* samples in previous fragments to find this value (where the sample durations are the deltas in the Decoding
* Time to Sample Box and the sample_durations in the preceding track runs).
*/
class SrsMp4TrackFragmentDecodeTimeBox : public SrsMp4FullBox
{
public:
uint64_t base_media_decode_time;
public:
SrsMp4TrackFragmentDecodeTimeBox();
virtual ~SrsMp4TrackFragmentDecodeTimeBox();
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
virtual int decode_header(SrsBuffer* buf);
public:
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
};
/**
* The tr_flags for trun
* ISO_IEC_14496-12-base-format-2012.pdf, page 69
*/
enum SrsMp4TrunFlags
{
// data-offset-present.
SrsMp4TrunFlagsDataOffset = 0x000001,
// this over-rides the default flags for the first sample only. This
// makes it possible to record a group of frames where the first is a key and the rest are difference
// frames, without supplying explicit flags for every sample. If this flag and field are used, sample-flags
// shall not be present.
SrsMp4TrunFlagsFirstSample = 0x000004,
// indicates that each sample has its own duration, otherwise the default is used.
SrsMp4TrunFlagsSampleDuration = 0x000100,
// each sample has its own size, otherwise the default is used.
SrsMp4TrunFlagsSampleSize = 0x000200,
// each sample has its own flags, otherwise the default is used.
SrsMp4TrunFlagsSampleFlag = 0x000400,
// each sample has a composition time offset (e.g. as used for I/P/B video in MPEG).
SrsMp4TrunFlagsSampleCtsOffset = 0x000800,
};
/**
* Entry for trun.
* ISO_IEC_14496-12-base-format-2012.pdf, page 69
*/
struct SrsMp4TrunEntry
{
uint8_t version;
uint32_t flags;
uint32_t sample_duration;
uint32_t sample_size;
uint32_t sample_flags;
// if version == 0, unsigned int(32); otherwise, signed int(32).
int64_t sample_composition_time_offset;
SrsMp4TrunEntry(uint8_t v, uint32_t f);
virtual ~SrsMp4TrunEntry();
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
virtual int decode_header(SrsBuffer* buf);
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
};
/**
* 8.8.8 Track Fragment Run Box (trun)
* ISO_IEC_14496-12-base-format-2012.pdf, page 69
* Within the Track Fragment Box, there are zero or more Track Run Boxes. If the duration-is-empty flag is set in
* the tf_flags, there are no track runs. A track run documents a contiguous set of samples for a track.
*/
class SrsMp4TrackFragmentRunBox : public SrsMp4FullBox
{
public:
// the number of samples being added in this run; also the number of rows in the following
// table (the rows can be empty)
uint32_t sample_count;
// the following are optional fields
public:
// added to the implicit or explicit data_offset established in the track fragment header.
int32_t data_offset;
// provides a set of flags for the first sample only of this run.
uint32_t first_sample_flags;
// all fields in the following array are optional
public:
std::vector<SrsMp4TrunEntry*> entries;
public:
SrsMp4TrackFragmentRunBox();
virtual ~SrsMp4TrackFragmentRunBox();
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
virtual int decode_header(SrsBuffer* buf);
public:
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
};
/**
* 8.1.1 Media Data Box (mdat)
* ISO_IEC_14496-12-base-format-2012.pdf, page 29

Loading…
Cancel
Save