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 "native_buffer_inner.h"
20 #include "videoenc_sample.h"
21 using namespace OHOS;
22 using namespace OHOS::Media;
23 using namespace std;
24 namespace {
25 constexpr int64_t NANOS_IN_SECOND = 1000000000L;
26 constexpr int64_t NANOS_IN_MICRO = 1000L;
27 constexpr uint32_t FRAME_INTERVAL = 16666;
28 constexpr uint32_t MAX_PIXEL_FMT = 5;
29 constexpr uint8_t RGBA_SIZE = 4;
30 constexpr uint32_t IDR_FRAME_INTERVAL = 10;
31 constexpr uint32_t TEST_FRAME_COUNT = 25;
32 constexpr uint32_t DOUBLE = 2;
33 sptr<Surface> cs = nullptr;
34 sptr<Surface> ps = nullptr;
35 VEncNdkSample *enc_sample = nullptr;
36
clearIntqueue(std::queue<uint32_t> & q)37 void clearIntqueue(std::queue<uint32_t> &q)
38 {
39 std::queue<uint32_t> empty;
40 swap(empty, q);
41 }
42
clearBufferqueue(std::queue<OH_AVCodecBufferAttr> & q)43 void clearBufferqueue(std::queue<OH_AVCodecBufferAttr> &q)
44 {
45 std::queue<OH_AVCodecBufferAttr> empty;
46 swap(empty, q);
47 }
48 } // namespace
49
~VEncNdkSample()50 VEncNdkSample::~VEncNdkSample()
51 {
52 if (SURF_INPUT && nativeWindow) {
53 OH_NativeWindow_DestroyNativeWindow(nativeWindow);
54 nativeWindow = nullptr;
55 }
56 Release();
57 }
58
VencError(OH_AVCodec * codec,int32_t errorCode,void * userData)59 static void VencError(OH_AVCodec *codec, int32_t errorCode, void *userData)
60 {
61 cout << "Error errorCode=" << errorCode << endl;
62 }
63
VencFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)64 static void VencFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
65 {
66 cout << "Format Changed" << endl;
67 }
68
VencInputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)69 static void VencInputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
70 {
71 if (enc_sample->isFlushing_) {
72 return;
73 }
74 if (enc_sample->inputCallbackFlush) {
75 enc_sample->Flush();
76 cout << "OH_VideoEncoder_Flush end" << endl;
77 enc_sample->isRunning_.store(false);
78 enc_sample->signal_->inCond_.notify_all();
79 enc_sample->signal_->outCond_.notify_all();
80 return;
81 }
82 if (enc_sample->inputCallbackStop) {
83 OH_VideoEncoder_Stop(codec);
84 cout << "OH_VideoEncoder_Stop end" << endl;
85 enc_sample->isRunning_.store(false);
86 enc_sample->signal_->inCond_.notify_all();
87 enc_sample->signal_->outCond_.notify_all();
88 return;
89 }
90 VEncSignal *signal = static_cast<VEncSignal *>(userData);
91 unique_lock<mutex> lock(signal->inMutex_);
92 signal->inIdxQueue_.push(index);
93 signal->inBufferQueue_.push(data);
94 signal->inCond_.notify_all();
95 }
96
VencOutputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)97 static void VencOutputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
98 void *userData)
99 {
100 if (enc_sample->isFlushing_) {
101 return;
102 }
103 if (enc_sample->outputCallbackFlush) {
104 enc_sample->Flush();
105 cout << "OH_VideoEncoder_Flush end" << endl;
106 enc_sample->isRunning_.store(false);
107 enc_sample->signal_->inCond_.notify_all();
108 enc_sample->signal_->outCond_.notify_all();
109 return;
110 }
111 if (enc_sample->outputCallbackStop) {
112 OH_VideoEncoder_Stop(codec);
113 cout << "OH_VideoEncoder_Stop end" << endl;
114 enc_sample->isRunning_.store(false);
115 enc_sample->signal_->inCond_.notify_all();
116 enc_sample->signal_->outCond_.notify_all();
117 return;
118 }
119 VEncSignal *signal = static_cast<VEncSignal *>(userData);
120 unique_lock<mutex> lock(signal->outMutex_);
121 signal->outIdxQueue_.push(index);
122 signal->attrQueue_.push(*attr);
123 signal->outBufferQueue_.push(data);
124 signal->outCond_.notify_all();
125 }
GetSystemTimeUs()126 int64_t VEncNdkSample::GetSystemTimeUs()
127 {
128 struct timespec now;
129 (void)clock_gettime(CLOCK_BOOTTIME, &now);
130 int64_t nanoTime = (int64_t)now.tv_sec * NANOS_IN_SECOND + now.tv_nsec;
131
132 return nanoTime / NANOS_IN_MICRO;
133 }
134
ConfigureVideoEncoder()135 int32_t VEncNdkSample::ConfigureVideoEncoder()
136 {
137 OH_AVFormat *format = OH_AVFormat_Create();
138 if (format == nullptr) {
139 cout << "Fatal: Failed to create format" << endl;
140 return AV_ERR_UNKNOWN;
141 }
142 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
143 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
144 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, DEFAULT_PIX_FMT);
145 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, DEFAULT_FRAME_RATE);
146 (void)OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, DEFAULT_BITRATE);
147 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, DEFAULT_KEY_FRAME_INTERVAL);
148 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_RANGE_FLAG, 1);
149 if (DEFAULT_BITRATE_MODE == CQ) {
150 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_QUALITY, DEFAULT_QUALITY);
151 }
152 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, DEFAULT_BITRATE_MODE);
153 int ret = OH_VideoEncoder_Configure(venc_, format);
154 OH_AVFormat_Destroy(format);
155 return ret;
156 }
157
ConfigureVideoEncoder_Temporal(int32_t temporal_gop_size)158 int32_t VEncNdkSample::ConfigureVideoEncoder_Temporal(int32_t temporal_gop_size)
159 {
160 OH_AVFormat *format = OH_AVFormat_Create();
161 if (format == nullptr) {
162 cout << "Fatal: Failed to create format" << endl;
163 return AV_ERR_UNKNOWN;
164 }
165 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
166 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
167 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, DEFAULT_PIX_FMT);
168 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, DEFAULT_FRAME_RATE);
169 (void)OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, DEFAULT_BITRATE);
170
171 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, DEFAULT_KEY_FRAME_INTERVAL);
172
173 if (TEMPORAL_CONFIG) {
174 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_TEMPORAL_GOP_SIZE, temporal_gop_size);
175 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE,
176 ADJACENT_REFERENCE);
177 }
178 if (TEMPORAL_ENABLE) {
179 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY, 1);
180 }
181 if (TEMPORAL_JUMP_MODE) {
182 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE, JUMP_REFERENCE);
183 }
184 int ret = OH_VideoEncoder_Configure(venc_, format);
185 OH_AVFormat_Destroy(format);
186 return ret;
187 }
188
ConfigureVideoEncoder_fuzz(int32_t data)189 int32_t VEncNdkSample::ConfigureVideoEncoder_fuzz(int32_t data)
190 {
191 OH_AVFormat *format = OH_AVFormat_Create();
192 if (format == nullptr) {
193 cout << "Fatal: Failed to create format" << endl;
194 return AV_ERR_UNKNOWN;
195 }
196 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, data);
197 DEFAULT_WIDTH = data;
198 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, data);
199 DEFAULT_HEIGHT = data;
200 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, data % MAX_PIXEL_FMT);
201 double frameRate = data;
202 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, frameRate);
203
204 OH_AVFormat_SetIntValue(format, OH_MD_KEY_RANGE_FLAG, data);
205 OH_AVFormat_SetIntValue(format, OH_MD_KEY_COLOR_PRIMARIES, data);
206 OH_AVFormat_SetIntValue(format, OH_MD_KEY_TRANSFER_CHARACTERISTICS, data);
207 OH_AVFormat_SetIntValue(format, OH_MD_KEY_MATRIX_COEFFICIENTS, data);
208 OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, data);
209 OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, data);
210 OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, data);
211 OH_AVFormat_SetIntValue(format, OH_MD_KEY_QUALITY, data);
212
213 int ret = OH_VideoEncoder_Configure(venc_, format);
214 OH_AVFormat_Destroy(format);
215 return ret;
216 }
217
SetVideoEncoderCallback()218 int32_t VEncNdkSample::SetVideoEncoderCallback()
219 {
220 signal_ = new VEncSignal();
221 if (signal_ == nullptr) {
222 cout << "Failed to new VEncSignal" << endl;
223 return AV_ERR_UNKNOWN;
224 }
225
226 cb_.onError = VencError;
227 cb_.onStreamChanged = VencFormatChanged;
228 cb_.onNeedInputData = VencInputDataReady;
229 cb_.onNeedOutputData = VencOutputDataReady;
230 return OH_VideoEncoder_SetCallback(venc_, cb_, static_cast<void *>(signal_));
231 }
232
state_EOS()233 int32_t VEncNdkSample::state_EOS()
234 {
235 unique_lock<mutex> lock(signal_->inMutex_);
236 signal_->inCond_.wait(lock, [this]() { return signal_->inIdxQueue_.size() > 0; });
237 uint32_t index = signal_->inIdxQueue_.front();
238 signal_->inIdxQueue_.pop();
239 signal_->inBufferQueue_.pop();
240 lock.unlock();
241 OH_AVCodecBufferAttr attr;
242 attr.pts = 0;
243 attr.size = 0;
244 attr.offset = 0;
245 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
246 return OH_VideoEncoder_PushInputData(venc_, index, attr);
247 }
ReleaseInFile()248 void VEncNdkSample::ReleaseInFile()
249 {
250 if (inFile_ != nullptr) {
251 if (inFile_->is_open()) {
252 inFile_->close();
253 }
254 inFile_.reset();
255 inFile_ = nullptr;
256 }
257 }
258
StopInloop()259 void VEncNdkSample::StopInloop()
260 {
261 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
262 unique_lock<mutex> lock(signal_->inMutex_);
263 clearIntqueue(signal_->inIdxQueue_);
264 isRunning_.store(false);
265 signal_->inCond_.notify_all();
266 lock.unlock();
267
268 inputLoop_->join();
269 inputLoop_ = nullptr;
270 }
271 }
272
testApi()273 void VEncNdkSample::testApi()
274 {
275 OH_VideoEncoder_GetSurface(venc_, &nativeWindow);
276 OH_VideoEncoder_Prepare(venc_);
277 OH_VideoEncoder_GetInputDescription(venc_);
278 OH_VideoEncoder_Start(venc_);
279 OH_AVFormat *format = OH_AVFormat_Create();
280 OH_AVFormat_SetIntValue(format, OH_MD_KEY_REQUEST_I_FRAME, 1);
281 OH_VideoEncoder_SetParameter(venc_, format);
282 OH_VideoEncoder_NotifyEndOfStream(venc_);
283 OH_VideoEncoder_GetOutputDescription(venc_);
284 OH_AVFormat_Destroy(format);
285 OH_VideoEncoder_Flush(venc_);
286 bool isValid = false;
287 OH_VideoEncoder_IsValid(venc_, &isValid);
288 OH_VideoEncoder_Stop(venc_);
289 OH_VideoEncoder_Reset(venc_);
290 }
291
CreateSurface()292 int32_t VEncNdkSample::CreateSurface()
293 {
294 int32_t ret = 0;
295 ret = OH_VideoEncoder_GetSurface(venc_, &nativeWindow);
296 if (ret != AV_ERR_OK) {
297 cout << "OH_VideoEncoder_GetSurface fail" << endl;
298 return ret;
299 }
300 ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_FORMAT, GRAPHIC_PIXEL_FMT_YCBCR_420_SP);
301 if (ret != AV_ERR_OK) {
302 cout << "NativeWindowHandleOpt SET_FORMAT fail" << endl;
303 return ret;
304 }
305 ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_BUFFER_GEOMETRY, DEFAULT_WIDTH, DEFAULT_HEIGHT);
306 if (ret != AV_ERR_OK) {
307 cout << "NativeWindowHandleOpt SET_BUFFER_GEOMETRY fail" << endl;
308 return ret;
309 }
310 return AV_ERR_OK;
311 }
312
GetStride()313 void VEncNdkSample::GetStride()
314 {
315 OH_AVFormat *format = OH_VideoEncoder_GetInputDescription(venc_);
316 int32_t inputStride = 0;
317 OH_AVFormat_GetIntValue(format, "stride", &inputStride);
318 stride_ = inputStride;
319 OH_AVFormat_Destroy(format);
320 }
321
OpenFile()322 int32_t VEncNdkSample::OpenFile()
323 {
324 if (fuzzMode) {
325 return AV_ERR_OK;
326 }
327 int32_t ret = AV_ERR_OK;
328 inFile_ = make_unique<ifstream>();
329 if (inFile_ == nullptr) {
330 isRunning_.store(false);
331 (void)OH_VideoEncoder_Stop(venc_);
332 return AV_ERR_UNKNOWN;
333 }
334 inFile_->open(INP_DIR, ios::in | ios::binary);
335 if (!inFile_->is_open()) {
336 cout << "file open fail" << endl;
337 isRunning_.store(false);
338 (void)OH_VideoEncoder_Stop(venc_);
339 inFile_->close();
340 inFile_.reset();
341 inFile_ = nullptr;
342 return AV_ERR_UNKNOWN;
343 }
344 return ret;
345 }
346
StartVideoEncoder()347 int32_t VEncNdkSample::StartVideoEncoder()
348 {
349 isRunning_.store(true);
350 int32_t ret = 0;
351 if (SURF_INPUT) {
352 ret = CreateSurface();
353 if (ret != AV_ERR_OK) {
354 return ret;
355 }
356 }
357 ret = OH_VideoEncoder_Start(venc_);
358 GetStride();
359 if (ret != AV_ERR_OK) {
360 cout << "Failed to start codec" << endl;
361 isRunning_.store(false);
362 signal_->inCond_.notify_all();
363 signal_->outCond_.notify_all();
364 return ret;
365 }
366 if (OpenFile() != AV_ERR_OK) {
367 return AV_ERR_UNKNOWN;
368 }
369 if (SURF_INPUT) {
370 inputLoop_ = make_unique<thread>(&VEncNdkSample::InputFuncSurface, this);
371 } else {
372 inputLoop_ = make_unique<thread>(&VEncNdkSample::InputFunc, this);
373 }
374 if (inputLoop_ == nullptr) {
375 isRunning_.store(false);
376 (void)OH_VideoEncoder_Stop(venc_);
377 ReleaseInFile();
378 return AV_ERR_UNKNOWN;
379 }
380 outputLoop_ = make_unique<thread>(&VEncNdkSample::OutputFunc, this);
381 if (outputLoop_ == nullptr) {
382 isRunning_.store(false);
383 (void)OH_VideoEncoder_Stop(venc_);
384 ReleaseInFile();
385 StopInloop();
386 Release();
387 return AV_ERR_UNKNOWN;
388 }
389 return AV_ERR_OK;
390 }
391
CreateVideoEncoder(const char * codecName)392 int32_t VEncNdkSample::CreateVideoEncoder(const char *codecName)
393 {
394 venc_ = OH_VideoEncoder_CreateByName(codecName);
395 enc_sample = this;
396 randomEos = rand() % TEST_FRAME_COUNT;
397 return venc_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
398 }
399
WaitForEOS()400 void VEncNdkSample::WaitForEOS()
401 {
402 if (inputLoop_)
403 inputLoop_->join();
404 if (outputLoop_)
405 outputLoop_->join();
406 inputLoop_ = nullptr;
407 outputLoop_ = nullptr;
408 }
409
ReturnZeroIfEOS(uint32_t expectedSize)410 uint32_t VEncNdkSample::ReturnZeroIfEOS(uint32_t expectedSize)
411 {
412 if (inFile_->gcount() != (expectedSize)) {
413 cout << "no more data" << endl;
414 return 0;
415 }
416 return 1;
417 }
418
ReadOneFrameYUV420SP(uint8_t * dst)419 uint32_t VEncNdkSample::ReadOneFrameYUV420SP(uint8_t *dst)
420 {
421 uint8_t *start = dst;
422 // copy Y
423 for (uint32_t i = 0; i < DEFAULT_HEIGHT; i++) {
424 inFile_->read(reinterpret_cast<char *>(dst), DEFAULT_WIDTH);
425 if (!ReturnZeroIfEOS(DEFAULT_WIDTH))
426 return 0;
427 dst += stride_;
428 }
429 // copy UV
430 for (uint32_t i = 0; i < DEFAULT_HEIGHT / SAMPLE_RATIO; i++) {
431 inFile_->read(reinterpret_cast<char *>(dst), DEFAULT_WIDTH);
432 if (!ReturnZeroIfEOS(DEFAULT_WIDTH))
433 return 0;
434 dst += stride_;
435 }
436 return dst - start;
437 }
438
ReadOneFrameRGBA8888(uint8_t * dst)439 void VEncNdkSample::ReadOneFrameRGBA8888(uint8_t *dst)
440 {
441 for (uint32_t i = 0; i < DEFAULT_HEIGHT; i++) {
442 inFile_->read(reinterpret_cast<char *>(dst), DEFAULT_WIDTH * RGBA_SIZE);
443 dst += stride_;
444 }
445 }
446
FlushSurf(OHNativeWindowBuffer * ohNativeWindowBuffer,OH_NativeBuffer * nativeBuffer)447 uint32_t VEncNdkSample::FlushSurf(OHNativeWindowBuffer *ohNativeWindowBuffer, OH_NativeBuffer *nativeBuffer)
448 {
449 struct Region region;
450 struct Region::Rect *rect = new Region::Rect();
451 rect->x = 0;
452 rect->y = 0;
453 rect->w = DEFAULT_WIDTH;
454 rect->h = DEFAULT_HEIGHT;
455 region.rects = rect;
456 NativeWindowHandleOpt(nativeWindow, SET_UI_TIMESTAMP, GetSystemTimeUs());
457 int32_t err = OH_NativeBuffer_Unmap(nativeBuffer);
458 if (err != 0) {
459 cout << "OH_NativeBuffer_Unmap failed" << endl;
460 return 1;
461 }
462 err = OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, ohNativeWindowBuffer, -1, region);
463 delete rect;
464 if (err != 0) {
465 cout << "FlushBuffer failed" << endl;
466 return 1;
467 }
468 return 0;
469 }
470
InputFuncSurface()471 void VEncNdkSample::InputFuncSurface()
472 {
473 while (true) {
474 if (outputCallbackFlush || outputCallbackStop) {
475 OH_VideoEncoder_NotifyEndOfStream(venc_);
476 break;
477 }
478 OHNativeWindowBuffer *ohNativeWindowBuffer;
479 int fenceFd = -1;
480 if (nativeWindow == nullptr) {
481 cout << "nativeWindow == nullptr" << endl;
482 break;
483 }
484
485 int32_t err = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &ohNativeWindowBuffer, &fenceFd);
486 if (err != 0) {
487 cout << "RequestBuffer failed, GSError=" << err << endl;
488 break;
489 }
490 if (fenceFd > 0) {
491 close(fenceFd);
492 }
493 OH_NativeBuffer *nativeBuffer = OH_NativeBufferFromNativeWindowBuffer(ohNativeWindowBuffer);
494 void *virAddr = nullptr;
495 err = OH_NativeBuffer_Map(nativeBuffer, &virAddr);
496 if (err != 0) {
497 cout << "OH_NativeBuffer_Map failed, GSError=" << err << endl;
498 isRunning_.store(false);
499 break;
500 }
501 uint8_t *dst = (uint8_t *)virAddr;
502 const SurfaceBuffer *sbuffer = SurfaceBuffer::NativeBufferToSurfaceBuffer(nativeBuffer);
503 int stride = sbuffer->GetStride();
504 if (dst == nullptr || stride < DEFAULT_WIDTH) {
505 cout << "invalid va or stride=" << stride << endl;
506 err = NativeWindowCancelBuffer(nativeWindow, ohNativeWindowBuffer);
507 isRunning_.store(false);
508 break;
509 }
510 stride_ = stride;
511 if (!ReadOneFrameYUV420SP(dst)) {
512 err = OH_VideoEncoder_NotifyEndOfStream(venc_);
513 if (err != 0) {
514 cout << "OH_VideoEncoder_NotifyEndOfStream failed" << endl;
515 }
516 break;
517 }
518 if (FlushSurf(ohNativeWindowBuffer, nativeBuffer))
519 break;
520 usleep(FRAME_INTERVAL);
521 }
522 }
523
Flush_buffer()524 void VEncNdkSample::Flush_buffer()
525 {
526 unique_lock<mutex> inLock(signal_->inMutex_);
527 clearIntqueue(signal_->inIdxQueue_);
528 std::queue<OH_AVMemory *> empty;
529 swap(empty, signal_->inBufferQueue_);
530 signal_->inCond_.notify_all();
531 inLock.unlock();
532 unique_lock<mutex> outLock(signal_->outMutex_);
533 clearIntqueue(signal_->outIdxQueue_);
534 clearBufferqueue(signal_->attrQueue_);
535 signal_->outCond_.notify_all();
536 outLock.unlock();
537 }
538
RepeatStartBeforeEOS()539 void VEncNdkSample::RepeatStartBeforeEOS()
540 {
541 if (REPEAT_START_FLUSH_BEFORE_EOS > 0) {
542 REPEAT_START_FLUSH_BEFORE_EOS--;
543 OH_VideoEncoder_Flush(venc_);
544 Flush_buffer();
545 OH_VideoEncoder_Start(venc_);
546 }
547
548 if (REPEAT_START_STOP_BEFORE_EOS > 0) {
549 REPEAT_START_STOP_BEFORE_EOS--;
550 OH_VideoEncoder_Stop(venc_);
551 Flush_buffer();
552 OH_VideoEncoder_Start(venc_);
553 }
554 }
555
RandomEOS(uint32_t index)556 bool VEncNdkSample::RandomEOS(uint32_t index)
557 {
558 if (enable_random_eos && randomEos == frameCount) {
559 OH_AVCodecBufferAttr attr;
560 attr.pts = 0;
561 attr.size = 0;
562 attr.offset = 0;
563 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
564 OH_VideoEncoder_PushInputData(venc_, index, attr);
565 cout << "random eos" << endl;
566 frameCount++;
567 unique_lock<mutex> lock(signal_->inMutex_);
568 signal_->inIdxQueue_.pop();
569 signal_->inBufferQueue_.pop();
570 return true;
571 }
572 return false;
573 }
574
AutoSwitchParam()575 void VEncNdkSample::AutoSwitchParam()
576 {
577 int64_t currentBitrate = DEFAULT_BITRATE;
578 double currentFrameRate = DEFAULT_FRAME_RATE;
579 if (frameCount == switchParamsTimeSec * (int32_t)DEFAULT_FRAME_RATE) {
580 OH_AVFormat *format = OH_AVFormat_Create();
581 if (needResetBitrate) {
582 currentBitrate = DEFAULT_BITRATE >> 1;
583 cout<<"switch bitrate "<< currentBitrate;
584 (void)OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, currentBitrate);
585 SetParameter(format) == AV_ERR_OK ? (0) : (errCount++);
586 }
587 if (needResetFrameRate) {
588 currentFrameRate = DEFAULT_FRAME_RATE * DOUBLE;
589 cout<< "switch framerate" << currentFrameRate << endl;
590 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, currentFrameRate);
591 SetParameter(format) == AV_ERR_OK ? (0) : (errCount++);
592 }
593 OH_AVFormat_Destroy(format);
594 }
595 if (frameCount == switchParamsTimeSec * (int32_t)DEFAULT_FRAME_RATE * DOUBLE) {
596 OH_AVFormat *format = OH_AVFormat_Create();
597 if (needResetBitrate) {
598 currentBitrate = DEFAULT_BITRATE << 1;
599 cout<<"switch bitrate "<< currentBitrate;
600 (void)OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, currentBitrate);
601 }
602 if (needResetFrameRate) {
603 currentFrameRate = DEFAULT_FRAME_RATE / DOUBLE;
604 cout<< "switch framerate" << currentFrameRate << endl;
605 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, currentFrameRate);
606 SetParameter(format) == AV_ERR_OK ? (0) : (errCount++);
607 }
608 SetParameter(format) == AV_ERR_OK ? (0) : (errCount++);
609 OH_AVFormat_Destroy(format);
610 }
611 }
612
SetEOS(uint32_t index)613 void VEncNdkSample::SetEOS(uint32_t index)
614 {
615 OH_AVCodecBufferAttr attr;
616 attr.pts = 0;
617 attr.size = 0;
618 attr.offset = 0;
619 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
620 int32_t res = OH_VideoEncoder_PushInputData(venc_, index, attr);
621 cout << "OH_VideoEncoder_PushInputData EOS res: " << res << endl;
622 unique_lock<mutex> lock(signal_->inMutex_);
623 signal_->inIdxQueue_.pop();
624 signal_->inBufferQueue_.pop();
625 }
626
SetForceIDR()627 void VEncNdkSample::SetForceIDR()
628 {
629 OH_AVFormat *format = OH_AVFormat_Create();
630 OH_AVFormat_SetIntValue(format, OH_MD_KEY_REQUEST_I_FRAME, 1);
631 OH_VideoEncoder_SetParameter(venc_, format);
632 OH_AVFormat_Destroy(format);
633 }
634
PushData(OH_AVMemory * buffer,uint32_t index,int32_t & result)635 int32_t VEncNdkSample::PushData(OH_AVMemory *buffer, uint32_t index, int32_t &result)
636 {
637 int32_t res = -2;
638 OH_AVCodecBufferAttr attr;
639 uint8_t *fileBuffer = OH_AVMemory_GetAddr(buffer);
640 if (fileBuffer == nullptr) {
641 cout << "Fatal: no memory" << endl;
642 return -1;
643 }
644 int32_t size = OH_AVMemory_GetSize(buffer);
645 if (DEFAULT_PIX_FMT == AV_PIXEL_FORMAT_RGBA) {
646 if (size < DEFAULT_HEIGHT * stride_) {
647 return -1;
648 }
649 ReadOneFrameRGBA8888(fileBuffer);
650 attr.size = stride_ * DEFAULT_HEIGHT;
651 } else {
652 if (size < (DEFAULT_HEIGHT * stride_ + (DEFAULT_HEIGHT * stride_ / DOUBLE))) {
653 return -1;
654 }
655 attr.size = ReadOneFrameYUV420SP(fileBuffer);
656 }
657 if (repeatRun && inFile_->eof()) {
658 inFile_->clear();
659 inFile_->seekg(0, ios::beg);
660 encode_count++;
661 cout << "repeat"<< " encode_count:" << encode_count << endl;
662 return -1;
663 }
664 if (inFile_->eof()) {
665 SetEOS(index);
666 return 0;
667 }
668 attr.pts = GetSystemTimeUs();
669 attr.offset = 0;
670 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
671 if (enableForceIDR && (frameCount % IDR_FRAME_INTERVAL == 0)) {
672 SetForceIDR();
673 }
674 result = OH_VideoEncoder_PushInputData(venc_, index, attr);
675 unique_lock<mutex> lock(signal_->inMutex_);
676 signal_->inIdxQueue_.pop();
677 signal_->inBufferQueue_.pop();
678 return res;
679 }
680
CheckResult(bool isRandomEosSuccess,int32_t pushResult)681 int32_t VEncNdkSample::CheckResult(bool isRandomEosSuccess, int32_t pushResult)
682 {
683 if (isRandomEosSuccess) {
684 if (pushResult == 0) {
685 errCount = errCount + 1;
686 cout << "push input after eos should be failed! pushResult:" << pushResult << endl;
687 }
688 return -1;
689 } else if (pushResult != 0) {
690 errCount = errCount + 1;
691 cout << "push input data failed, error:" << pushResult << endl;
692 return -1;
693 }
694 return 0;
695 }
696
InputDataNormal(bool & runningFlag,uint32_t index,OH_AVMemory * buffer)697 void VEncNdkSample::InputDataNormal(bool &runningFlag, uint32_t index, OH_AVMemory *buffer)
698 {
699 if (!inFile_->eof()) {
700 bool isRandomEosSuccess = RandomEOS(index);
701 if (isRandomEosSuccess) {
702 runningFlag = false;
703 return;
704 }
705 int32_t pushResult = 0;
706 int32_t ret = PushData(buffer, index, pushResult);
707 if (ret == 0) {
708 runningFlag = false;
709 return;
710 } else if (ret == -1) {
711 return;
712 }
713 if (CheckResult(isRandomEosSuccess, pushResult) == -1) {
714 runningFlag = false;
715 isRunning_.store(false);
716 signal_->inCond_.notify_all();
717 signal_->outCond_.notify_all();
718 return;
719 }
720 frameCount++;
721 if (enableAutoSwitchParam) {
722 AutoSwitchParam();
723 }
724 }
725 }
726
InputDataFuzz(bool & runningFlag,uint32_t index)727 void VEncNdkSample::InputDataFuzz(bool &runningFlag, uint32_t index)
728 {
729 frameCount++;
730 if (frameCount == DEFAULT_FUZZ_TIME) {
731 SetEOS(index);
732 runningFlag = false;
733 return;
734 }
735 OH_AVCodecBufferAttr attr;
736 attr.pts = GetSystemTimeUs();
737 attr.offset = 0;
738 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
739 OH_VideoEncoder_PushInputData(venc_, index, attr);
740 unique_lock<mutex> lock(signal_->inMutex_);
741 signal_->inIdxQueue_.pop();
742 signal_->inBufferQueue_.pop();
743 }
744
InputFunc()745 void VEncNdkSample::InputFunc()
746 {
747 errCount = 0;
748 bool runningFlag = true;
749 while (runningFlag) {
750 if (!isRunning_.load()) {
751 break;
752 }
753 RepeatStartBeforeEOS();
754 unique_lock<mutex> lock(signal_->inMutex_);
755 signal_->inCond_.wait(lock, [this]() {
756 if (!isRunning_.load()) {
757 return true;
758 }
759 return signal_->inIdxQueue_.size() > 0 && !isFlushing_.load();
760 });
761 if (!isRunning_.load()) {
762 break;
763 }
764 uint32_t index = signal_->inIdxQueue_.front();
765 auto buffer = signal_->inBufferQueue_.front();
766 lock.unlock();
767 unique_lock<mutex> flushlock(signal_->flushMutex_);
768 if (isFlushing_) {
769 continue;
770 }
771 if (fuzzMode == false) {
772 InputDataNormal(runningFlag, index, buffer);
773 } else {
774 InputDataFuzz(runningFlag, index);
775 }
776 flushlock.unlock();
777 if (sleepOnFPS) {
778 usleep(FRAME_INTERVAL);
779 }
780 }
781 }
782
CheckAttrFlag(OH_AVCodecBufferAttr attr)783 int32_t VEncNdkSample::CheckAttrFlag(OH_AVCodecBufferAttr attr)
784 {
785 if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) {
786 cout << "attr.flags == AVCODEC_BUFFER_FLAGS_EOS" << endl;
787 unique_lock<mutex> inLock(signal_->inMutex_);
788 isRunning_.store(false);
789 signal_->inCond_.notify_all();
790 signal_->outCond_.notify_all();
791 inLock.unlock();
792 return -1;
793 }
794 if (attr.flags == AVCODEC_BUFFER_FLAGS_CODEC_DATA) {
795 cout << "enc AVCODEC_BUFFER_FLAGS_CODEC_DATA" << attr.pts << endl;
796 }
797 outCount = outCount + 1;
798 return 0;
799 }
800
OutputFuncFail()801 void VEncNdkSample::OutputFuncFail()
802 {
803 cout << "errCount > 0" << endl;
804 unique_lock<mutex> inLock(signal_->inMutex_);
805 isRunning_.store(false);
806 signal_->inCond_.notify_all();
807 signal_->outCond_.notify_all();
808 inLock.unlock();
809 (void)Stop();
810 Release();
811 }
812
OutputFunc()813 void VEncNdkSample::OutputFunc()
814 {
815 FILE *outFile = fopen(OUT_DIR, "wb");
816
817 while (true) {
818 if (!isRunning_.load()) {
819 break;
820 }
821 OH_AVCodecBufferAttr attr;
822 uint32_t index;
823 unique_lock<mutex> lock(signal_->outMutex_);
824 signal_->outCond_.wait(lock, [this]() {
825 if (!isRunning_.load()) {
826 return true;
827 }
828 return signal_->outIdxQueue_.size() > 0 && !isFlushing_.load();
829 });
830 if (!isRunning_.load()) {
831 break;
832 }
833 index = signal_->outIdxQueue_.front();
834 attr = signal_->attrQueue_.front();
835 OH_AVMemory *buffer = signal_->outBufferQueue_.front();
836 signal_->outBufferQueue_.pop();
837 signal_->outIdxQueue_.pop();
838 signal_->attrQueue_.pop();
839 lock.unlock();
840 if (CheckAttrFlag(attr) == -1) {
841 break;
842 }
843 int size = attr.size;
844 if (outFile == nullptr) {
845 cout << "dump data fail" << endl;
846 } else {
847 fwrite(OH_AVMemory_GetAddr(buffer), 1, size, outFile);
848 }
849
850 if (OH_VideoEncoder_FreeOutputData(venc_, index) != AV_ERR_OK) {
851 cout << "Fatal: ReleaseOutputBuffer fail" << endl;
852 errCount = errCount + 1;
853 }
854 if (errCount > 0) {
855 OutputFuncFail();
856 break;
857 }
858 }
859 if (outFile) {
860 (void)fclose(outFile);
861 }
862 }
863
Flush()864 int32_t VEncNdkSample::Flush()
865 {
866 isFlushing_.store(true);
867 unique_lock<mutex> flushLock(signal_->flushMutex_);
868 unique_lock<mutex> inLock(signal_->inMutex_);
869 clearIntqueue(signal_->inIdxQueue_);
870 signal_->inCond_.notify_all();
871 inLock.unlock();
872 unique_lock<mutex> outLock(signal_->outMutex_);
873 clearIntqueue(signal_->outIdxQueue_);
874 clearBufferqueue(signal_->attrQueue_);
875 signal_->outCond_.notify_all();
876 outLock.unlock();
877 int32_t ret = OH_VideoEncoder_Flush(venc_);
878 isFlushing_.store(false);
879 flushLock.unlock();
880 return ret;
881 }
882
Reset()883 int32_t VEncNdkSample::Reset()
884 {
885 isRunning_.store(false);
886 StopInloop();
887 StopOutloop();
888 ReleaseInFile();
889 return OH_VideoEncoder_Reset(venc_);
890 }
891
Release()892 int32_t VEncNdkSample::Release()
893 {
894 int ret = OH_VideoEncoder_Destroy(venc_);
895 venc_ = nullptr;
896 if (signal_ != nullptr) {
897 delete signal_;
898 signal_ = nullptr;
899 }
900 return ret;
901 }
902
Stop()903 int32_t VEncNdkSample::Stop()
904 {
905 StopInloop();
906 clearIntqueue(signal_->outIdxQueue_);
907 clearBufferqueue(signal_->attrQueue_);
908 ReleaseInFile();
909 return OH_VideoEncoder_Stop(venc_);
910 }
911
Start()912 int32_t VEncNdkSample::Start()
913 {
914 return OH_VideoEncoder_Start(venc_);
915 }
916
StopOutloop()917 void VEncNdkSample::StopOutloop()
918 {
919 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
920 unique_lock<mutex> lock(signal_->outMutex_);
921 clearIntqueue(signal_->outIdxQueue_);
922 clearBufferqueue(signal_->attrQueue_);
923 signal_->outCond_.notify_all();
924 lock.unlock();
925 }
926 }
927
SetParameter(OH_AVFormat * format)928 int32_t VEncNdkSample::SetParameter(OH_AVFormat *format)
929 {
930 if (venc_) {
931 return OH_VideoEncoder_SetParameter(venc_, format);
932 }
933 return AV_ERR_UNKNOWN;
934 }