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
16 #include <iostream>
17 #include <string>
18 #include <unistd.h>
19 #include "iconsumer_surface.h"
20 #include "securec.h"
21
22 #include "ui/rs_surface_node.h"
23 #include "window_option.h"
24 #include "wm/window.h"
25
26 #include "av_common.h"
27 #include "avcodec_codec_name.h"
28 #include "avcodec_common.h"
29 #include "avcodec_errors.h"
30 #include "demo_log.h"
31 #include "media_description.h"
32 #include "native_avcodec_base.h"
33 #include "native_avformat.h"
34 #include "avcodec_video_decoder_demo.h"
35
36 using namespace OHOS;
37 using namespace OHOS::MediaAVCodec;
38 using namespace OHOS::MediaAVCodec::VideoDemo;
39 using namespace std;
40 namespace {
41 constexpr uint32_t DEFAULT_WIDTH = 320;
42 constexpr uint32_t DEFAULT_HEIGHT = 240;
43 constexpr uint32_t FRAME_DURATION_US = 33000;
44
45 constexpr string_view inputFilePath = "/data/test/media/out_320_240_10s.h264";
46 constexpr string_view outputFilePath = "/data/test/media/out_320_240_10s.yuv";
47 constexpr string_view outputSurfacePath = "/data/test/media/out_320_240_10s.rgba";
48 constexpr uint32_t SLEEP_TIME = 1;
49 uint32_t outFrameCount = 0;
50 } // namespace
51
OnError(OH_AVCodec * codec,int32_t errorCode,void * userData)52 static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData)
53 {
54 (void)codec;
55 (void)errorCode;
56 (void)userData;
57 cout << "Error received, errorCode:" << errorCode << endl;
58 }
59
OnOutputFormatChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)60 static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
61 {
62 (void)codec;
63 (void)format;
64 (void)userData;
65 cout << "OnOutputFormatChanged received" << endl;
66 }
67
OnInputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,void * userData)68 static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
69 {
70 (void)codec;
71 VDecSignal *signal_ = static_cast<VDecSignal *>(userData);
72 cout << "OnInputBufferAvailable received, index:" << index << endl;
73 unique_lock<mutex> lock(signal_->inMutex_);
74 signal_->inQueue_.push(index);
75 signal_->inBufferQueue_.push(data);
76 signal_->inCond_.notify_all();
77 }
78
OnOutputBufferAvailable(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)79 static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
80 void *userData)
81 {
82 (void)codec;
83 VDecSignal *signal_ = static_cast<VDecSignal *>(userData);
84 if (attr) {
85 cout << "OnOutputBufferAvailable received, index:" << index << ", attr->size:" << attr->size << endl;
86 unique_lock<mutex> lock(signal_->outMutex_);
87 signal_->outQueue_.push(index);
88 signal_->outBufferQueue_.push(data);
89 signal_->attrQueue_.push(*attr);
90 outFrameCount += attr->size > 0 ? 1 : 0;
91 signal_->outCond_.notify_all();
92 } else {
93 cout << "OnOutputBufferAvailable error, attr is nullptr!" << endl;
94 }
95 }
96
RunCase(std::string & mode)97 void VDecDemo::RunCase(std::string &mode)
98 {
99 mode_ = mode;
100 DEMO_CHECK_AND_RETURN_LOG(CreateDec() == AVCS_ERR_OK, "Fatal: CreateDec fail");
101
102 OH_AVFormat *format = OH_AVFormat_Create();
103 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_WIDTH.data(), DEFAULT_WIDTH);
104 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_HEIGHT.data(), DEFAULT_HEIGHT);
105 OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_PIXEL_FORMAT.data(),
106 static_cast<int32_t>(VideoPixelFormat::YUV420P));
107 DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail");
108
109 if (mode_ != "0") {
110 sptr<Surface> ps = GetSurface(mode_);
111 OHNativeWindow *nativeWindow = CreateNativeWindowFromSurface(&ps);
112 DEMO_CHECK_AND_RETURN_LOG(SetSurface(nativeWindow) == AVCS_ERR_OK, "Fatal: SetSurface fail");
113 }
114
115 DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail");
116
117 while (isRunning_.load()) {
118 sleep(SLEEP_TIME); // sleep 1s
119 }
120
121 DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail");
122 std::cout << "end stop!" << std::endl;
123 DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail");
124 }
125
VDecDemo()126 VDecDemo::VDecDemo()
127 {
128 codec_ = avcodec_find_decoder(AV_CODEC_ID_H264);
129 if (codec_ == nullptr) {
130 std::cout << "find h264 fail" << std::endl;
131 exit(1);
132 }
133
134 parser_ = av_parser_init(codec_->id);
135 if (parser_ == nullptr) {
136 std::cout << "parser init fail" << std::endl;
137 exit(1);
138 }
139
140 codec_ctx_ = avcodec_alloc_context3(codec_);
141 if (codec_ctx_ == nullptr) {
142 std::cout << "alloc context fail" << std::endl;
143 exit(1);
144 }
145
146 if (avcodec_open2(codec_ctx_, codec_, NULL) < 0) {
147 std::cout << "codec open fail" << std::endl;
148 exit(1);
149 }
150
151 pkt_ = av_packet_alloc();
152 if (pkt_ == nullptr) {
153 std::cout << "alloc pkt fail" << std::endl;
154 exit(1);
155 }
156 pkt_->data = NULL;
157 pkt_->size = 0;
158 }
159
~VDecDemo()160 VDecDemo::~VDecDemo()
161 {
162 if (signal_) {
163 delete signal_;
164 signal_ = nullptr;
165 }
166
167 avcodec_free_context(&codec_ctx_);
168 av_parser_close(parser_);
169 av_packet_free(&pkt_);
170
171 if (inputFile_ != nullptr) {
172 inputFile_->close();
173 }
174
175 if (outFile_ != nullptr) {
176 outFile_->close();
177 }
178 }
179
GetSurface(std::string & mode)180 sptr<Surface> VDecDemo::GetSurface(std::string &mode)
181 {
182 sptr<Surface> ps = nullptr;
183 if (mode == "1") {
184 sptr<Surface> cs = Surface::CreateSurfaceAsConsumer();
185 sptr<IBufferConsumerListener> listener = new InnerVideoDemo::TestConsumerListener(cs, outputSurfacePath);
186 cs->RegisterConsumerListener(listener);
187 auto p = cs->GetProducer();
188 ps = Surface::CreateSurfaceAsProducer(p);
189 } else if (mode == "2") {
190 sptr<Rosen::Window> window = nullptr;
191 sptr<Rosen::WindowOption> option = new Rosen::WindowOption();
192 option->SetWindowRect({0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT});
193 option->SetWindowType(Rosen::WindowType::WINDOW_TYPE_FLOAT);
194 option->SetWindowMode(Rosen::WindowMode::WINDOW_MODE_FLOATING);
195 window = Rosen::Window::Create("avcodec_unittest", option);
196 DEMO_CHECK_AND_RETURN_RET_LOG(window != nullptr && window->GetSurfaceNode() != nullptr, nullptr,
197 "Fatal: Create window fail");
198 window->Show();
199 ps = window->GetSurfaceNode()->GetSurface();
200 }
201
202 return ps;
203 }
204
CreateDec()205 int32_t VDecDemo::CreateDec()
206 {
207 videoDec_ = OH_VideoDecoder_CreateByName(AVCodecCodecName::VIDEO_DECODER_AVC_NAME.data());
208 DEMO_CHECK_AND_RETURN_RET_LOG(videoDec_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail");
209
210 signal_ = new VDecSignal();
211 DEMO_CHECK_AND_RETURN_RET_LOG(signal_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
212
213 cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable};
214 int32_t ret = OH_VideoDecoder_SetCallback(videoDec_, cb_, signal_);
215 DEMO_CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, "Fatal: SetCallback fail");
216
217 return AVCS_ERR_OK;
218 }
219
Configure(OH_AVFormat * format)220 int32_t VDecDemo::Configure(OH_AVFormat *format)
221 {
222 return OH_VideoDecoder_Configure(videoDec_, format);
223 }
224
SetSurface(OHNativeWindow * window)225 int32_t VDecDemo::SetSurface(OHNativeWindow *window)
226 {
227 return OH_VideoDecoder_SetSurface(videoDec_, window);
228 }
229
Start()230 int32_t VDecDemo::Start()
231 {
232 inputFile_ = std::make_unique<std::ifstream>();
233 DEMO_CHECK_AND_RETURN_RET_LOG(inputFile_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
234 inputFile_->open(inputFilePath.data(), std::ios::in | std::ios::binary);
235
236 if (mode_ == "0") {
237 outFile_ = std::make_unique<std::ofstream>();
238 DEMO_CHECK_AND_RETURN_RET_LOG(outFile_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
239 outFile_->open(outputFilePath.data(), std::ios::out | std::ios::binary);
240 }
241
242 isRunning_.store(true);
243
244 inputLoop_ = make_unique<thread>(&VDecDemo::InputFunc, this);
245 DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
246
247 outputLoop_ = make_unique<thread>(&VDecDemo::OutputFunc, this);
248 DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory");
249
250 return OH_VideoDecoder_Start(videoDec_);
251 }
252
Stop()253 int32_t VDecDemo::Stop()
254 {
255 isRunning_.store(false);
256 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
257 unique_lock<mutex> lock(signal_->inMutex_);
258 signal_->inCond_.notify_all();
259 lock.unlock();
260 inputLoop_->join();
261 }
262
263 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
264 unique_lock<mutex> lock(signal_->outMutex_);
265 signal_->outCond_.notify_all();
266 lock.unlock();
267 outputLoop_->join();
268 }
269 std::cout << "start stop!" << std::endl;
270 return OH_VideoDecoder_Stop(videoDec_);
271 }
272
Flush()273 int32_t VDecDemo::Flush()
274 {
275 return OH_VideoDecoder_Flush(videoDec_);
276 }
277
Reset()278 int32_t VDecDemo::Reset()
279 {
280 return OH_VideoDecoder_Reset(videoDec_);
281 }
282
Release()283 int32_t VDecDemo::Release()
284 {
285 return OH_VideoDecoder_Destroy(videoDec_);
286 }
287
ExtractPacket()288 int32_t VDecDemo::ExtractPacket()
289 {
290 int32_t len = 0;
291 int32_t ret = 0;
292
293 if (data_ == nullptr) {
294 data_ = inbuf_;
295 (void)inputFile_->read(reinterpret_cast<char *>(inbuf_), VIDEO_INBUF_SIZE);
296 data_size_ = inputFile_->gcount();
297 }
298
299 if ((data_size_ < VIDEO_REFILL_THRESH) && !file_end_) {
300 memmove_s(inbuf_, data_size_, data_, data_size_);
301 data_ = inbuf_;
302 (void)inputFile_->read(reinterpret_cast<char *>(data_ + data_size_), VIDEO_INBUF_SIZE - data_size_);
303 len = inputFile_->gcount();
304 if (len > 0) {
305 data_size_ += len;
306 } else if (len == 0 && data_size_ == 0) {
307 file_end_ = true;
308 cout << "extract file end" << endl;
309 }
310 }
311
312 if (data_size_ > 0) {
313 ret = av_parser_parse2(parser_, codec_ctx_, &pkt_->data, &pkt_->size, data_, data_size_, AV_NOPTS_VALUE,
314 AV_NOPTS_VALUE, 0);
315 if (ret < 0) {
316 cout << "av_parser_parser2 Error!" << endl;
317 }
318 data_ += ret;
319 data_size_ -= ret;
320 if (pkt_->size) {
321 return AVCS_ERR_OK;
322 } else {
323 return AVCS_ERR_UNKNOWN;
324 }
325 }
326 return AVCS_ERR_UNKNOWN;
327 }
328
InputFunc()329 void VDecDemo::InputFunc()
330 {
331 while (true) {
332 if (!isRunning_.load()) {
333 break;
334 }
335
336 unique_lock<mutex> lock(signal_->inMutex_);
337 signal_->inCond_.wait(lock, [this]() { return (signal_->inQueue_.size() > 0 || !isRunning_.load()); });
338
339 if (!isRunning_.load()) {
340 break;
341 }
342
343 uint32_t index = signal_->inQueue_.front();
344 auto buffer = signal_->inBufferQueue_.front();
345 lock.unlock();
346 if (!file_end_ && (ExtractPacket() != AVCS_ERR_OK || pkt_->size == 0)) {
347 continue;
348 }
349
350 OH_AVCodecBufferAttr info;
351 if (file_end_) {
352 info.size = 0;
353 info.offset = 0;
354 info.pts = 0;
355 info.flags = AVCODEC_BUFFER_FLAGS_EOS;
356 OH_VideoDecoder_PushInputData(videoDec_, index, info);
357 cout << "push end" << endl;
358 break;
359 }
360
361 info.size = pkt_->size;
362 info.offset = 0;
363 info.pts = pkt_->pts;
364 DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
365 memcpy_s(OH_AVMemory_GetAddr(buffer), pkt_->size, pkt_->data, pkt_->size);
366
367 int32_t ret = AVCS_ERR_OK;
368 if (isFirstFrame_) {
369 info.flags = AVCODEC_BUFFER_FLAGS_SYNC_FRAME;
370 ret = OH_VideoDecoder_PushInputData(videoDec_, index, info);
371 isFirstFrame_ = false;
372 } else {
373 info.flags = AVCODEC_BUFFER_FLAGS_NONE;
374 ret = OH_VideoDecoder_PushInputData(videoDec_, index, info);
375 }
376
377 if (ret != AVCS_ERR_OK) {
378 cout << "Fatal error, exit" << endl;
379 break;
380 }
381
382 timeStamp_ += FRAME_DURATION_US;
383 lock.lock();
384 signal_->inQueue_.pop();
385 signal_->inBufferQueue_.pop();
386 }
387 }
388
OutputFunc()389 void VDecDemo::OutputFunc()
390 {
391 while (true) {
392 if (!isRunning_.load()) {
393 cout << "stop, exit" << endl;
394 break;
395 }
396
397 unique_lock<mutex> lock(signal_->outMutex_);
398 signal_->outCond_.wait(lock, [this]() { return (signal_->outQueue_.size() > 0 || !isRunning_.load()); });
399
400 if (!isRunning_.load()) {
401 cout << "wait to stop, exit" << endl;
402 break;
403 }
404
405 uint32_t index = signal_->outQueue_.front();
406 OH_AVCodecBufferAttr attr = signal_->attrQueue_.front();
407 OH_AVMemory *data = signal_->outBufferQueue_.front();
408 lock.unlock();
409 if (outFile_ != nullptr && attr.size != 0 && data != nullptr && OH_AVMemory_GetAddr(data) != nullptr) {
410 cout << "OutputFunc write file,buffer index" << index << ", data size = :" << attr.size << endl;
411 outFile_->write(reinterpret_cast<char *>(OH_AVMemory_GetAddr(data)), attr.size);
412 }
413
414 if (attr.flags == AVCODEC_BUFFER_FLAGS_EOS) {
415 cout << "decode eos, write frame:" << outFrameCount << endl;
416 isRunning_.store(false);
417 }
418
419 if (mode_ == "0" && OH_VideoDecoder_FreeOutputData(videoDec_, index) != AV_ERR_OK) {
420 cout << "Fatal: FreeOutputData fail" << endl;
421 break;
422 }
423
424 if (mode_ != "0" && OH_VideoDecoder_RenderOutputData(videoDec_, index) != AV_ERR_OK) {
425 cout << "Fatal: RenderOutputData fail" << endl;
426 break;
427 }
428
429 lock.lock();
430 signal_->outBufferQueue_.pop();
431 signal_->attrQueue_.pop();
432 signal_->outQueue_.pop();
433 }
434 }