1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-13 03:41:55 +00:00

for #738, decode mp4 video track boxes.

This commit is contained in:
winlin 2017-02-02 15:10:11 +08:00
parent 5a84b6ca94
commit 128a1fd3db
4 changed files with 301 additions and 118 deletions

View file

@ -236,6 +236,7 @@ int proxy(srs_mp4_t mp4, srs_rtmp_t ortmp)
int ret = 0; int ret = 0;
if ((ret = srs_mp4_init_demuxer(mp4)) != 0) { if ((ret = srs_mp4_init_demuxer(mp4)) != 0) {
srs_human_trace("init demuxer failed. ret=%d", ret);
return ret; return ret;
} }
if ((ret = connect_oc(ortmp)) != 0) { if ((ret = connect_oc(ortmp)) != 0) {

View file

@ -247,6 +247,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define ERROR_MP4_BOX_ILLEGAL_TYPE 3071 #define ERROR_MP4_BOX_ILLEGAL_TYPE 3071
#define ERROR_MP4_BOX_ILLEGAL_SCHEMA 3072 #define ERROR_MP4_BOX_ILLEGAL_SCHEMA 3072
#define ERROR_MP4_BOX_STRING 3073 #define ERROR_MP4_BOX_STRING 3073
#define ERROR_MP4_BOX_ILLEGAL_BRAND 3074
#define ERROR_MP4_NOT_NON_SEEKABLE 3075
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
// HTTP/StreamCaster/KAFKA protocol error. // HTTP/StreamCaster/KAFKA protocol error.

View file

@ -64,6 +64,18 @@ using namespace std;
#define SRS_MP4_BOX_CO64 0x636f3634 // 'co64' #define SRS_MP4_BOX_CO64 0x636f3634 // 'co64'
#define SRS_MP4_BOX_STSZ 0x7374737a // 'stsz' #define SRS_MP4_BOX_STSZ 0x7374737a // 'stsz'
#define SRS_MP4_BOX_STZ2 0x73747a32 // 'stz2' #define SRS_MP4_BOX_STZ2 0x73747a32 // 'stz2'
#define SRS_MP4_BOX_AVC1 0x61766331 // 'avc1'
#define SRS_MP4_BOX_AVCC 0x61766343 // 'avcC'
#define SRS_MP4_BOX_MP4A 0x6d703461 // 'mp4a'
#define SRS_MP4_BOX_ESDS 0x65736473 // 'esds'
#define SRS_MP4_BRAND_ISOM 0x69736f6d // 'isom'
#define SRS_MP4_BRAND_ISO2 0x69736f32 // 'iso2'
#define SRS_MP4_BRAND_AVC1 0x61766331 // 'avc1'
#define SRS_MP4_BRAND_MP41 0x6d703431 // 'mp41'
#define SRS_MP4_HANDLER_VIDE 0x76696465 // 'vide'
#define SRS_MP4_HANDLER_SOUN 0x736f756e // 'soun'
#define SRS_MP4_EOF_SIZE 0 #define SRS_MP4_EOF_SIZE 0
#define SRS_MP4_USE_LARGE_SIZE 1 #define SRS_MP4_USE_LARGE_SIZE 1
@ -75,9 +87,12 @@ int srs_mp4_string_length(const string& v)
void srs_mp4_string_write(SrsBuffer* buf, const string& v) void srs_mp4_string_write(SrsBuffer* buf, const string& v)
{ {
if (!v.empty()) { // Nothing for empty string.
buf->write_bytes((char*)v.data(), (int)v.length()); if (v.empty()) {
return;
} }
buf->write_bytes((char*)v.data(), (int)v.length());
buf->write_1bytes(0x00); buf->write_1bytes(0x00);
} }
@ -85,22 +100,25 @@ int srs_mp4_string_read(SrsBuffer* buf, string& v, int left)
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
char* p = buf->data() + buf->pos(); if (left == 0) {
char* start = p;
while (p < start + left) {
if (*p == 0x00) {
v.append(start, p - start);
buf->skip((int)(p - start));
return ret; return ret;
} }
}
char* start = buf->data() + buf->pos();
size_t len = strnlen(start, left);
if (len == left) {
ret = ERROR_MP4_BOX_STRING; ret = ERROR_MP4_BOX_STRING;
srs_error("MP4 string corrupt, left=%d. ret=%d", left, ret); srs_error("MP4 string corrupt, left=%d. ret=%d", left, ret);
return ret; return ret;
} }
v.append(start, len);
buf->skip((int)len + 1);
return ret;
}
SrsMp4Box::SrsMp4Box() SrsMp4Box::SrsMp4Box()
{ {
smallsize = 0; smallsize = 0;
@ -132,6 +150,21 @@ int SrsMp4Box::left_space(SrsBuffer* buf)
return (int)sz() - (buf->pos() - start_pos); return (int)sz() - (buf->pos() - start_pos);
} }
bool SrsMp4Box::is_ftyp()
{
return type == SRS_MP4_BOX_FTYP;
}
bool SrsMp4Box::is_moov()
{
return type == SRS_MP4_BOX_MOOV;
}
bool SrsMp4Box::is_mdat()
{
return type == SRS_MP4_BOX_MDAT;
}
int SrsMp4Box::discovery(SrsBuffer* buf, SrsMp4Box** ppbox) int SrsMp4Box::discovery(SrsBuffer* buf, SrsMp4Box** ppbox)
{ {
*ppbox = NULL; *ppbox = NULL;
@ -196,6 +229,9 @@ int SrsMp4Box::discovery(SrsBuffer* buf, SrsMp4Box** ppbox)
case SRS_MP4_BOX_STCO: box = new SrsMp4ChunkOffsetBox(); break; case SRS_MP4_BOX_STCO: box = new SrsMp4ChunkOffsetBox(); break;
case SRS_MP4_BOX_CO64: box = new SrsMp4ChunkLargeOffsetBox(); break; case SRS_MP4_BOX_CO64: box = new SrsMp4ChunkLargeOffsetBox(); break;
case SRS_MP4_BOX_STSZ: box = new SrsMp4SampleSizeBox(); break; case SRS_MP4_BOX_STSZ: box = new SrsMp4SampleSizeBox(); break;
case SRS_MP4_BOX_AVC1: box = new SrsMp4VisualSampleEntry(); break;
case SRS_MP4_BOX_AVCC: box = new SrsMp4AvccBox(); break;
case SRS_MP4_BOX_MP4A: box = new SrsMp4AudioSampleEntry(); break;
default: default:
ret = ERROR_MP4_BOX_ILLEGAL_TYPE; ret = ERROR_MP4_BOX_ILLEGAL_TYPE;
srs_error("MP4 illegal box type=%d. ret=%d", type, ret); srs_error("MP4 illegal box type=%d. ret=%d", type, ret);
@ -722,7 +758,7 @@ int SrsMp4MovieHeaderBox::decode_header(SrsBuffer* buf)
} }
rate = buf->read_4bytes(); rate = buf->read_4bytes();
volume = buf->read_4bytes(); volume = buf->read_2bytes();
buf->skip(2); buf->skip(2);
buf->skip(8); buf->skip(8);
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
@ -862,53 +898,6 @@ SrsMp4ElstEntry::SrsMp4ElstEntry()
media_rate_fraction = 0; 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() SrsMp4EditListBox::SrsMp4EditListBox()
{ {
type = SRS_MP4_BOX_ELST; type = SRS_MP4_BOX_ELST;
@ -924,11 +913,12 @@ SrsMp4EditListBox::~SrsMp4EditListBox()
int SrsMp4EditListBox::nb_header() int SrsMp4EditListBox::nb_header()
{ {
int size = SrsMp4FullBox::nb_header(); int size = SrsMp4FullBox::nb_header() + 4;
for (uint32_t i = 0; i < entry_count; i++) { if (version == 1) {
SrsMp4ElstEntry& entry = entries[i]; size += entry_count * (2+2+8+8);
size += entry.nb_header(version); } else {
size += entry_count * (2+2+4+4);
} }
return size; return size;
@ -942,11 +932,20 @@ int SrsMp4EditListBox::encode_header(SrsBuffer* buf)
return ret; return ret;
} }
buf->write_4bytes(entry_count);
for (uint32_t i = 0; i < entry_count; i++) { for (uint32_t i = 0; i < entry_count; i++) {
SrsMp4ElstEntry& entry = entries[i]; SrsMp4ElstEntry& entry = entries[i];
if ((ret = entry.encode_header(buf, version)) != ERROR_SUCCESS) {
return ret; if (version == 1) {
buf->write_8bytes(entry.segment_duration);
buf->write_8bytes(entry.media_time);
} else {
buf->write_4bytes((uint32_t)entry.segment_duration);
buf->write_4bytes((int32_t)entry.media_time);
} }
buf->write_2bytes(entry.media_rate_integer);
buf->write_2bytes(entry.media_rate_fraction);
} }
return ret; return ret;
@ -960,16 +959,23 @@ int SrsMp4EditListBox::decode_header(SrsBuffer* buf)
return ret; return ret;
} }
int left = left_space(buf); entry_count = buf->read_4bytes();
entry_count = left / SrsMp4ElstEntry().nb_header(version);
if (entry_count > 0) { if (entry_count > 0) {
entries = new SrsMp4ElstEntry[entry_count]; entries = new SrsMp4ElstEntry[entry_count];
} }
for (int i = 0; i < entry_count; i++) { for (int i = 0; i < entry_count; i++) {
SrsMp4ElstEntry& entry = entries[i]; SrsMp4ElstEntry& entry = entries[i];
if ((ret = entry.decode_header(buf, version)) != ERROR_SUCCESS) {
return ret; if (version == 1) {
entry.segment_duration = buf->read_8bytes();
entry.media_time = buf->read_8bytes();
} else {
entry.segment_duration = buf->read_4bytes();
entry.media_time = buf->read_4bytes();
} }
entry.media_rate_integer = buf->read_2bytes();
entry.media_rate_fraction = buf->read_2bytes();
} }
return ret; return ret;
@ -1104,6 +1110,16 @@ SrsMp4HandlerReferenceBox::~SrsMp4HandlerReferenceBox()
{ {
} }
bool SrsMp4HandlerReferenceBox::is_video()
{
return handler_type == SRS_MP4_HANDLER_VIDE;
}
bool SrsMp4HandlerReferenceBox::is_audio()
{
return handler_type == SRS_MP4_HANDLER_SOUN;
}
int SrsMp4HandlerReferenceBox::nb_header() int SrsMp4HandlerReferenceBox::nb_header()
{ {
return SrsMp4FullBox::nb_header()+4+4+12+srs_mp4_string_length(name); return SrsMp4FullBox::nb_header()+4+4+12+srs_mp4_string_length(name);
@ -1268,12 +1284,26 @@ SrsMp4DataEntryBox::~SrsMp4DataEntryBox()
{ {
} }
int SrsMp4DataEntryBox::nb_header() SrsMp4DataEntryUrlBox::SrsMp4DataEntryUrlBox()
{ {
type = SRS_MP4_BOX_URL;
}
SrsMp4DataEntryUrlBox::~SrsMp4DataEntryUrlBox()
{
}
int SrsMp4DataEntryUrlBox::nb_header()
{
// a 24-bit integer with flags; one flag is defined (x000001) which means that the media
// data is in the same file as the Movie Box containing this data reference.
if (flags == 1) {
return SrsMp4FullBox::nb_header();
}
return SrsMp4FullBox::nb_header()+srs_mp4_string_length(location); return SrsMp4FullBox::nb_header()+srs_mp4_string_length(location);
} }
int SrsMp4DataEntryBox::encode_header(SrsBuffer* buf) int SrsMp4DataEntryUrlBox::encode_header(SrsBuffer* buf)
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
@ -1281,12 +1311,19 @@ int SrsMp4DataEntryBox::encode_header(SrsBuffer* buf)
return ret; return ret;
} }
// a 24-bit integer with flags; one flag is defined (x000001) which means that the media
// data is in the same file as the Movie Box containing this data reference.
if (location.empty()) {
flags = 0x01;
return ret;
}
srs_mp4_string_write(buf, location); srs_mp4_string_write(buf, location);
return ret; return ret;
} }
int SrsMp4DataEntryBox::decode_header(SrsBuffer* buf) int SrsMp4DataEntryUrlBox::decode_header(SrsBuffer* buf)
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
@ -1294,23 +1331,20 @@ int SrsMp4DataEntryBox::decode_header(SrsBuffer* buf)
return ret; return ret;
} }
// a 24-bit integer with flags; one flag is defined (x000001) which means that the media
// data is in the same file as the Movie Box containing this data reference.
if (flags == 0x01) {
return ret;
}
if ((ret = srs_mp4_string_read(buf, location, left_space(buf))) != ERROR_SUCCESS) { if ((ret = srs_mp4_string_read(buf, location, left_space(buf))) != ERROR_SUCCESS) {
srs_error("MP4 urx read string failed. ret=%d", ret); srs_error("MP4 url read location failed. ret=%d", ret);
return ret; return ret;
} }
return ret; return ret;
} }
SrsMp4DataEntryUrlBox::SrsMp4DataEntryUrlBox()
{
type = SRS_MP4_BOX_URL;
}
SrsMp4DataEntryUrlBox::~SrsMp4DataEntryUrlBox()
{
}
SrsMp4DataEntryUrnBox::SrsMp4DataEntryUrnBox() SrsMp4DataEntryUrnBox::SrsMp4DataEntryUrnBox()
{ {
type = SRS_MP4_BOX_URN; type = SRS_MP4_BOX_URN;
@ -1322,7 +1356,7 @@ SrsMp4DataEntryUrnBox::~SrsMp4DataEntryUrnBox()
int SrsMp4DataEntryUrnBox::nb_header() int SrsMp4DataEntryUrnBox::nb_header()
{ {
return SrsMp4DataEntryBox::nb_header()+srs_mp4_string_length(name); return SrsMp4FullBox::nb_header()+srs_mp4_string_length(location)+srs_mp4_string_length(name);
} }
int SrsMp4DataEntryUrnBox::encode_header(SrsBuffer* buf) int SrsMp4DataEntryUrnBox::encode_header(SrsBuffer* buf)
@ -1333,6 +1367,7 @@ int SrsMp4DataEntryUrnBox::encode_header(SrsBuffer* buf)
return ret; return ret;
} }
srs_mp4_string_write(buf, location);
srs_mp4_string_write(buf, name); srs_mp4_string_write(buf, name);
return ret; return ret;
@ -1346,8 +1381,13 @@ int SrsMp4DataEntryUrnBox::decode_header(SrsBuffer* buf)
return ret; return ret;
} }
if ((ret = srs_mp4_string_read(buf, location, left_space(buf))) != ERROR_SUCCESS) {
srs_error("MP4 urn read location failed. ret=%d", ret);
return ret;
}
if ((ret = srs_mp4_string_read(buf, name, left_space(buf))) != ERROR_SUCCESS) { if ((ret = srs_mp4_string_read(buf, name, left_space(buf))) != ERROR_SUCCESS) {
srs_error("MP4 urn read string failed. ret=%d", ret); srs_error("MP4 urn read name failed. ret=%d", ret);
return ret; return ret;
} }
@ -1578,6 +1618,55 @@ int SrsMp4VisualSampleEntry::decode_header(SrsBuffer* buf)
return ret; return ret;
} }
SrsMp4AvccBox::SrsMp4AvccBox()
{
type = SRS_MP4_BOX_AVCC;
nb_config = 0;
avc_config = NULL;
}
SrsMp4AvccBox::~SrsMp4AvccBox()
{
srs_freepa(avc_config);
}
int SrsMp4AvccBox::nb_header()
{
return SrsMp4Box::nb_header()+nb_config;
}
int SrsMp4AvccBox::encode_header(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
if ((ret = SrsMp4Box::encode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
if (nb_config) {
buf->write_bytes((char*)avc_config, nb_config);
}
return ret;
}
int SrsMp4AvccBox::decode_header(SrsBuffer* buf)
{
int ret = ERROR_SUCCESS;
if ((ret = SrsMp4Box::decode_header(buf)) != ERROR_SUCCESS) {
return ret;
}
nb_config = left_space(buf);
if (nb_config) {
avc_config = new uint8_t[nb_config];
buf->read_bytes((char*)avc_config, nb_config);
}
return ret;
}
SrsMp4AudioSampleEntry::SrsMp4AudioSampleEntry() SrsMp4AudioSampleEntry::SrsMp4AudioSampleEntry()
{ {
reserved0 = 0; reserved0 = 0;
@ -1905,8 +1994,7 @@ int SrsMp4SyncSampleBox::decode_header(SrsBuffer* buf)
sample_numbers = new uint32_t[entry_count]; sample_numbers = new uint32_t[entry_count];
} }
for (uint32_t i = 0; i < entry_count; i++) { for (uint32_t i = 0; i < entry_count; i++) {
uint32_t sample_number = sample_numbers[i]; sample_numbers[i] = buf->read_4bytes();
buf->write_4bytes(sample_number);
} }
return ret; return ret;
@ -2143,16 +2231,18 @@ int SrsMp4SampleSizeBox::decode_header(SrsBuffer* buf)
return ret; return ret;
} }
#define SRS_MP4_BUF_SIZE 4096
SrsMp4Decoder::SrsMp4Decoder() SrsMp4Decoder::SrsMp4Decoder()
{ {
reader = NULL; reader = NULL;
next = NULL; buf = new char[SRS_MP4_BUF_SIZE];
stream = new SrsSimpleStream(); stream = new SrsSimpleStream();
} }
SrsMp4Decoder::~SrsMp4Decoder() SrsMp4Decoder::~SrsMp4Decoder()
{ {
srs_freep(next); srs_freepa(buf);
srs_freep(stream); srs_freep(stream);
} }
@ -2163,36 +2253,90 @@ int SrsMp4Decoder::initialize(ISrsReader* r)
srs_assert(r); srs_assert(r);
reader = r; reader = r;
if ((ret = load_next_box(&next)) != ERROR_SUCCESS) { // File Type Box (ftyp)
if (true) {
SrsMp4Box* box = NULL;
SrsAutoFree(SrsMp4Box, box);
if ((ret = load_next_box(&box, SRS_MP4_BOX_FTYP)) != ERROR_SUCCESS) {
return ret;
}
SrsMp4FileTypeBox* ftyp = dynamic_cast<SrsMp4FileTypeBox*>(box);
bool legal_brand = false;
static uint32_t legal_brands[] = {
SRS_MP4_BRAND_ISOM, SRS_MP4_BRAND_ISO2, SRS_MP4_BRAND_AVC1, SRS_MP4_BRAND_MP41
};
for (int i = 0; i < sizeof(legal_brands)/sizeof(uint32_t); i++) {
if (ftyp->major_brand == legal_brands[i]) {
legal_brand = true;
break;
}
}
if (!legal_brand) {
ret = ERROR_MP4_BOX_ILLEGAL_BRAND;
srs_error("MP4 brand is illegal, brand=%d. ret=%d", ftyp->major_brand, ret);
return ret;
}
}
// Media Data Box (mdat) or Movie Box (moov)
SrsMp4Box* box = NULL;
SrsAutoFree(SrsMp4Box, box);
while (true) {
if ((ret = load_next_box(&box, 0)) != ERROR_SUCCESS) {
return ret; return ret;
} }
if (next->type != SRS_MP4_BOX_FTYP) { if (!box->is_mdat() && !box->is_moov()) {
ret = ERROR_MP4_BOX_ILLEGAL_SCHEMA; srs_freep(box);
srs_error("MP4 first box must be FTYP, not %d. ret=%d", next->type, ret); continue;
}
break;
}
// Only support non-seek mp4, that is, mdat should never before moov.
// @see https://github.com/ossrs/srs/issues/738#issuecomment-276343669
if (box->is_mdat()) {
ret = ERROR_MP4_NOT_NON_SEEKABLE;
srs_error("MP4 is not non-seekable. ret=%d", ret);
return ret; return ret;
} }
return ret; return ret;
} }
int SrsMp4Decoder::load_next_box(SrsMp4Box** ppbox) int SrsMp4Decoder::load_next_box(SrsMp4Box** ppbox, uint32_t required_box_type)
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
// Ignore for already loaded. while (true) {
if (next) { SrsMp4Box* box = NULL;
if ((ret = do_load_next_box(&box, required_box_type)) != ERROR_SUCCESS) {
srs_freep(box);
return ret; return ret;
} }
char* buf = new char[4096]; if (!required_box_type || box->type == required_box_type) {
SrsAutoFreeA(char, buf); *ppbox = box;
break;
}
srs_freep(box);
}
return ret;
}
int SrsMp4Decoder::do_load_next_box(SrsMp4Box** ppbox, uint32_t required_box_type)
{
int ret = ERROR_SUCCESS;
SrsMp4Box* box = NULL;
while (true) { while (true) {
uint64_t required = next? next->sz():4; uint64_t required = box? box->sz():4;
while (stream->length() < required) { while (stream->length() < required) {
ssize_t nread; ssize_t nread;
if ((ret = reader->read(buf, 4096, &nread)) != ERROR_SUCCESS) { if ((ret = reader->read(buf, SRS_MP4_BUF_SIZE, &nread)) != ERROR_SUCCESS) {
srs_error("MP4 load failed, nread=%d, required=%d. ret=%d", nread, required, ret); srs_error("MP4 load failed, nread=%d, required=%d. ret=%d", nread, required, ret);
return ret; return ret;
} }
@ -2205,7 +2349,7 @@ int SrsMp4Decoder::load_next_box(SrsMp4Box** ppbox)
SrsAutoFree(SrsBuffer, buffer); SrsAutoFree(SrsBuffer, buffer);
// Discovery the box with basic header. // Discovery the box with basic header.
if (!next && (ret = SrsMp4Box::discovery(buffer, ppbox)) != ERROR_SUCCESS) { if (!box && (ret = SrsMp4Box::discovery(buffer, &box)) != ERROR_SUCCESS) {
if (ret == ERROR_MP4_BOX_REQUIRE_SPACE) { if (ret == ERROR_MP4_BOX_REQUIRE_SPACE) {
continue; continue;
} }
@ -2214,13 +2358,23 @@ int SrsMp4Decoder::load_next_box(SrsMp4Box** ppbox)
} }
// Decode util we can demux the whole box. // Decode util we can demux the whole box.
if (!buffer->require((int)next->sz())) { if (!buffer->require((int)box->sz())) {
continue; continue;
} }
ret = next->decode(buffer);
if (!required_box_type || box->type == required_box_type) {
ret = box->decode(buffer);
}
// Remove the consumed bytes. // Remove the consumed bytes.
stream->erase((int)next->sz()); stream->erase((int)box->sz());
if (ret != ERROR_SUCCESS) {
srs_freep(box);
} else {
*ppbox = box;
}
break; break;
} }

View file

@ -72,6 +72,10 @@ public:
virtual uint64_t sz(); virtual uint64_t sz();
// Get the left space of box, for decoder. // Get the left space of box, for decoder.
virtual int left_space(SrsBuffer* buf); virtual int left_space(SrsBuffer* buf);
// Box type helper.
virtual bool is_ftyp();
virtual bool is_moov();
virtual bool is_mdat();
/** /**
* Discovery the box from buffer. * Discovery the box from buffer.
* @param ppbox Output the discoveried box, which user must free it. * @param ppbox Output the discoveried box, which user must free it.
@ -353,10 +357,6 @@ public:
int16_t media_rate_fraction; int16_t media_rate_fraction;
public: public:
SrsMp4ElstEntry(); 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);
}; };
/** /**
@ -463,6 +463,9 @@ public:
public: public:
SrsMp4HandlerReferenceBox(); SrsMp4HandlerReferenceBox();
virtual ~SrsMp4HandlerReferenceBox(); virtual ~SrsMp4HandlerReferenceBox();
public:
virtual bool is_video();
virtual bool is_audio();
protected: protected:
virtual int nb_header(); virtual int nb_header();
virtual int encode_header(SrsBuffer* buf); virtual int encode_header(SrsBuffer* buf);
@ -542,6 +545,8 @@ public:
/** /**
* 8.7.2 Data Reference Box * 8.7.2 Data Reference Box
* ISO_IEC_14496-12-base-format-2012.pdf, page 56 * ISO_IEC_14496-12-base-format-2012.pdf, page 56
* a 24-bit integer with flags; one flag is defined (x000001) which means that the media
* data is in the same file as the Movie Box containing this data reference.
*/ */
class SrsMp4DataEntryBox : public SrsMp4FullBox class SrsMp4DataEntryBox : public SrsMp4FullBox
{ {
@ -550,10 +555,6 @@ public:
public: public:
SrsMp4DataEntryBox(); SrsMp4DataEntryBox();
virtual ~SrsMp4DataEntryBox(); virtual ~SrsMp4DataEntryBox();
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
virtual int decode_header(SrsBuffer* buf);
}; };
/** /**
@ -565,6 +566,10 @@ class SrsMp4DataEntryUrlBox : public SrsMp4DataEntryBox
public: public:
SrsMp4DataEntryUrlBox(); SrsMp4DataEntryUrlBox();
virtual ~SrsMp4DataEntryUrlBox(); virtual ~SrsMp4DataEntryUrlBox();
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
virtual int decode_header(SrsBuffer* buf);
}; };
/** /**
@ -679,6 +684,24 @@ protected:
virtual int decode_header(SrsBuffer* buf); virtual int decode_header(SrsBuffer* buf);
}; };
/**
* 5.3.4 AVC Video Stream Definition (avcC)
* ISO_IEC_14496-15-AVC-format-2012.pdf, page 19
*/
class SrsMp4AvccBox : public SrsMp4Box
{
public:
int nb_config;
uint8_t* avc_config;
public:
SrsMp4AvccBox();
virtual ~SrsMp4AvccBox();
protected:
virtual int nb_header();
virtual int encode_header(SrsBuffer* buf);
virtual int decode_header(SrsBuffer* buf);
};
/** /**
* 8.5.2 Sample Description Box (mp4a) * 8.5.2 Sample Description Box (mp4a)
* ISO_IEC_14496-12-base-format-2012.pdf, page 45 * ISO_IEC_14496-12-base-format-2012.pdf, page 45
@ -957,8 +980,8 @@ private:
// The stream used to demux the boxes. // The stream used to demux the boxes.
// TODO: FIXME: refine for performance issue. // TODO: FIXME: refine for performance issue.
SrsSimpleStream* stream; SrsSimpleStream* stream;
// Always load next box. // The temporary buffer to read from buffer.
SrsMp4Box* next; char* buf;
public: public:
SrsMp4Decoder(); SrsMp4Decoder();
virtual ~SrsMp4Decoder(); virtual ~SrsMp4Decoder();
@ -970,7 +993,10 @@ public:
*/ */
virtual int initialize(ISrsReader* r); virtual int initialize(ISrsReader* r);
private: private:
virtual int load_next_box(SrsMp4Box** ppbox); // Load the next box from reader.
// @param required_box_type The box type required, 0 for any box.
virtual int load_next_box(SrsMp4Box** ppbox, uint32_t required_box_type);
virtual int do_load_next_box(SrsMp4Box** ppbox, uint32_t required_box_type);
}; };
#endif #endif