• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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_inner_sample.h"
16 #include <arpa/inet.h>
17 #include <sys/time.h>
18 #include <utility>
19 #include <memory>
20 #include "native_avcodec_base.h"
21 #include "window.h"
22 #include "native_window.h"
23 #include "avcodec_errors.h"
24 #include "avcodec_common.h"
25 
26 using namespace OHOS;
27 using namespace OHOS::MediaAVCodec;
28 using namespace std;
29 namespace {
30 constexpr int64_t NANOS_IN_SECOND = 1000000000L;
31 constexpr int64_t NANOS_IN_MICRO = 1000L;
32 std::shared_ptr<std::ifstream> inFile_;
33 std::condition_variable g_cv;
34 std::atomic<bool> g_isRunning = true;
35 HDRCodecInnderNdkSample* hdr_sample = nullptr;
36 
GetSystemTimeUs()37 int64_t GetSystemTimeUs()
38 {
39     struct timespec now;
40     (void)clock_gettime(CLOCK_BOOTTIME, &now);
41     int64_t nanoTime = static_cast<int64_t>(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec;
42 
43     return nanoTime / NANOS_IN_MICRO;
44 }
clearIntqueue(std::queue<uint32_t> & q)45 static void clearIntqueue(std::queue<uint32_t> &q)
46 {
47     std::queue<uint32_t> empty;
48     swap(empty, q);
49 }
50 }
51 
HdrDecInnerCallback(std::shared_ptr<InnerSignal> signal)52 HdrDecInnerCallback::HdrDecInnerCallback(std::shared_ptr<InnerSignal> signal) : decInnersignal_(signal) {}
HdrEncInnerCallback(std::shared_ptr<InnerSignal> signal)53 HdrEncInnerCallback::HdrEncInnerCallback(std::shared_ptr<InnerSignal> signal) : encInnersignal_(signal) {}
54 
~HDRCodecInnderNdkSample()55 HDRCodecInnderNdkSample::~HDRCodecInnderNdkSample()
56 {
57     Release();
58 }
59 
OnOutputFormatChanged(const Format & format)60 void HdrDecInnerCallback::OnOutputFormatChanged(const Format& format)
61 {
62     cout << "Format Changed" << endl;
63 }
64 
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVSharedMemory> buffer)65 void HdrDecInnerCallback::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
66 {
67     if (decInnersignal_ == nullptr) {
68         cout << "buffer is null 1" << endl;
69     }
70     unique_lock<mutex> lock(decInnersignal_->inMutex_);
71     decInnersignal_->inIdxQueue_.push(index);
72     decInnersignal_->inBufferQueue_.push(buffer);
73     decInnersignal_->inCond_.notify_all();
74 }
75 
OnOutputBufferAvailable(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag,std::shared_ptr<AVSharedMemory> buffer)76 void HdrDecInnerCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag,
77     std::shared_ptr<AVSharedMemory> buffer)
78 {
79     hdr_sample->vdec_->ReleaseOutputBuffer(index, true);
80     if (flag & AVCODEC_BUFFER_FLAG_EOS) {
81         hdr_sample->venc_->NotifyEos();
82     } else {
83         hdr_sample->frameCountDec++;
84     }
85 }
86 
OnError(AVCodecErrorType errorType,int32_t errorCode)87 void HdrDecInnerCallback::OnError(AVCodecErrorType errorType, int32_t errorCode)
88 {
89     hdr_sample->errorCount++;
90     cout << "Dec Error errorCode:" << errorCode << endl;
91 }
92 
OnError(AVCodecErrorType errorType,int32_t errorCode)93 void HdrEncInnerCallback::OnError(AVCodecErrorType errorType, int32_t errorCode)
94 {
95     hdr_sample->errorCount++;
96     cout << "Enc Error errorCode:" << errorCode << endl;
97 }
98 
OnOutputFormatChanged(const Format & format)99 void HdrEncInnerCallback::OnOutputFormatChanged(const Format& format)
100 {
101     cout << "Format Changed" << endl;
102 }
103 
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVSharedMemory> buffer)104 void HdrEncInnerCallback::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
105 {
106     (void)index;
107     (void)buffer;
108 }
109 
OnOutputBufferAvailable(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag,std::shared_ptr<AVSharedMemory> buffer)110 void HdrEncInnerCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info,
111     AVCodecBufferFlag flag, std::shared_ptr<AVSharedMemory> buffer)
112 {
113     hdr_sample->venc_->ReleaseOutputBuffer(index);
114     if (flag & AVCODEC_BUFFER_FLAG_EOS) {
115         g_isRunning.store(false);
116         g_cv.notify_all();
117     } else {
118         hdr_sample->frameCountEnc++;
119     }
120 }
121 
CreateCodec()122 int32_t HDRCodecInnderNdkSample::CreateCodec()
123 {
124     if (signal_ == nullptr) {
125         signal_ = make_shared<InnerSignal>();
126     }
127     if (signal_ == nullptr) {
128         return AVCS_ERR_UNKNOWN;
129     }
130     vdec_ = VideoDecoderFactory::CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
131     if (vdec_ == nullptr) {
132         return AVCS_ERR_UNKNOWN;
133     }
134 
135     venc_ = VideoEncoderFactory::CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC);
136     if (venc_ == nullptr) {
137         return AVCS_ERR_UNKNOWN;
138     }
139     hdr_sample = this;
140     return AVCS_ERR_OK;
141 }
142 
FlushBuffer()143 void HDRCodecInnderNdkSample::FlushBuffer()
144 {
145     unique_lock<mutex> decInLock(signal_->inMutex_);
146     clearIntqueue(signal_->inIdxQueue_);
147     std::queue<std::shared_ptr<AVSharedMemory>> empty;
148     swap(empty, signal_->inBufferQueue_);
149     signal_->inCond_.notify_all();
150     inFile_->clear();
151     inFile_->seekg(0, ios::beg);
152     decInLock.unlock();
153 }
154 
RepeatCall()155 int32_t HDRCodecInnderNdkSample::RepeatCall()
156 {
157     if (REPEAT_START_FLUSH_BEFORE_EOS > 0) {
158         return RepeatCallStartFlush();
159     }
160     if (REPEAT_START_STOP_BEFORE_EOS > 0) {
161         return RepeatCallStartStop();
162     }
163     if (REPEAT_START_FLUSH_STOP_BEFORE_EOS > 0) {
164         return RepeatCallStartFlushStop();
165     }
166     return 0;
167 }
168 
InputFunc()169 void HDRCodecInnderNdkSample::InputFunc()
170 {
171     bool flag = true;
172     while (flag) {
173         if (!g_isRunning.load()) {
174             flag = false;
175             break;
176         }
177         int32_t ret = RepeatCall();
178         if (ret != 0) {
179             cout << "repeat call failed, errcode " << ret << endl;
180             errorCount++;
181             g_isRunning.store(false);
182             g_cv.notify_all();
183             flag = false;
184             break;
185         }
186         uint32_t index;
187         unique_lock<mutex> lock(signal_->inMutex_);
188         signal_->inCond_.wait(lock, [this]() {
189             if (!g_isRunning.load()) {
190                 return true;
191             }
192             return signal_->inIdxQueue_.size() > 0;
193         });
194         if (!g_isRunning.load()) {
195             flag = false;
196             break;
197         }
198         index = signal_->inIdxQueue_.front();
199         auto buffer = signal_->inBufferQueue_.front();
200 
201         signal_->inIdxQueue_.pop();
202         signal_->inBufferQueue_.pop();
203         lock.unlock();
204         if (SendData(vdec_, index, buffer) == 1)
205             break;
206     }
207 }
208 
Configure()209 int32_t HDRCodecInnderNdkSample::Configure()
210 {
211     Format format;
212     (void)format.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH);
213     (void)format.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, DEFAULT_HEIGHT);
214     (void)format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast<int32_t>(VideoPixelFormat::NV12));
215     (void)format.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, DEFAULT_FRAME_RATE);
216     int ret = vdec_->Configure(format);
217     if (ret != AVCS_ERR_OK) {
218         return ret;
219     }
220     (void)format.PutIntValue(MediaDescriptionKey::MD_KEY_PROFILE, DEFAULT_PROFILE);
221     ret = venc_->Configure(format);
222     if (ret != AVCS_ERR_OK) {
223         return ret;
224     }
225     sptr<Surface> surface = venc_->CreateInputSurface();
226     if (surface == nullptr) {
227         cout << "CreateInputSurface is fail" << endl;
228         return AVCS_ERR_UNKNOWN;
229     }
230     window = CreateNativeWindowFromSurface(&surface);
231     if (window == nullptr) {
232         cout << "CreateNativeWindowFromSurface is fail" << endl;
233         return AVCS_ERR_UNKNOWN;
234     }
235     ret = vdec_->SetOutputSurface(window->surface);
236     if (ret != AVCS_ERR_OK) {
237         return ret;
238     }
239 
240     ret = EncSetCallback();
241     if (ret != AVCS_ERR_OK) {
242         return ret;
243     }
244     return DecSetCallback();
245 }
246 
DecSetCallback()247 int32_t HDRCodecInnderNdkSample::DecSetCallback()
248 {
249     if (signal_ == nullptr) {
250         cout << "Failed to new HdrInnerSignal" << endl;
251         return AVCS_ERR_UNKNOWN;
252     }
253     decCb_ = make_shared<HdrDecInnerCallback>(signal_);
254     return vdec_->SetCallback(decCb_);
255 }
256 
EncSetCallback()257 int32_t HDRCodecInnderNdkSample::EncSetCallback()
258 {
259     if (signal_ == nullptr) {
260         cout << "Failed to new HdrInnerSignal" << endl;
261         return AVCS_ERR_UNKNOWN;
262     }
263     encCb_ = make_shared<HdrEncInnerCallback>(signal_);
264     return venc_->SetCallback(encCb_);
265 }
266 
ReConfigure()267 int32_t HDRCodecInnderNdkSample::ReConfigure()
268 {
269     int32_t ret = vdec_->Reset();
270     if (ret != AVCS_ERR_OK) {
271         return ret;
272     }
273     ret = venc_->Reset();
274     if (ret != AVCS_ERR_OK) {
275         return ret;
276     }
277     FlushBuffer();
278     Format format;
279 
280     format.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH);
281     format.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, DEFAULT_HEIGHT);
282     format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast<int32_t>(VideoPixelFormat::NV12));
283     format.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, DEFAULT_FRAME_RATE);
284     ret = vdec_->Configure(format);
285     if (ret != AVCS_ERR_OK) {
286         return ret;
287     }
288     format.PutIntValue(MediaDescriptionKey::MD_KEY_PROFILE, DEFAULT_PROFILE);
289     ret = venc_->Configure(format);
290     if (ret != AVCS_ERR_OK) {
291         return ret;
292     }
293     ret = vdec_->SetOutputSurface(window->surface);
294     if (ret != AVCS_ERR_OK) {
295         return ret;
296     }
297     return ret;
298 }
299 
Start()300 int32_t HDRCodecInnderNdkSample::Start()
301 {
302     int32_t ret = 0;
303     inFile_ = make_unique<ifstream>();
304     inFile_->open(INP_DIR, ios::in | ios::binary);
305     if (!inFile_->is_open()) {
306         (void)vdec_->Release();
307         (void)venc_->Release();
308         inFile_->close();
309         inFile_.reset();
310         inFile_ = nullptr;
311         return AVCS_ERR_UNKNOWN;
312     }
313     g_isRunning.store(true);
314     ret = venc_->Start();
315     if (ret != AVCS_ERR_OK) {
316         return ret;
317     }
318     ret = vdec_->Start();
319     if (ret != AVCS_ERR_OK) {
320         return ret;
321     }
322     inputLoop_ = make_unique<thread>(&HDRCodecInnderNdkSample::InputFunc, this);
323     if (inputLoop_ == nullptr) {
324         g_isRunning.store(false);
325         (void)vdec_->Stop();
326         ReleaseInFile();
327         return AVCS_ERR_UNKNOWN;
328     }
329 
330     return 0;
331 }
332 
StopInloop()333 void HDRCodecInnderNdkSample::StopInloop()
334 {
335     if (inputLoop_ != nullptr && inputLoop_->joinable()) {
336         unique_lock<mutex> lock(signal_->inMutex_);
337         clearIntqueue(signal_->inIdxQueue_);
338         g_isRunning.store(false);
339         signal_->inCond_.notify_all();
340         lock.unlock();
341         inputLoop_->join();
342         inputLoop_.reset();
343     }
344 }
345 
ReleaseInFile()346 void HDRCodecInnderNdkSample::ReleaseInFile()
347 {
348     if (inFile_ != nullptr) {
349         if (inFile_->is_open()) {
350             inFile_->close();
351         }
352         inFile_.reset();
353         inFile_ = nullptr;
354     }
355 }
356 
WaitForEos()357 void HDRCodecInnderNdkSample::WaitForEos()
358 {
359     std::mutex mtx;
360     unique_lock<mutex> lock(mtx);
361     g_cv.wait(lock, []() {
362         return !(g_isRunning.load());
363     });
364     inputLoop_->join();
365     vdec_->Stop();
366     venc_->Stop();
367 }
368 
SendData(std::shared_ptr<AVCodecVideoDecoder> codec,uint32_t index,std::shared_ptr<AVSharedMemory> buffer)369 int32_t HDRCodecInnderNdkSample::SendData(std::shared_ptr<AVCodecVideoDecoder> codec,
370     uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
371 {
372     uint32_t bufferSize = 0;
373     int32_t result = 0;
374     AVCodecBufferInfo info;
375     AVCodecBufferFlag flag;
376     static bool isFirstFrame = true;
377     (void)inFile_->read(reinterpret_cast<char *>(&bufferSize), sizeof(uint32_t));
378     if (inFile_->eof()) {
379         flag = AVCODEC_BUFFER_FLAG_EOS;
380         info.offset = 0;
381         codec->QueueInputBuffer(index, info, flag);
382         return 1;
383     }
384     if (isFirstFrame) {
385         flag = AVCODEC_BUFFER_FLAG_CODEC_DATA;
386         isFirstFrame = false;
387     } else {
388         flag = AVCODEC_BUFFER_FLAG_NONE;
389     }
390     int32_t size = buffer->GetSize();
391     uint8_t *avBuffer = buffer->GetBase();
392     if (avBuffer == nullptr) {
393         return 0;
394     }
395     uint8_t *fileBuffer = new uint8_t[bufferSize];
396     if (fileBuffer == nullptr) {
397         cout << "Fatal: no memory" << endl;
398         delete[] fileBuffer;
399         return 0;
400     }
401     (void)inFile_->read(reinterpret_cast<char *>(fileBuffer), bufferSize);
402     if (memcpy_s(avBuffer, size, fileBuffer, bufferSize) != EOK) {
403         delete[] fileBuffer;
404         cout << "Fatal: memcpy fail" << endl;
405         return 0;
406     }
407     delete[] fileBuffer;
408     info.presentationTimeUs = GetSystemTimeUs();
409     info.size = bufferSize;
410     info.offset = 0;
411     result = codec->QueueInputBuffer(index, info, flag);
412     if (result != AVCS_ERR_OK) {
413         cout << "push input data failed,error:" << result << endl;
414     }
415     return 0;
416 }
417 
RepeatCallStartFlush()418 int32_t HDRCodecInnderNdkSample::RepeatCallStartFlush()
419 {
420     int32_t ret = 0;
421     REPEAT_START_FLUSH_BEFORE_EOS--;
422     ret = venc_->Flush();
423     if (ret != AVCS_ERR_OK) {
424         return ret;
425     }
426     ret = vdec_->Flush();
427     if (ret != AVCS_ERR_OK) {
428         return ret;
429     }
430     FlushBuffer();
431     ret = venc_->Start();
432     if (ret != AVCS_ERR_OK) {
433         return ret;
434     }
435     ret = vdec_->Start();
436     if (ret != AVCS_ERR_OK) {
437         return ret;
438     }
439     return 0;
440 }
441 
RepeatCallStartStop()442 int32_t HDRCodecInnderNdkSample::RepeatCallStartStop()
443 {
444     int32_t ret = 0;
445     REPEAT_START_STOP_BEFORE_EOS--;
446     ret = vdec_->Stop();
447     if (ret != AVCS_ERR_OK) {
448         return ret;
449     }
450     ret = venc_->Stop();
451     if (ret != AVCS_ERR_OK) {
452         return ret;
453     }
454     FlushBuffer();
455     ret = venc_->Start();
456     if (ret != AVCS_ERR_OK) {
457         return ret;
458     }
459     ret = vdec_->Start();
460     if (ret != AVCS_ERR_OK) {
461         return ret;
462     }
463     return 0;
464 }
465 
RepeatCallStartFlushStop()466 int32_t HDRCodecInnderNdkSample::RepeatCallStartFlushStop()
467 {
468     int32_t ret = 0;
469     REPEAT_START_FLUSH_STOP_BEFORE_EOS--;
470     ret = venc_->Flush();
471     if (ret != AVCS_ERR_OK) {
472         return ret;
473     }
474     ret = vdec_->Flush();
475     if (ret != AVCS_ERR_OK) {
476         return ret;
477     }
478     ret = vdec_->Stop();
479     if (ret != AVCS_ERR_OK) {
480         return ret;
481     }
482     ret = venc_->Stop();
483     if (ret != AVCS_ERR_OK) {
484         return ret;
485     }
486     FlushBuffer();
487     ret = venc_->Start();
488     if (ret != AVCS_ERR_OK) {
489         return ret;
490     }
491     ret = vdec_->Start();
492     if (ret != AVCS_ERR_OK) {
493         return ret;
494     }
495     return 0;
496 }
497 
Release()498 void HDRCodecInnderNdkSample::Release()
499 {
500     if (vdec_ != nullptr) {
501         vdec_->Release();
502         vdec_ = nullptr;
503     }
504     if (venc_ != nullptr) {
505         venc_->Release();
506         venc_ = nullptr;
507     }
508     if (signal_ != nullptr) {
509         signal_ = nullptr;
510     }
511     if (hdr_sample != nullptr) {
512         hdr_sample = nullptr;
513     }
514     if (window != nullptr) {
515         OH_NativeWindow_DestroyNativeWindow(window);
516         window = nullptr;
517     }
518 }