diff --git a/trunk/src/kernel/srs_kernel_codec.hpp b/trunk/src/kernel/srs_kernel_codec.hpp index 739851a50f..3c715ca09d 100644 --- a/trunk/src/kernel/srs_kernel_codec.hpp +++ b/trunk/src/kernel/srs_kernel_codec.hpp @@ -97,6 +97,7 @@ enum SrsCodecVideo { // set to the zero to reserved, for array map. SrsCodecVideoReserved = 0, + SrsCodecVideoForbidden = 0, SrsCodecVideoReserved1 = 1, SrsCodecVideoReserved2 = 9, @@ -135,6 +136,7 @@ enum SrsCodecAudio { // set to the max value to reserved, for array map. SrsCodecAudioReserved1 = 16, + SrsCodecAudioForbidden = 16, // for user to disable audio, for example, use pure video hls. SrsCodecAudioDisabled = 17, diff --git a/trunk/src/kernel/srs_kernel_mp4.cpp b/trunk/src/kernel/srs_kernel_mp4.cpp index 343eef5185..ad09dcf169 100644 --- a/trunk/src/kernel/srs_kernel_mp4.cpp +++ b/trunk/src/kernel/srs_kernel_mp4.cpp @@ -31,6 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include using namespace std; #define SRS_MP4_EOF_SIZE 0 @@ -672,6 +673,40 @@ SrsMp4TrackBox* SrsMp4MovieBox::audio() return NULL; } +int SrsMp4MovieBox::nb_vide_tracks() +{ + int nb_tracks = 0; + + for (int i = 0; i < boxes.size(); i++) { + SrsMp4Box* box = boxes.at(i); + if (box->type == SrsMp4BoxTypeTRAK) { + SrsMp4TrackBox* trak = dynamic_cast(box); + if ((trak->track_type() & SrsMp4TrackTypeVideo) == SrsMp4TrackTypeVideo) { + nb_tracks++; + } + } + } + + return nb_tracks; +} + +int SrsMp4MovieBox::nb_soun_tracks() +{ + int nb_tracks = 0; + + for (int i = 0; i < boxes.size(); i++) { + SrsMp4Box* box = boxes.at(i); + if (box->type == SrsMp4BoxTypeTRAK) { + SrsMp4TrackBox* trak = dynamic_cast(box); + if ((trak->track_type() & SrsMp4TrackTypeAudio) == SrsMp4TrackTypeAudio) { + nb_tracks++; + } + } + } + + return nb_tracks; +} + int SrsMp4MovieBox::nb_header() { return SrsMp4Box::nb_header(); @@ -823,14 +858,102 @@ SrsMp4TrackHeaderBox::~SrsMp4TrackHeaderBox() SrsMp4TrackType SrsMp4TrackBox::track_type() { - SrsMp4Box* box = get(SrsMp4BoxTypeMDIA); + // TODO: Maybe should discovery all mdia boxes. + SrsMp4MediaBox* box = mdia(); if (!box) { return SrsMp4TrackTypeForbidden; } + return box->track_type(); +} + +SrsMp4TrackHeaderBox* SrsMp4TrackBox::tkhd() +{ + SrsMp4Box* box = get(SrsMp4BoxTypeTKHD); + return dynamic_cast(box); +} + +SrsCodecVideo SrsMp4TrackBox::vide_codec() +{ + SrsMp4SampleDescriptionBox* box = stsd(); + if (!box) { + return SrsCodecVideoForbidden; + } - // TODO: Maybe should discovery all mdia boxes. - SrsMp4MediaBox* mdia = dynamic_cast(box); - return mdia->track_type(); + if (box->entry_count() == 0) { + return SrsCodecVideoForbidden; + } + + SrsMp4SampleEntry* entry = box->entrie_at(0); + switch(entry->type) { + case SrsMp4BoxTypeAVC1: return SrsCodecVideoAVC; + default: return SrsCodecVideoForbidden; + } +} + +SrsCodecAudio SrsMp4TrackBox::soun_codec() +{ + SrsMp4SampleDescriptionBox* box = stsd(); + if (!box) { + return SrsCodecAudioForbidden; + } + + if (box->entry_count() == 0) { + return SrsCodecAudioForbidden; + } + + SrsMp4SampleEntry* entry = box->entrie_at(0); + switch(entry->type) { + case SrsMp4BoxTypeMP4A: return SrsCodecAudioAAC; + default: return SrsCodecAudioForbidden; + } +} + +SrsMp4AvccBox* SrsMp4TrackBox::avcc() +{ + SrsMp4VisualSampleEntry* box = avc1(); + return box? box->avcC():NULL; +} + +SrsMp4DecoderSpecificInfo* SrsMp4TrackBox::asc() +{ + SrsMp4AudioSampleEntry* box = mp4a(); + return box? box->asc():NULL; +} + +SrsMp4MediaBox* SrsMp4TrackBox::mdia() +{ + SrsMp4Box* box = get(SrsMp4BoxTypeMDIA); + return dynamic_cast(box); +} + +SrsMp4MediaInformationBox* SrsMp4TrackBox::minf() +{ + SrsMp4MediaBox* box = mdia(); + return box? box->minf():NULL; +} + +SrsMp4SampleTableBox* SrsMp4TrackBox::stbl() +{ + SrsMp4MediaInformationBox* box = minf(); + return box? box->stbl():NULL; +} + +SrsMp4SampleDescriptionBox* SrsMp4TrackBox::stsd() +{ + SrsMp4SampleTableBox* box = stbl(); + return box? box->stsd():NULL; +} + +SrsMp4VisualSampleEntry* SrsMp4TrackBox::avc1() +{ + SrsMp4SampleDescriptionBox* box = stsd(); + return box? box->avc1():NULL; +} + +SrsMp4AudioSampleEntry* SrsMp4TrackBox::mp4a() +{ + SrsMp4SampleDescriptionBox* box = stsd(); + return box? box->mp4a():NULL; } int SrsMp4TrackHeaderBox::nb_header() @@ -1043,6 +1166,12 @@ SrsMp4TrackType SrsMp4MediaBox::track_type() } } +SrsMp4MediaInformationBox* SrsMp4MediaBox::minf() +{ + SrsMp4Box* box = get(SrsMp4BoxTypeMINF); + return dynamic_cast(box); +} + SrsMp4MediaHeaderBox::SrsMp4MediaHeaderBox() { type = SrsMp4BoxTypeMDHD; @@ -1225,6 +1354,12 @@ SrsMp4MediaInformationBox::~SrsMp4MediaInformationBox() { } +SrsMp4SampleTableBox* SrsMp4MediaInformationBox::stbl() +{ + SrsMp4Box* box = get(SrsMp4BoxTypeSTBL); + return dynamic_cast(box); +} + SrsMp4VideoMeidaHeaderBox::SrsMp4VideoMeidaHeaderBox() { type = SrsMp4BoxTypeVMHD; @@ -1554,6 +1689,12 @@ SrsMp4SampleTableBox::~SrsMp4SampleTableBox() { } +SrsMp4SampleDescriptionBox* SrsMp4SampleTableBox::stsd() +{ + SrsMp4Box* box = get(SrsMp4BoxTypeSTSD); + return dynamic_cast(box); +} + SrsMp4SampleEntry::SrsMp4SampleEntry() { memset(reserved, 0, 6); @@ -1616,6 +1757,12 @@ SrsMp4VisualSampleEntry::~SrsMp4VisualSampleEntry() { } +SrsMp4AvccBox* SrsMp4VisualSampleEntry::avcC() +{ + SrsMp4Box* box = get(SrsMp4BoxTypeAVCC); + return dynamic_cast(box); +} + int SrsMp4VisualSampleEntry::nb_header() { return SrsMp4SampleEntry::nb_header()+2+2+12+2+2+4+4+4+2+32+2+2; @@ -1733,6 +1880,18 @@ SrsMp4AudioSampleEntry::~SrsMp4AudioSampleEntry() { } +SrsMp4EsdsBox* SrsMp4AudioSampleEntry::esds() +{ + SrsMp4Box* box = get(SrsMp4BoxTypeESDS); + return dynamic_cast(box); +} + +SrsMp4DecoderSpecificInfo* SrsMp4AudioSampleEntry::asc() +{ + SrsMp4EsdsBox* box = esds(); + return box? box->asc():NULL; +} + int SrsMp4AudioSampleEntry::nb_header() { return SrsMp4SampleEntry::nb_header()+8+2+2+2+2+4; @@ -2165,6 +2324,11 @@ SrsMp4EsdsBox::~SrsMp4EsdsBox() srs_freep(es); } +SrsMp4DecoderSpecificInfo* SrsMp4EsdsBox::asc() +{ + return es->decConfigDescr.decSpecificInfo; +} + int SrsMp4EsdsBox::nb_header() { return SrsMp4FullBox::nb_header() + es->nb_bytes(); @@ -2223,6 +2387,30 @@ SrsMp4SampleDescriptionBox::~SrsMp4SampleDescriptionBox() entries.clear(); } +SrsMp4VisualSampleEntry* SrsMp4SampleDescriptionBox::avc1() +{ + vector::iterator it; + for (it = entries.begin(); it != entries.end(); ++it) { + SrsMp4SampleEntry* entry = *it; + if (entry->type == SrsMp4BoxTypeAVC1) { + return dynamic_cast(entry); + } + } + return NULL; +} + +SrsMp4AudioSampleEntry* SrsMp4SampleDescriptionBox::mp4a() +{ + vector::iterator it; + for (it = entries.begin(); it != entries.end(); ++it) { + SrsMp4SampleEntry* entry = *it; + if (entry->type == SrsMp4BoxTypeMP4A) { + return dynamic_cast(entry); + } + } + return NULL; +} + uint32_t SrsMp4SampleDescriptionBox::entry_count() { return (uint32_t)entries.size(); @@ -2839,7 +3027,7 @@ int SrsMp4Decoder::initialize(ISrsReader* r) return ret; } - // Parse the MOOV. + // Parse the Movie Header Box(moov). SrsMp4MovieBox* moov = dynamic_cast(box); return parse_moov(moov); } @@ -2863,7 +3051,31 @@ int SrsMp4Decoder::parse_moov(SrsMp4MovieBox* moov) return ret; } - srs_trace("MP4 moov dur=%dms, vide=%d, soun=%d", mvhd->duration(), vide != NULL, soun != NULL); + SrsMp4AvccBox* avcc = vide? vide->avcc():NULL; + SrsMp4DecoderSpecificInfo* asc = soun? soun->asc():NULL; + if (vide && !avcc) { + ret = ERROR_MP4_ILLEGAL_MOOV; + srs_error("MP4 missing video sequence header. ret=%d", ret); + return ret; + } + if (soun && !asc) { + ret = ERROR_MP4_ILLEGAL_MOOV; + srs_error("MP4 missing audio sequence header. ret=%d", ret); + return ret; + } + + stringstream ss; + ss << "dur=" << mvhd->duration() << "ms"; + // video codec. + ss << ", vide=" << moov->nb_vide_tracks() << "(" + << srs_codec_video2str(vide?vide->vide_codec():SrsCodecVideoForbidden) + << "," << (avcc? avcc->nb_config:0) << "BSH" << ")"; + // audio codec. + ss << ", soun=" << moov->nb_soun_tracks() << "(" + << srs_codec_audio2str(soun?soun->soun_codec():SrsCodecAudioForbidden) + << "," << (asc? asc->nb_asc:0) << "BSH" << ")"; + + srs_trace("MP4 moov %s", ss.str().c_str()); return ret; } diff --git a/trunk/src/kernel/srs_kernel_mp4.hpp b/trunk/src/kernel/srs_kernel_mp4.hpp index ed171d07eb..b05bf44066 100644 --- a/trunk/src/kernel/srs_kernel_mp4.hpp +++ b/trunk/src/kernel/srs_kernel_mp4.hpp @@ -30,12 +30,26 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include #include #include class ISrsReader; +class SrsMp4TrackBox; +class SrsMp4MediaBox; class SrsSimpleStream; +class SrsMp4MovieHeaderBox; +class SrsMp4TrackHeaderBox; +class SrsMp4SampleTableBox; +class SrsMp4MediaInformationBox; +class SrsMp4SampleDescriptionBox; +class SrsMp4AvccBox; +class SrsMp4DecoderSpecificInfo; +class SrsMp4VisualSampleEntry; +class SrsMp4AvccBox; +class SrsMp4AudioSampleEntry; +class SrsMp4EsdsBox; /** * 4.2 Object Structure @@ -264,9 +278,6 @@ class SrsMp4FreeSpaceBox : public SrsMp4Box virtual int decode_header(SrsBuffer* buf); }; -class SrsMp4TrackBox; -class SrsMp4MovieHeaderBox; - /** * 8.2.1 Movie Box (moov) * ISO_IEC_14496-12-base-format-2012.pdf, page 30 @@ -285,6 +296,10 @@ class SrsMp4MovieBox : public SrsMp4Box virtual SrsMp4TrackBox* video(); // Get the first audio track. virtual SrsMp4TrackBox* audio(); + // Get the number of video tracks. + virtual int nb_vide_tracks(); + // Get the number of audio tracks. + virtual int nb_soun_tracks(); protected: virtual int nb_header(); virtual int encode_header(SrsBuffer* buf); @@ -366,6 +381,29 @@ class SrsMp4TrackBox : public SrsMp4Box // for example, it maybe Audio|Video when contains both. // Generally, only single type, no combination. virtual SrsMp4TrackType track_type(); + // Get the track header box. + virtual SrsMp4TrackHeaderBox* tkhd(); + // For vide track, get the video codec. + virtual SrsCodecVideo vide_codec(); + // For soun track, get the audio codec. + virtual SrsCodecAudio soun_codec(); + // For H.264/AVC codec, get the sps/pps. + virtual SrsMp4AvccBox* avcc(); + // For AAC codec, get the asc. + virtual SrsMp4DecoderSpecificInfo* asc(); +private: + // Get the media box. + virtual SrsMp4MediaBox* mdia(); + // Get the media info box. + virtual SrsMp4MediaInformationBox* minf(); + // Get the sample table box. + virtual SrsMp4SampleTableBox* stbl(); + // Get the sample description box + virtual SrsMp4SampleDescriptionBox* stsd(); + // For H.264/AVC, get the avc1 box. + virtual SrsMp4VisualSampleEntry* avc1(); + // For AAC, get the mp4a box. + virtual SrsMp4AudioSampleEntry* mp4a(); }; /** @@ -502,6 +540,8 @@ class SrsMp4MediaBox : public SrsMp4Box // for example, it maybe Audio|Video when contains both. // Generally, only single type, no combination. virtual SrsMp4TrackType track_type(); + // Get the media info box. + virtual SrsMp4MediaInformationBox* minf(); }; /** @@ -592,6 +632,9 @@ class SrsMp4MediaInformationBox : public SrsMp4Box public: SrsMp4MediaInformationBox(); virtual ~SrsMp4MediaInformationBox(); +public: + // Get the sample table box. + virtual SrsMp4SampleTableBox* stbl(); }; /** @@ -734,6 +777,9 @@ class SrsMp4SampleTableBox : public SrsMp4Box public: SrsMp4SampleTableBox(); virtual ~SrsMp4SampleTableBox(); +public: + // Get the sample description box + virtual SrsMp4SampleDescriptionBox* stsd(); }; /** @@ -788,6 +834,9 @@ class SrsMp4VisualSampleEntry : public SrsMp4SampleEntry public: SrsMp4VisualSampleEntry(); virtual ~SrsMp4VisualSampleEntry(); +public: + // For avc1, get the avcc box. + virtual SrsMp4AvccBox* avcC(); protected: virtual int nb_header(); virtual int encode_header(SrsBuffer* buf); @@ -828,6 +877,11 @@ class SrsMp4AudioSampleEntry : public SrsMp4SampleEntry public: SrsMp4AudioSampleEntry(); virtual ~SrsMp4AudioSampleEntry(); +public: + // For AAC codec, get the esds. + virtual SrsMp4EsdsBox* esds(); + // For AAC codec, get the asc. + virtual SrsMp4DecoderSpecificInfo* asc(); protected: virtual int nb_header(); virtual int encode_header(SrsBuffer* buf); @@ -1003,6 +1057,9 @@ class SrsMp4EsdsBox : public SrsMp4FullBox public: SrsMp4EsdsBox(); virtual ~SrsMp4EsdsBox(); +public: + // For AAC codec, get the asc. + virtual SrsMp4DecoderSpecificInfo* asc(); protected: virtual int nb_header(); virtual int encode_header(SrsBuffer* buf); @@ -1022,6 +1079,11 @@ class SrsMp4SampleDescriptionBox : public SrsMp4FullBox public: SrsMp4SampleDescriptionBox(); virtual ~SrsMp4SampleDescriptionBox(); +public: + // For H.264/AVC, get the avc1 box. + virtual SrsMp4VisualSampleEntry* avc1(); + // For AAC, get the mp4a box. + virtual SrsMp4AudioSampleEntry* mp4a(); public: virtual uint32_t entry_count(); virtual SrsMp4SampleEntry* entrie_at(int index);