diff --git a/trunk/src/kernel/srs_kernel_buffer.hpp b/trunk/src/kernel/srs_kernel_buffer.hpp index 32cff9c13..c506eac91 100644 --- a/trunk/src/kernel/srs_kernel_buffer.hpp +++ b/trunk/src/kernel/srs_kernel_buffer.hpp @@ -69,6 +69,7 @@ public: /** * get the number of bytes to code to. */ + // TODO: FIXME: change to uint64_t. virtual int nb_bytes() = 0; /** * encode object to bytes in SrsBuffer. diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index dcb49bf20..7baefa53b 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -242,6 +242,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define ERROR_REQUEST_DATA 3066 #define ERROR_EDGE_PORT_INVALID 3067 #define ERROR_EXPECT_FILE_IO 3068 +#define ERROR_MP4_BOX_OVERFLOW 3069 +#define ERROR_MP4_BOX_REQUIRE_SPACE 3070 +#define ERROR_MP4_BOX_ILLEGAL_TYPE 3071 +#define ERROR_MP4_BOX_ILLEGAL_SCHEMA 3072 +#define ERROR_MP4_BOX_STRING 3073 /////////////////////////////////////////////////////// // HTTP/StreamCaster/KAFKA protocol error. diff --git a/trunk/src/kernel/srs_kernel_flv.cpp b/trunk/src/kernel/srs_kernel_flv.cpp index 09cda642e..ada330915 100644 --- a/trunk/src/kernel/srs_kernel_flv.cpp +++ b/trunk/src/kernel/srs_kernel_flv.cpp @@ -721,6 +721,7 @@ int SrsFlvDecoder::read_header(char header[9]) srs_assert(header); + // TODO: FIXME: Should use readfully. if ((ret = reader->read(header, 9, NULL)) != ERROR_SUCCESS) { return ret; } @@ -746,6 +747,7 @@ int SrsFlvDecoder::read_tag_header(char* ptype, int32_t* pdata_size, uint32_t* p char th[11]; // tag header // read tag header + // TODO: FIXME: Should use readfully. if ((ret = reader->read(th, 11, NULL)) != ERROR_SUCCESS) { if (ret != ERROR_SYSTEM_FILE_EOF) { srs_error("read flv tag header failed. ret=%d", ret); @@ -783,6 +785,7 @@ int SrsFlvDecoder::read_tag_data(char* data, int32_t size) srs_assert(data); + // TODO: FIXME: Should use readfully. if ((ret = reader->read(data, size, NULL)) != ERROR_SUCCESS) { if (ret != ERROR_SYSTEM_FILE_EOF) { srs_error("read flv tag header failed. ret=%d", ret); @@ -801,6 +804,7 @@ int SrsFlvDecoder::read_previous_tag_size(char previous_tag_size[4]) srs_assert(previous_tag_size); // ignore 4bytes tag size. + // TODO: FIXME: Should use readfully. if ((ret = reader->read(previous_tag_size, 4, NULL)) != ERROR_SUCCESS) { if (ret != ERROR_SYSTEM_FILE_EOF) { srs_error("read flv previous tag size failed. ret=%d", ret); diff --git a/trunk/src/kernel/srs_kernel_io.hpp b/trunk/src/kernel/srs_kernel_io.hpp index 9bf9dd838..f2a18d04a 100644 --- a/trunk/src/kernel/srs_kernel_io.hpp +++ b/trunk/src/kernel/srs_kernel_io.hpp @@ -44,6 +44,10 @@ public: ISrsReader(); virtual ~ISrsReader(); public: + /** + * Read bytes from reader. + * @param nread How many bytes read from channel. NULL to ignore. + */ virtual int read(void* buf, size_t size, ssize_t* nread) = 0; }; diff --git a/trunk/src/kernel/srs_kernel_mp4.cpp b/trunk/src/kernel/srs_kernel_mp4.cpp index 1d38ffec4..2e1f3c603 100644 --- a/trunk/src/kernel/srs_kernel_mp4.cpp +++ b/trunk/src/kernel/srs_kernel_mp4.cpp @@ -23,19 +23,380 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include -#include - #include #include +#include +#include +#include +#include + +#include +using namespace std; + +#define SRS_MP4_BOX_UUID 0x75756964 // 'uuid' +#define SRS_MP4_BOX_FTYP 0x66747970 // 'ftyp' +#define SRS_MP4_BOX_MDAT 0x6d646174 // 'mdat' +#define SRS_MP4_BOX_FREE 0x66726565 // 'free' +#define SRS_MP4_BOX_SKIP 0x736b6970 // 'skip' +#define SRS_MP4_BOX_MOOV 0x6d6f6f76 // 'moov' +#define SRS_MP4_BOX_MVHD 0x6d766864 // 'mvhd' +#define SRS_MP4_BOX_TRAK 0x7472616b // 'trak' +#define SRS_MP4_BOX_TKHD 0x746b6864 // 'tkhd' +#define SRS_MP4_BOX_EDTS 0x65647473 // 'edts' +#define SRS_MP4_BOX_ELST 0x656c7374 // 'elst' +#define SRS_MP4_BOX_MDIA 0x6d646961 // 'mdia' +#define SRS_MP4_BOX_MDHD 0x6d646864 // 'mdhd' +#define SRS_MP4_BOX_HDLR 0x68646c72 // 'hdlr' +#define SRS_MP4_BOX_MINF 0x6d696e66 // 'minf' +#define SRS_MP4_BOX_VMHD 0x766d6864 // 'vmhd' +#define SRS_MP4_BOX_SMHD 0x736d6864 // 'smhd' +#define SRS_MP4_BOX_DINF 0x64696e66 // 'dinf' +#define SRS_MP4_BOX_URL 0x75726c20 // 'url ' +#define SRS_MP4_BOX_URN 0x75726e20 // 'urn ' +#define SRS_MP4_BOX_DREF 0x64726566 // 'dref' +#define SRS_MP4_BOX_STBL 0x7374626c // 'stbl' +#define SRS_MP4_BOX_STSD 0x73747364 // 'stsd' +#define SRS_MP4_BOX_STTS 0x73747473 // 'stts' +#define SRS_MP4_BOX_CTTS 0x63747473 // 'ctts' +#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_STSZ 0x7374737a // 'stsz' + +#define SRS_MP4_EOF_SIZE 0 +#define SRS_MP4_USE_LARGE_SIZE 1 + +int srs_mp4_string_length(const string& v) +{ + return (int)v.length()+1; +} + +void srs_mp4_string_write(SrsBuffer* buf, const string& v) +{ + if (!v.empty()) { + buf->write_bytes((char*)v.data(), (int)v.length()); + } + buf->write_1bytes(0x00); +} + +int srs_mp4_string_read(SrsBuffer* buf, string& v, int left) +{ + int ret = ERROR_SUCCESS; + + char* p = buf->data() + buf->pos(); + + char* start = p; + while (p < start + left) { + if (*p == 0x00) { + v.append(start, p - start); + buf->skip((int)(p - start)); + return ret; + } + } + + ret = ERROR_MP4_BOX_STRING; + srs_error("MP4 string corrupt, left=%d. ret=%d", left, ret); + return ret; +} SrsMp4Box::SrsMp4Box() { - size = 0; + smallsize = 0; + largesize = 0; + usertype = NULL; + start_pos = 0; type = 0; } SrsMp4Box::~SrsMp4Box() { + vector::iterator it; + for (it = boxes.begin(); it != boxes.end(); ++it) { + SrsMp4Box* box = *it; + srs_freep(box); + } + boxes.clear(); + + srs_freepa(usertype); +} + +uint64_t SrsMp4Box::sz() +{ + return smallsize == SRS_MP4_USE_LARGE_SIZE? largesize:smallsize; +} + +int SrsMp4Box::left_space(SrsBuffer* buf) +{ + return (int)sz() - (buf->pos() - start_pos); +} + +int SrsMp4Box::discovery(SrsBuffer* buf, SrsMp4Box** ppbox) +{ + *ppbox = NULL; + + int ret = ERROR_SUCCESS; + + if (!buf->require(8)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 discovery require 8 bytes space. ret=%d", ret); + return ret; + } + + // Discovery the size and type. + uint64_t largesize = 0; + uint32_t smallsize = (uint32_t)buf->read_4bytes(); + uint32_t type = (uint32_t)buf->read_4bytes(); + if (smallsize == SRS_MP4_USE_LARGE_SIZE) { + if (!buf->require(8)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 discovery require 16 bytes space. ret=%d", ret); + return ret; + } + largesize = (uint64_t)buf->read_8bytes(); + buf->skip(-8); + } + buf->skip(-8); + + // Only support 31bits size. + if (largesize > 0x7fffffff) { + ret = ERROR_MP4_BOX_OVERFLOW; + srs_error("MP4 discovery overflow 31bits, size=%"PRId64". ret=%d", largesize, ret); + return ret; + } + + SrsMp4Box* box = NULL; + switch(type) { + case SRS_MP4_BOX_FTYP: box = new SrsMp4FileTypeBox(); break; + case SRS_MP4_BOX_MDAT: box = new SrsMp4MediaDataBox(); break; + case SRS_MP4_BOX_FREE: case SRS_MP4_BOX_SKIP: box = new SrsMp4FreeSpaceBox(); break; + case SRS_MP4_BOX_MOOV: box = new SrsMp4MovieBox(); break; + case SRS_MP4_BOX_MVHD: box = new SrsMp4MovieHeaderBox(); break; + case SRS_MP4_BOX_TRAK: box = new SrsMp4TrackBox(); break; + case SRS_MP4_BOX_TKHD: box = new SrsMp4TrackHeaderBox(); break; + case SRS_MP4_BOX_EDTS: box = new SrsMp4EditBox(); break; + case SRS_MP4_BOX_ELST: box = new SrsMp4EditListBox(); break; + case SRS_MP4_BOX_MDIA: box = new SrsMp4MediaBox(); break; + case SRS_MP4_BOX_MDHD: box = new SrsMp4MediaHeaderBox(); break; + case SRS_MP4_BOX_HDLR: box = new SrsMp4HandlerReferenceBox(); break; + case SRS_MP4_BOX_MINF: box = new SrsMp4MediaInformationBox(); break; + case SRS_MP4_BOX_VMHD: box = new SrsMp4VideoMeidaHeaderBox(); break; + case SRS_MP4_BOX_SMHD: box = new SrsMp4SoundMeidaHeaderBox(); break; + case SRS_MP4_BOX_DINF: box = new SrsMp4DataInformationBox(); break; + case SRS_MP4_BOX_URL: box = new SrsMp4DataEntryUrlBox(); break; + case SRS_MP4_BOX_URN: box = new SrsMp4DataEntryUrnBox(); break; + case SRS_MP4_BOX_DREF: box = new SrsMp4DataReferenceBox(); break; + case SRS_MP4_BOX_STBL: box = new SrsMp4SampleTableBox(); break; + case SRS_MP4_BOX_STSD: box = new SrsMp4SampleDescriptionBox(); break; + case SRS_MP4_BOX_STTS: box = new SrsMp4DecodingTime2SampleBox(); break; + case SRS_MP4_BOX_CTTS: box = new SrsMp4CompositionTime2SampleBox(); break; + 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_STSZ: box = new SrsMp4SampleSizeBox(); break; + default: + ret = ERROR_MP4_BOX_ILLEGAL_TYPE; + srs_error("MP4 illegal box type=%d. ret=%d", type, ret); + break; + } + + if (box) { + box->smallsize = smallsize; + box->largesize = largesize; + box->type = type; + *ppbox = box; + } + + return ret; +} + +int SrsMp4Box::nb_bytes() +{ + int sz = nb_header(); + + vector::iterator it; + for (it = boxes.begin(); it != boxes.end(); ++it) { + SrsMp4Box* box = *it; + sz += box->nb_bytes(); + } + + return sz; +} + +int SrsMp4Box::encode(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = encode_header(buf)) != ERROR_SUCCESS) { + srs_error("MP4 encode box header failed. ret=%d", ret); + return ret; + } + + if ((ret = encode_boxes(buf)) != ERROR_SUCCESS) { + srs_error("MP4 encode contained boxes failed. ret=%d", ret); + return ret; + } + + return ret; +} + +int SrsMp4Box::decode(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + start_pos = buf->pos(); + + if ((ret = decode_header(buf)) != ERROR_SUCCESS) { + srs_error("MP4 decode box header failed. ret=%d", ret); + return ret; + } + + if ((ret = decode_boxes(buf)) != ERROR_SUCCESS) { + srs_error("MP4 decode contained boxes failed. ret=%d", ret); + return ret; + } + + return ret; +} + +int SrsMp4Box::encode_boxes(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + vector::iterator it; + for (it = boxes.begin(); it != boxes.end(); ++it) { + SrsMp4Box* box = *it; + if ((ret = box->encode(buf)) != ERROR_SUCCESS) { + srs_error("MP4 encode contained box failed. ret=%d", ret); + return ret; + } + } + + return ret; +} + +int SrsMp4Box::decode_boxes(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + int left = left_space(buf); + while (left > 0) { + SrsMp4Box* box = NULL; + if ((ret = discovery(buf, &box)) != ERROR_SUCCESS) { + srs_error("MP4 discovery contained box failed. ret=%d", ret); + return ret; + } + + srs_assert(box); + if ((ret = box->decode(buf)) != ERROR_SUCCESS) { + srs_freep(box); + srs_error("MP4 decode contained box failed. ret=%d", ret); + return ret; + } + + boxes.push_back(box); + left -= box->sz(); + } + + return ret; +} + +int SrsMp4Box::nb_header() +{ + int size = 8; + if (smallsize == SRS_MP4_USE_LARGE_SIZE) { + size += 8; + } + + if (type == SRS_MP4_BOX_UUID) { + size += 16; + } + + return size; +} + +int SrsMp4Box::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + // Only support 31bits size. + if (sz() > 0x7fffffff) { + ret = ERROR_MP4_BOX_OVERFLOW; + srs_error("MP4 box size overflow 31bits, size=%"PRId64". ret=%d", sz(), ret); + return ret; + } + + int size = nb_header(); + if (!buf->require(size)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 box require %d bytes space. ret=%d", size, ret); + return ret; + } + + buf->write_4bytes(smallsize); + if (smallsize == SRS_MP4_USE_LARGE_SIZE) { + buf->write_8bytes(largesize); + } + buf->write_4bytes(type); + + if (type == SRS_MP4_BOX_UUID) { + buf->write_bytes((char*)usertype, 16); + } + + return ret; +} + +int SrsMp4Box::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if (!buf->require(8)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 box require 8 bytes space. ret=%d", ret); + return ret; + } + smallsize = (uint32_t)buf->read_4bytes(); + type = (uint32_t)buf->read_4bytes(); + + if (smallsize == SRS_MP4_EOF_SIZE) { + srs_warn("MP4 box EOF."); + return ret; + } + + if (smallsize == SRS_MP4_USE_LARGE_SIZE) { + if (!buf->require(8)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 box require 8 bytes space. ret=%d", ret); + return ret; + } + largesize = (uint64_t)buf->read_8bytes(); + } + + // Only support 31bits size. + if (sz() > 0x7fffffff) { + ret = ERROR_MP4_BOX_OVERFLOW; + srs_error("MP4 box size overflow 31bits, size=%"PRId64". ret=%d", sz(), ret); + return ret; + } + + if (type == SRS_MP4_BOX_UUID) { + if (!buf->require(16)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 box requires 16 bytes space. ret=%d", ret); + return ret; + } + usertype = new uint8_t[16]; + buf->read_bytes((char*)usertype, 16); + } + + // The left required size, determined by the default version(0). + int lrsz = nb_header() - SrsMp4Box::nb_header(); + if (!buf->require(lrsz)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 box requires %d bytes space. ret=%d", lrsz, ret); + return ret; + } + + return ret; } SrsMp4FullBox::SrsMp4FullBox() @@ -48,9 +409,58 @@ SrsMp4FullBox::~SrsMp4FullBox() { } +int SrsMp4FullBox::nb_header() +{ + return SrsMp4Box::nb_header() + 1 + 3; +} + +int SrsMp4FullBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4Box::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + buf->write_1bytes(version); + buf->write_3bytes(flags); + + return ret; +} + +int SrsMp4FullBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4Box::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + if (!buf->require(4)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 full box requires 4 bytes space. ret=%d", ret); + return ret; + } + + flags = (uint32_t)buf->read_4bytes(); + + version = (uint8_t)((flags >> 24) & 0xff); + flags &= 0x00ffffff; + + // The left required size, determined by the version. + int lrsz = nb_header() - SrsMp4FullBox::nb_header(); + if (!buf->require(lrsz)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 full box requires %d bytes space. ret=%d", lrsz, ret); + return ret; + } + + return ret; +} + SrsMp4FileTypeBox::SrsMp4FileTypeBox() { - type = 0x66747970; // 'ftyp' + type = SRS_MP4_BOX_FTYP; nb_compatible_brands = 0; compatible_brands = NULL; major_brand = minor_version = 0; @@ -61,9 +471,60 @@ SrsMp4FileTypeBox::~SrsMp4FileTypeBox() srs_freepa(compatible_brands); } +int SrsMp4FileTypeBox::nb_header() +{ + return SrsMp4Box::nb_header() + 8 + nb_compatible_brands * 4; +} + +int SrsMp4FileTypeBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4Box::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + buf->write_4bytes(major_brand); + buf->write_4bytes(minor_version); + + for (int i = 0; i < nb_compatible_brands; i++) { + uint32_t& cb = compatible_brands[i]; + buf->write_4bytes(cb); + } + + return ret; +} + +int SrsMp4FileTypeBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4Box::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + major_brand = buf->read_4bytes(); + minor_version = buf->read_4bytes(); + + // Compatible brands to the end of the box. + int left = left_space(buf); + + if (left > 0) { + nb_compatible_brands = left / 4; + compatible_brands = new uint32_t[nb_compatible_brands]; + } + + for (int i = 0; left > 0; i++, left -= 4){ + uint32_t cb = buf->read_4bytes(); + compatible_brands[i] = cb; + } + + return ret; +} + SrsMp4MediaDataBox::SrsMp4MediaDataBox() { - type = 0x6d646174; // 'mdat' + type = SRS_MP4_BOX_MDAT; data = NULL; nb_data = 0; } @@ -73,18 +534,95 @@ SrsMp4MediaDataBox::~SrsMp4MediaDataBox() srs_freepa(data); } +int SrsMp4MediaDataBox::nb_header() +{ + return SrsMp4Box::nb_header() + nb_data; +} + +int SrsMp4MediaDataBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4Box::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + if (nb_data) { + buf->write_bytes((char*)data, nb_data); + } + + return ret; +} + +int SrsMp4MediaDataBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4Box::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + int left = left_space(buf); + if (left) { + data = new uint8_t[left]; + buf->read_bytes((char*)data, left); + } + + return ret; +} + SrsMp4FreeSpaceBox::SrsMp4FreeSpaceBox() { - type = 0x66726565; // ‘free’ or ‘skip’ + type = SRS_MP4_BOX_FREE; // 'free' or 'skip' + data = NULL; + nb_data = 0; } SrsMp4FreeSpaceBox::~SrsMp4FreeSpaceBox() { + srs_freepa(data); +} + +int SrsMp4FreeSpaceBox::nb_header() +{ + return SrsMp4Box::nb_header() + nb_data; +} + +int SrsMp4FreeSpaceBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4Box::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + if (nb_data) { + buf->write_bytes((char*)data, nb_data); + } + + return ret; +} + +int SrsMp4FreeSpaceBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4Box::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + int left = left_space(buf); + if (left) { + data = new uint8_t[left]; + buf->read_bytes((char*)data, left); + } + + return ret; } SrsMp4MovieBox::SrsMp4MovieBox() { - type = 0x6d6f6f76; // 'moov' + type = SRS_MP4_BOX_MOOV; } SrsMp4MovieBox::~SrsMp4MovieBox() @@ -93,7 +631,7 @@ SrsMp4MovieBox::~SrsMp4MovieBox() SrsMp4MovieHeaderBox::SrsMp4MovieHeaderBox() { - type = 0x6d766864; // 'mvhd' + type = SRS_MP4_BOX_MVHD; rate = 0x00010000; // typically 1.0 volume = 0x0100; // typically, full volume @@ -110,9 +648,92 @@ SrsMp4MovieHeaderBox::~SrsMp4MovieHeaderBox() { } +int SrsMp4MovieHeaderBox::nb_header() +{ + int size = SrsMp4FullBox::nb_header(); + + if (version == 1) { + size += 8+8+4+8; + } else { + size += 4+4+4+4; + } + + size += 4+2+2+8+36+24+4; + + return size; +} + +int SrsMp4MovieHeaderBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + if (version == 1) { + buf->write_8bytes(creation_time); + buf->write_8bytes(modification_time); + buf->write_4bytes(timescale); + buf->write_8bytes(duration); + } else { + buf->write_4bytes((uint32_t)creation_time); + buf->write_4bytes((uint32_t)modification_time); + buf->write_4bytes(timescale); + buf->write_4bytes((uint32_t)duration); + } + + buf->write_4bytes(rate); + buf->write_2bytes(volume); + buf->write_2bytes(reserved0); + buf->write_8bytes(reserved1); + for (int i = 0; i < 9; i++) { + buf->write_4bytes(matrix[i]); + } + for (int i = 0; i < 6; i++) { + buf->write_4bytes(pre_defined[i]); + } + buf->write_4bytes(next_track_ID); + + return ret; +} + +int SrsMp4MovieHeaderBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + if (version == 1) { + creation_time = buf->read_8bytes(); + modification_time = buf->read_8bytes(); + timescale = buf->read_4bytes(); + duration = buf->read_8bytes(); + } else { + creation_time = buf->read_4bytes(); + modification_time = buf->read_4bytes(); + timescale = buf->read_4bytes(); + duration = buf->read_4bytes(); + } + + rate = buf->read_4bytes(); + volume = buf->read_4bytes(); + buf->skip(2); + buf->skip(8); + for (int i = 0; i < 9; i++) { + matrix[i] = buf->read_4bytes(); + } + buf->skip(24); + next_track_ID = buf->read_4bytes(); + + return ret; +} + SrsMp4TrackBox::SrsMp4TrackBox() { - type = 0x7472616b; // 'trak' + type = SRS_MP4_BOX_TRAK; } SrsMp4TrackBox::~SrsMp4TrackBox() @@ -121,13 +742,13 @@ SrsMp4TrackBox::~SrsMp4TrackBox() SrsMp4TrackHeaderBox::SrsMp4TrackHeaderBox() { - type = 0x746b6864; // 'tkhd' + type = SRS_MP4_BOX_TKHD; reserved0 = 0; reserved1 = 0; reserved2 = 0; layer = alternate_group = 0; - volume = 0x0100; // if track_is_audio 0x0100 else 0 + volume = 0; // if track_is_audio 0x0100 else 0 int32_t v[] = {0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000}; memcpy(matrix, v, 36); @@ -137,9 +758,96 @@ SrsMp4TrackHeaderBox::~SrsMp4TrackHeaderBox() { } +int SrsMp4TrackHeaderBox::nb_header() +{ + int size = SrsMp4FullBox::nb_header(); + + if (version == 1) { + size += 8+8+4+4+8; + } else { + size += 4+4+4+4+4; + } + + size += 8+2+2+2+2+36+4+4; + + return size; +} + +int SrsMp4TrackHeaderBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + if (version == 1) { + buf->write_8bytes(creation_time); + buf->write_8bytes(modification_time); + buf->write_4bytes(track_ID); + buf->write_4bytes(reserved0); + buf->write_8bytes(duration); + } else { + buf->write_4bytes((uint32_t)creation_time); + buf->write_4bytes((uint32_t)modification_time); + buf->write_4bytes(track_ID); + buf->write_4bytes(reserved0); + buf->write_4bytes((uint32_t)duration); + } + + buf->write_8bytes(reserved1); + buf->write_2bytes(layer); + buf->write_2bytes(alternate_group); + buf->write_2bytes(volume); + buf->write_2bytes(reserved2); + for (int i = 0; i < 9; i++) { + buf->write_4bytes(matrix[i]); + } + buf->write_4bytes(width); + buf->write_4bytes(height); + + return ret; +} + +int SrsMp4TrackHeaderBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + if (version == 1) { + creation_time = buf->read_8bytes(); + modification_time = buf->read_8bytes(); + track_ID = buf->read_4bytes(); + buf->skip(4); + duration = buf->read_8bytes(); + } else { + creation_time = buf->read_4bytes(); + modification_time = buf->read_4bytes(); + track_ID = buf->read_4bytes(); + buf->skip(4); + duration = buf->read_4bytes(); + } + + buf->skip(8); + layer = buf->read_2bytes(); + alternate_group = buf->read_2bytes(); + volume = buf->read_2bytes(); + buf->skip(2); + for (int i = 0; i < 9; i++) { + matrix[i] = buf->read_4bytes(); + } + width = buf->read_4bytes(); + height = buf->read_4bytes(); + + return ret; +} + SrsMp4EditBox::SrsMp4EditBox() { - type = 0x65647473; // 'edts' + type = SRS_MP4_BOX_EDTS; } SrsMp4EditBox::~SrsMp4EditBox() @@ -151,9 +859,56 @@ SrsMp4ElstEntry::SrsMp4ElstEntry() media_rate_fraction = 0; } +int SrsMp4ElstEntry::nb_header(uint32_t version) +{ + int size = 0; + + if (version == 1) { + size += 8+8; + } else { + size += 4+4; + } + + size += 2+2; + + return size; +} + +int SrsMp4ElstEntry::encode_header(SrsBuffer* buf, uint32_t version) +{ + if (version == 1) { + buf->write_8bytes(segment_duration); + buf->write_8bytes(media_time); + } else { + buf->write_4bytes((uint32_t)segment_duration); + buf->write_4bytes((int32_t)media_time); + } + + buf->write_2bytes(media_rate_integer); + buf->write_2bytes(media_rate_fraction); + + return ERROR_SUCCESS; +} + +int SrsMp4ElstEntry::decode_header(SrsBuffer* buf, uint32_t version) +{ + if (version == 1) { + segment_duration = buf->read_8bytes(); + media_time = buf->read_8bytes(); + } else { + segment_duration = buf->read_4bytes(); + media_time = buf->read_4bytes(); + } + + media_rate_integer = buf->read_2bytes(); + media_rate_fraction = buf->read_2bytes(); + + return ERROR_SUCCESS; +} + SrsMp4EditListBox::SrsMp4EditListBox() { - type = 0x656c7374; // 'elst' + type = SRS_MP4_BOX_ELST; entry_count = 0; entries = NULL; @@ -164,9 +919,62 @@ SrsMp4EditListBox::~SrsMp4EditListBox() srs_freepa(entries); } +int SrsMp4EditListBox::nb_header() +{ + int size = SrsMp4FullBox::nb_header(); + + for (uint32_t i = 0; i < entry_count; i++) { + SrsMp4ElstEntry& entry = entries[i]; + size += entry.nb_header(version); + } + + return size; +} + +int SrsMp4EditListBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + for (uint32_t i = 0; i < entry_count; i++) { + SrsMp4ElstEntry& entry = entries[i]; + if ((ret = entry.encode_header(buf, version)) != ERROR_SUCCESS) { + return ret; + } + } + + return ret; +} + +int SrsMp4EditListBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + int left = left_space(buf); + entry_count = left / SrsMp4ElstEntry().nb_header(version); + if (entry_count > 0) { + entries = new SrsMp4ElstEntry[entry_count]; + } + for (int i = 0; i < entry_count; i++) { + SrsMp4ElstEntry& entry = entries[i]; + if ((ret = entry.decode_header(buf, version)) != ERROR_SUCCESS) { + return ret; + } + } + + return ret; +} + SrsMp4MediaBox::SrsMp4MediaBox() { - type = 0x6d646961; // 'mdia' + type = SRS_MP4_BOX_MDIA; } SrsMp4MediaBox::~SrsMp4MediaBox() @@ -175,9 +983,8 @@ SrsMp4MediaBox::~SrsMp4MediaBox() SrsMp4MediaHeaderBox::SrsMp4MediaHeaderBox() { - type = 0x6d646864; // 'mdhd' - - pad = 0; + type = SRS_MP4_BOX_MDHD; + language = 0; pre_defined = 0; } @@ -185,9 +992,106 @@ SrsMp4MediaHeaderBox::~SrsMp4MediaHeaderBox() { } +uint8_t SrsMp4MediaHeaderBox::language0() +{ + return (language >> 10) & 0x1f; +} + +void SrsMp4MediaHeaderBox::set_language0(uint8_t v) +{ + language |= uint16_t(v & 0x1f) << 10; +} + +uint8_t SrsMp4MediaHeaderBox::language1() +{ + return (language >> 5) & 0x1f; +} + +void SrsMp4MediaHeaderBox::set_language1(uint8_t v) +{ + language |= uint16_t(v & 0x1f) << 5; +} + +uint8_t SrsMp4MediaHeaderBox::language2() +{ + return language & 0x1f; +} + +void SrsMp4MediaHeaderBox::set_language2(uint8_t v) +{ + language |= uint16_t(v & 0x1f); +} + +int SrsMp4MediaHeaderBox::nb_header() +{ + int size = SrsMp4FullBox::nb_header(); + + if (version == 1) { + size += 8+8+4+8; + } else { + size += 4+4+4+4; + } + + size += 2+2; + + return size; +} + +int SrsMp4MediaHeaderBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + if (version == 1) { + buf->write_8bytes(creation_time); + buf->write_8bytes(modification_time); + buf->write_4bytes(timescale); + buf->write_8bytes(duration); + } else { + buf->write_4bytes((uint32_t)creation_time); + buf->write_4bytes((uint32_t)modification_time); + buf->write_4bytes(timescale); + buf->write_4bytes((uint32_t)duration); + } + + buf->write_2bytes(language); + buf->write_2bytes(pre_defined); + + return ret; +} + +int SrsMp4MediaHeaderBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + if (version == 1) { + creation_time = buf->read_8bytes(); + modification_time = buf->read_8bytes(); + timescale = buf->read_4bytes(); + duration = buf->read_8bytes(); + } else { + creation_time = buf->read_4bytes(); + modification_time = buf->read_4bytes(); + timescale = buf->read_4bytes(); + duration = buf->read_4bytes(); + } + + language = buf->read_2bytes(); + buf->skip(2); + + return ret; +} + SrsMp4HandlerReferenceBox::SrsMp4HandlerReferenceBox() { - type = 0x68646c72; // 'hdlr' + type = SRS_MP4_BOX_HDLR; pre_defined = 0; memset(reserved, 0, 12); @@ -197,9 +1101,52 @@ SrsMp4HandlerReferenceBox::~SrsMp4HandlerReferenceBox() { } +int SrsMp4HandlerReferenceBox::nb_header() +{ + return SrsMp4FullBox::nb_header()+4+4+12+srs_mp4_string_length(name); +} + +int SrsMp4HandlerReferenceBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + buf->write_4bytes(pre_defined); + buf->write_4bytes(handler_type); + buf->write_4bytes(reserved[0]); + buf->write_4bytes(reserved[1]); + buf->write_4bytes(reserved[2]); + srs_mp4_string_write(buf, name); + + return ret; +} + +int SrsMp4HandlerReferenceBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + buf->skip(4); + handler_type = buf->read_4bytes(); + buf->skip(12); + + if ((ret = srs_mp4_string_read(buf, name, left_space(buf))) != ERROR_SUCCESS) { + srs_error("MP4 hdlr read string failed. ret=%d", ret); + return ret; + } + + return ret; +} + SrsMp4MediaInformationBox::SrsMp4MediaInformationBox() { - type = 0x6d696e66; // 'minf' + type = SRS_MP4_BOX_MINF; } SrsMp4MediaInformationBox::~SrsMp4MediaInformationBox() @@ -208,7 +1155,7 @@ SrsMp4MediaInformationBox::~SrsMp4MediaInformationBox() SrsMp4VideoMeidaHeaderBox::SrsMp4VideoMeidaHeaderBox() { - type = 0x766d6864; // 'vmhd' + type = SRS_MP4_BOX_VMHD; version = 0; flags = 1; @@ -220,9 +1167,46 @@ SrsMp4VideoMeidaHeaderBox::~SrsMp4VideoMeidaHeaderBox() { } +int SrsMp4VideoMeidaHeaderBox::nb_header() +{ + return SrsMp4FullBox::nb_header()+2+6; +} + +int SrsMp4VideoMeidaHeaderBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + buf->write_2bytes(graphicsmode); + buf->write_2bytes(opcolor[0]); + buf->write_2bytes(opcolor[1]); + buf->write_2bytes(opcolor[2]); + + return ret; +} + +int SrsMp4VideoMeidaHeaderBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + graphicsmode = buf->read_2bytes(); + opcolor[0] = buf->read_2bytes(); + opcolor[1] = buf->read_2bytes(); + opcolor[2] = buf->read_2bytes(); + + return ret; +} + SrsMp4SoundMeidaHeaderBox::SrsMp4SoundMeidaHeaderBox() { - type = 0x736d6864; // 'smhd' + type = SRS_MP4_BOX_SMHD; reserved = balance = 0; } @@ -231,9 +1215,42 @@ SrsMp4SoundMeidaHeaderBox::~SrsMp4SoundMeidaHeaderBox() { } +int SrsMp4SoundMeidaHeaderBox::nb_header() +{ + return SrsMp4FullBox::nb_header()+2+2; +} + +int SrsMp4SoundMeidaHeaderBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + buf->write_2bytes(balance); + buf->write_2bytes(reserved); + + return ret; +} + +int SrsMp4SoundMeidaHeaderBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + balance = buf->read_2bytes(); + buf->skip(2); + + return ret; +} + SrsMp4DataInformationBox::SrsMp4DataInformationBox() { - type = 0x64696e66; // 'dinf' + type = SRS_MP4_BOX_DINF; } SrsMp4DataInformationBox::~SrsMp4DataInformationBox() @@ -244,31 +1261,199 @@ SrsMp4DataEntryBox::SrsMp4DataEntryBox() { } +SrsMp4DataEntryBox::~SrsMp4DataEntryBox() +{ +} + +int SrsMp4DataEntryBox::nb_header() +{ + return SrsMp4FullBox::nb_header()+srs_mp4_string_length(location); +} + +int SrsMp4DataEntryBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + srs_mp4_string_write(buf, location); + + return ret; +} + +int SrsMp4DataEntryBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + if ((ret = srs_mp4_string_read(buf, location, left_space(buf))) != ERROR_SUCCESS) { + srs_error("MP4 urx read string failed. ret=%d", ret); + return ret; + } + + return ret; +} + SrsMp4DataEntryUrlBox::SrsMp4DataEntryUrlBox() { - type = 0x75726c20; // 'url ' + type = SRS_MP4_BOX_URL; +} + +SrsMp4DataEntryUrlBox::~SrsMp4DataEntryUrlBox() +{ } SrsMp4DataEntryUrnBox::SrsMp4DataEntryUrnBox() { - type = 0x75726e20; // 'urn ' + type = SRS_MP4_BOX_URN; +} + +SrsMp4DataEntryUrnBox::~SrsMp4DataEntryUrnBox() +{ +} + +int SrsMp4DataEntryUrnBox::nb_header() +{ + return SrsMp4DataEntryBox::nb_header()+srs_mp4_string_length(name); +} + +int SrsMp4DataEntryUrnBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4DataEntryBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + srs_mp4_string_write(buf, name); + + return ret; +} + +int SrsMp4DataEntryUrnBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4DataEntryBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + if ((ret = srs_mp4_string_read(buf, name, left_space(buf))) != ERROR_SUCCESS) { + srs_error("MP4 urn read string failed. ret=%d", ret); + return ret; + } + + return ret; } SrsMp4DataReferenceBox::SrsMp4DataReferenceBox() { - type = 0x64726566; // 'dref' - - entry_count = 0; - entries = NULL; + type = SRS_MP4_BOX_DREF; } SrsMp4DataReferenceBox::~SrsMp4DataReferenceBox() { + vector::iterator it; + for (it = entries.begin(); it != entries.end(); ++it) { + SrsMp4DataEntryBox* entry = *it; + srs_freep(entry); + } + entries.clear(); +} + +uint32_t SrsMp4DataReferenceBox::entry_count() +{ + return (uint32_t)entries.size(); +} + +SrsMp4DataEntryBox* SrsMp4DataReferenceBox::entry_at(int index) +{ + return entries.at(index); +} + +int SrsMp4DataReferenceBox::nb_header() +{ + int size = SrsMp4FullBox::nb_header(); + + size += 4; + + vector::iterator it; + for (it = entries.begin(); it != entries.end(); ++it) { + SrsMp4DataEntryBox* entry = *it; + size += entry->nb_bytes(); + } + + return size; +} + +int SrsMp4DataReferenceBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + buf->write_4bytes((int32_t)entries.size()); + + vector::iterator it; + for (it = entries.begin(); it != entries.end(); ++it) { + SrsMp4DataEntryBox* entry = *it; + if ((ret = entry->encode(buf)) != ERROR_SUCCESS) { + return ret; + } + } + + return ret; +} + +int SrsMp4DataReferenceBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + int left = left_space(buf); + while (left > 0) { + 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) { + fbox->version = version; + fbox->flags = flags; + } + + if (box->type == SRS_MP4_BOX_URL) { + entries.push_back(dynamic_cast(box)); + } else if (box->type == SRS_MP4_BOX_URN) { + entries.push_back(dynamic_cast(box)); + } else { + srs_freep(box); + } + } + + return ret; } SrsMp4SampleTableBox::SrsMp4SampleTableBox() { - type = 0x7374626c; // 'stbl' + type = SRS_MP4_BOX_STBL; } SrsMp4SampleTableBox::~SrsMp4SampleTableBox() @@ -284,6 +1469,41 @@ SrsMp4SampleEntry::~SrsMp4SampleEntry() { } +int SrsMp4SampleEntry::nb_header() +{ + return SrsMp4Box::nb_header()+6+2; +} + +int SrsMp4SampleEntry::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4Box::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + for (int i = 0; i < 6; i++) { + buf->write_1bytes(reserved[i]); + } + buf->write_2bytes(data_reference_index); + + return ret; +} + +int SrsMp4SampleEntry::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4Box::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + buf->skip(6); + data_reference_index = buf->read_2bytes(); + + return ret; +} + SrsMp4VisualSampleEntry::SrsMp4VisualSampleEntry() { pre_defined0 = 0; @@ -302,9 +1522,64 @@ SrsMp4VisualSampleEntry::~SrsMp4VisualSampleEntry() { } +int SrsMp4VisualSampleEntry::nb_header() +{ + return SrsMp4SampleEntry::nb_header()+2+2+12+2+2+4+4+4+2+32+2+2; +} + +int SrsMp4VisualSampleEntry::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4SampleEntry::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + buf->write_2bytes(pre_defined0); + buf->write_2bytes(reserved0); + buf->write_4bytes(pre_defined1[0]); + buf->write_4bytes(pre_defined1[1]); + buf->write_4bytes(pre_defined1[2]); + buf->write_2bytes(width); + buf->write_2bytes(height); + buf->write_4bytes(horizresolution); + buf->write_4bytes(vertresolution); + buf->write_4bytes(reserved1); + buf->write_2bytes(frame_count); + buf->write_bytes(compressorname, 32); + buf->write_2bytes(depth); + buf->write_2bytes(pre_defined2); + + return ret; +} + +int SrsMp4VisualSampleEntry::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4SampleEntry::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + buf->skip(2); + buf->skip(2); + buf->skip(12); + width = buf->read_2bytes(); + height = buf->read_2bytes(); + horizresolution = buf->read_4bytes(); + vertresolution = buf->read_4bytes(); + buf->skip(4); + frame_count = buf->read_2bytes(); + buf->read_bytes(compressorname, 32); + depth = buf->read_2bytes(); + buf->skip(2); + + return ret; +} + SrsMp4AudioSampleEntry::SrsMp4AudioSampleEntry() { - memset(reserved0, 0, 8); + reserved0 = 0; pre_defined0 = 0; reserved1 = 0; channelcount = 2; @@ -315,17 +1590,134 @@ SrsMp4AudioSampleEntry::~SrsMp4AudioSampleEntry() { } +int SrsMp4AudioSampleEntry::nb_header() +{ + return SrsMp4SampleEntry::nb_header()+8+2+2+2+2+4; +} + +int SrsMp4AudioSampleEntry::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4SampleEntry::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + buf->write_8bytes(reserved0); + buf->write_2bytes(channelcount); + buf->write_2bytes(samplesize); + buf->write_2bytes(pre_defined0); + buf->write_2bytes(reserved1); + buf->write_4bytes(samplerate); + + return ret; +} + +int SrsMp4AudioSampleEntry::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4SampleEntry::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + buf->skip(8); + channelcount = buf->read_2bytes(); + samplesize = buf->read_2bytes(); + buf->skip(2); + buf->skip(2); + samplerate = buf->read_4bytes(); + + return ret; +} + SrsMp4SampleDescriptionBox::SrsMp4SampleDescriptionBox() { - type = 0x73747364; // 'stsd' - - entry_count = 0; - entries = NULL; + type = SRS_MP4_BOX_STSD; } SrsMp4SampleDescriptionBox::~SrsMp4SampleDescriptionBox() { - srs_freepa(entries); + vector::iterator it; + for (it = entries.begin(); it != entries.end(); ++it) { + SrsMp4SampleEntry* entry = *it; + srs_freep(entry); + } + entries.clear(); +} + +uint32_t SrsMp4SampleDescriptionBox::entry_count() +{ + return (uint32_t)entries.size(); +} + +SrsMp4SampleEntry* SrsMp4SampleDescriptionBox::entrie_at(int index) +{ + return entries.at(index); +} + +int SrsMp4SampleDescriptionBox::nb_header() +{ + int size = SrsMp4FullBox::nb_header(); + + vector::iterator it; + for (it = entries.begin(); it != entries.end(); ++it) { + SrsMp4SampleEntry* entry = *it; + size += entry->nb_bytes(); + } + + return size; +} + +int SrsMp4SampleDescriptionBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + vector::iterator it; + for (it = entries.begin(); it != entries.end(); ++it) { + SrsMp4SampleEntry* entry = *it; + if ((ret = entry->encode(buf)) != ERROR_SUCCESS) { + return ret; + } + } + + return ret; +} + +int SrsMp4SampleDescriptionBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + int left = left_space(buf); + while (left > 0) { + 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) { + entries.push_back(entry); + } else { + srs_freep(box); + } + } + + return ret; } SrsMp4SttsEntry::SrsMp4SttsEntry() @@ -336,7 +1728,7 @@ SrsMp4SttsEntry::SrsMp4SttsEntry() SrsMp4DecodingTime2SampleBox::SrsMp4DecodingTime2SampleBox() { - type = 0x73747473; // 'stts' + type = SRS_MP4_BOX_STTS; entry_count = 0; entries = NULL; @@ -347,6 +1739,33 @@ SrsMp4DecodingTime2SampleBox::~SrsMp4DecodingTime2SampleBox() srs_freepa(entries); } +int SrsMp4DecodingTime2SampleBox::nb_header() +{ + return SrsMp4FullBox::nb_header(); +} + +int SrsMp4DecodingTime2SampleBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsMp4DecodingTime2SampleBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + SrsMp4CttsEntry::SrsMp4CttsEntry() { sample_count = 0; @@ -355,7 +1774,7 @@ SrsMp4CttsEntry::SrsMp4CttsEntry() SrsMp4CompositionTime2SampleBox::SrsMp4CompositionTime2SampleBox() { - type = 0x63747473; // 'ctts' + type = SRS_MP4_BOX_CTTS; entry_count = 0; entries = NULL; @@ -366,9 +1785,36 @@ SrsMp4CompositionTime2SampleBox::~SrsMp4CompositionTime2SampleBox() srs_freepa(entries); } +int SrsMp4CompositionTime2SampleBox::nb_header() +{ + return SrsMp4FullBox::nb_header(); +} + +int SrsMp4CompositionTime2SampleBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsMp4CompositionTime2SampleBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + SrsMp4SyncSampleBox::SrsMp4SyncSampleBox() { - type = 0x73747373; // 'stss' + type = SRS_MP4_BOX_STSS; entry_count = 0; sample_numbers = NULL; @@ -379,6 +1825,33 @@ SrsMp4SyncSampleBox::~SrsMp4SyncSampleBox() srs_freepa(sample_numbers); } +int SrsMp4SyncSampleBox::nb_header() +{ + return SrsMp4FullBox::nb_header(); +} + +int SrsMp4SyncSampleBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsMp4SyncSampleBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + SrsMp4StscEntry::SrsMp4StscEntry() { first_chunk = 0; @@ -388,7 +1861,7 @@ SrsMp4StscEntry::SrsMp4StscEntry() SrsMp4Sample2ChunkBox::SrsMp4Sample2ChunkBox() { - type = 0x73747363; // 'stsc' + type = SRS_MP4_BOX_STSC; entry_count = 0; entries = NULL; @@ -399,9 +1872,36 @@ SrsMp4Sample2ChunkBox::~SrsMp4Sample2ChunkBox() srs_freepa(entries); } +int SrsMp4Sample2ChunkBox::nb_header() +{ + return SrsMp4FullBox::nb_header(); +} + +int SrsMp4Sample2ChunkBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsMp4Sample2ChunkBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + SrsMp4ChunkOffsetBox::SrsMp4ChunkOffsetBox() { - type = 0x7374636f; // 'stco' + type = SRS_MP4_BOX_STCO; entry_count = 0; entries = NULL; @@ -412,9 +1912,36 @@ SrsMp4ChunkOffsetBox::~SrsMp4ChunkOffsetBox() srs_freepa(entries); } +int SrsMp4ChunkOffsetBox::nb_header() +{ + return SrsMp4FullBox::nb_header(); +} + +int SrsMp4ChunkOffsetBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsMp4ChunkOffsetBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + SrsMp4SampleSizeBox::SrsMp4SampleSizeBox() { - type = 0x7374737a; // 'stsz' + type = SRS_MP4_BOX_STSZ; sample_size = sample_count = 0; entry_sizes = NULL; @@ -425,12 +1952,44 @@ SrsMp4SampleSizeBox::~SrsMp4SampleSizeBox() srs_freepa(entry_sizes); } +int SrsMp4SampleSizeBox::nb_header() +{ + return SrsMp4FullBox::nb_header(); +} + +int SrsMp4SampleSizeBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsMp4SampleSizeBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + SrsMp4Decoder::SrsMp4Decoder() { + reader = NULL; + next = NULL; + stream = new SrsSimpleStream(); } SrsMp4Decoder::~SrsMp4Decoder() { + srs_freep(next); + srs_freep(stream); } int SrsMp4Decoder::initialize(ISrsReader* r) @@ -440,6 +1999,67 @@ int SrsMp4Decoder::initialize(ISrsReader* r) srs_assert(r); reader = r; + if ((ret = load_next_box(&next)) != ERROR_SUCCESS) { + return ret; + } + + if (next->type != SRS_MP4_BOX_FTYP) { + ret = ERROR_MP4_BOX_ILLEGAL_SCHEMA; + srs_error("MP4 first box must be FTYP, not %d. ret=%d", next->type, ret); + return ret; + } + + return ret; +} + +int SrsMp4Decoder::load_next_box(SrsMp4Box** ppbox) +{ + int ret = ERROR_SUCCESS; + + // Ignore for already loaded. + if (next) { + return ret; + } + + char* buf = new char[4096]; + SrsAutoFreeA(char, buf); + + while (true) { + uint64_t required = next? next->sz():4; + while (stream->length() < required) { + ssize_t nread; + if ((ret = reader->read(buf, 4096, &nread)) != ERROR_SUCCESS) { + srs_error("MP4 load failed, nread=%d, required=%d. ret=%d", nread, required, ret); + return ret; + } + + srs_assert(nread > 0); + stream->append(buf, (int)nread); + } + + SrsBuffer* buffer = new SrsBuffer(stream->bytes(), stream->length()); + SrsAutoFree(SrsBuffer, buffer); + + // Discovery the box with basic header. + if (!next && (ret = SrsMp4Box::discovery(buffer, ppbox)) != ERROR_SUCCESS) { + if (ret == ERROR_MP4_BOX_REQUIRE_SPACE) { + continue; + } + srs_error("MP4 load box failed. ret=%d", ret); + return ret; + } + + // Decode util we can demux the whole box. + if (!buffer->require((int)next->sz())) { + continue; + } + ret = next->decode(buffer); + + // Remove the consumed bytes. + stream->erase((int)next->sz()); + break; + } + return ret; } diff --git a/trunk/src/kernel/srs_kernel_mp4.hpp b/trunk/src/kernel/srs_kernel_mp4.hpp index ab08fbe19..b1da800dc 100644 --- a/trunk/src/kernel/srs_kernel_mp4.hpp +++ b/trunk/src/kernel/srs_kernel_mp4.hpp @@ -29,30 +29,77 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include +#include + #include +#include class ISrsReader; +class SrsSimpleStream; /** * 4.2 Object Structure * ISO_IEC_14496-12-base-format-2012.pdf, page 16 */ -class SrsMp4Box +class SrsMp4Box : public ISrsCodec { -public: +private: + // The size is the entire size of the box, including the size and type header, fields, + // and all contained boxes. This facilitates general parsing of the file. + // // if size is 1 then the actual size is in the field largesize; // if size is 0, then this box is the last one in the file, and its contents // extend to the end of the file (normally only used for a Media Data Box) - uint32_t size; + uint32_t smallsize; + uint64_t largesize; +public: + // identifies the box type; standard boxes use a compact type, which is normally four printable + // characters, to permit ease of identification, and is shown so in the boxes below. User extensions use + // an extended type; in this case, the type field is set to ‘uuid’. uint32_t type; + // For box 'uuid'. + uint8_t* usertype; +private: + std::vector boxes; +private: + // The position at buffer to start demux the box. + int start_pos; public: SrsMp4Box(); virtual ~SrsMp4Box(); +public: + // Get the size of box, whatever small or large size. + virtual uint64_t sz(); + // Get the left space of box, for decoder. + virtual int left_space(SrsBuffer* buf); + /** + * Discovery the box from buffer. + * @param ppbox Output the discoveried box, which user must free it. + */ + static int discovery(SrsBuffer* buf, SrsMp4Box** ppbox); +// Interface ISrsCodec +public: + virtual int nb_bytes(); + virtual int encode(SrsBuffer* buf); + virtual int decode(SrsBuffer* buf); +protected: + virtual int encode_boxes(SrsBuffer* buf); + virtual int decode_boxes(SrsBuffer* buf); +// Sub classes can override these functions for special codec. +protected: + // The size of header, not including the contained boxes. + virtual int nb_header(); + // It's not necessary to check the buffer, because we already know the size in parent function, + // so we have checked the buffer is ok to write. + virtual int encode_header(SrsBuffer* buf); + // It's not necessary to check the buffer, unless the box is not only determined by the verson. + // Generally, it's not necessary, that is, all boxes is determinated by version. + virtual int decode_header(SrsBuffer* buf); }; /** * 4.2 Object Structure - * ISO_IEC_14496-12-base-format-2012.pdf, page 16 + * ISO_IEC_14496-12-base-format-2012.pdf, page 17 */ class SrsMp4FullBox : public SrsMp4Box { @@ -64,6 +111,10 @@ public: public: SrsMp4FullBox(); virtual ~SrsMp4FullBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -88,6 +139,10 @@ private: public: SrsMp4FileTypeBox(); virtual ~SrsMp4FileTypeBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -101,11 +156,16 @@ public: class SrsMp4MediaDataBox : public SrsMp4Box { private: + // the contained media data int nb_data; uint8_t* data; public: SrsMp4MediaDataBox(); virtual ~SrsMp4MediaDataBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -114,9 +174,16 @@ public: */ class SrsMp4FreeSpaceBox : public SrsMp4Box { +private: + int nb_data; + uint8_t* data; public: SrsMp4FreeSpaceBox(); virtual ~SrsMp4FreeSpaceBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -172,6 +239,10 @@ public: public: SrsMp4MovieHeaderBox(); virtual ~SrsMp4MovieHeaderBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -201,10 +272,6 @@ public: // an integer that declares the most recent time the presentation was modified (in // seconds since midnight, Jan. 1, 1904, in UTC time) uint64_t modification_time; - // an integer that specifies the time-scale for the entire presentation; this is the number of - // time units that pass in one second. For example, a time coordinate system that measures time in - // sixtieths of a second has a time scale of 60. - uint32_t timescale; // an integer that uniquely identifies this track over the entire life-time of this presentation. // Track IDs are never re-used and cannot be zero. uint32_t track_ID; @@ -244,6 +311,10 @@ public: public: SrsMp4TrackHeaderBox(); virtual ~SrsMp4TrackHeaderBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -282,6 +353,10 @@ public: int16_t media_rate_fraction; public: SrsMp4ElstEntry(); +public: + virtual int nb_header(uint32_t version); + virtual int encode_header(SrsBuffer* buf, uint32_t version); + virtual int decode_header(SrsBuffer* buf, uint32_t version); }; /** @@ -300,6 +375,10 @@ public: public: SrsMp4EditListBox(); virtual ~SrsMp4EditListBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -338,16 +417,29 @@ public: // is derived from the presentation’s tracks: the value of this field corresponds to the duration of the // longest track in the presentation. If the duration cannot be determined then duration is set to all 1s. uint64_t duration; -public: - uint8_t pad:1; +private: // the language code for this media. See ISO 639-2/T for the set of three character // codes. Each character is packed as the difference between its ASCII value and 0x60. Since the code // is confined to being three lower-case letters, these values are strictly positive. - uint16_t language:15; + uint16_t language; uint16_t pre_defined; public: SrsMp4MediaHeaderBox(); virtual ~SrsMp4MediaHeaderBox(); +public: + // the language code for this media. See ISO 639-2/T for the set of three character + // codes. Each character is packed as the difference between its ASCII value and 0x60. Since the code + // is confined to being three lower-case letters, these values are strictly positive. + virtual uint8_t language0(); + virtual void set_language0(uint8_t v); + virtual uint8_t language1(); + virtual void set_language1(uint8_t v); + virtual uint8_t language2(); + virtual void set_language2(uint8_t v); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -371,6 +463,10 @@ public: public: SrsMp4HandlerReferenceBox(); virtual ~SrsMp4HandlerReferenceBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -403,6 +499,10 @@ public: public: SrsMp4VideoMeidaHeaderBox(); virtual ~SrsMp4VideoMeidaHeaderBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -421,6 +521,10 @@ public: public: SrsMp4SoundMeidaHeaderBox(); virtual ~SrsMp4SoundMeidaHeaderBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -445,6 +549,11 @@ public: std::string location; public: SrsMp4DataEntryBox(); + virtual ~SrsMp4DataEntryBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -455,6 +564,7 @@ class SrsMp4DataEntryUrlBox : public SrsMp4DataEntryBox { public: SrsMp4DataEntryUrlBox(); + virtual ~SrsMp4DataEntryUrlBox(); }; /** @@ -467,6 +577,11 @@ public: std::string name; public: SrsMp4DataEntryUrnBox(); + virtual ~SrsMp4DataEntryUrnBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -478,13 +593,18 @@ public: */ class SrsMp4DataReferenceBox : public SrsMp4FullBox { -public: - // an integer that counts the actual entries - uint32_t entry_count; - SrsMp4DataEntryBox* entries; +private: + std::vector entries; public: SrsMp4DataReferenceBox(); virtual ~SrsMp4DataReferenceBox(); +public: + virtual uint32_t entry_count(); + virtual SrsMp4DataEntryBox* entry_at(int index); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -516,6 +636,10 @@ public: public: SrsMp4SampleEntry(); virtual ~SrsMp4SampleEntry(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -549,6 +673,10 @@ public: public: SrsMp4VisualSampleEntry(); virtual ~SrsMp4VisualSampleEntry(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -558,7 +686,7 @@ public: class SrsMp4AudioSampleEntry : public SrsMp4SampleEntry { public: - uint32_t reserved0[2]; + uint64_t reserved0; uint16_t channelcount; uint16_t samplesize; uint16_t pre_defined0; @@ -567,6 +695,10 @@ public: public: SrsMp4AudioSampleEntry(); virtual ~SrsMp4AudioSampleEntry(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -577,13 +709,18 @@ public: */ class SrsMp4SampleDescriptionBox : public SrsMp4FullBox { -public: - // an integer that gives the number of entries in the following table - uint32_t entry_count; - SrsMp4SampleEntry* entries; +private: + std::vector entries; public: SrsMp4SampleDescriptionBox(); virtual ~SrsMp4SampleDescriptionBox(); +public: + virtual uint32_t entry_count(); + virtual SrsMp4SampleEntry* entrie_at(int index); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -618,6 +755,10 @@ public: public: SrsMp4DecodingTime2SampleBox(); virtual ~SrsMp4DecodingTime2SampleBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; @@ -657,6 +798,10 @@ public: public: SrsMp4CompositionTime2SampleBox(); virtual ~SrsMp4CompositionTime2SampleBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -676,6 +821,10 @@ public: public: SrsMp4SyncSampleBox(); virtual ~SrsMp4SyncSampleBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -716,6 +865,10 @@ public: public: SrsMp4Sample2ChunkBox(); virtual ~SrsMp4Sample2ChunkBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -736,6 +889,10 @@ public: public: SrsMp4ChunkOffsetBox(); virtual ~SrsMp4ChunkOffsetBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -760,6 +917,10 @@ public: public: SrsMp4SampleSizeBox(); virtual ~SrsMp4SampleSizeBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); }; /** @@ -768,7 +929,13 @@ public: class SrsMp4Decoder { private: + // Underlayer reader. ISrsReader* reader; + // The stream used to demux the boxes. + // TODO: FIXME: refine for performance issue. + SrsSimpleStream* stream; + // Always load next box. + SrsMp4Box* next; public: SrsMp4Decoder(); virtual ~SrsMp4Decoder(); @@ -779,6 +946,8 @@ public: * the decoder just read data from the reader. */ virtual int initialize(ISrsReader* r); +private: + virtual int load_next_box(SrsMp4Box** ppbox); }; #endif