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 }