Bug 1380118 - aom: Don't resample 8-bit images. r?kinetik
The libaom av1 decoder will return 16 bit per channel
aom_image_t structures with only 8 significant bits.
Detect this case and use the mSkip fields of PlanarYCbCrImage
to handle the extra data instead of allocating and performing
an extra copy to obtain the necessary 8 bit representation.
MozReview-Commit-ID: 8H9YZe86Qzu
--- a/dom/media/platforms/agnostic/AOMDecoder.cpp
+++ b/dom/media/platforms/agnostic/AOMDecoder.cpp
@@ -184,18 +184,20 @@ AOMDecoder::ProcessDecode(MediaRawData*
}
aom_codec_iter_t iter = nullptr;
aom_image_t *img;
UniquePtr<aom_image_t, AomImageFree> img8;
DecodedData results;
while ((img = aom_codec_get_frame(&mCodec, &iter))) {
- if (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) {
- // Downsample images with more than 8 bits per channel.
+ // Track whether the underlying buffer is 8 or 16 bits per channel.
+ bool highbd = bool(img->fmt & AOM_IMG_FMT_HIGHBITDEPTH);
+ if (img->bit_depth > 8) {
+ // Downsample images with more than 8 significant bits per channel.
aom_img_fmt_t fmt8 = static_cast<aom_img_fmt_t>(img->fmt ^ AOM_IMG_FMT_HIGHBITDEPTH);
img8.reset(aom_img_alloc(NULL, fmt8, img->d_w, img->d_h, 16));
if (img8 == nullptr) {
LOG("Couldn't allocate bitdepth reduction target!");
return DecodePromise::CreateAndReject(
MediaResult(NS_ERROR_OUT_OF_MEMORY,
RESULT_DETAIL("Couldn't allocate conversion buffer for AV1 frame")),
__func__);
@@ -208,39 +210,46 @@ AOMDecoder::ProcessDecode(MediaRawData*
aom_codec_err_to_string(r))),
__func__);
}
// img normally points to storage owned by mCodec, so it is not freed.
// To copy out the contents of img8 we can overwrite img with an alias.
// Since img is assigned at the start of the while loop and img8 is held
// outside that loop, the alias won't outlive the storage it points to.
img = img8.get();
+ highbd = false;
}
NS_ASSERTION(img->fmt == AOM_IMG_FMT_I420 ||
- img->fmt == AOM_IMG_FMT_I444,
+ img->fmt == AOM_IMG_FMT_I42016 ||
+ img->fmt == AOM_IMG_FMT_I444 ||
+ img->fmt == AOM_IMG_FMT_I44416,
"AV1 image format not I420 or I444");
// 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;
+ b.mPlanes[0].mOffset = 0;
+ b.mPlanes[0].mSkip = highbd ? 1 : 0;
b.mPlanes[1].mData = img->planes[1];
b.mPlanes[1].mStride = img->stride[1];
- b.mPlanes[1].mOffset = b.mPlanes[1].mSkip = 0;
+ b.mPlanes[1].mOffset = 0;
+ b.mPlanes[1].mSkip = highbd ? 1 : 0;
b.mPlanes[2].mData = img->planes[2];
b.mPlanes[2].mStride = img->stride[2];
- b.mPlanes[2].mOffset = b.mPlanes[2].mSkip = 0;
+ b.mPlanes[2].mOffset = 0;
+ b.mPlanes[2].mSkip = highbd ? 1 : 0;
- if (img->fmt == AOM_IMG_FMT_I420) {
+ if (img->fmt == AOM_IMG_FMT_I420 ||
+ img->fmt == AOM_IMG_FMT_I42016) {
b.mPlanes[1].mHeight = (img->d_h + 1) >> img->y_chroma_shift;
b.mPlanes[1].mWidth = (img->d_w + 1) >> img->x_chroma_shift;
b.mPlanes[2].mHeight = (img->d_h + 1) >> img->y_chroma_shift;
b.mPlanes[2].mWidth = (img->d_w + 1) >> img->x_chroma_shift;
} else if (img->fmt == AOM_IMG_FMT_I444) {
b.mPlanes[1].mHeight = img->d_h;
b.mPlanes[1].mWidth = img->d_w;