mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-26 02:17:34 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
bac9ec9a84
39 changed files with 541 additions and 108 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,
|
||||
|
|
@ -340,6 +419,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>
|
||||
MediaRawData::Clone() const
|
||||
{
|
||||
|
|
@ -356,6 +444,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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -474,6 +474,17 @@ public:
|
|||
int64_t aTimecode,
|
||||
const IntRect& aPicture);
|
||||
|
||||
static already_AddRefed<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);
|
||||
|
||||
static already_AddRefed<VideoData> CreateAndCopyIntoTextureClient(const VideoInfo& aInfo,
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
|
|
@ -622,15 +633,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<const uint8_t>() { return MakeSpan(Data(), Size()); }
|
||||
|
|
@ -661,6 +679,7 @@ protected:
|
|||
private:
|
||||
friend class MediaRawDataWriter;
|
||||
AlignedByteBuffer mBuffer;
|
||||
AlignedByteBuffer mAlphaBuffer;
|
||||
CryptoSample mCryptoInternal;
|
||||
MediaRawData(const MediaRawData&); // Not implemented
|
||||
};
|
||||
|
|
|
|||
|
|
@ -215,6 +215,7 @@ public:
|
|||
, mRotation(aOther.mRotation)
|
||||
, mBitDepth(aOther.mBitDepth)
|
||||
, mImageRect(aOther.mImageRect)
|
||||
, mAlphaPresent(aOther.mAlphaPresent)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -238,6 +239,16 @@ public:
|
|||
return MakeUnique<VideoInfo>(*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 {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ MediaSourceDemuxer::AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes
|
|||
RefPtr<MediaSourceDecoder::ResourceSizes> sizes = aSizes;
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableFunction([self, sizes] () {
|
||||
for (TrackBuffersManager* manager : self->mSourceBuffers) {
|
||||
for (const RefPtr<TrackBuffersManager>& manager : self->mSourceBuffers) {
|
||||
manager->AddSizeOfResources(sizes);
|
||||
}
|
||||
});
|
||||
|
|
@ -171,42 +171,45 @@ MediaSourceDemuxer::GetCrypto()
|
|||
}
|
||||
|
||||
void
|
||||
MediaSourceDemuxer::AttachSourceBuffer(TrackBuffersManager* aSourceBuffer)
|
||||
MediaSourceDemuxer::AttachSourceBuffer(
|
||||
RefPtr<TrackBuffersManager>& aSourceBuffer)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NewRunnableMethod<TrackBuffersManager*>(
|
||||
nsCOMPtr<nsIRunnable> task = NewRunnableMethod<RefPtr<TrackBuffersManager>&&>(
|
||||
this, &MediaSourceDemuxer::DoAttachSourceBuffer,
|
||||
aSourceBuffer);
|
||||
GetTaskQueue()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDemuxer::DoAttachSourceBuffer(mozilla::TrackBuffersManager* aSourceBuffer)
|
||||
MediaSourceDemuxer::DoAttachSourceBuffer(
|
||||
RefPtr<mozilla::TrackBuffersManager>&& aSourceBuffer)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
mSourceBuffers.AppendElement(aSourceBuffer);
|
||||
mSourceBuffers.AppendElement(Move(aSourceBuffer));
|
||||
ScanSourceBuffersForContent();
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDemuxer::DetachSourceBuffer(TrackBuffersManager* aSourceBuffer)
|
||||
MediaSourceDemuxer::DetachSourceBuffer(
|
||||
RefPtr<TrackBuffersManager>& aSourceBuffer)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NewRunnableMethod<TrackBuffersManager*>(
|
||||
this, &MediaSourceDemuxer::DoDetachSourceBuffer,
|
||||
aSourceBuffer);
|
||||
RefPtr<MediaSourceDemuxer> self = this;
|
||||
nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
|
||||
[self, aSourceBuffer]() {
|
||||
self->DoDetachSourceBuffer(aSourceBuffer);
|
||||
});
|
||||
GetTaskQueue()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDemuxer::DoDetachSourceBuffer(TrackBuffersManager* aSourceBuffer)
|
||||
MediaSourceDemuxer::DoDetachSourceBuffer(
|
||||
const RefPtr<TrackBuffersManager>& aSourceBuffer)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
for (uint32_t i = 0; i < mSourceBuffers.Length(); i++) {
|
||||
if (mSourceBuffers[i].get() == aSourceBuffer) {
|
||||
mSourceBuffers.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
mSourceBuffers.RemoveElementsBy(
|
||||
[&aSourceBuffer](const RefPtr<TrackBuffersManager> aLinkedSourceBuffer) {
|
||||
return aLinkedSourceBuffer == aSourceBuffer;
|
||||
});
|
||||
if (aSourceBuffer == mAudioTrack) {
|
||||
mAudioTrack = nullptr;
|
||||
}
|
||||
|
|
@ -230,7 +233,7 @@ MediaSourceDemuxer::GetTrackInfo(TrackType aTrack)
|
|||
}
|
||||
}
|
||||
|
||||
TrackBuffersManager*
|
||||
RefPtr<TrackBuffersManager>
|
||||
MediaSourceDemuxer::GetManager(TrackType aTrack)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ public:
|
|||
void NotifyDataArrived() override;
|
||||
|
||||
/* interface for TrackBuffersManager */
|
||||
void AttachSourceBuffer(TrackBuffersManager* aSourceBuffer);
|
||||
void DetachSourceBuffer(TrackBuffersManager* aSourceBuffer);
|
||||
void AttachSourceBuffer(RefPtr<TrackBuffersManager>& aSourceBuffer);
|
||||
void DetachSourceBuffer(RefPtr<TrackBuffersManager>& aSourceBuffer);
|
||||
AutoTaskQueue* GetTaskQueue() { return mTaskQueue; }
|
||||
|
||||
// Returns a string describing the state of the MediaSource internal
|
||||
|
|
@ -64,10 +64,10 @@ private:
|
|||
// Scan source buffers and update information.
|
||||
bool ScanSourceBuffersForContent();
|
||||
RefPtr<InitPromise> AttemptInit();
|
||||
TrackBuffersManager* GetManager(TrackInfo::TrackType aType);
|
||||
RefPtr<TrackBuffersManager> GetManager(TrackInfo::TrackType aType);
|
||||
TrackInfo* GetTrackInfo(TrackInfo::TrackType);
|
||||
void DoAttachSourceBuffer(TrackBuffersManager* aSourceBuffer);
|
||||
void DoDetachSourceBuffer(TrackBuffersManager* aSourceBuffer);
|
||||
void DoAttachSourceBuffer(RefPtr<TrackBuffersManager>&& aSourceBuffer);
|
||||
void DoDetachSourceBuffer(const RefPtr<TrackBuffersManager>& aSourceBuffer);
|
||||
bool OnTaskQueue()
|
||||
{
|
||||
return !GetTaskQueue() || GetTaskQueue()->IsCurrentThreadIn();
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ SourceBuffer::Detach()
|
|||
if (mTrackBuffersManager) {
|
||||
mTrackBuffersManager->Detach();
|
||||
mMediaSource->GetDecoder()->GetDemuxer()->DetachSourceBuffer(
|
||||
mTrackBuffersManager.get());
|
||||
mTrackBuffersManager);
|
||||
}
|
||||
mTrackBuffersManager = nullptr;
|
||||
mMediaSource = nullptr;
|
||||
|
|
@ -321,7 +321,7 @@ SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
|
|||
SetMode(SourceBufferAppendMode::Segments, dummy);
|
||||
}
|
||||
mMediaSource->GetDecoder()->GetDemuxer()->AttachSourceBuffer(
|
||||
mTrackBuffersManager.get());
|
||||
mTrackBuffersManager);
|
||||
}
|
||||
|
||||
SourceBuffer::~SourceBuffer()
|
||||
|
|
|
|||
|
|
@ -35,6 +35,38 @@ static VPXDecoder::Codec MimeTypeToCodec(const nsACString& aMimeType)
|
|||
return VPXDecoder::Codec::Unknown;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
InitContext(vpx_codec_ctx_t* aCtx,
|
||||
const VideoInfo& aInfo,
|
||||
const VPXDecoder::Codec aCodec)
|
||||
{
|
||||
int decode_threads = 2;
|
||||
|
||||
vpx_codec_iface_t* dx = nullptr;
|
||||
if (aCodec == VPXDecoder::Codec::VP8) {
|
||||
dx = vpx_codec_vp8_dx();
|
||||
}
|
||||
else if (aCodec == VPXDecoder::Codec::VP9) {
|
||||
dx = vpx_codec_vp9_dx();
|
||||
if (aInfo.mDisplay.width >= 2048) {
|
||||
decode_threads = 8;
|
||||
}
|
||||
else if (aInfo.mDisplay.width >= 1024) {
|
||||
decode_threads = 4;
|
||||
}
|
||||
}
|
||||
decode_threads = std::min(decode_threads, PR_GetNumberOfProcessors());
|
||||
|
||||
vpx_codec_dec_cfg_t config;
|
||||
config.threads = decode_threads;
|
||||
config.w = config.h = 0; // set after decode
|
||||
|
||||
if (!dx || vpx_codec_dec_init(aCtx, dx, &config, 0)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
VPXDecoder::VPXDecoder(const CreateDecoderParams& aParams)
|
||||
: mImageContainer(aParams.mImageContainer)
|
||||
, mTaskQueue(aParams.mTaskQueue)
|
||||
|
|
@ -45,6 +77,7 @@ VPXDecoder::VPXDecoder(const CreateDecoderParams& aParams)
|
|||
{
|
||||
MOZ_COUNT_CTOR(VPXDecoder);
|
||||
PodZero(&mVPX);
|
||||
PodZero(&mVPXAlpha);
|
||||
}
|
||||
|
||||
VPXDecoder::~VPXDecoder()
|
||||
|
|
@ -56,34 +89,24 @@ void
|
|||
VPXDecoder::Shutdown()
|
||||
{
|
||||
vpx_codec_destroy(&mVPX);
|
||||
vpx_codec_destroy(&mVPXAlpha);
|
||||
}
|
||||
|
||||
RefPtr<MediaDataDecoder::InitPromise>
|
||||
VPXDecoder::Init()
|
||||
{
|
||||
int decode_threads = 2;
|
||||
|
||||
vpx_codec_iface_t* dx = nullptr;
|
||||
if (mCodec == Codec::VP8) {
|
||||
dx = vpx_codec_vp8_dx();
|
||||
} else if (mCodec == Codec::VP9) {
|
||||
dx = vpx_codec_vp9_dx();
|
||||
if (mInfo.mDisplay.width >= 2048) {
|
||||
decode_threads = 8;
|
||||
} else if (mInfo.mDisplay.width >= 1024) {
|
||||
decode_threads = 4;
|
||||
if (NS_FAILED(InitContext(&mVPX, mInfo, mCodec))) {
|
||||
return VPXDecoder::InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
__func__);
|
||||
}
|
||||
if (mInfo.HasAlpha()) {
|
||||
if (NS_FAILED(InitContext(&mVPXAlpha, mInfo, mCodec))) {
|
||||
return VPXDecoder::InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
__func__);
|
||||
}
|
||||
}
|
||||
decode_threads = std::min(decode_threads, PR_GetNumberOfProcessors());
|
||||
|
||||
vpx_codec_dec_cfg_t config;
|
||||
config.threads = decode_threads;
|
||||
config.w = config.h = 0; // set after decode
|
||||
|
||||
if (!dx || vpx_codec_dec_init(&mVPX, dx, &config, 0)) {
|
||||
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||
}
|
||||
return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__);
|
||||
return VPXDecoder::InitPromise::CreateAndResolve(TrackInfo::kVideoTrack,
|
||||
__func__);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -115,14 +138,27 @@ VPXDecoder::DoDecode(MediaRawData* aSample)
|
|||
RESULT_DETAIL("VPX error: %s", vpx_codec_err_to_string(r)));
|
||||
}
|
||||
|
||||
vpx_codec_iter_t iter = nullptr;
|
||||
vpx_image_t *img;
|
||||
vpx_codec_iter_t iter = nullptr;
|
||||
vpx_image_t *img;
|
||||
vpx_image_t *img_alpha = nullptr;
|
||||
bool alpha_decoded = false;
|
||||
|
||||
while ((img = vpx_codec_get_frame(&mVPX, &iter))) {
|
||||
NS_ASSERTION(img->fmt == VPX_IMG_FMT_I420 ||
|
||||
img->fmt == VPX_IMG_FMT_I444,
|
||||
"WebM image format not I420 or I444");
|
||||
|
||||
NS_ASSERTION(!alpha_decoded,
|
||||
"Multiple frames per packet that contains alpha");
|
||||
|
||||
if (aSample->AlphaSize() > 0) {
|
||||
if(!alpha_decoded){
|
||||
MediaResult rv = DecodeAlpha(&img_alpha, aSample);
|
||||
if (NS_FAILED(rv)) {
|
||||
return(rv);
|
||||
}
|
||||
alpha_decoded = true;
|
||||
}
|
||||
}
|
||||
// Chroma shifts are rounded down as per the decoding examples in the SDK
|
||||
VideoData::YCbCrBuffer b;
|
||||
b.mPlanes[0].mData = img->planes[0];
|
||||
|
|
@ -174,17 +210,38 @@ VPXDecoder::DoDecode(MediaRawData* aSample)
|
|||
}();
|
||||
// TODO: need a newer libvpx to support full color range
|
||||
|
||||
RefPtr<VideoData> v =
|
||||
VideoData::CreateAndCopyData(mInfo,
|
||||
mImageContainer,
|
||||
aSample->mOffset,
|
||||
aSample->mTime,
|
||||
aSample->mDuration,
|
||||
b,
|
||||
aSample->mKeyframe,
|
||||
aSample->mTimecode,
|
||||
mInfo.ScaledImageRect(img->d_w,
|
||||
img->d_h));
|
||||
RefPtr<VideoData> v;
|
||||
if (!img_alpha) {
|
||||
v = VideoData::CreateAndCopyData(mInfo,
|
||||
mImageContainer,
|
||||
aSample->mOffset,
|
||||
aSample->mTime,
|
||||
aSample->mDuration,
|
||||
b,
|
||||
aSample->mKeyframe,
|
||||
aSample->mTimecode,
|
||||
mInfo.ScaledImageRect(img->d_w,
|
||||
img->d_h));
|
||||
} else {
|
||||
VideoData::YCbCrBuffer::Plane alpha_plane;
|
||||
alpha_plane.mData = img_alpha->planes[0];
|
||||
alpha_plane.mStride = img_alpha->stride[0];
|
||||
alpha_plane.mHeight = img_alpha->d_h;
|
||||
alpha_plane.mWidth = img_alpha->d_w;
|
||||
alpha_plane.mOffset = alpha_plane.mSkip = 0;
|
||||
v = VideoData::CreateAndCopyData(mInfo,
|
||||
mImageContainer,
|
||||
aSample->mOffset,
|
||||
aSample->mTime,
|
||||
aSample->mDuration,
|
||||
b,
|
||||
alpha_plane,
|
||||
aSample->mKeyframe,
|
||||
aSample->mTimecode,
|
||||
mInfo.ScaledImageRect(img->d_w,
|
||||
img->d_h));
|
||||
|
||||
}
|
||||
|
||||
if (!v) {
|
||||
LOG("Image allocation error source %ldx%ld display %ldx%ld picture %ldx%ld",
|
||||
|
|
@ -234,6 +291,32 @@ VPXDecoder::Drain()
|
|||
mTaskQueue->Dispatch(NewRunnableMethod(this, &VPXDecoder::ProcessDrain));
|
||||
}
|
||||
|
||||
MediaResult
|
||||
VPXDecoder::DecodeAlpha(vpx_image_t** aImgAlpha,
|
||||
MediaRawData* aSample)
|
||||
{
|
||||
vpx_codec_err_t r = vpx_codec_decode(&mVPXAlpha,
|
||||
aSample->AlphaData(),
|
||||
aSample->AlphaSize(),
|
||||
nullptr,
|
||||
0);
|
||||
if (r) {
|
||||
LOG("VPX decode alpha error: %s", vpx_codec_err_to_string(r));
|
||||
return MediaResult(
|
||||
NS_ERROR_DOM_MEDIA_DECODE_ERR,
|
||||
RESULT_DETAIL("VPX decode alpha error: %s", vpx_codec_err_to_string(r)));
|
||||
}
|
||||
|
||||
vpx_codec_iter_t iter = nullptr;
|
||||
|
||||
*aImgAlpha = vpx_codec_get_frame(&mVPXAlpha, &iter);
|
||||
NS_ASSERTION((*aImgAlpha)->fmt == VPX_IMG_FMT_I420 ||
|
||||
(*aImgAlpha)->fmt == VPX_IMG_FMT_I444,
|
||||
"WebM image format not I420 or I444");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
VPXDecoder::IsVPX(const nsACString& aMimeType, uint8_t aCodecMask)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ private:
|
|||
void ProcessDecode(MediaRawData* aSample);
|
||||
MediaResult DoDecode(MediaRawData* aSample);
|
||||
void ProcessDrain();
|
||||
MediaResult DecodeAlpha(vpx_image_t** aImgAlpha,
|
||||
MediaRawData* aSample);
|
||||
|
||||
const RefPtr<ImageContainer> mImageContainer;
|
||||
const RefPtr<TaskQueue> mTaskQueue;
|
||||
|
|
@ -66,6 +68,9 @@ private:
|
|||
// VPx decoder state
|
||||
vpx_codec_ctx_t mVPX;
|
||||
|
||||
// VPx alpha decoder state
|
||||
vpx_codec_ctx_t mVPXAlpha;
|
||||
|
||||
const VideoInfo& mInfo;
|
||||
|
||||
const Codec mCodec;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,13 @@ public:
|
|||
already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const CreateDecoderParams& aParams) override
|
||||
{
|
||||
// Temporary - forces use of VPXDecoder when alpha is present.
|
||||
// Bug 1263836 will handle alpha scenario once implemented. It will shift
|
||||
// the check for alpha to PDMFactory but not itself remove the need for a
|
||||
// check.
|
||||
if (aParams.VideoConfig().HasAlpha()) {
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<MediaDataDecoder> decoder =
|
||||
new FFmpegVideoDecoder<V>(mLib,
|
||||
aParams.mTaskQueue,
|
||||
|
|
|
|||
|
|
@ -83,6 +83,14 @@ WMFDecoderModule::Startup()
|
|||
already_AddRefed<MediaDataDecoder>
|
||||
WMFDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
|
||||
{
|
||||
// Temporary - forces use of VPXDecoder when alpha is present.
|
||||
// Bug 1263836 will handle alpha scenario once implemented. It will shift
|
||||
// the check for alpha to PDMFactory but not itself remove the need for a
|
||||
// check.
|
||||
if (aParams.VideoConfig().HasAlpha()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoPtr<WMFVideoMFTManager> manager(
|
||||
new WMFVideoMFTManager(aParams.VideoConfig(),
|
||||
aParams.mKnowsCompositor,
|
||||
|
|
|
|||
|
|
@ -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<MediaRawData> sample = new MediaRawData(data, length);
|
||||
if (length && !sample->Data()) {
|
||||
// OOM.
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
RefPtr<MediaRawData> 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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue