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