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> &reg)
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