Support RGBA input buffers.
This change adds separate EGL shader for RGBA->YUV conversion
and modifies the JPEG compression to render input texture
into temporary framebuffer (doing the compression if necessary).
Bug: 301023410
Test: atest virtual_camera_tests
Test: atest VirtualCameraTest
Change-Id: Id3bd19d4c364691e2b1554fcf78d5f9940754314
diff --git a/services/camera/virtualcamera/util/EglFramebuffer.cc b/services/camera/virtualcamera/util/EglFramebuffer.cc
index acf0122..57b94d3 100644
--- a/services/camera/virtualcamera/util/EglFramebuffer.cc
+++ b/services/camera/virtualcamera/util/EglFramebuffer.cc
@@ -112,6 +112,10 @@
return mHeight;
}
+std::shared_ptr<AHardwareBuffer> EglFrameBuffer::getHardwareBuffer() {
+ return mHardwareBuffer;
+}
+
} // namespace virtualcamera
} // namespace companion
} // namespace android
diff --git a/services/camera/virtualcamera/util/EglFramebuffer.h b/services/camera/virtualcamera/util/EglFramebuffer.h
index 35f85e2..b39df6d 100644
--- a/services/camera/virtualcamera/util/EglFramebuffer.h
+++ b/services/camera/virtualcamera/util/EglFramebuffer.h
@@ -50,6 +50,9 @@
// Return height of framebuffer (in pixels).
int getHeight() const;
+ // Return underlying hardware buffer.
+ std::shared_ptr<AHardwareBuffer> getHardwareBuffer();
+
private:
// Keeping shared_ptr to hardware buffer instance here prevents it from being
// freed while tied to EGL framebufer / EGL texture.
diff --git a/services/camera/virtualcamera/util/EglProgram.cc b/services/camera/virtualcamera/util/EglProgram.cc
index c468d39..510fd33 100644
--- a/services/camera/virtualcamera/util/EglProgram.cc
+++ b/services/camera/virtualcamera/util/EglProgram.cc
@@ -76,17 +76,29 @@
vTextureCoord = aTextureCoord;
})";
-constexpr char kExternalTextureFragmentShader[] = R"(#version 300 es
+constexpr char kExternalYuvTextureFragmentShader[] = R"(#version 300 es
#extension GL_OES_EGL_image_external_essl3 : require
#extension GL_EXT_YUV_target : require
precision mediump float;
in vec2 vTextureCoord;
- out vec4 fragColor;
+ layout (yuv) out vec4 fragColor;
uniform __samplerExternal2DY2YEXT uTexture;
void main() {
fragColor = texture(uTexture, vTextureCoord);
})";
+constexpr char kExternalRgbaTextureFragmentShader[] = R"(#version 300 es
+ #extension GL_OES_EGL_image_external : require
+ #extension GL_EXT_YUV_target : require
+ precision mediump float;
+ in vec2 vTextureCoord;
+ layout (yuv) out vec4 fragColor;
+ uniform samplerExternalOES uTexture;
+ void main() {
+ vec4 rgbaColor = texture(uTexture, vTextureCoord);
+ fragColor = vec4(rgb_2_yuv(rgbaColor.xyz, itu_601_full_range), 0.0);
+ })";
+
constexpr int kCoordsPerVertex = 3;
constexpr std::array<float, 12> kSquareCoords{-1.f, 1.0f, 0.0f, // top left
-1.f, -1.f, 0.0f, // bottom left
@@ -237,7 +249,7 @@
return true;
}
-EglTextureProgram::EglTextureProgram() {
+EglTextureProgram::EglTextureProgram(const TextureFormat textureFormat) {
if (!isGlExtensionSupported(kGlExtYuvTarget)) {
ALOGE(
"Cannot initialize external texture program due to missing "
@@ -245,7 +257,10 @@
return;
}
- if (initialize(kExternalTextureVertexShader, kExternalTextureFragmentShader)) {
+ const char* fragmentShaderSrc = textureFormat == TextureFormat::YUV
+ ? kExternalYuvTextureFragmentShader
+ : kExternalRgbaTextureFragmentShader;
+ if (initialize(kExternalTextureVertexShader, fragmentShaderSrc)) {
ALOGV("Successfully initialized EGL shaders for external texture program.");
} else {
ALOGE("External texture EGL shader program initialization failed.");
diff --git a/services/camera/virtualcamera/util/EglProgram.h b/services/camera/virtualcamera/util/EglProgram.h
index 8e394e7..1b5f2cd 100644
--- a/services/camera/virtualcamera/util/EglProgram.h
+++ b/services/camera/virtualcamera/util/EglProgram.h
@@ -55,7 +55,9 @@
// TODO(b/301023410) Add support for translation / cropping.
class EglTextureProgram : public EglProgram {
public:
- EglTextureProgram();
+ enum class TextureFormat { RGBA, YUV };
+
+ EglTextureProgram(TextureFormat textureFormat = TextureFormat::YUV);
bool draw(GLuint textureId);
};
diff --git a/services/camera/virtualcamera/util/Util.cc b/services/camera/virtualcamera/util/Util.cc
index 11dc3a6..df771b1 100644
--- a/services/camera/virtualcamera/util/Util.cc
+++ b/services/camera/virtualcamera/util/Util.cc
@@ -18,20 +18,26 @@
#include <unistd.h>
+#include <algorithm>
+#include <array>
+
#include "jpeglib.h"
namespace android {
namespace companion {
namespace virtualcamera {
+using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::hardware::common::NativeHandle;
+
// Lower bound for maximal supported texture size is at least 2048x2048
// but on most platforms will be more.
// TODO(b/301023410) - Query actual max texture size.
constexpr int kMaxTextureSize = 2048;
constexpr int kLibJpegDctSize = DCTSIZE;
-using ::aidl::android::companion::virtualcamera::Format;
-using ::aidl::android::hardware::common::NativeHandle;
+constexpr std::array<Format, 2> kSupportedFormats{Format::YUV_420_888,
+ Format::RGBA_8888};
sp<Fence> importFence(const NativeHandle& aidlHandle) {
if (aidlHandle.fds.size() != 1) {
@@ -41,11 +47,15 @@
return sp<Fence>::make(::dup(aidlHandle.fds[0].get()));
}
+bool isPixelFormatSupportedForInput(const Format format) {
+ return std::find(kSupportedFormats.begin(), kSupportedFormats.end(),
+ format) != kSupportedFormats.end();
+}
+
// Returns true if specified format is supported for virtual camera input.
bool isFormatSupportedForInput(const int width, const int height,
const Format format) {
- if (format != Format::YUV_420_888) {
- // For now only YUV_420_888 is supported for input.
+ if (!isPixelFormatSupportedForInput(format)) {
return false;
}
diff --git a/services/camera/virtualcamera/util/Util.h b/services/camera/virtualcamera/util/Util.h
index b778321..a73c99b 100644
--- a/services/camera/virtualcamera/util/Util.h
+++ b/services/camera/virtualcamera/util/Util.h
@@ -43,6 +43,10 @@
sp<Fence> importFence(
const ::aidl::android::hardware::common::NativeHandle& handle);
+// Returns true if specified pixel format is supported for virtual camera input.
+bool isPixelFormatSupportedForInput(
+ ::aidl::android::companion::virtualcamera::Format format);
+
// Returns true if specified format is supported for virtual camera input.
bool isFormatSupportedForInput(
int width, int height,