• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 "gst_video_capture_pool.h"
17 #include <gst/gst.h>
18 #include "buffer_type_meta.h"
19 #include "surface.h"
20 #include "scope_guard.h"
21 #include "securec.h"
22 #include "media_log.h"
23 #include "media_dfx.h"
24 #include "media_errors.h"
25 using namespace OHOS;
26 
27 #define gst_video_capture_pool_parent_class parent_class
28 
29 GST_DEBUG_CATEGORY_STATIC(gst_video_capture_pool_debug_category);
30 #define GST_CAT_DEFAULT gst_video_capture_pool_debug_category
31 
32 enum {
33     PROP_0,
34     PROP_CACHED_DATA,
35 };
36 
37 G_DEFINE_TYPE(GstVideoCapturePool, gst_video_capture_pool, GST_TYPE_CONSUMER_SURFACE_POOL);
38 
39 static void gst_video_capture_pool_set_property(GObject *object, guint id, const GValue *value, GParamSpec *pspec);
40 static GstFlowReturn gst_video_capture_pool_buffer_available(GstConsumerSurfacePool *surfacepool, bool *releasebuffer);
41 static GstFlowReturn gst_video_capture_pool_find_buffer(GstBufferPool *gstpool, GstBuffer **buffer, bool *found);
42 static GstFlowReturn gst_video_capture_pool_get_buffer(GstConsumerSurfacePool *surfacepool,
43     GstBuffer **buffer, bool *releasebuffer);
44 static GstFlowReturn gst_video_capture_pool_release_buffer(GstConsumerSurfacePool *surfacepool, bool *releasebuffer);
45 
gst_video_capture_pool_class_init(GstVideoCapturePoolClass * klass)46 static void gst_video_capture_pool_class_init(GstVideoCapturePoolClass *klass)
47 {
48     g_return_if_fail(klass != nullptr);
49     GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
50     GST_DEBUG_CATEGORY_INIT(gst_video_capture_pool_debug_category, "videocapturepool", 0,
51         "video capture pool base class");
52 
53     gobjectClass->set_property = gst_video_capture_pool_set_property;
54 
55     g_object_class_install_property(gobjectClass, PROP_CACHED_DATA,
56         g_param_spec_boolean("cached-data", "es pause", "es pause",
57             FALSE, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
58 }
59 
gst_video_capture_pool_init(GstVideoCapturePool * pool)60 static void gst_video_capture_pool_init(GstVideoCapturePool *pool)
61 {
62     g_return_if_fail(pool != nullptr);
63     GstConsumerSurfacePool *surfacepool = GST_CONSUMER_SURFACE_POOL(pool);
64     surfacepool->buffer_available = gst_video_capture_pool_buffer_available;
65     surfacepool->find_buffer = gst_video_capture_pool_find_buffer;
66 
67     pool->cached_data = false;
68     pool->poolMgr = nullptr;
69 }
70 
gst_video_capture_pool_new()71 GstBufferPool *gst_video_capture_pool_new()
72 {
73     GstBufferPool *pool = GST_BUFFER_POOL_CAST(g_object_new(
74         GST_TYPE_VIDEO_CAPTURE_POOL, "name", "video_capture_pool", nullptr));
75     (void)gst_object_ref_sink(pool);
76 
77     return pool;
78 }
79 
gst_video_capture_pool_set_property(GObject * object,guint id,const GValue * value,GParamSpec * pspec)80 static void gst_video_capture_pool_set_property(GObject *object, guint id, const GValue *value, GParamSpec *pspec)
81 {
82     (void)pspec;
83     GstVideoCapturePool *pool = GST_VIDEO_CAPTURE_POOL(object);
84     g_return_if_fail(pool != nullptr && value != nullptr);
85 
86     g_mutex_lock(&pool->pool_lock);
87     ON_SCOPE_EXIT(0) {
88         g_mutex_unlock(&pool->pool_lock);
89     };
90     switch (id) {
91         case PROP_CACHED_DATA:
92             if (g_value_get_boolean(value) == true) {
93                 if (pool->poolMgr == nullptr) {
94                     const uint32_t size = 6; // Save up to 6 buffer data.
95                     pool->poolMgr = std::make_shared<OHOS::Media::VideoPoolManager>(size);
96                     g_return_if_fail(pool->poolMgr != nullptr);
97                 }
98 
99                 // If the queue is not empty, it is not supported to cache the suspended data again.
100                 if (pool->poolMgr->IsBufferQueEmpty()) {
101                     pool->cached_data = true;
102                 }
103             } else {
104                 pool->cached_data = false;
105                 if (pool->poolMgr != nullptr) {
106                     GST_DEBUG_OBJECT(pool, "Received %d frames of data during pause.",
107                         pool->poolMgr->GetBufferQueSize());
108                 }
109             }
110             break;
111         default:
112             break;
113     }
114 }
115 
gst_video_capture_pool_buffer_available(GstConsumerSurfacePool * surfacepool,bool * releasebuffer)116 static GstFlowReturn gst_video_capture_pool_buffer_available(GstConsumerSurfacePool *surfacepool, bool *releasebuffer)
117 {
118     g_return_val_if_fail(surfacepool != nullptr && releasebuffer != nullptr, GST_FLOW_ERROR);
119     GstVideoCapturePool *pool = GST_VIDEO_CAPTURE_POOL(surfacepool);
120 
121     g_mutex_lock(&pool->pool_lock);
122     ON_SCOPE_EXIT(0) {
123         g_mutex_unlock(&pool->pool_lock);
124     };
125 
126     *releasebuffer = false;
127     if (pool->cached_data) {
128         if (pool->poolMgr != nullptr && pool->poolMgr->IsBufferQueFull() == false) {
129             GstBuffer *buf;
130             if (gst_video_capture_pool_get_buffer(surfacepool, &buf, releasebuffer) == GST_FLOW_OK) {
131                 (void)pool->poolMgr->PushBuffer(buf);
132                 *releasebuffer = false;
133             } else {
134                 GST_WARNING_OBJECT(surfacepool, "video capture pool get buffer failed");
135             }
136         }
137     } else {
138         if (gst_video_capture_pool_release_buffer(surfacepool, releasebuffer) != GST_FLOW_OK) {
139             GST_WARNING_OBJECT(surfacepool, "video capture pool release buffer failed");
140         }
141     }
142 
143     return GST_FLOW_OK;
144 }
145 
gst_video_capture_pool_find_buffer(GstBufferPool * gstpool,GstBuffer ** buffer,bool * found)146 static GstFlowReturn gst_video_capture_pool_find_buffer(GstBufferPool *gstpool, GstBuffer **buffer, bool *found)
147 {
148     GstVideoCapturePool *pool = GST_VIDEO_CAPTURE_POOL(gstpool);
149     g_return_val_if_fail(pool != nullptr && buffer != nullptr && found != nullptr, GST_FLOW_ERROR);
150 
151     g_mutex_lock(&pool->pool_lock);
152     ON_SCOPE_EXIT(0) {
153         g_mutex_unlock(&pool->pool_lock);
154     };
155 
156     *found = false;
157     if (pool->poolMgr != nullptr && pool->poolMgr->GetBufferQueSize() > 0) {
158         *buffer = pool->poolMgr->PopBuffer();
159         *found = true;
160     }
161 
162     return GST_FLOW_OK;
163 }
164 
gst_video_capture_pool_get_buffer(GstConsumerSurfacePool * surfacepool,GstBuffer ** buffer,bool * releasebuffer)165 static GstFlowReturn gst_video_capture_pool_get_buffer(GstConsumerSurfacePool *surfacepool,
166     GstBuffer **buffer, bool *releasebuffer)
167 {
168     g_return_val_if_fail(surfacepool != nullptr && buffer != nullptr && surfacepool->get_surface_buffer != nullptr &&
169         surfacepool->release_surface_buffer != nullptr && releasebuffer != nullptr, GST_FLOW_ERROR);
170 
171     // Get buffer
172     OHOS::sptr<OHOS::SurfaceBuffer> surfacebuffer = nullptr;
173     gint32 fencefd = -1;
174     GstFlowReturn ret = surfacepool->get_surface_buffer(surfacepool, surfacebuffer, fencefd);
175     g_return_val_if_fail(ret == GST_FLOW_OK && surfacebuffer != nullptr, GST_FLOW_ERROR);
176     *releasebuffer = true;
177     ON_SCOPE_EXIT(0) {
178         surfacepool->release_surface_buffer(surfacepool, surfacebuffer, fencefd);
179     };
180 
181     // Get buffer data.
182     gint64 timestamp = 0;
183     gint32 data_size = 0;
184     gboolean end_of_stream = false;
185     const OHOS::sptr<OHOS::BufferExtraData>& extraData = surfacebuffer->GetExtraData();
186     g_return_val_if_fail(extraData != nullptr, GST_FLOW_ERROR);
187     (void)extraData->ExtraGet("timeStamp", timestamp);
188     (void)extraData->ExtraGet("dataSize", data_size);
189     g_return_val_if_fail(static_cast<gint32>(surfacebuffer->GetSize()) >= data_size, GST_FLOW_ERROR);
190     (void)extraData->ExtraGet("endOfStream", end_of_stream);
191 
192     // copy data
193     GstBuffer *dts_buffer = gst_buffer_new_allocate(nullptr, data_size, nullptr);
194     g_return_val_if_fail(dts_buffer != nullptr, GST_FLOW_ERROR);
195     ON_SCOPE_EXIT(1) {
196         gst_buffer_unref(dts_buffer);
197     };
198 
199     GstMapInfo info = GST_MAP_INFO_INIT;
200     g_return_val_if_fail(gst_buffer_map(dts_buffer, &info, GST_MAP_WRITE) == TRUE, GST_FLOW_ERROR);
201     ON_SCOPE_EXIT(2) { // ON_SCOPE_EXIT 2
202         gst_buffer_unmap(dts_buffer, &info);
203     };
204 
205     uint8_t *src = static_cast<uint8_t *>(surfacebuffer->GetVirAddr());
206     errno_t rc = memcpy_s(info.data, info.size, src, static_cast<size_t>(data_size));
207     g_return_val_if_fail(rc == EOK, GST_FLOW_ERROR);
208 
209     // Meta
210     GstBufferTypeMeta *meta = (GstBufferTypeMeta *)gst_buffer_add_meta(dts_buffer, GST_BUFFER_TYPE_META_INFO, NULL);
211     g_return_val_if_fail(meta != NULL, GST_FLOW_ERROR);
212 
213     meta->type = BUFFER_TYPE_HANDLE;
214     meta->bufLen = static_cast<uint32_t>(data_size);
215     meta->length = static_cast<uint32_t>(data_size);
216     meta->bufferFlag = end_of_stream ? BUFFER_FLAG_EOS : 0;
217     meta->pixelFormat = surfacebuffer->GetFormat();
218     meta->width = static_cast<uint32_t>(surfacebuffer->GetWidth());
219     meta->height = static_cast<uint32_t>(surfacebuffer->GetHeight());
220     meta->invalidpts = TRUE;
221 
222     GST_BUFFER_PTS(dts_buffer) = static_cast<uint64_t>(timestamp);
223     GST_DEBUG_OBJECT(surfacepool, "BufferQue video capture buffer size is: %" G_GSIZE_FORMAT ", pts: %"
224         G_GUINT64_FORMAT, gst_buffer_get_size(dts_buffer), timestamp);
225 
226     CANCEL_SCOPE_EXIT_GUARD(1);
227     *buffer = dts_buffer;
228     return GST_FLOW_OK;
229 }
230 
gst_video_capture_pool_release_buffer(GstConsumerSurfacePool * surfacepool,bool * releasebuffer)231 static GstFlowReturn gst_video_capture_pool_release_buffer(GstConsumerSurfacePool *surfacepool, bool *releasebuffer)
232 {
233     g_return_val_if_fail(surfacepool != nullptr && surfacepool->get_surface_buffer != nullptr &&
234         surfacepool->release_surface_buffer != nullptr && releasebuffer != nullptr, GST_FLOW_ERROR);
235 
236     // Get buffer
237     OHOS::sptr<OHOS::SurfaceBuffer> surfacebuffer = nullptr;
238     gint32 fencefd = -1;
239     GstFlowReturn ret = surfacepool->get_surface_buffer(surfacepool, surfacebuffer, fencefd);
240     g_return_val_if_fail(ret == GST_FLOW_OK && surfacebuffer != nullptr, GST_FLOW_ERROR);
241     *releasebuffer = true;
242     surfacepool->release_surface_buffer(surfacepool, surfacebuffer, fencefd);
243 
244     return GST_FLOW_OK;
245 }