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(OHOS_LITE) && defined(RECORDER_SUPPORT) && defined(VIDEO_SUPPORT)
17
18 #define HST_LOG_TAG "VideoCapturePlugin"
19
20 #include "video_capture_plugin.h"
21 #include <algorithm>
22 #include <cmath>
23 #include "foundation/log.h"
24 #include "plugin/common/plugin_time.h"
25 #include "utils/utils.h"
26 #include "utils/constants.h"
27
28 namespace {
29 // register plugins
30 using namespace OHOS::Media::Plugin;
31 using namespace VideoCapture;
VideoCapturePluginCreater(const std::string & name)32 std::shared_ptr<SourcePlugin> VideoCapturePluginCreater(const std::string &name)
33 {
34 return std::make_shared<VideoCapturePlugin>(name);
35 }
36
VideoCaptureRegister(const std::shared_ptr<Register> & reg)37 Status VideoCaptureRegister(const std::shared_ptr<Register> ®)
38 {
39 SourcePluginDef definition;
40 definition.name = "AudioCapture";
41 definition.description = "Video capture from audio service";
42 definition.rank = 100; // 100: max rank
43 definition.inputType = SrcInputType::VID_SURFACE_YUV;
44 definition.creator = VideoCapturePluginCreater;
45 Capability outCaps(OHOS::Media::MEDIA_MIME_VIDEO_RAW);
46 definition.outCaps.push_back(outCaps);
47 // add es outCaps later
48 return reg->AddPlugin(definition);
49 }
__anon4a561c470202null50 PLUGIN_DEFINITION(StdVideoCapture, LicenseType::APACHE_V2, VideoCaptureRegister, [] {});
51 }
52
53 namespace OHOS {
54 namespace Media {
55 namespace Plugin {
56 using namespace OHOS::Media::Plugin;
57
58 constexpr int32_t DEFAULT_SURFACE_QUEUE_SIZE = 6;
59 constexpr int32_t DEFAULT_SURFACE_SIZE = 1024 * 1024;
60 constexpr int32_t DEFAULT_VIDEO_WIDTH = 1920;
61 constexpr int32_t DEFAULT_VIDEO_HEIGHT = 1080;
62
Alloc(size_t size)63 void* VideoCaptureAllocator::Alloc(size_t size)
64 {
65 if (size == 0) {
66 return nullptr;
67 }
68 return reinterpret_cast<void*>(new (std::nothrow) uint8_t[size]); // NOLINT: cast
69 }
70
Free(void * ptr)71 void VideoCaptureAllocator::Free(void* ptr) // NOLINT: void*
72 {
73 if (ptr != nullptr) {
74 delete[](uint8_t*) ptr;
75 }
76 }
77
VideoCapturePlugin(std::string name)78 VideoCapturePlugin::VideoCapturePlugin(std::string name)
79 : SourcePlugin(std::move(name)),
80 width_(DEFAULT_VIDEO_WIDTH),
81 height_(DEFAULT_VIDEO_HEIGHT)
82 {
83 MEDIA_LOG_D("IN");
84 }
85
~VideoCapturePlugin()86 VideoCapturePlugin::~VideoCapturePlugin()
87 {
88 MEDIA_LOG_D("IN");
89 }
90
Init()91 Status VideoCapturePlugin::Init()
92 {
93 MEDIA_LOG_D("IN");
94 return Status::OK;
95 }
96
Deinit()97 Status VideoCapturePlugin::Deinit()
98 {
99 MEDIA_LOG_D("IN");
100 return Status::OK;
101 }
102
ConfigSurfaceConsumer()103 void VideoCapturePlugin::ConfigSurfaceConsumer()
104 {
105 auto ret = surfaceConsumer_->SetUserData("video_width", std::to_string(width_));
106 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
107 MEDIA_LOG_E("set video width fail");
108 }
109 ret = surfaceConsumer_->SetUserData("video_height", std::to_string(height_));
110 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
111 MEDIA_LOG_E("set video height fail");
112 }
113 ret = surfaceConsumer_->SetQueueSize(DEFAULT_SURFACE_QUEUE_SIZE);
114 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
115 MEDIA_LOG_E("set queue size fail");
116 }
117 ret = surfaceConsumer_->SetUserData("surface_size", std::to_string(DEFAULT_SURFACE_SIZE));
118 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
119 MEDIA_LOG_E("set surface size fail");
120 }
121 ret = surfaceConsumer_->SetDefaultWidthAndHeight(width_, height_);
122 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
123 MEDIA_LOG_E("set surface width and height fail");
124 }
125 }
126
Prepare()127 Status VideoCapturePlugin::Prepare()
128 {
129 MEDIA_LOG_D("IN");
130 surfaceConsumer_ = Surface::CreateSurfaceAsConsumer();
131 if (!surfaceConsumer_) {
132 MEDIA_LOG_E("CreateSurfaceAsConsumer() fail");
133 return Status::ERROR_UNKNOWN;
134 }
135 sptr<IBufferConsumerListener> consumerListener = new (std::nothrow) SurfaceConsumerListener(*this);
136 if (!consumerListener) {
137 MEDIA_LOG_E("Malloc SurfaceConsumerListener fail");
138 return Status::ERROR_NO_MEMORY;
139 }
140 if (surfaceConsumer_->RegisterConsumerListener(consumerListener) != OHOS::SurfaceError::SURFACE_ERROR_OK) {
141 MEDIA_LOG_E("RegisterConsumerListener() fail");
142 return Status::ERROR_UNKNOWN;
143 }
144 sptr<IBufferProducer> bufferProducer = surfaceConsumer_->GetProducer();
145 if (!bufferProducer) {
146 MEDIA_LOG_E("Malloc GetProducer fail");
147 return Status::ERROR_UNKNOWN;
148 }
149 surfaceProducer_ = Surface::CreateSurfaceAsProducer(bufferProducer);
150 if (!surfaceProducer_) {
151 MEDIA_LOG_E("CreateSurfaceAsProducer() fail");
152 return Status::ERROR_UNKNOWN;
153 }
154 ConfigSurfaceConsumer();
155 return Status::OK;
156 }
157
Reset()158 Status VideoCapturePlugin::Reset()
159 {
160 MEDIA_LOG_D("IN");
161 return Status::OK;
162 }
163
Start()164 Status VideoCapturePlugin::Start()
165 {
166 MEDIA_LOG_D("IN");
167 OHOS::Media::OSAL::ScopedLock lock(mutex_);
168 if (isStop_.load()) {
169 if (curTimestampNs_ < stopTimestampNs_) {
170 MEDIA_LOG_E("Get wrong audio time");
171 }
172 totalPauseTimeNs_ += std::fabs(curTimestampNs_ - stopTimestampNs_);
173 isStop_ = false;
174 }
175 return Status::OK;
176 }
177
Stop()178 Status VideoCapturePlugin::Stop()
179 {
180 MEDIA_LOG_D("IN");
181 OHOS::Media::OSAL::ScopedLock lock(mutex_);
182 if (!isStop_.load()) {
183 stopTimestampNs_ = curTimestampNs_;
184 isStop_ = true;
185 }
186 return Status::OK;
187 }
188
IsParameterSupported(Tag tag)189 bool VideoCapturePlugin::IsParameterSupported(Tag tag)
190 {
191 MEDIA_LOG_D("IN");
192 return false;
193 }
194
GetParameter(Tag tag,ValueType & value)195 Status VideoCapturePlugin::GetParameter(Tag tag, ValueType& value)
196 {
197 MEDIA_LOG_D("IN");
198 switch (tag) {
199 case Tag::VIDEO_SURFACE: {
200 value = surfaceProducer_.GetRefPtr();
201 break;
202 }
203 default:
204 MEDIA_LOG_I("Unknown key");
205 break;
206 }
207 return Status::OK;
208 }
209
SetParameter(Tag tag,const ValueType & value)210 Status VideoCapturePlugin::SetParameter(Tag tag, const ValueType& value)
211 {
212 switch (tag) {
213 case Tag::VIDEO_HEIGHT: {
214 if (value.SameTypeWith(typeid(uint32_t))) {
215 height_ = Plugin::AnyCast<uint32_t>(value);
216 }
217 break;
218 }
219 case Tag::VIDEO_WIDTH: {
220 if (value.SameTypeWith(typeid(uint32_t))) {
221 width_ = Plugin::AnyCast<uint32_t>(value);
222 }
223 break;
224 }
225 default:
226 MEDIA_LOG_I("Unknown key");
227 break;
228 }
229 return Status::OK;
230 }
231
GetAllocator()232 std::shared_ptr<Allocator> VideoCapturePlugin::GetAllocator()
233 {
234 MEDIA_LOG_D("IN");
235 return mAllocator_;
236 }
237
SetCallback(Callback * cb)238 Status VideoCapturePlugin::SetCallback(Callback* cb)
239 {
240 MEDIA_LOG_D("IN");
241 UNUSED_VARIABLE(cb);
242 return Status::ERROR_UNIMPLEMENTED;
243 }
244
SetSource(std::shared_ptr<MediaSource> source)245 Status VideoCapturePlugin::SetSource(std::shared_ptr<MediaSource> source)
246 {
247 UNUSED_VARIABLE(source);
248 return Status::ERROR_UNIMPLEMENTED;
249 }
250
AcquireSurfaceBuffer()251 Status VideoCapturePlugin::AcquireSurfaceBuffer()
252 {
253 auto ret = surfaceConsumer_->AcquireBuffer(surfaceBuffer_, fence_, timestamp_, damage_);
254 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
255 MEDIA_LOG_E("surfaceConsumer AcquireBuffer() fail: %" PUBLIC_LOG "u", ret);
256 return Status::ERROR_UNKNOWN;
257 }
258 ret = surfaceBuffer_->ExtraGet("dataSize", bufferSize_);
259 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK || bufferSize_ <= 0) {
260 MEDIA_LOG_E("surfaceBuffer get data size fail: %" PUBLIC_LOG "u", ret);
261 return Status::ERROR_UNKNOWN;
262 }
263 ret = surfaceBuffer_->ExtraGet("isKeyFrame", isKeyFrame_);
264 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
265 MEDIA_LOG_E("surfaceBuffer get isKeyFrame fail: %" PUBLIC_LOG "u", ret);
266 return Status::ERROR_UNKNOWN;
267 }
268 int64_t pts;
269 ret = surfaceBuffer_->ExtraGet("timeStamp", pts);
270 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK || pts < 0) {
271 MEDIA_LOG_E("surfaceBuffer get data size fail: %" PUBLIC_LOG "u", ret);
272 return Status::ERROR_UNKNOWN;
273 }
274 if (pts < curTimestampNs_) {
275 MEDIA_LOG_W("Get wrong timestamp from surface buffer");
276 }
277 curTimestampNs_ = static_cast<uint64_t>(pts);
278 return Status::OK;
279 }
280
Read(std::shared_ptr<Buffer> & buffer,size_t expectedLen)281 Status VideoCapturePlugin::Read(std::shared_ptr<Buffer>& buffer, size_t expectedLen)
282 {
283 OHOS::Media::OSAL::ScopedLock lock(mutex_);
284 if (!buffer) {
285 return Status::ERROR_INVALID_PARAMETER;
286 }
287 auto bufferMeta = buffer->GetBufferMeta();
288 if (!bufferMeta || bufferMeta->GetType() != BufferMetaType::VIDEO || surfaceConsumer_ == nullptr) {
289 return Status::ERROR_INVALID_PARAMETER;
290 }
291 std::shared_ptr<Memory> bufData;
292 if (buffer->IsEmpty()) {
293 bufData = buffer->AllocMemory(GetAllocator(), expectedLen);
294 } else {
295 bufData = buffer->GetMemory();
296 }
297 if (bufData->GetMemoryType() != MemoryType::VIRTUAL_ADDR || bufData->GetCapacity() <= 0) {
298 return Status::ERROR_NO_MEMORY;
299 }
300 readCond_.Wait(lock, [this] { return bufferCnt_ > 0 || isStop_.load(); });
301 if (isStop_.load()) {
302 MEDIA_LOG_I("flush or EOS, skip read buffer");
303 return Status::END_OF_STREAM;
304 }
305 auto ret = AcquireSurfaceBuffer();
306 if (ret != Status::OK) {
307 MEDIA_LOG_E("AcquireSurfaceBuffer fail: %" PUBLIC_LOG "d", ret);
308 return ret;
309 }
310 if (bufData->Write(static_cast<const uint8_t*>(surfaceBuffer_->GetVirAddr()), bufferSize_) != bufferSize_) {
311 MEDIA_LOG_E("write buffer data fail");
312 return Status::ERROR_UNKNOWN;
313 }
314 Ns2HstTime(curTimestampNs_ - totalPauseTimeNs_, reinterpret_cast<int64_t &>(buffer->pts));
315 bufferCnt_--;
316 return Status::OK;
317 }
318
GetSize(size_t & size)319 Status VideoCapturePlugin::GetSize(size_t& size)
320 {
321 if (bufferSize_ == 0) {
322 return Status::ERROR_INVALID_PARAMETER;
323 }
324 size = bufferSize_;
325 MEDIA_LOG_D("bufferSize_: %" PUBLIC_LOG "zu", size);
326 return Status::OK;
327 }
328
IsSeekable()329 bool VideoCapturePlugin::IsSeekable()
330 {
331 return false;
332 }
333
SeekTo(uint64_t offset)334 Status VideoCapturePlugin::SeekTo(uint64_t offset)
335 {
336 UNUSED_VARIABLE(offset);
337 return Status::ERROR_UNIMPLEMENTED;
338 }
339
OnBufferAvailable()340 void VideoCapturePlugin::SurfaceConsumerListener::OnBufferAvailable()
341 {
342 return owner_.OnBufferAvailable();
343 }
344
OnBufferAvailable()345 void VideoCapturePlugin::OnBufferAvailable()
346 {
347 if (!surfaceConsumer_) {
348 return;
349 }
350 OHOS::Media::OSAL::ScopedLock lock(mutex_);
351 bufferCnt_++;
352 if (bufferCnt_ == 1) {
353 readCond_.NotifyAll();
354 }
355 }
356 } // namespace Plugin
357 } // namespace Media
358 } // namespace OHOS
359 #endif