From 8b746b6c127dcf9c83ef860f28ebd2f2e367f5df Mon Sep 17 00:00:00 2001 From: Jeremy Andrews Date: Mon, 23 Oct 2023 19:58:33 -0500 Subject: Issue #2357 - WebM demuxer can't tell when a video wants to be transparent. Required to have an alpha channel (which in the strange world of graphics seems to refer to transparency, and not experimental code) in WebM videos. Straight port of Firefox 53 implementation, adapted slightly for a couple of patches previously taken without this. Ref: BZ 1320829 --- dom/media/MediaData.cpp | 12 ++++++++++++ dom/media/MediaData.h | 12 ++++++++++-- dom/media/MediaInfo.h | 14 ++++++++++++++ dom/media/webm/WebMDemuxer.cpp | 33 +++++++++++++++++++++++++++++---- layout/media/symbols.def.in | 1 + 5 files changed, 66 insertions(+), 6 deletions(-) diff --git a/dom/media/MediaData.cpp b/dom/media/MediaData.cpp index 4852ea486b..c113b62fe6 100644 --- a/dom/media/MediaData.cpp +++ b/dom/media/MediaData.cpp @@ -340,6 +340,15 @@ MediaRawData::MediaRawData(const uint8_t* aData, size_t aSize) { } +MediaRawData::MediaRawData(const uint8_t* aData, size_t aSize, + const uint8_t* aAlphaData, size_t aAlphaSize) + : MediaData(RAW_DATA, 0) + , mCrypto(mCryptoInternal) + , mBuffer(aData, aSize) + , mAlphaBuffer(aAlphaData, aAlphaSize) +{ +} + already_AddRefed MediaRawData::Clone() const { @@ -356,6 +365,9 @@ MediaRawData::Clone() const if (!s->mBuffer.Append(mBuffer.Data(), mBuffer.Length())) { return nullptr; } + if (!s->mAlphaBuffer.Append(mAlphaBuffer.Data(), mAlphaBuffer.Length())) { + return nullptr; + } return s.forget(); } diff --git a/dom/media/MediaData.h b/dom/media/MediaData.h index dc93c84872..7e93541baa 100644 --- a/dom/media/MediaData.h +++ b/dom/media/MediaData.h @@ -622,15 +622,22 @@ private: class MediaRawData : public MediaData { public: MediaRawData(); - MediaRawData(const uint8_t* aData, size_t mSize); + MediaRawData(const uint8_t* aData, size_t aSize); + MediaRawData(const uint8_t* aData, size_t aSize, + const uint8_t* aAlphaData, size_t aAlphaSize); // Pointer to data or null if not-yet allocated const uint8_t* Data() const { return mBuffer.Data(); } + // Pointer to alpha data or null if not-yet allocated + const uint8_t* AlphaData() const { return mAlphaBuffer.Data(); } // Size of buffer. size_t Size() const { return mBuffer.Length(); } + size_t AlphaSize() const { return mAlphaBuffer.Length(); } size_t ComputedSizeOfIncludingThis() const { - return sizeof(*this) + mBuffer.ComputedSizeOfExcludingThis(); + return sizeof(*this) + + mBuffer.ComputedSizeOfExcludingThis() + + mAlphaBuffer.ComputedSizeOfExcludingThis(); } // Access the buffer as a Span. operator Span() { return MakeSpan(Data(), Size()); } @@ -661,6 +668,7 @@ protected: private: friend class MediaRawDataWriter; AlignedByteBuffer mBuffer; + AlignedByteBuffer mAlphaBuffer; CryptoSample mCryptoInternal; MediaRawData(const MediaRawData&); // Not implemented }; diff --git a/dom/media/MediaInfo.h b/dom/media/MediaInfo.h index 2ddaf5a43f..62477cabd8 100644 --- a/dom/media/MediaInfo.h +++ b/dom/media/MediaInfo.h @@ -215,6 +215,7 @@ public: , mRotation(aOther.mRotation) , mBitDepth(aOther.mBitDepth) , mImageRect(aOther.mImageRect) + , mAlphaPresent(aOther.mAlphaPresent) { } @@ -238,6 +239,16 @@ public: return MakeUnique(*this); } + void SetAlpha(bool aAlphaPresent) + { + mAlphaPresent = aAlphaPresent; + } + + bool HasAlpha() const + { + return mAlphaPresent; + } + nsIntRect ImageRect() const { if (mImageRect.width < 0 || mImageRect.height < 0) { @@ -312,6 +323,9 @@ private: // mImage may be cropped; currently only used with the WebM container. // A negative width or height indicate that no cropping is to occur. nsIntRect mImageRect; + + // Indicates whether or not frames may contain alpha information. + bool mAlphaPresent = false; }; class AudioInfo : public TrackInfo { diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index 090229365e..1009fedc69 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -378,6 +378,7 @@ WebMDemuxer::ReadMetadata() mInfo.mVideo.mDisplay = displaySize; mInfo.mVideo.mImage = frameSize; mInfo.mVideo.SetImageRect(pictureRect); + mInfo.mVideo.SetAlpha(params.alpha_mode); switch (params.stereo_mode) { case NESTEGG_VIDEO_MONO: @@ -656,6 +657,21 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl WEBM_DEBUG("nestegg_packet_data failed r=%d", r); return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } + unsigned char* alphaData; + size_t alphaLength = 0; + // Check packets for alpha information if file has declared alpha frames + // may be present. + if (mInfo.mVideo.HasAlpha()) { + r = nestegg_packet_additional_data(holder->Packet(), + 1, + &alphaData, + &alphaLength); + if (r == -1) { + WEBM_DEBUG( + "nestegg_packet_additional_data failed to retrieve alpha data r=%d", + r); + } + } bool isKeyframe = false; if (aType == TrackInfo::kAudioTrack) { isKeyframe = true; @@ -713,10 +729,19 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl WEBM_DEBUG("push sample tstamp: %ld next_tstamp: %ld length: %ld kf: %d", tstamp, next_tstamp, length, isKeyframe); - RefPtr sample = new MediaRawData(data, length); - if (length && !sample->Data()) { - // OOM. - return NS_ERROR_OUT_OF_MEMORY; + RefPtr sample; + if (mInfo.mVideo.HasAlpha() && alphaLength != 0) { + sample = new MediaRawData(data, length, alphaData, alphaLength); + if (length && !sample->Data() || (alphaLength && !sample->AlphaData())) { + // OOM. + return NS_ERROR_OUT_OF_MEMORY; + } + } else { + sample = new MediaRawData(data, length); + if (length && !sample->Data()) { + // OOM. + return NS_ERROR_OUT_OF_MEMORY; + } } sample->mTimecode = tstamp; sample->mTime = tstamp; diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index 2ad49cbfcf..140d8e7480 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -9,6 +9,7 @@ nestegg_duration nestegg_free_packet nestegg_init nestegg_offset_seek +nestegg_packet_additional_data nestegg_packet_count nestegg_packet_discard_padding nestegg_packet_data -- cgit v1.2.3