diff --git a/trunk/doc/ISO_IEC_14496-1-System-2010.pdf b/trunk/doc/ISO_IEC_14496-1-System-2010.pdf new file mode 100644 index 000000000..d804ac825 Binary files /dev/null and b/trunk/doc/ISO_IEC_14496-1-System-2010.pdf differ diff --git a/trunk/src/kernel/srs_kernel_mp4.cpp b/trunk/src/kernel/srs_kernel_mp4.cpp index 54bbc58b8..db7eed4f4 100644 --- a/trunk/src/kernel/srs_kernel_mp4.cpp +++ b/trunk/src/kernel/srs_kernel_mp4.cpp @@ -232,6 +232,7 @@ int SrsMp4Box::discovery(SrsBuffer* buf, SrsMp4Box** ppbox) 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; + case SRS_MP4_BOX_ESDS: box = new SrsMp4EsdsBox(); break; default: ret = ERROR_MP4_BOX_ILLEGAL_TYPE; srs_error("MP4 illegal box type=%d. ret=%d", type, ret); @@ -1721,6 +1722,298 @@ int SrsMp4AudioSampleEntry::decode_header(SrsBuffer* buf) return ret; } +SrsMp4BaseDescriptor::SrsMp4BaseDescriptor() +{ + tag = SRS_MP4_ES_TAG_ES_forbidden; +} + +SrsMp4BaseDescriptor::~SrsMp4BaseDescriptor() +{ +} + +int SrsMp4BaseDescriptor::nb_bytes() +{ + // 1 byte tag. + int size = 1; + + // 1-3 bytes size. + uint32_t length = nb_payload(); + if (length > 0x1fffff) { + size += 4; + } else if (length > 0x3fff) { + size += 3; + } else if (length > 0x7f) { + size += 2; + } else { + size += 1; + } + + // length bytes payload. + size += length; + + return size; +} + +int SrsMp4BaseDescriptor::encode(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + int size = nb_bytes(); + if (!buf->require(size)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 ES requires %d bytes space. ret=%d", size, ret); + return ret; + } + + buf->write_1bytes((uint8_t)tag); + + // As an expandable class the size of each class instance in bytes is encoded and accessible + // through the instance variable sizeOfInstance (see 8.3.3). + uint32_t length = nb_payload(); // bit(8) to bit(32) + + return ret; +} + +int SrsMp4BaseDescriptor::decode(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + int size = nb_bytes(); + if (!buf->require(size)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 ES requires %d bytes space. ret=%d", size, ret); + return ret; + } + + tag = (SRS_MP4_ES_TAG_ES)buf->read_1bytes(); + return ret; +} + +SrsMp4DecoderConfigDescriptor::SrsMp4DecoderConfigDescriptor() +{ + tag = SRS_MP4_ES_TAG_ES_DecoderConfigDescrTag; +} + +SrsMp4DecoderConfigDescriptor::~SrsMp4DecoderConfigDescriptor() +{ +} + +uint32_t SrsMp4DecoderConfigDescriptor::nb_payload() +{ + return 0; +} + +int SrsMp4DecoderConfigDescriptor::encode_payload(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + return ret; +} + +int SrsMp4DecoderConfigDescriptor::decode_payload(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + return ret; +} + +SrsMp4SLConfigDescriptor::SrsMp4SLConfigDescriptor() +{ + tag = SRS_MP4_ES_TAG_ES_SLConfigDescrTag; +} + +SrsMp4SLConfigDescriptor::~SrsMp4SLConfigDescriptor() +{ +} + +uint32_t SrsMp4SLConfigDescriptor::nb_payload() +{ + return 0; +} + +int SrsMp4SLConfigDescriptor::encode_payload(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + return ret; +} + +int SrsMp4SLConfigDescriptor::decode_payload(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + return ret; +} + +SrsMp4ES_Descriptor::SrsMp4ES_Descriptor() +{ + tag = SRS_MP4_ES_TAG_ES_DescrTag; + streamDependenceFlag = URL_Flag = OCRstreamFlag = 0; + URLlength = 0; + URLstring = NULL; +} + +SrsMp4ES_Descriptor::~SrsMp4ES_Descriptor() +{ + srs_freepa(URLstring); +} + +uint32_t SrsMp4ES_Descriptor::nb_payload() +{ + int size = 2 +1; + size += streamDependenceFlag? 2:0; + if (URL_Flag) { + size += 1 + URLlength; + } + size += OCRstreamFlag? 2:0; + size += decConfigDescr.nb_bytes() +slConfigDescr.nb_bytes(); + return size; +} + +int SrsMp4ES_Descriptor::encode_payload(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + buf->write_2bytes(ES_ID); + + uint8_t v = streamPriority & 0x1f; + v |= (streamDependenceFlag & 0x01) << 7; + v |= (URL_Flag & 0x01) << 6; + v |= (OCRstreamFlag & 0x01) << 5; + buf->write_1bytes(v); + + if (streamDependenceFlag) { + buf->write_2bytes(dependsOn_ES_ID); + } + + if (URL_Flag && URLlength) { + buf->write_1bytes(URLlength); + buf->write_bytes((char*)URLstring, URLlength); + } + + if (OCRstreamFlag) { + buf->write_2bytes(OCR_ES_Id); + } + + if ((ret = decConfigDescr.encode(buf)) != ERROR_SUCCESS) { + return ret; + } + + if ((ret = slConfigDescr.encode(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsMp4ES_Descriptor::decode_payload(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + ES_ID = buf->read_2bytes(); + + uint8_t v = buf->read_1bytes(); + streamPriority = v & 0x1f; + streamDependenceFlag = (v >> 7) & 0x01; + URL_Flag = (v >> 6) & 0x01; + OCRstreamFlag = (v >> 5) & 0x01; + + if (streamDependenceFlag) { + if (!buf->require(2)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 ES requires 2 bytes space. ret=%d", ret); + return ret; + } + dependsOn_ES_ID = buf->read_2bytes(); + } + + if (URL_Flag) { + if (!buf->require(1)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 ES requires 1 byte space. ret=%d", ret); + return ret; + } + URLlength = buf->read_1bytes(); + + if (!buf->require(URLlength)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 ES requires %d bytes space. ret=%d", URLlength, ret); + return ret; + } + URLstring = new uint8_t[URLlength]; + buf->read_bytes((char*)URLstring, URLlength); + } + + if (OCRstreamFlag) { + if (!buf->require(2)) { + ret = ERROR_MP4_BOX_REQUIRE_SPACE; + srs_error("MP4 ES requires 2 bytes space. ret=%d", ret); + return ret; + } + OCR_ES_Id = buf->read_2bytes(); + } + + if ((ret = decConfigDescr.decode(buf)) != ERROR_SUCCESS) { + return ret; + } + + if ((ret = slConfigDescr.decode(buf)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +SrsMp4EsdsBox::SrsMp4EsdsBox() +{ + type = SRS_MP4_BOX_ESDS; + es = new SrsMp4ES_Descriptor(); +} + +SrsMp4EsdsBox::~SrsMp4EsdsBox() +{ + srs_freep(es); +} + +int SrsMp4EsdsBox::nb_header() +{ + return SrsMp4FullBox::nb_header() + es->nb_bytes(); +} + +int SrsMp4EsdsBox::encode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + int left = left_space(buf); + SrsBuffer buffer(buf->data() + buf->pos(), left); + if ((ret = es->encode(&buffer)) != ERROR_SUCCESS) { + return ret; + } + + buf->skip(buffer.pos()); + + return ret; +} + +int SrsMp4EsdsBox::decode_header(SrsBuffer* buf) +{ + int ret = ERROR_SUCCESS; + + if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) { + return ret; + } + + int left = left_space(buf); + SrsBuffer buffer(buf->data() + buf->pos(), left); + if ((ret = es->decode(&buffer)) != ERROR_SUCCESS) { + return ret; + } + + buf->skip(buffer.pos()); + + return ret; +} + SrsMp4SampleDescriptionBox::SrsMp4SampleDescriptionBox() { type = SRS_MP4_BOX_STSD; diff --git a/trunk/src/kernel/srs_kernel_mp4.hpp b/trunk/src/kernel/srs_kernel_mp4.hpp index 03c3c50b9..dc2c299d3 100644 --- a/trunk/src/kernel/srs_kernel_mp4.hpp +++ b/trunk/src/kernel/srs_kernel_mp4.hpp @@ -724,6 +724,159 @@ protected: virtual int decode_header(SrsBuffer* buf); }; +// Table 1 — List of Class Tags for Descriptors +// ISO_IEC_14496-1-System-2010.pdf, page 31 +enum SRS_MP4_ES_TAG_ES { + SRS_MP4_ES_TAG_ES_forbidden = 0x00, + SRS_MP4_ES_TAG_ES_ObjectDescrTag = 0x01, + SRS_MP4_ES_TAG_ES_InitialObjectDescrTag = 0x02, + SRS_MP4_ES_TAG_ES_DescrTag = 0x03, + SRS_MP4_ES_TAG_ES_DecoderConfigDescrTag = 0x04, + SRS_MP4_ES_TAG_ES_DecSpecificInfoTag = 0x05, + SRS_MP4_ES_TAG_ES_SLConfigDescrTag = 0x06, + SRS_MP4_ES_TAG_ES_ExtSLConfigDescrTag = 0x064, +}; + +/** + * 7.2.2.2 BaseDescriptor + * ISO_IEC_14496-1-System-2010.pdf, page 32 + */ +class SrsMp4BaseDescriptor : public ISrsCodec +{ +public: + // The values of the class tags are + // defined in Table 2. As an expandable class the size of each class instance in bytes is encoded and accessible + // through the instance variable sizeOfInstance (see 8.3.3). + SRS_MP4_ES_TAG_ES tag; // bit(8) +public: + SrsMp4BaseDescriptor(); + virtual ~SrsMp4BaseDescriptor(); +// Interface ISrsCodec +public: + virtual int nb_bytes(); + virtual int encode(SrsBuffer* buf); + virtual int decode(SrsBuffer* buf); +protected: + virtual uint32_t nb_payload() = 0; + virtual int encode_payload(SrsBuffer* buf) = 0; + virtual int decode_payload(SrsBuffer* buf) = 0; +}; + +/** + * 7.2.6.6 DecoderConfigDescriptor + * ISO_IEC_14496-1-System-2010.pdf, page 48 + */ +class SrsMp4DecoderConfigDescriptor : public SrsMp4BaseDescriptor +{ +public: + uint8_t objectTypeIndication; + uint8_t streamType; // bit(6) + uint8_t upStream; // bit(1) + uint8_t reserved; // bit(1) + uint32_t bufferSizeDB; // bit(24) + uint32_t maxBitrate; + uint32_t avgBitrate; +public: + SrsMp4DecoderConfigDescriptor(); + virtual ~SrsMp4DecoderConfigDescriptor(); +protected: + virtual uint32_t nb_payload(); + virtual int encode_payload(SrsBuffer* buf); + virtual int decode_payload(SrsBuffer* buf); +}; + +/** + * 7.3.2.3 SL Packet Header Configuration + * ISO_IEC_14496-1-System-2010.pdf, page 92 + */ +class SrsMp4SLConfigDescriptor : public SrsMp4BaseDescriptor +{ +public: + uint8_t predefined; + // if (predefined==0) + uint8_t useAccessUnitStartFlag; // bit(1) + uint8_t useAccessUnitEndFlag; // bit(1) + uint8_t useRandomAccessPointFlag; // bit(1) + uint8_t hasRandomAccessUnitsOnlyFlag; // bit(1) + uint8_t usePaddingFlag; // bit(1) + uint8_t useTimeStampsFlag; // bit(1) + uint8_t useIdleFlag; // bit(1) + uint8_t durationFlag; // bit(1) + uint32_t timeStampResolution; + uint32_t OCRResolution; + uint8_t timeStampLength; // must be ≤ 64 + uint8_t OCRLength; // must be ≤ 64 + uint8_t AU_Length; // must be ≤ 32 + uint8_t instantBitrateLength; + uint8_t degradationPriorityLength; // bit(4) + uint8_t AU_seqNumLength; // bit(5) // must be ≤ 16 + uint8_t packetSeqNumLength; // bit(5) // must be ≤ 16 + uint8_t reserved; // bit(2) // 0b11 + // if (durationFlag) + uint32_t timeScale; + uint16_t accessUnitDuration; + uint16_t compositionUnitDuration; + // if (!useTimeStampsFlag) + uint64_t startDecodingTimeStamp; // bit(timeStampLength) + uint64_t startCompositionTimeStamp; // bit(timeStampLength) +public: + SrsMp4SLConfigDescriptor(); + virtual ~SrsMp4SLConfigDescriptor(); +protected: + virtual uint32_t nb_payload(); + virtual int encode_payload(SrsBuffer* buf); + virtual int decode_payload(SrsBuffer* buf); +}; + +/** + * 7.2.6.5 ES_Descriptor + * ISO_IEC_14496-1-System-2010.pdf, page 47 + */ +class SrsMp4ES_Descriptor : public SrsMp4BaseDescriptor +{ +public: + uint16_t ES_ID; + uint8_t streamDependenceFlag; // bit(1) + uint8_t URL_Flag; // bit(1) + uint8_t OCRstreamFlag; // bit(1) + uint8_t streamPriority; // bit(5) + // if (streamDependenceFlag) + uint16_t dependsOn_ES_ID; + // if (URL_Flag) + uint8_t URLlength; + uint8_t* URLstring; + // if (OCRstreamFlag) + uint16_t OCR_ES_Id; + SrsMp4DecoderConfigDescriptor decConfigDescr; + SrsMp4SLConfigDescriptor slConfigDescr; +public: + SrsMp4ES_Descriptor(); + virtual ~SrsMp4ES_Descriptor(); +protected: + virtual uint32_t nb_payload(); + virtual int encode_payload(SrsBuffer* buf); + virtual int decode_payload(SrsBuffer* buf); +}; + +/** + * 5.6 Sample Description Boxes + * Elementary Stream Descriptors (esds) + * ISO_IEC_14496-14-MP4-2003.pdf, page 15 + * @see http://www.mp4ra.org/codecs.html + */ +class SrsMp4EsdsBox : public SrsMp4FullBox +{ +public: + SrsMp4ES_Descriptor* es; +public: + SrsMp4EsdsBox(); + virtual ~SrsMp4EsdsBox(); +protected: + virtual int nb_header(); + virtual int encode_header(SrsBuffer* buf); + virtual int decode_header(SrsBuffer* buf); +}; + /** * 8.5.2 Sample Description Box (stsd), for Audio/Video. * ISO_IEC_14496-12-base-format-2012.pdf, page 40