From 0e9d876c18d95c204f176bd4569509372b670222 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Fri, 23 Jun 2017 01:51:42 +0200 Subject: [PATCH] Bug 1374774: P7. Add SPSNAL and SPSNALIterator classes. r=gerald We will use them to simplify the parsing of the extradata. MozReview-Commit-ID: 5M5uGXAkkFb --HG-- extra : rebase_source : e83c8995ebbc60359029f15334e91baaeb098bbd --- media/libstagefright/binding/H264.cpp | 147 ++++++++++++++++-- .../binding/include/mp4_demuxer/H264.h | 15 +- 2 files changed, 145 insertions(+), 17 deletions(-) diff --git a/media/libstagefright/binding/H264.cpp b/media/libstagefright/binding/H264.cpp index 5d36b81a1b3b..0a71d88c25b2 100644 --- a/media/libstagefright/binding/H264.cpp +++ b/media/libstagefright/binding/H264.cpp @@ -188,17 +188,149 @@ SPSData::operator==(const SPSData& aOther) const !memcmp(this, &aOther, sizeof(SPSData)); } +bool +SPSData::operator!=(const SPSData& aOther) const +{ + return !(operator==(aOther)); +} + +// SPSNAL and SPSNALIterator do not own their data. +class SPSNAL +{ +public: + SPSNAL(const uint8_t* aPtr, size_t aLength) + { + MOZ_ASSERT(aPtr && aLength); + + if ((*ptr & 0x1f) != H264_NAL_SPS) { + return; + } + mDecodedNAL = H264::DecodeNALUnit(aPtr, aLength); + if (mDecodedNAL) { + mLength = GetBitLength(mDecodedNAL); + } + } + + SPSNAL() { } + + bool IsValid() const { return mDecodedNAL; } + + bool operator==(const SPSNAL& aOther) const + { + if (!mDecodedNAL || !aOther.mDecodedNAL) { + return false; + } + if (mLength != aOther.mLength) { + return false; + } + + MOZ_ASSERT(mLength / 8 <= mDecodedNAL->Length()); + + if (memcmp(mDecodedNAL->Elements(), + aOther.mDecodedNAL->Elements(), + mLength / 8)) { + return false; + } + + uint32_t remaining = mLength - (mLength & ~7); + + BitReader b1(mDecodedNAL->Elements() + mLength / 8, remaining); + BitReader b2(aOther.mDecodedNAL->Elements() + mLength / 8, remaining); + for (uint32_t i = 0; i < remaining; i++) { + if (b1.ReadBit() != b2.ReadBit()) { + return false; + } + } + return true; + } + + bool operator!=(const SPSNAL& aOther) const + { + return !(operator==(aOther)); + } + + bool GetSPSData(SPSData& aDest) + { + return H264::DecodeSPS(mDecodedNAL, aDest); + } + +private: + RefPtr mDecodedNAL; + uint32_t mLength = 0; +}; + +class SPSNALIterator +{ +public: + explicit SPSNALIterator(const mozilla::MediaByteBuffer* aExtraData) + : mExtraDataPtr(aExtraData->Elements()) + , mReader(aExtraData) + { + if (!mReader.Read(5)) { + return; + } + + mNumSPS = mReader.ReadU8() & 0x1f; + if (mNumSPS == 0) { + return; + } + mValid = true; + } + + SPSNALIterator& operator++() + { + if (mEOS || !mValid) { + return *this; + } + if (--mNumSPS == 0) { + mEOS = true; + } + uint16_t length = mReader.ReadU16(); + if (length == 0 || !mReader.Read(length)) { + mEOS = true; + } + return *this; + } + + explicit operator bool() const + { + return mValid && !mEOS; + } + + SPSNAL operator*() const + { + MOZ_ASSERT(bool(*this)); + ByteReader reader(mExtraDataPtr + mReader.Offset(), mReader.Remaining()); + uint16_t length = reader.ReadU16(); + if (length == 0) { + return SPSNAL(); + } + const uint8_t* ptr = reader.Read(length); + if (!ptr) { + return SPSNAL(); + } + return SPSNAL(ptr, length); + } + +private: + const uint8_t* mExtraDataPtr; + ByteReader mReader; + bool mValid = false; + bool mEOS = false; + uint8_t mNumSPS = 0; +}; + /* static */ already_AddRefed -H264::DecodeNALUnit(const mozilla::MediaByteBuffer* aNAL) +H264::DecodeNALUnit(const uint8_t* aNAL, size_t aLength) { MOZ_ASSERT(aNAL); - if (aNAL->Length() < 4) { + if (aLength < 4) { return nullptr; } RefPtr rbsp = new mozilla::MediaByteBuffer; - ByteReader reader(aNAL); + ByteReader reader(aNAL, aLength); uint8_t nal_unit_type = reader.ReadU8() & 0x1f; uint32_t nalUnitHeaderBytes = 1; if (nal_unit_type == H264_NAL_PREFIX || @@ -628,10 +760,7 @@ H264::DecodeSPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData, return false; } - RefPtr rawNAL = new mozilla::MediaByteBuffer; - rawNAL->AppendElements(ptr, length); - - RefPtr sps = DecodeNALUnit(rawNAL); + RefPtr sps = DecodeNALUnit(ptr, length); if (!sps) { return false; @@ -770,9 +899,7 @@ H264::ExtractExtraData(const mozilla::MediaRawData* aSample) uint8_t nalType = *p & 0x1f; if (nalType == H264_NAL_SPS) { - RefPtr rawNAL = new mozilla::MediaByteBuffer; - rawNAL->AppendElements(p, nalLen); - RefPtr sps = DecodeNALUnit(rawNAL); + RefPtr sps = DecodeNALUnit(p, nalLen); SPSData data; if (!DecodeSPS(sps, data)) { // Invalid SPS, ignore. diff --git a/media/libstagefright/binding/include/mp4_demuxer/H264.h b/media/libstagefright/binding/include/mp4_demuxer/H264.h index 2ce303dfe773..792d5d314b1a 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/H264.h +++ b/media/libstagefright/binding/include/mp4_demuxer/H264.h @@ -39,6 +39,7 @@ class BitReader; struct SPSData { bool operator==(const SPSData& aOther) const; + bool operator!=(const SPSData& aOther) const; bool valid; @@ -410,13 +411,6 @@ struct SPSData class H264 { public: - /* Extract RAW BYTE SEQUENCE PAYLOAD from NAL content. - Returns nullptr if invalid content. - This is compliant to ITU H.264 7.3.1 Syntax in tabular form NAL unit syntax - */ - static already_AddRefed DecodeNALUnit( - const mozilla::MediaByteBuffer* aNAL); - /* Check if out of band extradata contains a SPS NAL */ static bool HasSPS(const mozilla::MediaByteBuffer* aExtraData); // Extract SPS and PPS NALs from aSample by looking into each NALs. @@ -451,6 +445,13 @@ public: static FrameType GetFrameType(const mozilla::MediaRawData* aSample); private: + friend class SPSNAL; + /* Extract RAW BYTE SEQUENCE PAYLOAD from NAL content. + Returns nullptr if invalid content. + This is compliant to ITU H.264 7.3.1 Syntax in tabular form NAL unit syntax + */ + static already_AddRefed DecodeNALUnit( + const uint8_t* aNAL, size_t aLength); /* Decode SPS NAL RBSP and fill SPSData structure */ static bool DecodeSPS(const mozilla::MediaByteBuffer* aSPS, SPSData& aDest); static bool vui_parameters(BitReader& aBr, SPSData& aDest);