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 uint32_t START_CODE_SIZE = 4;
29 constexpr uint32_t PREREAD_BUFFER_SIZE = 0.1 * 1024 * 1024;
30 constexpr uint8_t MPEG4_FRAME_HEAD[] = {0x00, 0x00, 0x01, 0xb6};
31 constexpr uint8_t MPEG4_SEQUENCE_HEAD[] = {0x00, 0x00, 0x01, 0xb0};
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 currentWidth = 0;
105 int32_t currentHeight = 0;
106 OH_AVFormat_GetIntValue(format, OH_MD_KEY_WIDTH, ¤tWidth);
107 OH_AVFormat_GetIntValue(format, OH_MD_KEY_HEIGHT, ¤tHeight);
108 dec_sample->DEFAULT_WIDTH = currentWidth;
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 unique_lock<mutex> lock(signal->outMutex_);
132 signal->outIdxQueue_.push(index);
133 signal->attrQueue_.push(*attr);
134 signal->outBufferQueue_.push(data);
135 signal->outCond_.notify_all();
136 }
137
MdCompare(unsigned char * buffer,int len,const char * source[])138 bool VDecNdkSample::MdCompare(unsigned char *buffer, int len, const char *source[])
139 {
140 bool result = true;
141 for (int i = 0; i < len; i++) {
142 char std[SHA512_DIGEST_LENGTH] = {0};
143 int re = strcmp(source[i], std);
144 if (re != 0) {
145 result = false;
146 break;
147 }
148 }
149 return result;
150 }
151
GetSystemTimeUs()152 int64_t VDecNdkSample::GetSystemTimeUs()
153 {
154 struct timespec now;
155 (void)clock_gettime(CLOCK_BOOTTIME, &now);
156 int64_t nanoTime = (int64_t)now.tv_sec * NANOS_IN_SECOND + now.tv_nsec;
157 return nanoTime / NANOS_IN_MICRO;
158 }
159
ConfigureVideoDecoder()160 int32_t VDecNdkSample::ConfigureVideoDecoder()
161 {
162 OH_AVFormat *format = OH_AVFormat_Create();
163 if (format == nullptr) {
164 cout << "Fatal: Failed to create format" << endl;
165 return AV_ERR_UNKNOWN;
166 }
167 if (maxInputSize > 0) {
168 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_MAX_INPUT_SIZE, maxInputSize);
169 }
170 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
171 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
172 originalHeight = DEFAULT_HEIGHT;
173 originalWidth = DEFAULT_WIDTH;
174 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, DEFAULT_FRAME_RATE);
175 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, DEFAULT_ROTATION);
176 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, DEFAULT_PIXEL_FORMAT);
177 int ret = OH_VideoDecoder_Configure(vdec_, format);
178 OH_AVFormat_Destroy(format);
179 return ret;
180 }
181
CheckOutputDescription()182 void VDecNdkSample::CheckOutputDescription()
183 {
184 OH_AVFormat *newFormat = OH_VideoDecoder_GetOutputDescription(vdec_);
185 if (newFormat != nullptr) {
186 int32_t picWidth = 0;
187 int32_t picHeight = 0;
188 OH_AVFormat_GetIntValue(newFormat, OH_MD_KEY_VIDEO_PIC_WIDTH, &picWidth);
189 OH_AVFormat_GetIntValue(newFormat, OH_MD_KEY_VIDEO_PIC_HEIGHT, &picHeight);
190 if (picWidth != DEFAULT_WIDTH || picHeight != DEFAULT_HEIGHT) {
191 std::cout << "picWidth:" << picWidth << " picHeight:" << picHeight << std::endl;
192 std::cout << "errCount !=:" << errCount << std::endl;
193 errCount++;
194 }
195 } else {
196 std::cout << "errCount newFormat == nullptr:" << errCount << std::endl;
197 errCount++;
198 }
199 OH_AVFormat_Destroy(newFormat);
200 }
201
RunVideoDec_Surface(string codeName)202 int32_t VDecNdkSample::RunVideoDec_Surface(string codeName)
203 {
204 SURFACE_OUTPUT = true;
205 int err = AV_ERR_OK;
206 cs = Surface::CreateSurfaceAsConsumer();
207 sptr<IBufferConsumerListener> listener = new TestConsumerListener(cs, OUT_DIR);
208 cs->RegisterConsumerListener(listener);
209 auto p = cs->GetProducer();
210 ps = Surface::CreateSurfaceAsProducer(p);
211 OHNativeWindow *nativeWindow = CreateNativeWindowFromSurface(&ps);
212 if (!nativeWindow) {
213 cout << "Failed to create surface" << endl;
214 return AV_ERR_UNKNOWN;
215 }
216 err = CreateVideoDecoder(codeName);
217 if (err != AV_ERR_OK) {
218 cout << "Failed to create video decoder" << endl;
219 return err;
220 }
221 err = SetVideoDecoderCallback();
222 if (err != AV_ERR_OK) {
223 cout << "Failed to setCallback" << endl;
224 Release();
225 return err;
226 }
227 err = ConfigureVideoDecoder();
228 if (err != AV_ERR_OK) {
229 cout << "Failed to configure video decoder" << endl;
230 Release();
231 return err;
232 }
233 err = OH_VideoDecoder_SetSurface(vdec_, nativeWindow);
234 if (err != AV_ERR_OK) {
235 cout << "Failed to set surface" << endl;
236 return err;
237 }
238 err = StartVideoDecoder();
239 if (err != AV_ERR_OK) {
240 cout << "Failed to start video decoder" << endl;
241 Release();
242 return err;
243 }
244 return err;
245 }
246
RunVideoDec(string codeName)247 int32_t VDecNdkSample::RunVideoDec(string codeName)
248 {
249 SURFACE_OUTPUT = false;
250 int err = CreateVideoDecoder(codeName);
251 if (err != AV_ERR_OK) {
252 cout << "Failed to create video decoder" << endl;
253 return err;
254 }
255
256 err = ConfigureVideoDecoder();
257 if (err != AV_ERR_OK) {
258 cout << "Failed to configure video decoder" << endl;
259 Release();
260 return err;
261 }
262
263 err = SetVideoDecoderCallback();
264 if (err != AV_ERR_OK) {
265 cout << "Failed to setCallback" << endl;
266 Release();
267 return err;
268 }
269
270 err = StartVideoDecoder();
271 if (err != AV_ERR_OK) {
272 cout << "Failed to start video decoder" << endl;
273 Release();
274 return err;
275 }
276 return err;
277 }
278
SetVideoDecoderCallback()279 int32_t VDecNdkSample::SetVideoDecoderCallback()
280 {
281 signal_ = new VDecSignal();
282 if (signal_ == nullptr) {
283 cout << "Failed to new VDecSignal" << endl;
284 return AV_ERR_UNKNOWN;
285 }
286
287 cb_.onError = VdecError;
288 cb_.onStreamChanged = VdecFormatChanged;
289 cb_.onNeedInputData = VdecInputDataReady;
290 cb_.onNeedOutputData = VdecOutputDataReady;
291 return OH_VideoDecoder_SetCallback(vdec_, cb_, static_cast<void *>(signal_));
292 }
293
ReleaseInFile()294 void VDecNdkSample::ReleaseInFile()
295 {
296 if (inFile_ != nullptr) {
297 if (inFile_->is_open()) {
298 inFile_->close();
299 }
300 inFile_.reset();
301 inFile_ = nullptr;
302 mpegUnit_.reset();
303 mpegUnit_ = nullptr;
304 prereadBuffer_.reset();
305 prereadBuffer_ = 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 prereadBuffer_ = std::make_unique<uint8_t []>(PREREAD_BUFFER_SIZE + START_CODE_SIZE);
334 mpegUnit_ = std::make_unique<std::vector<uint8_t>>(MAX_HEIGHT * MAX_WIDTH << 1);
335
336 if (inFile_ == nullptr) {
337 isRunning_.store(false);
338 (void)OH_VideoDecoder_Stop(vdec_);
339 return AV_ERR_UNKNOWN;
340 }
341 inFile_->open(INP_DIR, ios::in | ios::binary);
342 if (!inFile_->is_open()) {
343 cout << "open input file failed" << endl;
344 isRunning_.store(false);
345 (void)OH_VideoDecoder_Stop(vdec_);
346 inFile_->close();
347 inFile_.reset();
348 inFile_ = nullptr;
349 return AV_ERR_UNKNOWN;
350 }
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_MPEG4_PART2);
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 uint32_t index = signal_->outIdxQueue_.front();
441 OH_AVCodecBufferAttr attr = signal_->attrQueue_.front();
442 OH_AVMemory *buffer = signal_->outBufferQueue_.front();
443 signal_->outBufferQueue_.pop();
444 signal_->outIdxQueue_.pop();
445 signal_->attrQueue_.pop();
446 lock.unlock();
447 if (attr.flags == AVCODEC_BUFFER_FLAGS_EOS) {
448 SHA512_Final(g_md, &g_c);
449 OPENSSL_cleanse(&g_c, sizeof(g_c));
450 MdCompare(g_md, SHA512_DIGEST_LENGTH, fileSourcesha256);
451 if (AFTER_EOS_DESTORY_CODEC) {
452 (void)Stop();
453 Release();
454 }
455 break;
456 }
457 if (dec_sample->checkOutPut) {
458 CheckOutputDescription();
459 }
460 WriteOutputFrame(index, buffer, attr, outFile);
461 if (errCount > 0) {
462 break;
463 }
464 }
465 (void)fclose(outFile);
466 }
467
Flush_buffer()468 void VDecNdkSample::Flush_buffer()
469 {
470 unique_lock<mutex> inLock(signal_->inMutex_);
471 clearIntqueue(signal_->inIdxQueue_);
472 std::queue<OH_AVMemory *> empty;
473 swap(empty, signal_->inBufferQueue_);
474 signal_->inCond_.notify_all();
475 inLock.unlock();
476 unique_lock<mutex> outLock(signal_->outMutex_);
477 clearIntqueue(signal_->outIdxQueue_);
478 clearBufferqueue(signal_->attrQueue_);
479 signal_->outCond_.notify_all();
480 outLock.unlock();
481 }
482
PtrStep(uint32_t & bufferSize,unsigned char ** pBuffer,uint32_t size)483 void VDecNdkSample::PtrStep(uint32_t &bufferSize, unsigned char **pBuffer, uint32_t size)
484 {
485 pPrereadBuffer_ += size;
486 bufferSize += size;
487 *pBuffer += size;
488 }
489
PtrStepExtraRead(uint32_t & bufferSize,unsigned char ** pBuffer)490 void VDecNdkSample::PtrStepExtraRead(uint32_t &bufferSize, unsigned char **pBuffer)
491 {
492 bufferSize -= START_CODE_SIZE;
493 *pBuffer -= START_CODE_SIZE;
494 pPrereadBuffer_ = 0;
495 }
496
GetBufferSize()497 void VDecNdkSample::GetBufferSize()
498 {
499 auto pBuffer = mpegUnit_->data();
500 uint32_t bufferSize = 0;
501 mpegUnit_->resize(MAX_NALU_SIZE);
502 do {
503 auto pos1 = std::search(prereadBuffer_.get() + pPrereadBuffer_ + START_CODE_SIZE,
504 prereadBuffer_.get() + prereadBufferSize_, std::begin(MPEG4_FRAME_HEAD), std::end(MPEG4_FRAME_HEAD));
505 uint32_t size1 = std::distance(prereadBuffer_.get() + pPrereadBuffer_, pos1);
506 auto pos2 = std::search(prereadBuffer_.get() + pPrereadBuffer_, prereadBuffer_.get() +
507 pPrereadBuffer_ + size1, std::begin(MPEG4_SEQUENCE_HEAD), std::end(MPEG4_SEQUENCE_HEAD));
508 uint32_t size = std::distance(prereadBuffer_.get() + pPrereadBuffer_, pos2);
509 if (size == 0) {
510 auto pos3 = std::search(prereadBuffer_.get() + pPrereadBuffer_ + size1 + START_CODE_SIZE,
511 prereadBuffer_.get() + prereadBufferSize_, std::begin(MPEG4_FRAME_HEAD), std::end(MPEG4_FRAME_HEAD));
512 uint32_t size2 = std::distance(prereadBuffer_.get() + pPrereadBuffer_, pos3);
513 if (memcpy_s(pBuffer, size2, prereadBuffer_.get() + pPrereadBuffer_, size2) != EOK) {
514 return;
515 }
516 PtrStep(bufferSize, &pBuffer, size2);
517 if (!((pPrereadBuffer_ == prereadBufferSize_) && !inFile_->eof())) {
518 break;
519 }
520 } else if (size1 > size) {
521 if (memcpy_s(pBuffer, size, prereadBuffer_.get() + pPrereadBuffer_, size) != EOK) {
522 return;
523 }
524 PtrStep(bufferSize, &pBuffer, size);
525 if (!((pPrereadBuffer_ == prereadBufferSize_) && !inFile_->eof())) {
526 break;
527 }
528 } else {
529 if (memcpy_s(pBuffer, size1, prereadBuffer_.get() + pPrereadBuffer_, size1) != EOK) {
530 return;
531 }
532 PtrStep(bufferSize, &pBuffer, size1);
533 if (!((pPrereadBuffer_ == prereadBufferSize_) && !inFile_->eof())) {
534 break;
535 }
536 }
537 inFile_->read(reinterpret_cast<char *>(prereadBuffer_.get() + START_CODE_SIZE), PREREAD_BUFFER_SIZE);
538 prereadBufferSize_ = inFile_->gcount() + START_CODE_SIZE;
539 pPrereadBuffer_ = START_CODE_SIZE;
540 if (memcpy_s(prereadBuffer_.get(), START_CODE_SIZE, pBuffer - START_CODE_SIZE, START_CODE_SIZE) != EOK) {
541 return;
542 }
543 PtrStepExtraRead(bufferSize, &pBuffer);
544 } while (pPrereadBuffer_ != prereadBufferSize_);
545 mpegUnit_->resize(bufferSize);
546 }
547
ReadData(uint32_t index,OH_AVMemory * buffer)548 int32_t VDecNdkSample::ReadData(uint32_t index, OH_AVMemory *buffer)
549 {
550 OH_AVCodecBufferAttr attr;
551 uint32_t bufferSize = 0;
552 if (BEFORE_EOS_INPUT && frameCount_ > EOS_COUNT) {
553 SetEOS(index);
554 return 1;
555 }
556 if (BEFORE_EOS_INPUT_INPUT && frameCount_ > EOS_COUNT) {
557 memset_s(&attr, sizeof(OH_AVCodecBufferAttr), 0, sizeof(OH_AVCodecBufferAttr));
558 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
559 BEFORE_EOS_INPUT_INPUT = false;
560 }
561 if (inFile_->tellg() == 0) {
562 inFile_->read(reinterpret_cast<char *>(prereadBuffer_.get() + START_CODE_SIZE), PREREAD_BUFFER_SIZE);
563 prereadBufferSize_ = inFile_->gcount() + START_CODE_SIZE;
564 pPrereadBuffer_ = START_CODE_SIZE;
565 }
566
567 if (finishLastPush) {
568 SetEOS(index);
569 mpegUnit_->resize(0);
570 return 1;
571 }
572 GetBufferSize();
573 bufferSize = mpegUnit_->size();
574 if (bufferSize > MAX_WIDTH * MAX_HEIGHT << 1) {
575 return 1;
576 }
577
578 return SendData(bufferSize, index, buffer);
579 }
580
SendData(uint32_t bufferSize,uint32_t index,OH_AVMemory * buffer)581 uint32_t VDecNdkSample::SendData(uint32_t bufferSize, uint32_t index, OH_AVMemory *buffer)
582 {
583 OH_AVCodecBufferAttr attr;
584 uint8_t *frameBuffer = nullptr;
585 int32_t ret = 0;
586 if (bufferSize > 0) {
587 frameBuffer = new uint8_t[bufferSize];
588 } else {
589 delete[] frameBuffer;
590 return 0;
591 }
592 memcpy_s(frameBuffer, bufferSize, mpegUnit_->data(), bufferSize);
593 attr.pts = GetSystemTimeUs();
594 attr.size = bufferSize;
595 attr.offset = 0;
596 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
597
598 if (pPrereadBuffer_ == prereadBufferSize_ && inFile_->eof()) {
599 finishLastPush = true;
600 }
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
625 if (finishLastPush && repeatRun) {
626 inFile_->clear();
627 inFile_->seekg(0, ios::beg);
628 finishLastPush = false;
629 cout << "repeat" << endl;
630 return 0;
631 }
632 return 0;
633 }
634
InputFunc_AVCC()635 void VDecNdkSample::InputFunc_AVCC()
636 {
637 frameCount_ = 1;
638 errCount = 0;
639 while (true) {
640 if (!isRunning_.load()) {
641 break;
642 }
643 if (frameCount_ % (EOS_COUNT >> 1) == 0) {
644 if (REPEAT_START_FLUSH_BEFORE_EOS > 0) {
645 REPEAT_START_FLUSH_BEFORE_EOS--;
646 OH_VideoDecoder_Flush(vdec_);
647 Flush_buffer();
648 OH_VideoDecoder_Start(vdec_);
649 }
650 if (REPEAT_START_STOP_BEFORE_EOS > 0) {
651 REPEAT_START_STOP_BEFORE_EOS--;
652 OH_VideoDecoder_Stop(vdec_);
653 Flush_buffer();
654 OH_VideoDecoder_Start(vdec_);
655 }
656 }
657 unique_lock<mutex> lock(signal_->inMutex_);
658 signal_->inCond_.wait(lock, [this]() {
659 if (!isRunning_.load()) {
660 cout << "quit signal" << endl;
661 return true;
662 }
663 return signal_->inIdxQueue_.size() > 0;
664 });
665 if (!isRunning_.load()) {
666 break;
667 }
668 uint32_t index = signal_->inIdxQueue_.front();
669 auto buffer = signal_->inBufferQueue_.front();
670 signal_->inIdxQueue_.pop();
671 signal_->inBufferQueue_.pop();
672 lock.unlock();
673 int ret = ReadData(index, buffer);
674 if (ret == 1) {
675 break;
676 }
677
678 if (sleepOnFPS) {
679 usleep(FRAME_INTERVAL);
680 }
681 }
682 }
683
InputFunc_FUZZ(const uint8_t * data,size_t size)684 OH_AVErrCode VDecNdkSample::InputFunc_FUZZ(const uint8_t *data, size_t size)
685 {
686 uint32_t index;
687 unique_lock<mutex> lock(signal_->inMutex_);
688 signal_->inCond_.wait(lock, [this]() {
689 if (!isRunning_.load() && g_fuzzError) {
690 return true;
691 }
692 return signal_->inIdxQueue_.size() > 0;
693 });
694 if (g_fuzzError)
695 return AV_ERR_TIMEOUT;
696 index = signal_->inIdxQueue_.front();
697 auto buffer = signal_->inBufferQueue_.front();
698 lock.unlock();
699 int32_t buffer_size = OH_AVMemory_GetSize(buffer);
700 uint8_t *buffer_addr = OH_AVMemory_GetAddr(buffer);
701
702 if (memcpy_s(buffer_addr, buffer_size, data, size) != EOK) {
703 cout << "Fatal: memcpy fail" << endl;
704 return AV_ERR_NO_MEMORY;
705 }
706 OH_AVCodecBufferAttr attr;
707 attr.pts = GetSystemTimeUs();
708 attr.size = buffer_size;
709 attr.offset = 0;
710 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
711 OH_AVErrCode ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
712 signal_->inIdxQueue_.pop();
713 signal_->inBufferQueue_.pop();
714 return ret;
715 }
716
SetEOS(uint32_t index)717 void VDecNdkSample::SetEOS(uint32_t index)
718 {
719 OH_AVCodecBufferAttr attr;
720 attr.pts = 0;
721 attr.size = 0;
722 attr.offset = 0;
723 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
724 int32_t res = OH_VideoDecoder_PushInputData(vdec_, index, attr);
725 cout << "OH_VideoDecoder_PushInputData EOS res: " << res << endl;
726 }
727
state_EOS()728 int32_t VDecNdkSample::state_EOS()
729 {
730 unique_lock<mutex> lock(signal_->inMutex_);
731 signal_->inCond_.wait(lock, [this]() {
732 if (!isRunning_.load()) {
733 return true;
734 }
735 return signal_->inIdxQueue_.size() > 0;
736 });
737 uint32_t index = signal_->inIdxQueue_.front();
738 signal_->inIdxQueue_.pop();
739 OH_AVCodecBufferAttr attr;
740 attr.pts = 0;
741 attr.size = 0;
742 attr.offset = 0;
743 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
744 return OH_VideoDecoder_PushInputData(vdec_, index, attr);
745 }
746
Flush()747 int32_t VDecNdkSample::Flush()
748 {
749 unique_lock<mutex> inLock(signal_->inMutex_);
750 clearIntqueue(signal_->inIdxQueue_);
751 signal_->inCond_.notify_all();
752 inLock.unlock();
753 unique_lock<mutex> outLock(signal_->outMutex_);
754 clearIntqueue(signal_->outIdxQueue_);
755 clearBufferqueue(signal_->attrQueue_);
756 signal_->outCond_.notify_all();
757 outLock.unlock();
758
759 return OH_VideoDecoder_Flush(vdec_);
760 }
761
Reset()762 int32_t VDecNdkSample::Reset()
763 {
764 isRunning_.store(false);
765 StopInloop();
766 StopOutloop();
767 ReleaseInFile();
768 return OH_VideoDecoder_Reset(vdec_);
769 }
770
Release()771 int32_t VDecNdkSample::Release()
772 {
773 int ret = 0;
774 if (vdec_ != nullptr) {
775 ret = OH_VideoDecoder_Destroy(vdec_);
776 vdec_ = nullptr;
777 }
778
779 if (signal_ != nullptr) {
780 delete signal_;
781 signal_ = nullptr;
782 }
783 return ret;
784 }
785
Stop()786 int32_t VDecNdkSample::Stop()
787 {
788 StopInloop();
789 clearIntqueue(signal_->outIdxQueue_);
790 clearBufferqueue(signal_->attrQueue_);
791 ReleaseInFile();
792 return OH_VideoDecoder_Stop(vdec_);
793 }
794
Start()795 int32_t VDecNdkSample::Start()
796 {
797 int32_t ret = OH_VideoDecoder_Start(vdec_);
798 if (ret == AV_ERR_OK) {
799 isRunning_.store(true);
800 }
801 return ret;
802 }
803
StopOutloop()804 void VDecNdkSample::StopOutloop()
805 {
806 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
807 unique_lock<mutex> lock(signal_->outMutex_);
808 clearIntqueue(signal_->outIdxQueue_);
809 clearBufferqueue(signal_->attrQueue_);
810 signal_->outCond_.notify_all();
811 lock.unlock();
812 }
813 }
814
SetParameter(OH_AVFormat * format)815 int32_t VDecNdkSample::SetParameter(OH_AVFormat *format)
816 {
817 return OH_VideoDecoder_SetParameter(vdec_, format);
818 }