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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "Codec2Buffer"
19 #include <utils/Log.h>
20 
21 #include <android/hardware/cas/native/1.0/types.h>
22 #include <android/hardware/drm/1.0/types.h>
23 #include <hidlmemory/FrameworkUtils.h>
24 #include <media/hardware/HardwareAPI.h>
25 #include <media/stagefright/CodecBase.h>
26 #include <media/stagefright/MediaCodecConstants.h>
27 #include <media/stagefright/foundation/ABuffer.h>
28 #include <media/stagefright/foundation/AMessage.h>
29 #include <media/stagefright/foundation/AUtils.h>
30 #include <mediadrm/ICrypto.h>
31 #include <nativebase/nativebase.h>
32 #include <ui/Fence.h>
33 
34 #include <C2AllocatorGralloc.h>
35 #include <C2BlockInternal.h>
36 #include <C2Debug.h>
37 
38 #include "Codec2Buffer.h"
39 
40 namespace android {
41 
42 // Codec2Buffer
43 
canCopyLinear(const std::shared_ptr<C2Buffer> & buffer) const44 bool Codec2Buffer::canCopyLinear(const std::shared_ptr<C2Buffer> &buffer) const {
45     if (const_cast<Codec2Buffer *>(this)->base() == nullptr) {
46         return false;
47     }
48     if (!buffer) {
49         // Nothing to copy, so we can copy by doing nothing.
50         return true;
51     }
52     if (buffer->data().type() != C2BufferData::LINEAR) {
53         return false;
54     }
55     if (buffer->data().linearBlocks().size() == 0u) {
56         // Nothing to copy, so we can copy by doing nothing.
57         return true;
58     } else if (buffer->data().linearBlocks().size() > 1u) {
59         // We don't know how to copy more than one blocks.
60         return false;
61     }
62     if (buffer->data().linearBlocks()[0].size() > capacity()) {
63         // It won't fit.
64         return false;
65     }
66     return true;
67 }
68 
copyLinear(const std::shared_ptr<C2Buffer> & buffer)69 bool Codec2Buffer::copyLinear(const std::shared_ptr<C2Buffer> &buffer) {
70     // We assume that all canCopyLinear() checks passed.
71     if (!buffer || buffer->data().linearBlocks().size() == 0u
72             || buffer->data().linearBlocks()[0].size() == 0u) {
73         setRange(0, 0);
74         return true;
75     }
76     C2ReadView view = buffer->data().linearBlocks()[0].map().get();
77     if (view.error() != C2_OK) {
78         ALOGD("Error while mapping: %d", view.error());
79         return false;
80     }
81     if (view.capacity() > capacity()) {
82         ALOGD("C2ConstLinearBlock lied --- it actually doesn't fit: view(%u) > this(%zu)",
83                 view.capacity(), capacity());
84         return false;
85     }
86     memcpy(base(), view.data(), view.capacity());
87     setRange(0, view.capacity());
88     return true;
89 }
90 
setImageData(const sp<ABuffer> & imageData)91 void Codec2Buffer::setImageData(const sp<ABuffer> &imageData) {
92     mImageData = imageData;
93 }
94 
95 // LocalLinearBuffer
96 
canCopy(const std::shared_ptr<C2Buffer> & buffer) const97 bool LocalLinearBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
98     return canCopyLinear(buffer);
99 }
100 
copy(const std::shared_ptr<C2Buffer> & buffer)101 bool LocalLinearBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
102     return copyLinear(buffer);
103 }
104 
105 // DummyContainerBuffer
106 
107 static uint8_t sDummyByte[1] = { 0 };
108 
DummyContainerBuffer(const sp<AMessage> & format,const std::shared_ptr<C2Buffer> & buffer)109 DummyContainerBuffer::DummyContainerBuffer(
110         const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer)
111     : Codec2Buffer(format, new ABuffer(sDummyByte, 1)),
112       mBufferRef(buffer) {
113     setRange(0, buffer ? 1 : 0);
114 }
115 
asC2Buffer()116 std::shared_ptr<C2Buffer> DummyContainerBuffer::asC2Buffer() {
117     return mBufferRef;
118 }
119 
clearC2BufferRefs()120 void DummyContainerBuffer::clearC2BufferRefs() {
121     mBufferRef.reset();
122 }
123 
canCopy(const std::shared_ptr<C2Buffer> &) const124 bool DummyContainerBuffer::canCopy(const std::shared_ptr<C2Buffer> &) const {
125     return !mBufferRef;
126 }
127 
copy(const std::shared_ptr<C2Buffer> & buffer)128 bool DummyContainerBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
129     mBufferRef = buffer;
130     setRange(0, mBufferRef ? 1 : 0);
131     return true;
132 }
133 
134 // LinearBlockBuffer
135 
136 // static
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2LinearBlock> & block)137 sp<LinearBlockBuffer> LinearBlockBuffer::Allocate(
138         const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block) {
139     C2WriteView writeView(block->map().get());
140     if (writeView.error() != C2_OK) {
141         return nullptr;
142     }
143     return new LinearBlockBuffer(format, std::move(writeView), block);
144 }
145 
asC2Buffer()146 std::shared_ptr<C2Buffer> LinearBlockBuffer::asC2Buffer() {
147     return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
148 }
149 
canCopy(const std::shared_ptr<C2Buffer> & buffer) const150 bool LinearBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
151     return canCopyLinear(buffer);
152 }
153 
copy(const std::shared_ptr<C2Buffer> & buffer)154 bool LinearBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
155     return copyLinear(buffer);
156 }
157 
LinearBlockBuffer(const sp<AMessage> & format,C2WriteView && writeView,const std::shared_ptr<C2LinearBlock> & block)158 LinearBlockBuffer::LinearBlockBuffer(
159         const sp<AMessage> &format,
160         C2WriteView&& writeView,
161         const std::shared_ptr<C2LinearBlock> &block)
162     : Codec2Buffer(format, new ABuffer(writeView.data(), writeView.size())),
163       mWriteView(writeView),
164       mBlock(block) {
165 }
166 
167 // ConstLinearBlockBuffer
168 
169 // static
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2Buffer> & buffer)170 sp<ConstLinearBlockBuffer> ConstLinearBlockBuffer::Allocate(
171         const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer) {
172     if (!buffer
173             || buffer->data().type() != C2BufferData::LINEAR
174             || buffer->data().linearBlocks().size() != 1u) {
175         return nullptr;
176     }
177     C2ReadView readView(buffer->data().linearBlocks()[0].map().get());
178     if (readView.error() != C2_OK) {
179         return nullptr;
180     }
181     return new ConstLinearBlockBuffer(format, std::move(readView), buffer);
182 }
183 
ConstLinearBlockBuffer(const sp<AMessage> & format,C2ReadView && readView,const std::shared_ptr<C2Buffer> & buffer)184 ConstLinearBlockBuffer::ConstLinearBlockBuffer(
185         const sp<AMessage> &format,
186         C2ReadView&& readView,
187         const std::shared_ptr<C2Buffer> &buffer)
188     : Codec2Buffer(format, new ABuffer(
189             // NOTE: ABuffer only takes non-const pointer but this data is
190             //       supposed to be read-only.
191             const_cast<uint8_t *>(readView.data()), readView.capacity())),
192       mReadView(readView),
193       mBufferRef(buffer) {
194 }
195 
asC2Buffer()196 std::shared_ptr<C2Buffer> ConstLinearBlockBuffer::asC2Buffer() {
197     return mBufferRef;
198 }
199 
clearC2BufferRefs()200 void ConstLinearBlockBuffer::clearC2BufferRefs() {
201     mBufferRef.reset();
202 }
203 
204 // GraphicView2MediaImageConverter
205 
206 namespace {
207 
208 class GraphicView2MediaImageConverter {
209 public:
210     /**
211      * Creates a C2GraphicView <=> MediaImage converter
212      *
213      * \param view C2GraphicView object
214      * \param colorFormat desired SDK color format for the MediaImage (if this is a flexible format,
215      *        an attempt is made to simply represent the graphic view as a flexible SDK format
216      *        without a memcpy)
217      * \param copy whether the converter is used for copy or not
218      */
GraphicView2MediaImageConverter(const C2GraphicView & view,int32_t colorFormat,bool copy)219     GraphicView2MediaImageConverter(
220             const C2GraphicView &view, int32_t colorFormat, bool copy)
221         : mInitCheck(NO_INIT),
222           mView(view),
223           mWidth(view.width()),
224           mHeight(view.height()),
225           mColorFormat(colorFormat),
226           mAllocatedDepth(0),
227           mBackBufferSize(0),
228           mMediaImage(new ABuffer(sizeof(MediaImage2))) {
229         if (view.error() != C2_OK) {
230             ALOGD("Converter: view.error() = %d", view.error());
231             mInitCheck = BAD_VALUE;
232             return;
233         }
234         MediaImage2 *mediaImage = (MediaImage2 *)mMediaImage->base();
235         const C2PlanarLayout &layout = view.layout();
236         if (layout.numPlanes == 0) {
237             ALOGD("Converter: 0 planes");
238             mInitCheck = BAD_VALUE;
239             return;
240         }
241         memset(mediaImage, 0, sizeof(*mediaImage));
242         mAllocatedDepth = layout.planes[0].allocatedDepth;
243         uint32_t bitDepth = layout.planes[0].bitDepth;
244 
245         // align width and height to support subsampling cleanly
246         uint32_t stride = align(view.crop().width, 2) * divUp(layout.planes[0].allocatedDepth, 8u);
247         uint32_t vStride = align(view.crop().height, 2);
248 
249         switch (layout.type) {
250             case C2PlanarLayout::TYPE_YUV:
251                 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV;
252                 if (layout.numPlanes != 3) {
253                     ALOGD("Converter: %d planes for YUV layout", layout.numPlanes);
254                     mInitCheck = BAD_VALUE;
255                     return;
256                 }
257                 if (layout.planes[0].channel != C2PlaneInfo::CHANNEL_Y
258                         || layout.planes[1].channel != C2PlaneInfo::CHANNEL_CB
259                         || layout.planes[2].channel != C2PlaneInfo::CHANNEL_CR
260                         || layout.planes[0].colSampling != 1
261                         || layout.planes[0].rowSampling != 1
262                         || layout.planes[1].colSampling != 2
263                         || layout.planes[1].rowSampling != 2
264                         || layout.planes[2].colSampling != 2
265                         || layout.planes[2].rowSampling != 2) {
266                     ALOGD("Converter: not YUV420 for YUV layout");
267                     mInitCheck = BAD_VALUE;
268                     return;
269                 }
270                 switch (mColorFormat) {
271                     case COLOR_FormatYUV420Flexible:
272                         if (!copy) {
273                             // try to map directly. check if the planes are near one another
274                             const uint8_t *minPtr = mView.data()[0];
275                             const uint8_t *maxPtr = mView.data()[0];
276                             int32_t planeSize = 0;
277                             for (uint32_t i = 0; i < layout.numPlanes; ++i) {
278                                 const C2PlaneInfo &plane = layout.planes[i];
279                                 ssize_t minOffset = plane.minOffset(mWidth, mHeight);
280                                 ssize_t maxOffset = plane.maxOffset(mWidth, mHeight);
281                                 if (minPtr > mView.data()[i] + minOffset) {
282                                     minPtr = mView.data()[i] + minOffset;
283                                 }
284                                 if (maxPtr < mView.data()[i] + maxOffset) {
285                                     maxPtr = mView.data()[i] + maxOffset;
286                                 }
287                                 planeSize += std::abs(plane.rowInc) * align(mHeight, 64)
288                                         / plane.rowSampling / plane.colSampling
289                                         * divUp(mAllocatedDepth, 8u);
290                             }
291 
292                             if ((maxPtr - minPtr + 1) <= planeSize) {
293                                 // FIXME: this is risky as reading/writing data out of bound results
294                                 //        in an undefined behavior, but gralloc does assume a
295                                 //        contiguous mapping
296                                 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
297                                     const C2PlaneInfo &plane = layout.planes[i];
298                                     mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
299                                     mediaImage->mPlane[i].mColInc = plane.colInc;
300                                     mediaImage->mPlane[i].mRowInc = plane.rowInc;
301                                     mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
302                                     mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
303                                 }
304                                 mWrapped = new ABuffer(const_cast<uint8_t *>(minPtr),
305                                                        maxPtr - minPtr + 1);
306                                 break;
307                             }
308                         }
309                         [[fallthrough]];
310 
311                     case COLOR_FormatYUV420Planar:
312                     case COLOR_FormatYUV420PackedPlanar:
313                         mediaImage->mPlane[mediaImage->Y].mOffset = 0;
314                         mediaImage->mPlane[mediaImage->Y].mColInc = 1;
315                         mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
316                         mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
317                         mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
318 
319                         mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
320                         mediaImage->mPlane[mediaImage->U].mColInc = 1;
321                         mediaImage->mPlane[mediaImage->U].mRowInc = stride / 2;
322                         mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
323                         mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
324 
325                         mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 5 / 4;
326                         mediaImage->mPlane[mediaImage->V].mColInc = 1;
327                         mediaImage->mPlane[mediaImage->V].mRowInc = stride / 2;
328                         mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
329                         mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
330                         break;
331 
332                     case COLOR_FormatYUV420SemiPlanar:
333                     case COLOR_FormatYUV420PackedSemiPlanar:
334                         mediaImage->mPlane[mediaImage->Y].mOffset = 0;
335                         mediaImage->mPlane[mediaImage->Y].mColInc = 1;
336                         mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
337                         mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
338                         mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
339 
340                         mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
341                         mediaImage->mPlane[mediaImage->U].mColInc = 2;
342                         mediaImage->mPlane[mediaImage->U].mRowInc = stride;
343                         mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
344                         mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
345 
346                         mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride + 1;
347                         mediaImage->mPlane[mediaImage->V].mColInc = 2;
348                         mediaImage->mPlane[mediaImage->V].mRowInc = stride;
349                         mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
350                         mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
351                         break;
352 
353                     default:
354                         ALOGD("Converter: incompactible color format (%d) for YUV layout", mColorFormat);
355                         mInitCheck = BAD_VALUE;
356                         return;
357                 }
358                 break;
359             case C2PlanarLayout::TYPE_YUVA:
360                 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUVA;
361                 // We don't have an SDK YUVA format
362                 ALOGD("Converter: incompactible color format (%d) for YUVA layout", mColorFormat);
363                 mInitCheck = BAD_VALUE;
364                 return;
365             case C2PlanarLayout::TYPE_RGB:
366                 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGB;
367                 switch (mColorFormat) {
368                     // TODO media image
369                     case COLOR_FormatRGBFlexible:
370                     case COLOR_Format24bitBGR888:
371                     case COLOR_Format24bitRGB888:
372                         break;
373                     default:
374                         ALOGD("Converter: incompactible color format (%d) for RGB layout", mColorFormat);
375                         mInitCheck = BAD_VALUE;
376                         return;
377                 }
378                 if (layout.numPlanes != 3) {
379                     ALOGD("Converter: %d planes for RGB layout", layout.numPlanes);
380                     mInitCheck = BAD_VALUE;
381                     return;
382                 }
383                 break;
384             case C2PlanarLayout::TYPE_RGBA:
385                 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_RGBA;
386                 switch (mColorFormat) {
387                     // TODO media image
388                     case COLOR_FormatRGBAFlexible:
389                     case COLOR_Format32bitABGR8888:
390                     case COLOR_Format32bitARGB8888:
391                     case COLOR_Format32bitBGRA8888:
392                         break;
393                     default:
394                         ALOGD("Incompactible color format (%d) for RGBA layout", mColorFormat);
395                         mInitCheck = BAD_VALUE;
396                         return;
397                 }
398                 if (layout.numPlanes != 4) {
399                     ALOGD("Converter: %d planes for RGBA layout", layout.numPlanes);
400                     mInitCheck = BAD_VALUE;
401                     return;
402                 }
403                 break;
404             default:
405                 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
406                 ALOGD("Unknown layout");
407                 mInitCheck = BAD_VALUE;
408                 return;
409         }
410         mediaImage->mNumPlanes = layout.numPlanes;
411         mediaImage->mWidth = view.crop().width;
412         mediaImage->mHeight = view.crop().height;
413         mediaImage->mBitDepth = bitDepth;
414         mediaImage->mBitDepthAllocated = mAllocatedDepth;
415 
416         uint32_t bufferSize = 0;
417         for (uint32_t i = 0; i < layout.numPlanes; ++i) {
418             const C2PlaneInfo &plane = layout.planes[i];
419             if (plane.allocatedDepth < plane.bitDepth
420                     || plane.rightShift != plane.allocatedDepth - plane.bitDepth) {
421                 ALOGD("rightShift value of %u unsupported", plane.rightShift);
422                 mInitCheck = BAD_VALUE;
423                 return;
424             }
425             if (plane.allocatedDepth > 8 && plane.endianness != C2PlaneInfo::NATIVE) {
426                 ALOGD("endianness value of %u unsupported", plane.endianness);
427                 mInitCheck = BAD_VALUE;
428                 return;
429             }
430             if (plane.allocatedDepth != mAllocatedDepth || plane.bitDepth != bitDepth) {
431                 ALOGV("different allocatedDepth/bitDepth per plane unsupported");
432                 mInitCheck = BAD_VALUE;
433                 return;
434             }
435             bufferSize += stride * vStride
436                     / plane.rowSampling / plane.colSampling;
437         }
438 
439         mBackBufferSize = bufferSize;
440         mInitCheck = OK;
441     }
442 
initCheck() const443     status_t initCheck() const { return mInitCheck; }
444 
backBufferSize() const445     uint32_t backBufferSize() const { return mBackBufferSize; }
446 
447     /**
448      * Wrap C2GraphicView using a MediaImage2. Note that if not wrapped, the content is not mapped
449      * in this function --- the caller should use CopyGraphicView2MediaImage() function to copy the
450      * data into a backing buffer explicitly.
451      *
452      * \return media buffer. This is null if wrapping failed.
453      */
wrap() const454     sp<ABuffer> wrap() const {
455         if (mBackBuffer == nullptr) {
456             return mWrapped;
457         }
458         return nullptr;
459     }
460 
setBackBuffer(const sp<ABuffer> & backBuffer)461     bool setBackBuffer(const sp<ABuffer> &backBuffer) {
462         if (backBuffer == nullptr) {
463             return false;
464         }
465         if (backBuffer->capacity() < mBackBufferSize) {
466             return false;
467         }
468         backBuffer->setRange(0, mBackBufferSize);
469         mBackBuffer = backBuffer;
470         return true;
471     }
472 
473     /**
474      * Copy C2GraphicView to MediaImage2.
475      */
copyToMediaImage()476     status_t copyToMediaImage() {
477         if (mInitCheck != OK) {
478             return mInitCheck;
479         }
480         return ImageCopy(mBackBuffer->base(), getMediaImage(), mView);
481     }
482 
imageData() const483     const sp<ABuffer> &imageData() const { return mMediaImage; }
484 
485 private:
486     status_t mInitCheck;
487 
488     const C2GraphicView mView;
489     uint32_t mWidth;
490     uint32_t mHeight;
491     int32_t mColorFormat;  ///< SDK color format for MediaImage
492     sp<ABuffer> mWrapped;  ///< wrapped buffer (if we can map C2Buffer to an ABuffer)
493     uint32_t mAllocatedDepth;
494     uint32_t mBackBufferSize;
495     sp<ABuffer> mMediaImage;
496     std::function<sp<ABuffer>(size_t)> mAlloc;
497 
498     sp<ABuffer> mBackBuffer;    ///< backing buffer if we have to copy C2Buffer <=> ABuffer
499 
getMediaImage()500     MediaImage2 *getMediaImage() {
501         return (MediaImage2 *)mMediaImage->base();
502     }
503 };
504 
505 }  // namespace
506 
507 // GraphicBlockBuffer
508 
509 // static
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2GraphicBlock> & block,std::function<sp<ABuffer> (size_t)> alloc)510 sp<GraphicBlockBuffer> GraphicBlockBuffer::Allocate(
511         const sp<AMessage> &format,
512         const std::shared_ptr<C2GraphicBlock> &block,
513         std::function<sp<ABuffer>(size_t)> alloc) {
514     C2GraphicView view(block->map().get());
515     if (view.error() != C2_OK) {
516         ALOGD("C2GraphicBlock::map failed: %d", view.error());
517         return nullptr;
518     }
519 
520     int32_t colorFormat = COLOR_FormatYUV420Flexible;
521     (void)format->findInt32("color-format", &colorFormat);
522 
523     GraphicView2MediaImageConverter converter(view, colorFormat, false /* copy */);
524     if (converter.initCheck() != OK) {
525         ALOGD("Converter init failed: %d", converter.initCheck());
526         return nullptr;
527     }
528     bool wrapped = true;
529     sp<ABuffer> buffer = converter.wrap();
530     if (buffer == nullptr) {
531         buffer = alloc(converter.backBufferSize());
532         if (!converter.setBackBuffer(buffer)) {
533             ALOGD("Converter failed to set back buffer");
534             return nullptr;
535         }
536         wrapped = false;
537     }
538     return new GraphicBlockBuffer(
539             format,
540             buffer,
541             std::move(view),
542             block,
543             converter.imageData(),
544             wrapped);
545 }
546 
GraphicBlockBuffer(const sp<AMessage> & format,const sp<ABuffer> & buffer,C2GraphicView && view,const std::shared_ptr<C2GraphicBlock> & block,const sp<ABuffer> & imageData,bool wrapped)547 GraphicBlockBuffer::GraphicBlockBuffer(
548         const sp<AMessage> &format,
549         const sp<ABuffer> &buffer,
550         C2GraphicView &&view,
551         const std::shared_ptr<C2GraphicBlock> &block,
552         const sp<ABuffer> &imageData,
553         bool wrapped)
554     : Codec2Buffer(format, buffer),
555       mView(view),
556       mBlock(block),
557       mWrapped(wrapped) {
558     setImageData(imageData);
559 }
560 
asC2Buffer()561 std::shared_ptr<C2Buffer> GraphicBlockBuffer::asC2Buffer() {
562     uint32_t width = mView.width();
563     uint32_t height = mView.height();
564     if (!mWrapped) {
565         (void)ImageCopy(mView, base(), imageData());
566     }
567     return C2Buffer::CreateGraphicBuffer(
568             mBlock->share(C2Rect(width, height), C2Fence()));
569 }
570 
571 // GraphicMetadataBuffer
GraphicMetadataBuffer(const sp<AMessage> & format,const std::shared_ptr<C2Allocator> & alloc)572 GraphicMetadataBuffer::GraphicMetadataBuffer(
573         const sp<AMessage> &format,
574         const std::shared_ptr<C2Allocator> &alloc)
575     : Codec2Buffer(format, new ABuffer(sizeof(VideoNativeMetadata))),
576       mAlloc(alloc) {
577     ((VideoNativeMetadata *)base())->pBuffer = nullptr;
578 }
579 
asC2Buffer()580 std::shared_ptr<C2Buffer> GraphicMetadataBuffer::asC2Buffer() {
581 #ifndef __LP64__
582     VideoNativeMetadata *meta = (VideoNativeMetadata *)base();
583     ANativeWindowBuffer *buffer = (ANativeWindowBuffer *)meta->pBuffer;
584     if (buffer == nullptr) {
585         ALOGD("VideoNativeMetadata contains null buffer");
586         return nullptr;
587     }
588 
589     ALOGV("VideoNativeMetadata: %dx%d", buffer->width, buffer->height);
590     C2Handle *handle = WrapNativeCodec2GrallocHandle(
591             buffer->handle,
592             buffer->width,
593             buffer->height,
594             buffer->format,
595             buffer->usage,
596             buffer->stride);
597     std::shared_ptr<C2GraphicAllocation> alloc;
598     c2_status_t err = mAlloc->priorGraphicAllocation(handle, &alloc);
599     if (err != C2_OK) {
600         ALOGD("Failed to wrap VideoNativeMetadata into C2GraphicAllocation");
601         return nullptr;
602     }
603     std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
604 
605     meta->pBuffer = 0;
606     // TODO: wrap this in C2Fence so that the component can wait when it
607     //       actually starts processing.
608     if (meta->nFenceFd >= 0) {
609         sp<Fence> fence(new Fence(meta->nFenceFd));
610         fence->waitForever(LOG_TAG);
611     }
612     return C2Buffer::CreateGraphicBuffer(
613             block->share(C2Rect(buffer->width, buffer->height), C2Fence()));
614 #else
615     ALOGE("GraphicMetadataBuffer does not work on 64-bit arch");
616     return nullptr;
617 #endif
618 }
619 
620 // ConstGraphicBlockBuffer
621 
622 // static
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2Buffer> & buffer,std::function<sp<ABuffer> (size_t)> alloc)623 sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::Allocate(
624         const sp<AMessage> &format,
625         const std::shared_ptr<C2Buffer> &buffer,
626         std::function<sp<ABuffer>(size_t)> alloc) {
627     if (!buffer
628             || buffer->data().type() != C2BufferData::GRAPHIC
629             || buffer->data().graphicBlocks().size() != 1u) {
630         ALOGD("C2Buffer precond fail");
631         return nullptr;
632     }
633     std::unique_ptr<const C2GraphicView> view(std::make_unique<const C2GraphicView>(
634             buffer->data().graphicBlocks()[0].map().get()));
635     std::unique_ptr<const C2GraphicView> holder;
636 
637     int32_t colorFormat = COLOR_FormatYUV420Flexible;
638     (void)format->findInt32("color-format", &colorFormat);
639 
640     GraphicView2MediaImageConverter converter(*view, colorFormat, false /* copy */);
641     if (converter.initCheck() != OK) {
642         ALOGD("Converter init failed: %d", converter.initCheck());
643         return nullptr;
644     }
645     bool wrapped = true;
646     sp<ABuffer> aBuffer = converter.wrap();
647     if (aBuffer == nullptr) {
648         aBuffer = alloc(converter.backBufferSize());
649         if (!converter.setBackBuffer(aBuffer)) {
650             ALOGD("Converter failed to set back buffer");
651             return nullptr;
652         }
653         wrapped = false;
654         converter.copyToMediaImage();
655         // We don't need the view.
656         holder = std::move(view);
657     }
658     return new ConstGraphicBlockBuffer(
659             format,
660             aBuffer,
661             std::move(view),
662             buffer,
663             converter.imageData(),
664             wrapped);
665 }
666 
667 // static
AllocateEmpty(const sp<AMessage> & format,std::function<sp<ABuffer> (size_t)> alloc)668 sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::AllocateEmpty(
669         const sp<AMessage> &format,
670         std::function<sp<ABuffer>(size_t)> alloc) {
671     int32_t width, height;
672     if (!format->findInt32("width", &width)
673             || !format->findInt32("height", &height)) {
674         ALOGD("format had no width / height");
675         return nullptr;
676     }
677     // NOTE: we currently only support YUV420 formats for byte-buffer mode.
678     sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * 3 / 2));
679     return new ConstGraphicBlockBuffer(
680             format,
681             aBuffer,
682             nullptr,
683             nullptr,
684             nullptr,
685             false);
686 }
687 
ConstGraphicBlockBuffer(const sp<AMessage> & format,const sp<ABuffer> & aBuffer,std::unique_ptr<const C2GraphicView> && view,const std::shared_ptr<C2Buffer> & buffer,const sp<ABuffer> & imageData,bool wrapped)688 ConstGraphicBlockBuffer::ConstGraphicBlockBuffer(
689         const sp<AMessage> &format,
690         const sp<ABuffer> &aBuffer,
691         std::unique_ptr<const C2GraphicView> &&view,
692         const std::shared_ptr<C2Buffer> &buffer,
693         const sp<ABuffer> &imageData,
694         bool wrapped)
695     : Codec2Buffer(format, aBuffer),
696       mView(std::move(view)),
697       mBufferRef(buffer),
698       mWrapped(wrapped) {
699     setImageData(imageData);
700 }
701 
asC2Buffer()702 std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
703     return mBufferRef;
704 }
705 
clearC2BufferRefs()706 void ConstGraphicBlockBuffer::clearC2BufferRefs() {
707     mView.reset();
708     mBufferRef.reset();
709 }
710 
canCopy(const std::shared_ptr<C2Buffer> & buffer) const711 bool ConstGraphicBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
712     if (mWrapped || mBufferRef) {
713         ALOGD("ConstGraphicBlockBuffer::canCopy: %swrapped ; buffer ref %s",
714                 mWrapped ? "" : "not ", mBufferRef ? "exists" : "doesn't exist");
715         return false;
716     }
717     if (!buffer) {
718         // Nothing to copy, so we can copy by doing nothing.
719         return true;
720     }
721     if (buffer->data().type() != C2BufferData::GRAPHIC) {
722         ALOGD("ConstGraphicBlockBuffer::canCopy: buffer precondition unsatisfied");
723         return false;
724     }
725     if (buffer->data().graphicBlocks().size() == 0) {
726         return true;
727     } else if (buffer->data().graphicBlocks().size() != 1u) {
728         ALOGD("ConstGraphicBlockBuffer::canCopy: too many blocks");
729         return false;
730     }
731 
732     int32_t colorFormat = COLOR_FormatYUV420Flexible;
733     // FIXME: format() is not const, but we cannot change it, so do a const cast here
734     const_cast<ConstGraphicBlockBuffer *>(this)->format()->findInt32("color-format", &colorFormat);
735 
736     GraphicView2MediaImageConverter converter(
737             buffer->data().graphicBlocks()[0].map().get(), colorFormat, true /* copy */);
738     if (converter.initCheck() != OK) {
739         ALOGD("ConstGraphicBlockBuffer::canCopy: converter init failed: %d", converter.initCheck());
740         return false;
741     }
742     if (converter.backBufferSize() > capacity()) {
743         ALOGD("ConstGraphicBlockBuffer::canCopy: insufficient capacity: req %u has %zu",
744                 converter.backBufferSize(), capacity());
745         return false;
746     }
747     return true;
748 }
749 
copy(const std::shared_ptr<C2Buffer> & buffer)750 bool ConstGraphicBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
751     if (!buffer || buffer->data().graphicBlocks().size() == 0) {
752         setRange(0, 0);
753         return true;
754     }
755     int32_t colorFormat = COLOR_FormatYUV420Flexible;
756     format()->findInt32("color-format", &colorFormat);
757 
758     GraphicView2MediaImageConverter converter(
759             buffer->data().graphicBlocks()[0].map().get(), colorFormat, true /* copy */);
760     if (converter.initCheck() != OK) {
761         ALOGD("ConstGraphicBlockBuffer::copy: converter init failed: %d", converter.initCheck());
762         return false;
763     }
764     sp<ABuffer> aBuffer = new ABuffer(base(), capacity());
765     if (!converter.setBackBuffer(aBuffer)) {
766         ALOGD("ConstGraphicBlockBuffer::copy: set back buffer failed");
767         return false;
768     }
769     setRange(0, aBuffer->size());  // align size info
770     converter.copyToMediaImage();
771     setImageData(converter.imageData());
772     mBufferRef = buffer;
773     return true;
774 }
775 
776 // EncryptedLinearBlockBuffer
777 
EncryptedLinearBlockBuffer(const sp<AMessage> & format,const std::shared_ptr<C2LinearBlock> & block,const sp<IMemory> & memory,int32_t heapSeqNum)778 EncryptedLinearBlockBuffer::EncryptedLinearBlockBuffer(
779         const sp<AMessage> &format,
780         const std::shared_ptr<C2LinearBlock> &block,
781         const sp<IMemory> &memory,
782         int32_t heapSeqNum)
783     // TODO: Using unsecurePointer() has some associated security pitfalls
784     //       (see declaration for details).
785     //       Either document why it is safe in this case or address the
786     //       issue (e.g. by copying).
787     : Codec2Buffer(format, new ABuffer(memory->unsecurePointer(), memory->size())),
788       mBlock(block),
789       mMemory(memory),
790       mHeapSeqNum(heapSeqNum) {
791 }
792 
asC2Buffer()793 std::shared_ptr<C2Buffer> EncryptedLinearBlockBuffer::asC2Buffer() {
794     return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
795 }
796 
fillSourceBuffer(hardware::drm::V1_0::SharedBuffer * source)797 void EncryptedLinearBlockBuffer::fillSourceBuffer(
798         hardware::drm::V1_0::SharedBuffer *source) {
799     BufferChannelBase::IMemoryToSharedBuffer(mMemory, mHeapSeqNum, source);
800 }
801 
fillSourceBuffer(hardware::cas::native::V1_0::SharedBuffer * source)802 void EncryptedLinearBlockBuffer::fillSourceBuffer(
803         hardware::cas::native::V1_0::SharedBuffer *source) {
804     ssize_t offset;
805     size_t size;
806 
807     mHidlMemory = hardware::fromHeap(mMemory->getMemory(&offset, &size));
808     source->heapBase = *mHidlMemory;
809     source->offset = offset;
810     source->size = size;
811 }
812 
copyDecryptedContent(const sp<IMemory> & decrypted,size_t length)813 bool EncryptedLinearBlockBuffer::copyDecryptedContent(
814         const sp<IMemory> &decrypted, size_t length) {
815     C2WriteView view = mBlock->map().get();
816     if (view.error() != C2_OK) {
817         return false;
818     }
819     if (view.size() < length) {
820         return false;
821     }
822     memcpy(view.data(), decrypted->unsecurePointer(), length);
823     return true;
824 }
825 
copyDecryptedContentFromMemory(size_t length)826 bool EncryptedLinearBlockBuffer::copyDecryptedContentFromMemory(size_t length) {
827     return copyDecryptedContent(mMemory, length);
828 }
829 
handle() const830 native_handle_t *EncryptedLinearBlockBuffer::handle() const {
831     return const_cast<native_handle_t *>(mBlock->handle());
832 }
833 
834 }  // namespace android
835