Loading services/camera/libcameraservice/tests/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,7 @@ cc_test { "libcutils", "libhidlbase", "libcamera_client", "libgui", "libui", "android.companion.virtualdevice.flags-aconfig-cc", "android.hardware.camera.common@1.0", Loading @@ -108,6 +109,7 @@ cc_test { // Only include sources that can't be run host-side here srcs: [ "Camera3StreamSplitterTest.cpp", "CameraPermissionsTest.cpp", "CameraProviderManagerTest.cpp", ], Loading services/camera/libcameraservice/tests/Camera3StreamSplitterTest.cpp 0 → 100644 +163 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Camera3StreamSplitterTest" // #define LOG_NDEBUG 0 #include "../device3/Camera3StreamSplitter.h" #include <android/hardware_buffer.h> #include <gui/BufferItemConsumer.h> #include <gui/IGraphicBufferConsumer.h> #include <gui/IGraphicBufferProducer.h> #include <gui/Surface.h> #include <ui/Fence.h> #include <ui/GraphicBuffer.h> #include <ui/GraphicBufferAllocator.h> #include <ui/PixelFormat.h> #include <system/window.h> #include <vndk/window.h> #include <gtest/gtest.h> using namespace android; namespace { uint64_t kConsumerUsage = AHARDWAREBUFFER_USAGE_CAMERA_READ; uint64_t kProducerUsage = AHARDWAREBUFFER_USAGE_CAMERA_READ; size_t kHalMaxBuffers = 3; uint32_t kWidth = 640; uint32_t kHeight = 480; PixelFormat kFormat = HAL_PIXEL_FORMAT_YCBCR_420_888; int64_t kDynamicRangeProfile = 0; std::tuple<sp<BufferItemConsumer>, sp<Surface>> createConsumerAndSurface() { sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); return {sp<BufferItemConsumer>::make(consumer, kConsumerUsage), sp<Surface>::make(producer)}; } class Camera3StreamSplitterTest : public testing::Test { public: void SetUp() override { mSplitter = sp<Camera3StreamSplitter>::make(); } protected: sp<Camera3StreamSplitter> mSplitter; }; class TestSurfaceListener : public SurfaceListener { public: virtual void onBufferReleased() override { mNumBuffersReleased++; } virtual bool needsReleaseNotify() { return true; } virtual void onBufferDetached(int) override {} virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>&) override {}; uint32_t mNumBuffersReleased = 0; }; class TestConsumerListener : public BufferItemConsumer::FrameAvailableListener { public: TestConsumerListener(const wp<BufferItemConsumer>& consumer) : mConsumer(consumer) {} virtual void onFrameAvailable(const BufferItem&) { sp<BufferItemConsumer> consumer = mConsumer.promote(); EXPECT_NE(nullptr, consumer); BufferItem item; EXPECT_EQ(OK, consumer->acquireBuffer(&item, 0)); mNumBuffersAcquired++; EXPECT_EQ(OK, consumer->releaseBuffer(item, Fence::NO_FENCE)); } virtual void onFrameReplaced(const BufferItem&) {} virtual void onFrameDequeued(const uint64_t) {} virtual void onFrameCancelled(const uint64_t) {} virtual void onFrameDetached(const uint64_t) {} wp<BufferItemConsumer> mConsumer; uint32_t mNumBuffersAcquired = 0; }; } // namespace TEST_F(Camera3StreamSplitterTest, TestWithoutSurfaces_NoBuffersConsumed) { sp<Surface> consumer; EXPECT_EQ(OK, mSplitter->connect({}, kConsumerUsage, kProducerUsage, kHalMaxBuffers, kWidth, kHeight, kFormat, &consumer, kDynamicRangeProfile)); sp<TestSurfaceListener> surfaceListener = sp<TestSurfaceListener>::make(); EXPECT_EQ(OK, consumer->connect(NATIVE_WINDOW_API_CAMERA, false, surfaceListener)); sp<GraphicBuffer> buffer = new GraphicBuffer(kWidth, kHeight, kFormat, kProducerUsage); EXPECT_EQ(OK, consumer->attachBuffer(buffer->getNativeBuffer())); // TODO: Do this with the surface itself once the API is available. EXPECT_EQ(OK, ANativeWindow_queueBuffer(consumer.get(), buffer->getNativeBuffer(), /*fenceFd*/ -1)); EXPECT_EQ(0u, surfaceListener->mNumBuffersReleased); } TEST_F(Camera3StreamSplitterTest, TestProcessSingleBuffer) { // // Set up output consumers: // constexpr auto kSurfaceId1 = 1; auto [bufferItemConsumer1, surface1] = createConsumerAndSurface(); sp<TestConsumerListener> consumerListener1 = sp<TestConsumerListener>::make(bufferItemConsumer1); bufferItemConsumer1->setFrameAvailableListener(consumerListener1); constexpr auto kSurfaceId2 = 2; auto [bufferItemConsumer2, surface2] = createConsumerAndSurface(); sp<TestConsumerListener> consumerListener2 = sp<TestConsumerListener>::make(bufferItemConsumer2); bufferItemConsumer2->setFrameAvailableListener(consumerListener2); // // Connect it to the splitter, get the input surface, and set it up: // sp<Surface> inputSurface; EXPECT_EQ(OK, mSplitter->connect({{kSurfaceId1, surface1}, {kSurfaceId2, surface2}}, kConsumerUsage, kProducerUsage, kHalMaxBuffers, kWidth, kHeight, kFormat, &inputSurface, kDynamicRangeProfile)); sp<TestSurfaceListener> surfaceListener = sp<TestSurfaceListener>::make(); EXPECT_EQ(OK, inputSurface->connect(NATIVE_WINDOW_API_CAMERA, false, surfaceListener)); // TODO: Do this with the surface itself once the API is available. EXPECT_EQ(OK, inputSurface->getIGraphicBufferProducer()->allowAllocation(false)); // // Create a buffer to use: // sp<GraphicBuffer> singleBuffer = new GraphicBuffer(kWidth, kHeight, kFormat, kProducerUsage); EXPECT_NE(nullptr, singleBuffer); mSplitter->attachBufferToOutputs(singleBuffer->getNativeBuffer(), {kSurfaceId1, kSurfaceId2}); // // Verify that when we attach the buffer, it's processed appropriately: // EXPECT_EQ(OK, inputSurface->attachBuffer(singleBuffer->getNativeBuffer())); EXPECT_EQ(OK, mSplitter->getOnFrameAvailableResult()); // TODO: Do this with the surface itself once the API is available. EXPECT_EQ(OK, ANativeWindow_queueBuffer(inputSurface.get(), singleBuffer->getNativeBuffer(), /*fenceFd*/ -1)); EXPECT_EQ(1u, consumerListener1->mNumBuffersAcquired); EXPECT_EQ(1u, consumerListener2->mNumBuffersAcquired); EXPECT_EQ(1u, surfaceListener->mNumBuffersReleased); } Loading
services/camera/libcameraservice/tests/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,7 @@ cc_test { "libcutils", "libhidlbase", "libcamera_client", "libgui", "libui", "android.companion.virtualdevice.flags-aconfig-cc", "android.hardware.camera.common@1.0", Loading @@ -108,6 +109,7 @@ cc_test { // Only include sources that can't be run host-side here srcs: [ "Camera3StreamSplitterTest.cpp", "CameraPermissionsTest.cpp", "CameraProviderManagerTest.cpp", ], Loading
services/camera/libcameraservice/tests/Camera3StreamSplitterTest.cpp 0 → 100644 +163 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Camera3StreamSplitterTest" // #define LOG_NDEBUG 0 #include "../device3/Camera3StreamSplitter.h" #include <android/hardware_buffer.h> #include <gui/BufferItemConsumer.h> #include <gui/IGraphicBufferConsumer.h> #include <gui/IGraphicBufferProducer.h> #include <gui/Surface.h> #include <ui/Fence.h> #include <ui/GraphicBuffer.h> #include <ui/GraphicBufferAllocator.h> #include <ui/PixelFormat.h> #include <system/window.h> #include <vndk/window.h> #include <gtest/gtest.h> using namespace android; namespace { uint64_t kConsumerUsage = AHARDWAREBUFFER_USAGE_CAMERA_READ; uint64_t kProducerUsage = AHARDWAREBUFFER_USAGE_CAMERA_READ; size_t kHalMaxBuffers = 3; uint32_t kWidth = 640; uint32_t kHeight = 480; PixelFormat kFormat = HAL_PIXEL_FORMAT_YCBCR_420_888; int64_t kDynamicRangeProfile = 0; std::tuple<sp<BufferItemConsumer>, sp<Surface>> createConsumerAndSurface() { sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); return {sp<BufferItemConsumer>::make(consumer, kConsumerUsage), sp<Surface>::make(producer)}; } class Camera3StreamSplitterTest : public testing::Test { public: void SetUp() override { mSplitter = sp<Camera3StreamSplitter>::make(); } protected: sp<Camera3StreamSplitter> mSplitter; }; class TestSurfaceListener : public SurfaceListener { public: virtual void onBufferReleased() override { mNumBuffersReleased++; } virtual bool needsReleaseNotify() { return true; } virtual void onBufferDetached(int) override {} virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>&) override {}; uint32_t mNumBuffersReleased = 0; }; class TestConsumerListener : public BufferItemConsumer::FrameAvailableListener { public: TestConsumerListener(const wp<BufferItemConsumer>& consumer) : mConsumer(consumer) {} virtual void onFrameAvailable(const BufferItem&) { sp<BufferItemConsumer> consumer = mConsumer.promote(); EXPECT_NE(nullptr, consumer); BufferItem item; EXPECT_EQ(OK, consumer->acquireBuffer(&item, 0)); mNumBuffersAcquired++; EXPECT_EQ(OK, consumer->releaseBuffer(item, Fence::NO_FENCE)); } virtual void onFrameReplaced(const BufferItem&) {} virtual void onFrameDequeued(const uint64_t) {} virtual void onFrameCancelled(const uint64_t) {} virtual void onFrameDetached(const uint64_t) {} wp<BufferItemConsumer> mConsumer; uint32_t mNumBuffersAcquired = 0; }; } // namespace TEST_F(Camera3StreamSplitterTest, TestWithoutSurfaces_NoBuffersConsumed) { sp<Surface> consumer; EXPECT_EQ(OK, mSplitter->connect({}, kConsumerUsage, kProducerUsage, kHalMaxBuffers, kWidth, kHeight, kFormat, &consumer, kDynamicRangeProfile)); sp<TestSurfaceListener> surfaceListener = sp<TestSurfaceListener>::make(); EXPECT_EQ(OK, consumer->connect(NATIVE_WINDOW_API_CAMERA, false, surfaceListener)); sp<GraphicBuffer> buffer = new GraphicBuffer(kWidth, kHeight, kFormat, kProducerUsage); EXPECT_EQ(OK, consumer->attachBuffer(buffer->getNativeBuffer())); // TODO: Do this with the surface itself once the API is available. EXPECT_EQ(OK, ANativeWindow_queueBuffer(consumer.get(), buffer->getNativeBuffer(), /*fenceFd*/ -1)); EXPECT_EQ(0u, surfaceListener->mNumBuffersReleased); } TEST_F(Camera3StreamSplitterTest, TestProcessSingleBuffer) { // // Set up output consumers: // constexpr auto kSurfaceId1 = 1; auto [bufferItemConsumer1, surface1] = createConsumerAndSurface(); sp<TestConsumerListener> consumerListener1 = sp<TestConsumerListener>::make(bufferItemConsumer1); bufferItemConsumer1->setFrameAvailableListener(consumerListener1); constexpr auto kSurfaceId2 = 2; auto [bufferItemConsumer2, surface2] = createConsumerAndSurface(); sp<TestConsumerListener> consumerListener2 = sp<TestConsumerListener>::make(bufferItemConsumer2); bufferItemConsumer2->setFrameAvailableListener(consumerListener2); // // Connect it to the splitter, get the input surface, and set it up: // sp<Surface> inputSurface; EXPECT_EQ(OK, mSplitter->connect({{kSurfaceId1, surface1}, {kSurfaceId2, surface2}}, kConsumerUsage, kProducerUsage, kHalMaxBuffers, kWidth, kHeight, kFormat, &inputSurface, kDynamicRangeProfile)); sp<TestSurfaceListener> surfaceListener = sp<TestSurfaceListener>::make(); EXPECT_EQ(OK, inputSurface->connect(NATIVE_WINDOW_API_CAMERA, false, surfaceListener)); // TODO: Do this with the surface itself once the API is available. EXPECT_EQ(OK, inputSurface->getIGraphicBufferProducer()->allowAllocation(false)); // // Create a buffer to use: // sp<GraphicBuffer> singleBuffer = new GraphicBuffer(kWidth, kHeight, kFormat, kProducerUsage); EXPECT_NE(nullptr, singleBuffer); mSplitter->attachBufferToOutputs(singleBuffer->getNativeBuffer(), {kSurfaceId1, kSurfaceId2}); // // Verify that when we attach the buffer, it's processed appropriately: // EXPECT_EQ(OK, inputSurface->attachBuffer(singleBuffer->getNativeBuffer())); EXPECT_EQ(OK, mSplitter->getOnFrameAvailableResult()); // TODO: Do this with the surface itself once the API is available. EXPECT_EQ(OK, ANativeWindow_queueBuffer(inputSurface.get(), singleBuffer->getNativeBuffer(), /*fenceFd*/ -1)); EXPECT_EQ(1u, consumerListener1->mNumBuffersAcquired); EXPECT_EQ(1u, consumerListener2->mNumBuffersAcquired); EXPECT_EQ(1u, surfaceListener->mNumBuffersReleased); }