1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "hdrcodec_ndk_sample.h"
16
17 #include <arpa/inet.h>
18 #include <sys/time.h>
19 #include <utility>
20 #include <memory>
21
22 #include "native_avcodec_base.h"
23
24 using namespace OHOS;
25 using namespace OHOS::Media;
26 using namespace std;
27 namespace {
28 constexpr int64_t NANOS_IN_SECOND = 1000000000L;
29 constexpr int64_t NANOS_IN_MICRO = 1000L;
30 std::shared_ptr<std::ifstream> inFile_;
31 std::condition_variable g_cv;
32 std::atomic<bool> g_isRunning = true;
33
GetSystemTimeUs()34 int64_t GetSystemTimeUs()
35 {
36 struct timespec now;
37 (void)clock_gettime(CLOCK_BOOTTIME, &now);
38 int64_t nanoTime = static_cast<int64_t>(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec;
39
40 return nanoTime / NANOS_IN_MICRO;
41 }
42
VdecFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)43 void VdecFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
44 {
45 cout << "Format Changed" << endl;
46 }
47
VdecInputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)48 void VdecInputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
49 {
50 HDRCodecNdkSample *sample = static_cast<HDRCodecNdkSample *>(userData);
51 VSignal *signal = sample->decSignal;
52 unique_lock<mutex> lock(signal->inMutex_);
53 signal->inIdxQueue_.push(index);
54 signal->inBufferQueue_.push(data);
55 signal->inCond_.notify_all();
56 }
57
VdecOutputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)58 void VdecOutputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
59 void *userData)
60 {
61 HDRCodecNdkSample *sample = static_cast<HDRCodecNdkSample *>(userData);
62 OH_VideoDecoder_RenderOutputData(codec, index);
63 if (attr->flags & AVCODEC_BUFFER_FLAGS_EOS) {
64 OH_VideoEncoder_NotifyEndOfStream(sample->venc_);
65 } else {
66 sample->frameCountDec++;
67 }
68 }
69
VdecError(OH_AVCodec * codec,int32_t errorCode,void * userData)70 void VdecError(OH_AVCodec *codec, int32_t errorCode, void *userData)
71 {
72 HDRCodecNdkSample *sample = static_cast<HDRCodecNdkSample *>(userData);
73 sample->errorCount++;
74 cout << "Error errorCode=" << errorCode << endl;
75 }
76
VencError(OH_AVCodec * codec,int32_t errorCode,void * userData)77 static void VencError(OH_AVCodec *codec, int32_t errorCode, void *userData)
78 {
79 HDRCodecNdkSample *sample = static_cast<HDRCodecNdkSample *>(userData);
80 sample->errorCount++;
81 cout << "Error errorCode=" << errorCode << endl;
82 }
83
VencFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)84 static void VencFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
85 {
86 cout << "Format Changed" << endl;
87 }
88
VencInputDataReady(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)89 static void VencInputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
90 {
91 (void)codec;
92 (void)index;
93 (void)data;
94 (void)userData;
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 HDRCodecNdkSample *sample = static_cast<HDRCodecNdkSample*>(userData);
101 OH_VideoEncoder_FreeOutputData(codec, index);
102 if (attr->flags & AVCODEC_BUFFER_FLAGS_EOS) {
103 g_isRunning.store(false);
104 g_cv.notify_all();
105 } else {
106 sample->frameCountEnc++;
107 }
108 }
109
clearIntqueue(std::queue<uint32_t> & q)110 static void clearIntqueue(std::queue<uint32_t> &q)
111 {
112 std::queue<uint32_t> empty;
113 swap(empty, q);
114 }
115
SendData(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data)116 static int32_t SendData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data)
117 {
118 uint32_t bufferSize = 0;
119 int32_t result = 0;
120 OH_AVCodecBufferAttr attr;
121 static bool isFirstFrame = true;
122 (void)inFile_->read(reinterpret_cast<char *>(&bufferSize), sizeof(uint32_t));
123 if (inFile_->eof()) {
124 attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
125 attr.offset = 0;
126 OH_VideoDecoder_PushInputData(codec, index, attr);
127 return 1;
128 }
129 if (isFirstFrame) {
130 attr.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
131 isFirstFrame = false;
132 } else {
133 attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
134 }
135 int32_t size = OH_AVMemory_GetSize(data);
136 uint8_t *avBuffer = OH_AVMemory_GetAddr(data);
137 if (avBuffer == nullptr) {
138 return 0;
139 }
140 uint8_t *fileBuffer = new uint8_t[bufferSize];
141 if (fileBuffer == nullptr) {
142 cout << "Fatal: no memory" << endl;
143 delete[] fileBuffer;
144 return 0;
145 }
146 (void)inFile_->read(reinterpret_cast<char *>(fileBuffer), bufferSize);
147 if (memcpy_s(avBuffer, size, fileBuffer, bufferSize) != EOK) {
148 delete[] fileBuffer;
149 cout << "Fatal: memcpy fail" << endl;
150 return 0;
151 }
152 delete[] fileBuffer;
153 attr.pts = GetSystemTimeUs();
154 attr.size = bufferSize;
155 attr.offset = 0;
156 result = OH_VideoDecoder_PushInputData(codec, index, attr);
157 if (result != AV_ERR_OK) {
158 cout << "push input data failed,error:" << result << endl;
159 }
160 return 0;
161 }
162
RepeatCallStartFlush(HDRCodecNdkSample * sample)163 static int32_t RepeatCallStartFlush(HDRCodecNdkSample *sample)
164 {
165 int32_t ret = 0;
166 sample->REPEAT_START_FLUSH_BEFORE_EOS--;
167 ret = OH_VideoEncoder_Flush(sample->venc_);
168 if (ret != AV_ERR_OK) {
169 return ret;
170 }
171 ret = OH_VideoDecoder_Flush(sample->vdec_);
172 if (ret != AV_ERR_OK) {
173 return ret;
174 }
175 sample->FlushBuffer();
176 ret = OH_VideoEncoder_Start(sample->venc_);
177 if (ret != AV_ERR_OK) {
178 return ret;
179 }
180 ret = OH_VideoDecoder_Start(sample->vdec_);
181 if (ret != AV_ERR_OK) {
182 return ret;
183 }
184 return 0;
185 }
186
RepeatCallStartStop(HDRCodecNdkSample * sample)187 static int32_t RepeatCallStartStop(HDRCodecNdkSample *sample)
188 {
189 int32_t ret = 0;
190 sample->REPEAT_START_STOP_BEFORE_EOS--;
191 ret = OH_VideoDecoder_Stop(sample->vdec_);
192 if (ret != AV_ERR_OK) {
193 return ret;
194 }
195 ret = OH_VideoEncoder_Stop(sample->venc_);
196 if (ret != AV_ERR_OK) {
197 return ret;
198 }
199 sample->FlushBuffer();
200 ret = OH_VideoEncoder_Start(sample->venc_);
201 if (ret != AV_ERR_OK) {
202 return ret;
203 }
204 ret = OH_VideoDecoder_Start(sample->vdec_);
205 if (ret != AV_ERR_OK) {
206 return ret;
207 }
208 return 0;
209 }
210
RepeatCallStartFlushStop(HDRCodecNdkSample * sample)211 static int32_t RepeatCallStartFlushStop(HDRCodecNdkSample *sample)
212 {
213 int32_t ret = 0;
214 sample->REPEAT_START_FLUSH_STOP_BEFORE_EOS--;
215 ret = OH_VideoEncoder_Flush(sample->venc_);
216 if (ret != AV_ERR_OK) {
217 return ret;
218 }
219 ret = OH_VideoDecoder_Flush(sample->vdec_);
220 if (ret != AV_ERR_OK) {
221 return ret;
222 }
223 ret = OH_VideoDecoder_Stop(sample->vdec_);
224 if (ret != AV_ERR_OK) {
225 return ret;
226 }
227 ret = OH_VideoEncoder_Stop(sample->venc_);
228 if (ret != AV_ERR_OK) {
229 return ret;
230 }
231 sample->FlushBuffer();
232 ret = OH_VideoEncoder_Start(sample->venc_);
233 if (ret != AV_ERR_OK) {
234 return ret;
235 }
236 ret = OH_VideoDecoder_Start(sample->vdec_);
237 if (ret != AV_ERR_OK) {
238 return ret;
239 }
240 return 0;
241 }
242 }
243
~HDRCodecNdkSample()244 HDRCodecNdkSample::~HDRCodecNdkSample()
245 {
246 }
247
CreateCodec()248 int32_t HDRCodecNdkSample::CreateCodec()
249 {
250 decSignal = new VSignal();
251 if (decSignal == nullptr) {
252 return AV_ERR_UNKNOWN;
253 }
254 vdec_ = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
255 if (vdec_ == nullptr) {
256 return AV_ERR_UNKNOWN;
257 }
258
259 venc_ = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
260 if (venc_ == nullptr) {
261 return AV_ERR_UNKNOWN;
262 }
263 return AV_ERR_OK;
264 }
265
FlushBuffer()266 void HDRCodecNdkSample::FlushBuffer()
267 {
268 unique_lock<mutex> decInLock(decSignal->inMutex_);
269 clearIntqueue(decSignal->inIdxQueue_);
270 std::queue<OH_AVMemory *>empty;
271 swap(empty, decSignal->inBufferQueue_);
272 decSignal->inCond_.notify_all();
273 decInLock.unlock();
274 }
275
RepeatCall()276 int32_t HDRCodecNdkSample::RepeatCall()
277 {
278 if (REPEAT_START_FLUSH_BEFORE_EOS > 0) {
279 return RepeatCallStartFlush(this);
280 }
281 if (REPEAT_START_STOP_BEFORE_EOS > 0) {
282 return RepeatCallStartStop(this);
283 }
284 if (REPEAT_START_FLUSH_STOP_BEFORE_EOS > 0) {
285 return RepeatCallStartFlushStop(this);
286 }
287 return 0;
288 }
289
InputFunc()290 void HDRCodecNdkSample::InputFunc()
291 {
292 while (true) {
293 if (!g_isRunning.load()) {
294 break;
295 }
296 int32_t ret = RepeatCall();
297 if (ret != 0) {
298 cout << "repeat call failed, errcode " << ret << endl;
299 errorCount++;
300 g_isRunning.store(false);
301 g_cv.notify_all();
302 break;
303 }
304 uint32_t index;
305 unique_lock<mutex> lock(decSignal->inMutex_);
306 decSignal->inCond_.wait(lock, [this]() {
307 if (!g_isRunning.load()) {
308 return true;
309 }
310 return decSignal->inIdxQueue_.size() > 0;
311 });
312 if (!g_isRunning.load()) {
313 break;
314 }
315 index = decSignal->inIdxQueue_.front();
316 auto buffer = decSignal->inBufferQueue_.front();
317
318 decSignal->inIdxQueue_.pop();
319 decSignal->inBufferQueue_.pop();
320 lock.unlock();
321 if (SendData(vdec_, index, buffer) == 1)
322 break;
323 }
324 }
325
Configure()326 int32_t HDRCodecNdkSample::Configure()
327 {
328 OH_AVFormat *format = OH_AVFormat_Create();
329 if (format == nullptr) {
330 cout << "Fatal: Failed to create format" << endl;
331 return AV_ERR_UNKNOWN;
332 }
333 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
334 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
335 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_NV12);
336 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, DEFAULT_FRAME_RATE);
337 int ret = OH_VideoDecoder_Configure(vdec_, format);
338 if (ret != AV_ERR_OK) {
339 return ret;
340 }
341 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, DEFAULT_PROFILE);
342 ret = OH_VideoEncoder_Configure(venc_, format);
343 if (ret != AV_ERR_OK) {
344 return ret;
345 }
346 ret = OH_VideoEncoder_GetSurface(venc_, &window);
347 if (ret != AV_ERR_OK) {
348 return ret;
349 }
350 ret = OH_VideoDecoder_SetSurface(vdec_, window);
351 if (ret != AV_ERR_OK) {
352 return ret;
353 }
354 encCb_.onError = VencError;
355 encCb_.onStreamChanged = VencFormatChanged;
356 encCb_.onNeedInputData = VencInputDataReady;
357 encCb_.onNeedOutputData = VencOutputDataReady;
358 ret = OH_VideoEncoder_SetCallback(venc_, encCb_, this);
359 if (ret != AV_ERR_OK) {
360 return ret;
361 }
362 OH_AVFormat_Destroy(format);
363 decCb_.onError = VdecError;
364 decCb_.onStreamChanged = VdecFormatChanged;
365 decCb_.onNeedInputData = VdecInputDataReady;
366 decCb_.onNeedOutputData = VdecOutputDataReady;
367 return OH_VideoDecoder_SetCallback(vdec_, decCb_, this);
368 }
369
ReConfigure()370 int32_t HDRCodecNdkSample::ReConfigure()
371 {
372 int32_t ret = OH_VideoDecoder_Reset(vdec_);
373 if (ret != AV_ERR_OK) {
374 return ret;
375 }
376 ret = OH_VideoEncoder_Reset(venc_);
377 if (ret != AV_ERR_OK) {
378 return ret;
379 }
380 FlushBuffer();
381 OH_AVFormat *format = OH_AVFormat_Create();
382 if (format == nullptr) {
383 cout<< "Fatal: Failed to create format" << endl;
384 return AV_ERR_UNKNOWN;
385 }
386 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
387 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
388 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_NV12);
389 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, DEFAULT_FRAME_RATE);
390 ret = OH_VideoDecoder_Configure(vdec_, format);
391 if (ret != AV_ERR_OK) {
392 OH_AVFormat_Destroy(format);
393 return ret;
394 }
395 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, DEFAULT_PROFILE);
396 ret = OH_VideoEncoder_Configure(venc_, format);
397 if (ret != AV_ERR_OK) {
398 OH_AVFormat_Destroy(format);
399 return ret;
400 }
401 ret = OH_VideoDecoder_SetSurface(vdec_, window);
402 if (ret != AV_ERR_OK) {
403 OH_AVFormat_Destroy(format);
404 return ret;
405 }
406
407 OH_AVFormat_Destroy(format);
408 return ret;
409 }
410
Start()411 int32_t HDRCodecNdkSample::Start()
412 {
413 int32_t ret = 0;
414 inFile_ = make_unique<ifstream>();
415 inFile_->open(INP_DIR, ios::in | ios::binary);
416 if (!inFile_->is_open()) {
417 (void)OH_VideoDecoder_Destroy(vdec_);
418 (void)OH_VideoEncoder_Destroy(venc_);
419 inFile_->close();
420 inFile_.reset();
421 inFile_ = nullptr;
422 return AV_ERR_UNKNOWN;
423 }
424 g_isRunning.store(true);
425 ret = OH_VideoEncoder_Start(venc_);
426 if (ret != AV_ERR_OK) {
427 return ret;
428 }
429 ret = OH_VideoDecoder_Start(vdec_);
430 if (ret != AV_ERR_OK) {
431 return ret;
432 }
433 inputLoop_ = make_unique<thread>(&HDRCodecNdkSample::InputFunc, this);
434 if (inputLoop_ == nullptr) {
435 g_isRunning.store(false);
436 (void)OH_VideoDecoder_Stop(vdec_);
437 ReleaseInFile();
438 return AV_ERR_UNKNOWN;
439 }
440
441 return 0;
442 }
443
StopInloop()444 void HDRCodecNdkSample::StopInloop()
445 {
446 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
447 unique_lock<mutex> lock(decSignal->inMutex_);
448 clearIntqueue(decSignal->inIdxQueue_);
449 g_isRunning.store(false);
450 decSignal->inCond_.notify_all();
451 lock.unlock();
452 inputLoop_->join();
453 inputLoop_.reset();
454 }
455 }
456
ReleaseInFile()457 void HDRCodecNdkSample::ReleaseInFile()
458 {
459 if (inFile_ != nullptr) {
460 if (inFile_->is_open()) {
461 inFile_->close();
462 }
463 inFile_.reset();
464 inFile_ = nullptr;
465 }
466 }
467
WaitForEos()468 void HDRCodecNdkSample::WaitForEos()
469 {
470 std::mutex mtx;
471 unique_lock<mutex> lock(mtx);
472 g_cv.wait(lock, []() {
473 return !(g_isRunning.load());
474 });
475 inputLoop_->join();
476 OH_VideoDecoder_Stop(vdec_);
477 OH_VideoEncoder_Stop(venc_);
478 }
479
Release()480 int32_t HDRCodecNdkSample::Release()
481 {
482 delete decSignal;
483 return 0;
484 }