summaryrefslogtreecommitdiff
path: root/dom/media/platforms/agnostic/VPXDecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/platforms/agnostic/VPXDecoder.cpp')
-rw-r--r--dom/media/platforms/agnostic/VPXDecoder.cpp153
1 files changed, 118 insertions, 35 deletions
diff --git a/dom/media/platforms/agnostic/VPXDecoder.cpp b/dom/media/platforms/agnostic/VPXDecoder.cpp
index 007ead0c7d..00cf7d85cc 100644
--- a/dom/media/platforms/agnostic/VPXDecoder.cpp
+++ b/dom/media/platforms/agnostic/VPXDecoder.cpp
@@ -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__);
}
- 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__);
+ if (mInfo.HasAlpha()) {
+ if (NS_FAILED(InitContext(&mVPXAlpha, mInfo, mCodec))) {
+ return VPXDecoder::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)