Skip to content

Commit

Permalink
Texture Transform matrix calculations for AImageReader.
Browse files Browse the repository at this point in the history
This CL does a texture transform matrix calculations similar to what
android's SurfaceTexture framework does under the hood. This matrix
was not provided by AImageReader api and hence the calculations has
to be done in chrome.

This matrix is applied to the texture coordinates by display
compositor in order to draw the pixels correctly.

Before this CL this matrix was hardcoded to an identity matrix but
certain video format.

Bug: 1025273
Change-Id: I68aea1114f14cedbccfc1a59a4f8d2834d921711
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1919805
Reviewed-by: Andrew Grieve <agrieve@chromium.org>
Reviewed-by: Sunny Sachanandani <sunnyps@chromium.org>
Reviewed-by: Frank Liberato <liberato@chromium.org>
Commit-Queue: vikas soni <vikassoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#716452}
  • Loading branch information
vikaschromie authored and Commit Bot committed Nov 19, 2019
1 parent ee527cc commit eed0437
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
10 changes: 10 additions & 0 deletions base/android/android_image_reader_abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ typedef struct AHardwareBuffer AHardwareBuffer;

typedef struct AImage AImage;

typedef struct AImageCropRect {
int32_t left;
int32_t top;
int32_t right;
int32_t bottom;
} AImageCropRect;

