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, ¤tWidht);
107 OH_AVFormat_GetIntValue(format, OH_MD_KEY_HEIGHT, ¤tHeight);
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 }