Upstream changes from hardware/google/av
This includes changes up to commit
c3f6c282c22de48e89fe1f364c37b13be7498404
Test: make cts -j123 && cts-tradefed run cts-dev -m \
CtsMediaTestCases --compatibility:module-arg \
CtsMediaTestCases:include-annotation:\
android.platform.test.annotations.RequiresDevice
Bug: 112362730
Change-Id: Idf91ba6d3b71a724292cc3ae533307194678ea83
diff --git a/media/codec2/sfplugin/utils/Android.bp b/media/codec2/sfplugin/utils/Android.bp
index eb6c3e9..8c8f025 100644
--- a/media/codec2/sfplugin/utils/Android.bp
+++ b/media/codec2/sfplugin/utils/Android.bp
@@ -26,6 +26,10 @@
"libutils",
],
+ static_libs: [
+ "libyuv_static",
+ ],
+
sanitize: {
cfi: true,
misc_undefined: [
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
index 84d22a3..6b8663f 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
@@ -18,6 +18,8 @@
#define LOG_TAG "Codec2BufferUtils"
#include <utils/Log.h>
+#include <libyuv.h>
+
#include <list>
#include <mutex>
@@ -62,14 +64,10 @@
*/
template<bool ToMediaImage, typename View, typename ImagePixel>
static status_t _ImageCopy(View &view, const MediaImage2 *img, ImagePixel *imgBase) {
- // TODO: more efficient copying --- e.g. one row at a time, copying
- // interleaved planes together, etc.
+ // TODO: more efficient copying --- e.g. copy interleaved planes together, etc.
const C2PlanarLayout &layout = view.layout();
const size_t bpp = divUp(img->mBitDepthAllocated, 8u);
- if (view.width() != img->mWidth
- || view.height() != img->mHeight) {
- return BAD_VALUE;
- }
+
for (uint32_t i = 0; i < layout.numPlanes; ++i) {
typename std::conditional<ToMediaImage, uint8_t, const uint8_t>::type *imgRow =
imgBase + img->mPlane[i].mOffset;
@@ -120,10 +118,72 @@
} // namespace
status_t ImageCopy(uint8_t *imgBase, const MediaImage2 *img, const C2GraphicView &view) {
+ if (view.width() != img->mWidth || view.height() != img->mHeight) {
+ return BAD_VALUE;
+ }
+ if ((IsNV12(view) && IsI420(img)) || (IsI420(view) && IsNV12(img))) {
+ // Take shortcuts to use libyuv functions between NV12 and I420 conversion.
+ const uint8_t* src_y = view.data()[0];
+ const uint8_t* src_u = view.data()[1];
+ const uint8_t* src_v = view.data()[2];
+ int32_t src_stride_y = view.layout().planes[0].rowInc;
+ int32_t src_stride_u = view.layout().planes[1].rowInc;
+ int32_t src_stride_v = view.layout().planes[2].rowInc;
+ uint8_t* dst_y = imgBase + img->mPlane[0].mOffset;
+ uint8_t* dst_u = imgBase + img->mPlane[1].mOffset;
+ uint8_t* dst_v = imgBase + img->mPlane[2].mOffset;
+ int32_t dst_stride_y = img->mPlane[0].mRowInc;
+ int32_t dst_stride_u = img->mPlane[1].mRowInc;
+ int32_t dst_stride_v = img->mPlane[2].mRowInc;
+ if (IsNV12(view) && IsI420(img)) {
+ if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
+ dst_u, dst_stride_u, dst_v, dst_stride_v, view.width(),
+ view.height())) {
+ return OK;
+ }
+ } else {
+ if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
+ dst_y, dst_stride_y, dst_u, dst_stride_u, view.width(),
+ view.height())) {
+ return OK;
+ }
+ }
+ }
return _ImageCopy<true>(view, img, imgBase);
}
status_t ImageCopy(C2GraphicView &view, const uint8_t *imgBase, const MediaImage2 *img) {
+ if (view.width() != img->mWidth || view.height() != img->mHeight) {
+ return BAD_VALUE;
+ }
+ if ((IsNV12(img) && IsI420(view)) || (IsI420(img) && IsNV12(view))) {
+ // Take shortcuts to use libyuv functions between NV12 and I420 conversion.
+ const uint8_t* src_y = imgBase + img->mPlane[0].mOffset;
+ const uint8_t* src_u = imgBase + img->mPlane[1].mOffset;
+ const uint8_t* src_v = imgBase + img->mPlane[2].mOffset;
+ int32_t src_stride_y = img->mPlane[0].mRowInc;
+ int32_t src_stride_u = img->mPlane[1].mRowInc;
+ int32_t src_stride_v = img->mPlane[2].mRowInc;
+ uint8_t* dst_y = view.data()[0];
+ uint8_t* dst_u = view.data()[1];
+ uint8_t* dst_v = view.data()[2];
+ int32_t dst_stride_y = view.layout().planes[0].rowInc;
+ int32_t dst_stride_u = view.layout().planes[1].rowInc;
+ int32_t dst_stride_v = view.layout().planes[2].rowInc;
+ if (IsNV12(img) && IsI420(view)) {
+ if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
+ dst_u, dst_stride_u, dst_v, dst_stride_v, view.width(),
+ view.height())) {
+ return OK;
+ }
+ } else {
+ if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
+ dst_y, dst_stride_y, dst_u, dst_stride_u, view.width(),
+ view.height())) {
+ return OK;
+ }
+ }
+ }
return _ImageCopy<false>(view, img, imgBase);
}
@@ -151,6 +211,65 @@
&& layout.planes[layout.PLANE_V].rowSampling == 2);
}
+bool IsNV12(const C2GraphicView &view) {
+ if (!IsYUV420(view)) {
+ return false;
+ }
+ const C2PlanarLayout &layout = view.layout();
+ return (layout.rootPlanes == 2
+ && layout.planes[layout.PLANE_U].colInc == 2
+ && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_U
+ && layout.planes[layout.PLANE_U].offset == 0
+ && layout.planes[layout.PLANE_V].colInc == 2
+ && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_U
+ && layout.planes[layout.PLANE_V].offset == 1);
+}
+
+bool IsI420(const C2GraphicView &view) {
+ if (!IsYUV420(view)) {
+ return false;
+ }
+ const C2PlanarLayout &layout = view.layout();
+ return (layout.rootPlanes == 3
+ && layout.planes[layout.PLANE_U].colInc == 1
+ && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_U
+ && layout.planes[layout.PLANE_U].offset == 0
+ && layout.planes[layout.PLANE_V].colInc == 1
+ && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_V
+ && layout.planes[layout.PLANE_V].offset == 0);
+}
+
+bool IsYUV420(const MediaImage2 *img) {
+ return (img->mType == MediaImage2::MEDIA_IMAGE_TYPE_YUV
+ && img->mNumPlanes == 3
+ && img->mBitDepth == 8
+ && img->mBitDepthAllocated == 8
+ && img->mPlane[0].mHorizSubsampling == 1
+ && img->mPlane[0].mVertSubsampling == 1
+ && img->mPlane[1].mHorizSubsampling == 2
+ && img->mPlane[1].mVertSubsampling == 2
+ && img->mPlane[2].mHorizSubsampling == 2
+ && img->mPlane[2].mVertSubsampling == 2);
+}
+
+bool IsNV12(const MediaImage2 *img) {
+ if (!IsYUV420(img)) {
+ return false;
+ }
+ return (img->mPlane[1].mColInc == 2
+ && img->mPlane[2].mColInc == 2
+ && (img->mPlane[2].mOffset - img->mPlane[1].mOffset == 1));
+}
+
+bool IsI420(const MediaImage2 *img) {
+ if (!IsYUV420(img)) {
+ return false;
+ }
+ return (img->mPlane[1].mColInc == 1
+ && img->mPlane[2].mColInc == 1
+ && img->mPlane[2].mOffset > img->mPlane[1].mOffset);
+}
+
MediaImage2 CreateYUV420PlanarMediaImage2(
uint32_t width, uint32_t height, uint32_t stride, uint32_t vstride) {
return MediaImage2 {
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.h b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
index eaf6776..afadf00 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.h
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
@@ -91,6 +91,31 @@
bool IsYUV420(const C2GraphicView &view);
/**
+ * Returns true iff a view has a NV12 layout.
+ */
+bool IsNV12(const C2GraphicView &view);
+
+/**
+ * Returns true iff a view has a I420 layout.
+ */
+bool IsI420(const C2GraphicView &view);
+
+/**
+ * Returns true iff a MediaImage2 has a YUV 420 888 layout.
+ */
+bool IsYUV420(const MediaImage2 *img);
+
+/**
+ * Returns true iff a MediaImage2 has a NV12 layout.
+ */
+bool IsNV12(const MediaImage2 *img);
+
+/**
+ * Returns true iff a MediaImage2 has a I420 layout.
+ */
+bool IsI420(const MediaImage2 *img);
+
+/**
* A raw memory block to use for internal buffers.
*
* TODO: replace this with C2LinearBlocks from a private C2BlockPool