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