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_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_src_parent_class parent_class
28
29 GST_DEBUG_CATEGORY_STATIC(gst_mem_src_debug_category);
30 #define GST_CAT_DEFAULT gst_mem_src_debug_category
31
32 struct _GstMemSrcPrivate {
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(GstMemSrc, gst_mem_src, GST_TYPE_BASE_SRC);
57
58 static guint gst_mem_src_signals[LAST_SIGNAL] = { 0 };
59 static void gst_mem_src_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
60 static void gst_mem_src_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
61 static gboolean gst_mem_src_query(GstBaseSrc *src, GstQuery *query);
62 static gboolean gst_mem_src_is_seekable(GstBaseSrc *basesrc);
63 static gboolean gst_mem_src_negotiate(GstBaseSrc *basesrc);
64 static void gst_mem_src_dispose(GObject *object);
65
gst_mem_src_class_init(GstMemSrcClass * klass)66 static void gst_mem_src_class_init(GstMemSrcClass *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_src_debug_category, "memsrc", 0, "mem src base class");
72 gobject_class->set_property = gst_mem_src_set_property;
73 gobject_class->get_property = gst_mem_src_get_property;
74 gobject_class->dispose = gst_mem_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_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_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(GstMemSrcClass, pull_buffer), nullptr, nullptr, nullptr,
104 GST_TYPE_BUFFER, 0, G_TYPE_NONE);
105
106 gst_mem_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(GstMemSrcClass, push_buffer), nullptr, nullptr, nullptr,
110 GST_TYPE_FLOW_RETURN, 1, GST_TYPE_BUFFER);
111
112 gstbasesrc_class->is_seekable = gst_mem_src_is_seekable;
113 gstbasesrc_class->query = gst_mem_src_query;
114 gstbasesrc_class->negotiate = gst_mem_src_negotiate;
115 }
116
gst_mem_src_init(GstMemSrc * memsrc)117 static void gst_mem_src_init(GstMemSrc *memsrc)
118 {
119 g_return_if_fail(memsrc != nullptr);
120 auto priv = reinterpret_cast<GstMemSrcPrivate *>(gst_mem_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_src_buffer_available(GstMemSrc * memsrc)133 GstFlowReturn gst_mem_src_buffer_available(GstMemSrc *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 if (priv->buffer_available) {
140 ret = priv->buffer_available(memsrc, priv->user_data);
141 } else {
142 GST_OBJECT_LOCK(memsrc);
143 gboolean emit = priv->emit_signals;
144 GST_OBJECT_UNLOCK(memsrc);
145 if (emit) {
146 g_signal_emit(memsrc, gst_mem_src_signals[SIGNAL_BUFFER_AVAILABLE], 0, &ret);
147 }
148 }
149 return ret;
150 }
151
gst_mem_src_negotiate(GstBaseSrc * basesrc)152 static gboolean gst_mem_src_negotiate(GstBaseSrc *basesrc)
153 {
154 g_return_val_if_fail(basesrc != nullptr, FALSE);
155 GstMemSrc *memsrc = GST_MEM_SRC(basesrc);
156 return gst_base_src_set_caps(basesrc, memsrc->caps);
157 }
158
gst_mem_src_set_caps(GstMemSrc * memsrc,const GstCaps * caps)159 void gst_mem_src_set_caps(GstMemSrc *memsrc, const GstCaps *caps)
160 {
161 g_return_if_fail(memsrc != nullptr);
162 GST_OBJECT_LOCK(memsrc);
163 GstCaps *old_caps = memsrc->caps;
164 if (caps != nullptr) {
165 memsrc->caps = gst_caps_copy(caps);
166 } else {
167 memsrc->caps = nullptr;
168 }
169 if (old_caps != nullptr) {
170 gst_caps_unref(old_caps);
171 }
172 GST_OBJECT_UNLOCK(memsrc);
173 }
174
gst_mem_src_set_emit_signals(GstMemSrc * memsrc,gboolean emit)175 void gst_mem_src_set_emit_signals(GstMemSrc *memsrc, gboolean emit)
176 {
177 g_return_if_fail(memsrc != nullptr && memsrc->priv != nullptr);
178 auto priv = memsrc->priv;
179 GST_OBJECT_LOCK(memsrc);
180 priv->emit_signals = emit;
181 GST_OBJECT_UNLOCK(memsrc);
182 }
183
gst_mem_src_set_buffer_size(GstMemSrc * memsrc,guint size)184 void gst_mem_src_set_buffer_size(GstMemSrc *memsrc, guint size)
185 {
186 g_return_if_fail(memsrc != nullptr);
187 GST_OBJECT_LOCK(memsrc);
188 memsrc->buffer_size = size;
189 GST_OBJECT_UNLOCK(memsrc);
190 }
191
gst_mem_src_set_buffer_num(GstMemSrc * memsrc,guint num)192 void gst_mem_src_set_buffer_num(GstMemSrc *memsrc, guint num)
193 {
194 g_return_if_fail(memsrc != nullptr);
195 GST_OBJECT_LOCK(memsrc);
196 memsrc->buffer_num = num;
197 GST_OBJECT_UNLOCK(memsrc);
198 }
199
gst_mem_src_is_seekable(GstBaseSrc * basesrc)200 static gboolean gst_mem_src_is_seekable(GstBaseSrc *basesrc)
201 {
202 (void)basesrc;
203 return FALSE;
204 }
205
gst_mem_src_dispose(GObject * object)206 static void gst_mem_src_dispose(GObject *object)
207 {
208 GstMemSrc *memsrc = GST_MEM_SRC(object);
209 g_return_if_fail(memsrc != nullptr && memsrc->priv != nullptr);
210 auto priv = memsrc->priv;
211
212 GST_OBJECT_LOCK(memsrc);
213 if (memsrc->caps) {
214 gst_caps_unref(memsrc->caps);
215 memsrc->caps = nullptr;
216 }
217 if (priv->notify) {
218 priv->notify(priv->user_data);
219 }
220 priv->user_data = nullptr;
221 priv->notify = nullptr;
222 GST_OBJECT_UNLOCK(memsrc);
223
224 G_OBJECT_CLASS(parent_class)->dispose(object);
225 }
226
gst_mem_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)227 static void gst_mem_src_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
228 {
229 GstMemSrc *memsrc = GST_MEM_SRC(object);
230 g_return_if_fail(memsrc != nullptr);
231 (void)pspec;
232 switch (prop_id) {
233 case PROP_CAPS:
234 gst_mem_src_set_caps(memsrc, gst_value_get_caps(value));
235 break;
236 case PROP_EMIT_SIGNALS:
237 gst_mem_src_set_emit_signals(memsrc, g_value_get_boolean(value));
238 break;
239 case PROP_BUFFER_SIZE:
240 gst_mem_src_set_buffer_size(memsrc, g_value_get_uint(value));
241 break;
242 case PROP_BUFFER_NUM:
243 gst_mem_src_set_buffer_num(memsrc, g_value_get_uint(value));
244 break;
245 default:
246 break;
247 }
248 }
249
gst_mem_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)250 static void gst_mem_src_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
251 {
252 GstMemSrc *memsrc = GST_MEM_SRC(object);
253 g_return_if_fail(memsrc != nullptr);
254 g_return_if_fail(value != nullptr);
255 (void)pspec;
256 switch (prop_id) {
257 case PROP_BUFFER_SIZE:
258 g_value_set_uint(value, memsrc->buffer_size);
259 GST_DEBUG_OBJECT(object, "set buffer size: %u", memsrc->buffer_size);
260 break;
261 case PROP_BUFFER_NUM:
262 g_value_set_uint(value, memsrc->buffer_num);
263 GST_DEBUG_OBJECT(object, "set buffer num: %u", memsrc->buffer_num);
264 break;
265 default:
266 break;
267 }
268 }
269
gst_mem_src_query(GstBaseSrc * src,GstQuery * query)270 static gboolean gst_mem_src_query(GstBaseSrc *src, GstQuery *query)
271 {
272 g_return_val_if_fail(src != nullptr, FALSE);
273 g_return_val_if_fail(query != nullptr, FALSE);
274 g_return_val_if_fail(GST_BASE_SRC_CLASS(parent_class) != nullptr, FALSE);
275 switch (GST_QUERY_TYPE(query)) {
276 case GST_QUERY_SCHEDULING: {
277 gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEQUENTIAL, 1, -1, 0);
278 gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH);
279 return TRUE;
280 }
281 default: {
282 return GST_BASE_SRC_CLASS(parent_class)->query(src, query);
283 }
284 }
285 return TRUE;
286 }
287
gst_mem_src_set_callback(GstMemSrc * memsrc,BufferAvailable callback,gpointer user_data,GDestroyNotify notify)288 void gst_mem_src_set_callback(GstMemSrc *memsrc, BufferAvailable callback,
289 gpointer user_data, GDestroyNotify notify)
290 {
291 g_return_if_fail(memsrc != nullptr && memsrc->priv != nullptr);
292 auto priv = memsrc->priv;
293 GST_OBJECT_LOCK(memsrc);
294 priv->user_data = user_data;
295 priv->notify = notify;
296 priv->buffer_available = callback;
297 GST_OBJECT_UNLOCK(memsrc);
298 }
299
300
gst_mem_src_pull_buffer(GstMemSrc * memsrc)301 GstBuffer *gst_mem_src_pull_buffer(GstMemSrc *memsrc)
302 {
303 GST_DEBUG_OBJECT(memsrc, "Pull buffer");
304 g_return_val_if_fail(memsrc != nullptr, nullptr);
305 GstMemSrcClass *memclass = GST_MEM_SRC_GET_CLASS(memsrc);
306
307 g_return_val_if_fail(memclass != nullptr, nullptr);
308 if (memclass->pull_buffer) {
309 return memclass->pull_buffer(memsrc);
310 }
311 GST_ERROR_OBJECT(memsrc, "there is no pull buffer function");
312 return nullptr;
313 }
314
gst_mem_src_push_buffer(GstMemSrc * memsrc,GstBuffer * buffer)315 GstFlowReturn gst_mem_src_push_buffer(GstMemSrc *memsrc, GstBuffer *buffer)
316 {
317 GST_DEBUG_OBJECT(memsrc, "Push buffer");
318 g_return_val_if_fail(memsrc != nullptr, GST_FLOW_ERROR);
319 GstMemSrcClass *memclass = GST_MEM_SRC_GET_CLASS(memsrc);
320
321 g_return_val_if_fail(memclass != nullptr, GST_FLOW_ERROR);
322 if (memclass->push_buffer) {
323 return memclass->push_buffer(memsrc, buffer);
324 }
325 GST_ERROR_OBJECT(memsrc, "there is no push buffer function");
326 return GST_FLOW_ERROR;
327 }