enum AIMAGE_FORMATS {
AIMAGE_FORMAT_YUV_420_888 = 0x23,
AIMAGE_FORMAT_PRIVATE = 0x22
Expand All @@ -57,6 +64,9 @@ using pAImage_getWidth = media_status_t (*)(const AImage* image,
using pAImage_getHeight = media_status_t (*)(const AImage* image,
int32_t* height);

using pAImage_getCropRect = media_status_t (*)(const AImage* image,
AImageCropRect* rect);

// For AImageReader

typedef struct AImageReader AImageReader;
Expand Down
6 changes: 6 additions & 0 deletions base/android/android_image_reader_compat.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ bool AndroidImageReader::LoadFunctions() {
LOAD_FUNCTION(libmediandk, AImage_getHardwareBuffer);
LOAD_FUNCTION(libmediandk, AImage_getWidth);
LOAD_FUNCTION(libmediandk, AImage_getHeight);
LOAD_FUNCTION(libmediandk, AImage_getCropRect);
LOAD_FUNCTION(libmediandk, AImageReader_newWithUsage);
LOAD_FUNCTION(libmediandk, AImageReader_setImageListener);
LOAD_FUNCTION(libmediandk, AImageReader_delete);
Expand Down Expand Up @@ -111,6 +112,11 @@ media_status_t AndroidImageReader::AImage_getHeight(const AImage* image,
return AImage_getHeight_(image, height);
}

media_status_t AndroidImageReader::AImage_getCropRect(const AImage* image,
AImageCropRect* rect) {
return AImage_getCropRect_(image, rect);
}

media_status_t AndroidImageReader::AImageReader_newWithUsage(
int32_t width,
int32_t height,
Expand Down
2 changes: 2 additions & 0 deletions base/android/android_image_reader_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class BASE_EXPORT AndroidImageReader {
AHardwareBuffer** buffer);
media_status_t AImage_getWidth(const AImage* image, int32_t* width);
media_status_t AImage_getHeight(const AImage* image, int32_t* height);
media_status_t AImage_getCropRect(const AImage* image, AImageCropRect* rect);
media_status_t AImageReader_newWithUsage(int32_t width,
int32_t height,
int32_t format,
Expand Down Expand Up @@ -73,6 +74,7 @@ class BASE_EXPORT AndroidImageReader {
pAImage_getHardwareBuffer AImage_getHardwareBuffer_;
pAImage_getWidth AImage_getWidth_;
pAImage_getHeight AImage_getHeight_;
pAImage_getCropRect AImage_getCropRect_;
pAImageReader_newWithUsage AImageReader_newWithUsage_;
pAImageReader_setImageListener AImageReader_setImageListener_;
pAImageReader_delete AImageReader_delete_;
Expand Down
90 changes: 90 additions & 0 deletions gpu/command_buffer/service/image_reader_gl_owner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <jni.h>
#include <stdint.h>

#include "base/android/android_hardware_buffer_compat.h"
#include "base/android/jni_android.h"
#include "base/android/scoped_hardware_buffer_fence_sync.h"
#include "base/logging.h"
Expand Down Expand Up @@ -349,6 +350,95 @@ void ImageReaderGLOwner::GetTransformMatrix(float mtx[]) {
static constexpr float kYInvertedIdentity[16]{1, 0, 0, 0, 0, -1, 0, 0,
0, 0, 1, 0, 0, 1, 0, 1};
memcpy(mtx, kYInvertedIdentity, sizeof(kYInvertedIdentity));

// Compute the transform matrix only if we have an image available.
if (!current_image_ref_)
return;

// Get the crop rectangle associated with this image. The crop rectangle
// specifies the region of valid pixels in the image.
// Note that to query the crop rectangle, we don't need to wait for the
// AImage to be ready by checking the associated image ready fence.
AImageCropRect crop_rect;
media_status_t return_code =
loader_.AImage_getCropRect(current_image_ref_->image(), &crop_rect);
if (return_code != AMEDIA_OK) {
DLOG(ERROR) << "Error querying crop rectangle from the image : "
<< return_code;
return;
}

// Get the AHardwareBuffer to query its dimensions.
AHardwareBuffer* buffer = nullptr;
loader_.AImage_getHardwareBuffer(current_image_ref_->image(), &buffer);
if (!buffer) {
DLOG(ERROR) << "Unable to get an AHardwareBuffer from the image";
return;
}

// Get the buffer descriptor. Note that for querying the buffer descriptor, we
// do not need to wait on the AHB to be ready.
AHardwareBuffer_Desc desc;
base::AndroidHardwareBufferCompat::GetInstance().Describe(buffer, &desc);

// Note: Below calculation of shrink_amount and the transform matrix params
// tx,ty,sx,sy is copied from the android
// SurfaceTexture::computeCurrentTransformMatrix() -
// https://android.googlesource.com/platform/frameworks/native/+/5c1139f/libs/gui/SurfaceTexture.cpp#516.
// We are assuming here that bilinear filtering is always enabled for
// sampling the texture.
float shrink_amount = 0.0f;
float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;

// In order to prevent bilinear sampling beyond the edge of the
// crop rectangle we may need to shrink it by 2 texels in each
// dimension. Normally this would just need to take 1/2 a texel
// off each end, but because the chroma channels of YUV420 images
// are subsampled we may need to shrink the crop region by a whole
// texel on each side.
switch (desc.format) {
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
// We know there's no subsampling of any channels, so we
// only need to shrink by a half a pixel.
shrink_amount = 0.5;
break;
default:
// If we don't recognize the format, we must assume the
// worst case (that we care about), which is YUV420.
shrink_amount = 1.0;
}

int32_t crop_rect_width = (crop_rect.right - crop_rect.left);
int32_t crop_rect_height = (crop_rect.bottom - crop_rect.top);
DCHECK_GE(crop_rect_width, 0);
DCHECK_GE(crop_rect_height, 0);

int32_t buffer_width = desc.width;
int32_t buffer_height = desc.height;
DCHECK_GT(buffer_width, 0);
DCHECK_GT(buffer_height, 0);

// Only shrink the dimensions that are not the size of the buffer.
if (crop_rect_width < buffer_width) {
tx = (float(crop_rect.left) + shrink_amount) / buffer_width;
sx = (float(crop_rect_width) - (2.0f * shrink_amount)) / buffer_width;
}

if (crop_rect_height < buffer_height) {
ty = (float(buffer_height - crop_rect.bottom) + shrink_amount) /
buffer_height;
sy = (float(crop_rect_height) - (2.0f * shrink_amount)) / buffer_height;
}

// Update the transform matrix with above parameters by also taking into
// account Y inversion/ vertical flip.
mtx[0] = sx;
mtx[5] = 0 - sy;
mtx[12] = tx;
mtx[13] = 1 - ty;
}

void ImageReaderGLOwner::ReleaseBackBuffers() {
Expand Down

0 comments on commit eed0437

Please sign in to comment.