Loading media/java/android/media/Image.java +9 −0 Original line number Diff line number Diff line Loading @@ -180,6 +180,15 @@ public abstract class Image implements AutoCloseable { * a semi-planar format, the Cb plane can also be treated as an interleaved Cb/Cr plane. * </td> * </tr> * <tr> * <td>{@link android.graphics.ImageFormat#YCBCR_P210 YCBCR_P210}</td> * <td>3</td> * <td>P210 is a 4:2:2 YCbCr semiplanar format comprised of a WxH Y plane * followed by a WxH Cb and Cr planes. Each sample is represented by a 16-bit * little-endian value, with the lower 6 bits set to zero. Since this is guaranteed to be * a semi-planar format, the Cb plane can also be treated as an interleaved Cb/Cr plane. * </td> * </tr> * </table> * * @see android.graphics.ImageFormat Loading media/java/android/media/ImageUtils.java +9 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ class ImageUtils { case ImageFormat.YUV_420_888: case ImageFormat.NV21: case ImageFormat.YCBCR_P010: case ImageFormat.YCBCR_P210: return 3; case ImageFormat.NV16: return 2; Loading Loading @@ -88,6 +89,7 @@ class ImageUtils { switch(hardwareBufferFormat) { case HardwareBuffer.YCBCR_420_888: case HardwareBuffer.YCBCR_P010: case HardwareBuffer.YCBCR_P210: return 3; case HardwareBuffer.RGBA_8888: case HardwareBuffer.RGBX_8888: Loading Loading @@ -269,6 +271,7 @@ class ImageUtils { case PixelFormat.RGBA_8888: case PixelFormat.RGBX_8888: case PixelFormat.RGBA_1010102: case ImageFormat.YCBCR_P210: estimatedBytePerPixel = 4.0; break; default: Loading Loading @@ -318,6 +321,12 @@ class ImageUtils { return new Size(image.getWidth(), image.getHeight()); case ImageFormat.PRIVATE: return new Size(0, 0); case ImageFormat.YCBCR_P210: if (planeIdx == 0) { return new Size(image.getWidth(), image.getHeight()); } else { return new Size(image.getWidth() / 2, image.getHeight()); } default: if (Log.isLoggable(IMAGEUTILS_LOG_TAG, Log.VERBOSE)) { Log.v(IMAGEUTILS_LOG_TAG, "getEffectivePlaneSizeForImage() uses" Loading media/java/android/media/MediaCodec.java +6 −3 Original line number Diff line number Diff line Loading @@ -6158,11 +6158,14 @@ final public class MediaCodec { buffer.limit(buffer.position() + Utils.divUp(bitDepth, 8) + (mHeight / vert - 1) * rowInc + (mWidth / horiz - 1) * colInc); mPlanes[ix] = new MediaPlane(buffer.slice(), rowInc, colInc); if ((mFormat == ImageFormat.YUV_420_888 || mFormat == ImageFormat.YCBCR_P010) if ((mFormat == ImageFormat.YUV_420_888 || mFormat == ImageFormat.YCBCR_P010 || mFormat == ImageFormat.YCBCR_P210) && ix == 1) { cbPlaneOffset = planeOffset; } else if ((mFormat == ImageFormat.YUV_420_888 || mFormat == ImageFormat.YCBCR_P010) && ix == 2) { || mFormat == ImageFormat.YCBCR_P010 || mFormat == ImageFormat.YCBCR_P210) && ix == 2) { crPlaneOffset = planeOffset; } } Loading @@ -6172,7 +6175,7 @@ final public class MediaCodec { } // Validate chroma semiplanerness. if (mFormat == ImageFormat.YCBCR_P010) { if (mFormat == ImageFormat.YCBCR_P010 || mFormat == ImageFormat.YCBCR_P210) { if (crPlaneOffset != cbPlaneOffset + planeOffsetInc) { throw new UnsupportedOperationException("Invalid plane offsets" + " cbPlaneOffset: " + cbPlaneOffset + " crPlaneOffset: " + crPlaneOffset); Loading media/jni/android_media_Utils.cpp +133 −6 Original line number Diff line number Diff line Loading @@ -17,13 +17,14 @@ // #define LOG_NDEBUG 0 #define LOG_TAG "AndroidMediaUtils" #include "android_media_Utils.h" #include <aidl/android/hardware/graphics/common/PixelFormat.h> #include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h> #include <ui/GraphicBufferMapper.h> #include <ui/GraphicTypes.h> #include <utils/Log.h> #include "android_media_Utils.h" #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) ) // Must be in sync with the value in HeicCompositeStream.cpp Loading @@ -33,6 +34,8 @@ namespace android { // -----------Utility functions used by ImageReader/Writer JNI----------------- using AidlPixelFormat = aidl::android::hardware::graphics::common::PixelFormat; enum { IMAGE_MAX_NUM_PLANES = 3, }; Loading Loading @@ -74,6 +77,7 @@ bool isPossiblyYUV(PixelFormat format) { case HAL_PIXEL_FORMAT_BLOB: case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: case HAL_PIXEL_FORMAT_YCBCR_P010: case static_cast<int>(AidlPixelFormat::YCBCR_P210): return false; case HAL_PIXEL_FORMAT_YV12: Loading Loading @@ -105,6 +109,7 @@ bool isPossibly10BitYUV(PixelFormat format) { return false; case HAL_PIXEL_FORMAT_YCBCR_P010: case static_cast<int>(AidlPixelFormat::YCBCR_P210): default: return true; } Loading Loading @@ -340,6 +345,47 @@ status_t getLockedImageInfo(LockedImage* buffer, int idx, cb = buffer->data + ySize; cr = cb + 2; pData = (idx == 0) ? buffer->data : (idx == 1) ? cb : cr; dataSize = (idx == 0) ? ySize : cSize; rStride = buffer->stride * 2; break; case static_cast<int>(AidlPixelFormat::YCBCR_P210): if (buffer->height % 2 != 0) { ALOGE("YCBCR_P210: height (%d) should be a multiple of 2", buffer->height); return BAD_VALUE; } if (buffer->width <= 0) { ALOGE("YCBCR_P210: width (%d) should be a > 0", buffer->width); return BAD_VALUE; } if (buffer->height <= 0) { ALOGE("YCBCR_210: height (%d) should be a > 0", buffer->height); return BAD_VALUE; } if (buffer->dataCb && buffer->dataCr) { pData = (idx == 0) ? buffer->data : (idx == 1) ? buffer->dataCb : buffer->dataCr; // only map until last pixel if (idx == 0) { pStride = 2; rStride = buffer->stride; dataSize = buffer->stride * (buffer->height - 1) + buffer->width * 2; } else { pStride = buffer->chromaStep; rStride = buffer->chromaStride; dataSize = buffer->chromaStride * (buffer->height - 1) + buffer->chromaStep * (buffer->width / 2); } break; } ySize = (buffer->stride * 2) * buffer->height; cSize = ySize; pStride = (idx == 0) ? 2 : 4; cb = buffer->data + ySize; cr = cb + 2; pData = (idx == 0) ? buffer->data : (idx == 1) ? cb : cr; dataSize = (idx == 0) ? ySize : cSize; rStride = buffer->stride * 2; Loading Loading @@ -544,6 +590,80 @@ static status_t extractP010Gralloc4PlaneLayout( return OK; } static status_t extractP210Gralloc4PlaneLayout(sp<GraphicBuffer> buffer, void *pData, int format, LockedImage *outputImage) { using aidl::android::hardware::graphics::common::PlaneLayoutComponent; using aidl::android::hardware::graphics::common::PlaneLayoutComponentType; GraphicBufferMapper &mapper = GraphicBufferMapper::get(); std::vector<ui::PlaneLayout> planeLayouts; status_t res = mapper.getPlaneLayouts(buffer->handle, &planeLayouts); if (res != OK) { return res; } constexpr int64_t Y_PLANE_COMPONENTS = int64_t(PlaneLayoutComponentType::Y); constexpr int64_t CBCR_PLANE_COMPONENTS = int64_t(PlaneLayoutComponentType::CB) | int64_t(PlaneLayoutComponentType::CR); uint8_t *dataY = nullptr; uint8_t *dataCb = nullptr; uint8_t *dataCr = nullptr; uint32_t strideY = 0; uint32_t strideCbCr = 0; for (const ui::PlaneLayout &layout : planeLayouts) { ALOGV("gralloc4 plane: %s", layout.toString().c_str()); int64_t components = 0; for (const PlaneLayoutComponent &component : layout.components) { if (component.sizeInBits != 10) { return BAD_VALUE; } components |= component.type.value; } if (components == Y_PLANE_COMPONENTS) { if (layout.sampleIncrementInBits != 16) { return BAD_VALUE; } if (layout.components[0].offsetInBits != 6) { return BAD_VALUE; } dataY = (uint8_t *)pData + layout.offsetInBytes; strideY = layout.strideInBytes; } else if (components == CBCR_PLANE_COMPONENTS) { if (layout.sampleIncrementInBits != 32) { return BAD_VALUE; } for (const PlaneLayoutComponent &component : layout.components) { if (component.type.value == int64_t(PlaneLayoutComponentType::CB) && component.offsetInBits != 6) { return BAD_VALUE; } if (component.type.value == int64_t(PlaneLayoutComponentType::CR) && component.offsetInBits != 22) { return BAD_VALUE; } } dataCb = (uint8_t *)pData + layout.offsetInBytes; dataCr = (uint8_t *)pData + layout.offsetInBytes + 2; strideCbCr = layout.strideInBytes; } else { return BAD_VALUE; } } outputImage->data = dataY; outputImage->width = buffer->getWidth(); outputImage->height = buffer->getHeight(); outputImage->format = format; outputImage->flexFormat = static_cast<int>(AidlPixelFormat::YCBCR_P210); outputImage->stride = strideY; outputImage->dataCb = dataCb; outputImage->dataCr = dataCr; outputImage->chromaStride = strideCbCr; outputImage->chromaStep = 4; return OK; } status_t lockImageFromBuffer(sp<GraphicBuffer> buffer, uint32_t inUsage, const Rect& rect, int fenceFd, LockedImage* outputImage) { ALOGV("%s: Try to lock the GraphicBuffer", __FUNCTION__); Loading Loading @@ -581,10 +701,17 @@ status_t lockImageFromBuffer(sp<GraphicBuffer> buffer, uint32_t inUsage, ALOGE("Lock buffer failed!"); return res; } if (isPossibly10BitYUV(format) && OK == extractP010Gralloc4PlaneLayout(buffer, pData, format, outputImage)) { if (isPossibly10BitYUV(format)) { if (format == HAL_PIXEL_FORMAT_YCBCR_P010 && OK == extractP010Gralloc4PlaneLayout(buffer, pData, format, outputImage)) { ALOGV("%s: Successfully locked the P010 image", __FUNCTION__); return OK; } else if ((format == static_cast<int>(AidlPixelFormat::YCBCR_P210)) && OK == extractP210Gralloc4PlaneLayout(buffer, pData, format, outputImage)) { ALOGV("%s: Successfully locked the P210 image", __FUNCTION__); return OK; } } } Loading Loading
media/java/android/media/Image.java +9 −0 Original line number Diff line number Diff line Loading @@ -180,6 +180,15 @@ public abstract class Image implements AutoCloseable { * a semi-planar format, the Cb plane can also be treated as an interleaved Cb/Cr plane. * </td> * </tr> * <tr> * <td>{@link android.graphics.ImageFormat#YCBCR_P210 YCBCR_P210}</td> * <td>3</td> * <td>P210 is a 4:2:2 YCbCr semiplanar format comprised of a WxH Y plane * followed by a WxH Cb and Cr planes. Each sample is represented by a 16-bit * little-endian value, with the lower 6 bits set to zero. Since this is guaranteed to be * a semi-planar format, the Cb plane can also be treated as an interleaved Cb/Cr plane. * </td> * </tr> * </table> * * @see android.graphics.ImageFormat Loading
media/java/android/media/ImageUtils.java +9 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ class ImageUtils { case ImageFormat.YUV_420_888: case ImageFormat.NV21: case ImageFormat.YCBCR_P010: case ImageFormat.YCBCR_P210: return 3; case ImageFormat.NV16: return 2; Loading Loading @@ -88,6 +89,7 @@ class ImageUtils { switch(hardwareBufferFormat) { case HardwareBuffer.YCBCR_420_888: case HardwareBuffer.YCBCR_P010: case HardwareBuffer.YCBCR_P210: return 3; case HardwareBuffer.RGBA_8888: case HardwareBuffer.RGBX_8888: Loading Loading @@ -269,6 +271,7 @@ class ImageUtils { case PixelFormat.RGBA_8888: case PixelFormat.RGBX_8888: case PixelFormat.RGBA_1010102: case ImageFormat.YCBCR_P210: estimatedBytePerPixel = 4.0; break; default: Loading Loading @@ -318,6 +321,12 @@ class ImageUtils { return new Size(image.getWidth(), image.getHeight()); case ImageFormat.PRIVATE: return new Size(0, 0); case ImageFormat.YCBCR_P210: if (planeIdx == 0) { return new Size(image.getWidth(), image.getHeight()); } else { return new Size(image.getWidth() / 2, image.getHeight()); } default: if (Log.isLoggable(IMAGEUTILS_LOG_TAG, Log.VERBOSE)) { Log.v(IMAGEUTILS_LOG_TAG, "getEffectivePlaneSizeForImage() uses" Loading
media/java/android/media/MediaCodec.java +6 −3 Original line number Diff line number Diff line Loading @@ -6158,11 +6158,14 @@ final public class MediaCodec { buffer.limit(buffer.position() + Utils.divUp(bitDepth, 8) + (mHeight / vert - 1) * rowInc + (mWidth / horiz - 1) * colInc); mPlanes[ix] = new MediaPlane(buffer.slice(), rowInc, colInc); if ((mFormat == ImageFormat.YUV_420_888 || mFormat == ImageFormat.YCBCR_P010) if ((mFormat == ImageFormat.YUV_420_888 || mFormat == ImageFormat.YCBCR_P010 || mFormat == ImageFormat.YCBCR_P210) && ix == 1) { cbPlaneOffset = planeOffset; } else if ((mFormat == ImageFormat.YUV_420_888 || mFormat == ImageFormat.YCBCR_P010) && ix == 2) { || mFormat == ImageFormat.YCBCR_P010 || mFormat == ImageFormat.YCBCR_P210) && ix == 2) { crPlaneOffset = planeOffset; } } Loading @@ -6172,7 +6175,7 @@ final public class MediaCodec { } // Validate chroma semiplanerness. if (mFormat == ImageFormat.YCBCR_P010) { if (mFormat == ImageFormat.YCBCR_P010 || mFormat == ImageFormat.YCBCR_P210) { if (crPlaneOffset != cbPlaneOffset + planeOffsetInc) { throw new UnsupportedOperationException("Invalid plane offsets" + " cbPlaneOffset: " + cbPlaneOffset + " crPlaneOffset: " + crPlaneOffset); Loading
media/jni/android_media_Utils.cpp +133 −6 Original line number Diff line number Diff line Loading @@ -17,13 +17,14 @@ // #define LOG_NDEBUG 0 #define LOG_TAG "AndroidMediaUtils" #include "android_media_Utils.h" #include <aidl/android/hardware/graphics/common/PixelFormat.h> #include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h> #include <ui/GraphicBufferMapper.h> #include <ui/GraphicTypes.h> #include <utils/Log.h> #include "android_media_Utils.h" #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) ) // Must be in sync with the value in HeicCompositeStream.cpp Loading @@ -33,6 +34,8 @@ namespace android { // -----------Utility functions used by ImageReader/Writer JNI----------------- using AidlPixelFormat = aidl::android::hardware::graphics::common::PixelFormat; enum { IMAGE_MAX_NUM_PLANES = 3, }; Loading Loading @@ -74,6 +77,7 @@ bool isPossiblyYUV(PixelFormat format) { case HAL_PIXEL_FORMAT_BLOB: case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: case HAL_PIXEL_FORMAT_YCBCR_P010: case static_cast<int>(AidlPixelFormat::YCBCR_P210): return false; case HAL_PIXEL_FORMAT_YV12: Loading Loading @@ -105,6 +109,7 @@ bool isPossibly10BitYUV(PixelFormat format) { return false; case HAL_PIXEL_FORMAT_YCBCR_P010: case static_cast<int>(AidlPixelFormat::YCBCR_P210): default: return true; } Loading Loading @@ -340,6 +345,47 @@ status_t getLockedImageInfo(LockedImage* buffer, int idx, cb = buffer->data + ySize; cr = cb + 2; pData = (idx == 0) ? buffer->data : (idx == 1) ? cb : cr; dataSize = (idx == 0) ? ySize : cSize; rStride = buffer->stride * 2; break; case static_cast<int>(AidlPixelFormat::YCBCR_P210): if (buffer->height % 2 != 0) { ALOGE("YCBCR_P210: height (%d) should be a multiple of 2", buffer->height); return BAD_VALUE; } if (buffer->width <= 0) { ALOGE("YCBCR_P210: width (%d) should be a > 0", buffer->width); return BAD_VALUE; } if (buffer->height <= 0) { ALOGE("YCBCR_210: height (%d) should be a > 0", buffer->height); return BAD_VALUE; } if (buffer->dataCb && buffer->dataCr) { pData = (idx == 0) ? buffer->data : (idx == 1) ? buffer->dataCb : buffer->dataCr; // only map until last pixel if (idx == 0) { pStride = 2; rStride = buffer->stride; dataSize = buffer->stride * (buffer->height - 1) + buffer->width * 2; } else { pStride = buffer->chromaStep; rStride = buffer->chromaStride; dataSize = buffer->chromaStride * (buffer->height - 1) + buffer->chromaStep * (buffer->width / 2); } break; } ySize = (buffer->stride * 2) * buffer->height; cSize = ySize; pStride = (idx == 0) ? 2 : 4; cb = buffer->data + ySize; cr = cb + 2; pData = (idx == 0) ? buffer->data : (idx == 1) ? cb : cr; dataSize = (idx == 0) ? ySize : cSize; rStride = buffer->stride * 2; Loading Loading @@ -544,6 +590,80 @@ static status_t extractP010Gralloc4PlaneLayout( return OK; } static status_t extractP210Gralloc4PlaneLayout(sp<GraphicBuffer> buffer, void *pData, int format, LockedImage *outputImage) { using aidl::android::hardware::graphics::common::PlaneLayoutComponent; using aidl::android::hardware::graphics::common::PlaneLayoutComponentType; GraphicBufferMapper &mapper = GraphicBufferMapper::get(); std::vector<ui::PlaneLayout> planeLayouts; status_t res = mapper.getPlaneLayouts(buffer->handle, &planeLayouts); if (res != OK) { return res; } constexpr int64_t Y_PLANE_COMPONENTS = int64_t(PlaneLayoutComponentType::Y); constexpr int64_t CBCR_PLANE_COMPONENTS = int64_t(PlaneLayoutComponentType::CB) | int64_t(PlaneLayoutComponentType::CR); uint8_t *dataY = nullptr; uint8_t *dataCb = nullptr; uint8_t *dataCr = nullptr; uint32_t strideY = 0; uint32_t strideCbCr = 0; for (const ui::PlaneLayout &layout : planeLayouts) { ALOGV("gralloc4 plane: %s", layout.toString().c_str()); int64_t components = 0; for (const PlaneLayoutComponent &component : layout.components) { if (component.sizeInBits != 10) { return BAD_VALUE; } components |= component.type.value; } if (components == Y_PLANE_COMPONENTS) { if (layout.sampleIncrementInBits != 16) { return BAD_VALUE; } if (layout.components[0].offsetInBits != 6) { return BAD_VALUE; } dataY = (uint8_t *)pData + layout.offsetInBytes; strideY = layout.strideInBytes; } else if (components == CBCR_PLANE_COMPONENTS) { if (layout.sampleIncrementInBits != 32) { return BAD_VALUE; } for (const PlaneLayoutComponent &component : layout.components) { if (component.type.value == int64_t(PlaneLayoutComponentType::CB) && component.offsetInBits != 6) { return BAD_VALUE; } if (component.type.value == int64_t(PlaneLayoutComponentType::CR) && component.offsetInBits != 22) { return BAD_VALUE; } } dataCb = (uint8_t *)pData + layout.offsetInBytes; dataCr = (uint8_t *)pData + layout.offsetInBytes + 2; strideCbCr = layout.strideInBytes; } else { return BAD_VALUE; } } outputImage->data = dataY; outputImage->width = buffer->getWidth(); outputImage->height = buffer->getHeight(); outputImage->format = format; outputImage->flexFormat = static_cast<int>(AidlPixelFormat::YCBCR_P210); outputImage->stride = strideY; outputImage->dataCb = dataCb; outputImage->dataCr = dataCr; outputImage->chromaStride = strideCbCr; outputImage->chromaStep = 4; return OK; } status_t lockImageFromBuffer(sp<GraphicBuffer> buffer, uint32_t inUsage, const Rect& rect, int fenceFd, LockedImage* outputImage) { ALOGV("%s: Try to lock the GraphicBuffer", __FUNCTION__); Loading Loading @@ -581,10 +701,17 @@ status_t lockImageFromBuffer(sp<GraphicBuffer> buffer, uint32_t inUsage, ALOGE("Lock buffer failed!"); return res; } if (isPossibly10BitYUV(format) && OK == extractP010Gralloc4PlaneLayout(buffer, pData, format, outputImage)) { if (isPossibly10BitYUV(format)) { if (format == HAL_PIXEL_FORMAT_YCBCR_P010 && OK == extractP010Gralloc4PlaneLayout(buffer, pData, format, outputImage)) { ALOGV("%s: Successfully locked the P010 image", __FUNCTION__); return OK; } else if ((format == static_cast<int>(AidlPixelFormat::YCBCR_P210)) && OK == extractP210Gralloc4PlaneLayout(buffer, pData, format, outputImage)) { ALOGV("%s: Successfully locked the P210 image", __FUNCTION__); return OK; } } } Loading