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