mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-26 19:55:39 +00:00
Bug 1380118 - aom: Resample high bit depth frames. r=kinetik
The libaom av1 decoder can return high bit depth frame data now. Handle those frames by downsampling them to 8 bits per channel so they can be passed to our normal playback pipeline. MozReview-Commit-ID: 97XYeh3YvQw --HG-- extra : rebase_source : 04592c06f2f71bd4e54cd1650a237564f76d868c
This commit is contained in:
parent
353ef545b4
commit
a4cea13c80
@ -8,6 +8,7 @@
|
|||||||
#include "MediaResult.h"
|
#include "MediaResult.h"
|
||||||
#include "TimeUnits.h"
|
#include "TimeUnits.h"
|
||||||
#include "aom/aomdx.h"
|
#include "aom/aomdx.h"
|
||||||
|
#include "aom/aom_image.h"
|
||||||
#include "gfx2DGlue.h"
|
#include "gfx2DGlue.h"
|
||||||
#include "mozilla/PodOperations.h"
|
#include "mozilla/PodOperations.h"
|
||||||
#include "mozilla/SyncRunnable.h"
|
#include "mozilla/SyncRunnable.h"
|
||||||
@ -107,6 +108,62 @@ AOMDecoder::Flush()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ported from third_party/aom/tools_common.c.
|
||||||
|
static aom_codec_err_t
|
||||||
|
highbd_img_downshift(aom_image_t *dst, aom_image_t *src, int down_shift) {
|
||||||
|
int plane;
|
||||||
|
if (dst->d_w != src->d_w || dst->d_h != src->d_h)
|
||||||
|
return AOM_CODEC_INVALID_PARAM;
|
||||||
|
if (dst->x_chroma_shift != src->x_chroma_shift)
|
||||||
|
return AOM_CODEC_INVALID_PARAM;
|
||||||
|
if (dst->y_chroma_shift != src->y_chroma_shift)
|
||||||
|
return AOM_CODEC_INVALID_PARAM;
|
||||||
|
if (dst->fmt != (src->fmt & ~AOM_IMG_FMT_HIGHBITDEPTH))
|
||||||
|
return AOM_CODEC_INVALID_PARAM;
|
||||||
|
if (down_shift < 0)
|
||||||
|
return AOM_CODEC_INVALID_PARAM;
|
||||||
|
switch (dst->fmt) {
|
||||||
|
case AOM_IMG_FMT_I420:
|
||||||
|
case AOM_IMG_FMT_I422:
|
||||||
|
case AOM_IMG_FMT_I444:
|
||||||
|
case AOM_IMG_FMT_I440:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return AOM_CODEC_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
switch (src->fmt) {
|
||||||
|
case AOM_IMG_FMT_I42016:
|
||||||
|
case AOM_IMG_FMT_I42216:
|
||||||
|
case AOM_IMG_FMT_I44416:
|
||||||
|
case AOM_IMG_FMT_I44016:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return AOM_CODEC_UNSUP_BITSTREAM;
|
||||||
|
}
|
||||||
|
for (plane = 0; plane < 3; plane++) {
|
||||||
|
int w = src->d_w;
|
||||||
|
int h = src->d_h;
|
||||||
|
int x, y;
|
||||||
|
if (plane) {
|
||||||
|
w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
|
||||||
|
h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
|
||||||
|
}
|
||||||
|
for (y = 0; y < h; y++) {
|
||||||
|
uint16_t *p_src =
|
||||||
|
(uint16_t *)(src->planes[plane] + y * src->stride[plane]);
|
||||||
|
uint8_t *p_dst =
|
||||||
|
dst->planes[plane] + y * dst->stride[plane];
|
||||||
|
for (x = 0; x < w; x++) *p_dst++ = (*p_src++ >> down_shift) & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AOM_CODEC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UniquePtr dtor wrapper for aom_image_t.
|
||||||
|
struct AomImageFree {
|
||||||
|
void operator()(aom_image_t* img) { aom_img_free(img); }
|
||||||
|
};
|
||||||
|
|
||||||
RefPtr<MediaDataDecoder::DecodePromise>
|
RefPtr<MediaDataDecoder::DecodePromise>
|
||||||
AOMDecoder::ProcessDecode(MediaRawData* aSample)
|
AOMDecoder::ProcessDecode(MediaRawData* aSample)
|
||||||
{
|
{
|
||||||
@ -128,12 +185,39 @@ AOMDecoder::ProcessDecode(MediaRawData* aSample)
|
|||||||
|
|
||||||
aom_codec_iter_t iter = nullptr;
|
aom_codec_iter_t iter = nullptr;
|
||||||
aom_image_t *img;
|
aom_image_t *img;
|
||||||
|
UniquePtr<aom_image_t, AomImageFree> img8;
|
||||||
DecodedData results;
|
DecodedData results;
|
||||||
|
|
||||||
while ((img = aom_codec_get_frame(&mCodec, &iter))) {
|
while ((img = aom_codec_get_frame(&mCodec, &iter))) {
|
||||||
|
if (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) {
|
||||||
|
// Downsample images with more than 8 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__);
|
||||||
|
}
|
||||||
|
if (aom_codec_err_t r = highbd_img_downshift(img8.get(), img, img->bit_depth - 8)) {
|
||||||
|
LOG_RESULT(r, "Image downconversion failed");
|
||||||
|
return DecodePromise::CreateAndReject(
|
||||||
|
MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
|
||||||
|
RESULT_DETAIL("Error converting AV1 frame to 8 bits: %s",
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
NS_ASSERTION(img->fmt == AOM_IMG_FMT_I420 ||
|
NS_ASSERTION(img->fmt == AOM_IMG_FMT_I420 ||
|
||||||
img->fmt == AOM_IMG_FMT_I444,
|
img->fmt == AOM_IMG_FMT_I444,
|
||||||
"WebM image format not I420 or I444");
|
"AV1 image format not I420 or I444");
|
||||||
|
|
||||||
// Chroma shifts are rounded down as per the decoding examples in the SDK
|
// Chroma shifts are rounded down as per the decoding examples in the SDK
|
||||||
VideoData::YCbCrBuffer b;
|
VideoData::YCbCrBuffer b;
|
||||||
|
Loading…
Reference in New Issue
Block a user