1 /*
2 * Copyright (C) 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 #ifdef MPEG4
19 #define LOG_TAG "C2SoftMpeg4Dec"
20 #else
21 #define LOG_TAG "C2SoftH263Dec"
22 #endif
23 #include <log/log.h>
24
25 #include <media/stagefright/foundation/AUtils.h>
26 #include <media/stagefright/foundation/MediaDefs.h>
27
28 #include <C2Debug.h>
29 #include <C2PlatformSupport.h>
30 #include <SimpleC2Interface.h>
31
32 #include "C2SoftMpeg4Dec.h"
33 #include "mp4dec_api.h"
34
35 namespace android {
36
37 #ifdef MPEG4
38 constexpr char COMPONENT_NAME[] = "c2.android.mpeg4.decoder";
39 #else
40 constexpr char COMPONENT_NAME[] = "c2.android.h263.decoder";
41 #endif
42
43 class C2SoftMpeg4Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
44 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)45 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
46 : SimpleInterface<void>::BaseParams(
47 helper,
48 COMPONENT_NAME,
49 C2Component::KIND_DECODER,
50 C2Component::DOMAIN_VIDEO,
51 #ifdef MPEG4
52 MEDIA_MIMETYPE_VIDEO_MPEG4
53 #else
54 MEDIA_MIMETYPE_VIDEO_H263
55 #endif
56 ) {
57 noPrivateBuffers(); // TODO: account for our buffers here
58 noInputReferences();
59 noOutputReferences();
60 noInputLatency();
61 noTimeStretch();
62
63 // TODO: output latency and reordering
64
65 addParameter(
66 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
67 .withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL))
68 .build());
69
70 addParameter(
71 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
72 .withDefault(new C2StreamPictureSizeInfo::output(0u, 176, 144))
73 .withFields({
74 #ifdef MPEG4
75 C2F(mSize, width).inRange(2, 1920, 2),
76 C2F(mSize, height).inRange(2, 1088, 2),
77 #else
78 C2F(mSize, width).inRange(2, 352, 2),
79 C2F(mSize, height).inRange(2, 288, 2),
80 #endif
81 })
82 .withSetter(SizeSetter)
83 .build());
84
85 #ifdef MPEG4
86 addParameter(
87 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
88 .withDefault(new C2StreamProfileLevelInfo::input(0u,
89 C2Config::PROFILE_MP4V_SIMPLE, C2Config::LEVEL_MP4V_3))
90 .withFields({
91 C2F(mProfileLevel, profile).equalTo(
92 C2Config::PROFILE_MP4V_SIMPLE),
93 C2F(mProfileLevel, level).oneOf({
94 C2Config::LEVEL_MP4V_0,
95 C2Config::LEVEL_MP4V_0B,
96 C2Config::LEVEL_MP4V_1,
97 C2Config::LEVEL_MP4V_2,
98 C2Config::LEVEL_MP4V_3,
99 C2Config::LEVEL_MP4V_3B,
100 C2Config::LEVEL_MP4V_4,
101 C2Config::LEVEL_MP4V_4A,
102 C2Config::LEVEL_MP4V_5,
103 C2Config::LEVEL_MP4V_6})
104 })
105 .withSetter(ProfileLevelSetter, mSize)
106 .build());
107 #else
108 addParameter(
109 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
110 .withDefault(new C2StreamProfileLevelInfo::input(0u,
111 C2Config::PROFILE_H263_BASELINE, C2Config::LEVEL_H263_30))
112 .withFields({
113 C2F(mProfileLevel, profile).oneOf({
114 C2Config::PROFILE_H263_BASELINE,
115 C2Config::PROFILE_H263_ISWV2}),
116 C2F(mProfileLevel, level).oneOf({
117 C2Config::LEVEL_H263_10,
118 C2Config::LEVEL_H263_20,
119 C2Config::LEVEL_H263_30,
120 C2Config::LEVEL_H263_40,
121 C2Config::LEVEL_H263_45})
122 })
123 .withSetter(ProfileLevelSetter, mSize)
124 .build());
125 #endif
126
127 addParameter(
128 DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
129 #ifdef MPEG4
130 .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 1920, 1088))
131 #else
132 .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 352, 288))
133 #endif
134 .withFields({
135 #ifdef MPEG4
136 C2F(mSize, width).inRange(2, 1920, 2),
137 C2F(mSize, height).inRange(2, 1088, 2),
138 #else
139 C2F(mSize, width).inRange(2, 352, 2),
140 C2F(mSize, height).inRange(2, 288, 2),
141 #endif
142 })
143 .withSetter(MaxPictureSizeSetter, mSize)
144 .build());
145
146 addParameter(
147 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
148 #ifdef MPEG4
149 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 1920 * 1088 * 3 / 2))
150 #else
151 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 352 * 288 * 3 / 2))
152 #endif
153 .withFields({
154 C2F(mMaxInputSize, value).any(),
155 })
156 .calculatedAs(MaxInputSizeSetter, mMaxSize)
157 .build());
158
159 C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() };
160 std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
161 C2StreamColorInfo::output::AllocShared(
162 1u, 0u, 8u /* bitDepth */, C2Color::YUV_420);
163 memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
164
165 defaultColorInfo =
166 C2StreamColorInfo::output::AllocShared(
167 { C2ChromaOffsetStruct::ITU_YUV_420_0() },
168 0u, 8u /* bitDepth */, C2Color::YUV_420);
169 helper->addStructDescriptors<C2ChromaOffsetStruct>();
170
171 addParameter(
172 DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
173 .withConstValue(defaultColorInfo)
174 .build());
175
176 // TODO: support more formats?
177 addParameter(
178 DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
179 .withConstValue(new C2StreamPixelFormatInfo::output(
180 0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
181 .build());
182 }
183
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::output> & oldMe,C2P<C2VideoSizeStreamInfo::output> & me)184 static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
185 C2P<C2VideoSizeStreamInfo::output> &me) {
186 (void)mayBlock;
187 C2R res = C2R::Ok();
188 if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
189 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
190 me.set().width = oldMe.v.width;
191 }
192 if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
193 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
194 me.set().height = oldMe.v.height;
195 }
196 return res;
197 }
198
MaxPictureSizeSetter(bool mayBlock,C2P<C2StreamMaxPictureSizeTuning::output> & me,const C2P<C2StreamPictureSizeInfo::output> & size)199 static C2R MaxPictureSizeSetter(bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
200 const C2P<C2StreamPictureSizeInfo::output> &size) {
201 (void)mayBlock;
202 // TODO: get max width/height from the size's field helpers vs. hardcoding
203 #ifdef MPEG4
204 me.set().width = c2_min(c2_max(me.v.width, size.v.width), 1920u);
205 me.set().height = c2_min(c2_max(me.v.height, size.v.height), 1088u);
206 #else
207 me.set().width = c2_min(c2_max(me.v.width, size.v.width), 352u);
208 me.set().height = c2_min(c2_max(me.v.height, size.v.height), 288u);
209 #endif
210 return C2R::Ok();
211 }
212
MaxInputSizeSetter(bool mayBlock,C2P<C2StreamMaxBufferSizeInfo::input> & me,const C2P<C2StreamMaxPictureSizeTuning::output> & maxSize)213 static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
214 const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
215 (void)mayBlock;
216 // assume compression ratio of 1
217 me.set().value = (((maxSize.v.width + 15) / 16) * ((maxSize.v.height + 15) / 16) * 384);
218 return C2R::Ok();
219 }
220
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::input> & me,const C2P<C2StreamPictureSizeInfo::output> & size)221 static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
222 const C2P<C2StreamPictureSizeInfo::output> &size) {
223 (void)mayBlock;
224 (void)size;
225 (void)me; // TODO: validate
226 return C2R::Ok();
227 }
228
getMaxWidth() const229 uint32_t getMaxWidth() const { return mMaxSize->width; }
getMaxHeight() const230 uint32_t getMaxHeight() const { return mMaxSize->height; }
231
232 private:
233 std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
234 std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
235 std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
236 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
237 std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
238 std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
239 };
240
C2SoftMpeg4Dec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)241 C2SoftMpeg4Dec::C2SoftMpeg4Dec(
242 const char *name,
243 c2_node_id_t id,
244 const std::shared_ptr<IntfImpl> &intfImpl)
245 : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
246 mIntf(intfImpl),
247 mDecHandle(nullptr),
248 mOutputBuffer{},
249 mInitialized(false) {
250 }
251
~C2SoftMpeg4Dec()252 C2SoftMpeg4Dec::~C2SoftMpeg4Dec() {
253 onRelease();
254 }
255
onInit()256 c2_status_t C2SoftMpeg4Dec::onInit() {
257 status_t err = initDecoder();
258 return err == OK ? C2_OK : C2_CORRUPTED;
259 }
260
onStop()261 c2_status_t C2SoftMpeg4Dec::onStop() {
262 if (mInitialized) {
263 if (mDecHandle) {
264 PVCleanUpVideoDecoder(mDecHandle);
265 }
266 mInitialized = false;
267 }
268 for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
269 if (mOutputBuffer[i]) {
270 free(mOutputBuffer[i]);
271 mOutputBuffer[i] = nullptr;
272 }
273 }
274 mNumSamplesOutput = 0;
275 mFramesConfigured = false;
276 mSignalledOutputEos = false;
277 mSignalledError = false;
278
279 return C2_OK;
280 }
281
onReset()282 void C2SoftMpeg4Dec::onReset() {
283 (void)onStop();
284 (void)onInit();
285 }
286
onRelease()287 void C2SoftMpeg4Dec::onRelease() {
288 if (mInitialized) {
289 if (mDecHandle) {
290 PVCleanUpVideoDecoder(mDecHandle);
291 delete mDecHandle;
292 mDecHandle = nullptr;
293 }
294 mInitialized = false;
295 }
296 if (mOutBlock) {
297 mOutBlock.reset();
298 }
299 for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
300 if (mOutputBuffer[i]) {
301 free(mOutputBuffer[i]);
302 mOutputBuffer[i] = nullptr;
303 }
304 }
305 }
306
onFlush_sm()307 c2_status_t C2SoftMpeg4Dec::onFlush_sm() {
308 if (mInitialized) {
309 if (PV_TRUE != PVResetVideoDecoder(mDecHandle)) {
310 return C2_CORRUPTED;
311 }
312 }
313 mSignalledOutputEos = false;
314 mSignalledError = false;
315 return C2_OK;
316 }
317
initDecoder()318 status_t C2SoftMpeg4Dec::initDecoder() {
319 #ifdef MPEG4
320 mIsMpeg4 = true;
321 #else
322 mIsMpeg4 = false;
323 #endif
324 if (!mDecHandle) {
325 mDecHandle = new tagvideoDecControls;
326 }
327 if (!mDecHandle) {
328 ALOGE("mDecHandle is null");
329 return NO_MEMORY;
330 }
331 memset(mDecHandle, 0, sizeof(tagvideoDecControls));
332
333 /* TODO: bring these values to 352 and 288. It cannot be done as of now
334 * because, h263 doesn't seem to allow port reconfiguration. In OMX, the
335 * problem of larger width and height than default width and height is
336 * overcome by adaptivePlayBack() api call. This call gets width and height
337 * information from extractor. Such a thing is not possible here.
338 * So we are configuring to larger values.*/
339 mWidth = 1408;
340 mHeight = 1152;
341 mNumSamplesOutput = 0;
342 mInitialized = false;
343 mFramesConfigured = false;
344 mSignalledOutputEos = false;
345 mSignalledError = false;
346
347 return OK;
348 }
349
fillEmptyWork(const std::unique_ptr<C2Work> & work)350 void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
351 uint32_t flags = 0;
352 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
353 flags |= C2FrameData::FLAG_END_OF_STREAM;
354 ALOGV("signalling eos");
355 }
356 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
357 work->worklets.front()->output.buffers.clear();
358 work->worklets.front()->output.ordinal = work->input.ordinal;
359 work->workletsProcessed = 1u;
360 }
361
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work)362 void C2SoftMpeg4Dec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work) {
363 std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(std::move(mOutBlock),
364 C2Rect(mWidth, mHeight));
365 mOutBlock = nullptr;
366 auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
367 uint32_t flags = 0;
368 if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
369 (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
370 flags |= C2FrameData::FLAG_END_OF_STREAM;
371 ALOGV("signalling eos");
372 }
373 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
374 work->worklets.front()->output.buffers.clear();
375 work->worklets.front()->output.buffers.push_back(buffer);
376 work->worklets.front()->output.ordinal = work->input.ordinal;
377 work->workletsProcessed = 1u;
378 };
379 if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
380 fillWork(work);
381 } else {
382 finish(index, fillWork);
383 }
384 }
385
ensureDecoderState(const std::shared_ptr<C2BlockPool> & pool)386 c2_status_t C2SoftMpeg4Dec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
387 if (!mDecHandle) {
388 ALOGE("not supposed to be here, invalid decoder context");
389 return C2_CORRUPTED;
390 }
391
392 mOutputBufferSize = align(mIntf->getMaxWidth(), 16) * align(mIntf->getMaxHeight(), 16) * 3 / 2;
393 for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
394 if (!mOutputBuffer[i]) {
395 mOutputBuffer[i] = (uint8_t *)malloc(mOutputBufferSize);
396 if (!mOutputBuffer[i]) {
397 return C2_NO_MEMORY;
398 }
399 }
400 }
401 if (mOutBlock &&
402 (mOutBlock->width() != align(mWidth, 16) || mOutBlock->height() != mHeight)) {
403 mOutBlock.reset();
404 }
405 if (!mOutBlock) {
406 uint32_t format = HAL_PIXEL_FORMAT_YV12;
407 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
408 c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight, format, usage, &mOutBlock);
409 if (err != C2_OK) {
410 ALOGE("fetchGraphicBlock for Output failed with status %d", err);
411 return err;
412 }
413 ALOGV("provided (%dx%d) required (%dx%d)",
414 mOutBlock->width(), mOutBlock->height(), mWidth, mHeight);
415 }
416 return C2_OK;
417 }
418
handleResChange(const std::unique_ptr<C2Work> & work)419 bool C2SoftMpeg4Dec::handleResChange(const std::unique_ptr<C2Work> &work) {
420 uint32_t disp_width, disp_height;
421 PVGetVideoDimensions(mDecHandle, (int32 *)&disp_width, (int32 *)&disp_height);
422
423 uint32_t buf_width, buf_height;
424 PVGetBufferDimensions(mDecHandle, (int32 *)&buf_width, (int32 *)&buf_height);
425
426 CHECK_LE(disp_width, buf_width);
427 CHECK_LE(disp_height, buf_height);
428
429 ALOGV("display size (%dx%d), buffer size (%dx%d)",
430 disp_width, disp_height, buf_width, buf_height);
431
432 bool resChanged = false;
433 if (disp_width != mWidth || disp_height != mHeight) {
434 mWidth = disp_width;
435 mHeight = disp_height;
436 resChanged = true;
437 for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
438 if (mOutputBuffer[i]) {
439 free(mOutputBuffer[i]);
440 mOutputBuffer[i] = nullptr;
441 }
442 }
443
444 if (!mIsMpeg4) {
445 PVCleanUpVideoDecoder(mDecHandle);
446
447 uint8_t *vol_data[1]{};
448 int32_t vol_size = 0;
449
450 if (!PVInitVideoDecoder(
451 mDecHandle, vol_data, &vol_size, 1, mIntf->getMaxWidth(), mIntf->getMaxHeight(), H263_MODE)) {
452 ALOGE("Error in PVInitVideoDecoder H263_MODE while resChanged was set to true");
453 mSignalledError = true;
454 work->result = C2_CORRUPTED;
455 return true;
456 }
457 }
458 mFramesConfigured = false;
459 }
460 return resChanged;
461 }
462
463 /* TODO: can remove temporary copy after library supports writing to display
464 * buffer Y, U and V plane pointers using stride info. */
copyOutputBufferToYV12Frame(uint8_t * dst,uint8_t * src,size_t dstYStride,size_t srcYStride,uint32_t width,uint32_t height)465 static void copyOutputBufferToYV12Frame(uint8_t *dst, uint8_t *src, size_t dstYStride,
466 size_t srcYStride, uint32_t width, uint32_t height) {
467 size_t dstUVStride = align(dstYStride / 2, 16);
468 size_t srcUVStride = srcYStride / 2;
469 uint8_t *srcStart = src;
470 uint8_t *dstStart = dst;
471 size_t vStride = align(height, 16);
472 for (size_t i = 0; i < height; ++i) {
473 memcpy(dst, src, width);
474 src += srcYStride;
475 dst += dstYStride;
476 }
477 /* U buffer */
478 src = srcStart + vStride * srcYStride;
479 dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
480 for (size_t i = 0; i < height / 2; ++i) {
481 memcpy(dst, src, width / 2);
482 src += srcUVStride;
483 dst += dstUVStride;
484 }
485 /* V buffer */
486 src = srcStart + vStride * srcYStride * 5 / 4;
487 dst = dstStart + (dstYStride * height);
488 for (size_t i = 0; i < height / 2; ++i) {
489 memcpy(dst, src, width / 2);
490 src += srcUVStride;
491 dst += dstUVStride;
492 }
493 }
494
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)495 void C2SoftMpeg4Dec::process(
496 const std::unique_ptr<C2Work> &work,
497 const std::shared_ptr<C2BlockPool> &pool) {
498 // Initialize output work
499 work->result = C2_OK;
500 work->workletsProcessed = 1u;
501 work->worklets.front()->output.configUpdate.clear();
502 work->worklets.front()->output.flags = work->input.flags;
503
504 if (mSignalledError || mSignalledOutputEos) {
505 work->result = C2_BAD_VALUE;
506 return;
507 }
508
509 size_t inOffset = 0u;
510 size_t inSize = 0u;
511 uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
512 C2ReadView rView = mDummyReadView;
513 if (!work->input.buffers.empty()) {
514 rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
515 inSize = rView.capacity();
516 if (inSize && rView.error()) {
517 ALOGE("read view map failed %d", rView.error());
518 work->result = C2_CORRUPTED;
519 return;
520 }
521 }
522 ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
523 inSize, (int)work->input.ordinal.timestamp.peeku(),
524 (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
525
526 bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
527 if (inSize == 0) {
528 fillEmptyWork(work);
529 if (eos) {
530 mSignalledOutputEos = true;
531 }
532 return;
533 }
534
535 uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
536 uint32_t *start_code = (uint32_t *)bitstream;
537 bool volHeader = *start_code == 0xB0010000;
538 if (volHeader) {
539 PVCleanUpVideoDecoder(mDecHandle);
540 mInitialized = false;
541 }
542
543 if (!mInitialized) {
544 uint8_t *vol_data[1]{};
545 int32_t vol_size = 0;
546
547 bool codecConfig = (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0;
548 if (codecConfig || volHeader) {
549 vol_data[0] = bitstream;
550 vol_size = inSize;
551 }
552 MP4DecodingMode mode = (mIsMpeg4) ? MPEG4_MODE : H263_MODE;
553 if (!PVInitVideoDecoder(
554 mDecHandle, vol_data, &vol_size, 1,
555 mIntf->getMaxWidth(), mIntf->getMaxHeight(), mode)) {
556 ALOGE("PVInitVideoDecoder failed. Unsupported content?");
557 mSignalledError = true;
558 work->result = C2_CORRUPTED;
559 return;
560 }
561 mInitialized = true;
562 MP4DecodingMode actualMode = PVGetDecBitstreamMode(mDecHandle);
563 if (mode != actualMode) {
564 ALOGE("Decoded mode not same as actual mode of the decoder");
565 mSignalledError = true;
566 work->result = C2_CORRUPTED;
567 return;
568 }
569
570 PVSetPostProcType(mDecHandle, 0);
571 if (handleResChange(work)) {
572 ALOGI("Setting width and height");
573 C2VideoSizeStreamInfo::output size(0u, mWidth, mHeight);
574 std::vector<std::unique_ptr<C2SettingResult>> failures;
575 c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
576 if (err == OK) {
577 work->worklets.front()->output.configUpdate.push_back(
578 C2Param::Copy(size));
579 } else {
580 ALOGE("Config update size failed");
581 mSignalledError = true;
582 work->result = C2_CORRUPTED;
583 return;
584 }
585 }
586 if (codecConfig) {
587 fillEmptyWork(work);
588 return;
589 }
590 }
591
592 size_t inPos = 0;
593 while (inPos < inSize) {
594 c2_status_t err = ensureDecoderState(pool);
595 if (C2_OK != err) {
596 mSignalledError = true;
597 work->result = err;
598 return;
599 }
600 C2GraphicView wView = mOutBlock->map().get();
601 if (wView.error()) {
602 ALOGE("graphic view map failed %d", wView.error());
603 work->result = C2_CORRUPTED;
604 return;
605 }
606
607 uint32_t yFrameSize = sizeof(uint8) * mDecHandle->size;
608 if (mOutputBufferSize < yFrameSize * 3 / 2){
609 ALOGE("Too small output buffer: %zu bytes", mOutputBufferSize);
610 mSignalledError = true;
611 work->result = C2_NO_MEMORY;
612 return;
613 }
614
615 if (!mFramesConfigured) {
616 PVSetReferenceYUV(mDecHandle,mOutputBuffer[1]);
617 mFramesConfigured = true;
618 }
619
620 // Need to check if header contains new info, e.g., width/height, etc.
621 VopHeaderInfo header_info;
622 uint32_t useExtTimestamp = (inPos == 0);
623 int32_t tmpInSize = (int32_t)inSize;
624 uint8_t *bitstreamTmp = bitstream;
625 uint32_t timestamp = workIndex;
626 if (PVDecodeVopHeader(
627 mDecHandle, &bitstreamTmp, ×tamp, &tmpInSize,
628 &header_info, &useExtTimestamp,
629 mOutputBuffer[mNumSamplesOutput & 1]) != PV_TRUE) {
630 ALOGE("failed to decode vop header.");
631 mSignalledError = true;
632 work->result = C2_CORRUPTED;
633 return;
634 }
635
636 // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
637 // decoder may detect size change after PVDecodeVopHeader.
638 bool resChange = handleResChange(work);
639 if (mIsMpeg4 && resChange) {
640 mSignalledError = true;
641 work->result = C2_CORRUPTED;
642 return;
643 } else if (resChange) {
644 ALOGI("Setting width and height");
645 C2VideoSizeStreamInfo::output size(0u, mWidth, mHeight);
646 std::vector<std::unique_ptr<C2SettingResult>> failures;
647 c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
648 if (err == OK) {
649 work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(size));
650 } else {
651 ALOGE("Config update size failed");
652 mSignalledError = true;
653 work->result = C2_CORRUPTED;
654 return;
655 }
656 continue;
657 }
658
659 if (PVDecodeVopBody(mDecHandle, &tmpInSize) != PV_TRUE) {
660 ALOGE("failed to decode video frame.");
661 mSignalledError = true;
662 work->result = C2_CORRUPTED;
663 return;
664 }
665 if (handleResChange(work)) {
666 mSignalledError = true;
667 work->result = C2_CORRUPTED;
668 return;
669 }
670
671 uint8_t *outputBufferY = wView.data()[C2PlanarLayout::PLANE_Y];
672 (void)copyOutputBufferToYV12Frame(outputBufferY, mOutputBuffer[mNumSamplesOutput & 1],
673 wView.width(), align(mWidth, 16), mWidth, mHeight);
674
675 inPos += inSize - (size_t)tmpInSize;
676 finishWork(workIndex, work);
677 ++mNumSamplesOutput;
678 if (inSize - inPos != 0) {
679 ALOGD("decoded frame, ignoring further trailing bytes %d",
680 (int)inSize - (int)inPos);
681 break;
682 }
683 }
684 }
685
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)686 c2_status_t C2SoftMpeg4Dec::drain(
687 uint32_t drainMode,
688 const std::shared_ptr<C2BlockPool> &pool) {
689 (void)pool;
690 if (drainMode == NO_DRAIN) {
691 ALOGW("drain with NO_DRAIN: no-op");
692 return C2_OK;
693 }
694 if (drainMode == DRAIN_CHAIN) {
695 ALOGW("DRAIN_CHAIN not supported");
696 return C2_OMITTED;
697 }
698 return C2_OK;
699 }
700
701 class C2SoftMpeg4DecFactory : public C2ComponentFactory {
702 public:
C2SoftMpeg4DecFactory()703 C2SoftMpeg4DecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
704 GetCodec2PlatformComponentStore()->getParamReflector())) {
705 }
706
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)707 virtual c2_status_t createComponent(
708 c2_node_id_t id,
709 std::shared_ptr<C2Component>* const component,
710 std::function<void(C2Component*)> deleter) override {
711 *component = std::shared_ptr<C2Component>(
712 new C2SoftMpeg4Dec(COMPONENT_NAME,
713 id,
714 std::make_shared<C2SoftMpeg4Dec::IntfImpl>(mHelper)),
715 deleter);
716 return C2_OK;
717 }
718
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)719 virtual c2_status_t createInterface(
720 c2_node_id_t id,
721 std::shared_ptr<C2ComponentInterface>* const interface,
722 std::function<void(C2ComponentInterface*)> deleter) override {
723 *interface = std::shared_ptr<C2ComponentInterface>(
724 new SimpleInterface<C2SoftMpeg4Dec::IntfImpl>(
725 COMPONENT_NAME, id, std::make_shared<C2SoftMpeg4Dec::IntfImpl>(mHelper)),
726 deleter);
727 return C2_OK;
728 }
729
730 virtual ~C2SoftMpeg4DecFactory() override = default;
731
732 private:
733 std::shared_ptr<C2ReflectorHelper> mHelper;
734 };
735
736 } // namespace android
737
CreateCodec2Factory()738 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
739 ALOGV("in %s", __func__);
740 return new ::android::C2SoftMpeg4DecFactory();
741 }
742
DestroyCodec2Factory(::C2ComponentFactory * factory)743 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
744 ALOGV("in %s", __func__);
745 delete factory;
746 }
747