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