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_ndk_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     }
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, &current_width);
111     OH_AVFormat_GetIntValue(format, OH_MD_KEY_HEIGHT, &current_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     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
172     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
173     (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, DEFAULT_FRAME_RATE);
174     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, DEFAULT_ROTATION);
175     (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, DEFAULT_PIXEL_FORMAT);
176     int ret = OH_VideoDecoder_Configure(vdec_, format);
177     OH_AVFormat_Destroy(format);
178     return ret;
179 }
180 
RunVideoDec_Surface(string codeName)181 int32_t VDecNdkSample::RunVideoDec_Surface(string codeName)
182 {
183     SURFACE_OUTPUT = true;
184     int err = AV_ERR_OK;
185     cs = Surface::CreateSurfaceAsConsumer();
186     sptr<IBufferConsumerListener> listener = new TestConsumerListener(cs, OUT_DIR);
187     cs->RegisterConsumerListener(listener);
188     auto p = cs->GetProducer();
189     ps = Surface::CreateSurfaceAsProducer(p);
190     OHNativeWindow *nativeWindow = CreateNativeWindowFromSurface(&ps);
191     if (!nativeWindow) {
192         cout << "Failed to create surface" << endl;
193         return AV_ERR_UNKNOWN;
194     }
195     err = CreateVideoDecoder(codeName);
196     if (err != AV_ERR_OK) {
197         cout << "Failed to create video decoder" << endl;
198         return err;
199     }
200     err = SetVideoDecoderCallback();
201     if (err != AV_ERR_OK) {
202         cout << "Failed to setCallback" << endl;
203         Release();
204         return err;
205     }
206     err = ConfigureVideoDecoder();
207     if (err != AV_ERR_OK) {
208         cout << "Failed to configure video decoder" << endl;
209         Release();
210         return err;
211     }
212     err = OH_VideoDecoder_SetSurface(vdec_, nativeWindow);
213     if (err != AV_ERR_OK) {
214         cout << "Failed to set surface" << endl;
215         return err;
216     }
217     err = StartVideoDecoder();
218     if (err != AV_ERR_OK) {
219         cout << "Failed to start video decoder" << endl;
220         Release();
221         return err;
222     }
223     return err;
224 }
225 
RunVideoDec(string codeName)226 int32_t VDecNdkSample::RunVideoDec(string codeName)
227 {
228     SURFACE_OUTPUT = false;
229     int err = CreateVideoDecoder(codeName);
230     if (err != AV_ERR_OK) {
231         cout << "Failed to create video decoder" << endl;
232         return err;
233     }
234 
235     err = ConfigureVideoDecoder();
236     if (err != AV_ERR_OK) {
237         cout << "Failed to configure video decoder" << endl;
238         Release();
239         return err;
240     }
241 
242     err = SetVideoDecoderCallback();
243     if (err != AV_ERR_OK) {
244         cout << "Failed to setCallback" << endl;
245         Release();
246         return err;
247     }
248 
249     err = StartVideoDecoder();
250     if (err != AV_ERR_OK) {
251         cout << "Failed to start video decoder" << endl;
252         Release();
253         return err;
254     }
255     return err;
256 }
257 
SetVideoDecoderCallback()258 int32_t VDecNdkSample::SetVideoDecoderCallback()
259 {
260     signal_ = new VDecSignal();
261     if (signal_ == nullptr) {
262         cout << "Failed to new VDecSignal" << endl;
263         return AV_ERR_UNKNOWN;
264     }
265 
266     cb_.onError = VdecError;
267     cb_.onStreamChanged = VdecFormatChanged;
268     cb_.onNeedInputData = VdecInputDataReady;
269     cb_.onNeedOutputData = VdecOutputDataReady;
270     return OH_VideoDecoder_SetCallback(vdec_, cb_, static_cast<void *>(signal_));
271 }
272 
ReleaseInFile()273 void VDecNdkSample::ReleaseInFile()
274 {
275     if (inFile_ != nullptr) {
276         if (inFile_->is_open()) {
277             inFile_->close();
278         }
279         inFile_.reset();
280         inFile_ = nullptr;
281     }
282 }
283 
StopInloop()284 void VDecNdkSample::StopInloop()
285 {
286     if (inputLoop_ != nullptr && inputLoop_->joinable()) {
287         unique_lock<mutex> lock(signal_->inMutex_);
288         clearIntqueue(signal_->inIdxQueue_);
289         signal_->inCond_.notify_all();
290         lock.unlock();
291 
292         inputLoop_->join();
293         inputLoop_.reset();
294     }
295 }
296 
StartVideoDecoder()297 int32_t VDecNdkSample::StartVideoDecoder()
298 {
299     int ret = OH_VideoDecoder_Start(vdec_);
300     if (ret != AV_ERR_OK) {
301         cout << "Failed to start codec" << endl;
302         return ret;
303     }
304 
305     isRunning_.store(true);
306 
307     inFile_ = make_unique<ifstream>();
308     if (inFile_ == nullptr) {
309         isRunning_.store(false);
310         (void)OH_VideoDecoder_Stop(vdec_);
311         return AV_ERR_UNKNOWN;
312     }
313     inFile_->open(INP_DIR, ios::in | ios::binary);
314     if (!inFile_->is_open()) {
315         cout << "open input file failed" << endl;
316         isRunning_.store(false);
317         (void)OH_VideoDecoder_Stop(vdec_);
318         inFile_->close();
319         inFile_.reset();
320         inFile_ = nullptr;
321         return AV_ERR_UNKNOWN;
322     }
323 
324     inputLoop_ = make_unique<thread>(&VDecNdkSample::InputFunc_AVCC, this);
325     if (inputLoop_ == nullptr) {
326         cout << "Failed to create input loop" << endl;
327         isRunning_.store(false);
328         (void)OH_VideoDecoder_Stop(vdec_);
329         ReleaseInFile();
330         return AV_ERR_UNKNOWN;
331     }
332 
333     outputLoop_ = make_unique<thread>(&VDecNdkSample::OutputFunc, this);
334 
335     if (outputLoop_ == nullptr) {
336         cout << "Failed to create output loop" << endl;
337         isRunning_.store(false);
338         (void)OH_VideoDecoder_Stop(vdec_);
339         ReleaseInFile();
340         StopInloop();
341         Release();
342         return AV_ERR_UNKNOWN;
343     }
344     return AV_ERR_OK;
345 }
346 
CreateVideoDecoder(string codeName)347 int32_t VDecNdkSample::CreateVideoDecoder(string codeName)
348 {
349     if (!codeName.empty()) {
350         vdec_ = OH_VideoDecoder_CreateByName(codeName.c_str());
351     } else {
352         vdec_ = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
353     }
354     dec_sample = this;
355     return vdec_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
356 }
357 
WaitForEOS()358 void VDecNdkSample::WaitForEOS()
359 {
360     if (!AFTER_EOS_DESTORY_CODEC && inputLoop_ && inputLoop_->joinable()) {
361         inputLoop_->join();
362     }
363 
364     if (outputLoop_ && outputLoop_->joinable()) {
365         outputLoop_->join();
366     }
367 }
368 
WriteOutputFrame(uint32_t index, OH_AVMemory *buffer, OH_AVCodecBufferAttr attr, FILE *outFile)369 void VDecNdkSample::WriteOutputFrame(uint32_t index, OH_AVMemory *buffer, OH_AVCodecBufferAttr attr, FILE *outFile)
370 {
371     if (!SURFACE_OUTPUT) {
372         uint8_t *tmpBuffer = new uint8_t[attr.size];
373         if (memcpy_s(tmpBuffer, attr.size, OH_AVMemory_GetAddr(buffer), attr.size) != EOK) {
374             cout << "Fatal: memory copy failed" << endl;
375         }
376         fwrite(tmpBuffer, 1, attr.size, outFile);
377         SHA512_Update(&c, tmpBuffer, attr.size);
378         delete[] tmpBuffer;
379         if (OH_VideoDecoder_FreeOutputData(vdec_, index) != AV_ERR_OK) {
380             cout << "Fatal: ReleaseOutputBuffer fail" << endl;
381             errCount = errCount + 1;
382         }
383     } else {
384         if (OH_VideoDecoder_RenderOutputData(vdec_, index) != AV_ERR_OK) {
385             cout << "Fatal: RenderOutputBuffer fail" << endl;
386             errCount = errCount + 1;
387         }
388     }
389 }
390 
OutputFunc()391 void VDecNdkSample::OutputFunc()
392 {
393     SHA512_Init(&c);
394     FILE *outFile = fopen(OUT_DIR, "wb");
395     if (outFile == nullptr) {
396         return;
397     }
398     while (true) {
399         if (!isRunning_.load()) {
400             break;
401         }
402         unique_lock<mutex> lock(signal_->outMutex_);
403         signal_->outCond_.wait(lock, [this]() {
404             if (!isRunning_.load()) {
405                 cout << "quit out signal" << endl;
406                 return true;
407             }
408             return signal_->outIdxQueue_.size() > 0;
409         });
410         if (!isRunning_.load()) {
411             break;
412         }
413         uint32_t index = signal_->outIdxQueue_.front();
414         OH_AVCodecBufferAttr attr = signal_->attrQueue_.front();
415         OH_AVMemory *buffer = signal_->outBufferQueue_.front();
416         signal_->outBufferQueue_.pop();
417         signal_->outIdxQueue_.pop();
418         signal_->attrQueue_.pop();
419         lock.unlock();
420         if (attr.flags == AVCODEC_BUFFER_FLAGS_EOS) {
421             SHA512_Final(md, &c);
422             OPENSSL_cleanse(&c, sizeof(c));
423             MdCompare(md, SHA512_DIGEST_LENGTH, fileSourcesha256);
424             if (AFTER_EOS_DESTORY_CODEC) {
425                 (void)Stop();
426                 Release();
427             }
428             break;
429         }
430         WriteOutputFrame(index, buffer, attr, outFile);
431         if (errCount > 0) {
432             break;
433         }
434     }
435     (void)fclose(outFile);
436 }
437 
Flush_buffer()438 void VDecNdkSample::Flush_buffer()
439 {
440     unique_lock<mutex> inLock(signal_->inMutex_);
441     clearIntqueue(signal_->inIdxQueue_);
442     std::queue<OH_AVMemory *> empty;
443     swap(empty, signal_->inBufferQueue_);
444     signal_->inCond_.notify_all();
445     inLock.unlock();
446     unique_lock<mutex> outLock(signal_->outMutex_);
447     clearIntqueue(signal_->outIdxQueue_);
448     clearBufferqueue(signal_->attrQueue_);
449     signal_->outCond_.notify_all();
450     outLock.unlock();
451 }
452 
CopyStartCode(uint8_t *frameBuffer, uint32_t bufferSize, OH_AVCodecBufferAttr &attr)453 void VDecNdkSample::CopyStartCode(uint8_t *frameBuffer, uint32_t bufferSize, OH_AVCodecBufferAttr &attr)
454 {
455     switch (frameBuffer[START_CODE_SIZE] & H264_NALU_TYPE) {
456         case SPS:
457         case PPS:
458         case SEI:
459             if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
460                 cout << "Fatal: memory copy failed" << endl;
461             }
462             attr.pts = GetSystemTimeUs();
463             attr.size = bufferSize + START_CODE_SIZE;
464             attr.offset = 0;
465             attr.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
466             break;
467         default: {
468             if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
469                 cout << "Fatal: memory copy failed" << endl;
470             }
471             attr.pts = GetSystemTimeUs();
472             attr.size = bufferSize + START_CODE_SIZE;
473             attr.offset = 0;
474             attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
475         }
476     }
477 }
478 
ReadData(uint32_t index, OH_AVMemory *buffer)479 int32_t VDecNdkSample::ReadData(uint32_t index, OH_AVMemory *buffer)
480 {
481     OH_AVCodecBufferAttr attr;
482     if (BEFORE_EOS_INPUT && frameCount_ > EOS_COUNT) {
483         SetEOS(index);
484         return 1;
485     }
486     if (BEFORE_EOS_INPUT_INPUT && frameCount_ > EOS_COUNT) {
487         memset_s(&attr, sizeof(OH_AVCodecBufferAttr), 0, sizeof(OH_AVCodecBufferAttr));
488         attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
489         BEFORE_EOS_INPUT_INPUT = false;
490     }
491     uint8_t ch[4] = {};
492     (void)inFile_->read(reinterpret_cast<char *>(ch), START_CODE_SIZE);
493     if (repeatRun && inFile_->eof()) {
494         inFile_->clear();
495         inFile_->seekg(0, ios::beg);
496         cout << "repeat" << endl;
497         return 0;
498     } else if (inFile_->eof()) {
499         SetEOS(index);
500         return 1;
501     }
502     uint32_t bufferSize = (uint32_t)(((ch[3] & 0xFF)) | ((ch[2] & 0xFF) << EIGHT) | ((ch[1] & 0xFF) << SIXTEEN) |
503                                      ((ch[0] & 0xFF) << TWENTY_FOUR));
504     if (bufferSize > MAX_WIDTH * MAX_HEIGHT << 1) {
505         return 1;
506     }
507 
508     return SendData(bufferSize, index, buffer);
509 }
510 
SendData(uint32_t bufferSize, uint32_t index, OH_AVMemory *buffer)511 uint32_t VDecNdkSample::SendData(uint32_t bufferSize, uint32_t index, OH_AVMemory *buffer)
512 {
513     OH_AVCodecBufferAttr attr;
514     uint8_t *frameBuffer = new uint8_t[bufferSize + START_CODE_SIZE];
515     (void)inFile_->read(reinterpret_cast<char *>(frameBuffer + START_CODE_SIZE), bufferSize);
516     CopyStartCode(frameBuffer, bufferSize, attr);
517     int32_t size = OH_AVMemory_GetSize(buffer);
518     if (size < attr.size) {
519         delete[] frameBuffer;
520         cout << "ERROR:AVMemory not enough, buffer size" << attr.size << "   AVMemory Size " << size << endl;
521         isRunning_.store(false);
522         StopOutloop();
523         return 1;
524     }
525     uint8_t *buffer_addr = OH_AVMemory_GetAddr(buffer);
526     if (memcpy_s(buffer_addr, size, frameBuffer, attr.size) != EOK) {
527         delete[] frameBuffer;
528         cout << "Fatal: memcpy fail" << endl;
529         isRunning_.store(false);
530         return 1;
531     }
532     delete[] frameBuffer;
533     int32_t ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
534     if (ret != AV_ERR_OK) {
535         errCount++;
536         cout << "push input data failed, error:" << ret << endl;
537     }
538     frameCount_ = frameCount_ + 1;
539     if (inFile_->eof()) {
540         isRunning_.store(false);
541         StopOutloop();
542     }
543     return 0;
544 }
545 
InputFunc_AVCC()546 void VDecNdkSample::InputFunc_AVCC()
547 {
548     frameCount_ = 1;
549     errCount = 0;
550     while (true) {
551         if (!isRunning_.load()) {
552             break;
553         }
554         if (frameCount_ % (EOS_COUNT >> 1) == 0) {
555             if (REPEAT_START_FLUSH_BEFORE_EOS > 0) {
556                 REPEAT_START_FLUSH_BEFORE_EOS--;
557                 OH_VideoDecoder_Flush(vdec_);
558                 Flush_buffer();
559                 OH_VideoDecoder_Start(vdec_);
560             }
561             if (REPEAT_START_STOP_BEFORE_EOS > 0) {
562                 REPEAT_START_STOP_BEFORE_EOS--;
563                 OH_VideoDecoder_Stop(vdec_);
564                 Flush_buffer();
565                 OH_VideoDecoder_Start(vdec_);
566             }
567         }
568         unique_lock<mutex> lock(signal_->inMutex_);
569         signal_->inCond_.wait(lock, [this]() {
570             if (!isRunning_.load()) {
571                 cout << "quit signal" << endl;
572                 return true;
573             }
574             return signal_->inIdxQueue_.size() > 0;
575         });
576         if (!isRunning_.load()) {
577             break;
578         }
579         uint32_t index = signal_->inIdxQueue_.front();
580         auto buffer = signal_->inBufferQueue_.front();
581         signal_->inIdxQueue_.pop();
582         signal_->inBufferQueue_.pop();
583         lock.unlock();
584         if (!inFile_->eof()) {
585             int ret = ReadData(index, buffer);
586             if (ret == 1) {
587                 break;
588             }
589         }
590 
591         if (sleepOnFPS) {
592             usleep(FRAME_INTERVAL);
593         }
594     }
595 }
596 
InputFunc_FUZZ(const uint8_t *data, size_t size)597 OH_AVErrCode VDecNdkSample::InputFunc_FUZZ(const uint8_t *data, size_t size)
598 {
599     uint32_t index;
600     unique_lock<mutex> lock(signal_->inMutex_);
601     signal_->inCond_.wait(lock, [this]() {
602         if (!isRunning_.load() && g_fuzzError) {
603             return true;
604         }
605         return signal_->inIdxQueue_.size() > 0;
606     });
607     if (g_fuzzError)
608         return AV_ERR_TIMEOUT;
609     index = signal_->inIdxQueue_.front();
610     auto buffer = signal_->inBufferQueue_.front();
611     lock.unlock();
612     int32_t buffer_size = OH_AVMemory_GetSize(buffer);
613     uint8_t *buffer_addr = OH_AVMemory_GetAddr(buffer);
614 
615     if (memcpy_s(buffer_addr, buffer_size, data, size) != EOK) {
616         cout << "Fatal: memcpy fail" << endl;
617         return AV_ERR_NO_MEMORY;
618     }
619     OH_AVCodecBufferAttr attr;
620     attr.pts = GetSystemTimeUs();
621     attr.size = buffer_size;
622     attr.offset = 0;
623     attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
624     OH_AVErrCode ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
625     signal_->inIdxQueue_.pop();
626     signal_->inBufferQueue_.pop();
627     return ret;
628 }
629 
SetEOS(uint32_t index)630 void VDecNdkSample::SetEOS(uint32_t index)
631 {
632     OH_AVCodecBufferAttr attr;
633     attr.pts = 0;
634     attr.size = 0;
635     attr.offset = 0;
636     attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
637     int32_t res = OH_VideoDecoder_PushInputData(vdec_, index, attr);
638     cout << "OH_VideoDecoder_PushInputData    EOS   res: " << res << endl;
639 }
640 
state_EOS()641 int32_t VDecNdkSample::state_EOS()
642 {
643     unique_lock<mutex> lock(signal_->inMutex_);
644     signal_->inCond_.wait(lock, [this]() {
645         if (!isRunning_.load()) {
646             return true;
647         }
648         return signal_->inIdxQueue_.size() > 0;
649     });
650     uint32_t index = signal_->inIdxQueue_.front();
651     signal_->inIdxQueue_.pop();
652     OH_AVCodecBufferAttr attr;
653     attr.pts = 0;
654     attr.size = 0;
655     attr.offset = 0;
656     attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
657     return OH_VideoDecoder_PushInputData(vdec_, index, attr);
658 }
659 
Flush()660 int32_t VDecNdkSample::Flush()
661 {
662     unique_lock<mutex> inLock(signal_->inMutex_);
663     clearIntqueue(signal_->inIdxQueue_);
664     signal_->inCond_.notify_all();
665     inLock.unlock();
666     unique_lock<mutex> outLock(signal_->outMutex_);
667     clearIntqueue(signal_->outIdxQueue_);
668     clearBufferqueue(signal_->attrQueue_);
669     signal_->outCond_.notify_all();
670     outLock.unlock();
671 
672     return OH_VideoDecoder_Flush(vdec_);
673 }
674 
Reset()675 int32_t VDecNdkSample::Reset()
676 {
677     isRunning_.store(false);
678     StopInloop();
679     StopOutloop();
680     ReleaseInFile();
681     return OH_VideoDecoder_Reset(vdec_);
682 }
683 
Release()684 int32_t VDecNdkSample::Release()
685 {
686     int ret = 0;
687     if (vdec_ != nullptr) {
688         ret = OH_VideoDecoder_Destroy(vdec_);
689         vdec_ = nullptr;
690     }
691 
692     if (signal_ != nullptr) {
693         delete signal_;
694         signal_ = nullptr;
695     }
696     return ret;
697 }
698 
Stop()699 int32_t VDecNdkSample::Stop()
700 {
701     StopInloop();
702     clearIntqueue(signal_->outIdxQueue_);
703     clearBufferqueue(signal_->attrQueue_);
704     ReleaseInFile();
705     return OH_VideoDecoder_Stop(vdec_);
706 }
707 
Start()708 int32_t VDecNdkSample::Start()
709 {
710     int32_t ret = OH_VideoDecoder_Start(vdec_);
711     if (ret == AV_ERR_OK) {
712         isRunning_.store(true);
713     }
714     return ret;
715 }
716 
StopOutloop()717 void VDecNdkSample::StopOutloop()
718 {
719     if (outputLoop_ != nullptr && outputLoop_->joinable()) {
720         unique_lock<mutex> lock(signal_->outMutex_);
721         clearIntqueue(signal_->outIdxQueue_);
722         clearBufferqueue(signal_->attrQueue_);
723         signal_->outCond_.notify_all();
724         lock.unlock();
725     }
726 }
727 
SetParameter(OH_AVFormat *format)728 int32_t VDecNdkSample::SetParameter(OH_AVFormat *format)
729 {
730     return OH_VideoDecoder_SetParameter(vdec_, format);
731 }