codec2: add P010 support
Bug: 163020028
Test: atest CtsMediaTestCases -- --module-arg CtsMediaTestCases:size:small
Test: atest ccodec_unit_test:RawGraphicOutputBuffersTest
Change-Id: Ibd0da668c510665a8838f0d7e6abd264814d6526
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 5072323..fa0d4ac 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -353,6 +353,66 @@
mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
break;
+ case COLOR_FormatYUVP010:
+ if (!copy) {
+ // try to map directly. check if the planes are near one another
+ const uint8_t *minPtr = mView.data()[0];
+ const uint8_t *maxPtr = mView.data()[0];
+ int32_t planeSize = 0;
+ for (uint32_t i = 0; i < layout.numPlanes; ++i) {
+ const C2PlaneInfo &plane = layout.planes[i];
+ ssize_t minOffset = plane.minOffset(
+ mWidth / plane.colSampling, mHeight / plane.rowSampling);
+ ssize_t maxOffset = plane.maxOffset(
+ mWidth / plane.colSampling, mHeight / plane.rowSampling);
+ if (minPtr > mView.data()[i] + minOffset) {
+ minPtr = mView.data()[i] + minOffset;
+ }
+ if (maxPtr < mView.data()[i] + maxOffset) {
+ maxPtr = mView.data()[i] + maxOffset;
+ }
+ planeSize += std::abs(plane.rowInc) * align(mHeight, 64)
+ / plane.rowSampling / plane.colSampling
+ * divUp(mAllocatedDepth, 8u);
+ }
+
+ if ((maxPtr - minPtr + 1) <= planeSize) {
+ // FIXME: this is risky as reading/writing data out of bound results
+ // in an undefined behavior, but gralloc does assume a
+ // contiguous mapping
+ for (uint32_t i = 0; i < layout.numPlanes; ++i) {
+ const C2PlaneInfo &plane = layout.planes[i];
+ mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
+ mediaImage->mPlane[i].mColInc = plane.colInc;
+ mediaImage->mPlane[i].mRowInc = plane.rowInc;
+ mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
+ mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
+ }
+ mWrapped = new ABuffer(
+ const_cast<uint8_t *>(minPtr),
+ maxPtr - minPtr + divUp(mAllocatedDepth, 8u));
+ break;
+ }
+ }
+ mediaImage->mPlane[mediaImage->Y].mOffset = 0;
+ mediaImage->mPlane[mediaImage->Y].mColInc = 2;
+ mediaImage->mPlane[mediaImage->Y].mRowInc = stride * 2;
+ mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
+ mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
+
+ mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride * 2;
+ mediaImage->mPlane[mediaImage->U].mColInc = 4;
+ mediaImage->mPlane[mediaImage->U].mRowInc = stride * 2;
+ mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
+ mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
+
+ mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 2 + 2;
+ mediaImage->mPlane[mediaImage->V].mColInc = 4;
+ mediaImage->mPlane[mediaImage->V].mRowInc = stride * 2;
+ mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
+ mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
+ break;
+
default:
ALOGD("Converter: incompactible color format (%d) for YUV layout", mColorFormat);
mInitCheck = BAD_VALUE;
diff --git a/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp b/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp
index ad8f6e5..66b7622 100644
--- a/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp
+++ b/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp
@@ -18,11 +18,12 @@
#include <gtest/gtest.h>
-#include <media/stagefright/foundation/AString.h>
+#include <codec2/hidl/client.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <C2BlockInternal.h>
#include <C2PlatformSupport.h>
+#include <Codec2Mapper.h>
namespace android {
@@ -105,6 +106,318 @@
}
}
+TEST(RawGraphicOutputBuffersTest, FlexYuvColorFormat) {
+ constexpr int32_t kWidth = 320;
+ constexpr int32_t kHeight = 240;
+
+ std::vector<uint32_t> flexPixelFormats({HAL_PIXEL_FORMAT_YCbCr_420_888});
+ std::shared_ptr<Codec2Client> client = Codec2Client::CreateFromService("default");
+ if (client) {
+ // Query vendor format for Flexible YUV
+ std::vector<std::unique_ptr<C2Param>> heapParams;
+ C2StoreFlexiblePixelFormatDescriptorsInfo *pixelFormatInfo = nullptr;
+ if (client->query(
+ {},
+ {C2StoreFlexiblePixelFormatDescriptorsInfo::PARAM_TYPE},
+ C2_MAY_BLOCK,
+ &heapParams) == C2_OK
+ && heapParams.size() == 1u) {
+ pixelFormatInfo = C2StoreFlexiblePixelFormatDescriptorsInfo::From(
+ heapParams[0].get());
+ } else {
+ pixelFormatInfo = nullptr;
+ }
+ if (pixelFormatInfo && *pixelFormatInfo) {
+ for (size_t i = 0; i < pixelFormatInfo->flexCount(); ++i) {
+ const C2FlexiblePixelFormatDescriptorStruct &desc =
+ pixelFormatInfo->m.values[i];
+ if (desc.bitDepth != 8
+ || desc.subsampling != C2Color::YUV_420
+ // TODO(b/180076105): some devices report wrong layouts
+ // || desc.layout == C2Color::INTERLEAVED_PACKED
+ // || desc.layout == C2Color::INTERLEAVED_ALIGNED
+ || desc.layout == C2Color::UNKNOWN_LAYOUT) {
+ continue;
+ }
+ flexPixelFormats.push_back(desc.pixelFormat);
+ }
+ }
+ }
+
+ for (uint32_t pixelFormat : flexPixelFormats) {
+ std::shared_ptr<RawGraphicOutputBuffers> buffers =
+ std::make_shared<RawGraphicOutputBuffers>(
+ AStringPrintf("test pixel format 0x%x", pixelFormat).c_str());
+
+ sp<AMessage> format{new AMessage};
+ format->setInt32(KEY_WIDTH, kWidth);
+ format->setInt32(KEY_HEIGHT, kHeight);
+ format->setInt32(KEY_COLOR_FORMAT, COLOR_FormatYUV420Flexible);
+ int32_t fwkPixelFormat = 0;
+ if (C2Mapper::mapPixelFormatCodecToFramework(pixelFormat, &fwkPixelFormat)) {
+ format->setInt32("android._color-format", fwkPixelFormat);
+ }
+ buffers->setFormat(format);
+
+ std::shared_ptr<C2BlockPool> pool;
+ ASSERT_EQ(OK, GetCodec2BlockPool(C2BlockPool::BASIC_GRAPHIC, nullptr, &pool));
+
+ std::shared_ptr<C2GraphicBlock> block;
+ ASSERT_EQ(OK, pool->fetchGraphicBlock(
+ kWidth, kHeight, pixelFormat,
+ C2MemoryUsage{C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block));
+
+ {
+ C2GraphicView view = block->map().get();
+ C2PlanarLayout layout = view.layout();
+
+ // Verify the block is in YUV420 format
+ ASSERT_EQ(C2PlanarLayout::TYPE_YUV, layout.type);
+ ASSERT_EQ(3u, layout.numPlanes);
+ const C2PlaneInfo& yPlane = layout.planes[C2PlanarLayout::PLANE_Y];
+ const C2PlaneInfo& uPlane = layout.planes[C2PlanarLayout::PLANE_U];
+ const C2PlaneInfo& vPlane = layout.planes[C2PlanarLayout::PLANE_V];
+
+ // Y plane
+ ASSERT_EQ(1u, yPlane.colSampling);
+ ASSERT_EQ(1u, yPlane.rowSampling);
+ ASSERT_EQ(8u, yPlane.allocatedDepth);
+ ASSERT_EQ(8u, yPlane.bitDepth);
+ ASSERT_EQ(0u, yPlane.rightShift);
+
+ // U plane
+ ASSERT_EQ(2u, uPlane.colSampling);
+ ASSERT_EQ(2u, uPlane.rowSampling);
+ ASSERT_EQ(8u, uPlane.allocatedDepth);
+ ASSERT_EQ(8u, uPlane.bitDepth);
+ ASSERT_EQ(0u, uPlane.rightShift);
+
+ // V plane
+ ASSERT_EQ(2u, vPlane.colSampling);
+ ASSERT_EQ(2u, vPlane.rowSampling);
+ ASSERT_EQ(8u, vPlane.allocatedDepth);
+ ASSERT_EQ(8u, vPlane.bitDepth);
+ ASSERT_EQ(0u, vPlane.rightShift);
+
+ uint8_t *yRowPtr = view.data()[C2PlanarLayout::PLANE_Y];
+ uint8_t *uRowPtr = view.data()[C2PlanarLayout::PLANE_U];
+ uint8_t *vRowPtr = view.data()[C2PlanarLayout::PLANE_V];
+ for (int32_t row = 0; row < kHeight; ++row) {
+ uint8_t *yPtr = yRowPtr;
+ uint8_t *uPtr = uRowPtr;
+ uint8_t *vPtr = vRowPtr;
+ for (int32_t col = 0; col < kWidth; ++col) {
+ *yPtr = ((row + col) & 0xFF);
+ yPtr += yPlane.colInc;
+
+ if (row < kHeight / 2 && col < kWidth / 2) {
+ *uPtr = ((row + col + 1) & 0xFF);
+ *vPtr = ((row + col + 2) & 0xFF);
+ uPtr += uPlane.colInc;
+ vPtr += vPlane.colInc;
+ }
+ }
+ yRowPtr += yPlane.rowInc;
+ if (row < kHeight / 2) {
+ uRowPtr += uPlane.rowInc;
+ vRowPtr += vPlane.rowInc;
+ }
+ }
+ }
+
+ std::shared_ptr<C2Buffer> c2Buffer = C2Buffer::CreateGraphicBuffer(block->share(
+ block->crop(), C2Fence{}));
+ size_t index;
+ sp<MediaCodecBuffer> clientBuffer;
+ ASSERT_EQ(OK, buffers->registerBuffer(c2Buffer, &index, &clientBuffer));
+ ASSERT_NE(nullptr, clientBuffer);
+ sp<ABuffer> imageData;
+ ASSERT_TRUE(clientBuffer->format()->findBuffer("image-data", &imageData));
+ MediaImage2 *img = (MediaImage2 *)imageData->data();
+ ASSERT_EQ(MediaImage2::MEDIA_IMAGE_TYPE_YUV, img->mType);
+ ASSERT_EQ(3u, img->mNumPlanes);
+ ASSERT_EQ(kWidth, img->mWidth);
+ ASSERT_EQ(kHeight, img->mHeight);
+ ASSERT_EQ(8u, img->mBitDepth);
+ ASSERT_EQ(8u, img->mBitDepthAllocated);
+ const MediaImage2::PlaneInfo &yPlane = img->mPlane[MediaImage2::Y];
+ const MediaImage2::PlaneInfo &uPlane = img->mPlane[MediaImage2::U];
+ const MediaImage2::PlaneInfo &vPlane = img->mPlane[MediaImage2::V];
+ ASSERT_EQ(1u, yPlane.mHorizSubsampling);
+ ASSERT_EQ(1u, yPlane.mVertSubsampling);
+ ASSERT_EQ(2u, uPlane.mHorizSubsampling);
+ ASSERT_EQ(2u, uPlane.mVertSubsampling);
+ ASSERT_EQ(2u, vPlane.mHorizSubsampling);
+ ASSERT_EQ(2u, vPlane.mVertSubsampling);
+
+ uint8_t *yRowPtr = clientBuffer->data() + yPlane.mOffset;
+ uint8_t *uRowPtr = clientBuffer->data() + uPlane.mOffset;
+ uint8_t *vRowPtr = clientBuffer->data() + vPlane.mOffset;
+ for (int32_t row = 0; row < kHeight; ++row) {
+ uint8_t *yPtr = yRowPtr;
+ uint8_t *uPtr = uRowPtr;
+ uint8_t *vPtr = vRowPtr;
+ for (int32_t col = 0; col < kWidth; ++col) {
+ ASSERT_EQ((row + col) & 0xFF, *yPtr);
+ yPtr += yPlane.mColInc;
+ if (row < kHeight / 2 && col < kWidth / 2) {
+ ASSERT_EQ((row + col + 1) & 0xFF, *uPtr);
+ ASSERT_EQ((row + col + 2) & 0xFF, *vPtr);
+ uPtr += uPlane.mColInc;
+ vPtr += vPlane.mColInc;
+ }
+ }
+ yRowPtr += yPlane.mRowInc;
+ if (row < kHeight / 2) {
+ uRowPtr += uPlane.mRowInc;
+ vRowPtr += vPlane.mRowInc;
+ }
+ }
+ }
+}
+
+TEST(RawGraphicOutputBuffersTest, P010ColorFormat) {
+ constexpr int32_t kWidth = 320;
+ constexpr int32_t kHeight = 240;
+
+ std::shared_ptr<RawGraphicOutputBuffers> buffers =
+ std::make_shared<RawGraphicOutputBuffers>("test P010");
+
+ sp<AMessage> format{new AMessage};
+ format->setInt32(KEY_WIDTH, kWidth);
+ format->setInt32(KEY_HEIGHT, kHeight);
+ format->setInt32(KEY_COLOR_FORMAT, COLOR_FormatYUVP010);
+ int32_t fwkPixelFormat = 0;
+ if (C2Mapper::mapPixelFormatCodecToFramework(HAL_PIXEL_FORMAT_YCBCR_P010, &fwkPixelFormat)) {
+ format->setInt32("android._color-format", fwkPixelFormat);
+ }
+ buffers->setFormat(format);
+
+ std::shared_ptr<C2BlockPool> pool;
+ ASSERT_EQ(OK, GetCodec2BlockPool(C2BlockPool::BASIC_GRAPHIC, nullptr, &pool));
+
+ std::shared_ptr<C2GraphicBlock> block;
+ c2_status_t err = pool->fetchGraphicBlock(
+ kWidth, kHeight, HAL_PIXEL_FORMAT_YCBCR_P010,
+ C2MemoryUsage{C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
+ if (err != C2_OK) {
+ GTEST_SKIP();
+ }
+
+ {
+ C2GraphicView view = block->map().get();
+ C2PlanarLayout layout = view.layout();
+
+ // Verify the block is in YUV420 format
+ ASSERT_EQ(C2PlanarLayout::TYPE_YUV, layout.type);
+ ASSERT_EQ(3u, layout.numPlanes);
+ const C2PlaneInfo& yPlane = layout.planes[C2PlanarLayout::PLANE_Y];
+ const C2PlaneInfo& uPlane = layout.planes[C2PlanarLayout::PLANE_U];
+ const C2PlaneInfo& vPlane = layout.planes[C2PlanarLayout::PLANE_V];
+
+ // Y plane
+ ASSERT_EQ(1u, yPlane.colSampling);
+ ASSERT_EQ(1u, yPlane.rowSampling);
+ ASSERT_EQ(16u, yPlane.allocatedDepth);
+ ASSERT_EQ(10u, yPlane.bitDepth);
+ ASSERT_EQ(6u, yPlane.rightShift);
+
+ // U plane
+ ASSERT_EQ(2u, uPlane.colSampling);
+ ASSERT_EQ(2u, uPlane.rowSampling);
+ ASSERT_EQ(16u, uPlane.allocatedDepth);
+ ASSERT_EQ(10u, uPlane.bitDepth);
+ ASSERT_EQ(6u, uPlane.rightShift);
+
+ // V plane
+ ASSERT_EQ(2u, vPlane.colSampling);
+ ASSERT_EQ(2u, vPlane.rowSampling);
+ ASSERT_EQ(16u, vPlane.allocatedDepth);
+ ASSERT_EQ(10u, vPlane.bitDepth);
+ ASSERT_EQ(6u, vPlane.rightShift);
+
+ uint8_t *yRowPtr = view.data()[C2PlanarLayout::PLANE_Y];
+ uint8_t *uRowPtr = view.data()[C2PlanarLayout::PLANE_U];
+ uint8_t *vRowPtr = view.data()[C2PlanarLayout::PLANE_V];
+ for (int32_t row = 0; row < kHeight; ++row) {
+ uint8_t *yPtr = yRowPtr;
+ uint8_t *uPtr = uRowPtr;
+ uint8_t *vPtr = vRowPtr;
+ for (int32_t col = 0; col < kWidth; ++col) {
+ yPtr[0] = ((row + col) & 0x3) << 6;
+ yPtr[1] = ((row + col) & 0x3FC) >> 2;
+ yPtr += yPlane.colInc;
+
+ if (row < kHeight / 2 && col < kWidth / 2) {
+ uPtr[0] = ((row + col + 1) & 0x3) << 6;
+ uPtr[1] = ((row + col + 1) & 0x3FC) >> 2;
+ vPtr[0] = ((row + col + 2) & 0x3) << 6;
+ vPtr[1] = ((row + col + 2) & 0x3FC) >> 2;
+ uPtr += uPlane.colInc;
+ vPtr += vPlane.colInc;
+ }
+ }
+ yRowPtr += yPlane.rowInc;
+ if (row < kHeight / 2) {
+ uRowPtr += uPlane.rowInc;
+ vRowPtr += vPlane.rowInc;
+ }
+ }
+ }
+
+ std::shared_ptr<C2Buffer> c2Buffer = C2Buffer::CreateGraphicBuffer(block->share(
+ block->crop(), C2Fence{}));
+ size_t index;
+ sp<MediaCodecBuffer> clientBuffer;
+ ASSERT_EQ(OK, buffers->registerBuffer(c2Buffer, &index, &clientBuffer));
+ ASSERT_NE(nullptr, clientBuffer);
+ sp<ABuffer> imageData;
+ ASSERT_TRUE(clientBuffer->format()->findBuffer("image-data", &imageData));
+ MediaImage2 *img = (MediaImage2 *)imageData->data();
+ ASSERT_EQ(MediaImage2::MEDIA_IMAGE_TYPE_YUV, img->mType);
+ ASSERT_EQ(3u, img->mNumPlanes);
+ ASSERT_EQ(kWidth, img->mWidth);
+ ASSERT_EQ(kHeight, img->mHeight);
+ ASSERT_EQ(10u, img->mBitDepth);
+ ASSERT_EQ(16u, img->mBitDepthAllocated);
+ const MediaImage2::PlaneInfo &yPlane = img->mPlane[MediaImage2::Y];
+ const MediaImage2::PlaneInfo &uPlane = img->mPlane[MediaImage2::U];
+ const MediaImage2::PlaneInfo &vPlane = img->mPlane[MediaImage2::V];
+ ASSERT_EQ(1u, yPlane.mHorizSubsampling);
+ ASSERT_EQ(1u, yPlane.mVertSubsampling);
+ ASSERT_EQ(2u, uPlane.mHorizSubsampling);
+ ASSERT_EQ(2u, uPlane.mVertSubsampling);
+ ASSERT_EQ(2u, vPlane.mHorizSubsampling);
+ ASSERT_EQ(2u, vPlane.mVertSubsampling);
+
+ uint8_t *yRowPtr = clientBuffer->data() + yPlane.mOffset;
+ uint8_t *uRowPtr = clientBuffer->data() + uPlane.mOffset;
+ uint8_t *vRowPtr = clientBuffer->data() + vPlane.mOffset;
+ for (int32_t row = 0; row < kHeight; ++row) {
+ uint8_t *yPtr = yRowPtr;
+ uint8_t *uPtr = uRowPtr;
+ uint8_t *vPtr = vRowPtr;
+ for (int32_t col = 0; col < kWidth; ++col) {
+ ASSERT_EQ(((row + col) & 0x3) << 6, yPtr[0]);
+ ASSERT_EQ(((row + col) & 0x3FC) >> 2, yPtr[1]);
+ yPtr += yPlane.mColInc;
+ if (row < kHeight / 2 && col < kWidth / 2) {
+ ASSERT_EQ(((row + col + 1) & 0x3) << 6, uPtr[0]);
+ ASSERT_EQ(((row + col + 1) & 0x3FC) >> 2, uPtr[1]);
+ ASSERT_EQ(((row + col + 2) & 0x3) << 6, vPtr[0]);
+ ASSERT_EQ(((row + col + 2) & 0x3FC) >> 2, vPtr[1]);
+ uPtr += uPlane.mColInc;
+ vPtr += vPlane.mColInc;
+ }
+ }
+ yRowPtr += yPlane.mRowInc;
+ if (row < kHeight / 2) {
+ uRowPtr += uPlane.mRowInc;
+ vRowPtr += vPlane.mRowInc;
+ }
+ }
+}
+
class TestGraphicAllocation : public C2GraphicAllocation {
public:
TestGraphicAllocation(
@@ -407,7 +720,6 @@
}
}
}
-
size_t yPlaneSize = stride * kHeight;
size_t uvPlaneSize = stride * kHeight / 4;
size_t capacity = yPlaneSize + uvPlaneSize * 2;
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index 903db6c..dcded8f 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -967,8 +967,9 @@
*c2Value = HAL_PIXEL_FORMAT_YV12;
return true;
default:
- // TODO: support some sort of passthrough
- return false;
+ // Passthrough
+ *c2Value = uint32_t(frameworkValue);
+ return true;
}
}
@@ -984,6 +985,8 @@
*frameworkValue = COLOR_FormatYUV420Flexible;
return true;
default:
- return false;
+ // Passthrough
+ *frameworkValue = int32_t(c2Value);
+ return true;
}
}
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 59471a2..8e59df1 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -532,11 +532,15 @@
break;
}
+ case static_cast<uint32_t>(PixelFormat4::YCBCR_422_SP):
+ // fall-through
+ case static_cast<uint32_t>(PixelFormat4::YCRCB_420_SP):
+ // fall-through
+ case static_cast<uint32_t>(PixelFormat4::YCBCR_422_I):
+ // fall-through
case static_cast<uint32_t>(PixelFormat4::YCBCR_420_888):
// fall-through
- case static_cast<uint32_t>(PixelFormat4::YV12):
- // fall-through
- default: {
+ case static_cast<uint32_t>(PixelFormat4::YV12): {
android_ycbcr ycbcrLayout;
status_t err = GraphicBufferMapper::get().lockYCbCr(
@@ -604,6 +608,158 @@
}
break;
}
+
+ case static_cast<uint32_t>(PixelFormat4::YCBCR_P010): {
+ void *pointer = nullptr;
+ status_t err = GraphicBufferMapper::get().lock(
+ const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
+ if (err) {
+ ALOGE("failed transaction: lock(YCBCR_P010)");
+ return C2_CORRUPTED;
+ }
+ addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
+ addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer + mStride * 2 * rect.height();
+ addr[C2PlanarLayout::PLANE_V] = addr[C2PlanarLayout::PLANE_U] + 2;
+ layout->type = C2PlanarLayout::TYPE_YUV;
+ layout->numPlanes = 3;
+ layout->rootPlanes = 2;
+ layout->planes[C2PlanarLayout::PLANE_Y] = {
+ C2PlaneInfo::CHANNEL_Y, // channel
+ 2, // colInc
+ static_cast<int32_t>(2 * mStride), // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 16, // allocatedDepth
+ 10, // bitDepth
+ 6, // rightShift
+ C2PlaneInfo::LITTLE_END, // endianness
+ C2PlanarLayout::PLANE_Y, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_U] = {
+ C2PlaneInfo::CHANNEL_CB, // channel
+ 4, // colInc
+ static_cast<int32_t>(2 * mStride), // rowInc
+ 2, // mColSampling
+ 2, // mRowSampling
+ 16, // allocatedDepth
+ 10, // bitDepth
+ 6, // rightShift
+ C2PlaneInfo::LITTLE_END, // endianness
+ C2PlanarLayout::PLANE_U, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_V] = {
+ C2PlaneInfo::CHANNEL_CR, // channel
+ 4, // colInc
+ static_cast<int32_t>(2 * mStride), // rowInc
+ 2, // mColSampling
+ 2, // mRowSampling
+ 16, // allocatedDepth
+ 10, // bitDepth
+ 6, // rightShift
+ C2PlaneInfo::LITTLE_END, // endianness
+ C2PlanarLayout::PLANE_U, // rootIx
+ 2, // offset
+ };
+ break;
+ }
+
+ default: {
+ // We don't know what it is, but let's try to lock it.
+ android_ycbcr ycbcrLayout;
+
+ status_t err = GraphicBufferMapper::get().lockYCbCr(
+ const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &ycbcrLayout);
+ if (err == OK) {
+ addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
+ addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
+ addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
+ layout->type = C2PlanarLayout::TYPE_YUV;
+ layout->numPlanes = 3;
+ layout->rootPlanes = 3;
+ layout->planes[C2PlanarLayout::PLANE_Y] = {
+ C2PlaneInfo::CHANNEL_Y, // channel
+ 1, // colInc
+ (int32_t)ycbcrLayout.ystride, // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_Y, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_U] = {
+ C2PlaneInfo::CHANNEL_CB, // channel
+ (int32_t)ycbcrLayout.chroma_step, // colInc
+ (int32_t)ycbcrLayout.cstride, // rowInc
+ 2, // mColSampling
+ 2, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_U, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_V] = {
+ C2PlaneInfo::CHANNEL_CR, // channel
+ (int32_t)ycbcrLayout.chroma_step, // colInc
+ (int32_t)ycbcrLayout.cstride, // rowInc
+ 2, // mColSampling
+ 2, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_V, // rootIx
+ 0, // offset
+ };
+ // handle interleaved formats
+ intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
+ if (uvOffset > 0 && uvOffset < (intptr_t)ycbcrLayout.chroma_step) {
+ layout->rootPlanes = 2;
+ layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
+ layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
+ } else if (uvOffset < 0 && uvOffset > -(intptr_t)ycbcrLayout.chroma_step) {
+ layout->rootPlanes = 2;
+ layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
+ layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
+ }
+ break;
+ }
+
+ // We really don't know what this is; lock the buffer and pass it through ---
+ // the client may know how to interpret it.
+ void *pointer = nullptr;
+ err = GraphicBufferMapper::get().lock(
+ const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
+ if (err) {
+ ALOGE("failed transaction: lock(??? %x)", mFormat);
+ return C2_CORRUPTED;
+ }
+ addr[0] = (uint8_t *)pointer;
+ layout->type = C2PlanarLayout::TYPE_UNKNOWN;
+ layout->numPlanes = 1;
+ layout->rootPlanes = 1;
+ layout->planes[0] = {
+ // TODO: CHANNEL_UNKNOWN?
+ C2PlaneInfo::channel_t(0xFF), // channel
+ 1, // colInc
+ int32_t(mStride), // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ 0, // rootIx
+ 0, // offset
+ };
+ break;
+ }
}
mLocked = true;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 178d334..6cf1ba0 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -619,6 +619,7 @@
constexpr int32_t COLOR_FormatYUV422SemiPlanar = 24;
constexpr int32_t COLOR_FormatYUV444Flexible = 0x7F444888;
constexpr int32_t COLOR_FormatYUV444Interleaved = 29;
+constexpr int32_t COLOR_FormatYUVP010 = 54;
constexpr int32_t COLOR_QCOM_FormatYUV420SemiPlanar = 0x7fa30c00;
constexpr int32_t COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;