mirror of
https://github.com/ossrs/srs.git
synced 2025-02-12 19:31:53 +00:00
Refine mp4 codec for mdat.
This commit is contained in:
parent
18d9f6c8f1
commit
c9bed5a8bf
3 changed files with 118 additions and 39 deletions
1
trunk/.gitignore
vendored
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…
Reference in a new issue