Refine mp4, extract mp4 box reader.

pull/854/head
winlin 8 years ago
parent c9bed5a8bf
commit 6ee85aea83

@ -3911,11 +3911,109 @@ int SrsMp4SampleManager::load_trak(map<uint64_t, SrsMp4Sample*>& tses, SrsFrameT
return ret; return ret;
} }
SrsMp4BoxReader::SrsMp4BoxReader()
{
rsio = NULL;
buf = new char[SRS_MP4_BUF_SIZE];
}
SrsMp4BoxReader::~SrsMp4BoxReader()
{
srs_freepa(buf);
}
int SrsMp4BoxReader::initialize(ISrsReadSeeker* rs)
{
rsio = rs;
return ERROR_SUCCESS;
}
int SrsMp4BoxReader::read(SrsSimpleStream* stream, SrsMp4Box** ppbox)
{
int ret = ERROR_SUCCESS;
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();
}
// Fill the stream util we can discovery box.
while (stream->length() < (int)required) {
ssize_t nread;
if ((ret = rsio->read(buf, SRS_MP4_BUF_SIZE, &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 (!box && (ret = SrsMp4Box::discovery(buffer, &box)) != ERROR_SUCCESS) {
if (ret == ERROR_MP4_BOX_REQUIRE_SPACE) {
continue;
}
srs_error("MP4 load box failed. ret=%d", ret);
return ret;
}
// When box is discoveried, check whether we can demux the whole box.
// For mdat, only the header is required.
required = (box->is_mdat()? box->sz_header():box->sz());
if (!buffer->require((int)required)) {
continue;
}
if (ret != ERROR_SUCCESS) {
srs_freep(box);
} else {
*ppbox = box;
}
break;
}
return ret;
}
int SrsMp4BoxReader::skip(SrsMp4Box* box, SrsSimpleStream* stream)
{
int ret = ERROR_SUCCESS;
// For mdat, always skip the content.
if (box->is_mdat()) {
int offset = (int)(box->sz() - stream->length());
if (offset < 0) {
stream->erase(stream->length() + offset);
} else {
stream->erase(stream->length());
}
if (offset > 0 && (ret = rsio->lseek(offset, SEEK_CUR, NULL)) != ERROR_SUCCESS) {
return ret;
}
} else {
// Remove the consumed bytes.
stream->erase((int)box->sz());
}
return ret;
}
SrsMp4Decoder::SrsMp4Decoder() SrsMp4Decoder::SrsMp4Decoder()
{ {
rsio = NULL; rsio = NULL;
brand = SrsMp4BoxBrandForbidden; brand = SrsMp4BoxBrandForbidden;
buf = new char[SRS_MP4_BUF_SIZE];
stream = new SrsSimpleStream(); stream = new SrsSimpleStream();
vcodec = SrsVideoCodecIdForbidden; vcodec = SrsVideoCodecIdForbidden;
acodec = SrsAudioCodecIdForbidden; acodec = SrsAudioCodecIdForbidden;
@ -3924,13 +4022,14 @@ SrsMp4Decoder::SrsMp4Decoder()
sound_bits = SrsAudioSampleBitsForbidden; sound_bits = SrsAudioSampleBitsForbidden;
channels = SrsAudioChannelsForbidden; channels = SrsAudioChannelsForbidden;
samples = new SrsMp4SampleManager(); samples = new SrsMp4SampleManager();
br = new SrsMp4BoxReader();
current_index = 0; current_index = 0;
current_offset = 0; current_offset = 0;
} }
SrsMp4Decoder::~SrsMp4Decoder() SrsMp4Decoder::~SrsMp4Decoder()
{ {
srs_freepa(buf); srs_freep(br);
srs_freep(stream); srs_freep(stream);
srs_freep(samples); srs_freep(samples);
} }
@ -3942,6 +4041,10 @@ int SrsMp4Decoder::initialize(ISrsReadSeeker* rs)
srs_assert(rs); srs_assert(rs);
rsio = rs; rsio = rs;
if ((ret = br->initialize(rs)) != ERROR_SUCCESS) {
return ret;
}
// For mdat before moov, we must reset the offset to the mdat. // For mdat before moov, we must reset the offset to the mdat.
off_t offset = -1; off_t offset = -1;
@ -3997,7 +4100,7 @@ int SrsMp4Decoder::read_sample(SrsMp4HandlerType* pht, uint16_t* pft, uint16_t*
*pdts = *ppts = 0; *pdts = *ppts = 0;
*pht = SrsMp4HandlerTypeVIDE; *pht = SrsMp4HandlerTypeVIDE;
uint32_t nb_sample = *pnb_sample = pavcc.size(); uint32_t nb_sample = *pnb_sample = (uint32_t)pavcc.size();
uint8_t* sample = *psample = new uint8_t[nb_sample]; uint8_t* sample = *psample = new uint8_t[nb_sample];
memcpy(sample, &pavcc[0], nb_sample); memcpy(sample, &pavcc[0], nb_sample);
@ -4012,7 +4115,7 @@ int SrsMp4Decoder::read_sample(SrsMp4HandlerType* pht, uint16_t* pft, uint16_t*
*pdts = *ppts = 0; *pdts = *ppts = 0;
*pht = SrsMp4HandlerTypeSOUN; *pht = SrsMp4HandlerTypeSOUN;
uint32_t nb_sample = *pnb_sample = pasc.size(); uint32_t nb_sample = *pnb_sample = (uint32_t)pasc.size();
uint8_t* sample = *psample = new uint8_t[nb_sample]; uint8_t* sample = *psample = new uint8_t[nb_sample];
memcpy(sample, &pasc[0], nb_sample); memcpy(sample, &pasc[0], nb_sample);
@ -4165,15 +4268,15 @@ int SrsMp4Decoder::parse_moov(SrsMp4MovieBox* moov)
ss << "dur=" << mvhd->duration() << "ms"; ss << "dur=" << mvhd->duration() << "ms";
// video codec. // video codec.
ss << ", vide=" << moov->nb_vide_tracks() << "(" ss << ", vide=" << moov->nb_vide_tracks() << "("
<< srs_video_codec_id2str(vcodec) << "," << pavcc.size() << "BSH" << srs_video_codec_id2str(vcodec) << "," << pavcc.size() << "BSH"
<< ")"; << ")";
// audio codec. // audio codec.
ss << ", soun=" << moov->nb_soun_tracks() << "(" ss << ", soun=" << moov->nb_soun_tracks() << "("
<< srs_audio_codec_id2str(acodec) << "," << pasc.size() << "BSH" << srs_audio_codec_id2str(acodec) << "," << pasc.size() << "BSH"
<< "," << srs_audio_channels2str(channels) << "," << srs_audio_channels2str(channels)
<< "," << srs_audio_sample_bits2str(sound_bits) << "," << srs_audio_sample_bits2str(sound_bits)
<< "," << srs_audio_sample_rate2str(sample_rate) << "," << srs_audio_sample_rate2str(sample_rate)
<< ")"; << ")";
srs_trace("MP4 moov %s", ss.str().c_str()); srs_trace("MP4 moov %s", ss.str().c_str());
@ -4205,44 +4308,15 @@ int SrsMp4Decoder::do_load_next_box(SrsMp4Box** ppbox, uint32_t required_box_typ
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
SrsMp4Box* box = NULL;
while (true) { while (true) {
// For the first time to read the box, maybe it's a basic box which is only 4bytes header. SrsMp4Box* box = NULL;
// 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) {
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 ((ret = br->read(stream, &box)) != ERROR_SUCCESS) {
if (!box && (ret = SrsMp4Box::discovery(buffer, &box)) != ERROR_SUCCESS) {
if (ret == ERROR_MP4_BOX_REQUIRE_SPACE) {
continue;
}
srs_error("MP4 load box failed. ret=%d", ret);
return ret; return ret;
} }
// When box is discoveried, check whether we can demux the whole box. SrsBuffer* buffer = new SrsBuffer(stream->bytes(), stream->length());
// For mdat, only the header is required. SrsAutoFree(SrsBuffer, buffer);
required = (box->is_mdat()? box->sz_header():box->sz());
if (!buffer->require((int)required)) {
continue;
}
// Decode the box: // Decode the box:
// 1. Any box, when no box type is required. // 1. Any box, when no box type is required.
@ -4252,20 +4326,8 @@ int SrsMp4Decoder::do_load_next_box(SrsMp4Box** ppbox, uint32_t required_box_typ
ret = box->decode(buffer); ret = box->decode(buffer);
} }
// For mdat, always skip the content. if (ret == ERROR_SUCCESS) {
if (box->is_mdat()) { ret = br->skip(box, stream);
int offset = (int)(box->sz() - stream->length());
if (offset < 0) {
stream->erase(stream->length() + offset);
} else {
stream->erase(stream->length());
}
if (offset > 0 && (ret = rsio->lseek(offset, SEEK_CUR, NULL)) != ERROR_SUCCESS) {
return ret;
}
} else {
// Remove the consumed bytes.
stream->erase((int)box->sz());
} }
if (ret != ERROR_SUCCESS) { if (ret != ERROR_SUCCESS) {

@ -1634,6 +1634,28 @@ private:
SrsMp4DecodingTime2SampleBox* stts, SrsMp4CompositionTime2SampleBox* ctts, SrsMp4SyncSampleBox* stss); SrsMp4DecodingTime2SampleBox* stts, SrsMp4CompositionTime2SampleBox* ctts, SrsMp4SyncSampleBox* stss);
}; };
/**
* The MP4 box reader, to get the RAW boxes without decode.
* @remark For mdat box, we only decode the header, then skip the data.
*/
class SrsMp4BoxReader
{
private:
ISrsReadSeeker* rsio;
// The temporary buffer to read from buffer.
char* buf;
public:
SrsMp4BoxReader();
virtual ~SrsMp4BoxReader();
public:
virtual int initialize(ISrsReadSeeker* rs);
public:
// Read a MP4 box to pbox, the stream is fill with the bytes of box to decode.
virtual int read(SrsSimpleStream* stream, SrsMp4Box** ppbox);
// Skip the box from stream, and skip in file if need.
virtual int skip(SrsMp4Box* box, SrsSimpleStream* stream);
};
/** /**
* The MP4 demuxer. * The MP4 demuxer.
*/ */
@ -1676,11 +1698,11 @@ private:
// Underlayer reader and seeker. // Underlayer reader and seeker.
// @remark The demuxer must use seeker for general MP4 to seek the moov. // @remark The demuxer must use seeker for general MP4 to seek the moov.
ISrsReadSeeker* rsio; ISrsReadSeeker* rsio;
// The MP4 box reader.
SrsMp4BoxReader* br;
// 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;
// The temporary buffer to read from buffer.
char* buf;
public: public:
SrsMp4Decoder(); SrsMp4Decoder();
virtual ~SrsMp4Decoder(); virtual ~SrsMp4Decoder();

Loading…
Cancel
Save