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