1 /*
2 * Copyright (C) 2021 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 "avcodec_vdec_demo.h"
17 #include <iostream>
18 #include <unistd.h>
19 #include "securec.h"
20 #include "demo_log.h"
21 #include "media_errors.h"
22 #include "ui/rs_surface_node.h"
23 #include "window.h"
24 #include "window_option.h"
25
26 using namespace OHOS;
27 using namespace OHOS::Media;
28 using namespace std;
29 namespace {
30 constexpr uint32_t DEFAULT_WIDTH = 480;
31 constexpr uint32_t DEFAULT_HEIGHT = 360;
32 constexpr uint32_t DEFAULT_FRAME_RATE = 30;
33 constexpr uint32_t MAX_INPUT_BUFFER_SIZE = 30000;
34 constexpr uint32_t FRAME_DURATION_US = 33000;
35 constexpr uint32_t DEFAULT_FRAME_COUNT = 1;
36 }
37
RunCase()38 void VDecDemo::RunCase()
39 {
40 DEMO_CHECK_AND_RETURN_LOG(CreateVdec() == MSERR_OK, "Fatal: CreateVdec fail");
41
42 Format format;
43 format.PutIntValue("width", DEFAULT_WIDTH);
44 format.PutIntValue("height", DEFAULT_HEIGHT);
45 format.PutIntValue("pixel_format", NV21);
46 format.PutIntValue("frame_rate", DEFAULT_FRAME_RATE);
47 format.PutIntValue("max_input_size", MAX_INPUT_BUFFER_SIZE);
48 DEMO_CHECK_AND_RETURN_LOG(Configure(format) == MSERR_OK, "Fatal: Configure fail");
49
50 DEMO_CHECK_AND_RETURN_LOG(SetSurface() == MSERR_OK, "Fatal: SetSurface fail");
51 DEMO_CHECK_AND_RETURN_LOG(Prepare() == MSERR_OK, "Fatal: Prepare fail");
52 DEMO_CHECK_AND_RETURN_LOG(Start() == MSERR_OK, "Fatal: Start fail");
53 sleep(3); // start run 3s
54 DEMO_CHECK_AND_RETURN_LOG(Stop() == MSERR_OK, "Fatal: Stop fail");
55 DEMO_CHECK_AND_RETURN_LOG(Release() == MSERR_OK, "Fatal: Release fail");
56 }
57
CreateVdec()58 int32_t VDecDemo::CreateVdec()
59 {
60 vdec_ = VideoDecoderFactory::CreateByMime("video/avc");
61 DEMO_CHECK_AND_RETURN_RET_LOG(vdec_ != nullptr, MSERR_UNKNOWN, "Fatal: CreateByMime fail");
62
63 signal_ = make_shared<VDecSignal>();
64 DEMO_CHECK_AND_RETURN_RET_LOG(signal_ != nullptr, MSERR_UNKNOWN, "Fatal: No memory");
65
66 cb_ = make_unique<VDecDemoCallback>(signal_);
67 DEMO_CHECK_AND_RETURN_RET_LOG(cb_ != nullptr, MSERR_UNKNOWN, "Fatal: No memory");
68 DEMO_CHECK_AND_RETURN_RET_LOG(vdec_->SetCallback(cb_) == MSERR_OK, MSERR_UNKNOWN, "Fatal: SetCallback fail");
69
70 return MSERR_OK;
71 }
72
Configure(const Format & format)73 int32_t VDecDemo::Configure(const Format &format)
74 {
75 return vdec_->Configure(format);
76 }
77
Prepare()78 int32_t VDecDemo::Prepare()
79 {
80 return vdec_->Prepare();
81 }
82
Start()83 int32_t VDecDemo::Start()
84 {
85 isRunning_.store(true);
86
87 testFile_ = std::make_unique<std::ifstream>();
88 DEMO_CHECK_AND_RETURN_RET_LOG(testFile_ != nullptr, MSERR_UNKNOWN, "Fatal: No memory");
89 testFile_->open("/data/media/video.es", std::ios::in | std::ios::binary);
90
91 inputLoop_ = make_unique<thread>(&VDecDemo::InputFunc, this);
92 DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, MSERR_UNKNOWN, "Fatal: No memory");
93
94 outputLoop_ = make_unique<thread>(&VDecDemo::OutputFunc, this);
95 DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, MSERR_UNKNOWN, "Fatal: No memory");
96
97 return vdec_->Start();
98 }
99
Stop()100 int32_t VDecDemo::Stop()
101 {
102 isRunning_.store(false);
103
104 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
105 unique_lock<mutex> lock(signal_->inMutex_);
106 signal_->inQueue_.push(0);
107 signal_->inCond_.notify_all();
108 lock.unlock();
109 inputLoop_->join();
110 inputLoop_.reset();
111 }
112
113 if (outputLoop_ != nullptr && outputLoop_->joinable()) {
114 unique_lock<mutex> lock(signal_->outMutex_);
115 signal_->outQueue_.push(0);
116 signal_->outCond_.notify_all();
117 lock.unlock();
118 outputLoop_->join();
119 outputLoop_.reset();
120 }
121
122 return vdec_->Stop();
123 }
124
Flush()125 int32_t VDecDemo::Flush()
126 {
127 return vdec_->Flush();
128 }
129
Reset()130 int32_t VDecDemo::Reset()
131 {
132 return vdec_->Reset();
133 }
134
Release()135 int32_t VDecDemo::Release()
136 {
137 return vdec_->Release();
138 }
139
SetSurface()140 int32_t VDecDemo::SetSurface()
141 {
142 sptr<Rosen::WindowOption> option = new Rosen::WindowOption();
143 option->SetWindowRect({0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT});
144 option->SetWindowType(Rosen::WindowType::WINDOW_TYPE_APP_LAUNCHING);
145 option->SetWindowMode(Rosen::WindowMode::WINDOW_MODE_FLOATING);
146 sptr<Rosen::Window> window = Rosen::Window::Create("avcodec video decoder window", option);
147 DEMO_CHECK_AND_RETURN_RET_LOG(window != nullptr && window->GetSurfaceNode() != nullptr, MSERR_UNKNOWN, "Fatal");
148
149 sptr<Surface> surface = window->GetSurfaceNode()->GetSurface();
150 window->Show();
151 DEMO_CHECK_AND_RETURN_RET_LOG(surface != nullptr, MSERR_UNKNOWN, "Fatal: get surface fail");
152 return vdec_->SetOutputSurface(surface);
153 }
154
InputFunc()155 void VDecDemo::InputFunc()
156 {
157 while (true) {
158 if (!isRunning_.load()) {
159 break;
160 }
161
162 unique_lock<mutex> lock(signal_->inMutex_);
163 signal_->inCond_.wait(lock, [this](){ return signal_->inQueue_.size() > 0; });
164
165 if (!isRunning_.load()) {
166 break;
167 }
168
169 uint32_t index = signal_->inQueue_.front();
170 auto buffer = vdec_->GetInputBuffer(index);
171 DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail");
172 DEMO_CHECK_AND_BREAK_LOG(testFile_ != nullptr && testFile_->is_open(), "Fatal: open file fail");
173
174 constexpr uint32_t bufferSize = 0; // replace with the actual size
175 char *fileBuffer = static_cast<char *>(malloc(sizeof(char) * bufferSize + 1));
176 DEMO_CHECK_AND_BREAK_LOG(fileBuffer != nullptr, "Fatal: malloc fail");
177
178 (void)testFile_->read(fileBuffer, bufferSize);
179 if (memcpy_s(buffer->GetBase(), buffer->GetSize(), fileBuffer, bufferSize) != EOK) {
180 free(fileBuffer);
181 cout << "Fatal: memcpy fail" << endl;
182 break;
183 }
184
185 AVCodecBufferInfo info;
186 info.size = bufferSize;
187 info.offset = 0;
188 info.presentationTimeUs = timeStamp_;
189
190 int32_t ret = MSERR_OK;
191 if (isFirstFrame_) {
192 ret = vdec_->QueueInputBuffer(index, info, AVCODEC_BUFFER_FLAG_CODEC_DATA);
193 isFirstFrame_ = false;
194 } else {
195 ret = vdec_->QueueInputBuffer(index, info, AVCODEC_BUFFER_FLAG_NONE);
196 }
197
198 free(fileBuffer);
199 timeStamp_ += FRAME_DURATION_US;
200 signal_->inQueue_.pop();
201
202 frameCount_++;
203 if (frameCount_ == DEFAULT_FRAME_COUNT) {
204 cout << "Finish decode, exit" << endl;
205 break;
206 }
207
208 if (ret != MSERR_OK) {
209 cout << "Fatal error, exit" << endl;
210 break;
211 }
212 }
213 }
214
OutputFunc()215 void VDecDemo::OutputFunc()
216 {
217 while (true) {
218 if (!isRunning_.load()) {
219 break;
220 }
221
222 unique_lock<mutex> lock(signal_->outMutex_);
223 signal_->outCond_.wait(lock, [this](){ return signal_->outQueue_.size() > 0; });
224
225 if (!isRunning_.load()) {
226 break;
227 }
228
229 uint32_t index = signal_->outQueue_.front();
230 if (vdec_->ReleaseOutputBuffer(index, true) != MSERR_OK) {
231 cout << "Fatal: ReleaseOutputBuffer fail" << endl;
232 break;
233 }
234
235 signal_->outQueue_.pop();
236 }
237 }
238
VDecDemoCallback(shared_ptr<VDecSignal> signal)239 VDecDemoCallback::VDecDemoCallback(shared_ptr<VDecSignal> signal)
240 : signal_(signal)
241 {
242 }
243
OnError(AVCodecErrorType errorType,int32_t errorCode)244 void VDecDemoCallback::OnError(AVCodecErrorType errorType, int32_t errorCode)
245 {
246 cout << "Error received, errorType:" << errorType << " errorCode:" << errorCode << endl;
247 }
248
OnOutputFormatChanged(const Format & format)249 void VDecDemoCallback::OnOutputFormatChanged(const Format &format)
250 {
251 cout << "OnOutputFormatChanged received" << endl;
252 }
253
OnInputBufferAvailable(uint32_t index)254 void VDecDemoCallback::OnInputBufferAvailable(uint32_t index)
255 {
256 cout << "OnInputBufferAvailable received, index:" << index << endl;
257 unique_lock<mutex> lock(signal_->inMutex_);
258 signal_->inQueue_.push(index);
259 signal_->inCond_.notify_all();
260 }
261
OnOutputBufferAvailable(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag)262 void VDecDemoCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag)
263 {
264 cout << "OnOutputBufferAvailable received, index:" << index << endl;
265 unique_lock<mutex> lock(signal_->outMutex_);
266 signal_->outQueue_.push(index);
267 signal_->outCond_.notify_all();
268 }