From 5a84b6ca941fac799714fd862d4d3ca94f58d614 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 2 Feb 2017 12:36:48 +0800 Subject: [PATCH] for #738, complete all mp4 boxes codec. --- trunk/src/kernel/srs_kernel_mp4.cpp | 192 ++++++++++++++++++++++++++-- trunk/src/kernel/srs_kernel_mp4.hpp | 35 ++++- 2 files changed, 207 insertions(+), 20 deletions(-) diff --git a/trunk/src/kernel/srs_kernel_mp4.cpp b/trunk/src/kernel/srs_kernel_mp4.cpp index 2e1f3c603..2b82c77d9 100644 --- a/trunk/src/kernel/srs_kernel_mp4.cpp +++ b/trunk/src/kernel/srs_kernel_mp4.cpp @@ -61,7 +61,9 @@ using namespace std; #define SRS_MP4_BOX_STSS 0x73747373 // 'stss' #define SRS_MP4_BOX_STSC 0x73747363 // 'stsc' #define SRS_MP4_BOX_STCO 0x7374636f // 'stco' +#define SRS_MP4_BOX_CO64 0x636f3634 // 'co64' #define SRS_MP4_BOX_STSZ 0x7374737a // 'stsz' +#define SRS_MP4_BOX_STZ2 0x73747a32 // 'stz2' #define SRS_MP4_EOF_SIZE 0 #define SRS_MP4_USE_LARGE_SIZE 1 @@ -192,6 +194,7 @@ int SrsMp4Box::discovery(SrsBuffer* buf, SrsMp4Box** ppbox) case SRS_MP4_BOX_STSS: box = new SrsMp4SyncSampleBox(); break; case SRS_MP4_BOX_STSC: box = new SrsMp4Sample2ChunkBox(); break; case SRS_MP4_BOX_STCO: box = new SrsMp4ChunkOffsetBox(); break; + case SRS_MP4_BOX_CO64: box = new SrsMp4ChunkLargeOffsetBox(); break; case SRS_MP4_BOX_STSZ: box = new SrsMp4SampleSizeBox(); break; default: ret = ERROR_MP4_BOX_ILLEGAL_TYPE; @@ -1420,18 +1423,16 @@ int SrsMp4DataReferenceBox::decode_header(SrsBuffer* buf) return ret; } - int left = left_space(buf); - while (left > 0) { + uint32_t nb_entries = buf->read_4bytes(); + for (uint32_t i = 0; i < nb_entries; i++) { SrsMp4Box* box = NULL; if ((ret = SrsMp4Box::discovery(buf, &box)) != ERROR_SUCCESS) { return ret; } - int pos = buf->pos(); if ((ret = box->decode(buf)) != ERROR_SUCCESS) { return ret; } - left -= buf->pos() - pos; SrsMp4FullBox* fbox = dynamic_cast(box); if (fbox) { @@ -1660,6 +1661,8 @@ int SrsMp4SampleDescriptionBox::nb_header() { int size = SrsMp4FullBox::nb_header(); + size += 4; + vector::iterator it; for (it = entries.begin(); it != entries.end(); ++it) { SrsMp4SampleEntry* entry = *it; @@ -1677,6 +1680,8 @@ int SrsMp4SampleDescriptionBox::encode_header(SrsBuffer* buf) return ret; } + buf->write_4bytes(entry_count()); + vector::iterator it; for (it = entries.begin(); it != entries.end(); ++it) { SrsMp4SampleEntry* entry = *it; @@ -1696,18 +1701,16 @@ int SrsMp4SampleDescriptionBox::decode_header(SrsBuffer* buf) return ret; } - int left = left_space(buf); - while (left > 0) { + uint32_t nb_entries = buf->read_4bytes(); + for (uint32_t i = 0; i < nb_entries; i++) { SrsMp4Box* box = NULL; if ((ret = SrsMp4Box::discovery(buf, &box)) != ERROR_SUCCESS) { return ret; } - int pos = buf->pos(); if ((ret = box->decode(buf)) != ERROR_SUCCESS) { return ret; } - left -= buf->pos() - pos; SrsMp4SampleEntry* entry = dynamic_cast(box); if (entry) { @@ -1741,7 +1744,7 @@ SrsMp4DecodingTime2SampleBox::~SrsMp4DecodingTime2SampleBox() int SrsMp4DecodingTime2SampleBox::nb_header() { - return SrsMp4FullBox::nb_header(); + return SrsMp4FullBox::nb_header() + 4 + 8*entry_count; } int SrsMp4DecodingTime2SampleBox::encode_header(SrsBuffer* buf) @@ -1752,6 +1755,13 @@ int SrsMp4DecodingTime2SampleBox::encode_header(SrsBuffer* buf) return ret; } + buf->write_4bytes(entry_count); + for (uint32_t i = 0; i < entry_count; i++) { + SrsMp4SttsEntry& entry = entries[i]; + buf->write_4bytes(entry.sample_count); + buf->write_4bytes(entry.sample_delta); + } + return ret; } @@ -1763,6 +1773,16 @@ int SrsMp4DecodingTime2SampleBox::decode_header(SrsBuffer* buf) return ret; } + entry_count = buf->read_4bytes(); + if (entry_count) { + entries = new SrsMp4SttsEntry[entry_count]; + } + for (uint32_t i = 0; i < entry_count; i++) { + SrsMp4SttsEntry& entry = entries[i]; + entry.sample_count = buf->read_4bytes(); + entry.sample_delta = buf->read_4bytes(); + } + return ret; } @@ -1787,7 +1807,7 @@ SrsMp4CompositionTime2SampleBox::~SrsMp4CompositionTime2SampleBox() int SrsMp4CompositionTime2SampleBox::nb_header() { - return SrsMp4FullBox::nb_header(); + return SrsMp4FullBox::nb_header() + 4 + 8*entry_count; } int SrsMp4CompositionTime2SampleBox::encode_header(SrsBuffer* buf) @@ -1798,6 +1818,17 @@ int SrsMp4CompositionTime2SampleBox::encode_header(SrsBuffer* buf) return ret; } + buf->write_4bytes(entry_count); + for (uint32_t i = 0; i < entry_count; i++) { + SrsMp4CttsEntry& entry = entries[i]; + buf->write_4bytes(entry.sample_count); + if (version == 0) { + buf->write_4bytes((uint32_t)entry.sample_offset); + } else if (version == 1) { + buf->write_4bytes((int32_t)entry.sample_offset); + } + } + return ret; } @@ -1809,6 +1840,20 @@ int SrsMp4CompositionTime2SampleBox::decode_header(SrsBuffer* buf) return ret; } + entry_count = buf->read_4bytes(); + if (entry_count) { + entries = new SrsMp4CttsEntry[entry_count]; + } + for (uint32_t i = 0; i < entry_count; i++) { + SrsMp4CttsEntry& entry = entries[i]; + entry.sample_count = buf->read_4bytes(); + if (version == 0) { + entry.sample_offset = (uint32_t)buf->read_4bytes(); + } else if (version == 1) { + entry.sample_offset = (int32_t)buf->read_4bytes(); + } + } + return ret; } @@ -1827,7 +1872,7 @@ SrsMp4SyncSampleBox::~SrsMp4SyncSampleBox() int SrsMp4SyncSampleBox::nb_header() { - return SrsMp4FullBox::nb_header(); + return SrsMp4FullBox::nb_header() +4 +4*entry_count; } int SrsMp4SyncSampleBox::encode_header(SrsBuffer* buf) @@ -1838,6 +1883,12 @@ int SrsMp4SyncSampleBox::encode_header(SrsBuffer* buf) return ret; } + buf->write_4bytes(entry_count); + for (uint32_t i = 0; i < entry_count; i++) { + uint32_t sample_number = sample_numbers[i]; + buf->write_4bytes(sample_number); + } + return ret; } @@ -1849,6 +1900,15 @@ int SrsMp4SyncSampleBox::decode_header(SrsBuffer* buf) return ret; } + entry_count = buf->read_4bytes(); + if (entry_count > 0) { + sample_numbers = new uint32_t[entry_count]; + } + for (uint32_t i = 0; i < entry_count; i++) { + uint32_t sample_number = sample_numbers[i]; + buf->write_4bytes(sample_number); + } + return ret; } @@ -1874,7 +1934,7 @@ SrsMp4Sample2ChunkBox::~SrsMp4Sample2ChunkBox() int SrsMp4Sample2ChunkBox::nb_header() { - return SrsMp4FullBox::nb_header(); + return SrsMp4FullBox::nb_header() +4 + 12*entry_count; } int SrsMp4Sample2ChunkBox::encode_header(SrsBuffer* buf) @@ -1885,6 +1945,14 @@ int SrsMp4Sample2ChunkBox::encode_header(SrsBuffer* buf) return ret; } + buf->write_4bytes(entry_count); + for (uint32_t i = 0; i < entry_count; i++) { + SrsMp4StscEntry& entry = entries[i]; + buf->write_4bytes(entry.first_chunk); + buf->write_4bytes(entry.samples_per_chunk); + buf->write_4bytes(entry.sample_description_index); + } + return ret; } @@ -1896,6 +1964,17 @@ int SrsMp4Sample2ChunkBox::decode_header(SrsBuffer* buf) return ret; } + entry_count = buf->read_4bytes(); + if (entry_count) { + entries = new SrsMp4StscEntry[entry_count]; + } + for (uint32_t i = 0; i < entry_count; i++) { + SrsMp4StscEntry& entry = entries[i]; + entry.first_chunk = buf->read_4bytes(); + entry.samples_per_chunk = buf->read_4bytes(); + entry.sample_description_index = buf->read_4bytes(); + } + return ret; } @@ -1914,7 +1993,7 @@ SrsMp4ChunkOffsetBox::~SrsMp4ChunkOffsetBox() int SrsMp4ChunkOffsetBox::nb_header() { - return SrsMp4FullBox::nb_header(); + return SrsMp4FullBox::nb_header() +4 +4*entry_count; } int SrsMp4ChunkOffsetBox::encode_header(SrsBuffer* buf) @@ -1925,6 +2004,11 @@ int SrsMp4ChunkOffsetBox::encode_header(SrsBuffer* buf) return ret; } + buf->write_4bytes(entry_count); + for (uint32_t i = 0; i < entry_count; i++) { + buf->write_4bytes(entries[i]); + } + return ret; } @@ -1936,6 +2020,67 @@ int SrsMp4ChunkOffsetBox::decode_header(SrsBuffer* buf) return ret; } + entry_count = buf->read_4bytes(); + if (entry_count) { + entries = new uint32_t[entry_count]; + } + for (uint32_t i = 0; i < entry_count; i++) { + entries[i] = buf->read_4bytes(); + } + + return ret; +} + +SrsMp4ChunkLargeOffsetBox::SrsMp4ChunkLargeOffsetBox() +{ + type = SRS_MP4_BOX_CO64; + + entry_count = 0; + entries = NULL; +} + +SrsMp4ChunkLargeOffsetBox::~SrsMp4ChunkLargeOffsetBox() +{ + srs_freepa(entries); +} + +int SrsMp4ChunkLargeOffsetBox::nb_header() +{ + return SrsMp4FullBox::nb_header() +4 +8*entry_count; +} + +int SrsMp4ChunkLargeOffsetBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + buf->write_4bytes(entry_count); + for (uint32_t i = 0; i < entry_count; i++) { + buf->write_8bytes(entries[i]); + } + + return ret; +} + +int SrsMp4ChunkLargeOffsetBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + entry_count = buf->read_4bytes(); + if (entry_count) { + entries = new uint64_t[entry_count]; + } + for (uint32_t i = 0; i < entry_count; i++) { + entries[i] = buf->read_8bytes(); + } + return ret; } @@ -1954,7 +2099,11 @@ SrsMp4SampleSizeBox::~SrsMp4SampleSizeBox() int SrsMp4SampleSizeBox::nb_header() { - return SrsMp4FullBox::nb_header(); + int size = SrsMp4FullBox::nb_header() +4+4; + if (sample_size == 0) { + size += 4*sample_count; + } + return size; } int SrsMp4SampleSizeBox::encode_header(SrsBuffer* buf) @@ -1965,6 +2114,12 @@ int SrsMp4SampleSizeBox::encode_header(SrsBuffer* buf) return ret; } + buf->write_4bytes(sample_size); + buf->write_4bytes(sample_count); + for (uint32_t i = 0; i < sample_count && sample_size == 0; i++) { + buf->write_4bytes(entry_sizes[i]); + } + return ret; } @@ -1976,6 +2131,15 @@ int SrsMp4SampleSizeBox::decode_header(SrsBuffer* buf) return ret; } + sample_size = buf->read_4bytes(); + sample_count = buf->read_4bytes(); + if (sample_size == 0) { + entry_sizes = new uint32_t[sample_count]; + } + for (uint32_t i = 0; i < sample_count && sample_size == 0; i++) { + entry_sizes[i] = buf->read_4bytes(); + } + return ret; } diff --git a/trunk/src/kernel/srs_kernel_mp4.hpp b/trunk/src/kernel/srs_kernel_mp4.hpp index b1da800dc..cb51140b0 100644 --- a/trunk/src/kernel/srs_kernel_mp4.hpp +++ b/trunk/src/kernel/srs_kernel_mp4.hpp @@ -761,7 +761,6 @@ protected: virtual int decode_header(SrsBuffer* buf); }; - /** * 8.6.1.3 Composition Time to Sample Box (ctts), for Video. * ISO_IEC_14496-12-base-format-2012.pdf, page 49 @@ -872,7 +871,7 @@ protected: }; /** - * 8.7.5 Chunk Offset Box (stco or co64), for Audio/Video. + * 8.7.5 Chunk Offset Box (stco), for Audio/Video. * ISO_IEC_14496-12-base-format-2012.pdf, page 59 * The chunk offset table gives the index of each chunk into the containing file. There are two variants, permitting * the use of 32-bit or 64-bit offsets. The latter is useful when managing very large presentations. At most one of @@ -883,9 +882,9 @@ class SrsMp4ChunkOffsetBox : public SrsMp4FullBox public: // an integer that gives the number of entries in the following table uint32_t entry_count; - // a 32 or 64 bit integer that gives the offset of the start of a chunk into its containing + // a 32 bit integer that gives the offset of the start of a chunk into its containing // media file. - uint64_t* entries; + uint32_t* entries; public: SrsMp4ChunkOffsetBox(); virtual ~SrsMp4ChunkOffsetBox(); @@ -896,8 +895,32 @@ protected: }; /** - * 8.7.3 Sample Size Boxes (stsz or stz2), for Audio/Video. - * ISO_IEC_14496-12-base-format-2012.pdf, page 57 + * 8.7.5 Chunk Large Offset Box (co64), for Audio/Video. + * ISO_IEC_14496-12-base-format-2012.pdf, page 59 + * The chunk offset table gives the index of each chunk into the containing file. There are two variants, permitting + * the use of 32-bit or 64-bit offsets. The latter is useful when managing very large presentations. At most one of + * these variants will occur in any single instance of a sample table. + */ +class SrsMp4ChunkLargeOffsetBox : public SrsMp4FullBox +{ +public: + // an integer that gives the number of entries in the following table + uint32_t entry_count; + // a 64 bit integer that gives the offset of the start of a chunk into its containing + // media file. + uint64_t* entries; +public: + SrsMp4ChunkLargeOffsetBox(); + virtual ~SrsMp4ChunkLargeOffsetBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); +}; + +/** + * 8.7.3.2 Sample Size Box (stsz), for Audio/Video. + * ISO_IEC_14496-12-base-format-2012.pdf, page 58 * This box contains the sample count and a table giving the size in bytes of each sample. This allows the media data * itself to be unframed. The total number of samples in the media is always indicated in the sample count. */