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