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