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