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 }