1/* 2 * Copyright (C) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15#include <arpa/inet.h> 16#include <sys/time.h> 17#include <utility> 18#include "videodec_sample.h" 19using namespace OHOS; 20using namespace OHOS::Media; 21using namespace std; 22namespace { 23const string MIME_TYPE = "video/avc"; 24constexpr int64_t NANOS_IN_SECOND = 1000000000L; 25constexpr int64_t NANOS_IN_MICRO = 1000L; 26 27constexpr int32_t EIGHT = 8; 28constexpr int32_t SIXTEEN = 16; 29constexpr int32_t TWENTY_FOUR = 24; 30constexpr uint8_t SEI = 6; 31constexpr uint8_t SPS = 7; 32constexpr uint8_t PPS = 8; 33constexpr uint32_t START_CODE_SIZE = 4; 34constexpr uint8_t START_CODE[START_CODE_SIZE] = {0, 0, 0, 1}; 35VDecFuzzSample *g_decSample = nullptr; 36constexpr uint8_t H264_NALU_TYPE = 0x1f; 37 38bool g_fuzzError = false; 39 40void clearIntqueue(std::queue<uint32_t> &q) 41{ 42 std::queue<uint32_t> empty; 43 swap(empty, q); 44} 45 46void clearBufferqueue(std::queue<OH_AVCodecBufferAttr> &q) 47{ 48 std::queue<OH_AVCodecBufferAttr> empty; 49 swap(empty, q); 50} 51 52void clearAvBufferQueue(std::queue<OH_AVMemory *> &q) 53{ 54 std::queue<OH_AVMemory *> empty; 55 swap(empty, q); 56} 57} // namespace 58 59class TestConsumerListener : public IBufferConsumerListener { 60public: 61 TestConsumerListener(sptr<Surface> cs) : cs(cs) {}; 62 ~TestConsumerListener() {} 63 void OnBufferAvailable() override 64 { 65 sptr<SurfaceBuffer> buffer; 66 int32_t flushFence; 67 cs->AcquireBuffer(buffer, flushFence, timestamp, damage); 68 69 cs->ReleaseBuffer(buffer, -1); 70 } 71 72private: 73 int64_t timestamp = 0; 74 Rect damage = {}; 75 sptr<Surface> cs {nullptr}; 76}; 77 78VDecFuzzSample::~VDecFuzzSample() 79{ 80 Release(); 81} 82 83void VdecError(OH_AVCodec *codec, int32_t errorCode, void *userData) 84{ 85 VDecSignal *signal = static_cast<VDecSignal *>(userData); 86 if (signal == nullptr) { 87 return; 88 } 89 cout << "Error errorCode=" << errorCode << endl; 90 g_fuzzError = true; 91 signal->inCond_.notify_all(); 92} 93 94void VdecFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) 95{ 96 cout << "Format Changed" << endl; 97 int32_t currentWidth = 0; 98 int32_t currentHeight = 0; 99 OH_AVFormat_GetIntValue(format, OH_MD_KEY_WIDTH, ¤tWidth); 100 OH_AVFormat_GetIntValue(format, OH_MD_KEY_HEIGHT, ¤tHeight); 101 g_decSample->defaultWidth = currentWidth; 102 g_decSample->defaultHeight = currentHeight; 103} 104 105void VdecInputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData) 106{ 107 VDecSignal *signal = static_cast<VDecSignal *>(userData); 108 if (signal == nullptr) { 109 return; 110 } 111 unique_lock<mutex> lock(signal->inMutex_); 112 signal->inIdxQueue_.push(index); 113 signal->inBufferQueue_.push(data); 114 signal->inCond_.notify_all(); 115} 116 117void VdecOutputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr, 118 void *userData) 119{ 120 VDecSignal *signal = static_cast<VDecSignal *>(userData); 121 if (signal == nullptr) { 122 return; 123 } 124 unique_lock<mutex> lock(signal->outMutex_); 125 signal->outIdxQueue_.push(index); 126 signal->attrQueue_.push(*attr); 127 signal->outBufferQueue_.push(data); 128 signal->outCond_.notify_all(); 129 if (g_decSample->isSurfMode) { 130 OH_VideoDecoder_RenderOutputData(codec, index); 131 } else { 132 OH_VideoDecoder_FreeOutputData(codec, index); 133 } 134} 135 136int64_t VDecFuzzSample::GetSystemTimeUs() 137{ 138 struct timespec now; 139 (void)clock_gettime(CLOCK_BOOTTIME, &now); 140 int64_t nanoTime = static_cast<int64_t>(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec; 141 return nanoTime / NANOS_IN_MICRO; 142} 143 144int32_t VDecFuzzSample::ConfigureVideoDecoder() 145{ 146 if (isSurfMode) { 147 cs = Surface::CreateSurfaceAsConsumer(); 148 sptr<IBufferConsumerListener> listener = new TestConsumerListener(cs); 149 cs->RegisterConsumerListener(listener); 150 auto p = cs->GetProducer(); 151 ps = Surface::CreateSurfaceAsProducer(p); 152 nativeWindow = CreateNativeWindowFromSurface(&ps); 153 OH_VideoDecoder_SetSurface(vdec_, nativeWindow); 154 } 155 OH_AVFormat *format = OH_AVFormat_Create(); 156 if (format == nullptr) { 157 cout << "Fatal: Failed to create format" << endl; 158 return AV_ERR_UNKNOWN; 159 } 160 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, defaultWidth); 161 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, defaultHeight); 162 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, defaultFrameRate); 163 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, defaultRotation); 164 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, defaultPixelFormat); 165 int ret = OH_VideoDecoder_Configure(vdec_, format); 166 OH_AVFormat_Destroy(format); 167 return ret; 168} 169 170int32_t VDecFuzzSample::RunVideoDec(string codeName) 171{ 172 int err = CreateVideoDecoder(codeName); 173 if (err != AV_ERR_OK) { 174 cout << "Failed to create video decoder" << endl; 175 return err; 176 } 177 err = ConfigureVideoDecoder(); 178 if (err != AV_ERR_OK) { 179 cout << "Failed to configure video decoder" << endl; 180 Release(); 181 return err; 182 } 183 err = SetVideoDecoderCallback(); 184 if (err != AV_ERR_OK) { 185 cout << "Failed to setCallback" << endl; 186 Release(); 187 return err; 188 } 189 err = StartVideoDecoder(); 190 if (err != AV_ERR_OK) { 191 cout << "Failed to start video decoder" << endl; 192 Release(); 193 return err; 194 } 195 return err; 196} 197 198int32_t VDecFuzzSample::SetVideoDecoderCallback() 199{ 200 signal_ = new VDecSignal(); 201 if (signal_ == nullptr) { 202 cout << "Failed to new VDecSignal" << endl; 203 return AV_ERR_UNKNOWN; 204 } 205 206 cb_.onError = VdecError; 207 cb_.onStreamChanged = VdecFormatChanged; 208 cb_.onNeedInputData = VdecInputDataReady; 209 cb_.onNeedOutputData = VdecOutputDataReady; 210 return OH_VideoDecoder_SetCallback(vdec_, cb_, static_cast<void *>(signal_)); 211} 212 213void VDecFuzzSample::ReleaseInFile() 214{ 215 if (inFile_ != nullptr) { 216 if (inFile_->is_open()) { 217 inFile_->close(); 218 } 219 inFile_.reset(); 220 inFile_ = nullptr; 221 } 222} 223 224void VDecFuzzSample::StopInloop() 225{ 226 if (inputLoop_ != nullptr && inputLoop_->joinable()) { 227 unique_lock<mutex> lock(signal_->inMutex_); 228 clearIntqueue(signal_->inIdxQueue_); 229 signal_->inCond_.notify_all(); 230 lock.unlock(); 231 232 inputLoop_->join(); 233 inputLoop_.reset(); 234 } 235} 236 237int32_t VDecFuzzSample::StartVideoDecoder() 238{ 239 int ret = OH_VideoDecoder_Start(vdec_); 240 if (ret != AV_ERR_OK) { 241 cout << "Failed to start codec" << endl; 242 return ret; 243 } 244 245 isRunning_.store(true); 246 247 inFile_ = make_unique<ifstream>(); 248 if (inFile_ == nullptr) { 249 isRunning_.store(false); 250 (void)OH_VideoDecoder_Stop(vdec_); 251 return AV_ERR_UNKNOWN; 252 } 253 inFile_->open(inpDir, ios::in | ios::binary); 254 if (!inFile_->is_open()) { 255 cout << "open input file failed" << endl; 256 isRunning_.store(false); 257 (void)OH_VideoDecoder_Stop(vdec_); 258 inFile_->close(); 259 inFile_.reset(); 260 inFile_ = nullptr; 261 return AV_ERR_UNKNOWN; 262 } 263 264 inputLoop_ = make_unique<thread>(&VDecFuzzSample::InputFuncAVCC, this); 265 if (inputLoop_ == nullptr) { 266 cout << "Failed to create input loop" << endl; 267 isRunning_.store(false); 268 (void)OH_VideoDecoder_Stop(vdec_); 269 ReleaseInFile(); 270 return AV_ERR_UNKNOWN; 271 } 272 return AV_ERR_OK; 273} 274 275int32_t VDecFuzzSample::CreateVideoDecoder(string codeName) 276{ 277 vdec_ = OH_VideoDecoder_CreateByName("aabbcc"); 278 if (vdec_) { 279 OH_VideoDecoder_Destroy(vdec_); 280 vdec_ = nullptr; 281 } 282 OH_AVCodec *tmpDec = OH_VideoDecoder_CreateByMime("aabbcc"); 283 if (tmpDec) { 284 OH_VideoDecoder_Destroy(tmpDec); 285 tmpDec = nullptr; 286 } 287 tmpDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC); 288 if (tmpDec) { 289 OH_VideoDecoder_Destroy(tmpDec); 290 tmpDec = nullptr; 291 } 292 vdec_ = OH_VideoDecoder_CreateByName(codeName.c_str()); 293 g_decSample = this; 294 return vdec_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK; 295} 296 297void VDecFuzzSample::WaitForEOS() 298{ 299 if (inputLoop_ && inputLoop_->joinable()) { 300 inputLoop_->join(); 301 } 302} 303 304void VDecFuzzSample::CopyStartCode(uint8_t *frameBuffer, uint32_t bufferSize, OH_AVCodecBufferAttr &attr) 305{ 306 switch (frameBuffer[START_CODE_SIZE] & H264_NALU_TYPE) { 307 case SPS: 308 case PPS: 309 case SEI: 310 if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) { 311 cout << "Fatal: memory copy failed" << endl; 312 } 313 attr.pts = GetSystemTimeUs(); 314 attr.size = bufferSize + START_CODE_SIZE; 315 attr.offset = 0; 316 attr.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA; 317 break; 318 default: { 319 if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) { 320 cout << "Fatal: memory copy failed" << endl; 321 } 322 attr.pts = GetSystemTimeUs(); 323 attr.size = bufferSize + START_CODE_SIZE; 324 attr.offset = 0; 325 attr.flags = AVCODEC_BUFFER_FLAGS_NONE; 326 } 327 } 328} 329 330int32_t VDecFuzzSample::ReadData(uint32_t index, OH_AVMemory *buffer) 331{ 332 uint8_t ch[4] = {}; 333 (void)inFile_->read(reinterpret_cast<char *>(ch), START_CODE_SIZE); 334 if (repeatRun && inFile_->eof()) { 335 inFile_->clear(); 336 inFile_->seekg(0, ios::beg); 337 cout << "repeat" << endl; 338 return 0; 339 } else if (inFile_->eof()) { 340 SetEOS(index); 341 return 1; 342 } 343 uint32_t bufferSize = static_cast<uint32_t>(((ch[3] & 0xFF)) | ((ch[2] & 0xFF) << EIGHT) | 344 ((ch[1] & 0xFF) << SIXTEEN) | ((ch[0] & 0xFF) << TWENTY_FOUR)); 345 return SendData(bufferSize, index, buffer); 346} 347 348uint32_t VDecFuzzSample::SendData(uint32_t bufferSize, uint32_t index, OH_AVMemory *buffer) 349{ 350 OH_AVCodecBufferAttr attr; 351 uint8_t *frameBuffer = new uint8_t[bufferSize + START_CODE_SIZE]; 352 (void)inFile_->read(reinterpret_cast<char *>(frameBuffer + START_CODE_SIZE), bufferSize); 353 CopyStartCode(frameBuffer, bufferSize, attr); 354 int32_t size = OH_AVMemory_GetSize(buffer); 355 if (size < attr.size) { 356 delete[] frameBuffer; 357 cout << "ERROR:AVMemory not enough, buffer size" << attr.size << " AVMemory Size " << size << endl; 358 isRunning_.store(false); 359 return 1; 360 } 361 uint8_t *bufferAddr = OH_AVMemory_GetAddr(buffer); 362 if (memcpy_s(bufferAddr, size, frameBuffer, attr.size) != EOK) { 363 delete[] frameBuffer; 364 cout << "Fatal: memcpy fail" << endl; 365 isRunning_.store(false); 366 return 1; 367 } 368 delete[] frameBuffer; 369 int32_t ret = OH_VideoDecoder_PushInputData(vdec_, index, attr); 370 if (ret != AV_ERR_OK) { 371 errCount++; 372 cout << "push input data failed, error:" << ret << endl; 373 } 374 frameCount_ = frameCount_ + 1; 375 if (inFile_->eof()) { 376 isRunning_.store(false); 377 } 378 return 0; 379} 380 381void VDecFuzzSample::InputFuncAVCC() 382{ 383 frameCount_ = 1; 384 errCount = 0; 385 while (true) { 386 if (!isRunning_.load()) { 387 break; 388 } 389 unique_lock<mutex> lock(signal_->inMutex_); 390 signal_->inCond_.wait(lock, [this]() { 391 if (!isRunning_.load()) { 392 cout << "quit signal" << endl; 393 return true; 394 } 395 return signal_->inIdxQueue_.size() > 0; 396 }); 397 if (!isRunning_.load()) { 398 break; 399 } 400 uint32_t index = signal_->inIdxQueue_.front(); 401 auto buffer = signal_->inBufferQueue_.front(); 402 signal_->inIdxQueue_.pop(); 403 signal_->inBufferQueue_.pop(); 404 lock.unlock(); 405 if (!inFile_->eof()) { 406 int ret = ReadData(index, buffer); 407 if (ret == 1) { 408 break; 409 } 410 } 411 } 412} 413 414OH_AVErrCode VDecFuzzSample::InputFuncFUZZ(const uint8_t *data, size_t size) 415{ 416 uint32_t index; 417 unique_lock<mutex> lock(signal_->inMutex_); 418 signal_->inCond_.wait(lock, [this]() { 419 if (!isRunning_.load() && g_fuzzError) { 420 return true; 421 } 422 return signal_->inIdxQueue_.size() > 0; 423 }); 424 if (g_fuzzError) 425 return AV_ERR_TIMEOUT; 426 index = signal_->inIdxQueue_.front(); 427 auto buffer = signal_->inBufferQueue_.front(); 428 lock.unlock(); 429 int32_t bufferSize = OH_AVMemory_GetSize(buffer); 430 uint8_t *bufferAddr = OH_AVMemory_GetAddr(buffer); 431 432 if (memcpy_s(bufferAddr, bufferSize, data, size) != EOK) { 433 cout << "Fatal: memcpy fail" << endl; 434 return AV_ERR_NO_MEMORY; 435 } 436 OH_AVCodecBufferAttr attr; 437 attr.pts = GetSystemTimeUs(); 438 attr.size = bufferSize; 439 attr.offset = 0; 440 attr.flags = AVCODEC_BUFFER_FLAGS_NONE; 441 OH_AVErrCode ret = OH_VideoDecoder_PushInputData(vdec_, index, attr); 442 signal_->inIdxQueue_.pop(); 443 signal_->inBufferQueue_.pop(); 444 return ret; 445} 446 447void VDecFuzzSample::SetEOS(uint32_t index) 448{ 449 OH_AVCodecBufferAttr attr; 450 attr.pts = 0; 451 attr.size = 0; 452 attr.offset = 0; 453 attr.flags = AVCODEC_BUFFER_FLAGS_EOS; 454 int32_t res = OH_VideoDecoder_PushInputData(vdec_, index, attr); 455 cout << "OH_VideoDecoder_PushInputData EOS res: " << res << endl; 456} 457 458int32_t VDecFuzzSample::Flush() 459{ 460 unique_lock<mutex> inLock(signal_->inMutex_); 461 clearIntqueue(signal_->inIdxQueue_); 462 signal_->inCond_.notify_all(); 463 inLock.unlock(); 464 unique_lock<mutex> outLock(signal_->outMutex_); 465 clearIntqueue(signal_->outIdxQueue_); 466 clearBufferqueue(signal_->attrQueue_); 467 signal_->outCond_.notify_all(); 468 isRunning_.store(false); 469 outLock.unlock(); 470 471 return OH_VideoDecoder_Flush(vdec_); 472} 473 474int32_t VDecFuzzSample::Reset() 475{ 476 isRunning_.store(false); 477 StopInloop(); 478 ReleaseInFile(); 479 return OH_VideoDecoder_Reset(vdec_); 480} 481 482int32_t VDecFuzzSample::Release() 483{ 484 int ret = 0; 485 if (vdec_ != nullptr) { 486 ret = OH_VideoDecoder_Destroy(vdec_); 487 vdec_ = nullptr; 488 } 489 if (signal_ != nullptr) { 490 clearAvBufferQueue(signal_->inBufferQueue_); 491 clearAvBufferQueue(signal_->outBufferQueue_); 492 delete signal_; 493 signal_ = nullptr; 494 } 495 return ret; 496} 497 498int32_t VDecFuzzSample::Stop() 499{ 500 StopInloop(); 501 clearIntqueue(signal_->outIdxQueue_); 502 clearBufferqueue(signal_->attrQueue_); 503 ReleaseInFile(); 504 return OH_VideoDecoder_Stop(vdec_); 505} 506 507int32_t VDecFuzzSample::Start() 508{ 509 int32_t ret = 0; 510 ret = OH_VideoDecoder_Start(vdec_); 511 if (ret == AV_ERR_OK) { 512 isRunning_.store(true); 513 } 514 return ret; 515} 516 517int32_t VDecFuzzSample::SetParameter(OH_AVFormat *format) 518{ 519 return OH_VideoDecoder_SetParameter(vdec_, format); 520}