blob: 62c8fcd87ff7819d11f356b6e0a92c17ff19f13a [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
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
bohua222c0b2021-01-12 18:54:53 -080021#include <android-base/properties.h>
Wonsik Kim41d83432020-04-27 16:40:49 -070022#include <android/hardware/cas/native/1.0/types.h>
23#include <android/hardware/drm/1.0/types.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080024#include <hidlmemory/FrameworkUtils.h>
25#include <media/hardware/HardwareAPI.h>
Robert Shih895fba92019-07-16 16:29:44 -070026#include <media/stagefright/CodecBase.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080027#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>
Wonsik Kim41d83432020-04-27 16:40:49 -070031#include <mediadrm/ICrypto.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080032#include <nativebase/nativebase.h>
Wonsik Kimebe0f9e2019-07-03 11:06:51 -070033#include <ui/Fence.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080034
35#include <C2AllocatorGralloc.h>
36#include <C2BlockInternal.h>
37#include <C2Debug.h>
38
39#include "Codec2Buffer.h"
40
41namespace android {
42
43// Codec2Buffer
44
45bool 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
70bool 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
92void Codec2Buffer::setImageData(const sp<ABuffer> &imageData) {
Wonsik Kimc48ddcf2019-02-11 16:16:57 -080093 mImageData = imageData;
Pawin Vongmasa36653902018-11-15 00:10:25 -080094}
95
96// LocalLinearBuffer
97
98bool LocalLinearBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
99 return canCopyLinear(buffer);
100}
101
102bool LocalLinearBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
103 return copyLinear(buffer);
104}
105
106// DummyContainerBuffer
107
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800108static uint8_t sDummyByte[1] = { 0 };
109
Pawin Vongmasa36653902018-11-15 00:10:25 -0800110DummyContainerBuffer::DummyContainerBuffer(
111 const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer)
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800112 : Codec2Buffer(format, new ABuffer(sDummyByte, 1)),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800113 mBufferRef(buffer) {
114 setRange(0, buffer ? 1 : 0);
115}
116
117std::shared_ptr<C2Buffer> DummyContainerBuffer::asC2Buffer() {
Wonsik Kimf9b32122020-04-02 11:30:17 -0700118 return mBufferRef;
119}
120
121void DummyContainerBuffer::clearC2BufferRefs() {
122 mBufferRef.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800123}
124
125bool DummyContainerBuffer::canCopy(const std::shared_ptr<C2Buffer> &) const {
126 return !mBufferRef;
127}
128
129bool 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
138sp<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
147std::shared_ptr<C2Buffer> LinearBlockBuffer::asC2Buffer() {
148 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
149}
150
151bool LinearBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
152 return canCopyLinear(buffer);
153}
154
155bool LinearBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
156 return copyLinear(buffer);
157}
158
159LinearBlockBuffer::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
171sp<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
185ConstLinearBlockBuffer::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
197std::shared_ptr<C2Buffer> ConstLinearBlockBuffer::asC2Buffer() {
Wonsik Kimf9b32122020-04-02 11:30:17 -0700198 return mBufferRef;
199}
200
201void ConstLinearBlockBuffer::clearC2BufferRefs() {
202 mBufferRef.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800203}
204
205// GraphicView2MediaImageConverter
206
207namespace {
208
209class GraphicView2MediaImageConverter {
210public:
211 /**
212 * Creates a C2GraphicView <=> MediaImage converter
213 *
214 * \param view C2GraphicView object
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700215 * \param format buffer format
Wonsik Kim7d966312019-06-04 14:00:49 -0700216 * \param copy whether the converter is used for copy or not
Pawin Vongmasa36653902018-11-15 00:10:25 -0800217 */
218 GraphicView2MediaImageConverter(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700219 const C2GraphicView &view, const sp<AMessage> &format, bool copy)
Pawin Vongmasa36653902018-11-15 00:10:25 -0800220 : mInitCheck(NO_INIT),
221 mView(view),
222 mWidth(view.width()),
223 mHeight(view.height()),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800224 mAllocatedDepth(0),
225 mBackBufferSize(0),
226 mMediaImage(new ABuffer(sizeof(MediaImage2))) {
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700227 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 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800233 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 }
Harish Mahendrakarcac53852019-02-20 10:59:10 -0800245 memset(mediaImage, 0, sizeof(*mediaImage));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800246 mAllocatedDepth = layout.planes[0].allocatedDepth;
247 uint32_t bitDepth = layout.planes[0].bitDepth;
248
249 // align width and height to support subsampling cleanly
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700250 uint32_t stride = align(view.crop().width, 2) * divUp(layout.planes[0].allocatedDepth, 8u);
Vinay Kaliad8c48102021-09-01 20:49:45 +0000251
252 int32_t fmtHeight = mHeight;
253 format->findInt32(KEY_HEIGHT, &fmtHeight);
254 uint32_t vStride = align(fmtHeight, 2);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800255
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700256 bool tryWrapping = !copy;
257
Pawin Vongmasa36653902018-11-15 00:10:25 -0800258 switch (layout.type) {
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700259 case C2PlanarLayout::TYPE_YUV: {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800260 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV;
261 if (layout.numPlanes != 3) {
262 ALOGD("Converter: %d planes for YUV layout", layout.numPlanes);
263 mInitCheck = BAD_VALUE;
264 return;
265 }
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700266 C2PlaneInfo yPlane = layout.planes[C2PlanarLayout::PLANE_Y];
267 C2PlaneInfo uPlane = layout.planes[C2PlanarLayout::PLANE_U];
268 C2PlaneInfo vPlane = layout.planes[C2PlanarLayout::PLANE_V];
269 if (yPlane.channel != C2PlaneInfo::CHANNEL_Y
270 || uPlane.channel != C2PlaneInfo::CHANNEL_CB
271 || vPlane.channel != C2PlaneInfo::CHANNEL_CR) {
272 ALOGD("Converter: not YUV layout");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800273 mInitCheck = BAD_VALUE;
274 return;
275 }
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700276 bool yuv420888 = yPlane.rowSampling == 1 && yPlane.colSampling == 1
277 && uPlane.rowSampling == 2 && uPlane.colSampling == 2
278 && vPlane.rowSampling == 2 && vPlane.colSampling == 2;
279 if (yuv420888) {
280 for (uint32_t i = 0; i < 3; ++i) {
281 const C2PlaneInfo &plane = layout.planes[i];
282 if (plane.allocatedDepth != 8 || plane.bitDepth != 8) {
283 yuv420888 = false;
284 break;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800285 }
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700286 }
287 yuv420888 = yuv420888 && yPlane.colInc == 1 && uPlane.rowInc == vPlane.rowInc;
288 }
289 int32_t copyFormat = mClientColorFormat;
290 if (yuv420888 && mClientColorFormat == COLOR_FormatYUV420Flexible) {
291 if (uPlane.colInc == 2 && vPlane.colInc == 2
292 && yPlane.rowInc == uPlane.rowInc) {
293 copyFormat = COLOR_FormatYUV420PackedSemiPlanar;
294 } else if (uPlane.colInc == 1 && vPlane.colInc == 1
295 && yPlane.rowInc == uPlane.rowInc * 2) {
296 copyFormat = COLOR_FormatYUV420PackedPlanar;
297 }
298 }
299 ALOGV("client_fmt=0x%x y:{colInc=%d rowInc=%d} u:{colInc=%d rowInc=%d} "
300 "v:{colInc=%d rowInc=%d}",
301 mClientColorFormat,
302 yPlane.colInc, yPlane.rowInc,
303 uPlane.colInc, uPlane.rowInc,
304 vPlane.colInc, vPlane.rowInc);
305 switch (copyFormat) {
306 case COLOR_FormatYUV420Flexible:
Pawin Vongmasa36653902018-11-15 00:10:25 -0800307 case COLOR_FormatYUV420Planar:
308 case COLOR_FormatYUV420PackedPlanar:
309 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
310 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700311 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800312 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
313 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
314
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700315 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800316 mediaImage->mPlane[mediaImage->U].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700317 mediaImage->mPlane[mediaImage->U].mRowInc = stride / 2;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800318 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
319 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
320
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700321 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 5 / 4;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800322 mediaImage->mPlane[mediaImage->V].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700323 mediaImage->mPlane[mediaImage->V].mRowInc = stride / 2;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800324 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
325 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700326
327 if (tryWrapping && mClientColorFormat != COLOR_FormatYUV420Flexible) {
328 tryWrapping = yuv420888 && uPlane.colInc == 1 && vPlane.colInc == 1
329 && yPlane.rowInc == uPlane.rowInc * 2
330 && view.data()[0] < view.data()[1]
331 && view.data()[1] < view.data()[2];
332 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800333 break;
334
335 case COLOR_FormatYUV420SemiPlanar:
336 case COLOR_FormatYUV420PackedSemiPlanar:
337 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
338 mediaImage->mPlane[mediaImage->Y].mColInc = 1;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700339 mediaImage->mPlane[mediaImage->Y].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800340 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
341 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
342
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700343 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800344 mediaImage->mPlane[mediaImage->U].mColInc = 2;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700345 mediaImage->mPlane[mediaImage->U].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800346 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
347 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
348
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700349 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride + 1;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800350 mediaImage->mPlane[mediaImage->V].mColInc = 2;
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700351 mediaImage->mPlane[mediaImage->V].mRowInc = stride;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800352 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
353 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700354
355 if (tryWrapping && mClientColorFormat != COLOR_FormatYUV420Flexible) {
356 tryWrapping = yuv420888 && uPlane.colInc == 2 && vPlane.colInc == 2
357 && yPlane.rowInc == uPlane.rowInc
358 && view.data()[0] < view.data()[1]
359 && view.data()[1] < view.data()[2];
360 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800361 break;
362
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700363 case COLOR_FormatYUVP010:
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700364 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
365 mediaImage->mPlane[mediaImage->Y].mColInc = 2;
366 mediaImage->mPlane[mediaImage->Y].mRowInc = stride * 2;
367 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = 1;
368 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = 1;
369
370 mediaImage->mPlane[mediaImage->U].mOffset = stride * vStride * 2;
371 mediaImage->mPlane[mediaImage->U].mColInc = 4;
372 mediaImage->mPlane[mediaImage->U].mRowInc = stride * 2;
373 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = 2;
374 mediaImage->mPlane[mediaImage->U].mVertSubsampling = 2;
375
376 mediaImage->mPlane[mediaImage->V].mOffset = stride * vStride * 2 + 2;
377 mediaImage->mPlane[mediaImage->V].mColInc = 4;
378 mediaImage->mPlane[mediaImage->V].mRowInc = stride * 2;
379 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = 2;
380 mediaImage->mPlane[mediaImage->V].mVertSubsampling = 2;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700381 if (tryWrapping) {
382 tryWrapping = yPlane.allocatedDepth == 16
383 && uPlane.allocatedDepth == 16
384 && vPlane.allocatedDepth == 16
385 && yPlane.bitDepth == 10
386 && uPlane.bitDepth == 10
387 && vPlane.bitDepth == 10
388 && yPlane.rightShift == 6
389 && uPlane.rightShift == 6
390 && vPlane.rightShift == 6
391 && yPlane.rowSampling == 1 && yPlane.colSampling == 1
392 && uPlane.rowSampling == 2 && uPlane.colSampling == 2
393 && vPlane.rowSampling == 2 && vPlane.colSampling == 2
394 && yPlane.colInc == 2
395 && uPlane.colInc == 4
396 && vPlane.colInc == 4
397 && yPlane.rowInc == uPlane.rowInc
398 && yPlane.rowInc == vPlane.rowInc;
399 }
Wonsik Kim29e3c4d2020-09-02 12:19:44 -0700400 break;
401
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700402 default: {
403 // default to fully planar format --- this will be overridden if wrapping
404 // TODO: keep interleaved format
405 int32_t colInc = divUp(mAllocatedDepth, 8u);
406 int32_t rowInc = stride * colInc / yPlane.colSampling;
407 mediaImage->mPlane[mediaImage->Y].mOffset = 0;
408 mediaImage->mPlane[mediaImage->Y].mColInc = colInc;
409 mediaImage->mPlane[mediaImage->Y].mRowInc = rowInc;
410 mediaImage->mPlane[mediaImage->Y].mHorizSubsampling = yPlane.colSampling;
411 mediaImage->mPlane[mediaImage->Y].mVertSubsampling = yPlane.rowSampling;
412 int32_t offset = rowInc * vStride / yPlane.rowSampling;
413
414 rowInc = stride * colInc / uPlane.colSampling;
415 mediaImage->mPlane[mediaImage->U].mOffset = offset;
416 mediaImage->mPlane[mediaImage->U].mColInc = colInc;
417 mediaImage->mPlane[mediaImage->U].mRowInc = rowInc;
418 mediaImage->mPlane[mediaImage->U].mHorizSubsampling = uPlane.colSampling;
419 mediaImage->mPlane[mediaImage->U].mVertSubsampling = uPlane.rowSampling;
420 offset += rowInc * vStride / uPlane.rowSampling;
421
422 rowInc = stride * colInc / vPlane.colSampling;
423 mediaImage->mPlane[mediaImage->V].mOffset = offset;
424 mediaImage->mPlane[mediaImage->V].mColInc = colInc;
425 mediaImage->mPlane[mediaImage->V].mRowInc = rowInc;
426 mediaImage->mPlane[mediaImage->V].mHorizSubsampling = vPlane.colSampling;
427 mediaImage->mPlane[mediaImage->V].mVertSubsampling = vPlane.rowSampling;
428 break;
429 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800430 }
431 break;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700432 }
433
Pawin Vongmasa36653902018-11-15 00:10:25 -0800434 case C2PlanarLayout::TYPE_YUVA:
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700435 ALOGD("Converter: unrecognized color format "
436 "(client %d component %d) for YUVA layout",
437 mClientColorFormat, mComponentColorFormat);
438 mInitCheck = NO_INIT;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800439 return;
440 case C2PlanarLayout::TYPE_RGB:
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700441 ALOGD("Converter: unrecognized color format "
442 "(client %d component %d) for RGB layout",
443 mClientColorFormat, mComponentColorFormat);
444 mInitCheck = NO_INIT;
445 // TODO: support MediaImage layout
446 return;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800447 case C2PlanarLayout::TYPE_RGBA:
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700448 ALOGD("Converter: unrecognized color format "
449 "(client %d component %d) for RGBA layout",
450 mClientColorFormat, mComponentColorFormat);
451 mInitCheck = NO_INIT;
452 // TODO: support MediaImage layout
453 return;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800454 default:
455 mediaImage->mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700456 if (layout.numPlanes == 1) {
457 const C2PlaneInfo &plane = layout.planes[0];
458 if (plane.colInc < 0 || plane.rowInc < 0) {
459 // Copy-only if we have negative colInc/rowInc
460 tryWrapping = false;
461 }
462 mediaImage->mPlane[0].mOffset = 0;
463 mediaImage->mPlane[0].mColInc = std::abs(plane.colInc);
464 mediaImage->mPlane[0].mRowInc = std::abs(plane.rowInc);
465 mediaImage->mPlane[0].mHorizSubsampling = plane.colSampling;
466 mediaImage->mPlane[0].mVertSubsampling = plane.rowSampling;
467 } else {
468 ALOGD("Converter: unrecognized layout: color format (client %d component %d)",
469 mClientColorFormat, mComponentColorFormat);
470 mInitCheck = NO_INIT;
471 return;
472 }
473 break;
474 }
475 if (tryWrapping) {
476 // try to map directly. check if the planes are near one another
477 const uint8_t *minPtr = mView.data()[0];
478 const uint8_t *maxPtr = mView.data()[0];
479 int32_t planeSize = 0;
480 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
481 const C2PlaneInfo &plane = layout.planes[i];
482 int64_t planeStride = std::abs(plane.rowInc / plane.colInc);
483 ssize_t minOffset = plane.minOffset(
484 mWidth / plane.colSampling, mHeight / plane.rowSampling);
485 ssize_t maxOffset = plane.maxOffset(
486 mWidth / plane.colSampling, mHeight / plane.rowSampling);
487 if (minPtr > mView.data()[i] + minOffset) {
488 minPtr = mView.data()[i] + minOffset;
489 }
490 if (maxPtr < mView.data()[i] + maxOffset) {
491 maxPtr = mView.data()[i] + maxOffset;
492 }
493 planeSize += planeStride * divUp(mAllocatedDepth, 8u)
494 * align(mHeight, 64) / plane.rowSampling;
495 }
496
Wonsik Kimdc173402021-07-22 19:38:17 -0700497 if (minPtr == mView.data()[0] && (maxPtr - minPtr + 1) <= planeSize) {
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700498 // FIXME: this is risky as reading/writing data out of bound results
499 // in an undefined behavior, but gralloc does assume a
500 // contiguous mapping
501 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
502 const C2PlaneInfo &plane = layout.planes[i];
503 mediaImage->mPlane[i].mOffset = mView.data()[i] - minPtr;
504 mediaImage->mPlane[i].mColInc = plane.colInc;
505 mediaImage->mPlane[i].mRowInc = plane.rowInc;
506 mediaImage->mPlane[i].mHorizSubsampling = plane.colSampling;
507 mediaImage->mPlane[i].mVertSubsampling = plane.rowSampling;
508 }
509 mWrapped = new ABuffer(const_cast<uint8_t *>(minPtr),
510 maxPtr - minPtr + 1);
511 ALOGV("Converter: wrapped (capacity=%zu)", mWrapped->capacity());
512 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800513 }
514 mediaImage->mNumPlanes = layout.numPlanes;
Harish Mahendrakarf7c49e22019-05-24 14:19:16 -0700515 mediaImage->mWidth = view.crop().width;
516 mediaImage->mHeight = view.crop().height;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800517 mediaImage->mBitDepth = bitDepth;
518 mediaImage->mBitDepthAllocated = mAllocatedDepth;
519
520 uint32_t bufferSize = 0;
521 for (uint32_t i = 0; i < layout.numPlanes; ++i) {
522 const C2PlaneInfo &plane = layout.planes[i];
523 if (plane.allocatedDepth < plane.bitDepth
524 || plane.rightShift != plane.allocatedDepth - plane.bitDepth) {
525 ALOGD("rightShift value of %u unsupported", plane.rightShift);
526 mInitCheck = BAD_VALUE;
527 return;
528 }
529 if (plane.allocatedDepth > 8 && plane.endianness != C2PlaneInfo::NATIVE) {
530 ALOGD("endianness value of %u unsupported", plane.endianness);
531 mInitCheck = BAD_VALUE;
532 return;
533 }
534 if (plane.allocatedDepth != mAllocatedDepth || plane.bitDepth != bitDepth) {
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700535 ALOGD("different allocatedDepth/bitDepth per plane unsupported");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800536 mInitCheck = BAD_VALUE;
537 return;
538 }
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700539 bufferSize += stride * vStride
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700540 / plane.rowSampling / plane.colSampling * divUp(mAllocatedDepth, 8u);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800541 }
542
543 mBackBufferSize = bufferSize;
544 mInitCheck = OK;
545 }
546
547 status_t initCheck() const { return mInitCheck; }
548
549 uint32_t backBufferSize() const { return mBackBufferSize; }
550
551 /**
552 * Wrap C2GraphicView using a MediaImage2. Note that if not wrapped, the content is not mapped
553 * in this function --- the caller should use CopyGraphicView2MediaImage() function to copy the
554 * data into a backing buffer explicitly.
555 *
556 * \return media buffer. This is null if wrapping failed.
557 */
558 sp<ABuffer> wrap() const {
559 if (mBackBuffer == nullptr) {
560 return mWrapped;
561 }
562 return nullptr;
563 }
564
565 bool setBackBuffer(const sp<ABuffer> &backBuffer) {
Wonsik Kim186fdbf2019-01-29 13:30:01 -0800566 if (backBuffer == nullptr) {
567 return false;
568 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800569 if (backBuffer->capacity() < mBackBufferSize) {
570 return false;
571 }
572 backBuffer->setRange(0, mBackBufferSize);
573 mBackBuffer = backBuffer;
574 return true;
575 }
576
577 /**
578 * Copy C2GraphicView to MediaImage2.
579 */
580 status_t copyToMediaImage() {
581 if (mInitCheck != OK) {
582 return mInitCheck;
583 }
584 return ImageCopy(mBackBuffer->base(), getMediaImage(), mView);
585 }
586
587 const sp<ABuffer> &imageData() const { return mMediaImage; }
588
589private:
590 status_t mInitCheck;
591
592 const C2GraphicView mView;
593 uint32_t mWidth;
594 uint32_t mHeight;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700595 int32_t mClientColorFormat; ///< SDK color format for MediaImage
596 int32_t mComponentColorFormat; ///< SDK color format from component
Pawin Vongmasa36653902018-11-15 00:10:25 -0800597 sp<ABuffer> mWrapped; ///< wrapped buffer (if we can map C2Buffer to an ABuffer)
598 uint32_t mAllocatedDepth;
599 uint32_t mBackBufferSize;
600 sp<ABuffer> mMediaImage;
601 std::function<sp<ABuffer>(size_t)> mAlloc;
602
603 sp<ABuffer> mBackBuffer; ///< backing buffer if we have to copy C2Buffer <=> ABuffer
604
605 MediaImage2 *getMediaImage() {
606 return (MediaImage2 *)mMediaImage->base();
607 }
608};
609
610} // namespace
611
612// GraphicBlockBuffer
613
614// static
615sp<GraphicBlockBuffer> GraphicBlockBuffer::Allocate(
616 const sp<AMessage> &format,
617 const std::shared_ptr<C2GraphicBlock> &block,
618 std::function<sp<ABuffer>(size_t)> alloc) {
619 C2GraphicView view(block->map().get());
620 if (view.error() != C2_OK) {
621 ALOGD("C2GraphicBlock::map failed: %d", view.error());
622 return nullptr;
623 }
624
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700625 GraphicView2MediaImageConverter converter(view, format, false /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800626 if (converter.initCheck() != OK) {
627 ALOGD("Converter init failed: %d", converter.initCheck());
628 return nullptr;
629 }
630 bool wrapped = true;
631 sp<ABuffer> buffer = converter.wrap();
632 if (buffer == nullptr) {
633 buffer = alloc(converter.backBufferSize());
634 if (!converter.setBackBuffer(buffer)) {
635 ALOGD("Converter failed to set back buffer");
636 return nullptr;
637 }
638 wrapped = false;
639 }
640 return new GraphicBlockBuffer(
641 format,
642 buffer,
643 std::move(view),
644 block,
645 converter.imageData(),
646 wrapped);
647}
648
649GraphicBlockBuffer::GraphicBlockBuffer(
650 const sp<AMessage> &format,
651 const sp<ABuffer> &buffer,
652 C2GraphicView &&view,
653 const std::shared_ptr<C2GraphicBlock> &block,
654 const sp<ABuffer> &imageData,
655 bool wrapped)
656 : Codec2Buffer(format, buffer),
657 mView(view),
658 mBlock(block),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800659 mWrapped(wrapped) {
660 setImageData(imageData);
661}
662
663std::shared_ptr<C2Buffer> GraphicBlockBuffer::asC2Buffer() {
664 uint32_t width = mView.width();
665 uint32_t height = mView.height();
666 if (!mWrapped) {
667 (void)ImageCopy(mView, base(), imageData());
668 }
669 return C2Buffer::CreateGraphicBuffer(
670 mBlock->share(C2Rect(width, height), C2Fence()));
671}
672
673// GraphicMetadataBuffer
674GraphicMetadataBuffer::GraphicMetadataBuffer(
675 const sp<AMessage> &format,
676 const std::shared_ptr<C2Allocator> &alloc)
677 : Codec2Buffer(format, new ABuffer(sizeof(VideoNativeMetadata))),
678 mAlloc(alloc) {
679 ((VideoNativeMetadata *)base())->pBuffer = nullptr;
680}
681
682std::shared_ptr<C2Buffer> GraphicMetadataBuffer::asC2Buffer() {
bohua222c0b2021-01-12 18:54:53 -0800683#ifdef __LP64__
684 static std::once_flag s_checkOnce;
Harish Mahendrakar731e9142021-04-21 17:20:39 -0700685 static bool s_is64bitOk {true};
bohua222c0b2021-01-12 18:54:53 -0800686 std::call_once(s_checkOnce, [&](){
687 const std::string abi32list =
688 ::android::base::GetProperty("ro.product.cpu.abilist32", "");
Harish Mahendrakar731e9142021-04-21 17:20:39 -0700689 if (!abi32list.empty()) {
690 int32_t inputSurfaceSetting =
691 ::android::base::GetIntProperty("debug.stagefright.c2inputsurface", int32_t(0));
692 s_is64bitOk = inputSurfaceSetting != 0;
bohua222c0b2021-01-12 18:54:53 -0800693 }
694 });
695
Harish Mahendrakar731e9142021-04-21 17:20:39 -0700696 if (!s_is64bitOk) {
697 ALOGE("GraphicMetadataBuffer does not work in 32+64 system if compiled as 64-bit object"\
698 "when debug.stagefright.c2inputsurface is set to 0");
bohua222c0b2021-01-12 18:54:53 -0800699 return nullptr;
700 }
701#endif
702
Pawin Vongmasa36653902018-11-15 00:10:25 -0800703 VideoNativeMetadata *meta = (VideoNativeMetadata *)base();
704 ANativeWindowBuffer *buffer = (ANativeWindowBuffer *)meta->pBuffer;
705 if (buffer == nullptr) {
706 ALOGD("VideoNativeMetadata contains null buffer");
707 return nullptr;
708 }
709
710 ALOGV("VideoNativeMetadata: %dx%d", buffer->width, buffer->height);
711 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Sungtak Leea4d13be2019-01-23 15:24:46 -0800712 buffer->handle,
Pawin Vongmasa36653902018-11-15 00:10:25 -0800713 buffer->width,
714 buffer->height,
715 buffer->format,
716 buffer->usage,
717 buffer->stride);
718 std::shared_ptr<C2GraphicAllocation> alloc;
719 c2_status_t err = mAlloc->priorGraphicAllocation(handle, &alloc);
720 if (err != C2_OK) {
721 ALOGD("Failed to wrap VideoNativeMetadata into C2GraphicAllocation");
Chih-Yu Huangc0ac3552021-03-11 14:37:10 +0900722 native_handle_close(handle);
723 native_handle_delete(handle);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800724 return nullptr;
725 }
726 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
727
728 meta->pBuffer = 0;
Wonsik Kimebe0f9e2019-07-03 11:06:51 -0700729 // TODO: wrap this in C2Fence so that the component can wait when it
730 // actually starts processing.
731 if (meta->nFenceFd >= 0) {
732 sp<Fence> fence(new Fence(meta->nFenceFd));
733 fence->waitForever(LOG_TAG);
734 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800735 return C2Buffer::CreateGraphicBuffer(
736 block->share(C2Rect(buffer->width, buffer->height), C2Fence()));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800737}
738
739// ConstGraphicBlockBuffer
740
741// static
742sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::Allocate(
743 const sp<AMessage> &format,
744 const std::shared_ptr<C2Buffer> &buffer,
745 std::function<sp<ABuffer>(size_t)> alloc) {
746 if (!buffer
747 || buffer->data().type() != C2BufferData::GRAPHIC
748 || buffer->data().graphicBlocks().size() != 1u) {
749 ALOGD("C2Buffer precond fail");
750 return nullptr;
751 }
752 std::unique_ptr<const C2GraphicView> view(std::make_unique<const C2GraphicView>(
753 buffer->data().graphicBlocks()[0].map().get()));
754 std::unique_ptr<const C2GraphicView> holder;
755
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700756 GraphicView2MediaImageConverter converter(*view, format, false /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800757 if (converter.initCheck() != OK) {
758 ALOGD("Converter init failed: %d", converter.initCheck());
759 return nullptr;
760 }
761 bool wrapped = true;
762 sp<ABuffer> aBuffer = converter.wrap();
763 if (aBuffer == nullptr) {
764 aBuffer = alloc(converter.backBufferSize());
765 if (!converter.setBackBuffer(aBuffer)) {
766 ALOGD("Converter failed to set back buffer");
767 return nullptr;
768 }
769 wrapped = false;
770 converter.copyToMediaImage();
771 // We don't need the view.
772 holder = std::move(view);
773 }
774 return new ConstGraphicBlockBuffer(
775 format,
776 aBuffer,
777 std::move(view),
778 buffer,
779 converter.imageData(),
780 wrapped);
781}
782
783// static
784sp<ConstGraphicBlockBuffer> ConstGraphicBlockBuffer::AllocateEmpty(
785 const sp<AMessage> &format,
786 std::function<sp<ABuffer>(size_t)> alloc) {
787 int32_t width, height;
788 if (!format->findInt32("width", &width)
789 || !format->findInt32("height", &height)) {
790 ALOGD("format had no width / height");
791 return nullptr;
792 }
Wonsik Kim8bfa17a2019-05-30 22:12:30 -0700793 // NOTE: we currently only support YUV420 formats for byte-buffer mode.
794 sp<ABuffer> aBuffer(alloc(align(width, 16) * align(height, 16) * 3 / 2));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800795 return new ConstGraphicBlockBuffer(
796 format,
797 aBuffer,
798 nullptr,
799 nullptr,
800 nullptr,
801 false);
802}
803
804ConstGraphicBlockBuffer::ConstGraphicBlockBuffer(
805 const sp<AMessage> &format,
806 const sp<ABuffer> &aBuffer,
807 std::unique_ptr<const C2GraphicView> &&view,
808 const std::shared_ptr<C2Buffer> &buffer,
809 const sp<ABuffer> &imageData,
810 bool wrapped)
811 : Codec2Buffer(format, aBuffer),
812 mView(std::move(view)),
813 mBufferRef(buffer),
814 mWrapped(wrapped) {
Wonsik Kimc48ddcf2019-02-11 16:16:57 -0800815 setImageData(imageData);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800816}
817
818std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
Wonsik Kimf9b32122020-04-02 11:30:17 -0700819 return mBufferRef;
820}
821
822void ConstGraphicBlockBuffer::clearC2BufferRefs() {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800823 mView.reset();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700824 mBufferRef.reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800825}
826
827bool ConstGraphicBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
828 if (mWrapped || mBufferRef) {
829 ALOGD("ConstGraphicBlockBuffer::canCopy: %swrapped ; buffer ref %s",
830 mWrapped ? "" : "not ", mBufferRef ? "exists" : "doesn't exist");
831 return false;
832 }
833 if (!buffer) {
834 // Nothing to copy, so we can copy by doing nothing.
835 return true;
836 }
837 if (buffer->data().type() != C2BufferData::GRAPHIC) {
838 ALOGD("ConstGraphicBlockBuffer::canCopy: buffer precondition unsatisfied");
839 return false;
840 }
841 if (buffer->data().graphicBlocks().size() == 0) {
842 return true;
843 } else if (buffer->data().graphicBlocks().size() != 1u) {
844 ALOGD("ConstGraphicBlockBuffer::canCopy: too many blocks");
845 return false;
846 }
847
Pawin Vongmasa36653902018-11-15 00:10:25 -0800848 GraphicView2MediaImageConverter converter(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700849 buffer->data().graphicBlocks()[0].map().get(),
850 // FIXME: format() is not const, but we cannot change it, so do a const cast here
851 const_cast<ConstGraphicBlockBuffer *>(this)->format(),
852 true /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800853 if (converter.initCheck() != OK) {
854 ALOGD("ConstGraphicBlockBuffer::canCopy: converter init failed: %d", converter.initCheck());
855 return false;
856 }
857 if (converter.backBufferSize() > capacity()) {
858 ALOGD("ConstGraphicBlockBuffer::canCopy: insufficient capacity: req %u has %zu",
859 converter.backBufferSize(), capacity());
860 return false;
861 }
862 return true;
863}
864
865bool ConstGraphicBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
866 if (!buffer || buffer->data().graphicBlocks().size() == 0) {
867 setRange(0, 0);
868 return true;
869 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800870
871 GraphicView2MediaImageConverter converter(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -0700872 buffer->data().graphicBlocks()[0].map().get(), format(), true /* copy */);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800873 if (converter.initCheck() != OK) {
874 ALOGD("ConstGraphicBlockBuffer::copy: converter init failed: %d", converter.initCheck());
875 return false;
876 }
877 sp<ABuffer> aBuffer = new ABuffer(base(), capacity());
878 if (!converter.setBackBuffer(aBuffer)) {
879 ALOGD("ConstGraphicBlockBuffer::copy: set back buffer failed");
880 return false;
881 }
Pin-chih Lin1971e2c2019-04-15 19:36:26 +0800882 setRange(0, aBuffer->size()); // align size info
Pawin Vongmasa36653902018-11-15 00:10:25 -0800883 converter.copyToMediaImage();
884 setImageData(converter.imageData());
885 mBufferRef = buffer;
886 return true;
887}
888
889// EncryptedLinearBlockBuffer
890
891EncryptedLinearBlockBuffer::EncryptedLinearBlockBuffer(
892 const sp<AMessage> &format,
893 const std::shared_ptr<C2LinearBlock> &block,
894 const sp<IMemory> &memory,
895 int32_t heapSeqNum)
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700896 // TODO: Using unsecurePointer() has some associated security pitfalls
897 // (see declaration for details).
898 // Either document why it is safe in this case or address the
899 // issue (e.g. by copying).
900 : Codec2Buffer(format, new ABuffer(memory->unsecurePointer(), memory->size())),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800901 mBlock(block),
902 mMemory(memory),
903 mHeapSeqNum(heapSeqNum) {
904}
905
906std::shared_ptr<C2Buffer> EncryptedLinearBlockBuffer::asC2Buffer() {
907 return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
908}
909
910void EncryptedLinearBlockBuffer::fillSourceBuffer(
Robert Shih895fba92019-07-16 16:29:44 -0700911 hardware::drm::V1_0::SharedBuffer *source) {
912 BufferChannelBase::IMemoryToSharedBuffer(mMemory, mHeapSeqNum, source);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800913}
914
915void EncryptedLinearBlockBuffer::fillSourceBuffer(
916 hardware::cas::native::V1_0::SharedBuffer *source) {
917 ssize_t offset;
918 size_t size;
919
920 mHidlMemory = hardware::fromHeap(mMemory->getMemory(&offset, &size));
921 source->heapBase = *mHidlMemory;
922 source->offset = offset;
923 source->size = size;
924}
925
926bool EncryptedLinearBlockBuffer::copyDecryptedContent(
927 const sp<IMemory> &decrypted, size_t length) {
928 C2WriteView view = mBlock->map().get();
929 if (view.error() != C2_OK) {
930 return false;
931 }
932 if (view.size() < length) {
933 return false;
934 }
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700935 memcpy(view.data(), decrypted->unsecurePointer(), length);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800936 return true;
937}
938
939bool EncryptedLinearBlockBuffer::copyDecryptedContentFromMemory(size_t length) {
940 return copyDecryptedContent(mMemory, length);
941}
942
943native_handle_t *EncryptedLinearBlockBuffer::handle() const {
944 return const_cast<native_handle_t *>(mBlock->handle());
945}
946
947} // namespace android