• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_mem_sink.h"
17 #include <cinttypes>
18 #include "surface.h"
19 #include "gst_producer_surface_pool.h"
20 #include "buffer_type_meta.h"
21 #include "media_log.h"
22 #include "param_wrapper.h"
23 #include "scope_guard.h"
24 #include "media_dfx.h"
25 #include "av_common.h"
26 
27 using namespace OHOS;
28 using namespace OHOS::Media;
29 
30 struct _GstSurfaceMemSinkPrivate {
31     OHOS::sptr<OHOS::Surface> surface;
32     GstProducerSurfacePool *pool;
33     guint rotation;
34 };
35 
36 enum {
37     PROP_0,
38     PROP_SURFACE,
39     PROP_SURFACE_POOL,
40     PROP_CACHE_BUFFERS_NUM,
41     PROP_PERFORMANCE_MODE,
42     PROP_VIDEO_SCALE_TYPE,
43     PROP_VIDEO_ROTATION,
44 };
45 
46 static GstStaticPadTemplate g_sinktemplate = GST_STATIC_PAD_TEMPLATE("sink",
47     GST_PAD_SINK,
48     GST_PAD_ALWAYS,
49     GST_STATIC_CAPS_ANY);
50 
51 static void gst_surface_mem_sink_dispose(GObject *obj);
52 static void gst_surface_mem_sink_finalize(GObject *obj);
53 static void gst_surface_mem_sink_set_property(GObject *object, guint propId, const GValue *value, GParamSpec *pspec);
54 static void gst_surface_mem_sink_get_property(GObject *object, guint propId, GValue *value, GParamSpec *pspec);
55 static gboolean gst_surface_mem_sink_do_propose_allocation(GstMemSink *memsink, GstQuery *query);
56 static GstFlowReturn gst_surface_mem_sink_do_app_render(GstMemSink *memsink, GstBuffer *buffer, bool is_preroll);
57 static void gst_surface_mem_sink_dump_from_sys_param(GstSurfaceMemSink *self);
58 static void gst_surface_mem_sink_dump_buffer(GstSurfaceMemSink *self, GstBuffer *buffer);
59 static GstStateChangeReturn gst_surface_mem_sink_change_state(GstElement *element, GstStateChange transition);
60 static gboolean gst_surface_mem_sink_event(GstBaseSink *bsink, GstEvent *event);
61 static GstFlowReturn gst_surface_mem_sink_subclass_do_app_render(GstSurfaceMemSink *sink,
62     GstBuffer *buffer, bool is_preroll);
63 
64 #define gst_surface_mem_sink_parent_class parent_class
65 G_DEFINE_TYPE_WITH_CODE(GstSurfaceMemSink, gst_surface_mem_sink,
66                         GST_TYPE_MEM_SINK, G_ADD_PRIVATE(GstSurfaceMemSink));
67 
68 GST_DEBUG_CATEGORY_STATIC(gst_surface_mem_sink_debug_category);
69 #define GST_CAT_DEFAULT gst_surface_mem_sink_debug_category
70 
gst_surface_mem_sink_class_init(GstSurfaceMemSinkClass * klass)71 static void gst_surface_mem_sink_class_init(GstSurfaceMemSinkClass *klass)
72 {
73     g_return_if_fail(klass != nullptr);
74 
75     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
76     GstMemSinkClass *mem_sink_class = GST_MEM_SINK_CLASS(klass);
77     GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
78     GstBaseSinkClass *base_sink_class = GST_BASE_SINK_CLASS(klass);
79 
80     gst_element_class_add_static_pad_template(element_class, &g_sinktemplate);
81 
82     gobject_class->dispose = gst_surface_mem_sink_dispose;
83     gobject_class->finalize = gst_surface_mem_sink_finalize;
84     gobject_class->set_property = gst_surface_mem_sink_set_property;
85     gobject_class->get_property = gst_surface_mem_sink_get_property;
86     element_class->change_state = gst_surface_mem_sink_change_state;
87 
88     gst_element_class_set_static_metadata(element_class,
89         "SurfaceMemSink", "Sink/Video",
90         "Output to surface buffer and allow the application to get access to the surface buffer",
91         "OpenHarmony");
92 
93     g_object_class_install_property(gobject_class, PROP_SURFACE,
94         g_param_spec_pointer("surface", "Surface",
95             "Surface for rendering output",
96             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
97 
98     g_object_class_install_property(gobject_class, PROP_SURFACE_POOL,
99         g_param_spec_pointer("surface-pool", "Surface Pool",
100             "Surface pool for rendering output buffers",
101             (GParamFlags)(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
102 
103     g_object_class_install_property(gobject_class, PROP_CACHE_BUFFERS_NUM,
104         g_param_spec_uint("cache-buffers-num", "Cache Buffers Num",
105             "The cache buffers num in pool",
106             0, G_MAXUINT, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
107 
108     g_object_class_install_property(gobject_class, PROP_PERFORMANCE_MODE,
109         g_param_spec_boolean("performance-mode", "performance mode", "performance mode",
110             FALSE, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
111 
112     g_object_class_install_property(gobject_class, PROP_VIDEO_SCALE_TYPE,
113         g_param_spec_uint("video-scale-type", "Video Scale Type",
114             "Set video scale type for graphic",
115             0, G_MAXUINT, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
116 
117     g_object_class_install_property(gobject_class, PROP_VIDEO_ROTATION,
118         g_param_spec_uint("video-rotation", "Video Rotation",
119             "Set video rotation for surface",
120             0, G_MAXUINT, 0, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
121 
122     mem_sink_class->do_propose_allocation = gst_surface_mem_sink_do_propose_allocation;
123     mem_sink_class->do_app_render = gst_surface_mem_sink_do_app_render;
124     base_sink_class->event = gst_surface_mem_sink_event;
125     klass->do_app_render = gst_surface_mem_sink_subclass_do_app_render;
126     GST_DEBUG_CATEGORY_INIT(gst_surface_mem_sink_debug_category, "surfacesink", 0, "surfacesink class");
127 }
128 
gst_surface_mem_sink_init(GstSurfaceMemSink * sink)129 static void gst_surface_mem_sink_init(GstSurfaceMemSink *sink)
130 {
131     g_return_if_fail(sink != nullptr);
132     GST_DEBUG_OBJECT(sink, "Init, id = %d", static_cast<int32_t>(FAKE_POINTER(sink)));
133 
134     auto priv = reinterpret_cast<GstSurfaceMemSinkPrivate *>(gst_surface_mem_sink_get_instance_private(sink));
135     g_return_if_fail(priv != nullptr);
136     sink->priv = priv;
137     sink->priv->surface = nullptr;
138     sink->priv->pool = GST_PRODUCER_SURFACE_POOL_CAST(gst_producer_surface_pool_new());
139     sink->priv->rotation = 0;
140     sink->prerollBuffer = nullptr;
141     sink->firstRenderFrame = TRUE;
142     sink->preInitPool = FALSE;
143     sink->dump.enable_dump = FALSE;
144     sink->dump.dump_file = nullptr;
145     sink->performanceMode = FALSE;
146     sink->lastRate = 0;
147     sink->renderCnt = 0;
148     GstMemSink *memSink = GST_MEM_SINK_CAST(sink);
149     memSink->max_pool_capacity = SURFACE_MAX_QUEUE_SIZE;
150     gst_surface_mem_sink_dump_from_sys_param(sink);
151 }
152 
gst_surface_mem_sink_dispose(GObject * obj)153 static void gst_surface_mem_sink_dispose(GObject *obj)
154 {
155     g_return_if_fail(obj != nullptr);
156 
157     GstSurfaceMemSink *surface_sink = GST_SURFACE_MEM_SINK_CAST(obj);
158     GstSurfaceMemSinkPrivate *priv = surface_sink->priv;
159     g_return_if_fail(priv != nullptr);
160 
161     GST_OBJECT_LOCK(surface_sink);
162     priv->surface = nullptr;
163     if (priv->pool != nullptr) {
164         gst_object_unref(priv->pool);
165         priv->pool = nullptr;
166     }
167     GST_OBJECT_UNLOCK(surface_sink);
168 
169     G_OBJECT_CLASS(parent_class)->dispose(obj);
170 }
171 
gst_surface_mem_sink_finalize(GObject * obj)172 static void gst_surface_mem_sink_finalize(GObject *obj)
173 {
174     g_return_if_fail(obj != nullptr);
175     GstSurfaceMemSink *surface_sink = GST_SURFACE_MEM_SINK_CAST(obj);
176     gst_caps_unref(surface_sink->caps);
177     G_OBJECT_CLASS(parent_class)->finalize(obj);
178 }
179 
gst_surface_mem_sink_get_rotation(guint rotation)180 static GraphicTransformType gst_surface_mem_sink_get_rotation(guint rotation)
181 {
182     // We gets the rotation direction clockwise, but Surface needs it counterclockwise
183     switch (rotation) {
184         case VIDEO_ROTATION_90: {
185             return GRAPHIC_ROTATE_270;
186         }
187         case VIDEO_ROTATION_180: {
188             return GRAPHIC_ROTATE_180;
189         }
190         case VIDEO_ROTATION_270: {
191             return GRAPHIC_ROTATE_90;
192         }
193         default:
194             return GRAPHIC_ROTATE_NONE;
195     }
196 }
197 
gst_surface_mem_sink_set_property(GObject * object,guint propId,const GValue * value,GParamSpec * pspec)198 static void gst_surface_mem_sink_set_property(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
199 {
200     g_return_if_fail(object != nullptr && value != nullptr);
201 
202     GstSurfaceMemSink *surface_sink = GST_SURFACE_MEM_SINK_CAST(object);
203     GstSurfaceMemSinkPrivate *priv = surface_sink->priv;
204     g_return_if_fail(priv != nullptr);
205 
206     switch (propId) {
207         case PROP_SURFACE: {
208             gpointer surface = g_value_get_pointer(value);
209             g_return_if_fail(surface != nullptr);
210             OHOS::sptr<OHOS::Surface> surface_ref = reinterpret_cast<OHOS::Surface *>(surface);
211             GST_OBJECT_LOCK(surface_sink);
212             priv->surface = surface_ref;
213             gst_producer_surface_pool_set_surface(priv->pool, surface_ref);
214             GST_OBJECT_UNLOCK(surface_sink);
215             break;
216         }
217         case PROP_CACHE_BUFFERS_NUM: {
218             guint cache_buffer_num = g_value_get_uint(value);
219             g_object_set(G_OBJECT(priv->pool), "cache-buffers-num", cache_buffer_num, nullptr);
220             break;
221         }
222         case PROP_PERFORMANCE_MODE:
223             surface_sink->performanceMode = g_value_get_boolean(value);
224             break;
225 
226         case PROP_VIDEO_SCALE_TYPE: {
227             guint video_scale_type = g_value_get_uint(value);
228             g_object_set(G_OBJECT(priv->pool), "video-scale-type", video_scale_type, nullptr);
229             break;
230         }
231         case PROP_VIDEO_ROTATION: {
232             priv->rotation = g_value_get_uint(value);
233             break;
234         }
235         default:
236             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
237             break;
238     }
239 }
240 
gst_surface_mem_sink_get_property(GObject * object,guint propId,GValue * value,GParamSpec * pspec)241 static void gst_surface_mem_sink_get_property(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
242 {
243     g_return_if_fail(object != nullptr);
244 
245     GstSurfaceMemSink *surface_sink = GST_SURFACE_MEM_SINK_CAST(object);
246     GstSurfaceMemSinkPrivate *priv = surface_sink->priv;
247     g_return_if_fail(priv != nullptr);
248 
249     switch (propId) {
250         case PROP_SURFACE: {
251             GST_OBJECT_LOCK(surface_sink);
252             g_return_if_fail(priv->surface != nullptr);
253             g_value_set_pointer(value, priv->surface.GetRefPtr());
254             GST_OBJECT_UNLOCK(surface_sink);
255             break;
256         }
257         case PROP_SURFACE_POOL: {
258             GST_OBJECT_LOCK(surface_sink);
259             ON_SCOPE_EXIT(0) { GST_OBJECT_UNLOCK(surface_sink); };
260             g_value_set_pointer(value, priv->pool);
261             GstSurfaceAllocator *allocator = gst_surface_allocator_new();
262             g_return_if_fail(allocator != nullptr);
263             ON_SCOPE_EXIT(1) { gst_object_unref(allocator); };
264             GstStructure *config = gst_buffer_pool_get_config(GST_BUFFER_POOL(priv->pool));
265             g_return_if_fail(config != nullptr);
266             gst_buffer_pool_config_set_allocator(config, GST_ALLOCATOR_CAST(allocator), nullptr);
267             (void)gst_buffer_pool_set_config(GST_BUFFER_POOL(priv->pool), config);
268             surface_sink->preInitPool = TRUE;
269             break;
270         }
271         case PROP_VIDEO_ROTATION: {
272             GST_OBJECT_LOCK(surface_sink);
273             g_value_set_uint(value, priv->rotation);
274             GST_OBJECT_UNLOCK(surface_sink);
275             break;
276         }
277         default:
278             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
279             break;
280     }
281 }
282 
gst_surface_mem_sink_drop_frame_check(GstSurfaceMemSink * surface_sink)283 static gboolean gst_surface_mem_sink_drop_frame_check(GstSurfaceMemSink *surface_sink)
284 {
285     GstBaseSink *gst_base_sink = GST_BASE_SINK(surface_sink);
286     static guint dropFrameArray[] = {0, 1, 0, 1, 0, 0, 1};
287 
288     guint rate = (guint)(gst_base_sink->segment.rate * 100);   // 100 : rate double convert to uint
289     if (surface_sink->lastRate != rate) {
290         surface_sink->lastRate = rate;
291         surface_sink->renderCnt = 0;
292     }
293     surface_sink->renderCnt++;
294 
295     if ((rate == 125 && surface_sink->renderCnt % 5 == 0) ||  // 125 : 1.25 * 100 && 5 : drop frame inteval
296         (rate == 175 && dropFrameArray[surface_sink->renderCnt % 7]) ||  // 175 : 1.75 * 100 && 7 : drop frame inteval
297         (rate == 200 && surface_sink->renderCnt % 2 == 0)) {  // 200 : 2.00 * 100 && 2 : drop frame inteval
298         return FALSE;
299     }
300 
301     return TRUE;
302 }
303 
gst_surface_mem_sink_subclass_do_app_render(GstSurfaceMemSink * sink,GstBuffer * buffer,bool is_preroll)304 static GstFlowReturn gst_surface_mem_sink_subclass_do_app_render(GstSurfaceMemSink *sink,
305     GstBuffer *buffer, bool is_preroll)
306 {
307     (void)sink;
308     (void)buffer;
309     (void)is_preroll;
310 
311     return GST_FLOW_OK;
312 }
313 
gst_surface_mem_sink_need_flush(GstSurfaceMemSink * surface_sink,GstBuffer * buffer,bool is_preroll)314 static gboolean gst_surface_mem_sink_need_flush(GstSurfaceMemSink *surface_sink, GstBuffer *buffer, bool is_preroll)
315 {
316     gboolean needFlush = TRUE;
317     if (is_preroll) {
318         surface_sink->prerollBuffer = buffer;
319     } else {
320         if (surface_sink->prerollBuffer == buffer) {
321             // if it's paused, then play, this buffer is render by preroll
322             surface_sink->prerollBuffer = nullptr;
323             needFlush = FALSE;
324         }
325     }
326     return needFlush;
327 }
328 
gst_surface_do_render_buffer(GstMemSink * memsink,GstBuffer * buffer,bool is_preroll)329 static GstFlowReturn gst_surface_do_render_buffer(GstMemSink *memsink, GstBuffer *buffer, bool is_preroll)
330 {
331     g_return_val_if_fail(memsink != nullptr && buffer != nullptr, GST_FLOW_ERROR);
332     GstSurfaceMemSink *surface_sink = GST_SURFACE_MEM_SINK_CAST(memsink);
333     g_return_val_if_fail(surface_sink != nullptr, GST_FLOW_ERROR);
334     GstSurfaceMemSinkPrivate *priv = surface_sink->priv;
335     g_return_val_if_fail(priv != nullptr, GST_FLOW_ERROR);
336 
337     for (guint i = 0; i < gst_buffer_n_memory(buffer); i++) {
338         GstMemory *memory = gst_buffer_peek_memory(buffer, i);
339         if (!gst_is_surface_memory(memory)) {
340             GST_WARNING_OBJECT(surface_sink, "not surface buffer !, 0x%06" PRIXPTR, FAKE_POINTER(memory));
341             continue;
342         }
343 
344         GstSurfaceMemory *surface_mem = reinterpret_cast<GstSurfaceMemory *>(memory);
345 
346         gboolean needFlush = gst_surface_mem_sink_need_flush(surface_sink, buffer, is_preroll);
347         if (needFlush) {
348             // surface do not support timestamp is 0.
349             GST_BUFFER_PTS(buffer) = GST_BUFFER_PTS(buffer) == 0 ? 1 : GST_BUFFER_PTS(buffer);
350             OHOS::BufferFlushConfig flushConfig = {
351                 { 0, 0, surface_mem->buf->GetWidth(), surface_mem->buf->GetHeight() }, GST_BUFFER_PTS(buffer)
352             };
353             gst_surface_mem_sink_dump_buffer(surface_sink, buffer);
354             {
355                 MediaTrace trace("Surface::FlushBuffer");
356                 surface_mem->need_render = TRUE;
357                 OHOS::SurfaceError ret = priv->surface->FlushBuffer(surface_mem->buf, surface_mem->fence, flushConfig);
358                 if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
359                     surface_mem->need_render = FALSE;
360                     GST_ERROR_OBJECT(surface_sink, "flush buffer to surface failed, %d", ret);
361                 }
362             }
363         }
364     }
365     return GST_FLOW_OK;
366 }
367 
gst_surface_mem_sink_do_app_render(GstMemSink * memsink,GstBuffer * buffer,bool is_preroll)368 static GstFlowReturn gst_surface_mem_sink_do_app_render(GstMemSink *memsink, GstBuffer *buffer, bool is_preroll)
369 {
370     g_return_val_if_fail(memsink != nullptr && buffer != nullptr, GST_FLOW_ERROR);
371     GstSurfaceMemSink *surface_sink = GST_SURFACE_MEM_SINK_CAST(memsink);
372     g_return_val_if_fail(surface_sink != nullptr, GST_FLOW_ERROR);
373 
374     GstSurfaceMemSinkClass *surface_sink_class = GST_SURFACE_MEM_SINK_GET_CLASS(surface_sink);
375     GST_OBJECT_LOCK(surface_sink);
376 
377     if (gst_surface_mem_sink_drop_frame_check(surface_sink) == FALSE) {
378         GST_OBJECT_UNLOCK(surface_sink);
379         GST_DEBUG_OBJECT(surface_sink, "user set rate, drop same frame");
380         return GST_FLOW_OK;
381     }
382 
383     /* Make sure set rotation information for each video, avoid the rotation
384      * information of the previous video affecting the subsequent video
385      */
386     if (surface_sink->firstRenderFrame) {
387         GST_DEBUG_OBJECT(surface_sink, "set rotation: %u", surface_sink->priv->rotation);
388         if (surface_sink->priv->surface) {
389             MediaTrace trace("Surface::SetTransform");
390             (void)surface_sink->priv->surface->SetTransform(
391                 gst_surface_mem_sink_get_rotation(surface_sink->priv->rotation));
392         }
393     }
394 
395     if (surface_sink->firstRenderFrame && is_preroll) {
396         GST_DEBUG_OBJECT(surface_sink, "first render frame");
397         surface_sink->firstRenderFrame = FALSE;
398         GST_OBJECT_UNLOCK(surface_sink);
399         return GST_FLOW_OK;
400     }
401 
402     (void)gst_surface_do_render_buffer(memsink, buffer, is_preroll);
403 
404     GST_OBJECT_UNLOCK(surface_sink);
405 
406     if (surface_sink_class->do_app_render != nullptr) {
407         (void)surface_sink_class->do_app_render(surface_sink, buffer, is_preroll);
408     }
409     GST_DEBUG_OBJECT(surface_sink, "End gst_surface_mem_sink_do_app_render");
410     return GST_FLOW_OK;
411 }
412 
gst_surface_mem_sink_do_propose_allocation(GstMemSink * memsink,GstQuery * query)413 static gboolean gst_surface_mem_sink_do_propose_allocation(GstMemSink *memsink, GstQuery *query)
414 {
415     g_return_val_if_fail(memsink != nullptr && query != nullptr, FALSE);
416     GstSurfaceMemSink *surface_sink = GST_SURFACE_MEM_SINK_CAST(memsink);
417     g_return_val_if_fail(surface_sink != nullptr, FALSE);
418 
419     GstCaps *caps = nullptr;
420     gboolean needPool = FALSE;
421     gst_query_parse_allocation(query, &caps, &needPool);
422 
423     if (!needPool) {
424         GST_ERROR_OBJECT(surface_sink, "no need buffer pool, unexpected!");
425         return FALSE;
426     }
427     if (surface_sink->performanceMode && surface_sink->preInitPool) {
428         GST_INFO_OBJECT(surface_sink, "pool pre init");
429         surface_sink->preInitPool = FALSE;
430         return TRUE;
431     }
432 
433     GST_OBJECT_LOCK(surface_sink);
434     ON_SCOPE_EXIT(0) { GST_OBJECT_UNLOCK(surface_sink); };
435 
436     guint size = 0;
437     guint minBuffers = 0;
438     guint maxBuffers = 0;
439     gst_query_parse_nth_allocation_pool(query, 0, nullptr, &size, &minBuffers, &maxBuffers);
440     if (maxBuffers == 0) {
441         GST_INFO_OBJECT(surface_sink, "correct the maxbuffer from %u to %u", maxBuffers, memsink->max_pool_capacity);
442         maxBuffers = memsink->max_pool_capacity;
443     }
444     GST_DEBUG("maxBuffers is: %u", maxBuffers);
445 
446     GstProducerSurfacePool *pool = surface_sink->priv->pool;
447     g_return_val_if_fail(pool != nullptr, FALSE);
448     g_return_val_if_fail(gst_buffer_pool_set_active(GST_BUFFER_POOL(pool), FALSE), FALSE);
449 
450     GstVideoInfo info;
451     GST_DEBUG("begin gst_video_info_from_caps");
452     gboolean ret = gst_video_info_from_caps(&info, caps);
453     g_return_val_if_fail(ret, FALSE);
454     gst_query_add_allocation_pool(query, GST_BUFFER_POOL_CAST(pool), info.size, minBuffers, maxBuffers);
455 
456     GstSurfaceAllocator *allocator = gst_surface_allocator_new();
457     g_return_val_if_fail(allocator != nullptr, FALSE);
458     ON_SCOPE_EXIT(1) { gst_object_unref(allocator); };
459     GstStructure *params = gst_structure_new("mem", "memtype", G_TYPE_STRING, "surface", nullptr);
460     gst_query_add_allocation_param(query, GST_ALLOCATOR_CAST(allocator), nullptr);
461     gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, nullptr);
462     gst_query_add_allocation_meta(query, GST_BUFFER_TYPE_META_API_TYPE, params);
463     gst_structure_free(params);
464 
465     GstStructure *config = gst_buffer_pool_get_config(GST_BUFFER_POOL_CAST(pool));
466     g_return_val_if_fail(config != nullptr, FALSE);
467 
468     gst_buffer_pool_config_set_params(config, caps, info.size, minBuffers, maxBuffers);
469     gst_buffer_pool_config_set_allocator(config, GST_ALLOCATOR_CAST(allocator), nullptr);
470     // set config will take ownership of the config, we dont need to free it.
471     ret = gst_buffer_pool_set_config(GST_BUFFER_POOL_CAST(pool), config);
472 
473     return ret;
474 }
475 
gst_surface_mem_sink_dump_from_sys_param(GstSurfaceMemSink * self)476 void gst_surface_mem_sink_dump_from_sys_param(GstSurfaceMemSink *self)
477 {
478     std::string dump_enable;
479     self->dump.enable_dump = FALSE;
480     int32_t res = OHOS::system::GetStringParameter("sys.media.dump.frame.enable", dump_enable, "");
481     if (res != 0 || dump_enable.empty()) {
482         GST_DEBUG_OBJECT(self, "sys.media.dump.frame.enable");
483         return;
484     }
485     GST_DEBUG_OBJECT(self, "sys.media.dump.frame.enable=%s", dump_enable.c_str());
486 
487     if (dump_enable == "true") {
488         self->dump.enable_dump = TRUE;
489     }
490 }
491 
gst_surface_mem_sink_event(GstBaseSink * bsink,GstEvent * event)492 static gboolean gst_surface_mem_sink_event(GstBaseSink *bsink, GstEvent *event)
493 {
494     GstSurfaceMemSink *surface_mem_sink = GST_SURFACE_MEM_SINK(bsink);
495     g_return_val_if_fail(surface_mem_sink != nullptr, FALSE);
496     g_return_val_if_fail(event != nullptr, FALSE);
497 
498     GST_DEBUG_OBJECT(surface_mem_sink, "event->type %d", event->type);
499     switch (event->type) {
500         case GST_EVENT_CAPS: {
501             GstCaps *caps;
502             gst_event_parse_caps(event, &caps);
503             surface_mem_sink->caps = caps;
504             gst_caps_ref(surface_mem_sink->caps);
505             break;
506         }
507         default:
508             break;
509     }
510     return GST_BASE_SINK_CLASS(parent_class)->event(bsink, event);
511 }
512 
gst_surface_mem_sink_dump_buffer(GstSurfaceMemSink * self,GstBuffer * buffer)513 static void gst_surface_mem_sink_dump_buffer(GstSurfaceMemSink *self, GstBuffer *buffer)
514 {
515     g_return_if_fail(self != nullptr);
516     g_return_if_fail(buffer != nullptr);
517     if (self->dump.enable_dump == FALSE) {
518         return;
519     }
520     GST_DEBUG_OBJECT(self, "Dump yuv buffer");
521 
522     if (self->dump.dump_file == nullptr) {
523         GST_ERROR_OBJECT(self, "file not opened");
524         return;
525     }
526 
527     GstVideoMeta *video_meta = gst_buffer_get_video_meta(buffer);
528     g_return_if_fail(video_meta != nullptr);
529     GstStructure *struc = gst_caps_get_structure(self->caps, 0);
530     g_return_if_fail(struc != nullptr);
531     const gchar *format = gst_structure_get_string(struc, "format");
532     g_return_if_fail(format != nullptr);
533 
534     GstMapInfo info = GST_MAP_INFO_INIT;
535     g_return_if_fail(gst_buffer_map(buffer, &info, GST_MAP_READ));
536 
537     guint stride_width = 0;
538     guint stride_height = 0;
539     guint stride_size = info.size;
540     if (g_str_equal(format, "NV12") || g_str_equal(format, "NV21")) {
541         stride_width = video_meta->stride[0];
542         if (stride_width != 0) {
543             stride_height = video_meta->offset[1] / stride_width;
544             if (stride_height % 32 != 0) { // 32 : 高对齐
545                 stride_height = ((stride_height / 32) + 1) * 32; // 32 : 高对齐
546             }
547             stride_size = (stride_width * stride_height * 3) / 2;  // 3 2 : NV12和NV21 size比例大小
548         }
549     }
550     GST_DEBUG_OBJECT(self, "format %s, stride width %u, stride height %u,"
551         "stride_size %u, info.size %" G_GSIZE_FORMAT,
552         format, stride_width, stride_height, stride_size, info.size);
553     if (stride_size > info.size) {
554         stride_size = info.size;
555     }
556     (void)fwrite(info.data, stride_size, 1, self->dump.dump_file);
557     (void)fflush(self->dump.dump_file);
558     gst_buffer_unmap(buffer, &info);
559 }
560 
gst_surface_mem_sink_change_state(GstElement * element,GstStateChange transition)561 static GstStateChangeReturn gst_surface_mem_sink_change_state(GstElement *element, GstStateChange transition)
562 {
563     g_return_val_if_fail(element != nullptr, GST_STATE_CHANGE_FAILURE);
564     GstSurfaceMemSink *self = GST_SURFACE_MEM_SINK(element);
565 
566     GST_DEBUG_OBJECT(element, "change state %d", transition);
567     switch (transition) {
568         case GST_STATE_CHANGE_READY_TO_PAUSED:
569             if (self->dump.enable_dump == TRUE) {
570                 std::string dump_file = "/data/media/dump-" +
571                     std::to_string(static_cast<int32_t>(FAKE_POINTER(element))) + ".yuv";
572                 if (self->dump.dump_file == nullptr) {
573                     self->dump.dump_file = fopen(dump_file.c_str(), "wb+");
574                 }
575             }
576             break;
577         case GST_STATE_CHANGE_PAUSED_TO_READY:
578             if (self->dump.enable_dump == TRUE) {
579                 if (self->dump.dump_file != nullptr) {
580                     fclose(self->dump.dump_file);
581                     self->dump.dump_file = nullptr;
582                 }
583             }
584             break;
585         default:
586             break;
587     }
588     return GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
589 }
590