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_surface_src.h"
17 #include <gst/video/video.h>
18 #include <sync_fence.h>
19 #include "gst_consumer_surface_pool.h"
20 #include "gst_consumer_surface_allocator.h"
21 #include "media_errors.h"
22 #include "surface_buffer.h"
23 #include "buffer_type_meta.h"
24 #include "scope_guard.h"
25 #include "display_type.h"
26 #include "param_wrapper.h"
27 #include "media_log.h"
28
29 #define gst_surface_src_parent_class parent_class
30 using namespace OHOS;
31 namespace {
32 constexpr guint DEFAULT_SURFACE_QUEUE_SIZE = 4;
33 constexpr int32_t DEFAULT_SURFACE_SIZE = 1024 * 1024;
34 constexpr int32_t DEFAULT_VIDEO_WIDTH = 1920;
35 constexpr int32_t DEFAULT_VIDEO_HEIGHT = 1080;
36 constexpr uint32_t STRIDE_ALIGN = 8;
37 }
38
39 GST_DEBUG_CATEGORY_STATIC(gst_surface_src_debug_category);
40 #define GST_CAT_DEFAULT gst_surface_src_debug_category
41
42 static GstStaticPadTemplate gst_src_template =
43 GST_STATIC_PAD_TEMPLATE("src",
44 GST_PAD_SRC,
45 GST_PAD_ALWAYS,
46 GST_STATIC_CAPS(GST_VIDEO_CAPS_MAKE(GST_VIDEO_FORMATS_ALL)));
47
48 enum {
49 PROP_0,
50 PROP_SURFACE,
51 PROP_SURFACE_STRIDE,
52 PROP_SUSPEND,
53 PROP_REPEAT,
54 PROP_MAX_FRAME_RATE,
55 PROP_NOTIFY_EOS,
56 };
57
58 G_DEFINE_TYPE(GstSurfaceSrc, gst_surface_src, GST_TYPE_MEM_SRC);
59
60 static void gst_surface_src_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
61 static void gst_surface_src_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
62 static GstStateChangeReturn gst_surface_src_change_state(GstElement *element, GstStateChange transition);
63 static gboolean gst_surface_src_create_surface(GstSurfaceSrc *surfacesrc);
64 static GstBufferPool *gst_surface_src_create_pool(GstMemSrc *memsrc);
65 static gboolean gst_surface_src_init_pool(GstSurfaceSrc *surfacesrc);
66 static void gst_surface_src_destroy_surface(GstSurfaceSrc *src);
67 static void gst_surface_src_destroy_pool(GstSurfaceSrc *src);
68 static gboolean gst_surface_src_decide_allocation(GstBaseSrc *basesrc, GstQuery *query);
69 static GstFlowReturn gst_surface_src_fill(GstBaseSrc *src, guint64 offset, guint size, GstBuffer *buf);
70 static void gst_surface_src_init_surface(GstSurfaceSrc *src);
71 static gboolean gst_surface_src_send_event(GstElement *element, GstEvent *event);
72 static void gst_surface_mem_src_dump_buffer(GstBaseSrc *self, GstBuffer *buffer);
73 static void gst_surface_mem_src_dump_from_sys_param(GstSurfaceSrc *src);
74
gst_surface_src_class_init(GstSurfaceSrcClass * klass)75 static void gst_surface_src_class_init(GstSurfaceSrcClass *klass)
76 {
77 g_return_if_fail(klass != nullptr);
78 GObjectClass *gobject_class = reinterpret_cast<GObjectClass*>(klass);
79 GstElementClass *gstelement_class = reinterpret_cast<GstElementClass*>(klass);
80 GstBaseSrcClass *gstbasesrc_class = reinterpret_cast<GstBaseSrcClass*>(klass);
81 GstMemSrcClass *gstmemsrc_class = reinterpret_cast<GstMemSrcClass*>(klass);
82 GST_DEBUG_CATEGORY_INIT(gst_surface_src_debug_category, "surfacepoolsrc", 0, "surface pool src base class");
83 gobject_class->get_property = gst_surface_src_get_property;
84 gobject_class->set_property = gst_surface_src_set_property;
85
86 g_object_class_install_property(gobject_class, PROP_SURFACE,
87 g_param_spec_pointer("surface", "Surface", "Surface for buffer",
88 (GParamFlags)(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
89
90 g_object_class_install_property(gobject_class, PROP_SURFACE_STRIDE,
91 g_param_spec_uint("surface-stride", "surface stride",
92 "surface buffer stride", 0, G_MAXINT32, STRIDE_ALIGN,
93 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
94
95 g_object_class_install_property(gobject_class, PROP_SUSPEND,
96 g_param_spec_boolean("suspend", "Suspend surface", "Suspend surface",
97 FALSE, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
98
99 g_object_class_install_property(gobject_class, PROP_REPEAT,
100 g_param_spec_uint("repeat", "Repeat frame", "Repeat previous frame after given milliseconds",
101 0, G_MAXUINT32, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
102
103 g_object_class_install_property(gobject_class, PROP_MAX_FRAME_RATE,
104 g_param_spec_uint("max-framerate", "Max frame rate", "Max frame rate",
105 0, G_MAXUINT32, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
106
107 g_object_class_install_property(gobject_class, PROP_NOTIFY_EOS,
108 g_param_spec_boolean("notify-eos", "notify eos", "Need notify eos",
109 FALSE, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
110
111 gstelement_class->change_state = gst_surface_src_change_state;
112 gstelement_class->send_event = gst_surface_src_send_event;
113 gstbasesrc_class->fill = gst_surface_src_fill;
114 gstbasesrc_class->decide_allocation = gst_surface_src_decide_allocation;
115 gstmemsrc_class->create_pool = gst_surface_src_create_pool;
116 gst_element_class_set_static_metadata(gstelement_class,
117 "surface mem source", "Source/Surface/Pool",
118 "Retrieve frame from surface buffer queue with raw data", "OpenHarmony");
119
120 gst_element_class_add_static_pad_template(gstelement_class, &gst_src_template);
121 }
122
gst_surface_src_init(GstSurfaceSrc * surfacesrc)123 static void gst_surface_src_init(GstSurfaceSrc *surfacesrc)
124 {
125 GST_DEBUG_OBJECT(surfacesrc, "Init, id = %d", static_cast<int32_t>(FAKE_POINTER(surfacesrc)));
126 g_return_if_fail(surfacesrc != nullptr);
127 surfacesrc->pool = nullptr;
128 surfacesrc->stride = STRIDE_ALIGN;
129 surfacesrc->need_flush = FALSE;
130 surfacesrc->flushing = FALSE;
131 gst_surface_mem_src_dump_from_sys_param(surfacesrc);
132 }
133
gst_surface_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)134 static void gst_surface_src_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
135 {
136 GstSurfaceSrc *src = GST_SURFACE_SRC(object);
137 g_return_if_fail(src != nullptr);
138 g_return_if_fail(value != nullptr);
139 (void)pspec;
140 switch (prop_id) {
141 case PROP_SURFACE:
142 g_value_set_pointer(value, src->producerSurface.GetRefPtr());
143 break;
144 case PROP_SURFACE_STRIDE:
145 g_value_set_uint(value, src->stride);
146 break;
147 default:
148 break;
149 }
150 }
151
gst_surface_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)152 static void gst_surface_src_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
153 {
154 GstSurfaceSrc *src = GST_SURFACE_SRC(object);
155 g_return_if_fail(src != nullptr && value != nullptr);
156 (void)pspec;
157 switch (prop_id) {
158 case PROP_SURFACE_STRIDE:
159 src->stride = g_value_get_uint(value);
160 if (src->stride > INT32_MAX) {
161 src->stride = STRIDE_ALIGN;
162 }
163 break;
164 case PROP_SUSPEND:
165 g_return_if_fail(src->pool != nullptr);
166 g_object_set(src->pool, "suspend", g_value_get_boolean(value), nullptr);
167 break;
168 case PROP_REPEAT:
169 g_return_if_fail(src->pool != nullptr);
170 g_object_set(src->pool, "repeat", g_value_get_uint(value), nullptr);
171 break;
172 case PROP_MAX_FRAME_RATE:
173 g_return_if_fail(src->pool != nullptr);
174 g_object_set(src->pool, "max-framerate", g_value_get_uint(value), nullptr);
175 break;
176 case PROP_NOTIFY_EOS:
177 g_return_if_fail(src->pool != nullptr);
178 g_object_set(src->pool, "notify-eos", g_value_get_boolean(value), nullptr);
179 break;
180 default:
181 break;
182 }
183 }
184
gst_surface_src_fill(GstBaseSrc * src,guint64 offset,guint size,GstBuffer * buf)185 static GstFlowReturn gst_surface_src_fill(GstBaseSrc *src, guint64 offset, guint size, GstBuffer *buf)
186 {
187 (void)src;
188 (void)offset;
189 (void)size;
190 gst_surface_mem_src_dump_buffer(src, buf);
191
192 GstBufferTypeMeta *meta = gst_buffer_get_buffer_type_meta(buf);
193 if (meta != nullptr && (meta->bufferFlag & BUFFER_FLAG_EOS)) {
194 GST_DEBUG_OBJECT(src, "EOS buffer");
195 return GST_FLOW_EOS;
196 }
197 return GST_FLOW_OK;
198 }
199
gst_surface_src_change_state(GstElement * element,GstStateChange transition)200 static GstStateChangeReturn gst_surface_src_change_state(GstElement *element, GstStateChange transition)
201 {
202 GstSurfaceSrc *surfacesrc = GST_SURFACE_SRC(element);
203 g_return_val_if_fail(surfacesrc != nullptr, GST_STATE_CHANGE_FAILURE);
204 switch (transition) {
205 case GST_STATE_CHANGE_NULL_TO_READY:
206 g_return_val_if_fail(gst_surface_src_create_surface(surfacesrc) == TRUE, GST_STATE_CHANGE_FAILURE);
207 g_return_val_if_fail(gst_surface_src_init_pool(surfacesrc) == TRUE, GST_STATE_CHANGE_FAILURE);
208 break;
209 case GST_STATE_CHANGE_READY_TO_PAUSED:
210 gst_surface_src_init_surface(surfacesrc);
211 break;
212 default:
213 break;
214 }
215 GstStateChangeReturn ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
216
217 switch (transition) {
218 case GST_STATE_CHANGE_READY_TO_NULL:
219 gst_surface_src_destroy_pool(surfacesrc);
220 gst_surface_src_destroy_surface(surfacesrc);
221 if (surfacesrc->dump.enable_dump == TRUE) {
222 if (surfacesrc->dump.dump_file != nullptr) {
223 fclose(surfacesrc->dump.dump_file);
224 surfacesrc->dump.dump_file = nullptr;
225 }
226 }
227 GST_OBJECT_LOCK(surfacesrc);
228 surfacesrc->need_flush = FALSE;
229 GST_OBJECT_UNLOCK(surfacesrc);
230 break;
231 default:
232 break;
233 }
234
235 return ret;
236 }
237
gst_surface_src_create_surface(GstSurfaceSrc * surfacesrc)238 static gboolean gst_surface_src_create_surface(GstSurfaceSrc *surfacesrc)
239 {
240 g_return_val_if_fail(surfacesrc != nullptr, FALSE);
241 sptr<Surface> consumerSurface = Surface::CreateSurfaceAsConsumer();
242 g_return_val_if_fail(consumerSurface != nullptr, FALSE);
243 sptr<IBufferProducer> producer = consumerSurface->GetProducer();
244 g_return_val_if_fail(producer != nullptr, FALSE);
245 sptr<Surface> producerSurface = Surface::CreateSurfaceAsProducer(producer);
246 g_return_val_if_fail(producerSurface != nullptr, FALSE);
247 surfacesrc->consumerSurface = consumerSurface;
248 surfacesrc->producerSurface = producerSurface;
249
250 SurfaceError ret = surfacesrc->consumerSurface->SetQueueSize(DEFAULT_SURFACE_QUEUE_SIZE);
251 if (ret != SURFACE_ERROR_OK) {
252 GST_WARNING_OBJECT(surfacesrc, "set queue size fail");
253 }
254 GST_DEBUG_OBJECT(surfacesrc, "create surface");
255 return TRUE;
256 }
257
gst_surface_src_send_event(GstElement * element,GstEvent * event)258 static gboolean gst_surface_src_send_event(GstElement *element, GstEvent *event)
259 {
260 GstSurfaceSrc *surfacesrc = GST_SURFACE_SRC(element);
261 g_return_val_if_fail(surfacesrc != nullptr, FALSE);
262 g_return_val_if_fail(event != nullptr, FALSE);
263 GST_INFO_OBJECT(surfacesrc, "New event %s", GST_EVENT_TYPE_NAME(event));
264
265 switch (GST_EVENT_TYPE(event)) {
266 case GST_EVENT_FLUSH_START:
267 if (surfacesrc->need_flush == FALSE) {
268 GST_INFO_OBJECT(surfacesrc, "No need flushing");
269 surfacesrc->flushing = FALSE;
270 return TRUE;
271 }
272 surfacesrc->flushing = TRUE;
273 break;
274 case GST_EVENT_FLUSH_STOP:
275 if (surfacesrc->flushing == FALSE) {
276 GST_INFO_OBJECT(surfacesrc, "No flush start");
277 return TRUE;
278 }
279 surfacesrc->flushing = FALSE;
280 break;
281 default:
282 break;
283 }
284
285 return GST_ELEMENT_CLASS(parent_class)->send_event(element, event);
286 }
287
gst_surface_src_create_pool(GstMemSrc * memsrc)288 static GstBufferPool *gst_surface_src_create_pool(GstMemSrc *memsrc)
289 {
290 (void)memsrc;
291 return gst_consumer_surface_pool_new();
292 }
293
gst_surface_src_init_pool(GstSurfaceSrc * surfacesrc)294 static gboolean gst_surface_src_init_pool(GstSurfaceSrc *surfacesrc)
295 {
296 GstMemSrcClass *memsrcclass = GST_MEM_SRC_GET_CLASS(surfacesrc);
297 g_return_val_if_fail(memsrcclass != nullptr, FALSE);
298 GstAllocationParams params;
299 GstBufferPool *pool = nullptr;
300 gst_allocation_params_init(¶ms);
301
302 if (memsrcclass->create_pool) {
303 GstMemSrc *memsrc = GST_MEM_SRC(surfacesrc);
304 pool = memsrcclass->create_pool(memsrc);
305 }
306
307 g_return_val_if_fail(pool != nullptr, FALSE);
308 ON_SCOPE_EXIT(0) { gst_object_unref(pool); };
309 GstAllocator *allocator = gst_consumer_surface_allocator_new();
310 g_return_val_if_fail(allocator != nullptr, FALSE);
311 ON_SCOPE_EXIT(1) { gst_object_unref(allocator); };
312 gst_consumer_surface_pool_set_surface(pool, surfacesrc->consumerSurface);
313 gst_consumer_surface_allocator_set_surface(allocator, surfacesrc->consumerSurface);
314 // init pool config
315 GstStructure *config = gst_buffer_pool_get_config(pool);
316 gst_buffer_pool_config_set_allocator(config, allocator, ¶ms);
317 g_return_val_if_fail(gst_buffer_pool_set_config(pool, config) != TRUE, FALSE);
318 surfacesrc->pool = pool;
319 CANCEL_SCOPE_EXIT_GUARD(0);
320 GST_DEBUG_OBJECT(surfacesrc, "create surface pool");
321 return TRUE;
322 }
323
gst_surface_src_destroy_pool(GstSurfaceSrc * src)324 static void gst_surface_src_destroy_pool(GstSurfaceSrc *src)
325 {
326 gst_object_unref(src->pool);
327 src->pool = nullptr;
328 }
329
gst_surface_src_destroy_surface(GstSurfaceSrc * src)330 static void gst_surface_src_destroy_surface(GstSurfaceSrc *src)
331 {
332 src->consumerSurface = nullptr;
333 src->producerSurface = nullptr;
334 }
335
gst_surface_src_init_surface(GstSurfaceSrc * src)336 static void gst_surface_src_init_surface(GstSurfaceSrc *src)
337 {
338 g_return_if_fail(src != nullptr && src->consumerSurface != nullptr);
339 // The internal function do not need judge whether it is empty
340 GstMemSrc *memsrc = GST_MEM_SRC(src);
341 sptr<Surface> surface = src->consumerSurface;
342 guint width = DEFAULT_VIDEO_WIDTH;
343 guint height = DEFAULT_VIDEO_HEIGHT;
344 GST_OBJECT_LOCK(memsrc);
345 if (memsrc->caps != nullptr) {
346 GstVideoInfo info;
347 gst_video_info_init(&info);
348 gst_video_info_from_caps(&info, memsrc->caps);
349 width = static_cast<guint>(info.width);
350 height = static_cast<guint>(info.height);
351 }
352 GST_OBJECT_UNLOCK(memsrc);
353 SurfaceError ret = surface->SetUserData("video_width", std::to_string(width));
354 if (ret != SURFACE_ERROR_OK) {
355 GST_WARNING_OBJECT(src, "Set video width fail");
356 }
357 ret = surface->SetUserData("video_height", std::to_string(height));
358 if (ret != SURFACE_ERROR_OK) {
359 GST_WARNING_OBJECT(src, "Set video height fail");
360 }
361 ret = surface->SetUserData("surface_size", std::to_string(DEFAULT_SURFACE_SIZE));
362 if (ret != SURFACE_ERROR_OK) {
363 GST_WARNING_OBJECT(src, "Set surface size fail");
364 }
365 ret = surface->SetDefaultWidthAndHeight(width, height);
366 if (ret != SURFACE_ERROR_OK) {
367 GST_WARNING_OBJECT(src, "Set surface width and height fail");
368 }
369 }
370
gst_surface_src_get_pool(GstSurfaceSrc * surfacesrc,GstQuery * query,GstCaps * outcaps)371 static gboolean gst_surface_src_get_pool(GstSurfaceSrc *surfacesrc, GstQuery *query, GstCaps *outcaps)
372 {
373 g_return_val_if_fail(surfacesrc != nullptr && query != nullptr && surfacesrc->consumerSurface != nullptr, FALSE);
374 if (surfacesrc->pool == nullptr) {
375 return FALSE;
376 }
377 GstMemSrc *memsrc = GST_MEM_SRC(surfacesrc);
378 guint min_buf = surfacesrc->consumerSurface->GetQueueSize();
379 guint max_buf = min_buf;
380 memsrc->buffer_num = max_buf;
381 gboolean is_video = gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, nullptr);
382 if (is_video) {
383 // when video need update size
384 GstVideoInfo info;
385 gst_video_info_init(&info);
386 gst_video_info_from_caps(&info, outcaps);
387 if (info.size != 0) {
388 memsrc->buffer_size = info.size;
389 }
390 }
391 GST_INFO_OBJECT(surfacesrc, "update buffer num %u", memsrc->buffer_num);
392 GstStructure *config = gst_buffer_pool_get_config(surfacesrc->pool);
393 if (is_video) {
394 gst_buffer_pool_config_add_option(config, GST_BUFFER_POOL_OPTION_VIDEO_META);
395 }
396 gst_buffer_pool_config_set_params(config, outcaps, memsrc->buffer_size, min_buf, max_buf);
397 if (gst_buffer_pool_set_config(surfacesrc->pool, config) != TRUE) {
398 GST_WARNING_OBJECT(surfacesrc, "set config failed");
399 }
400
401 if (gst_query_get_n_allocation_pools(query) > 0) {
402 gst_query_set_nth_allocation_pool(query, 0, surfacesrc->pool, memsrc->buffer_num, min_buf, max_buf);
403 } else {
404 gst_query_add_allocation_pool(query, surfacesrc->pool, memsrc->buffer_num, min_buf, max_buf);
405 }
406
407 GST_DEBUG_OBJECT(surfacesrc, "set surface pool success");
408 return TRUE;
409 }
410
gst_surface_src_decide_allocation(GstBaseSrc * basesrc,GstQuery * query)411 static gboolean gst_surface_src_decide_allocation(GstBaseSrc *basesrc, GstQuery *query)
412 {
413 GstSurfaceSrc *surfacesrc = GST_SURFACE_SRC(basesrc);
414 g_return_val_if_fail(basesrc != nullptr && query != nullptr, FALSE);
415 GST_OBJECT_LOCK(surfacesrc);
416 surfacesrc->need_flush = TRUE;
417 GST_OBJECT_UNLOCK(surfacesrc);
418 GstCaps *outcaps = nullptr;
419 GstBufferPool *pool = nullptr;
420 guint size = 0;
421 guint min_buf = DEFAULT_SURFACE_QUEUE_SIZE;
422 guint max_buf = DEFAULT_SURFACE_QUEUE_SIZE;
423
424 // get caps and save to video info
425 gst_query_parse_allocation(query, &outcaps, nullptr);
426 // get pool and pool info from down stream
427 if (gst_query_get_n_allocation_pools(query) > 0) {
428 gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min_buf, &max_buf);
429 }
430 auto caps_struct = gst_caps_get_structure(outcaps, 0);
431 auto mediaType = gst_structure_get_name(caps_struct);
432 gboolean isVideo = g_str_has_prefix(mediaType, "video/");
433 if (isVideo) {
434 gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, nullptr);
435 }
436 GstVideoInfo info;
437 gst_video_info_init(&info);
438 gst_video_info_from_caps(&info, outcaps);
439 size = info.size;
440
441 // we use our own pool
442 if (pool != nullptr) {
443 gst_query_set_nth_allocation_pool(query, 0, nullptr, 0, 0, 0);
444 gst_object_unref(pool);
445 pool = nullptr;
446 }
447 if (gst_surface_src_get_pool(surfacesrc, query, outcaps)) {
448 return TRUE;
449 }
450 return FALSE;
451 }
452
gst_surface_mem_src_dump_buffer(GstBaseSrc * self,GstBuffer * buffer)453 static void gst_surface_mem_src_dump_buffer(GstBaseSrc *self, GstBuffer *buffer)
454 {
455 g_return_if_fail(self != nullptr);
456 GstSurfaceSrc *src = GST_SURFACE_SRC(self);
457 g_return_if_fail(src != nullptr);
458 g_return_if_fail(buffer != nullptr);
459
460 if (src->dump.enable_dump == FALSE) {
461 return;
462 }
463
464 GST_DEBUG_OBJECT(src, "Dump surface src buffer");
465 std::string input_dump_file = "/data/media/surface-in-" +
466 std::to_string(static_cast<int32_t>(FAKE_POINTER(self))) + ".yuv";
467 if (src->dump.dump_file == nullptr) {
468 src->dump.dump_file = fopen(input_dump_file.c_str(), "wb+");
469 }
470 if (src->dump.dump_file == nullptr) {
471 GST_ERROR_OBJECT(self, "open file failed");
472 return;
473 }
474 GstMapInfo info = GST_MAP_INFO_INIT;
475 g_return_if_fail(gst_buffer_map(buffer, &info, GST_MAP_READ));
476 (void)fwrite(info.data, info.size, 1, src->dump.dump_file);
477 (void)fflush(src->dump.dump_file);
478 gst_buffer_unmap(buffer, &info);
479 }
480
gst_surface_mem_src_dump_from_sys_param(GstSurfaceSrc * src)481 static void gst_surface_mem_src_dump_from_sys_param(GstSurfaceSrc *src)
482 {
483 std::string dump_enable;
484 src->dump.enable_dump = FALSE;
485 int32_t res = OHOS::system::GetStringParameter("sys.media.dump.surfacesrc.enable", dump_enable, "");
486 if (res != 0 || dump_enable.empty()) {
487 GST_DEBUG_OBJECT(src, "sys.media.dump.surfacesrc.enable");
488 return;
489 }
490 GST_DEBUG_OBJECT(src, "sys.media.dump.surfacesrc.enable=%s", dump_enable.c_str());
491
492 if (dump_enable == "true") {
493 src->dump.enable_dump = TRUE;
494 }
495 }