winlin

for #738, implements boxes codec

... ... @@ -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.
... ...
... ... @@ -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.
... ...
... ... @@ -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);
... ...
... ... @@ -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;
};
... ...
... ... @@ -23,19 +23,380 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_kernel_mp4.hpp>
#include <string.h>
#include <srs_kernel_log.hpp>
#include <srs_kernel_error.hpp>
#include <srs_kernel_stream.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_io.hpp>
#include <srs_kernel_buffer.hpp>
#include <string.h>
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<SrsMp4Box*>::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<SrsMp4Box*>::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<SrsMp4Box*>::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,90 +992,468 @@ 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);
}
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 = SRS_MP4_BOX_MINF;
}
SrsMp4MediaInformationBox::~SrsMp4MediaInformationBox()
{
}
SrsMp4VideoMeidaHeaderBox::SrsMp4VideoMeidaHeaderBox()
{
type = SRS_MP4_BOX_VMHD;
version = 0;
flags = 1;
graphicsmode = 0;
memset(opcolor, 0, 6);
}
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 = SRS_MP4_BOX_SMHD;
reserved = balance = 0;
}
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 = SRS_MP4_BOX_DINF;
}
SrsMp4DataInformationBox::~SrsMp4DataInformationBox()
{
}
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;
pre_defined = 0;
memset(reserved, 0, 12);
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;
}
SrsMp4HandlerReferenceBox::~SrsMp4HandlerReferenceBox()
SrsMp4DataEntryUrlBox::SrsMp4DataEntryUrlBox()
{
type = SRS_MP4_BOX_URL;
}
SrsMp4MediaInformationBox::SrsMp4MediaInformationBox()
SrsMp4DataEntryUrlBox::~SrsMp4DataEntryUrlBox()
{
type = 0x6d696e66; // 'minf'
}
SrsMp4MediaInformationBox::~SrsMp4MediaInformationBox()
SrsMp4DataEntryUrnBox::SrsMp4DataEntryUrnBox()
{
type = SRS_MP4_BOX_URN;
}
SrsMp4VideoMeidaHeaderBox::SrsMp4VideoMeidaHeaderBox()
SrsMp4DataEntryUrnBox::~SrsMp4DataEntryUrnBox()
{
type = 0x766d6864; // 'vmhd'
version = 0;
flags = 1;
graphicsmode = 0;
memset(opcolor, 0, 6);
}
SrsMp4VideoMeidaHeaderBox::~SrsMp4VideoMeidaHeaderBox()
int SrsMp4DataEntryUrnBox::nb_header()
{
return SrsMp4DataEntryBox::nb_header()+srs_mp4_string_length(name);
}
SrsMp4SoundMeidaHeaderBox::SrsMp4SoundMeidaHeaderBox()
int SrsMp4DataEntryUrnBox::encode_header(SrsBuffer* buf)
{
type = 0x736d6864; // 'smhd'
int ret = ERROR_SUCCESS;
reserved = balance = 0;
if ((ret = SrsMp4DataEntryBox::encode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
srs_mp4_string_write(buf, name);
return ret;
}
SrsMp4SoundMeidaHeaderBox::~SrsMp4SoundMeidaHeaderBox()
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;
}
SrsMp4DataInformationBox::SrsMp4DataInformationBox()
SrsMp4DataReferenceBox::SrsMp4DataReferenceBox()
{
type = 0x64696e66; // 'dinf'
type = SRS_MP4_BOX_DREF;
}
SrsMp4DataInformationBox::~SrsMp4DataInformationBox()
SrsMp4DataReferenceBox::~SrsMp4DataReferenceBox()
{
vector<SrsMp4DataEntryBox*>::iterator it;
for (it = entries.begin(); it != entries.end(); ++it) {
SrsMp4DataEntryBox* entry = *it;
srs_freep(entry);
}
entries.clear();
}
SrsMp4DataEntryBox::SrsMp4DataEntryBox()
uint32_t SrsMp4DataReferenceBox::entry_count()
{
return (uint32_t)entries.size();
}
SrsMp4DataEntryUrlBox::SrsMp4DataEntryUrlBox()
SrsMp4DataEntryBox* SrsMp4DataReferenceBox::entry_at(int index)
{
type = 0x75726c20; // 'url '
return entries.at(index);
}
SrsMp4DataEntryUrnBox::SrsMp4DataEntryUrnBox()
int SrsMp4DataReferenceBox::nb_header()
{
type = 0x75726e20; // 'urn '
int size = SrsMp4FullBox::nb_header();
size += 4;
vector<SrsMp4DataEntryBox*>::iterator it;
for (it = entries.begin(); it != entries.end(); ++it) {
SrsMp4DataEntryBox* entry = *it;
size += entry->nb_bytes();
}
return size;
}
SrsMp4DataReferenceBox::SrsMp4DataReferenceBox()
int SrsMp4DataReferenceBox::encode_header(SrsBuffer* buf)
{
type = 0x64726566; // 'dref'
int ret = ERROR_SUCCESS;
entry_count = 0;
entries = NULL;
if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
buf->write_4bytes((int32_t)entries.size());
vector<SrsMp4DataEntryBox*>::iterator it;
for (it = entries.begin(); it != entries.end(); ++it) {
SrsMp4DataEntryBox* entry = *it;
if ((ret = entry->encode(buf)) != ERROR_SUCCESS) {
return ret;
}
}
return ret;
}
SrsMp4DataReferenceBox::~SrsMp4DataReferenceBox()
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<SrsMp4FullBox*>(box);
if (fbox) {
fbox->version = version;
fbox->flags = flags;
}
if (box->type == SRS_MP4_BOX_URL) {
entries.push_back(dynamic_cast<SrsMp4DataEntryUrlBox*>(box));
} else if (box->type == SRS_MP4_BOX_URN) {
entries.push_back(dynamic_cast<SrsMp4DataEntryUrnBox*>(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()
{
}
SrsMp4SampleDescriptionBox::SrsMp4SampleDescriptionBox()
int SrsMp4AudioSampleEntry::nb_header()
{
return SrsMp4SampleEntry::nb_header()+8+2+2+2+2+4;
}
int SrsMp4AudioSampleEntry::encode_header(SrsBuffer* buf)
{
type = 0x73747364; // 'stsd'
int ret = ERROR_SUCCESS;
entry_count = 0;
entries = NULL;
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 = SRS_MP4_BOX_STSD;
}
SrsMp4SampleDescriptionBox::~SrsMp4SampleDescriptionBox()
{
srs_freepa(entries);
vector<SrsMp4SampleEntry*>::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<SrsMp4SampleEntry*>::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<SrsMp4SampleEntry*>::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<SrsMp4SampleEntry*>(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;
}
... ...
... ... @@ -29,30 +29,77 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <srs_core.hpp>
#include <srs_kernel_buffer.hpp>
#include <string>
#include <vector>
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<SrsMp4Box*> 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<SrsMp4DataEntryBox*> 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<SrsMp4SampleEntry*> 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
... ...