gav1: support 444 and 422 for 10bit (YV12/P010 paths)
This will enable 444 and 422 support for AVIF images as well.
The HAL_PIXEL_FORMAT_RGBA_1010102 path is left as a follow up.
I?10ToP010 were added in:
7ed0473 Update external/libyuv to r1837
and upstream in version 1779.
To keep this compatible with mainline LIBYUV_VERSION checks are added
around the new code. libyuv is not a part of mainline and is currently
at libyuv version 1732.
Bug: 261112792
Bug: 279553165
Test: decode images on oriole and panther devices
Test: compile pre/post libyuv update
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d0466e830e09a8e7912fcad94b771b1607755f2a)
Merged-In: I2593552a5cb9c343f7939d32803ed61e3e8f47e3
Change-Id: I2593552a5cb9c343f7939d32803ed61e3e8f47e3
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
index 77296a4..914167d 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -726,6 +726,24 @@
}
}
+void C2SoftGav1Dec::setError(const std::unique_ptr<C2Work> &work, c2_status_t error) {
+ mSignalledError = true;
+ work->result = error;
+ work->workletsProcessed = 1u;
+}
+
+bool C2SoftGav1Dec::allocTmpFrameBuffer(size_t size) {
+ if (size > mTmpFrameBufferSize) {
+ mTmpFrameBuffer = std::make_unique<uint16_t[]>(size);
+ if (mTmpFrameBuffer == nullptr) {
+ mTmpFrameBufferSize = 0;
+ return false;
+ }
+ mTmpFrameBufferSize = size;
+ }
+ return true;
+}
+
bool C2SoftGav1Dec::outputBuffer(const std::shared_ptr<C2BlockPool> &pool,
const std::unique_ptr<C2Work> &work) {
if (!(work && pool)) return false;
@@ -772,6 +790,7 @@
getHDRStaticParams(buffer, work);
getHDR10PlusInfoData(buffer, work);
+#if LIBYUV_VERSION < 1779
if (buffer->bitdepth == 10 &&
!(buffer->image_format == libgav1::kImageFormatYuv420 ||
buffer->image_format == libgav1::kImageFormatMonochrome400)) {
@@ -781,6 +800,7 @@
work->result = C2_CORRUPTED;
return false;
}
+#endif
const bool isMonochrome =
buffer->image_format == libgav1::kImageFormatMonochrome400;
@@ -854,9 +874,6 @@
uint8_t *dstY = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
uint8_t *dstU = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_U]);
uint8_t *dstV = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_V]);
- size_t srcYStride = buffer->stride[0];
- size_t srcUStride = buffer->stride[1];
- size_t srcVStride = buffer->stride[2];
C2PlanarLayout layout = wView.layout();
size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
@@ -867,26 +884,100 @@
const uint16_t *srcY = (const uint16_t *)buffer->plane[0];
const uint16_t *srcU = (const uint16_t *)buffer->plane[1];
const uint16_t *srcV = (const uint16_t *)buffer->plane[2];
+ size_t srcYStride = buffer->stride[0] / 2;
+ size_t srcUStride = buffer->stride[1] / 2;
+ size_t srcVStride = buffer->stride[2] / 2;
if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
convertYUV420Planar16ToY410OrRGBA1010102(
- (uint32_t *)dstY, srcY, srcU, srcV, srcYStride / 2,
- srcUStride / 2, srcVStride / 2,
+ (uint32_t *)dstY, srcY, srcU, srcV, srcYStride,
+ srcUStride, srcVStride,
dstYStride / sizeof(uint32_t), mWidth, mHeight,
std::static_pointer_cast<const C2ColorAspectsStruct>(codedColorAspects));
} else if (format == HAL_PIXEL_FORMAT_YCBCR_P010) {
+ dstYStride /= 2;
+ dstUStride /= 2;
+ dstVStride /= 2;
+#if LIBYUV_VERSION >= 1779
+ if (buffer->image_format == libgav1::kImageFormatYuv444 ||
+ buffer->image_format == libgav1::kImageFormatYuv422) {
+ // TODO(https://crbug.com/libyuv/952): replace this block with libyuv::I410ToP010 and
+ // libyuv::I210ToP010 when they are available.
+ // Note it may be safe to alias dstY in I010ToP010, but the libyuv API doesn't make any
+ // guarantees.
+ const size_t tmpSize = dstYStride * mHeight + dstUStride * align(mHeight, 2);
+ if (!allocTmpFrameBuffer(tmpSize)) {
+ ALOGE("Error allocating temp conversion buffer (%zu bytes)", tmpSize);
+ setError(work, C2_NO_MEMORY);
+ return false;
+ }
+ uint16_t *const tmpY = mTmpFrameBuffer.get();
+ uint16_t *const tmpU = tmpY + dstYStride * mHeight;
+ uint16_t *const tmpV = tmpU + dstUStride * align(mHeight, 2) / 2;
+ if (buffer->image_format == libgav1::kImageFormatYuv444) {
+ libyuv::I410ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride,
+ tmpY, dstYStride, tmpU, dstUStride, tmpV, dstUStride,
+ mWidth, mHeight);
+ } else {
+ libyuv::I210ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride,
+ tmpY, dstYStride, tmpU, dstUStride, tmpV, dstUStride,
+ mWidth, mHeight);
+ }
+ libyuv::I010ToP010(tmpY, dstYStride, tmpU, dstUStride, tmpV, dstVStride,
+ (uint16_t*)dstY, dstYStride, (uint16_t*)dstU, dstUStride,
+ mWidth, mHeight);
+ } else {
+ convertYUV420Planar16ToP010((uint16_t *)dstY, (uint16_t *)dstU, srcY, srcU, srcV,
+ srcYStride, srcUStride, srcVStride, dstYStride,
+ dstUStride, mWidth, mHeight, isMonochrome);
+ }
+#else // LIBYUV_VERSION < 1779
convertYUV420Planar16ToP010((uint16_t *)dstY, (uint16_t *)dstU, srcY, srcU, srcV,
- srcYStride / 2, srcUStride / 2, srcVStride / 2, dstYStride / 2,
- dstUStride / 2, mWidth, mHeight, isMonochrome);
+ srcYStride, srcUStride, srcVStride, dstYStride,
+ dstUStride, mWidth, mHeight, isMonochrome);
+#endif // LIBYUV_VERSION >= 1779
} else {
- convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2,
- srcUStride / 2, srcVStride / 2, dstYStride, dstUStride, mWidth,
- mHeight, isMonochrome);
+#if LIBYUV_VERSION >= 1779
+ if (buffer->image_format == libgav1::kImageFormatYuv444) {
+ // TODO(https://crbug.com/libyuv/950): replace this block with libyuv::I410ToI420 when
+ // it's available.
+ const size_t tmpSize = dstYStride * mHeight + dstUStride * align(mHeight, 2);
+ if (!allocTmpFrameBuffer(tmpSize)) {
+ ALOGE("Error allocating temp conversion buffer (%zu bytes)", tmpSize);
+ setError(work, C2_NO_MEMORY);
+ return false;
+ }
+ uint16_t *const tmpY = mTmpFrameBuffer.get();
+ uint16_t *const tmpU = tmpY + dstYStride * mHeight;
+ uint16_t *const tmpV = tmpU + dstUStride * align(mHeight, 2) / 2;
+ libyuv::I410ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride,
+ tmpY, dstYStride, tmpU, dstUStride, tmpV, dstVStride,
+ mWidth, mHeight);
+ libyuv::I010ToI420(tmpY, dstYStride, tmpU, dstUStride, tmpV, dstUStride,
+ dstY, dstYStride, dstU, dstUStride, dstV, dstVStride,
+ mWidth, mHeight);
+ } else if (buffer->image_format == libgav1::kImageFormatYuv422) {
+ libyuv::I210ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride,
+ dstY, dstYStride, dstU, dstUStride, dstV, dstVStride,
+ mWidth, mHeight);
+ } else {
+ convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride,
+ srcUStride, srcVStride, dstYStride, dstUStride,
+ mWidth, mHeight, isMonochrome);
+ }
+#else // LIBYUV_VERSION < 1779
+ convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride,
+ srcUStride, srcVStride, dstYStride, dstUStride,
+ mWidth, mHeight, isMonochrome);
+#endif // LIBYUV_VERSION >= 1779
}
} else {
const uint8_t *srcY = (const uint8_t *)buffer->plane[0];
const uint8_t *srcU = (const uint8_t *)buffer->plane[1];
const uint8_t *srcV = (const uint8_t *)buffer->plane[2];
+ size_t srcYStride = buffer->stride[0];
+ size_t srcUStride = buffer->stride[1];
+ size_t srcVStride = buffer->stride[2];
if (buffer->image_format == libgav1::kImageFormatYuv444) {
libyuv::I444ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride,
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.h b/media/codec2/components/gav1/C2SoftGav1Dec.h
index f0e14d7..c3b27ea 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.h
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.h
@@ -19,6 +19,8 @@
#include <inttypes.h>
+#include <memory>
+
#include <media/stagefright/foundation/ColorUtils.h>
#include <SimpleC2Component.h>
@@ -60,6 +62,9 @@
uint32_t mHeight;
bool mSignalledOutputEos;
bool mSignalledError;
+ // Used during 10-bit I444/I422 to 10-bit P010 & 8-bit I420 conversions.
+ std::unique_ptr<uint16_t[]> mTmpFrameBuffer;
+ size_t mTmpFrameBufferSize = 0;
C2StreamHdrStaticMetadataInfo::output mHdrStaticMetadataInfo;
std::unique_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfo = nullptr;
@@ -97,6 +102,9 @@
void destroyDecoder();
void finishWork(uint64_t index, const std::unique_ptr<C2Work>& work,
const std::shared_ptr<C2GraphicBlock>& block);
+ // Sets |work->result| and mSignalledError. Returns false.
+ void setError(const std::unique_ptr<C2Work> &work, c2_status_t error);
+ bool allocTmpFrameBuffer(size_t size);
bool outputBuffer(const std::shared_ptr<C2BlockPool>& pool,
const std::unique_ptr<C2Work>& work);
c2_status_t drainInternal(uint32_t drainMode,