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