Refine mp4 codec for mdat.

pull/854/head
winlin 8 years ago
parent 18d9f6c8f1
commit c9bed5a8bf

1
trunk/.gitignore vendored

@ -5,6 +5,7 @@
/doc/frozen*.flv
/doc/kungfupanda*.flv
/doc/time*.flv
/doc/source*.mp4
/html
/ide/srs_xcode/srs_xcode.xcodeproj/project.xcworkspace/xcshareddata/
/ide/srs_xcode/srs_xcode.xcodeproj/project.xcworkspace/xcuserdata/

@ -103,6 +103,11 @@ uint64_t SrsMp4Box::sz()
return smallsize == SRS_MP4_USE_LARGE_SIZE? largesize:smallsize;
}
int SrsMp4Box::sz_header()
{
return nb_header();
}
int SrsMp4Box::left_space(SrsBuffer* buf)
{
return (int)sz() - (buf->pos() - start_pos);
@ -193,7 +198,6 @@ int SrsMp4Box::discovery(SrsBuffer* buf, SrsMp4Box** ppbox)
switch(type) {
case SrsMp4BoxTypeFTYP: box = new SrsMp4FileTypeBox(); break;
case SrsMp4BoxTypeMDAT: box = new SrsMp4MediaDataBox(); break;
case SrsMp4BoxTypeFREE: case SrsMp4BoxTypeSKIP: box = new SrsMp4FreeSpaceBox(); break;
case SrsMp4BoxTypeMOOV: box = new SrsMp4MovieBox(); break;
case SrsMp4BoxTypeMVHD: box = new SrsMp4MovieHeaderBox(); break;
case SrsMp4BoxTypeTRAK: box = new SrsMp4TrackBox(); break;
@ -226,6 +230,9 @@ int SrsMp4Box::discovery(SrsBuffer* buf, SrsMp4Box** ppbox)
case SrsMp4BoxTypeUDTA: box = new SrsMp4UserDataBox(); break;
case SrsMp4BoxTypeMVEX: box = new SrsMp4MovieExtendsBox(); break;
case SrsMp4BoxTypeTREX: box = new SrsMp4TrackExtendsBox(); break;
// Skip some unknown boxes.
case SrsMp4BoxTypeFREE: case SrsMp4BoxTypeSKIP: case SrsMp4BoxTypePASP:
box = new SrsMp4FreeSpaceBox(); break;
default:
ret = ERROR_MP4_BOX_ILLEGAL_TYPE;
srs_error("MP4 illegal box type=%d. ret=%d", type, ret);
@ -259,7 +266,7 @@ int SrsMp4Box::encode(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
uint64_t size = encode_actual_size();
uint64_t size = nb_bytes();
if (size > 0xffffffff) {
largesize = size;
} else {
@ -407,7 +414,7 @@ int SrsMp4Box::decode_header(SrsBuffer* buf)
type = (SrsMp4BoxType)buf->read_4bytes();
if (smallsize == SRS_MP4_EOF_SIZE) {
srs_warn("MP4 box EOF.");
srs_trace("MP4 box EOF.");
return ret;
}
@ -448,11 +455,6 @@ int SrsMp4Box::decode_header(SrsBuffer* buf)
return ret;
}
uint64_t SrsMp4Box::encode_actual_size()
{
return nb_bytes();
}
SrsMp4FullBox::SrsMp4FullBox()
{
version = 0;
@ -589,20 +591,29 @@ int SrsMp4FileTypeBox::decode_header(SrsBuffer* buf)
SrsMp4MediaDataBox::SrsMp4MediaDataBox()
{
type = SrsMp4BoxTypeMDAT;
data = NULL;
nb_data = 0;
}
SrsMp4MediaDataBox::~SrsMp4MediaDataBox()
{
srs_freepa(data);
}
uint64_t SrsMp4MediaDataBox::encode_actual_size()
int SrsMp4MediaDataBox::nb_bytes()
{
return SrsMp4Box::nb_header() + nb_data;
}
int SrsMp4MediaDataBox::encode(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
if ((ret = SrsMp4Box::encode(buf)) != ERROR_SUCCESS) {
return ret;
}
return ret;
}
int SrsMp4MediaDataBox::decode(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
@ -611,11 +622,23 @@ int SrsMp4MediaDataBox::decode(SrsBuffer* buf)
return ret;
}
nb_data = left_space(buf);
nb_data = (int)(sz() - nb_header());
// Because the
return ret;
}
int SrsMp4MediaDataBox::encode_boxes(SrsBuffer* buf)
{
return ERROR_SUCCESS;
}
int SrsMp4MediaDataBox::decode_boxes(SrsBuffer* buf)
{
return ERROR_SUCCESS;
}
SrsMp4FreeSpaceBox::SrsMp4FreeSpaceBox()
{
type = SrsMp4BoxTypeFREE; // 'free' or 'skip'
@ -627,7 +650,7 @@ SrsMp4FreeSpaceBox::~SrsMp4FreeSpaceBox()
int SrsMp4FreeSpaceBox::nb_header()
{
return SrsMp4Box::nb_header() + data.size();
return SrsMp4Box::nb_header() + (int)data.size();
}
int SrsMp4FreeSpaceBox::encode_header(SrsBuffer* buf)
@ -639,7 +662,7 @@ int SrsMp4FreeSpaceBox::encode_header(SrsBuffer* buf)
}
if (!data.empty()) {
buf->write_bytes(&data[0], data.size());
buf->write_bytes(&data[0], (int)data.size());
}
return ret;
@ -4184,7 +4207,13 @@ int SrsMp4Decoder::do_load_next_box(SrsMp4Box** ppbox, uint32_t required_box_typ
SrsMp4Box* box = NULL;
while (true) {
// For the first time to read the box, maybe it's a basic box which is only 4bytes header.
// When we disconvery the real box, we know the size of the whole box, then read again and decode it.
uint64_t required = box? box->sz():4;
// For mdat box, we only requires to decode the header.
if (box && box->is_mdat()) {
required = box->sz_header();
}
while (stream->length() < (int)required) {
ssize_t nread;
if ((ret = rsio->read(buf, SRS_MP4_BUF_SIZE, &nread)) != ERROR_SUCCESS) {
@ -4208,15 +4237,17 @@ int SrsMp4Decoder::do_load_next_box(SrsMp4Box** ppbox, uint32_t required_box_typ
return ret;
}
// Util we can demux the whole box.
// When box is discoveried, check whether we can demux the whole box.
// For mdat, only the header is required.
if (!box->is_mdat()) {
if (!buffer->require((int)box->sz())) {
continue;
}
required = (box->is_mdat()? box->sz_header():box->sz());
if (!buffer->require((int)required)) {
continue;
}
// Decode the matched box or any box is matched.
// Decode the box:
// 1. Any box, when no box type is required.
// 2. Matched box, when box type match the required type.
// 3. Mdat box, always decode the mdat because we only decode the header of it.
if (!required_box_type || box->type == required_box_type || box->is_mdat()) {
ret = box->decode(buffer);
}
@ -4316,7 +4347,7 @@ int SrsMp4Encoder::initialize(ISrsWriteSeeker* ws)
return ret;
}
int nb_data = mdat->nb_bytes();
int nb_data = mdat->sz_header();
uint8_t* data = new uint8_t[nb_data];
SrsAutoFreeA(uint8_t, data);
if ((ret = buffer->initialize((char*)data, nb_data)) != ERROR_SUCCESS) {
@ -4573,13 +4604,13 @@ int SrsMp4Encoder::flush()
return ret;
}
// Write empty mdat box,
// its payload will be writen by samples,
// Write mdat box with size of data,
// its payload already writen by samples,
// and we will update its header(size) when flush.
SrsMp4MediaDataBox* mdat = new SrsMp4MediaDataBox();
SrsAutoFree(SrsMp4MediaDataBox, mdat);
int nb_data = mdat->nb_bytes();
int nb_data = mdat->sz_header();
uint8_t* data = new uint8_t[nb_data];
SrsAutoFreeA(uint8_t, data);
if ((ret = buffer->initialize((char*)data, nb_data)) != ERROR_SUCCESS) {
@ -4606,7 +4637,7 @@ int SrsMp4Encoder::copy_sequence_header(bool vsh, uint8_t* sample, uint32_t nb_s
int ret = ERROR_SUCCESS;
if (vsh && !pavcc.empty()) {
if (nb_sample == pavcc.size() && srs_bytes_equals(sample, &pavcc[0], pavcc.size())) {
if (nb_sample == pavcc.size() && srs_bytes_equals(sample, &pavcc[0], (int)pavcc.size())) {
return ret;
}
@ -4616,7 +4647,7 @@ int SrsMp4Encoder::copy_sequence_header(bool vsh, uint8_t* sample, uint32_t nb_s
}
if (!vsh && !pasc.empty()) {
if (nb_sample == pasc.size() && srs_bytes_equals(sample, &pasc[0], pasc.size())) {
if (nb_sample == pasc.size() && srs_bytes_equals(sample, &pasc[0], (int)pasc.size())) {
return ret;
}

@ -110,6 +110,8 @@ enum SrsMp4BoxType
SrsMp4BoxTypeUDTA = 0x75647461, // 'udta'
SrsMp4BoxTypeMVEX = 0x6d766578, // 'mvex'
SrsMp4BoxTypeTREX = 0x74726578, // 'trex'
SrsMp4BoxTypePASP = 0x70617370, // 'pasp'
};
/**
@ -172,7 +174,11 @@ public:
virtual ~SrsMp4Box();
public:
// Get the size of box, whatever small or large size.
// @remark For general box(except mdat), we use this sz() to create the buffer to codec it.
virtual uint64_t sz();
// Get the size of header, without contained boxes.
// @remark For mdat box, we must codec its header, use this instead of sz().
virtual int sz_header();
// Get the left space of box, for decoder.
virtual int left_space(SrsBuffer* buf);
// Box type helper.
@ -198,7 +204,8 @@ public:
protected:
virtual int encode_boxes(SrsBuffer* buf);
virtual int decode_boxes(SrsBuffer* buf);
// Sub classes can override these functions for special codec.
// Sub classes can override these functions for special codec.
// @remark For mdat box, we use completely different codec.
protected:
// The size of header, not including the contained boxes.
virtual int nb_header();
@ -208,13 +215,6 @@ protected:
// 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);
protected:
// The actual size of this box, generally it must equal to nb_bytes,
// but for some special boxes, for instance mdat, the box encode actual size maybe large than
// the nb_bytes to write, because the data is written directly.
// That is, the actual size is used to encode the box size in header,
// while the nb_bytes is the bytes encoded the box.
virtual uint64_t encode_actual_size();
};
/**
@ -273,22 +273,69 @@ protected:
* A presentation may contain zero or more Media Data Boxes. The actual media data follows the type field;
* its structure is described by the metadata (see particularly the sample table, subclause 8.5, and the
* item location box, subclause 8.11.3).
*
* @remark The mdat box only decode and encode the header,
* so user must read and write the data by yourself.
* To encode mdat:
* SrsMp4MediaDataBox* mdat = new SrsMp4MediaDataBox();
* mdat->nb_data = 1024000;
*
* char* buffer = new char[mdat->sz_header()];
* SrsBuffer* buf = new SrsBuffer(buffer);
* mdat->encode(buf);
*
* file->write(buffer, mdat->sz_header()); // Write the mdat box header.
* file->write(data, size); // Write the mdat box data.
*
* To decode mdat:
* SrsMp4MediaDataBox* mdat = new SrsMp4MediaDataBox();
* char* buffer = new char[mdat->sz_header()];
* SrsBuffer* buf = ...; // Read mdat->sz_header() data from io.
*
* mdat->decode(buf); // The buf should be empty now.
* file->lseek(mdat->nb_data, SEEK_CUR); // Skip the mdat data in file.
*
* To discovery any box from file:
* SrsSimpleStream* stream = new SrsSimpleStream();
* SrsBuffer* buf = new SrsBuffer(stream...); // Create read buffer from stream.
*
* // We don't know what's the next box, so try to read 4bytes and discovery it.
* append(file, stream, 4); // Append 4bytes from file to stream.
*
* SrsMp4Box* box = NULL;
* SrsMp4Box::discovery(buf, &box);
*
* required = (box->is_mdat()? box->sz_header():box->sz()); // Now we know how many bytes we needed.
* append(file, stream, required);
* box->decode(buf);
*
* if (box->is_mdat()) {
* file->lseek(mdat->nb_data, SEEK_CUR); // Skip the mdat data in file.
* }
*/
class SrsMp4MediaDataBox : public SrsMp4Box
{
public:
// the contained media data
// The contained media data, which we never directly read/write it.
// TODO: FIXME: Support 64bits size.
int nb_data;
// @remark User must alloc the data and codec it.
uint8_t* data;
public:
SrsMp4MediaDataBox();
virtual ~SrsMp4MediaDataBox();
protected:
virtual uint64_t encode_actual_size();
// Interface ISrsCodec
public:
// The total size of bytes, including the sz_header() and nb_data,
// which used to write the smallsize or largesize of mp4.
virtual int nb_bytes();
// To encode the mdat box, the buf should only contains the sz_header(),
// because the mdata only encode the header.
virtual int encode(SrsBuffer* buf);
// To decode the mdat box, the buf should only contains the sz_header(),
// because the mdat only decode the header.
virtual int decode(SrsBuffer* buf);
protected:
virtual int encode_boxes(SrsBuffer* buf);
virtual int decode_boxes(SrsBuffer* buf);
};
/**

Loading…
Cancel
Save