Bug 1321076 - Updated VPXDecoder to decode alpha frames. r=jya
VPXDecoder initializes a second context when alpha is encountered.
MozReview-Commit-ID: FMzHFvP8YK0
--- a/dom/media/platforms/agnostic/VPXDecoder.cpp
+++ b/dom/media/platforms/agnostic/VPXDecoder.cpp
@@ -29,65 +29,87 @@ static int MimeTypeToCodec(const nsACStr
} else if (aMimeType.EqualsLiteral("video/webm; codecs=vp9")) {
return VPXDecoder::Codec::VP9;
} else if (aMimeType.EqualsLiteral("video/vp9")) {
return VPXDecoder::Codec::VP9;
}
return -1;
}
+static nsresult
+InitContext(vpx_codec_ctx_t* aCtx,
+ const VideoInfo& aInfo,
+ const int 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)
, mCallback(aParams.mCallback)
, mIsFlushing(false)
, mInfo(aParams.VideoConfig())
, mCodec(MimeTypeToCodec(aParams.VideoConfig().mMimeType))
{
MOZ_COUNT_CTOR(VPXDecoder);
PodZero(&mVPX);
+ PodZero(&mVPXAlpha);
}
VPXDecoder::~VPXDecoder()
{
MOZ_COUNT_DTOR(VPXDecoder);
}
void
VPXDecoder::Shutdown()
{
vpx_codec_destroy(&mVPX);
}
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
VPXDecoder::Flush()
{
MOZ_ASSERT(mCallback->OnReaderTaskQueue());
mIsFlushing = true;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([this] () {
@@ -116,24 +138,37 @@ VPXDecoder::DoDecode(MediaRawData* aSamp
if (vpx_codec_err_t r = vpx_codec_decode(&mVPX, aSample->Data(), aSample->Size(), nullptr, 0)) {
LOG("VPX Decode error: %s", vpx_codec_err_to_string(r));
return MediaResult(
NS_ERROR_DOM_MEDIA_DECODE_ERR,
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];
b.mPlanes[0].mStride = img->stride[0];
b.mPlanes[0].mHeight = img->d_h;
b.mPlanes[0].mWidth = img->d_w;
b.mPlanes[0].mOffset = b.mPlanes[0].mSkip = 0;
@@ -218,16 +253,42 @@ VPXDecoder::ProcessDrain()
void
VPXDecoder::Drain()
{
MOZ_ASSERT(mCallback->OnReaderTaskQueue());
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)
{
return ((aCodecMask & VPXDecoder::VP8) &&
aMimeType.EqualsLiteral("video/webm; codecs=vp8")) ||
((aCodecMask & VPXDecoder::VP9) &&
aMimeType.EqualsLiteral("video/webm; codecs=vp9")) ||
--- a/dom/media/platforms/agnostic/VPXDecoder.h
+++ b/dom/media/platforms/agnostic/VPXDecoder.h
@@ -45,25 +45,30 @@ public:
static bool IsVPX(const nsACString& aMimeType, uint8_t aCodecMask=VP8|VP9);
static bool IsVP8(const nsACString& aMimeType);
static bool IsVP9(const nsACString& aMimeType);
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;
MediaDataDecoderCallback* mCallback;
Atomic<bool> mIsFlushing;
// VPx decoder state
vpx_codec_ctx_t mVPX;
+ // VPx alpha decoder state
+ vpx_codec_ctx_t mVPXAlpha;
+
const VideoInfo& mInfo;
const int mCodec;
};
} // namespace mozilla
#endif