mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 23:38:38 +09:00
Issue #2357 - VPXDecoder does not decode alpha frames.
Another requirement to have transparency in videos. Straight port of Firefox 53 implementation, save for some oddities relating to needing to put uint8_t instead of uint8 in yuv_convert to get this to compile. Ref: BZ 1321076, 1329104
This commit is contained in:
parent
71cc0ef940
commit
c0ba3a8d2e
9 changed files with 315 additions and 65 deletions
|
|
@ -7,6 +7,8 @@
|
|||
#include "MediaInfo.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "mozilla/layers/SharedRGBImage.h"
|
||||
#include "YCbCrUtils.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
|
@ -89,6 +91,45 @@ ValidatePlane(const VideoData::YCbCrBuffer::Plane& aPlane)
|
|||
aPlane.mStride > 0 && aPlane.mWidth <= aPlane.mStride;
|
||||
}
|
||||
|
||||
static bool ValidateBufferAndPicture(const VideoData::YCbCrBuffer& aBuffer,
|
||||
const IntRect& aPicture)
|
||||
{
|
||||
// The following situation should never happen unless there is a bug
|
||||
// in the decoder
|
||||
if (aBuffer.mPlanes[1].mWidth != aBuffer.mPlanes[2].mWidth ||
|
||||
aBuffer.mPlanes[1].mHeight != aBuffer.mPlanes[2].mHeight) {
|
||||
NS_ERROR("C planes with different sizes");
|
||||
return false;
|
||||
}
|
||||
|
||||
// The following situations could be triggered by invalid input
|
||||
if (aPicture.width <= 0 || aPicture.height <= 0) {
|
||||
// In debug mode, makes the error more noticeable
|
||||
MOZ_ASSERT(false, "Empty picture rect");
|
||||
return false;
|
||||
}
|
||||
if (!ValidatePlane(aBuffer.mPlanes[0]) ||
|
||||
!ValidatePlane(aBuffer.mPlanes[1]) ||
|
||||
!ValidatePlane(aBuffer.mPlanes[2])) {
|
||||
NS_WARNING("Invalid plane size");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure the picture size specified in the headers can be extracted out of
|
||||
// the frame we've been supplied without indexing out of bounds.
|
||||
CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
|
||||
CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
|
||||
if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
|
||||
!yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
|
||||
{
|
||||
// The specified picture dimensions can't be contained inside the video
|
||||
// frame, we'll stomp memory if we try to copy it. Fail.
|
||||
NS_WARNING("Overflowing picture rect");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
VideoData::VideoData(int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
|
|
@ -242,36 +283,7 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
|||
return v.forget();
|
||||
}
|
||||
|
||||
// The following situation should never happen unless there is a bug
|
||||
// in the decoder
|
||||
if (aBuffer.mPlanes[1].mWidth != aBuffer.mPlanes[2].mWidth ||
|
||||
aBuffer.mPlanes[1].mHeight != aBuffer.mPlanes[2].mHeight) {
|
||||
NS_ERROR("C planes with different sizes");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The following situations could be triggered by invalid input
|
||||
if (aPicture.width <= 0 || aPicture.height <= 0) {
|
||||
// In debug mode, makes the error more noticeable
|
||||
MOZ_ASSERT(false, "Empty picture rect");
|
||||
return nullptr;
|
||||
}
|
||||
if (!ValidatePlane(aBuffer.mPlanes[0]) || !ValidatePlane(aBuffer.mPlanes[1]) ||
|
||||
!ValidatePlane(aBuffer.mPlanes[2])) {
|
||||
NS_WARNING("Invalid plane size");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Ensure the picture size specified in the headers can be extracted out of
|
||||
// the frame we've been supplied without indexing out of bounds.
|
||||
CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
|
||||
CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
|
||||
if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
|
||||
!yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
|
||||
{
|
||||
// The specified picture dimensions can't be contained inside the video
|
||||
// frame, we'll stomp memory if we try to copy it. Fail.
|
||||
NS_WARNING("Overflowing picture rect");
|
||||
if (!ValidateBufferAndPicture(aBuffer, aPicture)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -305,6 +317,73 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
|||
return v.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<VideoData>
|
||||
VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
||||
ImageContainer* aContainer,
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
const YCbCrBuffer& aBuffer,
|
||||
const YCbCrBuffer::Plane &aAlphaPlane,
|
||||
bool aKeyframe,
|
||||
int64_t aTimecode,
|
||||
const IntRect& aPicture)
|
||||
{
|
||||
if (!aContainer) {
|
||||
// Create a dummy VideoData with no image. This gives us something to
|
||||
// send to media streams if necessary.
|
||||
RefPtr<VideoData> v(new VideoData(aOffset,
|
||||
aTime,
|
||||
aDuration,
|
||||
aKeyframe,
|
||||
aTimecode,
|
||||
aInfo.mDisplay,
|
||||
0));
|
||||
return v.forget();
|
||||
}
|
||||
|
||||
if (!ValidateBufferAndPicture(aBuffer, aPicture)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<VideoData> v(new VideoData(aOffset,
|
||||
aTime,
|
||||
aDuration,
|
||||
aKeyframe,
|
||||
aTimecode,
|
||||
aInfo.mDisplay,
|
||||
0));
|
||||
|
||||
// Convert from YUVA to BGRA format on the software side.
|
||||
RefPtr<layers::SharedRGBImage> videoImage =
|
||||
aContainer->CreateSharedRGBImage();
|
||||
v->mImage = videoImage;
|
||||
|
||||
if (!v->mImage) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!videoImage->Allocate(IntSize(aBuffer.mPlanes[0].mWidth,
|
||||
aBuffer.mPlanes[0].mHeight),
|
||||
SurfaceFormat::B8G8R8A8)) {
|
||||
return nullptr;
|
||||
}
|
||||
uint8_t* argb_buffer = videoImage->GetBuffer();
|
||||
IntSize size = videoImage->GetSize();
|
||||
|
||||
// The naming convention for libyuv and associated utils is word-order.
|
||||
// The naming convention in the gfx stack is byte-order.
|
||||
ConvertYCbCrAToARGB(aBuffer.mPlanes[0].mData,
|
||||
aBuffer.mPlanes[1].mData,
|
||||
aBuffer.mPlanes[2].mData,
|
||||
aAlphaPlane.mData,
|
||||
aBuffer.mPlanes[0].mStride, aBuffer.mPlanes[1].mStride,
|
||||
argb_buffer, size.width * 4,
|
||||
size.width, size.height);
|
||||
|
||||
return v.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<VideoData>
|
||||
VideoData::CreateFromImage(const VideoInfo& aInfo,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue