• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }