xref: /aosp_15_r20/external/v4l2_codec2/common/FormatConverter.cpp (revision 0ec5a0ec62797f775085659156625e7f1bdb369f)
1*0ec5a0ecSAndroid Build Coastguard Worker // Copyright 2019 The Chromium Authors. All rights reserved.
2*0ec5a0ecSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*0ec5a0ecSAndroid Build Coastguard Worker // found in the LICENSE file.
4*0ec5a0ecSAndroid Build Coastguard Worker 
5*0ec5a0ecSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
6*0ec5a0ecSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_VIDEO
7*0ec5a0ecSAndroid Build Coastguard Worker #define LOG_TAG "FormatConverter"
8*0ec5a0ecSAndroid Build Coastguard Worker 
9*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/FormatConverter.h>
10*0ec5a0ecSAndroid Build Coastguard Worker 
11*0ec5a0ecSAndroid Build Coastguard Worker #include <inttypes.h>
12*0ec5a0ecSAndroid Build Coastguard Worker 
13*0ec5a0ecSAndroid Build Coastguard Worker #include <memory>
14*0ec5a0ecSAndroid Build Coastguard Worker #include <string>
15*0ec5a0ecSAndroid Build Coastguard Worker 
16*0ec5a0ecSAndroid Build Coastguard Worker #include <C2AllocatorGralloc.h>
17*0ec5a0ecSAndroid Build Coastguard Worker #include <C2PlatformSupport.h>
18*0ec5a0ecSAndroid Build Coastguard Worker #include <android/hardware/graphics/common/1.0/types.h>
19*0ec5a0ecSAndroid Build Coastguard Worker #include <inttypes.h>
20*0ec5a0ecSAndroid Build Coastguard Worker #include <libyuv.h>
21*0ec5a0ecSAndroid Build Coastguard Worker #include <ui/GraphicBuffer.h>
22*0ec5a0ecSAndroid Build Coastguard Worker #include <utils/Log.h>
23*0ec5a0ecSAndroid Build Coastguard Worker #include <utils/Trace.h>
24*0ec5a0ecSAndroid Build Coastguard Worker 
25*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/VideoTypes.h>  // for HalPixelFormat
26*0ec5a0ecSAndroid Build Coastguard Worker 
27*0ec5a0ecSAndroid Build Coastguard Worker using android::hardware::graphics::common::V1_0::BufferUsage;
28*0ec5a0ecSAndroid Build Coastguard Worker 
29*0ec5a0ecSAndroid Build Coastguard Worker namespace android {
30*0ec5a0ecSAndroid Build Coastguard Worker 
31*0ec5a0ecSAndroid Build Coastguard Worker namespace {
32*0ec5a0ecSAndroid Build Coastguard Worker // The constant expression of mapping the pixel format conversion pair (src, dst) to a unique
33*0ec5a0ecSAndroid Build Coastguard Worker // integer.
convertMap(VideoPixelFormat src,VideoPixelFormat dst)34*0ec5a0ecSAndroid Build Coastguard Worker constexpr int convertMap(VideoPixelFormat src, VideoPixelFormat dst) {
35*0ec5a0ecSAndroid Build Coastguard Worker     return static_cast<int>(src) * (static_cast<int>(VideoPixelFormat::UNKNOWN) + 1) +
36*0ec5a0ecSAndroid Build Coastguard Worker            static_cast<int>(dst);
37*0ec5a0ecSAndroid Build Coastguard Worker }
38*0ec5a0ecSAndroid Build Coastguard Worker 
39*0ec5a0ecSAndroid Build Coastguard Worker // The helper function to copy a plane pixel by pixel. It assumes bytesPerPixel is 1.
copyPlaneByPixel(const uint8_t * src,int srcStride,int srcColInc,uint8_t * dst,int dstStride,int dstColInc,int width,int height)40*0ec5a0ecSAndroid Build Coastguard Worker void copyPlaneByPixel(const uint8_t* src, int srcStride, int srcColInc, uint8_t* dst, int dstStride,
41*0ec5a0ecSAndroid Build Coastguard Worker                       int dstColInc, int width, int height) {
42*0ec5a0ecSAndroid Build Coastguard Worker     for (int row = 0; row < height; row++) {
43*0ec5a0ecSAndroid Build Coastguard Worker         const uint8_t* srcRow = src;
44*0ec5a0ecSAndroid Build Coastguard Worker         uint8_t* dstRow = dst;
45*0ec5a0ecSAndroid Build Coastguard Worker         for (int col = 0; col < width; col++) {
46*0ec5a0ecSAndroid Build Coastguard Worker             memcpy(dstRow, srcRow, 1);
47*0ec5a0ecSAndroid Build Coastguard Worker             srcRow += srcColInc;
48*0ec5a0ecSAndroid Build Coastguard Worker             dstRow += dstColInc;
49*0ec5a0ecSAndroid Build Coastguard Worker         }
50*0ec5a0ecSAndroid Build Coastguard Worker         src += srcStride;
51*0ec5a0ecSAndroid Build Coastguard Worker         dst += dstStride;
52*0ec5a0ecSAndroid Build Coastguard Worker     }
53*0ec5a0ecSAndroid Build Coastguard Worker }
54*0ec5a0ecSAndroid Build Coastguard Worker 
55*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace
56*0ec5a0ecSAndroid Build Coastguard Worker 
ImplDefinedToRGBXMap(sp<GraphicBuffer> buf,uint8_t * addr,int rowInc)57*0ec5a0ecSAndroid Build Coastguard Worker ImplDefinedToRGBXMap::ImplDefinedToRGBXMap(sp<GraphicBuffer> buf, uint8_t* addr, int rowInc)
58*0ec5a0ecSAndroid Build Coastguard Worker       : mBuffer(std::move(buf)), mAddr(addr), mRowInc(rowInc) {}
59*0ec5a0ecSAndroid Build Coastguard Worker 
~ImplDefinedToRGBXMap()60*0ec5a0ecSAndroid Build Coastguard Worker ImplDefinedToRGBXMap::~ImplDefinedToRGBXMap() {
61*0ec5a0ecSAndroid Build Coastguard Worker     mBuffer->unlock();
62*0ec5a0ecSAndroid Build Coastguard Worker }
63*0ec5a0ecSAndroid Build Coastguard Worker 
64*0ec5a0ecSAndroid Build Coastguard Worker // static
create(const C2ConstGraphicBlock & block)65*0ec5a0ecSAndroid Build Coastguard Worker std::unique_ptr<ImplDefinedToRGBXMap> ImplDefinedToRGBXMap::create(
66*0ec5a0ecSAndroid Build Coastguard Worker         const C2ConstGraphicBlock& block) {
67*0ec5a0ecSAndroid Build Coastguard Worker     uint32_t width, height, format, stride, igbpSlot, generation;
68*0ec5a0ecSAndroid Build Coastguard Worker     uint64_t usage, igbpId;
69*0ec5a0ecSAndroid Build Coastguard Worker     android::_UnwrapNativeCodec2GrallocMetadata(block.handle(), &width, &height, &format, &usage,
70*0ec5a0ecSAndroid Build Coastguard Worker                                                 &stride, &generation, &igbpId, &igbpSlot);
71*0ec5a0ecSAndroid Build Coastguard Worker 
72*0ec5a0ecSAndroid Build Coastguard Worker     if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
73*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("The original format (=%u) is not IMPLEMENTATION_DEFINED", format);
74*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
75*0ec5a0ecSAndroid Build Coastguard Worker     }
76*0ec5a0ecSAndroid Build Coastguard Worker 
77*0ec5a0ecSAndroid Build Coastguard Worker     native_handle_t* grallocHandle = android::UnwrapNativeCodec2GrallocHandle(block.handle());
78*0ec5a0ecSAndroid Build Coastguard Worker     sp<GraphicBuffer> buf = new GraphicBuffer(grallocHandle, GraphicBuffer::CLONE_HANDLE, width,
79*0ec5a0ecSAndroid Build Coastguard Worker                                               height, format, 1, usage, stride);
80*0ec5a0ecSAndroid Build Coastguard Worker     native_handle_delete(grallocHandle);
81*0ec5a0ecSAndroid Build Coastguard Worker 
82*0ec5a0ecSAndroid Build Coastguard Worker     void* pointer = nullptr;
83*0ec5a0ecSAndroid Build Coastguard Worker     int32_t status = buf->lock(GRALLOC_USAGE_SW_READ_OFTEN, &pointer);
84*0ec5a0ecSAndroid Build Coastguard Worker     if (status != OK) {
85*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to lock buffer as IMPLEMENTATION_DEFINED format");
86*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
87*0ec5a0ecSAndroid Build Coastguard Worker     }
88*0ec5a0ecSAndroid Build Coastguard Worker 
89*0ec5a0ecSAndroid Build Coastguard Worker     uint8_t* addr = reinterpret_cast<uint8_t*>(pointer);
90*0ec5a0ecSAndroid Build Coastguard Worker     int rowInc = static_cast<int>(stride * 4);  // RGBX 4-byte data per pixel
91*0ec5a0ecSAndroid Build Coastguard Worker     ALOGD("Parsed input format IMPLEMENTATION_DEFINED to RGBX_8888");
92*0ec5a0ecSAndroid Build Coastguard Worker     return std::unique_ptr<ImplDefinedToRGBXMap>(
93*0ec5a0ecSAndroid Build Coastguard Worker             new ImplDefinedToRGBXMap(std::move(buf), addr, rowInc));
94*0ec5a0ecSAndroid Build Coastguard Worker }
95*0ec5a0ecSAndroid Build Coastguard Worker 
96*0ec5a0ecSAndroid Build Coastguard Worker // static
create(VideoPixelFormat outFormat,const ui::Size & visibleSize,uint32_t inputCount,const ui::Size & codedSize)97*0ec5a0ecSAndroid Build Coastguard Worker std::unique_ptr<FormatConverter> FormatConverter::create(VideoPixelFormat outFormat,
98*0ec5a0ecSAndroid Build Coastguard Worker                                                          const ui::Size& visibleSize,
99*0ec5a0ecSAndroid Build Coastguard Worker                                                          uint32_t inputCount,
100*0ec5a0ecSAndroid Build Coastguard Worker                                                          const ui::Size& codedSize) {
101*0ec5a0ecSAndroid Build Coastguard Worker     if (outFormat != VideoPixelFormat::I420 && outFormat != VideoPixelFormat::NV12) {
102*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Unsupported output format: %d", static_cast<int32_t>(outFormat));
103*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
104*0ec5a0ecSAndroid Build Coastguard Worker     }
105*0ec5a0ecSAndroid Build Coastguard Worker 
106*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<FormatConverter> converter(new FormatConverter);
107*0ec5a0ecSAndroid Build Coastguard Worker     if (converter->initialize(outFormat, visibleSize, inputCount, codedSize) != C2_OK) {
108*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to initialize FormatConverter");
109*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
110*0ec5a0ecSAndroid Build Coastguard Worker     }
111*0ec5a0ecSAndroid Build Coastguard Worker     return converter;
112*0ec5a0ecSAndroid Build Coastguard Worker }
113*0ec5a0ecSAndroid Build Coastguard Worker 
initialize(VideoPixelFormat outFormat,const ui::Size & visibleSize,uint32_t inputCount,const ui::Size & codedSize)114*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t FormatConverter::initialize(VideoPixelFormat outFormat, const ui::Size& visibleSize,
115*0ec5a0ecSAndroid Build Coastguard Worker                                         uint32_t inputCount, const ui::Size& codedSize) {
116*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("initialize(out_format=%s, visible_size=%dx%d, input_count=%u, coded_size=%dx%d)",
117*0ec5a0ecSAndroid Build Coastguard Worker           videoPixelFormatToString(outFormat).c_str(), visibleSize.width, visibleSize.height,
118*0ec5a0ecSAndroid Build Coastguard Worker           inputCount, codedSize.width, codedSize.height);
119*0ec5a0ecSAndroid Build Coastguard Worker 
120*0ec5a0ecSAndroid Build Coastguard Worker     mOutFormat = outFormat;
121*0ec5a0ecSAndroid Build Coastguard Worker     mVisibleSize = visibleSize;
122*0ec5a0ecSAndroid Build Coastguard Worker     mCodedSize = codedSize;
123*0ec5a0ecSAndroid Build Coastguard Worker 
124*0ec5a0ecSAndroid Build Coastguard Worker     mTempPlaneU =
125*0ec5a0ecSAndroid Build Coastguard Worker             std::unique_ptr<uint8_t[]>(new uint8_t[mVisibleSize.width * mVisibleSize.height / 4]);
126*0ec5a0ecSAndroid Build Coastguard Worker     mTempPlaneV =
127*0ec5a0ecSAndroid Build Coastguard Worker             std::unique_ptr<uint8_t[]>(new uint8_t[mVisibleSize.width * mVisibleSize.height / 4]);
128*0ec5a0ecSAndroid Build Coastguard Worker 
129*0ec5a0ecSAndroid Build Coastguard Worker     // Allocate graphic blocks for format conversion.
130*0ec5a0ecSAndroid Build Coastguard Worker     uint32_t requested_buffer_count = std::max(1u, inputCount);
131*0ec5a0ecSAndroid Build Coastguard Worker     c2_status_t status = allocateBuffers(requested_buffer_count);
132*0ec5a0ecSAndroid Build Coastguard Worker     if (status != C2_OK) {
133*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to allocate buffers (error: %d)", status);
134*0ec5a0ecSAndroid Build Coastguard Worker         return status;
135*0ec5a0ecSAndroid Build Coastguard Worker     }
136*0ec5a0ecSAndroid Build Coastguard Worker 
137*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
138*0ec5a0ecSAndroid Build Coastguard Worker }
139*0ec5a0ecSAndroid Build Coastguard Worker 
allocateBuffers(uint32_t count)140*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t FormatConverter::allocateBuffers(uint32_t count) {
141*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("Allocating %u buffers (format: %s, visible size: %dx%d, coded size: %dx%d)", count,
142*0ec5a0ecSAndroid Build Coastguard Worker           videoPixelFormatToString(mOutFormat).c_str(), mVisibleSize.width, mVisibleSize.height,
143*0ec5a0ecSAndroid Build Coastguard Worker           mCodedSize.width, mCodedSize.height);
144*0ec5a0ecSAndroid Build Coastguard Worker 
145*0ec5a0ecSAndroid Build Coastguard Worker     HalPixelFormat halFormat;
146*0ec5a0ecSAndroid Build Coastguard Worker     if (mOutFormat == VideoPixelFormat::I420) {
147*0ec5a0ecSAndroid Build Coastguard Worker         // Android HAL format doesn't have I420, we use YV12 instead and swap U/V while converting.
148*0ec5a0ecSAndroid Build Coastguard Worker         halFormat = HalPixelFormat::YV12;
149*0ec5a0ecSAndroid Build Coastguard Worker     } else {
150*0ec5a0ecSAndroid Build Coastguard Worker         halFormat = HalPixelFormat::YCBCR_420_888;  // Will allocate NV12 in minigbm.
151*0ec5a0ecSAndroid Build Coastguard Worker     }
152*0ec5a0ecSAndroid Build Coastguard Worker 
153*0ec5a0ecSAndroid Build Coastguard Worker     std::shared_ptr<C2BlockPool> pool;
154*0ec5a0ecSAndroid Build Coastguard Worker     c2_status_t status = GetCodec2BlockPool(C2BlockPool::BASIC_GRAPHIC, nullptr, &pool);
155*0ec5a0ecSAndroid Build Coastguard Worker     if (status != C2_OK) {
156*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to get basic graphic block pool (error: %d)", status);
157*0ec5a0ecSAndroid Build Coastguard Worker         return C2_NO_MEMORY;
158*0ec5a0ecSAndroid Build Coastguard Worker     }
159*0ec5a0ecSAndroid Build Coastguard Worker 
160*0ec5a0ecSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < count; i++) {
161*0ec5a0ecSAndroid Build Coastguard Worker         std::shared_ptr<C2GraphicBlock> block;
162*0ec5a0ecSAndroid Build Coastguard Worker         status = pool->fetchGraphicBlock(mCodedSize.width, mCodedSize.height,
163*0ec5a0ecSAndroid Build Coastguard Worker                                          static_cast<uint32_t>(halFormat),
164*0ec5a0ecSAndroid Build Coastguard Worker                                          {(C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE),
165*0ec5a0ecSAndroid Build Coastguard Worker                                           static_cast<uint64_t>(BufferUsage::VIDEO_ENCODER)},
166*0ec5a0ecSAndroid Build Coastguard Worker                                          &block);
167*0ec5a0ecSAndroid Build Coastguard Worker         if (status != C2_OK) {
168*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Failed to fetch graphic block (error: %d)", status);
169*0ec5a0ecSAndroid Build Coastguard Worker             return C2_NO_MEMORY;
170*0ec5a0ecSAndroid Build Coastguard Worker         }
171*0ec5a0ecSAndroid Build Coastguard Worker         mGraphicBlocks.emplace_back(new BlockEntry(std::move(block)));
172*0ec5a0ecSAndroid Build Coastguard Worker         mAvailableQueue.push(mGraphicBlocks.back().get());
173*0ec5a0ecSAndroid Build Coastguard Worker     }
174*0ec5a0ecSAndroid Build Coastguard Worker 
175*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
176*0ec5a0ecSAndroid Build Coastguard Worker }
177*0ec5a0ecSAndroid Build Coastguard Worker 
convertBlock(uint64_t frameIndex,const C2ConstGraphicBlock & inputBlock,C2ConstGraphicBlock * convertedBlock)178*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t FormatConverter::convertBlock(uint64_t frameIndex,
179*0ec5a0ecSAndroid Build Coastguard Worker                                           const C2ConstGraphicBlock& inputBlock,
180*0ec5a0ecSAndroid Build Coastguard Worker                                           C2ConstGraphicBlock* convertedBlock) {
181*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
182*0ec5a0ecSAndroid Build Coastguard Worker     const C2GraphicView& inputView = inputBlock.map().get();
183*0ec5a0ecSAndroid Build Coastguard Worker     C2PlanarLayout inputLayout = inputView.layout();
184*0ec5a0ecSAndroid Build Coastguard Worker 
185*0ec5a0ecSAndroid Build Coastguard Worker     // Determine the input buffer pixel format.
186*0ec5a0ecSAndroid Build Coastguard Worker     VideoPixelFormat inputFormat = VideoPixelFormat::UNKNOWN;
187*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<ImplDefinedToRGBXMap> idMap;
188*0ec5a0ecSAndroid Build Coastguard Worker     if (inputLayout.type == C2PlanarLayout::TYPE_YUV) {
189*0ec5a0ecSAndroid Build Coastguard Worker         if (inputLayout.rootPlanes == 3) {
190*0ec5a0ecSAndroid Build Coastguard Worker             inputFormat = VideoPixelFormat::YV12;
191*0ec5a0ecSAndroid Build Coastguard Worker         } else if (inputLayout.rootPlanes == 2) {
192*0ec5a0ecSAndroid Build Coastguard Worker             const uint8_t* const* data = inputView.data();
193*0ec5a0ecSAndroid Build Coastguard Worker             inputFormat = (data[C2PlanarLayout::PLANE_V] > data[C2PlanarLayout::PLANE_U])
194*0ec5a0ecSAndroid Build Coastguard Worker                                   ? VideoPixelFormat::NV12
195*0ec5a0ecSAndroid Build Coastguard Worker                                   : VideoPixelFormat::NV21;
196*0ec5a0ecSAndroid Build Coastguard Worker         }
197*0ec5a0ecSAndroid Build Coastguard Worker     } else if (inputLayout.type == C2PlanarLayout::TYPE_RGB) {
198*0ec5a0ecSAndroid Build Coastguard Worker         inputFormat = VideoPixelFormat::ABGR;
199*0ec5a0ecSAndroid Build Coastguard Worker     } else if (static_cast<uint32_t>(inputLayout.type) == 0u) {
200*0ec5a0ecSAndroid Build Coastguard Worker         // The above layout() cannot fill layout information and sets it to 0 instead if the input
201*0ec5a0ecSAndroid Build Coastguard Worker         // format is IMPLEMENTATION_DEFINED and its backed format is RGB. We fill the layout by
202*0ec5a0ecSAndroid Build Coastguard Worker         // using ImplDefinedToRGBXMap in this case.
203*0ec5a0ecSAndroid Build Coastguard Worker         idMap = ImplDefinedToRGBXMap::create(inputBlock);
204*0ec5a0ecSAndroid Build Coastguard Worker         if (!idMap) {
205*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Unable to parse RGBX_8888 from IMPLEMENTATION_DEFINED");
206*0ec5a0ecSAndroid Build Coastguard Worker             return C2_CORRUPTED;
207*0ec5a0ecSAndroid Build Coastguard Worker         }
208*0ec5a0ecSAndroid Build Coastguard Worker         // There is only RGBA_8888 specified in C2AllocationGralloc::map(), no BGRA_8888. Maybe
209*0ec5a0ecSAndroid Build Coastguard Worker         // BGRA_8888 is not used now?
210*0ec5a0ecSAndroid Build Coastguard Worker         inputFormat = VideoPixelFormat::ABGR;
211*0ec5a0ecSAndroid Build Coastguard Worker         inputLayout.type = C2PlanarLayout::TYPE_RGB;
212*0ec5a0ecSAndroid Build Coastguard Worker     } else {
213*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to determine input pixel format: %u", inputLayout.type);
214*0ec5a0ecSAndroid Build Coastguard Worker         return C2_CORRUPTED;
215*0ec5a0ecSAndroid Build Coastguard Worker     }
216*0ec5a0ecSAndroid Build Coastguard Worker 
217*0ec5a0ecSAndroid Build Coastguard Worker     if (inputFormat == mOutFormat) {
218*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Zero-Copy is applied");
219*0ec5a0ecSAndroid Build Coastguard Worker         mGraphicBlocks.emplace_back(new BlockEntry(frameIndex));
220*0ec5a0ecSAndroid Build Coastguard Worker         *convertedBlock = inputBlock;
221*0ec5a0ecSAndroid Build Coastguard Worker         return C2_OK;
222*0ec5a0ecSAndroid Build Coastguard Worker     }
223*0ec5a0ecSAndroid Build Coastguard Worker 
224*0ec5a0ecSAndroid Build Coastguard Worker     if (!isReady()) {
225*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("There is no available block for conversion");
226*0ec5a0ecSAndroid Build Coastguard Worker         return C2_NO_MEMORY;
227*0ec5a0ecSAndroid Build Coastguard Worker     }
228*0ec5a0ecSAndroid Build Coastguard Worker 
229*0ec5a0ecSAndroid Build Coastguard Worker     BlockEntry* entry = mAvailableQueue.front();
230*0ec5a0ecSAndroid Build Coastguard Worker     std::shared_ptr<C2GraphicBlock> outputBlock = entry->mBlock;
231*0ec5a0ecSAndroid Build Coastguard Worker 
232*0ec5a0ecSAndroid Build Coastguard Worker     C2GraphicView outputView = outputBlock->map().get();
233*0ec5a0ecSAndroid Build Coastguard Worker     C2PlanarLayout outputLayout = outputView.layout();
234*0ec5a0ecSAndroid Build Coastguard Worker     uint8_t* dstY = outputView.data()[C2PlanarLayout::PLANE_Y];
235*0ec5a0ecSAndroid Build Coastguard Worker     uint8_t* dstU = outputView.data()[C2PlanarLayout::PLANE_V];   // only for I420
236*0ec5a0ecSAndroid Build Coastguard Worker     uint8_t* dstV = outputView.data()[C2PlanarLayout::PLANE_U];   // only for I420
237*0ec5a0ecSAndroid Build Coastguard Worker     uint8_t* dstUV = outputView.data()[C2PlanarLayout::PLANE_U];  // only for NV12
238*0ec5a0ecSAndroid Build Coastguard Worker     const int dstStrideY = outputLayout.planes[C2PlanarLayout::PLANE_Y].rowInc;
239*0ec5a0ecSAndroid Build Coastguard Worker     const int dstStrideU = outputLayout.planes[C2PlanarLayout::PLANE_V].rowInc;   // only for I420
240*0ec5a0ecSAndroid Build Coastguard Worker     const int dstStrideV = outputLayout.planes[C2PlanarLayout::PLANE_U].rowInc;   // only for I420
241*0ec5a0ecSAndroid Build Coastguard Worker     const int dstStrideUV = outputLayout.planes[C2PlanarLayout::PLANE_U].rowInc;  // only for NV12
242*0ec5a0ecSAndroid Build Coastguard Worker 
243*0ec5a0ecSAndroid Build Coastguard Worker     if (inputLayout.type == C2PlanarLayout::TYPE_YUV) {
244*0ec5a0ecSAndroid Build Coastguard Worker         const uint8_t* srcY = inputView.data()[C2PlanarLayout::PLANE_Y];
245*0ec5a0ecSAndroid Build Coastguard Worker         const uint8_t* srcU = inputView.data()[C2PlanarLayout::PLANE_U];
246*0ec5a0ecSAndroid Build Coastguard Worker         const uint8_t* srcV = inputView.data()[C2PlanarLayout::PLANE_V];
247*0ec5a0ecSAndroid Build Coastguard Worker         const int srcStrideY = inputLayout.planes[C2PlanarLayout::PLANE_Y].rowInc;
248*0ec5a0ecSAndroid Build Coastguard Worker         const int srcStrideU = inputLayout.planes[C2PlanarLayout::PLANE_U].rowInc;
249*0ec5a0ecSAndroid Build Coastguard Worker         const int srcStrideV = inputLayout.planes[C2PlanarLayout::PLANE_V].rowInc;
250*0ec5a0ecSAndroid Build Coastguard Worker 
251*0ec5a0ecSAndroid Build Coastguard Worker         switch (convertMap(inputFormat, mOutFormat)) {
252*0ec5a0ecSAndroid Build Coastguard Worker         case convertMap(VideoPixelFormat::YV12, VideoPixelFormat::I420):
253*0ec5a0ecSAndroid Build Coastguard Worker             libyuv::I420Copy(srcY, srcStrideY, srcU, srcStrideU, srcV, srcStrideV, dstY, dstStrideY,
254*0ec5a0ecSAndroid Build Coastguard Worker                              dstU, dstStrideU, dstV, dstStrideV, mVisibleSize.width,
255*0ec5a0ecSAndroid Build Coastguard Worker                              mVisibleSize.height);
256*0ec5a0ecSAndroid Build Coastguard Worker             break;
257*0ec5a0ecSAndroid Build Coastguard Worker         case convertMap(VideoPixelFormat::YV12, VideoPixelFormat::NV12):
258*0ec5a0ecSAndroid Build Coastguard Worker             libyuv::I420ToNV12(srcY, srcStrideY, srcU, srcStrideU, srcV, srcStrideV, dstY,
259*0ec5a0ecSAndroid Build Coastguard Worker                                dstStrideY, dstUV, dstStrideUV, mVisibleSize.width,
260*0ec5a0ecSAndroid Build Coastguard Worker                                mVisibleSize.height);
261*0ec5a0ecSAndroid Build Coastguard Worker             break;
262*0ec5a0ecSAndroid Build Coastguard Worker         case convertMap(VideoPixelFormat::NV12, VideoPixelFormat::I420):
263*0ec5a0ecSAndroid Build Coastguard Worker             libyuv::NV12ToI420(srcY, srcStrideY, srcU, srcStrideU, dstY, dstStrideY, dstU,
264*0ec5a0ecSAndroid Build Coastguard Worker                                dstStrideU, dstV, dstStrideV, mVisibleSize.width,
265*0ec5a0ecSAndroid Build Coastguard Worker                                mVisibleSize.height);
266*0ec5a0ecSAndroid Build Coastguard Worker             break;
267*0ec5a0ecSAndroid Build Coastguard Worker         case convertMap(VideoPixelFormat::NV21, VideoPixelFormat::I420):
268*0ec5a0ecSAndroid Build Coastguard Worker             libyuv::NV21ToI420(srcY, srcStrideY, srcV, srcStrideV, dstY, dstStrideY, dstU,
269*0ec5a0ecSAndroid Build Coastguard Worker                                dstStrideU, dstV, dstStrideV, mVisibleSize.width,
270*0ec5a0ecSAndroid Build Coastguard Worker                                mVisibleSize.height);
271*0ec5a0ecSAndroid Build Coastguard Worker             break;
272*0ec5a0ecSAndroid Build Coastguard Worker         case convertMap(VideoPixelFormat::NV21, VideoPixelFormat::NV12):
273*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("%s(): Converting PIXEL_FORMAT_NV21 -> PIXEL_FORMAT_NV12", __func__);
274*0ec5a0ecSAndroid Build Coastguard Worker             libyuv::CopyPlane(srcY, srcStrideY, dstY, dstStrideY, mVisibleSize.width,
275*0ec5a0ecSAndroid Build Coastguard Worker                               mVisibleSize.height);
276*0ec5a0ecSAndroid Build Coastguard Worker             copyPlaneByPixel(srcU, srcStrideU, 2, dstUV, dstStrideUV, 2, mVisibleSize.width / 2,
277*0ec5a0ecSAndroid Build Coastguard Worker                              mVisibleSize.height / 2);
278*0ec5a0ecSAndroid Build Coastguard Worker             copyPlaneByPixel(srcV, srcStrideV, 2, dstUV + 1, dstStrideUV, 2, mVisibleSize.width / 2,
279*0ec5a0ecSAndroid Build Coastguard Worker                              mVisibleSize.height / 2);
280*0ec5a0ecSAndroid Build Coastguard Worker             break;
281*0ec5a0ecSAndroid Build Coastguard Worker         default:
282*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Unsupported pixel format conversion from %s to %s",
283*0ec5a0ecSAndroid Build Coastguard Worker                   videoPixelFormatToString(inputFormat).c_str(),
284*0ec5a0ecSAndroid Build Coastguard Worker                   videoPixelFormatToString(mOutFormat).c_str());
285*0ec5a0ecSAndroid Build Coastguard Worker             return C2_CORRUPTED;
286*0ec5a0ecSAndroid Build Coastguard Worker         }
287*0ec5a0ecSAndroid Build Coastguard Worker     } else if (inputLayout.type == C2PlanarLayout::TYPE_RGB) {
288*0ec5a0ecSAndroid Build Coastguard Worker         const uint8_t* srcRGB = (idMap) ? idMap->addr() : inputView.data()[C2PlanarLayout::PLANE_R];
289*0ec5a0ecSAndroid Build Coastguard Worker         const int srcStrideRGB =
290*0ec5a0ecSAndroid Build Coastguard Worker                 (idMap) ? idMap->rowInc() : inputLayout.planes[C2PlanarLayout::PLANE_R].rowInc;
291*0ec5a0ecSAndroid Build Coastguard Worker 
292*0ec5a0ecSAndroid Build Coastguard Worker         switch (convertMap(inputFormat, mOutFormat)) {
293*0ec5a0ecSAndroid Build Coastguard Worker         case convertMap(VideoPixelFormat::ABGR, VideoPixelFormat::I420):
294*0ec5a0ecSAndroid Build Coastguard Worker             libyuv::ABGRToI420(srcRGB, srcStrideRGB, dstY, dstStrideY, dstU, dstStrideU, dstV,
295*0ec5a0ecSAndroid Build Coastguard Worker                                dstStrideV, mVisibleSize.width, mVisibleSize.height);
296*0ec5a0ecSAndroid Build Coastguard Worker             break;
297*0ec5a0ecSAndroid Build Coastguard Worker         case convertMap(VideoPixelFormat::ABGR, VideoPixelFormat::NV12): {
298*0ec5a0ecSAndroid Build Coastguard Worker             // There is no libyuv function to convert ABGR to NV12. Therefore, we first convert to
299*0ec5a0ecSAndroid Build Coastguard Worker             // I420 on dst-Y plane and temporary U/V plane. Then we copy U and V pixels from
300*0ec5a0ecSAndroid Build Coastguard Worker             // temporary planes to dst-UV interleavedly.
301*0ec5a0ecSAndroid Build Coastguard Worker             const int tempStride = mVisibleSize.width / 2;
302*0ec5a0ecSAndroid Build Coastguard Worker             libyuv::ABGRToI420(srcRGB, srcStrideRGB, dstY, dstStrideY, mTempPlaneU.get(),
303*0ec5a0ecSAndroid Build Coastguard Worker                                tempStride, mTempPlaneV.get(), tempStride, mVisibleSize.width,
304*0ec5a0ecSAndroid Build Coastguard Worker                                mVisibleSize.height);
305*0ec5a0ecSAndroid Build Coastguard Worker             libyuv::MergeUVPlane(mTempPlaneU.get(), tempStride, mTempPlaneV.get(), tempStride,
306*0ec5a0ecSAndroid Build Coastguard Worker                                  dstUV, dstStrideUV, mVisibleSize.width / 2,
307*0ec5a0ecSAndroid Build Coastguard Worker                                  mVisibleSize.height / 2);
308*0ec5a0ecSAndroid Build Coastguard Worker             break;
309*0ec5a0ecSAndroid Build Coastguard Worker         }
310*0ec5a0ecSAndroid Build Coastguard Worker         default:
311*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Unsupported pixel format conversion from %s to %s",
312*0ec5a0ecSAndroid Build Coastguard Worker                   videoPixelFormatToString(inputFormat).c_str(),
313*0ec5a0ecSAndroid Build Coastguard Worker                   videoPixelFormatToString(mOutFormat).c_str());
314*0ec5a0ecSAndroid Build Coastguard Worker             return C2_CORRUPTED;
315*0ec5a0ecSAndroid Build Coastguard Worker         }
316*0ec5a0ecSAndroid Build Coastguard Worker     } else {
317*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Unsupported input layout type");
318*0ec5a0ecSAndroid Build Coastguard Worker         return C2_CORRUPTED;
319*0ec5a0ecSAndroid Build Coastguard Worker     }
320*0ec5a0ecSAndroid Build Coastguard Worker 
321*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("convertBlock(frame_index=%" PRIu64 ", format=%s)", frameIndex,
322*0ec5a0ecSAndroid Build Coastguard Worker           videoPixelFormatToString(inputFormat).c_str());
323*0ec5a0ecSAndroid Build Coastguard Worker     entry->mAssociatedFrameIndex = frameIndex;
324*0ec5a0ecSAndroid Build Coastguard Worker     mAvailableQueue.pop();
325*0ec5a0ecSAndroid Build Coastguard Worker 
326*0ec5a0ecSAndroid Build Coastguard Worker     *convertedBlock =
327*0ec5a0ecSAndroid Build Coastguard Worker             outputBlock->share(C2Rect(mVisibleSize.width, mVisibleSize.height), C2Fence());
328*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
329*0ec5a0ecSAndroid Build Coastguard Worker }
330*0ec5a0ecSAndroid Build Coastguard Worker 
returnBlock(uint64_t frameIndex)331*0ec5a0ecSAndroid Build Coastguard Worker c2_status_t FormatConverter::returnBlock(uint64_t frameIndex) {
332*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("returnBlock(frame_index=%" PRIu64 ")", frameIndex);
333*0ec5a0ecSAndroid Build Coastguard Worker 
334*0ec5a0ecSAndroid Build Coastguard Worker     auto iter = std::find_if(mGraphicBlocks.begin(), mGraphicBlocks.end(),
335*0ec5a0ecSAndroid Build Coastguard Worker                              [frameIndex](const std::unique_ptr<BlockEntry>& be) {
336*0ec5a0ecSAndroid Build Coastguard Worker                                  return be->mAssociatedFrameIndex == frameIndex;
337*0ec5a0ecSAndroid Build Coastguard Worker                              });
338*0ec5a0ecSAndroid Build Coastguard Worker     if (iter == mGraphicBlocks.end()) {
339*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to find graphic block by converted/zero-copied frame index: %" PRIu64 "",
340*0ec5a0ecSAndroid Build Coastguard Worker               frameIndex);
341*0ec5a0ecSAndroid Build Coastguard Worker         return C2_BAD_INDEX;
342*0ec5a0ecSAndroid Build Coastguard Worker     }
343*0ec5a0ecSAndroid Build Coastguard Worker 
344*0ec5a0ecSAndroid Build Coastguard Worker     if ((*iter)->mBlock) {
345*0ec5a0ecSAndroid Build Coastguard Worker         // Returned block is format converted.
346*0ec5a0ecSAndroid Build Coastguard Worker         (*iter)->mAssociatedFrameIndex = kNoFrameAssociated;
347*0ec5a0ecSAndroid Build Coastguard Worker         mAvailableQueue.push(iter->get());
348*0ec5a0ecSAndroid Build Coastguard Worker     } else {
349*0ec5a0ecSAndroid Build Coastguard Worker         // Returned block is zero-copied.
350*0ec5a0ecSAndroid Build Coastguard Worker         mGraphicBlocks.erase(iter);
351*0ec5a0ecSAndroid Build Coastguard Worker     }
352*0ec5a0ecSAndroid Build Coastguard Worker     return C2_OK;
353*0ec5a0ecSAndroid Build Coastguard Worker }
354*0ec5a0ecSAndroid Build Coastguard Worker 
355*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace android
356