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_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 Release();
247 }
248
CreateCodec()249 int32_t HDRCodecNdkSample::CreateCodec()
250 {
251 decSignal = new VSignal();
252 if (decSignal == nullptr) {
253 return AV_ERR_UNKNOWN;
254 }
255 vdec_ = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
256 if (vdec_ == nullptr) {
257 return AV_ERR_UNKNOWN;
258 }
259
260 venc_ = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
261 if (venc_ == nullptr) {
262 return AV_ERR_UNKNOWN;
263 }
264 return AV_ERR_OK;
265 }
266
FlushBuffer()267 void HDRCodecNdkSample::FlushBuffer()
268 {
269 unique_lock<mutex> decInLock(decSignal->inMutex_);
270 clearIntqueue(decSignal->inIdxQueue_);
271 std::queue<OH_AVMemory *>empty;
272 swap(empty, decSignal->inBufferQueue_);
273 decSignal->inCond_.notify_all();
274 inFile_->clear();
275 inFile_->seekg(0, ios::beg);
276 decInLock.unlock();
277 }
278
RepeatCall()279 int32_t HDRCodecNdkSample::RepeatCall()
280 {
281 if (REPEAT_START_FLUSH_BEFORE_EOS > 0) {
282 return RepeatCallStartFlush(this);
283 }
284 if (REPEAT_START_STOP_BEFORE_EOS > 0) {
285 return RepeatCallStartStop(this);
286 }
287 if (REPEAT_START_FLUSH_STOP_BEFORE_EOS > 0) {
288 return RepeatCallStartFlushStop(this);
289 }
290 return 0;
291 }
292
InputFunc()293 void HDRCodecNdkSample::InputFunc()
294 {
295 while (true) {
296 if (!g_isRunning.load()) {
297 break;
298 }
299 int32_t ret = RepeatCall();
300 if (ret != 0) {
301 cout << "repeat call failed, errcode " << ret << endl;
302 errorCount++;
303 g_isRunning.store(false);
304 g_cv.notify_all();
305 break;
306 }
307 uint32_t index;
308 unique_lock<mutex> lock(decSignal->inMutex_);
309 decSignal->inCond_.wait(lock, [this]() {
310 if (!g_isRunning.load()) {
311 return true;
312 }
313 return decSignal->inIdxQueue_.size() > 0;
314 });
315 if (!g_isRunning.load()) {
316 break;
317 }
318 index = decSignal->inIdxQueue_.front();
319 auto buffer = decSignal->inBufferQueue_.front();
320
321 decSignal->inIdxQueue_.pop();
322 decSignal->inBufferQueue_.pop();
323 lock.unlock();
324 if (SendData(vdec_, index, buffer) == 1)
325 break;
326 }
327 }
328
Configure()329 int32_t HDRCodecNdkSample::Configure()
330 {
331 OH_AVFormat *format = OH_AVFormat_Create();
332 if (format == nullptr) {
333 cout << "Fatal: Failed to create format" << endl;
334 return AV_ERR_UNKNOWN;
335 }
336 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
337 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
338 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_NV12);
339 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, DEFAULT_FRAME_RATE);
340 int ret = OH_VideoDecoder_Configure(vdec_, format);
341 if (ret != AV_ERR_OK) {
342 return ret;
343 }
344 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, DEFAULT_PROFILE);
345 ret = OH_VideoEncoder_Configure(venc_, format);
346 if (ret != AV_ERR_OK) {
347 return ret;
348 }
349 ret = OH_VideoEncoder_GetSurface(venc_, &window);
350 if (ret != AV_ERR_OK) {
351 return ret;
352 }
353 ret = OH_VideoDecoder_SetSurface(vdec_, window);
354 if (ret != AV_ERR_OK) {
355 return ret;
356 }
357 encCb_.onError = VencError;
358 encCb_.onStreamChanged = VencFormatChanged;
359 encCb_.onNeedInputData = VencInputDataReady;
360 encCb_.onNeedOutputData = VencOutputDataReady;
361 ret = OH_VideoEncoder_SetCallback(venc_, encCb_, this);
362 if (ret != AV_ERR_OK) {
363 return ret;
364 }
365 OH_AVFormat_Destroy(format);
366 decCb_.onError = VdecError;
367 decCb_.onStreamChanged = VdecFormatChanged;
368 decCb_.onNeedInputData = VdecInputDataReady;
369 decCb_.onNeedOutputData = VdecOutputDataReady;
370 return OH_VideoDecoder_SetCallback(vdec_, decCb_, this);
371 }
372
ReConfigure()373 int32_t HDRCodecNdkSample::ReConfigure()
374 {
375 int32_t ret = OH_VideoDecoder_Reset(vdec_);
376 if (ret != AV_ERR_OK) {
377 return ret;
378 }
379 ret = OH_VideoEncoder_Reset(venc_);
380 if (ret != AV_ERR_OK) {
381 return ret;
382 }
383 FlushBuffer();
384 OH_AVFormat *format = OH_AVFormat_Create();
385 if (format == nullptr) {
386 cout<< "Fatal: Failed to create format" << endl;
387 return AV_ERR_UNKNOWN;
388 }
389 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, DEFAULT_WIDTH);
390 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, DEFAULT_HEIGHT);
391 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_NV12);
392 (void)OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, DEFAULT_FRAME_RATE);
393 ret = OH_VideoDecoder_Configure(vdec_, format);
394 if (ret != AV_ERR_OK) {
395 OH_AVFormat_Destroy(format);
396 return ret;
397 }
398 (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, DEFAULT_PROFILE);
399 ret = OH_VideoEncoder_Configure(venc_, format);
400 if (ret != AV_ERR_OK) {
401 OH_AVFormat_Destroy(format);
402 return ret;
403 }
404 ret = OH_VideoDecoder_SetSurface(vdec_, window);
405 if (ret != AV_ERR_OK) {
406 OH_AVFormat_Destroy(format);
407 return ret;
408 }
409 OH_AVFormat_Destroy(format);
410 return ret;
411 }
412
Start()413 int32_t HDRCodecNdkSample::Start()
414 {
415 int32_t ret = 0;
416 inFile_ = make_unique<ifstream>();
417 inFile_->open(INP_DIR, ios::in | ios::binary);
418 if (!inFile_->is_open()) {
419 (void)OH_VideoDecoder_Destroy(vdec_);
420 (void)OH_VideoEncoder_Destroy(venc_);
421 inFile_->close();
422 inFile_.reset();
423 inFile_ = nullptr;
424 return AV_ERR_UNKNOWN;
425 }
426 g_isRunning.store(true);
427 ret = OH_VideoEncoder_Start(venc_);
428 if (ret != AV_ERR_OK) {
429 return ret;
430 }
431 ret = OH_VideoDecoder_Start(vdec_);
432 if (ret != AV_ERR_OK) {
433 return ret;
434 }
435 inputLoop_ = make_unique<thread>(&HDRCodecNdkSample::InputFunc, this);
436 if (inputLoop_ == nullptr) {
437 g_isRunning.store(false);
438 (void)OH_VideoDecoder_Stop(vdec_);
439 ReleaseInFile();
440 return AV_ERR_UNKNOWN;
441 }
442
443 return 0;
444 }
445
StopInloop()446 void HDRCodecNdkSample::StopInloop()
447 {
448 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
449 unique_lock<mutex> lock(decSignal->inMutex_);
450 clearIntqueue(decSignal->inIdxQueue_);
451 g_isRunning.store(false);
452 decSignal->inCond_.notify_all();
453 lock.unlock();
454 inputLoop_->join();
455 inputLoop_.reset();
456 }
457 }
458
ReleaseInFile()459 void HDRCodecNdkSample::ReleaseInFile()
460 {
461 if (inFile_ != nullptr) {
462 if (inFile_->is_open()) {
463 inFile_->close();
464 }
465 inFile_.reset();
466 inFile_ = nullptr;
467 }
468 }
469
WaitForEos()470 void HDRCodecNdkSample::WaitForEos()
471 {
472 std::mutex mtx;
473 unique_lock<mutex> lock(mtx);
474 g_cv.wait(lock, []() {
475 return !(g_isRunning.load());
476 });
477 inputLoop_->join();
478 OH_VideoDecoder_Stop(vdec_);
479 OH_VideoEncoder_Stop(venc_);
480 }
481
Release()482 int32_t HDRCodecNdkSample::Release()
483 {
484 if (decSignal != nullptr) {
485 delete decSignal;
486 decSignal = nullptr;
487 }
488 if (vdec_ != nullptr) {
489 OH_VideoDecoder_Destroy(vdec_);
490 vdec_ = nullptr;
491 }
492 if (venc_ != nullptr) {
493 OH_VideoEncoder_Destroy(venc_);
494 venc_ = nullptr;
495 }
496 return 0;
497 }