1 /*
2 * Copyright (c) 2021-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 #if defined(RECORDER_SUPPORT) && defined(VIDEO_SUPPORT)
17
18 #define HST_LOG_TAG "VideoCaptureFilter"
19
20 #include "pipeline/filters/source/video_capture/video_capture_filter.h"
21 #include "foundation/log.h"
22 #include "pipeline/factory/filter_factory.h"
23 #include "pipeline/filters/common/plugin_utils.h"
24 #include "plugin/common/plugin_attr_desc.h"
25
26 namespace OHOS {
27 namespace Media {
28 namespace Pipeline {
29 using namespace Plugin;
30
31 static AutoRegisterFilter<VideoCaptureFilter> g_registerFilterHelper("builtin.recorder.videocapture");
32
VideoCaptureFilter(const std::string & name)33 VideoCaptureFilter::VideoCaptureFilter(const std::string& name)
34 : FilterBase(name),
35 taskPtr_(nullptr),
36 plugin_(nullptr),
37 pluginAllocator_(nullptr),
38 pluginInfo_(nullptr)
39 {
40 filterType_ = FilterType::CAPTURE_SOURCE;
41 MEDIA_LOG_D("ctor called");
42 }
43
~VideoCaptureFilter()44 VideoCaptureFilter::~VideoCaptureFilter()
45 {
46 MEDIA_LOG_D("dtor called");
47 if (taskPtr_) {
48 taskPtr_->Stop();
49 }
50 if (plugin_) {
51 plugin_->Deinit();
52 }
53 }
54
GetWorkModes()55 std::vector<WorkMode> VideoCaptureFilter::GetWorkModes()
56 {
57 return {WorkMode::PUSH};
58 }
59
InitAndConfigPlugin(const std::shared_ptr<Plugin::Meta> & videoMeta)60 ErrorCode VideoCaptureFilter::InitAndConfigPlugin(const std::shared_ptr<Plugin::Meta>& videoMeta)
61 {
62 MEDIA_LOG_D("IN");
63 ErrorCode err = TranslatePluginStatus(plugin_->Init());
64 if (err != ErrorCode::SUCCESS) {
65 return err;
66 }
67 plugin_->SetCallback(this);
68 pluginAllocator_ = plugin_->GetAllocator();
69 err = TranslatePluginStatus(plugin_->SetParameter(Tag::VIDEO_WIDTH, videoWidth_));
70 if (err != ErrorCode::SUCCESS) {
71 return err;
72 }
73 err = TranslatePluginStatus(plugin_->SetParameter(Tag::VIDEO_HEIGHT, videoHeight_));
74 if (err != ErrorCode::SUCCESS) {
75 return err;
76 }
77 err = TranslatePluginStatus(plugin_->SetParameter(Tag::VIDEO_CAPTURE_RATE, captureRate_));
78 if (err != ErrorCode::SUCCESS) {
79 return err;
80 }
81 err = TranslatePluginStatus(plugin_->SetParameter(Tag::VIDEO_PIXEL_FORMAT, pixelFormat_));
82 if (err != ErrorCode::SUCCESS) {
83 return err;
84 }
85 return ErrorCode::SUCCESS;
86 }
87
SetParameter(int32_t key,const Plugin::Any & value)88 ErrorCode VideoCaptureFilter::SetParameter(int32_t key, const Plugin::Any& value)
89 {
90 auto tag = static_cast<OHOS::Media::Plugin::Tag>(key);
91 switch (tag) {
92 case Tag::SRC_INPUT_TYPE:
93 inputTypeSpecified_ = AssignParameterIfMatch(tag, inputType_, value);
94 if (inputType_ == Plugin::SrcInputType::VID_SURFACE_YUV) {
95 pixelFormat_ = Plugin::VideoPixelFormat::YUV420P;
96 } else if (inputType_ == Plugin::SrcInputType::VID_SURFACE_RGB) {
97 pixelFormat_ = Plugin::VideoPixelFormat::RGBA;
98 } else {
99 MEDIA_LOG_W("unsupport inputType: " PUBLIC_LOG_U32, inputType_);
100 }
101 break;
102 case Tag::VIDEO_WIDTH:
103 (void)AssignParameterIfMatch(tag, videoWidth_, value);
104 break;
105 case Tag::VIDEO_HEIGHT:
106 (void)AssignParameterIfMatch(tag, videoHeight_, value);
107 break;
108 case Tag::VIDEO_CAPTURE_RATE:
109 (void)AssignParameterIfMatch(tag, captureRate_, value);
110 break;
111 case Tag::MEDIA_BITRATE:
112 (void)AssignParameterIfMatch(tag, bitRate_, value);
113 break;
114 case Tag::VIDEO_FRAME_RATE:
115 (void)AssignParameterIfMatch(tag, frameRate_, value);
116 break;
117 default:
118 MEDIA_LOG_W("Unknown key " PUBLIC_LOG_S, Plugin::GetTagStrName(tag));
119 break;
120 }
121 return ErrorCode::SUCCESS;
122 }
123
GetParameter(int32_t key,Plugin::Any & value)124 ErrorCode VideoCaptureFilter::GetParameter(int32_t key, Plugin::Any& value)
125 {
126 Tag tag = static_cast<Plugin::Tag>(key);
127 switch (tag) {
128 case Tag::SRC_INPUT_TYPE: {
129 value = inputType_;
130 break;
131 }
132 case Tag::VIDEO_WIDTH: {
133 value = videoWidth_;
134 break;
135 }
136 case Tag::VIDEO_HEIGHT: {
137 value = videoHeight_;
138 break;
139 }
140 case Tag::VIDEO_CAPTURE_RATE: {
141 value = captureRate_;
142 break;
143 }
144 case Tag::VIDEO_SURFACE: {
145 if (plugin_ != nullptr) {
146 plugin_->GetParameter(tag, value);
147 }
148 break;
149 }
150 default:
151 MEDIA_LOG_W("Unknown key " PUBLIC_LOG_S, Plugin::GetTagStrName(tag));
152 break;
153 }
154 return ErrorCode::SUCCESS;
155 }
156
DoConfigure()157 ErrorCode VideoCaptureFilter::DoConfigure()
158 {
159 auto emptyMeta = std::make_shared<Plugin::Meta>();
160 auto videoMeta = std::make_shared<Plugin::Meta>();
161 if (!MergeMetaWithCapability(*emptyMeta, capNegWithDownstream_, *videoMeta)) {
162 MEDIA_LOG_E("cannot find available capability of plugin " PUBLIC_LOG_S, pluginInfo_->name.c_str());
163 return ErrorCode::ERROR_UNKNOWN;
164 }
165 FALSE_LOG(videoMeta->Set<Plugin::Tag::VIDEO_WIDTH>(videoWidth_));
166 FALSE_LOG(videoMeta->Set<Plugin::Tag::VIDEO_HEIGHT>(videoHeight_));
167 FALSE_LOG(videoMeta->Set<Plugin::Tag::MEDIA_BITRATE>(bitRate_));
168 FALSE_LOG(videoMeta->Set<Plugin::Tag::VIDEO_FRAME_RATE>(frameRate_));
169 FALSE_LOG(videoMeta->Set<Plugin::Tag::MIME>(mime_));
170 FALSE_LOG(videoMeta->Set<Plugin::Tag::VIDEO_PIXEL_FORMAT>(pixelFormat_));
171 Plugin::Meta upstreamParams;
172 Plugin::Meta downstreamParams;
173 if (!outPorts_[0]->Configure(videoMeta, upstreamParams, downstreamParams)) {
174 MEDIA_LOG_E("Configure downstream fail");
175 return ErrorCode::ERROR_UNKNOWN;
176 }
177 return InitAndConfigPlugin(videoMeta);
178 }
179
Prepare()180 ErrorCode VideoCaptureFilter::Prepare()
181 {
182 MEDIA_LOG_I("Prepare entered.");
183 if (!taskPtr_) {
184 taskPtr_ = std::make_shared<OSAL::Task>("DataReader");
185 taskPtr_->RegisterHandler([this] { ReadLoop(); });
186 }
187 ErrorCode err = FindPlugin();
188 if (err != ErrorCode::SUCCESS || !plugin_) {
189 MEDIA_LOG_E("Find plugin fail");
190 return err;
191 }
192 err = DoConfigure();
193 if (err != ErrorCode::SUCCESS) {
194 MEDIA_LOG_E("DoConfigure fail");
195 return err;
196 }
197 err = TranslatePluginStatus(plugin_->Prepare());
198 if (err == ErrorCode::SUCCESS) {
199 MEDIA_LOG_D("media source send EVENT_READY");
200 OnEvent(Event{name_, EventType::EVENT_READY, {}});
201 }
202 return err;
203 }
204
Start()205 ErrorCode VideoCaptureFilter::Start()
206 {
207 MEDIA_LOG_I("Start entered.");
208 if (taskPtr_) {
209 taskPtr_->Start();
210 }
211 return plugin_ ? TranslatePluginStatus(plugin_->Start()) : ErrorCode::ERROR_INVALID_OPERATION;
212 }
213
Stop()214 ErrorCode VideoCaptureFilter::Stop()
215 {
216 MEDIA_LOG_I("Stop entered.");
217 if (taskPtr_) {
218 taskPtr_->Stop();
219 }
220 ErrorCode ret = ErrorCode::SUCCESS;
221 if (plugin_) {
222 ret = TranslatePluginStatus(plugin_->Stop());
223 }
224 return ret;
225 }
226
Pause()227 ErrorCode VideoCaptureFilter::Pause()
228 {
229 MEDIA_LOG_I("Pause entered.");
230 if (taskPtr_) {
231 taskPtr_->PauseAsync();
232 }
233 ErrorCode ret = ErrorCode::SUCCESS;
234 if (plugin_) {
235 ret = TranslatePluginStatus(plugin_->Stop());
236 }
237 return ret;
238 }
239
Resume()240 ErrorCode VideoCaptureFilter::Resume()
241 {
242 MEDIA_LOG_I("Resume entered.");
243 if (taskPtr_) {
244 taskPtr_->Start();
245 }
246 return plugin_ ? TranslatePluginStatus(plugin_->Start()) : ErrorCode::ERROR_INVALID_OPERATION;
247 }
248
SendEos()249 ErrorCode VideoCaptureFilter::SendEos()
250 {
251 MEDIA_LOG_I("SendEos entered.");
252 Stop();
253 auto eosBuffer = std::make_shared<AVBuffer>();
254 eosBuffer->flag |= BUFFER_FLAG_EOS;
255 SendBuffer(eosBuffer);
256 isEos_ = true;
257 return ErrorCode::SUCCESS;
258 }
259
InitPorts()260 void VideoCaptureFilter::InitPorts()
261 {
262 MEDIA_LOG_D("IN");
263 auto outPort = std::make_shared<OutPort>(this);
264 outPorts_.push_back(outPort);
265 }
266
ReadLoop()267 void VideoCaptureFilter::ReadLoop()
268 {
269 if (isEos_.load()) {
270 return;
271 }
272 uint64_t bufferSize = 0;
273 auto ret = plugin_->GetSize(bufferSize);
274 if (ret != Status::OK || bufferSize <= 0) {
275 MEDIA_LOG_E("Get plugin buffer size fail");
276 return;
277 }
278 AVBufferPtr bufferPtr = std::make_shared<AVBuffer>(BufferMetaType::VIDEO);
279 ret = plugin_->Read(bufferPtr, static_cast<size_t>(bufferSize));
280 if (ret != Status::OK) {
281 MEDIA_LOG_D("Read buffer from plugin fail: " PUBLIC_LOG_U32, ret);
282 return;
283 }
284 SendBuffer(bufferPtr);
285 OSAL::SleepFor(10); // 10: sleep 10ms when read one frame
286 }
287
CreatePlugin(const std::shared_ptr<PluginInfo> & info,const std::string & name,PluginManager & manager)288 ErrorCode VideoCaptureFilter::CreatePlugin(const std::shared_ptr<PluginInfo>& info, const std::string& name,
289 PluginManager& manager)
290 {
291 if ((plugin_ != nullptr) && (pluginInfo_ != nullptr)) {
292 if (info->name == pluginInfo_->name && TranslatePluginStatus(plugin_->Reset()) == ErrorCode::SUCCESS) {
293 MEDIA_LOG_I("Reuse last plugin: " PUBLIC_LOG_S, name.c_str());
294 return ErrorCode::SUCCESS;
295 }
296 if (TranslatePluginStatus(plugin_->Deinit()) != ErrorCode::SUCCESS) {
297 MEDIA_LOG_E("Deinit last plugin: " PUBLIC_LOG_S " error", pluginInfo_->name.c_str());
298 }
299 }
300 plugin_ = manager.CreateSourcePlugin(name);
301 if (plugin_ == nullptr) {
302 MEDIA_LOG_E("PluginManager CreatePlugin " PUBLIC_LOG_S " fail", name.c_str());
303 return ErrorCode::ERROR_UNKNOWN;
304 }
305 pluginInfo_ = info;
306 MEDIA_LOG_I("Create new plugin: " PUBLIC_LOG_S " success", pluginInfo_->name.c_str());
307 return ErrorCode::SUCCESS;
308 }
309
DoNegotiate(const CapabilitySet & outCaps)310 bool VideoCaptureFilter::DoNegotiate(const CapabilitySet &outCaps)
311 {
312 if (outCaps.empty()) {
313 MEDIA_LOG_E("audio capture plugin must have out caps");
314 return false;
315 }
316 for (const auto& outCap : outCaps) {
317 auto thisOut = std::make_shared<Plugin::Capability>();
318 mime_ = outCap.mime;
319 *thisOut = outCap; // pixel format
320 Plugin::Meta upstreamParams;
321 Plugin::Meta downstreamParams;
322 if (outPorts_[0]->Negotiate(thisOut, capNegWithDownstream_, upstreamParams, downstreamParams)) {
323 MEDIA_LOG_I("Negotiate success");
324 return true;
325 }
326 }
327 return false;
328 }
329
FindPlugin()330 ErrorCode VideoCaptureFilter::FindPlugin()
331 {
332 if (!inputTypeSpecified_) {
333 MEDIA_LOG_E("Must set input type first");
334 return ErrorCode::ERROR_INVALID_OPERATION;
335 }
336 PluginManager& pluginManager = PluginManager::Instance();
337 auto nameList = pluginManager.ListPlugins(PluginType::SOURCE);
338 for (const std::string& name : nameList) {
339 std::shared_ptr<PluginInfo> info = pluginManager.GetPluginInfo(PluginType::SOURCE, name);
340 MEDIA_LOG_I("name: " PUBLIC_LOG_S ", info->name: " PUBLIC_LOG_S, name.c_str(), info->name.c_str());
341 auto val = info->extra[PLUGIN_INFO_EXTRA_INPUT_TYPE];
342 if (val.SameTypeWith(typeid(Plugin::SrcInputType))) {
343 auto supportInputType = OHOS::Media::Plugin::AnyCast<Plugin::SrcInputType>(val);
344 if (inputType_ == supportInputType && DoNegotiate(info->outCaps) &&
345 CreatePlugin(info, name, pluginManager) == ErrorCode::SUCCESS) {
346 MEDIA_LOG_I("CreatePlugin " PUBLIC_LOG_S " success", name_.c_str());
347 return ErrorCode::SUCCESS;
348 }
349 }
350 }
351 MEDIA_LOG_I("Cannot find any plugin");
352 return ErrorCode::ERROR_UNSUPPORTED_FORMAT;
353 }
354
SendBuffer(const std::shared_ptr<AVBuffer> & buffer)355 void VideoCaptureFilter::SendBuffer(const std::shared_ptr<AVBuffer>& buffer)
356 {
357 OSAL::ScopedLock lock(pushMutex_);
358 if (!isEos_.load()) {
359 outPorts_[0]->PushData(buffer, -1);
360 }
361 }
362 } // namespace Pipeline
363 } // namespace Media
364 } // namespace OHOS
365 #endif