1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef CODEC2_COMMON_BUFFER_TYPES_H
18 #define CODEC2_COMMON_BUFFER_TYPES_H
19 
20 #ifndef LOG_TAG
21 #define LOG_TAG "Codec2-BufferTypes"
22 #endif
23 #include <android-base/logging.h>
24 
25 #include <codec2/common/BufferPoolSender.h>
26 #include <codec2/common/ParamTypes.h>
27 #include <media/stagefright/foundation/AUtils.h>
28 
29 #include <C2AllocatorIon.h>
30 #include <C2AllocatorGralloc.h>
31 #include <C2BlockInternal.h>
32 #include <C2Buffer.h>
33 #include <C2Component.h>
34 #include <C2FenceFactory.h>
35 #include <C2Param.h>
36 #include <C2ParamDef.h>
37 #include <C2PlatformSupport.h>
38 #include <C2Work.h>
39 
40 #include <algorithm>
41 #include <functional>
42 #include <iomanip>
43 #include <map>
44 
45 namespace android {
46 
47 // Types of metadata for Blocks.
48 struct C2Hal_Range {
49     uint32_t offset;
50     uint32_t length; // Do not use "size" because the name collides with C2Info::size().
51 };
52 typedef C2GlobalParam<C2Info, C2Hal_Range, 0> C2Hal_RangeInfo;
53 
54 struct C2Hal_Rect {
55     uint32_t left;
56     uint32_t top;
57     uint32_t width;
58     uint32_t height;
59 };
60 typedef C2GlobalParam<C2Info, C2Hal_Rect, 1> C2Hal_RectInfo;
61 
62 // Note: The handle is not cloned.
63 template <typename BaseBlock>
64 void SetHandle(BaseBlock *baseBlock, const C2Handle *handle);
65 
66 template <typename BaseBlock>
67 void SetAHardwareBuffer(BaseBlock *baseBlock, AHardwareBuffer *pBuf);
68 
69 template <typename BufferPoolTypes, typename BaseBlock>
70 void SetPooledBlock(
71         BaseBlock *baseBlock,
72         const typename BufferPoolTypes::BufferStatusMessage &pooledBlock);
73 
74 template <typename BufferPoolTypes>
75 bool GetBufferPoolData(
76         const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
77         std::shared_ptr<typename BufferPoolTypes::BufferPoolData> *bpData);
78 
79 // Find or add a HAL BaseBlock object from a given C2Handle* to a list and an
80 // associated map.
81 // Note: The handle is not cloned.
82 template <typename BaseBlock>
_addBaseBlock(uint32_t * index,const C2Handle * handle,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)83 bool _addBaseBlock(
84         uint32_t* index,
85         const C2Handle* handle,
86         std::list<BaseBlock>* baseBlocks,
87         std::map<const void*, uint32_t>* baseBlockIndices) {
88     if (!handle) {
89         LOG(ERROR) << "addBaseBlock called on a null C2Handle.";
90         return false;
91     }
92     auto it = baseBlockIndices->find(handle);
93     if (it != baseBlockIndices->end()) {
94         *index = it->second;
95     } else {
96         *index = baseBlocks->size();
97         baseBlockIndices->emplace(handle, *index);
98         baseBlocks->emplace_back();
99 
100         BaseBlock &dBaseBlock = baseBlocks->back();
101         SetHandle(&dBaseBlock, handle);
102     }
103     return true;
104 }
105 
106 // Find or add a HAL BaseBlock object from a given AHardwareBuffer* to a list and an
107 // associated map.
108 template <typename BaseBlock>
_addBaseBlock(uint32_t * index,AHardwareBuffer * pBuf,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)109 bool _addBaseBlock(
110         uint32_t* index,
111         AHardwareBuffer* pBuf,
112         std::list<BaseBlock>* baseBlocks,
113         std::map<const void*, uint32_t>* baseBlockIndices) {
114     if (!pBuf) {
115         LOG(ERROR) << "addBaseBlock called on a null AHardwareBuffer.";
116     }
117     auto it = baseBlockIndices->find(pBuf);
118     if (it != baseBlockIndices->end()) {
119         *index = it->second;
120     } else {
121         *index = baseBlocks->size();
122         baseBlockIndices->emplace(pBuf, *index);
123         baseBlocks->emplace_back();
124 
125         BaseBlock &dBaseBlock = baseBlocks->back();
126         SetAHardwareBuffer(&dBaseBlock, pBuf);
127     }
128     return true;
129 }
130 
131 // Find or add a hidl BaseBlock object from a given BufferPoolData to a list and
132 // an associated map.
133 template <typename BufferPoolTypes, typename BaseBlock>
_addBaseBlock(uint32_t * index,const std::shared_ptr<typename BufferPoolTypes::BufferPoolData> & bpData,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)134 bool _addBaseBlock(
135         uint32_t* index,
136         const std::shared_ptr<typename BufferPoolTypes::BufferPoolData> &bpData,
137         BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
138         std::list<BaseBlock>* baseBlocks,
139         std::map<const void*, uint32_t>* baseBlockIndices) {
140     if (!bpData) {
141         LOG(ERROR) << "addBaseBlock called on a null BufferPoolData.";
142         return false;
143     }
144     auto it = baseBlockIndices->find(bpData.get());
145     if (it != baseBlockIndices->end()) {
146         *index = it->second;
147     } else {
148         *index = baseBlocks->size();
149         baseBlockIndices->emplace(bpData.get(), *index);
150         baseBlocks->emplace_back();
151 
152         BaseBlock &dBaseBlock = baseBlocks->back();
153 
154         if (bufferPoolSender) {
155             typename BufferPoolTypes::BufferStatusMessage pooledBlock;
156             typename BufferPoolTypes::BufferPoolStatus bpStatus =
157                 bufferPoolSender->send(bpData, &pooledBlock);
158 
159             if (bpStatus != BufferPoolTypes::ResultStatus::OK) {
160                 LOG(ERROR) << "Failed to send buffer with BufferPool. Error: "
161                            << static_cast<int32_t>(bpStatus)
162                            << ".";
163                 return false;
164             }
165             SetPooledBlock<BufferPoolTypes>(&dBaseBlock, pooledBlock);
166         }
167     }
168     return true;
169 }
170 
171 template <typename BufferPoolTypes, typename BaseBlock>
addBaseBlock(uint32_t * index,const C2Handle * handle,const std::shared_ptr<const _C2BlockPoolData> & blockPoolData,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)172 bool addBaseBlock(
173         uint32_t* index,
174         const C2Handle* handle,
175         const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
176         BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
177         std::list<BaseBlock>* baseBlocks,
178         std::map<const void*, uint32_t>* baseBlockIndices) {
179     if (!blockPoolData) {
180         // No BufferPoolData ==> NATIVE block.
181         return _addBaseBlock(
182                 index, handle,
183                 baseBlocks, baseBlockIndices);
184     }
185     switch (blockPoolData->getType()) {
186     case _C2BlockPoolData::TYPE_BUFFERPOOL:
187     case _C2BlockPoolData::TYPE_BUFFERPOOL2: {
188             // BufferPoolData
189             std::shared_ptr<typename BufferPoolTypes::BufferPoolData> bpData;
190             if (!GetBufferPoolData<BufferPoolTypes>(blockPoolData, &bpData) || !bpData) {
191                 LOG(ERROR) << "BufferPoolData unavailable in a block.";
192                 return false;
193             }
194             return _addBaseBlock(
195                     index, bpData,
196                     bufferPoolSender, baseBlocks, baseBlockIndices);
197         }
198     case _C2BlockPoolData::TYPE_BUFFERQUEUE: {
199             uint32_t gen;
200             uint64_t bqId;
201             int32_t bqSlot;
202             // Update handle if migration happened.
203             if (_C2BlockFactory::GetBufferQueueData(
204                     blockPoolData, &gen, &bqId, &bqSlot)) {
205                 android::MigrateNativeCodec2GrallocHandle(
206                         const_cast<native_handle_t*>(handle), gen, bqId, bqSlot);
207             }
208             return _addBaseBlock(
209                     index, handle,
210                     baseBlocks, baseBlockIndices);
211         }
212     case _C2BlockPoolData::TYPE_AHWBUFFER: {
213             AHardwareBuffer *pBuf;
214             if (!_C2BlockFactory::GetAHardwareBuffer(blockPoolData, &pBuf)) {
215                 LOG(ERROR) << "AHardwareBuffer unavailable in a block.";
216                 return false;
217             }
218             return _addBaseBlock(
219                     index, pBuf,
220                     baseBlocks, baseBlockIndices);
221         }
222     default:
223         LOG(ERROR) << "Unknown C2BlockPoolData type.";
224         return false;
225     }
226 }
227 
228 // C2Fence -> Handle
229 // Note: File descriptors are not duplicated. The original file descriptor must
230 // not be closed before the transaction is complete.
231 template <typename Handle>
objcpy(Handle * d,const C2Fence & s)232 bool objcpy(Handle* d, const C2Fence& s) {
233     d->setTo(nullptr);
234     native_handle_t* handle = _C2FenceFactory::CreateNativeHandle(s);
235     if (handle) {
236         d->setTo(handle, true /* owns */);
237 //  } else if (!s.ready()) {
238 //      // TODO: we should wait for unmarshallable fences but this may not be
239 //      // the best place for it. We can safely ignore here as at this time
240 //      // all fences used here are marshallable.
241     }
242     return true;
243 }
244 
245 // C2ConstLinearBlock -> Block
246 // Note: Native handles are not duplicated. The original handles must not be
247 // closed before the transaction is complete.
248 template <typename Block, typename BufferPoolTypes, typename BaseBlock>
objcpy(Block * d,const C2ConstLinearBlock & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)249 bool objcpy(Block* d, const C2ConstLinearBlock& s,
250         BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
251         std::list<BaseBlock>* baseBlocks,
252         std::map<const void*, uint32_t>* baseBlockIndices) {
253     std::shared_ptr<const _C2BlockPoolData> bpData =
254             _C2BlockFactory::GetLinearBlockPoolData(s);
255     if (!addBaseBlock((uint32_t *)&d->index, s.handle(), bpData,
256             bufferPoolSender, baseBlocks, baseBlockIndices)) {
257         LOG(ERROR) << "Invalid block data in C2ConstLinearBlock.";
258         return false;
259     }
260 
261     // Create the metadata.
262     C2Hal_RangeInfo dRangeInfo;
263     dRangeInfo.offset = static_cast<uint32_t>(s.offset());
264     dRangeInfo.length = static_cast<uint32_t>(s.size());
265     if (!_createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRangeInfo })) {
266         LOG(ERROR) << "Invalid range info in C2ConstLinearBlock.";
267         return false;
268     }
269 
270     // Copy the fence
271     if (!objcpy(&d->fence, s.fence())) {
272         LOG(ERROR) << "Invalid C2ConstLinearBlock::fence.";
273         return false;
274     }
275     return true;
276 }
277 
278 // C2ConstGraphicBlock -> Block
279 // Note: Native handles are not duplicated. The original handles must not be
280 // closed before the transaction is complete.
281 template <typename Block, typename BufferPoolTypes, typename BaseBlock>
objcpy(Block * d,const C2ConstGraphicBlock & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)282 bool objcpy(Block* d, const C2ConstGraphicBlock& s,
283         BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
284         std::list<BaseBlock>* baseBlocks,
285         std::map<const void*, uint32_t>* baseBlockIndices) {
286     std::shared_ptr<const _C2BlockPoolData> bpData =
287             _C2BlockFactory::GetGraphicBlockPoolData(s);
288     if (!addBaseBlock((uint32_t *)&d->index, s.handle(), bpData,
289             bufferPoolSender, baseBlocks, baseBlockIndices)) {
290         LOG(ERROR) << "Invalid block data in C2ConstGraphicBlock.";
291         return false;
292     }
293 
294     // Create the metadata.
295     C2Hal_RectInfo dRectInfo;
296     C2Rect sRect = s.crop();
297     dRectInfo.left = static_cast<uint32_t>(sRect.left);
298     dRectInfo.top = static_cast<uint32_t>(sRect.top);
299     dRectInfo.width = static_cast<uint32_t>(sRect.width);
300     dRectInfo.height = static_cast<uint32_t>(sRect.height);
301     if (!_createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRectInfo })) {
302         LOG(ERROR) << "Invalid rect info in C2ConstGraphicBlock.";
303         return false;
304     }
305 
306     // Copy the fence
307     if (!objcpy(&d->fence, s.fence())) {
308         LOG(ERROR) << "Invalid C2ConstGraphicBlock::fence.";
309         return false;
310     }
311     return true;
312 }
313 
314 // C2BufferData -> Buffer
315 // This function only fills in d->blocks.
316 template <typename Buffer, typename BufferPoolTypes, typename BaseBlock>
objcpy(Buffer * d,const C2BufferData & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)317 bool objcpy(Buffer* d, const C2BufferData& s,
318         BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
319         std::list<BaseBlock>* baseBlocks,
320         std::map<const void*, uint32_t>* baseBlockIndices) {
321     d->blocks.resize(
322             s.linearBlocks().size() +
323             s.graphicBlocks().size());
324     size_t i = 0;
325     for (const C2ConstLinearBlock& linearBlock : s.linearBlocks()) {
326         auto& dBlock = d->blocks[i++];
327         if (!objcpy(
328                 &dBlock, linearBlock,
329                 bufferPoolSender, baseBlocks, baseBlockIndices)) {
330             LOG(ERROR) << "Invalid C2BufferData::linearBlocks. "
331                        << "(Destination index = " << i - 1 << ".)";
332             return false;
333         }
334     }
335     for (const C2ConstGraphicBlock& graphicBlock : s.graphicBlocks()) {
336         auto& dBlock = d->blocks[i++];
337         if (!objcpy(
338                 &dBlock, graphicBlock,
339                 bufferPoolSender, baseBlocks, baseBlockIndices)) {
340             LOG(ERROR) << "Invalid C2BufferData::graphicBlocks. "
341                        << "(Destination index = " << i - 1 << ".)";
342             return false;
343         }
344     }
345     return true;
346 }
347 
348 // C2Buffer -> Buffer
349 template <typename Buffer, typename BufferPoolTypes, typename BaseBlock>
objcpy(Buffer * d,const C2Buffer & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)350 bool objcpy(Buffer* d, const C2Buffer& s,
351         BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
352         std::list<BaseBlock>* baseBlocks,
353         std::map<const void*, uint32_t>* baseBlockIndices) {
354     if (!_createParamsBlob(&d->info, s.info())) {
355         LOG(ERROR) << "Invalid C2Buffer::info.";
356         return false;
357     }
358     if (!objcpy(d, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
359         LOG(ERROR) << "Invalid C2Buffer::data.";
360         return false;
361     }
362     return true;
363 }
364 
365 // C2InfoBuffer -> InfoBuffer
366 template <typename InfoBuffer, typename BufferPoolTypes, typename BaseBlock>
objcpy(InfoBuffer * d,const C2InfoBuffer & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)367 bool objcpy(InfoBuffer* d, const C2InfoBuffer& s,
368         BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
369         std::list<BaseBlock>* baseBlocks,
370         std::map<const void*, uint32_t>* baseBlockIndices) {
371     d->index = static_cast<decltype(d->index)>(s.index());
372     auto& dBuffer = d->buffer;
373     if (!objcpy(&dBuffer, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
374         LOG(ERROR) << "Invalid C2InfoBuffer::data";
375         return false;
376     }
377     return true;
378 }
379 
380 // C2FrameData -> FrameData
381 template <typename FrameData, typename BufferPoolTypes, typename BaseBlock>
objcpy(FrameData * d,const C2FrameData & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)382 bool objcpy(FrameData* d, const C2FrameData& s,
383         BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
384         std::list<BaseBlock>* baseBlocks,
385         std::map<const void*, uint32_t>* baseBlockIndices) {
386     d->flags = static_cast<decltype(d->flags)>(s.flags);
387     if (!objcpy(&d->ordinal, s.ordinal)) {
388         LOG(ERROR) << "Invalid C2FrameData::ordinal.";
389         return false;
390     }
391 
392     d->buffers.resize(s.buffers.size());
393     size_t i = 0;
394     for (const std::shared_ptr<C2Buffer>& sBuffer : s.buffers) {
395         auto& dBuffer = d->buffers[i++];
396         if (!sBuffer) {
397             // A null (pointer to) C2Buffer corresponds to a Buffer with empty
398             // info and blocks.
399             auto *dInfo = GetBlob(&dBuffer.info);
400             dInfo->resize(0);
401             dBuffer.blocks.resize(0);
402             continue;
403         }
404         if (!objcpy(
405                 &dBuffer, *sBuffer,
406                 bufferPoolSender, baseBlocks, baseBlockIndices)) {
407             LOG(ERROR) << "Invalid C2FrameData::buffers["
408                        << i - 1 << "].";
409             return false;
410         }
411     }
412 
413     if (!_createParamsBlob(&d->configUpdate, s.configUpdate)) {
414         LOG(ERROR) << "Invalid C2FrameData::configUpdate.";
415         return false;
416     }
417 
418     d->infoBuffers.resize(s.infoBuffers.size());
419     i = 0;
420     for (const C2InfoBuffer& sInfoBuffer : s.infoBuffers) {
421         auto& dInfoBuffer = d->infoBuffers[i++];
422         if (!objcpy(&dInfoBuffer, sInfoBuffer,
423                 bufferPoolSender, baseBlocks, baseBlockIndices)) {
424             LOG(ERROR) << "Invalid C2FrameData::infoBuffers["
425                        << i - 1 << "].";
426             return false;
427         }
428     }
429 
430     return true;
431 }
432 
433 // std::list<std::unique_ptr<C2Work>> -> WorkBundle
434 template <typename WorkBundle, typename BufferPoolTypes>
objcpy(WorkBundle * d,const std::list<std::unique_ptr<C2Work>> & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender)435 bool objcpy(
436         WorkBundle* d,
437         const std::list<std::unique_ptr<C2Work>>& s,
438         BufferPoolSender<BufferPoolTypes>* bufferPoolSender) {
439     // baseBlocks holds a list of BaseBlock objects that Blocks can refer to.
440     std::list<typename decltype(d->baseBlocks)::value_type> baseBlocks;
441 
442     // baseBlockIndices maps a raw pointer to native_handle_t or BufferPoolData
443     // inside baseBlocks to the corresponding index into baseBlocks. The keys
444     // (pointers) are used to identify blocks that have the same "base block" in
445     // s, a list of C2Work objects. Because baseBlocks will be copied into a
446     // hidl_vec eventually, the values of baseBlockIndices are zero-based
447     // integer indices instead of list iterators.
448     //
449     // Note that the pointers can be raw because baseBlockIndices has a shorter
450     // lifespan than all of base blocks.
451     std::map<const void*, uint32_t> baseBlockIndices;
452 
453     d->works.resize(s.size());
454     size_t i = 0;
455     for (const std::unique_ptr<C2Work>& sWork : s) {
456         auto &dWork = d->works[i++];
457         if (!sWork) {
458             LOG(WARNING) << "Null C2Work encountered.";
459             continue;
460         }
461 
462         // chain info is not in use currently.
463 
464         // input
465         if (!objcpy(&dWork.input, sWork->input,
466                 bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
467             LOG(ERROR) << "Invalid C2Work::input.";
468             return false;
469         }
470 
471         // worklets
472         if (sWork->worklets.size() == 0) {
473             LOG(DEBUG) << "Work with no worklets.";
474         } else {
475             // Parcel the worklets.
476             auto &dWorklets = dWork.worklets;
477             dWorklets.resize(sWork->worklets.size());
478             size_t j = 0;
479             for (const std::unique_ptr<C2Worklet>& sWorklet : sWork->worklets)
480             {
481                 if (!sWorklet) {
482                     LOG(WARNING) << "Null C2Work::worklets["
483                                  << j << "].";
484                     continue;
485                 }
486                 auto &dWorklet = dWorklets[j++];
487 
488                 // component id
489                 dWorklet.componentId = static_cast<uint32_t>(
490                         sWorklet->component);
491 
492                 // tunings
493                 if (!_createParamsBlob(&dWorklet.tunings, sWorklet->tunings)) {
494                     LOG(ERROR) << "Invalid C2Work::worklets["
495                                << j - 1 << "]->tunings.";
496                     return false;
497                 }
498 
499                 // failures
500                 dWorklet.failures.resize(sWorklet->failures.size());
501                 size_t k = 0;
502                 for (const std::unique_ptr<C2SettingResult>& sFailure :
503                         sWorklet->failures) {
504                     if (!sFailure) {
505                         LOG(WARNING) << "Null C2Work::worklets["
506                                      << j - 1 << "]->failures["
507                                      << k << "].";
508                         continue;
509                     }
510                     if (!objcpy(&dWorklet.failures[k++], *sFailure)) {
511                         LOG(ERROR) << "Invalid C2Work::worklets["
512                                    << j - 1 << "]->failures["
513                                    << k - 1 << "].";
514                         return false;
515                     }
516                 }
517 
518                 // output
519                 if (!objcpy(&dWorklet.output, sWorklet->output,
520                         bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
521                     LOG(ERROR) << "Invalid C2Work::worklets["
522                                << j - 1 << "]->output.";
523                     return false;
524                 }
525             }
526         }
527 
528         // worklets processed
529         dWork.workletsProcessed = sWork->workletsProcessed;
530 
531         // result
532         SetStatus(&dWork.result, sWork->result);
533     }
534 
535     // Move std::list<BaseBlock> to vector<BaseBlock>.
536     {
537         d->baseBlocks.resize(baseBlocks.size());
538         size_t i = 0;
539         for (auto&& baseBlock : baseBlocks) {
540             d->baseBlocks[i++] = std::move(baseBlock);
541         }
542     }
543 
544     return true;
545 }
546 
547 struct C2BaseBlock {
548     enum type_t {
549         LINEAR,
550         GRAPHIC,
551     };
552     type_t type;
553     std::shared_ptr<C2LinearBlock> linear;
554     std::shared_ptr<C2GraphicBlock> graphic;
555 };
556 
557 // Handle -> C2Fence
558 // Note: File descriptors are not duplicated. The original file descriptor must
559 // not be closed before the transaction is complete.
560 template <typename Handle>
objcpy(C2Fence * d,const Handle & s)561 bool objcpy(C2Fence* d, const Handle& s) {
562     const native_handle_t* handle = s.getNativeHandle();
563     *d = _C2FenceFactory::CreateFromNativeHandle(handle);
564     return true;
565 }
566 
567 // C2LinearBlock, vector<C2Param*>, C2Fence -> C2Buffer
568 bool CreateLinearBuffer(
569         std::shared_ptr<C2Buffer>* buffer,
570         const std::shared_ptr<C2LinearBlock>& block,
571         const std::vector<C2Param*>& meta,
572         const C2Fence& fence);
573 
574 // C2GraphicBlock, vector<C2Param*>, C2Fence -> C2Buffer
575 bool CreateGraphicBuffer(
576         std::shared_ptr<C2Buffer>* buffer,
577         const std::shared_ptr<C2GraphicBlock>& block,
578         const std::vector<C2Param*>& meta,
579         const C2Fence& fence);
580 
581 // Buffer -> C2Buffer
582 // Note: The native handles will be cloned.
583 template <typename Buffer>
objcpy(std::shared_ptr<C2Buffer> * d,const Buffer & s,const std::vector<C2BaseBlock> & baseBlocks)584 bool objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
585         const std::vector<C2BaseBlock>& baseBlocks) {
586     *d = nullptr;
587 
588     // Currently, a non-null C2Buffer must contain exactly 1 block.
589     if (s.blocks.size() == 0) {
590         return true;
591     } else if (s.blocks.size() != 1) {
592         LOG(ERROR) << "Invalid Buffer: "
593                       "Currently, a C2Buffer must contain exactly 1 block.";
594         return false;
595     }
596 
597     const auto &sBlock = s.blocks[0];
598     if (sBlock.index >= baseBlocks.size()) {
599         LOG(ERROR) << "Invalid Buffer::blocks[0].index: "
600                       "Array index out of range.";
601         return false;
602     }
603     const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
604 
605     // Parse meta.
606     std::vector<C2Param*> sBlockMeta;
607     if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
608         LOG(ERROR) << "Invalid Buffer::blocks[0].meta.";
609         return false;
610     }
611 
612     // Copy fence.
613     C2Fence dFence;
614     if (!objcpy(&dFence, sBlock.fence)) {
615         LOG(ERROR) << "Invalid Buffer::blocks[0].fence.";
616         return false;
617     }
618 
619     // Construct a block.
620     switch (baseBlock.type) {
621     case C2BaseBlock::LINEAR:
622         if (!CreateLinearBuffer(d, baseBlock.linear, sBlockMeta, dFence)) {
623             LOG(ERROR) << "Invalid C2BaseBlock::linear.";
624             return false;
625         }
626         break;
627     case C2BaseBlock::GRAPHIC:
628         if (!CreateGraphicBuffer(d, baseBlock.graphic, sBlockMeta, dFence)) {
629             LOG(ERROR) << "Invalid C2BaseBlock::graphic.";
630             return false;
631         }
632         break;
633     default:
634         LOG(ERROR) << "Invalid C2BaseBlock::type.";
635         return false;
636     }
637 
638     // Parse info
639     std::vector<C2Param*> params;
640     if (!parseParamsBlob(&params, s.info)) {
641         LOG(ERROR) << "Invalid Buffer::info.";
642         return false;
643     }
644     for (C2Param* param : params) {
645         if (param == nullptr) {
646             LOG(ERROR) << "Null param in Buffer::info.";
647             return false;
648         }
649         std::shared_ptr<C2Param> c2param{
650                 C2Param::Copy(*param).release()};
651         if (!c2param) {
652             LOG(ERROR) << "Invalid param in Buffer::info.";
653             return false;
654         }
655         c2_status_t status =
656                 (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
657         if (status != C2_OK) {
658             LOG(ERROR) << "C2Buffer::setInfo failed.";
659             return false;
660         }
661     }
662 
663     return true;
664 }
665 
666 // InfoBuffer -> C2InfoBuffer
667 template <typename InfoBuffer>
objcpy(std::vector<C2InfoBuffer> * d,const InfoBuffer & s,const std::vector<C2BaseBlock> & baseBlocks)668 bool objcpy(
669         std::vector<C2InfoBuffer> *d,
670         const InfoBuffer& s,
671         const std::vector<C2BaseBlock>& baseBlocks) {
672 
673     // Currently, a non-null C2InfoBufer must contain exactly 1 block.
674     if (s.buffer.blocks.size() == 0) {
675         return true;
676     } else if (s.buffer.blocks.size() != 1) {
677         LOG(ERROR) << "Invalid InfoBuffer::Buffer "
678                       "Currently, a C2InfoBuffer must contain exactly 1 block.";
679         return false;
680     }
681 
682     const auto &sBlock = s.buffer.blocks[0];
683     if (sBlock.index >= baseBlocks.size()) {
684         LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].index: "
685                       "Array index out of range.";
686         return false;
687     }
688     const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
689 
690     // Parse meta.
691     std::vector<C2Param*> sBlockMeta;
692     if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
693         LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].meta.";
694         return false;
695     }
696 
697     // Copy fence.
698     C2Fence dFence;
699     if (!objcpy(&dFence, sBlock.fence)) {
700         LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].fence.";
701         return false;
702     }
703 
704     // Construct a block.
705     switch (baseBlock.type) {
706     case C2BaseBlock::LINEAR:
707         if (sBlockMeta.size() == 1 && sBlockMeta[0] != nullptr &&
708             sBlockMeta[0]->size() == sizeof(C2Hal_RangeInfo)) {
709             C2Hal_RangeInfo *rangeInfo =
710                     reinterpret_cast<C2Hal_RangeInfo*>(sBlockMeta[0]);
711             d->emplace_back(C2InfoBuffer::CreateLinearBuffer(
712                     uint32_t(s.index),
713                     baseBlock.linear->share(
714                             rangeInfo->offset, rangeInfo->length, dFence)));
715             return true;
716         }
717         LOG(ERROR) << "Invalid Meta for C2BaseBlock::Linear InfoBuffer.";
718         break;
719     case C2BaseBlock::GRAPHIC:
720         // It's not used now
721         LOG(ERROR) << "Non-Used C2BaseBlock::type for InfoBuffer.";
722         break;
723     default:
724         LOG(ERROR) << "Invalid C2BaseBlock::type for InfoBuffer.";
725         break;
726     }
727 
728     return false;
729 }
730 
731 // FrameData -> C2FrameData
732 template <typename FrameData>
objcpy(C2FrameData * d,const FrameData & s,const std::vector<C2BaseBlock> & baseBlocks)733 bool objcpy(C2FrameData* d, const FrameData& s,
734         const std::vector<C2BaseBlock>& baseBlocks) {
735     d->flags = static_cast<C2FrameData::flags_t>(s.flags);
736     if (!objcpy(&d->ordinal, s.ordinal)) {
737         LOG(ERROR) << "Invalid FrameData::ordinal.";
738         return false;
739     }
740     d->buffers.clear();
741     d->buffers.reserve(s.buffers.size());
742     for (const auto& sBuffer : s.buffers) {
743         std::shared_ptr<C2Buffer> dBuffer;
744         if (!objcpy(&dBuffer, sBuffer, baseBlocks)) {
745             LOG(ERROR) << "Invalid FrameData::buffers.";
746             return false;
747         }
748         d->buffers.emplace_back(dBuffer);
749     }
750 
751     std::vector<C2Param*> params;
752     if (!parseParamsBlob(&params, s.configUpdate)) {
753         LOG(ERROR) << "Invalid FrameData::configUpdate.";
754         return false;
755     }
756     d->configUpdate.clear();
757     for (C2Param* param : params) {
758         d->configUpdate.emplace_back(C2Param::Copy(*param));
759         if (!d->configUpdate.back()) {
760             LOG(ERROR) << "Unexpected error while parsing "
761                           "FrameData::configUpdate.";
762             return false;
763         }
764     }
765 
766     d->infoBuffers.clear();
767     if (s.infoBuffers.size() == 0) {
768         // InfoBuffer is optional
769         return true;
770     }
771     d->infoBuffers.reserve(s.infoBuffers.size());
772     for (const auto &sInfoBuffer: s.infoBuffers) {
773         if (!objcpy(&(d->infoBuffers), sInfoBuffer, baseBlocks)) {
774             LOG(ERROR) << "Invalid Framedata::infoBuffers.";
775             return false;
776         }
777     }
778     return true;
779 }
780 
781 // BaseBlock -> C2BaseBlock
782 template <typename BaseBlock>
783 bool objcpy(C2BaseBlock* d, const BaseBlock& s);
784 
785 // WorkBundle -> std::list<std::unique_ptr<C2Work>>
786 template <typename WorkBundle>
objcpy(std::list<std::unique_ptr<C2Work>> * d,const WorkBundle & s)787 bool objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
788     // Convert BaseBlocks to C2BaseBlocks.
789     std::vector<C2BaseBlock> dBaseBlocks(s.baseBlocks.size());
790     for (size_t i = 0; i < s.baseBlocks.size(); ++i) {
791         if (!objcpy(&dBaseBlocks[i], s.baseBlocks[i])) {
792             LOG(ERROR) << "Invalid WorkBundle::baseBlocks["
793                        << i << "].";
794             return false;
795         }
796     }
797 
798     d->clear();
799     for (const auto& sWork : s.works) {
800         d->emplace_back(std::make_unique<C2Work>());
801         C2Work& dWork = *d->back();
802 
803         // chain info is not in use currently.
804 
805         // input
806         if (!objcpy(&dWork.input, sWork.input, dBaseBlocks)) {
807             LOG(ERROR) << "Invalid Work::input.";
808             return false;
809         }
810 
811         // worklet(s)
812         dWork.worklets.clear();
813         for (const auto& sWorklet : sWork.worklets) {
814             std::unique_ptr<C2Worklet> dWorklet = std::make_unique<C2Worklet>();
815 
816             // component id
817             dWorklet->component = static_cast<c2_node_id_t>(
818                     sWorklet.componentId);
819 
820             // tunings
821             if (!_copyParamsFromBlob(&dWorklet->tunings, sWorklet.tunings)) {
822                 LOG(ERROR) << "Invalid Worklet::tunings";
823                 return false;
824             }
825 
826             // failures
827             dWorklet->failures.clear();
828             dWorklet->failures.reserve(sWorklet.failures.size());
829             for (const auto& sFailure : sWorklet.failures) {
830                 std::unique_ptr<C2SettingResult> dFailure;
831                 if (!objcpy(&dFailure, sFailure)) {
832                     LOG(ERROR) << "Invalid Worklet::failures.";
833                     return false;
834                 }
835                 dWorklet->failures.emplace_back(std::move(dFailure));
836             }
837 
838             // output
839             if (!objcpy(&dWorklet->output, sWorklet.output, dBaseBlocks)) {
840                 LOG(ERROR) << "Invalid Worklet::output.";
841                 return false;
842             }
843 
844             dWork.worklets.emplace_back(std::move(dWorklet));
845         }
846 
847         // workletsProcessed
848         dWork.workletsProcessed = sWork.workletsProcessed;
849 
850         // result
851         dWork.result = GetStatus(sWork.result);
852     }
853 
854     return true;
855 }
856 
857 // BufferQueue-Based Block Operations
858 // ==================================
859 
860 // Call before transferring block to other processes.
861 //
862 // The given block is ready to transfer to other processes. This will guarantee
863 // the given block data is not mutated by bufferqueue migration.
864 bool BeginTransferBufferQueueBlock(const C2ConstGraphicBlock& block);
865 
866 // Call beginTransferBufferQueueBlock() on blocks in the given workList.
867 // processInput determines whether input blocks are yielded. processOutput
868 // works similarly on output blocks. (The default value of processInput is
869 // false while the default value of processOutput is true. This implies that in
870 // most cases, only output buffers contain bufferqueue-based blocks.)
871 void BeginTransferBufferQueueBlocks(
872         const std::list<std::unique_ptr<C2Work>>& workList,
873         bool processInput = false,
874         bool processOutput = true);
875 
876 // Call after transferring block is finished and make sure that
877 // beginTransferBufferQueueBlock() is called before.
878 //
879 // The transfer of given block is finished. If transfer is successful the given
880 // block is not owned by process anymore. Since transfer is finished the given
881 // block data is OK to mutate by bufferqueue migration after this call.
882 bool EndTransferBufferQueueBlock(const C2ConstGraphicBlock& block,
883                                  bool transfer);
884 
885 // Call endTransferBufferQueueBlock() on blocks in the given workList.
886 // processInput determines whether input blocks are yielded. processOutput
887 // works similarly on output blocks. (The default value of processInput is
888 // false while the default value of processOutput is true. This implies that in
889 // most cases, only output buffers contain bufferqueue-based blocks.)
890 void EndTransferBufferQueueBlocks(
891         const std::list<std::unique_ptr<C2Work>>& workList,
892         bool transfer,
893         bool processInput = false,
894         bool processOutput = true);
895 
896 // The given block is ready to be rendered. the given block is not owned by
897 // process anymore. If migration is in progress, this returns false in order
898 // not to render.
899 bool DisplayBufferQueueBlock(const C2ConstGraphicBlock& block);
900 
901 }  // namespace android
902 
903 #endif  // CODEC2_COMMON_BUFFER_TYPES_H
904