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 #define ATRACE_TAG ATRACE_TAG_VIDEO
20 #include <utils/Log.h>
21 #include <utils/Trace.h>
22
23 #include <android_media_codec.h>
24
25 #include <aidl/android/hardware/graphics/common/Cta861_3.h>
26 #include <aidl/android/hardware/graphics/common/Smpte2086.h>
27 #include <android-base/no_destructor.h>
28 #include <android-base/properties.h>
29 #include <android/hardware/cas/native/1.0/types.h>
30 #include <android/hardware/drm/1.0/types.h>
31 #include <hidlmemory/FrameworkUtils.h>
32 #include <media/hardware/HardwareAPI.h>
33 #include <media/stagefright/CodecBase.h>
34 #include <media/stagefright/MediaCodecConstants.h>
35 #include <media/stagefright/foundation/ABuffer.h>
36 #include <media/stagefright/foundation/AMessage.h>
37 #include <media/stagefright/foundation/AUtils.h>
38 #include <media/stagefright/foundation/ColorUtils.h>
39 #include <mediadrm/ICrypto.h>
40 #include <nativebase/nativebase.h>
41 #include <ui/GraphicBufferMapper.h>
42 #include <ui/Fence.h>
43
44 #include <C2AllocatorGralloc.h>
45 #include <C2BlockInternal.h>
46 #include <C2Debug.h>
47
48 #include "Codec2Buffer.h"
49 #include "Codec2BufferUtils.h"
50
51 namespace android {
52
53 // Codec2Buffer
54
canCopyLinear(const std::shared_ptr<C2Buffer> & buffer) const55 bool Codec2Buffer::canCopyLinear(const std::shared_ptr<C2Buffer> &buffer) const {
56 if (const_cast<Codec2Buffer *>(this)->base() == nullptr) {
57 return false;
58 }
59 if (!buffer) {
60 // Nothing to copy, so we can copy by doing nothing.
61 return true;
62 }
63 if (buffer->data().type() != C2BufferData::LINEAR) {
64 return false;
65 }
66 if (buffer->data().linearBlocks().size() == 0u) {
67 // Nothing to copy, so we can copy by doing nothing.
68 return true;
69 } else if (buffer->data().linearBlocks().size() > 1u) {
70 // We don't know how to copy more than one blocks.
71 return false;
72 }
73 if (buffer->data().linearBlocks()[0].size() > capacity()) {
74 // It won't fit.
75 return false;
76 }
77 return true;
78 }
79
copyLinear(const std::shared_ptr<C2Buffer> & buffer)80 bool Codec2Buffer::copyLinear(const std::shared_ptr<C2Buffer> &buffer) {
81 // We assume that all canCopyLinear() checks passed.
82 if (!buffer || buffer->data().linearBlocks().size() == 0u
83 || buffer->data().linearBlocks()[0].size() == 0u) {
84 setRange(0, 0);
85 return true;
86 }
87 C2ReadView view = buffer->data().linearBlocks()[0].map().get();
88 if (view.error() != C2_OK) {
89 ALOGD("Error while mapping: %d", view.error());
90 return false;
91 }
92 if (view.capacity() > capacity()) {
93 ALOGD("C2ConstLinearBlock lied --- it actually doesn't fit: view(%u) > this(%zu)",
94 view.capacity(), capacity());
95 return false;
96 }
97 memcpy(base(), view.data(), view.capacity());
98 setRange(0, view.capacity());
99 return true;
100 }
101
setImageData(const sp<ABuffer> & imageData)102 void Codec2Buffer::setImageData(const sp<ABuffer> &imageData) {
103 mImageData = imageData;
104 }
105
106 // LocalLinearBuffer
107
canCopy(const std::shared_ptr<C2Buffer> & buffer) const108 bool LocalLinearBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
109 return canCopyLinear(buffer);
110 }
111
copy(const std::shared_ptr<C2Buffer> & buffer)112 bool LocalLinearBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
113 return copyLinear(buffer);
114 }
115
116 // DummyContainerBuffer
117
118 static uint8_t sDummyByte[1] = { 0 };
119
DummyContainerBuffer(const sp<AMessage> & format,const std::shared_ptr<C2Buffer> & buffer)120 DummyContainerBuffer::DummyContainerBuffer(
121 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer)
122 : Codec2Buffer(format, new ABuffer(sDummyByte, 1)),
123 mBufferRef(buffer) {
124 setRange(0, buffer ? 1 : 0);
125 }
126
asC2Buffer()127 std::shared_ptr<C2Buffer> DummyContainerBuffer::asC2Buffer() {
128 return mBufferRef;
129 }
130
clearC2BufferRefs()131 void DummyContainerBuffer::clearC2BufferRefs() {
132 mBufferRef.reset();
133 }
134
canCopy(const std::shared_ptr<C2Buffer> &) const135 bool DummyContainerBuffer::canCopy(const std::shared_ptr<C2Buffer> &) const {
136 return !mBufferRef;
137 }
138
copy(const std::shared_ptr<C2Buffer> & buffer)139 bool DummyContainerBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
140 mBufferRef = buffer;
141 setRange(0, mBufferRef ? 1 : 0);
142 return true;
143 }
144
145 // LinearBlockBuffer
146
147 // static
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2LinearBlock> & block)148 sp<LinearBlockBuffer> LinearBlockBuffer::Allocate(
149 const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block) {
150 C2WriteView writeView(block->map().get());
151 if (writeView.error() != C2_OK) {
152 return nullptr;
153 }
154 return new LinearBlockBuffer(format, std::move(writeView), block);
155 }
156
asC2Buffer()157 std::shared_ptr<C2Buffer> LinearBlockBuffer::asC2Buffer() {
158 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
159 }
160
canCopy(const std::shared_ptr<C2Buffer> & buffer) const161 bool LinearBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
162 return canCopyLinear(buffer);
163 }
164
copy(const std::shared_ptr<C2Buffer> & buffer)165 bool LinearBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
166 return copyLinear(buffer);
167 }
168
LinearBlockBuffer(const sp<AMessage> & format,C2WriteView && writeView,const std::shared_ptr<C2LinearBlock> & block)169 LinearBlockBuffer::LinearBlockBuffer(
170 const sp<AMessage> &format,
171 C2WriteView&& writeView,
172 const std::shared_ptr<C2LinearBlock> &block)
173 : Codec2Buffer(format, new ABuffer(writeView.data(), writeView.size())),
174 mWriteView(writeView),
175 mBlock(block) {
176 }
177
178 // ConstLinearBlockBuffer
179
180 // static
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2Buffer> & buffer)181 sp<ConstLinearBlockBuffer> ConstLinearBlockBuffer::Allocate(
182 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer) {
183 if (!buffer
184 || buffer->data().type() != C2BufferData::LINEAR
185 || buffer->data().linearBlocks().size() != 1u) {
186 if (!buffer) {
187 ALOGD("ConstLinearBlockBuffer::Allocate: null buffer");
188 } else {
189 ALOGW("ConstLinearBlockBuffer::Allocate: type=%d # linear blocks=%zu",
190 buffer->data().type(), buffer->data().linearBlocks().size());
191 }
192 return nullptr;
193 }
194 C2ReadView readView(buffer->data().linearBlocks()[0].map().get());
195 if (readView.error() != C2_OK) {
196 ALOGW("ConstLinearBlockBuffer::Allocate: readView.error()=%d", readView.error());
197 return nullptr;
198 }
199 return new ConstLinearBlockBuffer(format, std::move(readView), buffer);
200 }
201
ConstLinearBlockBuffer(const sp<AMessage> & format,C2ReadView && readView,const std::shared_ptr<C2Buffer> & buffer)202 ConstLinearBlockBuffer::ConstLinearBlockBuffer(
203 const sp<AMessage> &format,
204 C2ReadView&& readView,
205 const std::shared_ptr<C2Buffer> &buffer)
206 : Codec2Buffer(format, new ABuffer(
207 // NOTE: ABuffer only takes non-const pointer but this data is
208 // supposed to be read-only.
209 const_cast<uint8_t *>(readView.data()), readView.capacity())),
210 mReadView(readView),
211 mBufferRef(buffer) {
212 }
213
asC2Buffer()214 std::shared_ptr<C2Buffer> ConstLinearBlockBuffer::asC2Buffer() {
215 return mBufferRef;
216 }
217
clearC2BufferRefs()218 void ConstLinearBlockBuffer::clearC2BufferRefs() {
219 mBufferRef.reset();
220 }
221
222 // GraphicBlockBuffer
223
224 // static
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2GraphicBlock> & block,std::function<sp<ABuffer> (size_t)> alloc)225 sp<GraphicBlockBuffer> GraphicBlockBuffer::Allocate(
226 const sp<AMessage> &format,
227 const std::shared_ptr<C2GraphicBlock> &block,
228 std::function<sp<ABuffer>(size_t)> alloc) {
229 ATRACE_BEGIN("GraphicBlockBuffer::Allocate block->map()");
230 C2GraphicView view(block->map().get());
231 ATRACE_END();
232 if (view.error() != C2_OK) {
233 ALOGD("C2GraphicBlock::map failed: %d", view.error());
234 return nullptr;
235 }
236
237 GraphicView2MediaImageConverter converter(view, format, false /* copy */);
238 if (converter.initCheck() != OK) {
239 ALOGD("Converter init failed: %d", converter.initCheck());
240 return nullptr;
241 }
242 bool wrapped = true;
243 sp<ABuffer> buffer = converter.wrap();
244 if (buffer == nullptr) {
245 buffer = alloc(converter.backBufferSize());
246 if (!converter.setBackBuffer(buffer)) {
247 ALOGD("Converter failed to set back buffer");
248 return nullptr;
249 }
250 wrapped = false;
251 }
252 return new GraphicBlockBuffer(
253 format,
254 buffer,
255 std::move(view),
256 block,
257 converter.imageData(),
258 wrapped);
259 }
260
GraphicBlockBuffer(const sp<AMessage> & format,const sp<ABuffer> & buffer,C2GraphicView && view,const std::shared_ptr<C2GraphicBlock> & block,const sp<ABuffer> & imageData,bool wrapped)261 GraphicBlockBuffer::GraphicBlockBuffer(
262 const sp<AMessage> &format,
263 const sp<ABuffer> &buffer,
264 C2GraphicView &&view,
265 const std::shared_ptr<C2GraphicBlock> &block,
266 const sp<ABuffer> &imageData,
267 bool wrapped)
268 : Codec2Buffer(format, buffer),
269 mView(view),
270 mBlock(block),
271 mWrapped(wrapped) {
272 setImageData(imageData);
273 }
274
asC2Buffer()275 std::shared_ptr<C2Buffer> GraphicBlockBuffer::asC2Buffer() {
276 ATRACE_CALL();
277 uint32_t width = mView.width();
278 uint32_t height = mView.height();
279 if (!mWrapped) {
280 (void)ImageCopy(mView, base(), imageData());
281 }
282 return C2Buffer::CreateGraphicBuffer(
283 mBlock->share(C2Rect(width, height), C2Fence()));
284 }
285
286 // GraphicMetadataBuffer
GraphicMetadataBuffer(const sp<AMessage> & format,const std::shared_ptr<C2Allocator> & alloc)287 GraphicMetadataBuffer::GraphicMetadataBuffer(
288 const sp<AMessage> &format,
289 const std::shared_ptr<C2Allocator> &alloc)
290 : Codec2Buffer(format, new ABuffer(sizeof(VideoNativeMetadata))),
291 mAlloc(alloc) {
292 ((VideoNativeMetadata *)base())->pBuffer = nullptr;
293 }
294
asC2Buffer()295 std::shared_ptr<C2Buffer> GraphicMetadataBuffer::asC2Buffer() {
296 #ifdef __LP64__
297 static std::once_flag s_checkOnce;
298 static bool s_is64bitOk {true};
299 std::call_once(s_checkOnce, [&](){
300 const std::string abi32list =
301 ::android::base::GetProperty("ro.product.cpu.abilist32", "");
302 if (!abi32list.empty()) {
303 int32_t inputSurfaceSetting =
304 ::android::base::GetIntProperty("debug.stagefright.c2inputsurface", int32_t(0));
305 s_is64bitOk = inputSurfaceSetting != 0;
306 }
307 });
308
309 if (!s_is64bitOk) {
310 ALOGE("GraphicMetadataBuffer does not work in 32+64 system if compiled as 64-bit object"\
311 "when debug.stagefright.c2inputsurface is set to 0");
312 return nullptr;
313 }
314 #endif
315
316 VideoNativeMetadata *meta = (VideoNativeMetadata *)base();
317 ANativeWindowBuffer *buffer = (ANativeWindowBuffer *)meta->pBuffer;
318 if (buffer == nullptr) {
319 ALOGD("VideoNativeMetadata contains null buffer");
320 return nullptr;
321 }
322
323 ALOGV("VideoNativeMetadata: %dx%d", buffer->width, buffer->height);
324 C2Handle *handle = WrapNativeCodec2GrallocHandle(
325 buffer->handle,
326 buffer->width,
327 buffer->height,
328 buffer->format,
329 buffer->usage,
330 buffer->stride);
331 std::shared_ptr<C2GraphicAllocation> alloc;
332 c2_status_t err = mAlloc->priorGraphicAllocation(handle, &alloc);
333 if (err != C2_OK) {
334 ALOGD("Failed to wrap VideoNativeMetadata into C2GraphicAllocation");
335 native_handle_close(handle);
336 native_handle_delete(handle);
337 return nullptr;
338 }
339 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
340
341 meta->pBuffer = 0;
342 // TODO: wrap this in C2Fence so that the component can wait when it
343 // actually starts processing.
344 if (meta->nFenceFd >= 0) {
345 sp<Fence> fence(new Fence(meta->nFenceFd));
346 fence->waitForever(LOG_TAG);
347 }
348 return C2Buffer::CreateGraphicBuffer(
349 block->share(C2Rect(buffer->width, buffer->height), C2Fence()));
350 }
351
352 // ConstGraphicBlockBuffer
353
354 // static
Allocate(const sp<AMessage> & format,const std::shared_ptr<C2Buffer> & buffer,std::function<sp<ABuffer> (size_t)> alloc)355 sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::Allocate(
356 const sp<AMessage> &format,
357 const std::shared_ptr<C2Buffer> &buffer,
358 std::function<sp<ABuffer>(size_t)> alloc) {
359 if (!buffer
360 || buffer->data().type() != C2BufferData::GRAPHIC
361 || buffer->data().graphicBlocks().size() != 1u) {
362 ALOGD("C2Buffer precond fail");
363 return nullptr;
364 }
365 ATRACE_BEGIN("ConstGraphicBlockBuffer::Allocate block->map()");
366 std::unique_ptr<const C2GraphicView> view(std::make_unique<const C2GraphicView>(
367 buffer->data().graphicBlocks()[0].map().get()));
368 ATRACE_END();
369 std::unique_ptr<const C2GraphicView> holder;
370
371 GraphicView2MediaImageConverter converter(*view, format, false /* copy */);
372 if (converter.initCheck() != OK) {
373 ALOGD("Converter init failed: %d", converter.initCheck());
374 return nullptr;
375 }
376 bool wrapped = true;
377 sp<ABuffer> aBuffer = converter.wrap();
378 if (aBuffer == nullptr) {
379 aBuffer = alloc(converter.backBufferSize());
380 if (!converter.setBackBuffer(aBuffer)) {
381 ALOGD("Converter failed to set back buffer");
382 return nullptr;
383 }
384 wrapped = false;
385 converter.copyToMediaImage();
386 // We don't need the view.
387 holder = std::move(view);
388 }
389 return new ConstGraphicBlockBuffer(
390 format,
391 aBuffer,
392 std::move(view),
393 buffer,
394 converter.imageData(),
395 wrapped);
396 }
397
398 // static
AllocateEmpty(const sp<AMessage> & format,std::function<sp<ABuffer> (size_t)> alloc)399 sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::AllocateEmpty(
400 const sp<AMessage> &format,
401 std::function<sp<ABuffer>(size_t)> alloc) {
402 int32_t width, height;
403 if (!format->findInt32("width", &width)
404 || !format->findInt32("height", &height)) {
405 ALOGD("format had no width / height");
406 return nullptr;
407 }
408 int32_t colorFormat = COLOR_FormatYUV420Flexible;
409 int32_t bpp = 12; // 8(Y) + 2(U) + 2(V)
410 if (format->findInt32(KEY_COLOR_FORMAT, &colorFormat)) {
411 if (colorFormat == COLOR_FormatYUVP010) {
412 bpp = 24; // 16(Y) + 4(U) + 4(V)
413 }
414 }
415 sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * bpp / 8));
416 if (aBuffer == nullptr) {
417 ALOGD("%s: failed to allocate buffer", __func__);
418 return nullptr;
419 }
420 return new ConstGraphicBlockBuffer(
421 format,
422 aBuffer,
423 nullptr,
424 nullptr,
425 nullptr,
426 false);
427 }
428
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)429 ConstGraphicBlockBuffer::ConstGraphicBlockBuffer(
430 const sp<AMessage> &format,
431 const sp<ABuffer> &aBuffer,
432 std::unique_ptr<const C2GraphicView> &&view,
433 const std::shared_ptr<C2Buffer> &buffer,
434 const sp<ABuffer> &imageData,
435 bool wrapped)
436 : Codec2Buffer(format, aBuffer),
437 mView(std::move(view)),
438 mBufferRef(buffer),
439 mWrapped(wrapped) {
440 setImageData(imageData);
441 }
442
asC2Buffer()443 std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
444 return mBufferRef;
445 }
446
clearC2BufferRefs()447 void ConstGraphicBlockBuffer::clearC2BufferRefs() {
448 mView.reset();
449 mBufferRef.reset();
450 }
451
canCopy(const std::shared_ptr<C2Buffer> & buffer) const452 bool ConstGraphicBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
453 if (mWrapped || mBufferRef) {
454 ALOGD("ConstGraphicBlockBuffer::canCopy: %swrapped ; buffer ref %s",
455 mWrapped ? "" : "not ", mBufferRef ? "exists" : "doesn't exist");
456 return false;
457 }
458 if (!buffer) {
459 // Nothing to copy, so we can copy by doing nothing.
460 return true;
461 }
462 if (buffer->data().type() != C2BufferData::GRAPHIC) {
463 ALOGD("ConstGraphicBlockBuffer::canCopy: buffer precondition unsatisfied");
464 return false;
465 }
466 if (buffer->data().graphicBlocks().size() == 0) {
467 return true;
468 } else if (buffer->data().graphicBlocks().size() != 1u) {
469 ALOGD("ConstGraphicBlockBuffer::canCopy: too many blocks");
470 return false;
471 }
472
473 ATRACE_BEGIN("ConstGraphicBlockBuffer::canCopy block->map()");
474 GraphicView2MediaImageConverter converter(
475 buffer->data().graphicBlocks()[0].map().get(),
476 // FIXME: format() is not const, but we cannot change it, so do a const cast here
477 const_cast<ConstGraphicBlockBuffer *>(this)->format(),
478 true /* copy */);
479 ATRACE_END();
480 if (converter.initCheck() != OK) {
481 ALOGD("ConstGraphicBlockBuffer::canCopy: converter init failed: %d", converter.initCheck());
482 return false;
483 }
484 if (converter.backBufferSize() > capacity()) {
485 ALOGD("ConstGraphicBlockBuffer::canCopy: insufficient capacity: req %u has %zu",
486 converter.backBufferSize(), capacity());
487 return false;
488 }
489 return true;
490 }
491
copy(const std::shared_ptr<C2Buffer> & buffer)492 bool ConstGraphicBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
493 if (!buffer || buffer->data().graphicBlocks().size() == 0) {
494 setRange(0, 0);
495 return true;
496 }
497
498 GraphicView2MediaImageConverter converter(
499 buffer->data().graphicBlocks()[0].map().get(), format(), true /* copy */);
500 if (converter.initCheck() != OK) {
501 ALOGD("ConstGraphicBlockBuffer::copy: converter init failed: %d", converter.initCheck());
502 return false;
503 }
504 sp<ABuffer> aBuffer = new ABuffer(base(), capacity());
505 if (!converter.setBackBuffer(aBuffer)) {
506 ALOGD("ConstGraphicBlockBuffer::copy: set back buffer failed");
507 return false;
508 }
509 setRange(0, aBuffer->size()); // align size info
510 converter.copyToMediaImage();
511 setImageData(converter.imageData());
512 mBufferRef = buffer;
513 return true;
514 }
515
516 // EncryptedLinearBlockBuffer
517
EncryptedLinearBlockBuffer(const sp<AMessage> & format,const std::shared_ptr<C2LinearBlock> & block,const sp<IMemory> & memory,int32_t heapSeqNum)518 EncryptedLinearBlockBuffer::EncryptedLinearBlockBuffer(
519 const sp<AMessage> &format,
520 const std::shared_ptr<C2LinearBlock> &block,
521 const sp<IMemory> &memory,
522 int32_t heapSeqNum)
523 // TODO: Using unsecurePointer() has some associated security pitfalls
524 // (see declaration for details).
525 // Either document why it is safe in this case or address the
526 // issue (e.g. by copying).
527 : Codec2Buffer(format, new ABuffer(memory->unsecurePointer(), memory->size())),
528 mBlock(block),
529 mMemory(memory),
530 mHeapSeqNum(heapSeqNum) {
531 }
532
asC2Buffer()533 std::shared_ptr<C2Buffer> EncryptedLinearBlockBuffer::asC2Buffer() {
534 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
535 }
536
fillSourceBuffer(hardware::drm::V1_0::SharedBuffer * source)537 void EncryptedLinearBlockBuffer::fillSourceBuffer(
538 hardware::drm::V1_0::SharedBuffer *source) {
539 BufferChannelBase::IMemoryToSharedBuffer(mMemory, mHeapSeqNum, source);
540 }
541
fillSourceBuffer(hardware::cas::native::V1_0::SharedBuffer * source)542 void EncryptedLinearBlockBuffer::fillSourceBuffer(
543 hardware::cas::native::V1_0::SharedBuffer *source) {
544 ssize_t offset;
545 size_t size;
546
547 mHidlMemory = hardware::fromHeap(mMemory->getMemory(&offset, &size));
548 source->heapBase = *mHidlMemory;
549 source->offset = offset;
550 source->size = size;
551 }
552
copyDecryptedContent(const sp<IMemory> & decrypted,size_t length)553 bool EncryptedLinearBlockBuffer::copyDecryptedContent(
554 const sp<IMemory> &decrypted, size_t length) {
555 C2WriteView view = mBlock->map().get();
556 if (view.error() != C2_OK) {
557 return false;
558 }
559 if (view.size() < length) {
560 return false;
561 }
562 memcpy(view.data(), decrypted->unsecurePointer(), length);
563 return true;
564 }
565
copyDecryptedContentFromMemory(size_t length)566 bool EncryptedLinearBlockBuffer::copyDecryptedContentFromMemory(size_t length) {
567 return copyDecryptedContent(mMemory, length);
568 }
569
handle() const570 native_handle_t *EncryptedLinearBlockBuffer::handle() const {
571 return const_cast<native_handle_t *>(mBlock->handle());
572 }
573
getMappedBlock(std::unique_ptr<MappedBlock> * const mappedBlock) const574 void EncryptedLinearBlockBuffer::getMappedBlock(
575 std::unique_ptr<MappedBlock> * const mappedBlock) const {
576 if (mappedBlock) {
577 mappedBlock->reset(new EncryptedLinearBlockBuffer::MappedBlock(mBlock));
578 }
579 return;
580 }
581
MappedBlock(const std::shared_ptr<C2LinearBlock> & block)582 EncryptedLinearBlockBuffer::MappedBlock::MappedBlock(
583 const std::shared_ptr<C2LinearBlock> &block) : mView(block->map().get()) {
584 }
585
copyDecryptedContent(const sp<IMemory> & decrypted,size_t length)586 bool EncryptedLinearBlockBuffer::MappedBlock::copyDecryptedContent(
587 const sp<IMemory> &decrypted, size_t length) {
588 if (mView.error() != C2_OK) {
589 return false;
590 }
591 if (mView.size() < length) {
592 ALOGE("View size(%d) less than decrypted length(%zu)",
593 mView.size(), length);
594 return false;
595 }
596 memcpy(mView.data(), decrypted->unsecurePointer(), length);
597 mView.setOffset(mView.offset() + length);
598 return true;
599 }
600
~MappedBlock()601 EncryptedLinearBlockBuffer::MappedBlock::~MappedBlock() {
602 mView.setOffset(0);
603 }
604
605 using ::aidl::android::hardware::graphics::common::Cta861_3;
606 using ::aidl::android::hardware::graphics::common::Smpte2086;
607
608 namespace {
609
610 class GrallocBuffer {
611 public:
GrallocBuffer(const C2Handle * const handle)612 GrallocBuffer(const C2Handle *const handle) : mBuffer(nullptr) {
613 GraphicBufferMapper& mapper = GraphicBufferMapper::get();
614
615 // Unwrap raw buffer handle from the C2Handle
616 native_handle_t *nh = UnwrapNativeCodec2GrallocHandle(handle);
617 if (!nh) {
618 ALOGE("handle is not compatible to any gralloc C2Handle types");
619 return;
620 }
621 // Import the raw handle so IMapper can use the buffer. The imported
622 // handle must be freed when the client is done with the buffer.
623 status_t status = mapper.importBufferNoValidate(
624 nh,
625 &mBuffer);
626
627 if (status != OK) {
628 ALOGE("Failed to import buffer. Status: %d.", status);
629 return;
630 }
631
632 // TRICKY: UnwrapNativeCodec2GrallocHandle creates a new handle but
633 // does not clone the fds. Thus we need to delete the handle
634 // without closing it.
635 native_handle_delete(nh);
636 }
637
~GrallocBuffer()638 ~GrallocBuffer() {
639 GraphicBufferMapper& mapper = GraphicBufferMapper::get();
640 if (mBuffer) {
641 // Free the imported buffer handle. This does not release the
642 // underlying buffer itself.
643 mapper.freeBuffer(mBuffer);
644 }
645 }
646
get() const647 buffer_handle_t get() const { return mBuffer; }
operator bool() const648 operator bool() const { return (mBuffer != nullptr); }
649 private:
650 buffer_handle_t mBuffer;
651 };
652
653 } // namspace
654
GetHdrMetadataFromGralloc4Handle(const C2Handle * const handle,std::shared_ptr<C2StreamHdrStaticMetadataInfo::input> * staticInfo,std::shared_ptr<C2StreamHdrDynamicMetadataInfo::input> * dynamicInfo)655 c2_status_t GetHdrMetadataFromGralloc4Handle(
656 const C2Handle *const handle,
657 std::shared_ptr<C2StreamHdrStaticMetadataInfo::input> *staticInfo,
658 std::shared_ptr<C2StreamHdrDynamicMetadataInfo::input> *dynamicInfo) {
659 c2_status_t err = C2_OK;
660 GraphicBufferMapper& mapper = GraphicBufferMapper::get();
661 GrallocBuffer buffer(handle);
662 if (!buffer) {
663 // Gralloc4 not supported; nothing to do
664 return err;
665 }
666 if (staticInfo) {
667 ALOGV("Grabbing static HDR info from gralloc metadata");
668 staticInfo->reset(new C2StreamHdrStaticMetadataInfo::input(0u));
669 memset(&(*staticInfo)->mastering, 0, sizeof((*staticInfo)->mastering));
670 (*staticInfo)->maxCll = 0;
671 (*staticInfo)->maxFall = 0;
672
673 std::optional<Smpte2086> smpte2086;
674 status_t status = mapper.getSmpte2086(buffer.get(), &smpte2086);
675 if (status != OK || !smpte2086) {
676 err = C2_CORRUPTED;
677 } else {
678 if (smpte2086) {
679 (*staticInfo)->mastering.red.x = smpte2086->primaryRed.x;
680 (*staticInfo)->mastering.red.y = smpte2086->primaryRed.y;
681 (*staticInfo)->mastering.green.x = smpte2086->primaryGreen.x;
682 (*staticInfo)->mastering.green.y = smpte2086->primaryGreen.y;
683 (*staticInfo)->mastering.blue.x = smpte2086->primaryBlue.x;
684 (*staticInfo)->mastering.blue.y = smpte2086->primaryBlue.y;
685 (*staticInfo)->mastering.white.x = smpte2086->whitePoint.x;
686 (*staticInfo)->mastering.white.y = smpte2086->whitePoint.y;
687
688 (*staticInfo)->mastering.maxLuminance = smpte2086->maxLuminance;
689 (*staticInfo)->mastering.minLuminance = smpte2086->minLuminance;
690 }
691 }
692
693 std::optional<Cta861_3> cta861_3;
694 status = mapper.getCta861_3(buffer.get(), &cta861_3);
695 if (status != OK || !cta861_3) {
696 err = C2_CORRUPTED;
697 } else {
698 if (cta861_3) {
699 (*staticInfo)->maxCll = cta861_3->maxContentLightLevel;
700 (*staticInfo)->maxFall = cta861_3->maxFrameAverageLightLevel;
701 }
702 }
703 }
704
705 if (err != C2_OK) {
706 staticInfo->reset();
707 }
708
709 if (dynamicInfo) {
710 ALOGV("Grabbing dynamic HDR info from gralloc metadata");
711 dynamicInfo->reset();
712 std::optional<std::vector<uint8_t>> vec;
713 status_t status = mapper.getSmpte2094_40(buffer.get(), &vec);
714 if (status != OK || !vec) {
715 dynamicInfo->reset();
716 err = C2_CORRUPTED;
717 } else {
718 if (vec) {
719 *dynamicInfo = C2StreamHdrDynamicMetadataInfo::input::AllocShared(
720 vec->size(), 0u, C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40);
721 memcpy((*dynamicInfo)->m.data, vec->data(), vec->size());
722 }
723 }
724 }
725
726 return err;
727 }
728
SetMetadataToGralloc4Handle(android_dataspace_t dataSpace,const std::shared_ptr<const C2StreamHdrStaticMetadataInfo::output> & staticInfo,const std::shared_ptr<const C2StreamHdrDynamicMetadataInfo::output> & dynamicInfo,const C2Handle * const handle)729 c2_status_t SetMetadataToGralloc4Handle(
730 android_dataspace_t dataSpace,
731 const std::shared_ptr<const C2StreamHdrStaticMetadataInfo::output> &staticInfo,
732 const std::shared_ptr<const C2StreamHdrDynamicMetadataInfo::output> &dynamicInfo,
733 const C2Handle *const handle) {
734 c2_status_t err = C2_OK;
735 GraphicBufferMapper& mapper = GraphicBufferMapper::get();
736 GrallocBuffer buffer(handle);
737 if (!buffer) {
738 // Gralloc4 not supported; nothing to do
739 return err;
740 }
741 // Use V0 dataspaces for Gralloc4+
742 if (android::media::codec::provider_->dataspace_v0_partial()) {
743 ColorUtils::convertDataSpaceToV0(dataSpace);
744 }
745 status_t status = mapper.setDataspace(buffer.get(), static_cast<ui::Dataspace>(dataSpace));
746 if (status != OK) {
747 err = C2_CORRUPTED;
748 }
749 if (staticInfo && *staticInfo) {
750 ALOGV("Setting static HDR info as gralloc metadata");
751 std::optional<Smpte2086> smpte2086 = Smpte2086{
752 {staticInfo->mastering.red.x, staticInfo->mastering.red.y},
753 {staticInfo->mastering.green.x, staticInfo->mastering.green.y},
754 {staticInfo->mastering.blue.x, staticInfo->mastering.blue.y},
755 {staticInfo->mastering.white.x, staticInfo->mastering.white.y},
756 staticInfo->mastering.maxLuminance,
757 staticInfo->mastering.minLuminance,
758 };
759 if (0.0 <= smpte2086->primaryRed.x && smpte2086->primaryRed.x <= 1.0
760 && 0.0 <= smpte2086->primaryRed.y && smpte2086->primaryRed.y <= 1.0
761 && 0.0 <= smpte2086->primaryGreen.x && smpte2086->primaryGreen.x <= 1.0
762 && 0.0 <= smpte2086->primaryGreen.y && smpte2086->primaryGreen.y <= 1.0
763 && 0.0 <= smpte2086->primaryBlue.x && smpte2086->primaryBlue.x <= 1.0
764 && 0.0 <= smpte2086->primaryBlue.y && smpte2086->primaryBlue.y <= 1.0
765 && 0.0 <= smpte2086->whitePoint.x && smpte2086->whitePoint.x <= 1.0
766 && 0.0 <= smpte2086->whitePoint.y && smpte2086->whitePoint.y <= 1.0
767 && 0.0 <= smpte2086->maxLuminance && 0.0 <= smpte2086->minLuminance) {
768 status = mapper.setSmpte2086(buffer.get(), smpte2086);
769 if (status != OK) {
770 err = C2_CORRUPTED;
771 }
772 }
773 std::optional<Cta861_3> cta861_3 = Cta861_3{
774 staticInfo->maxCll,
775 staticInfo->maxFall,
776 };
777 if (0.0 <= cta861_3->maxContentLightLevel && 0.0 <= cta861_3->maxFrameAverageLightLevel) {
778 status = mapper.setCta861_3(buffer.get(), cta861_3);
779 if (status != OK) {
780 err = C2_CORRUPTED;
781 }
782 }
783 }
784 if (dynamicInfo && *dynamicInfo && dynamicInfo->flexCount() > 0) {
785 ALOGV("Setting dynamic HDR info as gralloc metadata");
786 if (dynamicInfo->m.type_ == C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40) {
787 std::optional<std::vector<uint8_t>> smpte2094_40 = std::vector<uint8_t>();
788 smpte2094_40->resize(dynamicInfo->flexCount());
789 memcpy(smpte2094_40->data(), dynamicInfo->m.data, dynamicInfo->flexCount());
790
791 status = mapper.setSmpte2094_40(buffer.get(), smpte2094_40);
792 if (status != OK) {
793 err = C2_CORRUPTED;
794 }
795 } else {
796 err = C2_BAD_VALUE;
797 }
798 }
799
800 return err;
801 }
802
803 } // namespace android
804