1 /*
2 * Copyright (C) 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 #include "gst_mem_pool_src.h"
17 #include <gst/video/video.h>
18 #include "media_errors.h"
19 #include "scope_guard.h"
20
21 using namespace OHOS;
22 namespace {
23 constexpr int32_t DEFAULT_BUFFER_SIZE = 41920;
24 constexpr int32_t DEFAULT_BUFFER_NUM = 8;
25 }
26
27 #define gst_mem_pool_src_parent_class parent_class
28
29 GST_DEBUG_CATEGORY_STATIC(gst_mem_pool_src_debug_category);
30 #define GST_CAT_DEFAULT gst_mem_pool_src_debug_category
31
32 struct _GstMemPoolSrcPrivate {
33 BufferAvailable buffer_available;
34 gboolean emit_signals;
35 gpointer user_data;
36 GDestroyNotify notify;
37 };
38
39 enum {
40 /* signals */
41 SIGNAL_BUFFER_AVAILABLE,
42 /* actions */
43 SIGNAL_PULL_BUFFER,
44 SIGNAL_PUSH_BUFFER,
45 LAST_SIGNAL
46 };
47
48 enum {
49 PROP_0,
50 PROP_CAPS,
51 PROP_EMIT_SIGNALS,
52 PROP_BUFFER_NUM,
53 PROP_BUFFER_SIZE,
54 };
55
56 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(GstMemPoolSrc, gst_mem_pool_src, GST_TYPE_BASE_SRC);
57
58 static guint gst_mem_pool_src_signals[LAST_SIGNAL] = { 0 };
59 static void gst_mem_pool_src_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
60 static void gst_mem_pool_src_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
61 static gboolean gst_mem_pool_src_query(GstBaseSrc *src, GstQuery *query);
62 static gboolean gst_mem_pool_src_is_seekable(GstBaseSrc *basesrc);
63 static gboolean gst_mem_pool_src_negotiate(GstBaseSrc *basesrc);
64 static void gst_mem_pool_src_dispose(GObject *object);
65
gst_mem_pool_src_class_init(GstMemPoolSrcClass * klass)66 static void gst_mem_pool_src_class_init(GstMemPoolSrcClass *klass)
67 {
68 g_return_if_fail(klass != nullptr);
69 GObjectClass *gobject_class = reinterpret_cast<GObjectClass *>(klass);
70 GstBaseSrcClass *gstbasesrc_class = reinterpret_cast<GstBaseSrcClass *>(klass);
71 GST_DEBUG_CATEGORY_INIT(gst_mem_pool_src_debug_category, "mempoolsrc", 0, "mem pool src base class");
72 gobject_class->set_property = gst_mem_pool_src_set_property;
73 gobject_class->get_property = gst_mem_pool_src_get_property;
74 gobject_class->dispose = gst_mem_pool_src_dispose;
75
76 g_object_class_install_property(gobject_class, PROP_BUFFER_SIZE,
77 g_param_spec_uint("buffer-size", "buffer size",
78 "buffer size", 0, G_MAXINT32, 0,
79 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
80
81 g_object_class_install_property(gobject_class, PROP_BUFFER_NUM,
82 g_param_spec_uint("buffer-num", "buffer num",
83 "buffer num", 0, G_MAXINT32, 0,
84 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
85
86 g_object_class_install_property(gobject_class, PROP_CAPS,
87 g_param_spec_boxed("caps", "Caps",
88 "The allowed caps for the src pad", GST_TYPE_CAPS,
89 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
90
91 g_object_class_install_property(gobject_class, PROP_EMIT_SIGNALS,
92 g_param_spec_boolean("emit-signals", "Emit signals",
93 "Emit new-preroll and new-sample signals", FALSE,
94 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
95
96 gst_mem_pool_src_signals[SIGNAL_BUFFER_AVAILABLE] =
97 g_signal_new("buffer-available", G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST,
98 0, nullptr, nullptr, nullptr, GST_TYPE_FLOW_RETURN, 0, G_TYPE_NONE);
99
100 gst_mem_pool_src_signals[SIGNAL_PULL_BUFFER] =
101 g_signal_new("pull-buffer", G_TYPE_FROM_CLASS(gobject_class),
102 static_cast<GSignalFlags>(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
103 G_STRUCT_OFFSET(GstMemPoolSrcClass, pull_buffer), nullptr, nullptr, nullptr,
104 GST_TYPE_BUFFER, 0, G_TYPE_NONE);
105
106 gst_mem_pool_src_signals[SIGNAL_PUSH_BUFFER] =
107 g_signal_new("push-buffer", G_TYPE_FROM_CLASS(gobject_class),
108 static_cast<GSignalFlags>(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
109 G_STRUCT_OFFSET(GstMemPoolSrcClass, push_buffer), nullptr, nullptr, nullptr,
110 GST_TYPE_FLOW_RETURN, 1, GST_TYPE_BUFFER);
111
112 gstbasesrc_class->is_seekable = gst_mem_pool_src_is_seekable;
113 gstbasesrc_class->query = gst_mem_pool_src_query;
114 gstbasesrc_class->negotiate = gst_mem_pool_src_negotiate;
115 }
116
gst_mem_pool_src_init(GstMemPoolSrc * memsrc)117 static void gst_mem_pool_src_init(GstMemPoolSrc *memsrc)
118 {
119 g_return_if_fail(memsrc != nullptr);
120 auto priv = reinterpret_cast<GstMemPoolSrcPrivate *>(gst_mem_pool_src_get_instance_private(memsrc));
121 g_return_if_fail(priv != nullptr);
122 gst_base_src_set_format(GST_BASE_SRC(memsrc), GST_FORMAT_TIME);
123 gst_base_src_set_live(GST_BASE_SRC(memsrc), TRUE);
124 memsrc->buffer_size = DEFAULT_BUFFER_SIZE;
125 memsrc->buffer_num = DEFAULT_BUFFER_NUM;
126 memsrc->priv = priv;
127 priv->buffer_available = nullptr;
128 priv->user_data = nullptr;
129 priv->notify = nullptr;
130 priv->emit_signals = FALSE;
131 }
132
gst_mem_pool_src_buffer_available(GstMemPoolSrc * memsrc)133 GstFlowReturn gst_mem_pool_src_buffer_available(GstMemPoolSrc *memsrc)
134 {
135 GST_DEBUG_OBJECT(memsrc, "Buffer available");
136 g_return_val_if_fail(memsrc != nullptr && memsrc->priv != nullptr, GST_FLOW_ERROR);
137 GstFlowReturn ret = GST_FLOW_OK;
138 auto priv = memsrc->priv;
139 gboolean emit = FALSE;
140 if (priv->buffer_available) {
141 ret = priv->buffer_available(memsrc, priv->user_data);
142 } else {
143 GST_OBJECT_LOCK(memsrc);
144 emit = priv->emit_signals;
145 GST_OBJECT_UNLOCK(memsrc);
146 if (emit) {
147 g_signal_emit(memsrc, gst_mem_pool_src_signals[SIGNAL_BUFFER_AVAILABLE], 0, &ret);
148 }
149 }
150 return ret;
151 }
152
gst_mem_pool_src_negotiate(GstBaseSrc * basesrc)153 static gboolean gst_mem_pool_src_negotiate(GstBaseSrc *basesrc)
154 {
155 g_return_val_if_fail(basesrc != nullptr, FALSE);
156 GstMemPoolSrc *memsrc = GST_MEM_POOL_SRC(basesrc);
157 return gst_base_src_set_caps(basesrc, memsrc->caps);
158 }
159
gst_mem_pool_src_set_caps(GstMemPoolSrc * memsrc,const GstCaps * caps)160 void gst_mem_pool_src_set_caps(GstMemPoolSrc *memsrc, const GstCaps *caps)
161 {
162 g_return_if_fail(memsrc != nullptr);
163 GST_DEBUG_OBJECT(memsrc, "Setting caps to %s", gst_caps_to_string(caps));
164 GST_OBJECT_LOCK(memsrc);
165 GstCaps *old_caps = memsrc->caps;
166 if (caps != nullptr) {
167 memsrc->caps = gst_caps_copy(caps);
168 } else {
169 memsrc->caps = nullptr;
170 }
171 if (old_caps != nullptr) {
172 gst_caps_unref(old_caps);
173 }
174 GST_OBJECT_UNLOCK(memsrc);
175 }
176
gst_mem_pool_src_set_emit_signals(GstMemPoolSrc * memsrc,gboolean emit)177 void gst_mem_pool_src_set_emit_signals(GstMemPoolSrc *memsrc, gboolean emit)
178 {
179 g_return_if_fail(memsrc != nullptr && memsrc->priv != nullptr);
180 auto priv = memsrc->priv;
181 GST_OBJECT_LOCK(memsrc);
182 priv->emit_signals = emit;
183 GST_OBJECT_UNLOCK(memsrc);
184 }
185
gst_mem_pool_src_set_buffer_size(GstMemPoolSrc * memsrc,guint size)186 void gst_mem_pool_src_set_buffer_size(GstMemPoolSrc *memsrc, guint size)
187 {
188 g_return_if_fail(memsrc != nullptr);
189 GST_OBJECT_LOCK(memsrc);
190 memsrc->buffer_size = size;
191 GST_OBJECT_UNLOCK(memsrc);
192 }
193
gst_mem_pool_src_set_buffer_num(GstMemPoolSrc * memsrc,guint num)194 void gst_mem_pool_src_set_buffer_num(GstMemPoolSrc *memsrc, guint num)
195 {
196 g_return_if_fail(memsrc != nullptr);
197 GST_OBJECT_LOCK(memsrc);
198 memsrc->buffer_num = num;
199 GST_OBJECT_UNLOCK(memsrc);
200 }
201
gst_mem_pool_src_is_seekable(GstBaseSrc * basesrc)202 static gboolean gst_mem_pool_src_is_seekable(GstBaseSrc *basesrc)
203 {
204 (void)basesrc;
205 return FALSE;
206 }
207
gst_mem_pool_src_dispose(GObject * object)208 static void gst_mem_pool_src_dispose(GObject *object)
209 {
210 GstMemPoolSrc *memsrc = GST_MEM_POOL_SRC(object);
211 g_return_if_fail(memsrc != nullptr && memsrc->priv != nullptr);
212 auto priv = memsrc->priv;
213
214 GST_OBJECT_LOCK(memsrc);
215 if (memsrc->caps) {
216 gst_caps_unref(memsrc->caps);
217 memsrc->caps = nullptr;
218 }
219 if (priv->notify) {
220 priv->notify(priv->user_data);
221 }
222 priv->user_data = nullptr;
223 priv->notify = nullptr;
224 GST_OBJECT_UNLOCK(memsrc);
225
226 G_OBJECT_CLASS(parent_class)->dispose(object);
227 }
228
gst_mem_pool_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)229 static void gst_mem_pool_src_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
230 {
231 GstMemPoolSrc *memsrc = GST_MEM_POOL_SRC(object);
232 g_return_if_fail(memsrc != nullptr);
233 (void)pspec;
234 switch (prop_id) {
235 case PROP_CAPS:
236 gst_mem_pool_src_set_caps(memsrc, gst_value_get_caps(value));
237 break;
238 case PROP_EMIT_SIGNALS:
239 gst_mem_pool_src_set_emit_signals(memsrc, g_value_get_boolean(value));
240 break;
241 case PROP_BUFFER_SIZE:
242 gst_mem_pool_src_set_buffer_size(memsrc, g_value_get_uint(value));
243 break;
244 case PROP_BUFFER_NUM:
245 gst_mem_pool_src_set_buffer_num(memsrc, g_value_get_uint(value));
246 break;
247 default:
248 break;
249 }
250 }
251
gst_mem_pool_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)252 static void gst_mem_pool_src_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
253 {
254 GstMemPoolSrc *memsrc = GST_MEM_POOL_SRC(object);
255 g_return_if_fail(memsrc != nullptr);
256 g_return_if_fail(value != nullptr);
257 (void)pspec;
258 switch (prop_id) {
259 case PROP_BUFFER_SIZE:
260 g_value_set_uint(value, memsrc->buffer_size);
261 GST_DEBUG_OBJECT(object, "set buffer size: %u", memsrc->buffer_size);
262 break;
263 case PROP_BUFFER_NUM:
264 g_value_set_uint(value, memsrc->buffer_num);
265 GST_DEBUG_OBJECT(object, "set buffer num: %u", memsrc->buffer_num);
266 break;
267 default:
268 break;
269 }
270 }
271
gst_mem_pool_src_query(GstBaseSrc * src,GstQuery * query)272 static gboolean gst_mem_pool_src_query(GstBaseSrc *src, GstQuery *query)
273 {
274 g_return_val_if_fail(src != nullptr, FALSE);
275 g_return_val_if_fail(query != nullptr, FALSE);
276 g_return_val_if_fail(GST_BASE_SRC_CLASS(parent_class) != nullptr, FALSE);
277 switch (GST_QUERY_TYPE(query)) {
278 case GST_QUERY_SCHEDULING: {
279 gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEQUENTIAL, 1, -1, 0);
280 gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH);
281 return TRUE;
282 }
283 default: {
284 return GST_BASE_SRC_CLASS(parent_class)->query(src, query);
285 }
286 }
287 return TRUE;
288 }
289
gst_mem_pool_src_set_callback(GstMemPoolSrc * memsrc,BufferAvailable callback,gpointer user_data,GDestroyNotify notify)290 void gst_mem_pool_src_set_callback(GstMemPoolSrc *memsrc, BufferAvailable callback,
291 gpointer user_data, GDestroyNotify notify)
292 {
293 g_return_if_fail(memsrc != nullptr && memsrc->priv != nullptr);
294 auto priv = memsrc->priv;
295 GST_OBJECT_LOCK(memsrc);
296 priv->user_data = user_data;
297 priv->notify = notify;
298 priv->buffer_available = callback;
299 GST_OBJECT_UNLOCK(memsrc);
300 }
301
302
gst_mem_pool_src_pull_buffer(GstMemPoolSrc * memsrc)303 GstBuffer *gst_mem_pool_src_pull_buffer(GstMemPoolSrc *memsrc)
304 {
305 GST_DEBUG_OBJECT(memsrc, "Pull buffer");
306 g_return_val_if_fail(memsrc != nullptr, nullptr);
307 GstMemPoolSrcClass *memclass = GST_MEM_POOL_SRC_GET_CLASS(memsrc);
308
309 g_return_val_if_fail(memclass != nullptr, nullptr);
310 if (memclass->pull_buffer) {
311 return memclass->pull_buffer(memsrc);
312 }
313 GST_ERROR_OBJECT(memsrc, "there is no pull buffer function");
314 return nullptr;
315 }
316
gst_mem_pool_src_push_buffer(GstMemPoolSrc * memsrc,GstBuffer * buffer)317 GstFlowReturn gst_mem_pool_src_push_buffer(GstMemPoolSrc *memsrc, GstBuffer *buffer)
318 {
319 GST_DEBUG_OBJECT(memsrc, "Push buffer");
320 g_return_val_if_fail(memsrc != nullptr, GST_FLOW_ERROR);
321 GstMemPoolSrcClass *memclass = GST_MEM_POOL_SRC_GET_CLASS(memsrc);
322
323 g_return_val_if_fail(memclass != nullptr, GST_FLOW_ERROR);
324 if (memclass->push_buffer) {
325 return memclass->push_buffer(memsrc, buffer);
326 }
327 GST_ERROR_OBJECT(memsrc, "there is no push buffer function");
328 return GST_FLOW_ERROR;
329 }