• 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 <android-base/properties.h>
22 #include <android/hardware/cas/native/1.0/types.h>
23 #include <android/hardware/drm/1.0/types.h>
24 #include <hidlmemory/FrameworkUtils.h>
25 #include <media/hardware/HardwareAPI.h>
26 #include <media/stagefright/CodecBase.h>
27 #include <media/stagefright/MediaCodecConstants.h>
28 #include <media/stagefright/foundation/ABuffer.h>
29 #include <media/stagefright/foundation/AMessage.h>
30 #include <media/stagefright/foundation/AUtils.h>
31 #include <mediadrm/ICrypto.h>
32 #include <nativebase/nativebase.h>
33 #include <ui/Fence.h>
34 
35 #include <C2AllocatorGralloc.h>
36 #include <C2BlockInternal.h>
37 #include <C2Debug.h>
38 
39 #include "Codec2Buffer.h"
40 
41 namespace android {
42 
43 // Codec2Buffer
44 
canCopyLinear(const std::shared_ptr<C2Buffer> & buffer) const45 bool Codec2Buffer::canCopyLinear(const std::shared_ptr<C2Buffer> &buffer) const {
46     if (const_cast<Codec2Buffer *>(this)->base() == nullptr) {
47         return false;
48     }
49     if (!buffer) {
50         // Nothing to copy, so we can copy by doing nothing.
51         return true;
52     }
53     if (buffer->data().type() != C2BufferData::LINEAR) {
54         return false;
55     }
56     if (buffer->data().linearBlocks().size() == 0u) {
57         // Nothing to copy, so we can copy by doing nothing.
58         return true;
59     } else if (buffer->data().linearBlocks().size() > 1u) {
60         // We don't know how to copy more than one blocks.
61         return false;
62     }
63     if (buffer->data().linearBlocks()[0].size() > capacity()) {
64         // It won't fit.
65         return false;
66     }
67     return true;
68 }
69 
copyLinear(const std::shared_ptr<C2Buffer> & buffer)70 bool Codec2Buffer::copyLinear(const std::shared_ptr<C2Buffer> &buffer) {
71     // We assume that all canCopyLinear() checks passed.
72     if (!buffer || buffer->data().linearBlocks().size() == 0u
73             || buffer->data().linearBlocks()[0].size() == 0u) {
74         setRange(0, 0);
75         return true;
76     }
77     C2ReadView view = buffer->data().linearBlocks()[0].map().get();
78     if (view.error() != C2_OK) {
79         ALOGD("Error while mapping: %d", view.error());
80         return false;
81     }
82     if (view.capacity() > capacity()) {
83         ALOGD("C2ConstLinearBlock lied --- it actually doesn't fit: view(%u) > this(%zu)",
84                 view.capacity(), capacity());
85         return false;
86     }
87     memcpy(base(), view.data(), view.capacity());
88     setRange(0, view.capacity());
89     return true;
90 }
91 
setImageData(const sp<ABuffer> & imageData)92 void Codec2Buffer::setImageData(const sp<ABuffer> &imageData) {
93     mImageData = imageData;
94 }
95 
96 // LocalLinearBuffer
97 
canCopy(const std::shared_ptr<C2Buffer> & buffer) const98 bool LocalLinearBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
99     return canCopyLinear(buffer);
100 }
101 
copy(const std::shared_ptr<C2Buffer> & buffer)102 bool LocalLinearBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
103     return copyLinear(buffer);
104 }
105 
106 // DummyContainerBuffer
107 
108 static uint8_t sDummyByte[1] = { 0 };
109 
DummyContainerBuffer(const sp<AMessage> & format,const std::shared_ptr<C2Buffer> & buffer)110 DummyContainerBuffer::DummyContainerBuffer(
111         const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer)
112     : Codec2Buffer(format, new ABuffer(sDummyByte, 1)),
113       mBufferRef(buffer) {
114     setRange(0, buffer ? 1 : 0);
115 }
116 
asC2Buffer()117 std::shared_ptr<C2Buffer> DummyContainerBuffer::asC2Buffer() {
118     return mBufferRef;
119 }
120 
clearC2BufferRefs()121 void DummyContainerBuffer::clearC2BufferRefs() {
122     mBufferRef.reset();
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 mBufferRef;
199 }
200 
clearC2BufferRefs()201 void ConstLinearBlockBuffer::clearC2BufferRefs() {
202     mBufferRef.reset();
203 }
204 
205 // GraphicView2MediaImageConverter
206 
207 namespace {
208 
209 class GraphicView2MediaImageConverter {
210 public:
211     /**
212      * Creates a C2GraphicView <=> MediaImage converter
213      *
214      * \param view C2GraphicView object
215      * \param format buffer format
216      * \param copy whether the converter is used for copy or not
217      */
GraphicView2MediaImageConverter(const C2GraphicView & view,const sp<AMessage> & format,bool copy)218     GraphicView2MediaImageConverter(
219             const C2GraphicView &view, const sp<AMessage> &format, bool copy)
220         : mInitCheck(NO_INIT),
221           mView(view),
222           mWidth(view.width()),
223           mHeight(view.height()),
224           mAllocatedDepth(0),
225           mBackBufferSize(0),
226           mMediaImage(new ABuffer(sizeof(MediaImage2))) {
227         if (!format->findInt32(KEY_COLOR_FORMAT, &mClientColorFormat)) {
228             mClientColorFormat = COLOR_FormatYUV420Flexible;
229         }
230         if (!format->findInt32("android._color-format", &mComponentColorFormat)) {
231             mComponentColorFormat = COLOR_FormatYUV420Flexible;
232         }
233         if (view.error() != C2_OK) {
234             ALOGD("Converter: view.error() = %d", view.error());
235             mInitCheck = BAD_VALUE;
236             return;
237         }
238         MediaImage2 *mediaImage = (MediaImage2 *)mMediaImage->base();
239         const C2PlanarLayout &layout = view.layout();
240         if (layout.numPlanes == 0) {
241             ALOGD("Converter: 0 planes");
242             mInitCheck = BAD_VALUE;
243             return;
244         }
245         memset(mediaImage, 0, sizeof(*mediaImage));
246         mAllocatedDepth = layout.planes[0].allocatedDepth;
247         uint32_t bitDepth = layout.planes[0].bitDepth;
248 
249         // align width and height to support subsampling cleanly
250         uint32_t stride = align(view.crop().width, 2) * divUp(layout.planes[0].allocatedDepth, 8u);
251         uint32_t vStride = align(view.crop().height, 2);
252 
253         bool tryWrapping = !copy;
254 
255         switch (layout.type) {
256             case C2PlanarLayout::TYPE_YUV: {
257                 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV;
258                 if (layout.numPlanes != 3) {
259                     ALOGD("Converter: %d planes for YUV layout", layout.numPlanes);
260                     mInitCheck = BAD_VALUE;
261                     return;
262                 }
263                 C2PlaneInfo yPlane = layout.planes[C2PlanarLayout::PLANE_Y];
264                 C2PlaneInfo uPlane = layout.planes[C2PlanarLayout::PLANE_U];
265                 C2PlaneInfo vPlane = layout.planes[C2PlanarLayout::PLANE_V];
266                 if (yPlane.channel != C2PlaneInfo::CHANNEL_Y
267                         || uPlane.channel != C2PlaneInfo::CHANNEL_CB
268                         || vPlane.channel != C2PlaneInfo::CHANNEL_CR) {
269                     ALOGD("Converter: not YUV layout");
270                     mInitCheck = BAD_VALUE;
271                     return;
272                 }
273                 bool yuv420888 = yPlane.rowSampling == 1 && yPlane.colSampling == 1
274                         && uPlane.rowSampling == 2 && uPlane.colSampling == 2
275                         && vPlane.rowSampling == 2 && vPlane.colSampling == 2;
276                 if (yuv420888) {
277                     for (uint32_t i = 0; i < 3; ++i) {
278                         const C2PlaneInfo &plane = layout.planes[i];
279                         if (plane.allocatedDepth != 8 || plane.bitDepth != 8) {
280                             yuv420888 = false;
281                             break;
282                         }
283                     }
284                     yuv420888 = yuv420888 && yPlane.colInc == 1 && uPlane.rowInc == vPlane.rowInc;
285                 }
286                 int32_t copyFormat = mClientColorFormat;
287                 if (yuv420888 && mClientColorFormat == COLOR_FormatYUV420Flexible) {
288                     if (uPlane.colInc == 2 && vPlane.colInc == 2
289                             && yPlane.rowInc == uPlane.rowInc) {
290                         copyFormat = COLOR_FormatYUV420PackedSemiPlanar;
291                     } else if (uPlane.colInc == 1 && vPlane.colInc == 1
292                             && yPlane.rowInc == uPlane.rowInc * 2) {
293                         copyFormat = COLOR_FormatYUV420PackedPlanar;
294                     }
295                 }
296                 ALOGV("client_fmt=0x%x y:{colInc=%d rowInc=%d} u:{colInc=%d rowInc=%d} "
297                         "v:{colInc=%d rowInc=%d}",
298                         mClientColorFormat,
299                         yPlane.colInc, yPlane.rowInc,
300                         uPlane.colInc, uPlane.rowInc,
301                         vPlane.colInc, vPlane.rowInc);
302                 switch (copyFormat) {
303                     case COLOR_FormatYUV420Flexible:
304                     case COLOR_FormatYUV420Planar:
305                     case COLOR_FormatYUV420PackedPlanar:
306                         mediaImage->mPlane[mediaImage->Y].mOffset = 0;
307                         mediaImage->mPlane[mediaImage->Y].mColInc = 1;
308                         mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
309                         mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
310                         mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
311 
312                         mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
313                         mediaImage->mPlane[mediaImage->U].mColInc = 1;
314                         mediaImage->mPlane[mediaImage->U].mRowInc = stride / 2;
315                         mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
316                         mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
317 
318                         mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 5 / 4;
319                         mediaImage->mPlane[mediaImage->V].mColInc = 1;
320                         mediaImage->mPlane[mediaImage->V].mRowInc = stride / 2;
321                         mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
322                         mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
323 
324                         if (tryWrapping && mClientColorFormat != COLOR_FormatYUV420Flexible) {
325                             tryWrapping = yuv420888 && uPlane.colInc == 1 && vPlane.colInc == 1
326                                     && yPlane.rowInc == uPlane.rowInc * 2
327                                     && view.data()[0] < view.data()[1]
328                                     && view.data()[1] < view.data()[2];
329                         }
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 
352                         if (tryWrapping && mClientColorFormat != COLOR_FormatYUV420Flexible) {
353                             tryWrapping = yuv420888 && uPlane.colInc == 2 && vPlane.colInc == 2
354                                     && yPlane.rowInc == uPlane.rowInc
355                                     && view.data()[0] < view.data()[1]
356                                     && view.data()[1] < view.data()[2];
357                         }
358                         break;
359 
360                     case COLOR_FormatYUVP010:
361                         mediaImage->mPlane[mediaImage->Y].mOffset = 0;
362                         mediaImage->mPlane[mediaImage->Y].mColInc = 2;
363                         mediaImage->mPlane[mediaImage->Y].mRowInc = stride * 2;
364                         mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
365                         mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
366 
367                         mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride * 2;
368                         mediaImage->mPlane[mediaImage->U].mColInc = 4;
369                         mediaImage->mPlane[mediaImage->U].mRowInc = stride * 2;
370                         mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
371                         mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
372 
373                         mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 2 + 2;
374                         mediaImage->mPlane[mediaImage->V].mColInc = 4;
375                         mediaImage->mPlane[mediaImage->V].mRowInc = stride * 2;
376                         mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
377                         mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
378                         if (tryWrapping) {
379                             tryWrapping = yPlane.allocatedDepth == 16
380                                     && uPlane.allocatedDepth == 16
381                                     && vPlane.allocatedDepth == 16
382                                     && yPlane.bitDepth == 10
383                                     && uPlane.bitDepth == 10
384                                     && vPlane.bitDepth == 10
385                                     && yPlane.rightShift == 6
386                                     && uPlane.rightShift == 6
387                                     && vPlane.rightShift == 6
388                                     && yPlane.rowSampling == 1 && yPlane.colSampling == 1
389                                     && uPlane.rowSampling == 2 && uPlane.colSampling == 2
390                                     && vPlane.rowSampling == 2 && vPlane.colSampling == 2
391                                     && yPlane.colInc == 2
392                                     && uPlane.colInc == 4
393                                     && vPlane.colInc == 4
394                                     && yPlane.rowInc == uPlane.rowInc
395                                     && yPlane.rowInc == vPlane.rowInc;
396                         }
397                         break;
398 
399                     default: {
400                         // default to fully planar format --- this will be overridden if wrapping
401                         // TODO: keep interleaved format
402                         int32_t colInc = divUp(mAllocatedDepth, 8u);
403                         int32_t rowInc = stride * colInc / yPlane.colSampling;
404                         mediaImage->mPlane[mediaImage->Y].mOffset = 0;
405                         mediaImage->mPlane[mediaImage->Y].mColInc = colInc;
406                         mediaImage->mPlane[mediaImage->Y].mRowInc = rowInc;
407                         mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = yPlane.colSampling;
408                         mediaImage->mPlane[mediaImage->Y].mVertSubsampling = yPlane.rowSampling;
409                         int32_t offset = rowInc * vStride / yPlane.rowSampling;
410 
411                         rowInc = stride * colInc / uPlane.colSampling;
412                         mediaImage->mPlane[mediaImage->U].mOffset = offset;
413                         mediaImage->mPlane[mediaImage->U].mColInc = colInc;
414                         mediaImage->mPlane[mediaImage->U].mRowInc = rowInc;
415                         mediaImage->mPlane[mediaImage->U].mHorizSubsampling = uPlane.colSampling;
416                         mediaImage->mPlane[mediaImage->U].mVertSubsampling = uPlane.rowSampling;
417                         offset += rowInc * vStride / uPlane.rowSampling;
418 
419                         rowInc = stride * colInc / vPlane.colSampling;
420                         mediaImage->mPlane[mediaImage->V].mOffset = offset;
421                         mediaImage->mPlane[mediaImage->V].mColInc = colInc;
422                         mediaImage->mPlane[mediaImage->V].mRowInc = rowInc;
423                         mediaImage->mPlane[mediaImage->V].mHorizSubsampling = vPlane.colSampling;
424                         mediaImage->mPlane[mediaImage->V].mVertSubsampling = vPlane.rowSampling;
425                         break;
426                     }
427                 }
428                 break;
429             }
430 
431             case C2PlanarLayout::TYPE_YUVA:
432                 ALOGD("Converter: unrecognized color format "
433                         "(client %d component %d) for YUVA layout",
434                         mClientColorFormat, mComponentColorFormat);
435                 mInitCheck = NO_INIT;
436                 return;
437             case C2PlanarLayout::TYPE_RGB:
438                 ALOGD("Converter: unrecognized color format "
439                         "(client %d component %d) for RGB layout",
440                         mClientColorFormat, mComponentColorFormat);
441                 mInitCheck = NO_INIT;
442                 // TODO: support MediaImage layout
443                 return;
444             case C2PlanarLayout::TYPE_RGBA:
445                 ALOGD("Converter: unrecognized color format "
446                         "(client %d component %d) for RGBA layout",
447                         mClientColorFormat, mComponentColorFormat);
448                 mInitCheck = NO_INIT;
449                 // TODO: support MediaImage layout
450                 return;
451             default:
452                 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
453                 if (layout.numPlanes == 1) {
454                     const C2PlaneInfo &plane = layout.planes[0];
455                     if (plane.colInc < 0 || plane.rowInc < 0) {
456                         // Copy-only if we have negative colInc/rowInc
457                         tryWrapping = false;
458                     }
459                     mediaImage->mPlane[0].mOffset = 0;
460                     mediaImage->mPlane[0].mColInc = std::abs(plane.colInc);
461                     mediaImage->mPlane[0].mRowInc = std::abs(plane.rowInc);
462                     mediaImage->mPlane[0].mHorizSubsampling = plane.colSampling;
463                     mediaImage->mPlane[0].mVertSubsampling = plane.rowSampling;
464                 } else {
465                     ALOGD("Converter: unrecognized layout: color format (client %d component %d)",
466                             mClientColorFormat, mComponentColorFormat);
467                     mInitCheck = NO_INIT;
468                     return;
469                 }
470                 break;
471         }
472         if (tryWrapping) {
473             // try to map directly. check if the planes are near one another
474             const uint8_t *minPtr = mView.data()[0];
475             const uint8_t *maxPtr = mView.data()[0];
476             int32_t planeSize = 0;
477             for (uint32_t i = 0; i < layout.numPlanes; ++i) {
478                 const C2PlaneInfo &plane = layout.planes[i];
479                 int64_t planeStride = std::abs(plane.rowInc / plane.colInc);
480                 ssize_t minOffset = plane.minOffset(
481                         mWidth / plane.colSampling, mHeight / plane.rowSampling);
482                 ssize_t maxOffset = plane.maxOffset(
483                         mWidth / plane.colSampling, mHeight / plane.rowSampling);
484                 if (minPtr > mView.data()[i] + minOffset) {
485                     minPtr = mView.data()[i] + minOffset;
486                 }
487                 if (maxPtr < mView.data()[i] + maxOffset) {
488                     maxPtr = mView.data()[i] + maxOffset;
489                 }
490                 planeSize += planeStride * divUp(mAllocatedDepth, 8u)
491                         * align(mHeight, 64) / plane.rowSampling;
492             }
493 
494             if (minPtr == mView.data()[0] && (maxPtr - minPtr + 1) <= planeSize) {
495                 // FIXME: this is risky as reading/writing data out of bound results
496                 //        in an undefined behavior, but gralloc does assume a
497                 //        contiguous mapping
498                 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
499                     const C2PlaneInfo &plane = layout.planes[i];
500                     mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
501                     mediaImage->mPlane[i].mColInc = plane.colInc;
502                     mediaImage->mPlane[i].mRowInc = plane.rowInc;
503                     mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
504                     mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
505                 }
506                 mWrapped = new ABuffer(const_cast<uint8_t *>(minPtr),
507                                        maxPtr - minPtr + 1);
508                 ALOGV("Converter: wrapped (capacity=%zu)", mWrapped->capacity());
509             }
510         }
511         mediaImage->mNumPlanes = layout.numPlanes;
512         mediaImage->mWidth = view.crop().width;
513         mediaImage->mHeight = view.crop().height;
514         mediaImage->mBitDepth = bitDepth;
515         mediaImage->mBitDepthAllocated = mAllocatedDepth;
516 
517         uint32_t bufferSize = 0;
518         for (uint32_t i = 0; i < layout.numPlanes; ++i) {
519             const C2PlaneInfo &plane = layout.planes[i];
520             if (plane.allocatedDepth < plane.bitDepth
521                     || plane.rightShift != plane.allocatedDepth - plane.bitDepth) {
522                 ALOGD("rightShift value of %u unsupported", plane.rightShift);
523                 mInitCheck = BAD_VALUE;
524                 return;
525             }
526             if (plane.allocatedDepth > 8 && plane.endianness != C2PlaneInfo::NATIVE) {
527                 ALOGD("endianness value of %u unsupported", plane.endianness);
528                 mInitCheck = BAD_VALUE;
529                 return;
530             }
531             if (plane.allocatedDepth != mAllocatedDepth || plane.bitDepth != bitDepth) {
532                 ALOGD("different allocatedDepth/bitDepth per plane unsupported");
533                 mInitCheck = BAD_VALUE;
534                 return;
535             }
536             bufferSize += stride * vStride
537                     / plane.rowSampling / plane.colSampling * divUp(mAllocatedDepth, 8u);
538         }
539 
540         mBackBufferSize = bufferSize;
541         mInitCheck = OK;
542     }
543 
initCheck() const544     status_t initCheck() const { return mInitCheck; }
545 
backBufferSize() const546     uint32_t backBufferSize() const { return mBackBufferSize; }
547 
548     /**
549      * Wrap C2GraphicView using a MediaImage2. Note that if not wrapped, the content is not mapped
550      * in this function --- the caller should use CopyGraphicView2MediaImage() function to copy the
551      * data into a backing buffer explicitly.
552      *
553      * \return media buffer. This is null if wrapping failed.
554      */
wrap() const555     sp<ABuffer> wrap() const {
556         if (mBackBuffer == nullptr) {
557             return mWrapped;
558         }
559         return nullptr;
560     }
561 
setBackBuffer(const sp<ABuffer> & backBuffer)562     bool setBackBuffer(const sp<ABuffer> &backBuffer) {
563         if (backBuffer == nullptr) {
564             return false;
565         }
566         if (backBuffer->capacity() < mBackBufferSize) {
567             return false;
568         }
569         backBuffer->setRange(0, mBackBufferSize);
570         mBackBuffer = backBuffer;
571         return true;
572     }
573 
574     /**
575      * Copy C2GraphicView to MediaImage2.
576      */
copyToMediaImage()577     status_t copyToMediaImage() {
578         if (mInitCheck != OK) {
579             return mInitCheck;
580         }
581         return ImageCopy(mBackBuffer->base(), getMediaImage(), mView);
582     }
583 
imageData() const584     const sp<ABuffer> &imageData() const { return mMediaImage; }
585 
586 private:
587     status_t mInitCheck;
588 
589     const C2GraphicView mView;
590     uint32_t mWidth;
591     uint32_t mHeight;
592     int32_t mClientColorFormat;  ///< SDK color format for MediaImage
593     int32_t mComponentColorFormat;  ///< SDK color format from component
594     sp<ABuffer> mWrapped;  ///< wrapped buffer (if we can map C2Buffer to an ABuffer)
595     uint32_t mAllocatedDepth;
596     uint32_t mBackBufferSize;
597     sp<ABuffer> mMediaImage;
598     std::function<sp<ABuffer>(size_t)> mAlloc;
599 
600     sp<ABuffer> mBackBuffer;    ///< backing buffer if we have to copy C2Buffer <=> ABuffer
601 
getMediaImage()602     MediaImage2 *getMediaImage() {
603         return (MediaImage2 *)mMediaImage->base();
604     }
605 };
606 
607 }  // namespace
608 
609 // GraphicBlockBuffer
610 
611 // static
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2GraphicBlock> & block,std::function<sp<ABuffer> (size_t)> alloc)612 sp<GraphicBlockBuffer> GraphicBlockBuffer::Allocate(
613         const sp<AMessage> &format,
614         const std::shared_ptr<C2GraphicBlock> &block,
615         std::function<sp<ABuffer>(size_t)> alloc) {
616     C2GraphicView view(block->map().get());
617     if (view.error() != C2_OK) {
618         ALOGD("C2GraphicBlock::map failed: %d", view.error());
619         return nullptr;
620     }
621 
622     GraphicView2MediaImageConverter converter(view, format, false /* copy */);
623     if (converter.initCheck() != OK) {
624         ALOGD("Converter init failed: %d", converter.initCheck());
625         return nullptr;
626     }
627     bool wrapped = true;
628     sp<ABuffer> buffer = converter.wrap();
629     if (buffer == nullptr) {
630         buffer = alloc(converter.backBufferSize());
631         if (!converter.setBackBuffer(buffer)) {
632             ALOGD("Converter failed to set back buffer");
633             return nullptr;
634         }
635         wrapped = false;
636     }
637     return new GraphicBlockBuffer(
638             format,
639             buffer,
640             std::move(view),
641             block,
642             converter.imageData(),
643             wrapped);
644 }
645 
GraphicBlockBuffer(const sp<AMessage> & format,const sp<ABuffer> & buffer,C2GraphicView && view,const std::shared_ptr<C2GraphicBlock> & block,const sp<ABuffer> & imageData,bool wrapped)646 GraphicBlockBuffer::GraphicBlockBuffer(
647         const sp<AMessage> &format,
648         const sp<ABuffer> &buffer,
649         C2GraphicView &&view,
650         const std::shared_ptr<C2GraphicBlock> &block,
651         const sp<ABuffer> &imageData,
652         bool wrapped)
653     : Codec2Buffer(format, buffer),
654       mView(view),
655       mBlock(block),
656       mWrapped(wrapped) {
657     setImageData(imageData);
658 }
659 
asC2Buffer()660 std::shared_ptr<C2Buffer> GraphicBlockBuffer::asC2Buffer() {
661     uint32_t width = mView.width();
662     uint32_t height = mView.height();
663     if (!mWrapped) {
664         (void)ImageCopy(mView, base(), imageData());
665     }
666     return C2Buffer::CreateGraphicBuffer(
667             mBlock->share(C2Rect(width, height), C2Fence()));
668 }
669 
670 // GraphicMetadataBuffer
GraphicMetadataBuffer(const sp<AMessage> & format,const std::shared_ptr<C2Allocator> & alloc)671 GraphicMetadataBuffer::GraphicMetadataBuffer(
672         const sp<AMessage> &format,
673         const std::shared_ptr<C2Allocator> &alloc)
674     : Codec2Buffer(format, new ABuffer(sizeof(VideoNativeMetadata))),
675       mAlloc(alloc) {
676     ((VideoNativeMetadata *)base())->pBuffer = nullptr;
677 }
678 
asC2Buffer()679 std::shared_ptr<C2Buffer> GraphicMetadataBuffer::asC2Buffer() {
680 #ifdef __LP64__
681     static std::once_flag s_checkOnce;
682     static bool s_is64bitOk {true};
683     std::call_once(s_checkOnce, [&](){
684         const std::string abi32list =
685         ::android::base::GetProperty("ro.product.cpu.abilist32", "");
686         if (!abi32list.empty()) {
687             int32_t inputSurfaceSetting =
688             ::android::base::GetIntProperty("debug.stagefright.c2inputsurface", int32_t(0));
689             s_is64bitOk = inputSurfaceSetting != 0;
690         }
691     });
692 
693     if (!s_is64bitOk) {
694         ALOGE("GraphicMetadataBuffer does not work in 32+64 system if compiled as 64-bit object"\
695               "when debug.stagefright.c2inputsurface is set to 0");
696         return nullptr;
697     }
698 #endif
699 
700     VideoNativeMetadata *meta = (VideoNativeMetadata *)base();
701     ANativeWindowBuffer *buffer = (ANativeWindowBuffer *)meta->pBuffer;
702     if (buffer == nullptr) {
703         ALOGD("VideoNativeMetadata contains null buffer");
704         return nullptr;
705     }
706 
707     ALOGV("VideoNativeMetadata: %dx%d", buffer->width, buffer->height);
708     C2Handle *handle = WrapNativeCodec2GrallocHandle(
709             buffer->handle,
710             buffer->width,
711             buffer->height,
712             buffer->format,
713             buffer->usage,
714             buffer->stride);
715     std::shared_ptr<C2GraphicAllocation> alloc;
716     c2_status_t err = mAlloc->priorGraphicAllocation(handle, &alloc);
717     if (err != C2_OK) {
718         ALOGD("Failed to wrap VideoNativeMetadata into C2GraphicAllocation");
719         native_handle_close(handle);
720         native_handle_delete(handle);
721         return nullptr;
722     }
723     std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
724 
725     meta->pBuffer = 0;
726     // TODO: wrap this in C2Fence so that the component can wait when it
727     //       actually starts processing.
728     if (meta->nFenceFd >= 0) {
729         sp<Fence> fence(new Fence(meta->nFenceFd));
730         fence->waitForever(LOG_TAG);
731     }
732     return C2Buffer::CreateGraphicBuffer(
733             block->share(C2Rect(buffer->width, buffer->height), C2Fence()));
734 }
735 
736 // ConstGraphicBlockBuffer
737 
738 // static
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2Buffer> & buffer,std::function<sp<ABuffer> (size_t)> alloc)739 sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::Allocate(
740         const sp<AMessage> &format,
741         const std::shared_ptr<C2Buffer> &buffer,
742         std::function<sp<ABuffer>(size_t)> alloc) {
743     if (!buffer
744             || buffer->data().type() != C2BufferData::GRAPHIC
745             || buffer->data().graphicBlocks().size() != 1u) {
746         ALOGD("C2Buffer precond fail");
747         return nullptr;
748     }
749     std::unique_ptr<const C2GraphicView> view(std::make_unique<const C2GraphicView>(
750             buffer->data().graphicBlocks()[0].map().get()));
751     std::unique_ptr<const C2GraphicView> holder;
752 
753     GraphicView2MediaImageConverter converter(*view, format, false /* copy */);
754     if (converter.initCheck() != OK) {
755         ALOGD("Converter init failed: %d", converter.initCheck());
756         return nullptr;
757     }
758     bool wrapped = true;
759     sp<ABuffer> aBuffer = converter.wrap();
760     if (aBuffer == nullptr) {
761         aBuffer = alloc(converter.backBufferSize());
762         if (!converter.setBackBuffer(aBuffer)) {
763             ALOGD("Converter failed to set back buffer");
764             return nullptr;
765         }
766         wrapped = false;
767         converter.copyToMediaImage();
768         // We don't need the view.
769         holder = std::move(view);
770     }
771     return new ConstGraphicBlockBuffer(
772             format,
773             aBuffer,
774             std::move(view),
775             buffer,
776             converter.imageData(),
777             wrapped);
778 }
779 
780 // static
AllocateEmpty(const sp<AMessage> & format,std::function<sp<ABuffer> (size_t)> alloc)781 sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::AllocateEmpty(
782         const sp<AMessage> &format,
783         std::function<sp<ABuffer>(size_t)> alloc) {
784     int32_t width, height;
785     if (!format->findInt32("width", &width)
786             || !format->findInt32("height", &height)) {
787         ALOGD("format had no width / height");
788         return nullptr;
789     }
790     // NOTE: we currently only support YUV420 formats for byte-buffer mode.
791     sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * 3 / 2));
792     return new ConstGraphicBlockBuffer(
793             format,
794             aBuffer,
795             nullptr,
796             nullptr,
797             nullptr,
798             false);
799 }
800 
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)801 ConstGraphicBlockBuffer::ConstGraphicBlockBuffer(
802         const sp<AMessage> &format,
803         const sp<ABuffer> &aBuffer,
804         std::unique_ptr<const C2GraphicView> &&view,
805         const std::shared_ptr<C2Buffer> &buffer,
806         const sp<ABuffer> &imageData,
807         bool wrapped)
808     : Codec2Buffer(format, aBuffer),
809       mView(std::move(view)),
810       mBufferRef(buffer),
811       mWrapped(wrapped) {
812     setImageData(imageData);
813 }
814 
asC2Buffer()815 std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
816     return mBufferRef;
817 }
818 
clearC2BufferRefs()819 void ConstGraphicBlockBuffer::clearC2BufferRefs() {
820     mView.reset();
821     mBufferRef.reset();
822 }
823 
canCopy(const std::shared_ptr<C2Buffer> & buffer) const824 bool ConstGraphicBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
825     if (mWrapped || mBufferRef) {
826         ALOGD("ConstGraphicBlockBuffer::canCopy: %swrapped ; buffer ref %s",
827                 mWrapped ? "" : "not ", mBufferRef ? "exists" : "doesn't exist");
828         return false;
829     }
830     if (!buffer) {
831         // Nothing to copy, so we can copy by doing nothing.
832         return true;
833     }
834     if (buffer->data().type() != C2BufferData::GRAPHIC) {
835         ALOGD("ConstGraphicBlockBuffer::canCopy: buffer precondition unsatisfied");
836         return false;
837     }
838     if (buffer->data().graphicBlocks().size() == 0) {
839         return true;
840     } else if (buffer->data().graphicBlocks().size() != 1u) {
841         ALOGD("ConstGraphicBlockBuffer::canCopy: too many blocks");
842         return false;
843     }
844 
845     GraphicView2MediaImageConverter converter(
846             buffer->data().graphicBlocks()[0].map().get(),
847             // FIXME: format() is not const, but we cannot change it, so do a const cast here
848             const_cast<ConstGraphicBlockBuffer *>(this)->format(),
849             true /* copy */);
850     if (converter.initCheck() != OK) {
851         ALOGD("ConstGraphicBlockBuffer::canCopy: converter init failed: %d", converter.initCheck());
852         return false;
853     }
854     if (converter.backBufferSize() > capacity()) {
855         ALOGD("ConstGraphicBlockBuffer::canCopy: insufficient capacity: req %u has %zu",
856                 converter.backBufferSize(), capacity());
857         return false;
858     }
859     return true;
860 }
861 
copy(const std::shared_ptr<C2Buffer> & buffer)862 bool ConstGraphicBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
863     if (!buffer || buffer->data().graphicBlocks().size() == 0) {
864         setRange(0, 0);
865         return true;
866     }
867 
868     GraphicView2MediaImageConverter converter(
869             buffer->data().graphicBlocks()[0].map().get(), format(), true /* copy */);
870     if (converter.initCheck() != OK) {
871         ALOGD("ConstGraphicBlockBuffer::copy: converter init failed: %d", converter.initCheck());
872         return false;
873     }
874     sp<ABuffer> aBuffer = new ABuffer(base(), capacity());
875     if (!converter.setBackBuffer(aBuffer)) {
876         ALOGD("ConstGraphicBlockBuffer::copy: set back buffer failed");
877         return false;
878     }
879     setRange(0, aBuffer->size());  // align size info
880     converter.copyToMediaImage();
881     setImageData(converter.imageData());
882     mBufferRef = buffer;
883     return true;
884 }
885 
886 // EncryptedLinearBlockBuffer
887 
EncryptedLinearBlockBuffer(const sp<AMessage> & format,const std::shared_ptr<C2LinearBlock> & block,const sp<IMemory> & memory,int32_t heapSeqNum)888 EncryptedLinearBlockBuffer::EncryptedLinearBlockBuffer(
889         const sp<AMessage> &format,
890         const std::shared_ptr<C2LinearBlock> &block,
891         const sp<IMemory> &memory,
892         int32_t heapSeqNum)
893     // TODO: Using unsecurePointer() has some associated security pitfalls
894     //       (see declaration for details).
895     //       Either document why it is safe in this case or address the
896     //       issue (e.g. by copying).
897     : Codec2Buffer(format, new ABuffer(memory->unsecurePointer(), memory->size())),
898       mBlock(block),
899       mMemory(memory),
900       mHeapSeqNum(heapSeqNum) {
901 }
902 
asC2Buffer()903 std::shared_ptr<C2Buffer> EncryptedLinearBlockBuffer::asC2Buffer() {
904     return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
905 }
906 
fillSourceBuffer(hardware::drm::V1_0::SharedBuffer * source)907 void EncryptedLinearBlockBuffer::fillSourceBuffer(
908         hardware::drm::V1_0::SharedBuffer *source) {
909     BufferChannelBase::IMemoryToSharedBuffer(mMemory, mHeapSeqNum, source);
910 }
911 
fillSourceBuffer(hardware::cas::native::V1_0::SharedBuffer * source)912 void EncryptedLinearBlockBuffer::fillSourceBuffer(
913         hardware::cas::native::V1_0::SharedBuffer *source) {
914     ssize_t offset;
915     size_t size;
916 
917     mHidlMemory = hardware::fromHeap(mMemory->getMemory(&offset, &size));
918     source->heapBase = *mHidlMemory;
919     source->offset = offset;
920     source->size = size;
921 }
922 
copyDecryptedContent(const sp<IMemory> & decrypted,size_t length)923 bool EncryptedLinearBlockBuffer::copyDecryptedContent(
924         const sp<IMemory> &decrypted, size_t length) {
925     C2WriteView view = mBlock->map().get();
926     if (view.error() != C2_OK) {
927         return false;
928     }
929     if (view.size() < length) {
930         return false;
931     }
932     memcpy(view.data(), decrypted->unsecurePointer(), length);
933     return true;
934 }
935 
copyDecryptedContentFromMemory(size_t length)936 bool EncryptedLinearBlockBuffer::copyDecryptedContentFromMemory(size_t length) {
937     return copyDecryptedContent(mMemory, length);
938 }
939 
handle() const940 native_handle_t *EncryptedLinearBlockBuffer::handle() const {
941     return const_cast<native_handle_t *>(mBlock->handle());
942 }
943 
944 }  // namespace android
945