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