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 "iconsumer_surface.h"
19 #include "openssl/crypto.h"
20 #include "openssl/sha.h"
21 #include "videodec_sample.h"
22 using namespace OHOS;
23 using namespace OHOS::Media;
24 using namespace std;
25 namespace {
26 constexpr int64_t NANOS_IN_SECOND = 1000000000L;
27 constexpr int64_t NANOS_IN_MICRO = 1000L;
28
29 constexpr int32_t EIGHT = 8;
30 constexpr int32_t SIXTEEN = 16;
31 constexpr int32_t TWENTY_FOUR = 24;
32 constexpr uint8_t SEI = 6;
33 constexpr uint8_t SPS = 7;
34 constexpr uint8_t PPS = 8;
35 constexpr uint32_t START_CODE_SIZE = 4;
36 constexpr uint8_t START_CODE[START_CODE_SIZE] = {0, 0, 0, 1};
37 constexpr uint32_t FRAME_INTERVAL = 16666;
38 constexpr uint32_t EOS_COUNT = 10;
39 constexpr uint32_t MAX_WIDTH = 4000;
40 constexpr uint32_t MAX_HEIGHT = 3000;
41 VDecNdkSample *dec_sample = nullptr;
42 constexpr uint8_t H264_NALU_TYPE = 0x1f;
43 SHA512_CTX c;
44 sptr<Surface> cs = nullptr;
45 sptr<Surface> ps = nullptr;
46 unsigned char md[SHA512_DIGEST_LENGTH];
47 bool g_fuzzError = false;
48
clearIntqueue(std::queue<uint32_t> & q)49 void clearIntqueue(std::queue<uint32_t> &q)
50 {
51 std::queue<uint32_t> empty;
52 swap(empty, q);
53 }
54
clearBufferqueue(std::queue<OH_AVCodecBufferAttr> & q)55 void clearBufferqueue(std::queue<OH_AVCodecBufferAttr> &q)
56 {
57 std::queue<OH_AVCodecBufferAttr> empty;
58 swap(empty, q);
59 }
60 } // namespace
61
62 class TestConsumerListener : public IBufferConsumerListener {
63 public:
TestConsumerListener(sptr<Surface> cs,std::string_view name)64 TestConsumerListener(sptr<Surface> cs, std::string_view name) : cs(cs)
65 {
66 outFile_ = std::make_unique<std::ofstream>();
67 outFile_->open(name.data(), std::ios::out | std::ios::binary);
68 };
~TestConsumerListener()69 ~TestConsumerListener()
70 {
71 if (outFile_ != nullptr) {
72 outFile_->close();
73 }
74 }
OnBufferAvailable()75 void OnBufferAvailable() override
76 {
77 sptr<SurfaceBuffer> buffer;
78 int32_t flushFence;
79 cs->AcquireBuffer(buffer, flushFence, timestamp, damage);
80 cs->ReleaseBuffer(buffer, -1);
81 }
82
83 private:
84 int64_t timestamp = 0;
85 Rect damage = {};
86 sptr<Surface> cs {nullptr};
87 std::unique_ptr<std::ofstream> outFile_;
88 };
~VDecNdkSample()89 VDecNdkSample::~VDecNdkSample()
90 {
91 Release();
92 }
93
VdecError(OH_AVCodec * codec,int32_t errorCode,void * userData)94 void VdecError(OH_AVCodec *codec, int32_t errorCode, void *userData)
95 {
96 VDecSignal *signal = static_cast<VDecSignal *>(userData);
97 if (signal == nullptr) {
98 return;
99 }
100 cout << "Error errorCode=" << errorCode << endl;
101 g_fuzzError = true;
102 signal->inCond_.notify_all();
103 }
104
VdecFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)105 void VdecFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
106 {
107 cout << "Format Changed" << endl;
108 int32_t current_width = 0;
109 int32_t current_height = 0;
110 OH_AVFormat_GetIntValue(format, OH_MD_KEY_WIDTH, ¤t_width);
111 OH_AVFormat_GetIntValue(format, OH_MD_KEY_HEIGHT, ¤t_height);
112 dec_sample->DEFAULT_WIDTH = current_width;
113 dec_sample->DEFAULT_HEIGHT = current_height;
114 }
115
VdecInputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)116 void VdecInputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
117 {
118 VDecSignal *signal = static_cast<VDecSignal *>(userData);
119 if (signal == nullptr) {
120 return;
121 }
122 unique_lock<mutex> lock(signal->inMutex_);
123 signal->inIdxQueue_.push(index);
124 signal->inBufferQueue_.push(data);
125 signal->inCond_.notify_all();
126 }
127
VdecOutputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)128 void VdecOutputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
129 void *userData)
130 {
131 VDecSignal *signal = static_cast<VDecSignal *>(userData);
132 if (signal == nullptr) {
133 return;
134 }
135 unique_lock<mutex> lock(signal->outMutex_);
136 signal->outIdxQueue_.push(index);
137 signal->attrQueue_.push(*attr);
138 signal->outBufferQueue_.push(data);
139 signal->outCond_.notify_all();
140 }
141
MdCompare(unsigned char * buffer,int len,const char * source[])142 bool VDecNdkSample::MdCompare(unsigned char *buffer, int len, const char *source[])
143 {
144 bool result = true;
145 for (int i = 0; i < len; i++) {
146 char std[SHA512_DIGEST_LENGTH] = {0};
147 int re = strcmp(source[i], std);
148 if (re != 0) {
149 result = false;
150 break;
151 }
152 }
153 return result;
154 }
155
GetSystemTimeUs()156 int64_t VDecNdkSample::GetSystemTimeUs()
157 {
158 struct timespec now;
159 (void)clock_gettime(CLOCK_BOOTTIME, &now);
160 int64_t nanoTime = (int64_t)now.tv_sec * NANOS_IN_SECOND + now.tv_nsec;
161 return nanoTime / NANOS_IN_MICRO;
162 }
163
ConfigureVideoDecoder()164 int32_t VDecNdkSample::ConfigureVideoDecoder()
165 {
166 OH_AVFormat *format = OH_AVFormat_Create();
167 if (format == nullptr) {
168 cout << "Fatal: Failed to create format" << endl;
169 return AV_ERR_UNKNOWN;
170 }
171 if (maxInputSize > 0) {
172 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_MAX_INPUT_SIZE, maxInputSize);
173 }
174 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
175 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
176 originalHeight = DEFAULT_HEIGHT;
177 originalWidth = DEFAULT_WIDTH;
178 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, DEFAULT_FRAME_RATE);
179 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, DEFAULT_ROTATION);
180 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, DEFAULT_PIXEL_FORMAT);
181 int ret = OH_VideoDecoder_Configure(vdec_, format);
182 OH_AVFormat_Destroy(format);
183 return ret;
184 }
185
CheckOutputDescription()186 void VDecNdkSample::CheckOutputDescription()
187 {
188 OH_AVFormat *newFormat = OH_VideoDecoder_GetOutputDescription(vdec_);
189 if (newFormat != nullptr) {
190 int32_t picWidth = 0;
191 int32_t picHeight = 0;
192 OH_AVFormat_GetIntValue(newFormat, OH_MD_KEY_VIDEO_PIC_WIDTH, &picWidth);
193 OH_AVFormat_GetIntValue(newFormat, OH_MD_KEY_VIDEO_PIC_HEIGHT, &picHeight);
194 if (picWidth != originalWidth || picHeight != originalHeight) {
195 std::cout << "picWidth:" << picWidth << " picHeight:" << picHeight << std::endl;
196 std::cout << "errCount !=:" << errCount << std::endl;
197 errCount++;
198 }
199 } else {
200 std::cout << "errCount newFormat == nullptr:" << errCount << std::endl;
201 errCount++;
202 }
203 OH_AVFormat_Destroy(newFormat);
204 }
205
RunVideoDec_Surface(string codeName)206 int32_t VDecNdkSample::RunVideoDec_Surface(string codeName)
207 {
208 SURFACE_OUTPUT = true;
209 int err = AV_ERR_OK;
210 cs = Surface::CreateSurfaceAsConsumer();
211 sptr<IBufferConsumerListener> listener = new TestConsumerListener(cs, OUT_DIR);
212 cs->RegisterConsumerListener(listener);
213 auto p = cs->GetProducer();
214 ps = Surface::CreateSurfaceAsProducer(p);
215 OHNativeWindow *nativeWindow = CreateNativeWindowFromSurface(&ps);
216 if (!nativeWindow) {
217 cout << "Failed to create surface" << endl;
218 return AV_ERR_UNKNOWN;
219 }
220 err = CreateVideoDecoder(codeName);
221 if (err != AV_ERR_OK) {
222 cout << "Failed to create video decoder" << endl;
223 return err;
224 }
225 err = SetVideoDecoderCallback();
226 if (err != AV_ERR_OK) {
227 cout << "Failed to setCallback" << endl;
228 Release();
229 return err;
230 }
231 err = ConfigureVideoDecoder();
232 if (err != AV_ERR_OK) {
233 cout << "Failed to configure video decoder" << endl;
234 Release();
235 return err;
236 }
237 err = OH_VideoDecoder_SetSurface(vdec_, nativeWindow);
238 if (err != AV_ERR_OK) {
239 cout << "Failed to set surface" << endl;
240 return err;
241 }
242 err = StartVideoDecoder();
243 if (err != AV_ERR_OK) {
244 cout << "Failed to start video decoder" << endl;
245 Release();
246 return err;
247 }
248 return err;
249 }
250
RunVideoDec(string codeName)251 int32_t VDecNdkSample::RunVideoDec(string codeName)
252 {
253 SURFACE_OUTPUT = false;
254 int err = CreateVideoDecoder(codeName);
255 if (err != AV_ERR_OK) {
256 cout << "Failed to create video decoder" << endl;
257 return err;
258 }
259
260 err = ConfigureVideoDecoder();
261 if (err != AV_ERR_OK) {
262 cout << "Failed to configure video decoder" << endl;
263 Release();
264 return err;
265 }
266
267 err = SetVideoDecoderCallback();
268 if (err != AV_ERR_OK) {
269 cout << "Failed to setCallback" << endl;
270 Release();
271 return err;
272 }
273
274 err = StartVideoDecoder();
275 if (err != AV_ERR_OK) {
276 cout << "Failed to start video decoder" << endl;
277 Release();
278 return err;
279 }
280 return err;
281 }
282
SetVideoDecoderCallback()283 int32_t VDecNdkSample::SetVideoDecoderCallback()
284 {
285 signal_ = new VDecSignal();
286 if (signal_ == nullptr) {
287 cout << "Failed to new VDecSignal" << endl;
288 return AV_ERR_UNKNOWN;
289 }
290
291 cb_.onError = VdecError;
292 cb_.onStreamChanged = VdecFormatChanged;
293 cb_.onNeedInputData = VdecInputDataReady;
294 cb_.onNeedOutputData = VdecOutputDataReady;
295 return OH_VideoDecoder_SetCallback(vdec_, cb_, static_cast<void *>(signal_));
296 }
297
ReleaseInFile()298 void VDecNdkSample::ReleaseInFile()
299 {
300 if (inFile_ != nullptr) {
301 if (inFile_->is_open()) {
302 inFile_->close();
303 }
304 inFile_.reset();
305 inFile_ = nullptr;
306 }
307 }
308
StopInloop()309 void VDecNdkSample::StopInloop()
310 {
311 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
312 unique_lock<mutex> lock(signal_->inMutex_);
313 clearIntqueue(signal_->inIdxQueue_);
314 signal_->inCond_.notify_all();
315 lock.unlock();
316
317 inputLoop_->join();
318 inputLoop_.reset();
319 }
320 }
321
StartVideoDecoder()322 int32_t VDecNdkSample::StartVideoDecoder()
323 {
324 int ret = OH_VideoDecoder_Start(vdec_);
325 if (ret != AV_ERR_OK) {
326 cout << "Failed to start codec" << endl;
327 return ret;
328 }
329
330 isRunning_.store(true);
331
332 inFile_ = make_unique<ifstream>();
333 if (inFile_ == nullptr) {
334 isRunning_.store(false);
335 (void)OH_VideoDecoder_Stop(vdec_);
336 return AV_ERR_UNKNOWN;
337 }
338 inFile_->open(INP_DIR, ios::in | ios::binary);
339 if (!inFile_->is_open()) {
340 cout << "open input file failed" << endl;
341 isRunning_.store(false);
342 (void)OH_VideoDecoder_Stop(vdec_);
343 inFile_->close();
344 inFile_.reset();
345 inFile_ = nullptr;
346 return AV_ERR_UNKNOWN;
347 }
348
349 inputLoop_ = make_unique<thread>(&VDecNdkSample::InputFunc_AVCC, this);
350 if (inputLoop_ == nullptr) {
351 cout << "Failed to create input loop" << endl;
352 isRunning_.store(false);
353 (void)OH_VideoDecoder_Stop(vdec_);
354 ReleaseInFile();
355 return AV_ERR_UNKNOWN;
356 }
357
358 outputLoop_ = make_unique<thread>(&VDecNdkSample::OutputFunc, this);
359
360 if (outputLoop_ == nullptr) {
361 cout << "Failed to create output loop" << endl;
362 isRunning_.store(false);
363 (void)OH_VideoDecoder_Stop(vdec_);
364 ReleaseInFile();
365 StopInloop();
366 Release();
367 return AV_ERR_UNKNOWN;
368 }
369 return AV_ERR_OK;
370 }
371
CreateVideoDecoder(string codeName)372 int32_t VDecNdkSample::CreateVideoDecoder(string codeName)
373 {
374 if (!codeName.empty()) {
375 vdec_ = OH_VideoDecoder_CreateByName(codeName.c_str());
376 } else {
377 vdec_ = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
378 }
379 dec_sample = this;
380 return vdec_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
381 }
382
WaitForEOS()383 void VDecNdkSample::WaitForEOS()
384 {
385 if (!AFTER_EOS_DESTORY_CODEC && inputLoop_ && inputLoop_->joinable()) {
386 inputLoop_->join();
387 }
388
389 if (outputLoop_ && outputLoop_->joinable()) {
390 outputLoop_->join();
391 }
392 }
393
WriteOutputFrame(uint32_t index,OH_AVMemory * buffer,OH_AVCodecBufferAttr attr,FILE * outFile)394 void VDecNdkSample::WriteOutputFrame(uint32_t index, OH_AVMemory *buffer, OH_AVCodecBufferAttr attr, FILE *outFile)
395 {
396 if (!SURFACE_OUTPUT) {
397 uint8_t *tmpBuffer = new uint8_t[attr.size];
398 if (memcpy_s(tmpBuffer, attr.size, OH_AVMemory_GetAddr(buffer), attr.size) != EOK) {
399 cout << "Fatal: memory copy failed" << endl;
400 }
401 fwrite(tmpBuffer, 1, attr.size, outFile);
402 SHA512_Update(&c, tmpBuffer, attr.size);
403 delete[] tmpBuffer;
404 if (OH_VideoDecoder_FreeOutputData(vdec_, index) != AV_ERR_OK) {
405 cout << "Fatal: ReleaseOutputBuffer fail" << endl;
406 errCount = errCount + 1;
407 }
408 } else {
409 if (OH_VideoDecoder_RenderOutputData(vdec_, index) != AV_ERR_OK) {
410 cout << "Fatal: RenderOutputBuffer fail" << endl;
411 errCount = errCount + 1;
412 }
413 }
414 }
415
OutputFunc()416 void VDecNdkSample::OutputFunc()
417 {
418 SHA512_Init(&c);
419 FILE *outFile = fopen(OUT_DIR, "wb");
420 if (outFile == nullptr) {
421 return;
422 }
423 while (true) {
424 if (!isRunning_.load()) {
425 break;
426 }
427 unique_lock<mutex> lock(signal_->outMutex_);
428 signal_->outCond_.wait(lock, [this]() {
429 if (!isRunning_.load()) {
430 cout << "quit out signal" << endl;
431 return true;
432 }
433 return signal_->outIdxQueue_.size() > 0;
434 });
435 if (!isRunning_.load()) {
436 break;
437 }
438 uint32_t index = signal_->outIdxQueue_.front();
439 OH_AVCodecBufferAttr attr = signal_->attrQueue_.front();
440 OH_AVMemory *buffer = signal_->outBufferQueue_.front();
441 signal_->outBufferQueue_.pop();
442 signal_->outIdxQueue_.pop();
443 signal_->attrQueue_.pop();
444 lock.unlock();
445 if (attr.flags == AVCODEC_BUFFER_FLAGS_EOS) {
446 SHA512_Final(md, &c);
447 OPENSSL_cleanse(&c, sizeof(c));
448 MdCompare(md, SHA512_DIGEST_LENGTH, fileSourcesha256);
449 if (AFTER_EOS_DESTORY_CODEC) {
450 (void)Stop();
451 Release();
452 }
453 break;
454 }
455 if (dec_sample->checkOutPut) {
456 CheckOutputDescription();
457 }
458 WriteOutputFrame(index, buffer, attr, outFile);
459 if (errCount > 0) {
460 break;
461 }
462 }
463 (void)fclose(outFile);
464 }
465
Flush_buffer()466 void VDecNdkSample::Flush_buffer()
467 {
468 unique_lock<mutex> inLock(signal_->inMutex_);
469 clearIntqueue(signal_->inIdxQueue_);
470 std::queue<OH_AVMemory *> empty;
471 swap(empty, signal_->inBufferQueue_);
472 signal_->inCond_.notify_all();
473 inLock.unlock();
474 unique_lock<mutex> outLock(signal_->outMutex_);
475 clearIntqueue(signal_->outIdxQueue_);
476 clearBufferqueue(signal_->attrQueue_);
477 signal_->outCond_.notify_all();
478 outLock.unlock();
479 }
480
CopyStartCode(uint8_t * frameBuffer,uint32_t bufferSize,OH_AVCodecBufferAttr & attr)481 void VDecNdkSample::CopyStartCode(uint8_t *frameBuffer, uint32_t bufferSize, OH_AVCodecBufferAttr &attr)
482 {
483 switch (frameBuffer[START_CODE_SIZE] & H264_NALU_TYPE) {
484 case SPS:
485 case PPS:
486 case SEI:
487 if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
488 cout << "Fatal: memory copy failed" << endl;
489 }
490 attr.pts = GetSystemTimeUs();
491 attr.size = bufferSize + START_CODE_SIZE;
492 attr.offset = 0;
493 attr.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
494 break;
495 default: {
496 if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
497 cout << "Fatal: memory copy failed" << endl;
498 }
499 attr.pts = GetSystemTimeUs();
500 attr.size = bufferSize + START_CODE_SIZE;
501 attr.offset = 0;
502 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
503 }
504 }
505 }
506
ReadData(uint32_t index,OH_AVMemory * buffer)507 int32_t VDecNdkSample::ReadData(uint32_t index, OH_AVMemory *buffer)
508 {
509 OH_AVCodecBufferAttr attr;
510 if (BEFORE_EOS_INPUT && frameCount_ > EOS_COUNT) {
511 SetEOS(index);
512 return 1;
513 }
514 if (BEFORE_EOS_INPUT_INPUT && frameCount_ > EOS_COUNT) {
515 memset_s(&attr, sizeof(OH_AVCodecBufferAttr), 0, sizeof(OH_AVCodecBufferAttr));
516 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
517 BEFORE_EOS_INPUT_INPUT = false;
518 }
519 uint8_t ch[4] = {};
520 (void)inFile_->read(reinterpret_cast<char *>(ch), START_CODE_SIZE);
521 if (repeatRun && inFile_->eof()) {
522 inFile_->clear();
523 inFile_->seekg(0, ios::beg);
524 cout << "repeat" << endl;
525 return 0;
526 } else if (inFile_->eof()) {
527 SetEOS(index);
528 return 1;
529 }
530 uint32_t bufferSize = (uint32_t)(((ch[3] & 0xFF)) | ((ch[2] & 0xFF) << EIGHT) | ((ch[1] & 0xFF) << SIXTEEN) |
531 ((ch[0] & 0xFF) << TWENTY_FOUR));
532 if (bufferSize > MAX_WIDTH * MAX_HEIGHT << 1) {
533 return 1;
534 }
535
536 return SendData(bufferSize, index, buffer);
537 }
538
SendData(uint32_t bufferSize,uint32_t index,OH_AVMemory * buffer)539 uint32_t VDecNdkSample::SendData(uint32_t bufferSize, uint32_t index, OH_AVMemory *buffer)
540 {
541 OH_AVCodecBufferAttr attr;
542 uint8_t *frameBuffer = new uint8_t[bufferSize + START_CODE_SIZE];
543 (void)inFile_->read(reinterpret_cast<char *>(frameBuffer + START_CODE_SIZE), bufferSize);
544 CopyStartCode(frameBuffer, bufferSize, attr);
545 int32_t size = OH_AVMemory_GetSize(buffer);
546 if (size < attr.size) {
547 delete[] frameBuffer;
548 cout << "ERROR:AVMemory not enough, buffer size" << attr.size << " AVMemory Size " << size << endl;
549 isRunning_.store(false);
550 StopOutloop();
551 return 1;
552 }
553 uint8_t *buffer_addr = OH_AVMemory_GetAddr(buffer);
554 if (memcpy_s(buffer_addr, size, frameBuffer, attr.size) != EOK) {
555 delete[] frameBuffer;
556 cout << "Fatal: memcpy fail" << endl;
557 isRunning_.store(false);
558 return 1;
559 }
560 delete[] frameBuffer;
561 int32_t ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
562 if (ret != AV_ERR_OK) {
563 errCount++;
564 cout << "push input data failed, error:" << ret << endl;
565 }
566 frameCount_ = frameCount_ + 1;
567 if (inFile_->eof()) {
568 isRunning_.store(false);
569 StopOutloop();
570 }
571 return 0;
572 }
573
InputFunc_AVCC()574 void VDecNdkSample::InputFunc_AVCC()
575 {
576 frameCount_ = 1;
577 errCount = 0;
578 while (true) {
579 if (!isRunning_.load()) {
580 break;
581 }
582 if (frameCount_ % (EOS_COUNT >> 1) == 0) {
583 if (REPEAT_START_FLUSH_BEFORE_EOS > 0) {
584 REPEAT_START_FLUSH_BEFORE_EOS--;
585 OH_VideoDecoder_Flush(vdec_);
586 Flush_buffer();
587 OH_VideoDecoder_Start(vdec_);
588 }
589 if (REPEAT_START_STOP_BEFORE_EOS > 0) {
590 REPEAT_START_STOP_BEFORE_EOS--;
591 OH_VideoDecoder_Stop(vdec_);
592 Flush_buffer();
593 OH_VideoDecoder_Start(vdec_);
594 }
595 }
596 unique_lock<mutex> lock(signal_->inMutex_);
597 signal_->inCond_.wait(lock, [this]() {
598 if (!isRunning_.load()) {
599 cout << "quit signal" << endl;
600 return true;
601 }
602 return signal_->inIdxQueue_.size() > 0;
603 });
604 if (!isRunning_.load()) {
605 break;
606 }
607 uint32_t index = signal_->inIdxQueue_.front();
608 auto buffer = signal_->inBufferQueue_.front();
609 signal_->inIdxQueue_.pop();
610 signal_->inBufferQueue_.pop();
611 lock.unlock();
612 if (!inFile_->eof()) {
613 int ret = ReadData(index, buffer);
614 if (ret == 1) {
615 break;
616 }
617 }
618
619 if (sleepOnFPS) {
620 usleep(FRAME_INTERVAL);
621 }
622 }
623 }
624
InputFunc_FUZZ(const uint8_t * data,size_t size)625 OH_AVErrCode VDecNdkSample::InputFunc_FUZZ(const uint8_t *data, size_t size)
626 {
627 uint32_t index;
628 unique_lock<mutex> lock(signal_->inMutex_);
629 signal_->inCond_.wait(lock, [this]() {
630 if (!isRunning_.load() && g_fuzzError) {
631 return true;
632 }
633 return signal_->inIdxQueue_.size() > 0;
634 });
635 if (g_fuzzError)
636 return AV_ERR_TIMEOUT;
637 index = signal_->inIdxQueue_.front();
638 auto buffer = signal_->inBufferQueue_.front();
639 lock.unlock();
640 int32_t buffer_size = OH_AVMemory_GetSize(buffer);
641 uint8_t *buffer_addr = OH_AVMemory_GetAddr(buffer);
642
643 if (memcpy_s(buffer_addr, buffer_size, data, size) != EOK) {
644 cout << "Fatal: memcpy fail" << endl;
645 return AV_ERR_NO_MEMORY;
646 }
647 OH_AVCodecBufferAttr attr;
648 attr.pts = GetSystemTimeUs();
649 attr.size = buffer_size;
650 attr.offset = 0;
651 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
652 OH_AVErrCode ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
653 signal_->inIdxQueue_.pop();
654 signal_->inBufferQueue_.pop();
655 return ret;
656 }
657
SetEOS(uint32_t index)658 void VDecNdkSample::SetEOS(uint32_t index)
659 {
660 OH_AVCodecBufferAttr attr;
661 attr.pts = 0;
662 attr.size = 0;
663 attr.offset = 0;
664 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
665 int32_t res = OH_VideoDecoder_PushInputData(vdec_, index, attr);
666 cout << "OH_VideoDecoder_PushInputData EOS res: " << res << endl;
667 }
668
state_EOS()669 int32_t VDecNdkSample::state_EOS()
670 {
671 unique_lock<mutex> lock(signal_->inMutex_);
672 signal_->inCond_.wait(lock, [this]() {
673 if (!isRunning_.load()) {
674 return true;
675 }
676 return signal_->inIdxQueue_.size() > 0;
677 });
678 uint32_t index = signal_->inIdxQueue_.front();
679 signal_->inIdxQueue_.pop();
680 OH_AVCodecBufferAttr attr;
681 attr.pts = 0;
682 attr.size = 0;
683 attr.offset = 0;
684 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
685 return OH_VideoDecoder_PushInputData(vdec_, index, attr);
686 }
687
Flush()688 int32_t VDecNdkSample::Flush()
689 {
690 unique_lock<mutex> inLock(signal_->inMutex_);
691 clearIntqueue(signal_->inIdxQueue_);
692 signal_->inCond_.notify_all();
693 inLock.unlock();
694 unique_lock<mutex> outLock(signal_->outMutex_);
695 clearIntqueue(signal_->outIdxQueue_);
696 clearBufferqueue(signal_->attrQueue_);
697 signal_->outCond_.notify_all();
698 outLock.unlock();
699
700 return OH_VideoDecoder_Flush(vdec_);
701 }
702
Reset()703 int32_t VDecNdkSample::Reset()
704 {
705 isRunning_.store(false);
706 StopInloop();
707 StopOutloop();
708 ReleaseInFile();
709 return OH_VideoDecoder_Reset(vdec_);
710 }
711
Release()712 int32_t VDecNdkSample::Release()
713 {
714 int ret = 0;
715 if (vdec_ != nullptr) {
716 ret = OH_VideoDecoder_Destroy(vdec_);
717 vdec_ = nullptr;
718 }
719
720 if (signal_ != nullptr) {
721 delete signal_;
722 signal_ = nullptr;
723 }
724 return ret;
725 }
726
Stop()727 int32_t VDecNdkSample::Stop()
728 {
729 StopInloop();
730 clearIntqueue(signal_->outIdxQueue_);
731 clearBufferqueue(signal_->attrQueue_);
732 ReleaseInFile();
733 return OH_VideoDecoder_Stop(vdec_);
734 }
735
Start()736 int32_t VDecNdkSample::Start()
737 {
738 int32_t ret = OH_VideoDecoder_Start(vdec_);
739 if (ret == AV_ERR_OK) {
740 isRunning_.store(true);
741 }
742 return ret;
743 }
744
StopOutloop()745 void VDecNdkSample::StopOutloop()
746 {
747 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
748 unique_lock<mutex> lock(signal_->outMutex_);
749 clearIntqueue(signal_->outIdxQueue_);
750 clearBufferqueue(signal_->attrQueue_);
751 signal_->outCond_.notify_all();
752 lock.unlock();
753 }
754 }
755
SetParameter(OH_AVFormat * format)756 int32_t VDecNdkSample::SetParameter(OH_AVFormat *format)
757 {
758 return OH_VideoDecoder_SetParameter(vdec_, format);
759 }