blob: 8e69f53c6f3458bbf686a8fd50589a2794940d5f [file] [log] [blame]
xuesong.jiang16983c92021-12-30 10:57:17 +08001/* GStreamer
2 * Copyright (C) 2021 <song.zhao@amlogic.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
17 * Boston, MA 02110-1335, USA.
18 */
19/**
20 * SECTION:element-gstamlvideosink
21 *
22 * The gstamlvideosink element call render lib to render video
23 *
24 */
25
xuesong.jiang1801e172021-10-11 10:56:41 +080026#ifdef HAVE_CONFIG_H
27#include <config.h>
28#endif
29
xuesong.jiang7c724a52021-10-22 17:18:58 +080030#include <stdbool.h>
xuesong.jiangd91230d2021-10-20 15:51:10 +080031#include <gst/gstdrmbufferpool.h>
xuesong.jiange90be372021-10-21 11:29:57 +080032#include <gst/allocators/gstdmabuf.h>
xuesong.jiang192316f2021-10-27 14:51:56 +080033#include "gstamlvideosink.h"
xuesong.jiang7f613802021-12-15 15:22:44 +080034#include <render_lib.h>
xuesong.jiang192316f2021-10-27 14:51:56 +080035// #ifdef USE_AMLOGIC_MESON
36// #ifdef USE_AMLOGIC_MESON_MSYNC
37// #define INVALID_SESSION_ID (16)
38#include "gstamlclock.h"
39#include "gstamlhalasink_new.h"
xuesong.jiang75ef01c2021-12-09 17:08:52 +080040#include <stdio.h>
xuesong.jiang192316f2021-10-27 14:51:56 +080041// #endif
42// #endif
xuesong.jiang1801e172021-10-11 10:56:41 +080043
xuesong.jiang91391f52021-11-19 15:42:30 +080044#ifdef GST_OBJECT_LOCK
45#undef GST_OBJECT_LOCK
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +080046#define GST_OBJECT_LOCK(obj) \
47 { \
48 GST_DEBUG("dbg basesink ctxt lock | aml | %p | locking", obj); \
49 g_mutex_lock(GST_OBJECT_GET_LOCK(obj)); \
50 GST_DEBUG("dbg basesink ctxt lock | aml | %p | locked", obj); \
51 }
xuesong.jiang91391f52021-11-19 15:42:30 +080052#endif
53
54#ifdef GST_OBJECT_UNLOCK
55#undef GST_OBJECT_UNLOCK
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +080056#define GST_OBJECT_UNLOCK(obj) \
57 { \
58 GST_DEBUG("dbg basesink ctxt lock | aml |%p | unlocking", obj); \
59 g_mutex_unlock(GST_OBJECT_GET_LOCK(obj)); \
60 GST_DEBUG("dbg basesink ctxt lock | aml |%p | unlocked", obj); \
61 }
xuesong.jiang91391f52021-11-19 15:42:30 +080062#endif
63
xuesong.jiang1801e172021-10-11 10:56:41 +080064/* signals */
xuesong.jiangd91230d2021-10-20 15:51:10 +080065enum
66{
67 SIGNAL_0,
68 LAST_SIGNAL
xuesong.jiang1801e172021-10-11 10:56:41 +080069};
70
xuesong.jiangd91230d2021-10-20 15:51:10 +080071/* Properties */
72enum
73{
74 PROP_0,
75 PROP_FULLSCREEN,
76 PROP_SETMUTE,
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +080077 PROP_AVSYNC_MODE,
xuesong.jiangd91230d2021-10-20 15:51:10 +080078};
79
xuesong.jiangfa8903d2022-02-11 15:13:05 +080080// #define AML_VIDEO_FORMATS \
81// "{ BGRx, BGRA, RGBx, xBGR, xRGB, RGBA, ABGR, ARGB, RGB, BGR, " \
82// "RGB16, BGR16, YUY2, YVYU, UYVY, AYUV, NV12, NV21, NV16, " \
83// "YUV9, YVU9, Y41B, I420, YV12, Y42B, v308 }"
84#define AML_VIDEO_FORMATS "{ NV21 }"
85
xuesong.jiangd91230d2021-10-20 15:51:10 +080086#define GST_CAPS_FEATURE_MEMORY_DMABUF "memory:DMABuf"
xuesong.jiang4a832aa2022-01-06 16:44:26 +080087#define GST_USE_PLAYBIN 1
xuesong.jiange0c6c542022-04-11 16:10:23 +080088#define GST_DEFAULT_AVSYNC_MODE 1 // 0:v master, 1:a master
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +080089
xuesong.jiange0c6c542022-04-11 16:10:23 +080090#define RENDER_DEVICE_NAME "westeros"
xuesong.jiangd91230d2021-10-20 15:51:10 +080091#define USE_DMABUF TRUE
92
xuesong.jiange0c6c542022-04-11 16:10:23 +080093#define DRMBP_EXTRA_BUF_SZIE_FOR_DISPLAY 1
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +080094#define DRMBP_LIMIT_MAX_BUFSIZE_TO_BUFSIZE 1
95#define DRMBP_UNLIMIT_MAX_BUFSIZE 0
xuesong.jiangb3f0f152021-12-23 20:19:08 +080096
xuesong.jiangd91230d2021-10-20 15:51:10 +080097struct _GstAmlVideoSinkPrivate
98{
xuesong.jiangebd18352021-12-28 17:13:22 +080099 GstBuffer *preroll_buffer;
xuesong.jiange90be372021-10-21 11:29:57 +0800100 gchar *render_device_name;
101 void *render_device_handle;
xuesong.jiangd91230d2021-10-20 15:51:10 +0800102 GstVideoInfo video_info;
103 gboolean video_info_changed;
104 gboolean use_dmabuf;
105 gboolean is_flushing;
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800106 gboolean got_eos;
xuesong.jiang50a0f932021-11-15 15:18:51 +0800107 gint mediasync_instanceid;
xuesong.jiang7c724a52021-10-22 17:18:58 +0800108 GstSegment segment;
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800109
xuesong.jiangd91230d2021-10-20 15:51:10 +0800110 /* property params */
111 gboolean fullscreen;
112 gboolean mute;
xuesong.jiang1801e172021-10-11 10:56:41 +0800113};
114
115static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE(
116 "sink", GST_PAD_SINK, GST_PAD_ALWAYS,
117 GST_STATIC_CAPS(
118 GST_VIDEO_CAPS_MAKE(AML_VIDEO_FORMATS) ";" GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
119 GST_CAPS_FEATURE_MEMORY_DMABUF, AML_VIDEO_FORMATS)));
120
121GST_DEBUG_CATEGORY(gst_aml_video_sink_debug);
122#define GST_CAT_DEFAULT gst_aml_video_sink_debug
123#define gst_aml_video_sink_parent_class parent_class
xuesong.jiang192316f2021-10-27 14:51:56 +0800124// #define GST_AML_VIDEO_SINK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), GST_TYPE_AML_VIDEO_SINK, GstAmlVideoSinkPrivate))
xuesong.jiang1801e172021-10-11 10:56:41 +0800125G_DEFINE_TYPE_WITH_CODE(GstAmlVideoSink, gst_aml_video_sink,
126 GST_TYPE_VIDEO_SINK, G_ADD_PRIVATE(GstAmlVideoSink));
127
128/* public interface define */
129static void gst_aml_video_sink_get_property(GObject *object, guint prop_id,
130 GValue *value, GParamSpec *pspec);
131static void gst_aml_video_sink_set_property(GObject *object, guint prop_id,
132 const GValue *value,
133 GParamSpec *pspec);
134static void gst_aml_video_sink_finalize(GObject *object);
135static GstStateChangeReturn
136gst_aml_video_sink_change_state(GstElement *element, GstStateChange transition);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800137static gboolean gst_aml_video_sink_propose_allocation(GstBaseSink *bsink, GstQuery *query);
xuesong.jiang1801e172021-10-11 10:56:41 +0800138static GstCaps *gst_aml_video_sink_get_caps(GstBaseSink *bsink,
139 GstCaps *filter);
140static gboolean gst_aml_video_sink_set_caps(GstBaseSink *bsink, GstCaps *caps);
xuesong.jiang7c724a52021-10-22 17:18:58 +0800141static gboolean gst_aml_video_sink_show_frame(GstVideoSink *bsink, GstBuffer *buffer);
xuesong.jiang50a0f932021-11-15 15:18:51 +0800142static gboolean gst_aml_video_sink_pad_event(GstPad *pad, GstObject *parent, GstEvent *event);
xuesong.jiang1801e172021-10-11 10:56:41 +0800143
144/* private interface define */
145static void gst_aml_video_sink_reset_private(GstAmlVideoSink *sink);
xuesong.jiang1700bab2021-11-17 17:11:11 +0800146void gst_render_msg_callback(void *userData, RenderMsgType type, void *msg);
147int gst_render_val_callback(void *userData, int key, void *value);
xuesong.jiang7c724a52021-10-22 17:18:58 +0800148static gboolean gst_aml_video_sink_tunnel_buf(GstAmlVideoSink *vsink, GstBuffer *gst_buf, RenderBuffer *tunnel_lib_buf_wrap);
xuesong.jiang50a0f932021-11-15 15:18:51 +0800149static gboolean gst_get_mediasync_instanceid(GstAmlVideoSink *vsink);
xuesong.jiang16983c92021-12-30 10:57:17 +0800150#if GST_USE_PLAYBIN
xuesong.jiang50a0f932021-11-15 15:18:51 +0800151static GstElement *gst_aml_video_sink_find_audio_sink(GstAmlVideoSink *sink);
xuesong.jiang16983c92021-12-30 10:57:17 +0800152#endif
xuesong.jiang50a0f932021-11-15 15:18:51 +0800153static gboolean gst_render_set_params(GstVideoSink *vsink);
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800154static void gst_emit_eos_signal(GstAmlVideoSink *vsink);
155static void gst_wait_eos_signal(GstAmlVideoSink *vsink);
xuesong.jiang1801e172021-10-11 10:56:41 +0800156
157/* public interface definition */
xuesong.jiang7c724a52021-10-22 17:18:58 +0800158static void gst_aml_video_sink_class_init(GstAmlVideoSinkClass *klass)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800159{
160 GObjectClass *gobject_class;
161 GstElementClass *gstelement_class;
162 GstBaseSinkClass *gstbasesink_class;
163 GstVideoSinkClass *gstvideosink_class;
xuesong.jiang1801e172021-10-11 10:56:41 +0800164
xuesong.jiangd91230d2021-10-20 15:51:10 +0800165 gobject_class = (GObjectClass *)klass;
166 gstelement_class = (GstElementClass *)klass;
167 gstbasesink_class = (GstBaseSinkClass *)klass;
168 gstvideosink_class = (GstVideoSinkClass *)klass;
xuesong.jiang1801e172021-10-11 10:56:41 +0800169
xuesong.jiangd91230d2021-10-20 15:51:10 +0800170 gobject_class->set_property = gst_aml_video_sink_set_property;
171 gobject_class->get_property = gst_aml_video_sink_get_property;
172 gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_aml_video_sink_finalize);
xuesong.jiang1801e172021-10-11 10:56:41 +0800173
xuesong.jiangd91230d2021-10-20 15:51:10 +0800174 gst_element_class_add_static_pad_template(gstelement_class, &sink_template);
xuesong.jiang1801e172021-10-11 10:56:41 +0800175
xuesong.jiangd91230d2021-10-20 15:51:10 +0800176 gst_element_class_set_static_metadata(
177 gstelement_class, "aml video sink", "Sink/Video",
178 "Output to video tunnel lib",
179 "Xuesong.Jiang@amlogic.com<Xuesong.Jiang@amlogic.com>");
xuesong.jiang1801e172021-10-11 10:56:41 +0800180
xuesong.jiangd91230d2021-10-20 15:51:10 +0800181 gstelement_class->change_state =
182 GST_DEBUG_FUNCPTR(gst_aml_video_sink_change_state);
xuesong.jiang1801e172021-10-11 10:56:41 +0800183
xuesong.jiangd91230d2021-10-20 15:51:10 +0800184 gstbasesink_class->propose_allocation = GST_DEBUG_FUNCPTR(gst_aml_video_sink_propose_allocation);
185 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR(gst_aml_video_sink_get_caps);
186 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR(gst_aml_video_sink_set_caps);
xuesong.jiang1801e172021-10-11 10:56:41 +0800187
xuesong.jiangd91230d2021-10-20 15:51:10 +0800188 gstvideosink_class->show_frame = GST_DEBUG_FUNCPTR(gst_aml_video_sink_show_frame);
xuesong.jiang1801e172021-10-11 10:56:41 +0800189
xuesong.jiangd91230d2021-10-20 15:51:10 +0800190 g_object_class_install_property(
191 gobject_class, PROP_FULLSCREEN,
192 g_param_spec_boolean("fullscreen", "Fullscreen",
193 "Whether the surface should be made fullscreen ",
194 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
xuesong.jiang1801e172021-10-11 10:56:41 +0800195
xuesong.jiangd91230d2021-10-20 15:51:10 +0800196 g_object_class_install_property(
197 gobject_class, PROP_SETMUTE,
198 g_param_spec_boolean("set mute", "set mute params",
199 "Whether set screen mute ",
200 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800201
202 g_object_class_install_property(
203 G_OBJECT_CLASS(klass), PROP_AVSYNC_MODE,
204 g_param_spec_int("avsync-mode", "avsync mode",
205 "Vmaster(0) Amaster(1) PCRmaster(2) IPTV(3) FreeRun(4)",
206 G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE));
xuesong.jiang1801e172021-10-11 10:56:41 +0800207}
208
xuesong.jiangd91230d2021-10-20 15:51:10 +0800209static void gst_aml_video_sink_init(GstAmlVideoSink *sink)
210{
211 GstBaseSink *basesink = (GstBaseSink *)sink;
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800212
213 /* init eos detect */
214 sink->queued = 0;
215 sink->dequeued = 0;
216 sink->rendered = 0;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800217 sink->avsync_mode = GST_DEFAULT_AVSYNC_MODE;
218 g_mutex_init(&sink->eos_lock);
219 g_cond_init(&sink->eos_cond);
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800220
xuesong.jiangd91230d2021-10-20 15:51:10 +0800221 gst_pad_set_event_function(basesink->sinkpad, gst_aml_video_sink_pad_event);
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800222
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800223 GST_AML_VIDEO_SINK_GET_PRIVATE(sink) = malloc(sizeof(GstAmlVideoSinkPrivate));
xuesong.jiangd91230d2021-10-20 15:51:10 +0800224 gst_aml_video_sink_reset_private(sink);
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800225
xuesong.jiangd2619562021-12-23 16:38:50 +0800226 gst_base_sink_set_sync(basesink, FALSE);
xuesong.jiang1801e172021-10-11 10:56:41 +0800227}
228
229static void gst_aml_video_sink_get_property(GObject *object, guint prop_id,
xuesong.jiangd91230d2021-10-20 15:51:10 +0800230 GValue *value, GParamSpec *pspec)
231{
232 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(object);
233 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiang1801e172021-10-11 10:56:41 +0800234
xuesong.jiangd91230d2021-10-20 15:51:10 +0800235 switch (prop_id)
236 {
237 case PROP_FULLSCREEN:
238 GST_OBJECT_LOCK(sink);
239 g_value_set_boolean(value, sink_priv->fullscreen);
240 GST_OBJECT_UNLOCK(sink);
241 break;
242 case PROP_SETMUTE:
243 GST_OBJECT_LOCK(sink);
xuesong.jiang7c724a52021-10-22 17:18:58 +0800244 g_value_set_boolean(value, sink_priv->mute);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800245 GST_OBJECT_UNLOCK(sink);
246 break;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800247 case PROP_AVSYNC_MODE:
248 GST_OBJECT_LOCK(sink);
249 g_value_set_boolean(value, sink->avsync_mode);
250 GST_OBJECT_UNLOCK(sink);
251 break;
xuesong.jiangd91230d2021-10-20 15:51:10 +0800252 default:
253 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
254 break;
255 }
xuesong.jiang1801e172021-10-11 10:56:41 +0800256}
257
258static void gst_aml_video_sink_set_property(GObject *object, guint prop_id,
259 const GValue *value,
xuesong.jiangd91230d2021-10-20 15:51:10 +0800260 GParamSpec *pspec)
261{
262 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(object);
263 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiang1801e172021-10-11 10:56:41 +0800264
xuesong.jiangd91230d2021-10-20 15:51:10 +0800265 switch (prop_id)
266 {
267 case PROP_FULLSCREEN:
268 GST_OBJECT_LOCK(sink);
269 gboolean is_fullscreen = g_value_get_boolean(value);
xuesong.jiange90be372021-10-21 11:29:57 +0800270 if (sink_priv->fullscreen != is_fullscreen)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800271 {
272 sink_priv->fullscreen = is_fullscreen;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800273 // TODO set full screen to tunnel lib
xuesong.jiangd91230d2021-10-20 15:51:10 +0800274 }
275 GST_OBJECT_UNLOCK(sink);
276 break;
277 case PROP_SETMUTE:
278 GST_OBJECT_LOCK(sink);
279 gboolean is_mute = g_value_get_boolean(value);
xuesong.jiange90be372021-10-21 11:29:57 +0800280 if (sink_priv->mute != is_mute)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800281 {
xuesong.jiang75ef01c2021-12-09 17:08:52 +0800282 sink_priv->mute = is_mute;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800283 // TODO set full screen to tunnel lib
284 }
285 GST_OBJECT_UNLOCK(sink);
286 break;
287 case PROP_AVSYNC_MODE:
288 GST_OBJECT_LOCK(sink);
289 gint mode = g_value_get_int(value);
290 if (mode >= 0)
291 {
292 sink->avsync_mode = mode;
293 GST_WARNING("AV sync mode %d", mode);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800294 }
295 GST_OBJECT_UNLOCK(sink);
296 break;
297 default:
298 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
299 break;
300 }
xuesong.jiang1801e172021-10-11 10:56:41 +0800301}
302
xuesong.jiangd91230d2021-10-20 15:51:10 +0800303static void gst_aml_video_sink_finalize(GObject *object)
304{
305 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(object);
xuesong.jiang1801e172021-10-11 10:56:41 +0800306
xuesong.jiangd91230d2021-10-20 15:51:10 +0800307 GST_DEBUG_OBJECT(sink, "Finalizing aml video sink..");
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800308
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800309 g_mutex_clear(&sink->eos_lock);
310 g_cond_clear(&sink->eos_cond);
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800311
xuesong.jiangd91230d2021-10-20 15:51:10 +0800312 gst_aml_video_sink_reset_private(sink);
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800313 if (GST_AML_VIDEO_SINK_GET_PRIVATE(sink))
xuesong.jiang5c0d1b82021-11-16 19:30:56 +0800314 free(GST_AML_VIDEO_SINK_GET_PRIVATE(sink));
xuesong.jiangd91230d2021-10-20 15:51:10 +0800315 G_OBJECT_CLASS(parent_class)->finalize(object);
xuesong.jiang1801e172021-10-11 10:56:41 +0800316}
317
318static GstStateChangeReturn
319gst_aml_video_sink_change_state(GstElement *element,
xuesong.jiangd91230d2021-10-20 15:51:10 +0800320 GstStateChange transition)
321{
322 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(element);
323 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800324 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
xuesong.jiang32d78282021-11-18 19:24:15 +0800325 GST_DEBUG_OBJECT(sink, "trace in");
xuesong.jiang1801e172021-10-11 10:56:41 +0800326
xuesong.jiangd91230d2021-10-20 15:51:10 +0800327 GST_OBJECT_LOCK(sink);
328 switch (transition)
329 {
330 case GST_STATE_CHANGE_NULL_TO_READY:
331 {
332 sink_priv->render_device_handle = render_open(sink_priv->render_device_name);
xuesong.jiange90be372021-10-21 11:29:57 +0800333 if (sink_priv->render_device_handle == NULL)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800334 {
335 GST_ERROR_OBJECT(sink, "render lib: open device fail");
336 goto error;
337 }
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800338 RenderCallback cb = {gst_render_msg_callback, gst_render_val_callback};
339 render_set_callback(sink_priv->render_device_handle, &cb);
340 render_set_user_data(sink_priv->render_device_handle, sink);
xuesong.jiang1801e172021-10-11 10:56:41 +0800341
xuesong.jiangd91230d2021-10-20 15:51:10 +0800342 break;
343 }
344 case GST_STATE_CHANGE_READY_TO_PAUSED:
345 {
xuesong.jiang1700bab2021-11-17 17:11:11 +0800346 if (render_connect(sink_priv->render_device_handle) == -1)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800347 {
348 GST_ERROR_OBJECT(sink, "render lib connect device fail");
349 goto error;
350 }
351 break;
352 }
353 default:
354 break;
355 }
356 GST_OBJECT_UNLOCK(sink);
xuesong.jiang1801e172021-10-11 10:56:41 +0800357
xuesong.jiang1700bab2021-11-17 17:11:11 +0800358 GST_LOG_OBJECT(sink, "amlvideosink deal state change ok, goto basesink state change");
xuesong.jiangd91230d2021-10-20 15:51:10 +0800359 ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
360
361 GST_OBJECT_LOCK(sink);
362 if (ret == GST_STATE_CHANGE_FAILURE)
363 goto error;
364
365 switch (transition)
366 {
367 case GST_STATE_CHANGE_PAUSED_TO_READY:
368 {
369 render_disconnect(sink_priv->render_device_handle);
370 break;
371 }
372 case GST_STATE_CHANGE_READY_TO_NULL:
373 {
xuesong.jiange90be372021-10-21 11:29:57 +0800374 if (sink_priv->render_device_handle)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800375 {
376 render_close(sink_priv->render_device_handle);
377 }
378 gst_aml_video_sink_reset_private(sink);
379
380 break;
381 }
382 default:
383 break;
384 }
385 GST_OBJECT_UNLOCK(sink);
xuesong.jiang1801e172021-10-11 10:56:41 +0800386 return ret;
387
xuesong.jiangd91230d2021-10-20 15:51:10 +0800388error:
389 GST_OBJECT_UNLOCK(sink);
390 ret = GST_STATE_CHANGE_FAILURE;
391 return ret;
392}
xuesong.jiang1801e172021-10-11 10:56:41 +0800393
xuesong.jiangd91230d2021-10-20 15:51:10 +0800394static gboolean gst_aml_video_sink_propose_allocation(GstBaseSink *bsink, GstQuery *query)
395{
xuesong.jiangeb46f672021-11-19 19:05:56 +0800396 GST_DEBUG_OBJECT(bsink, "trace in");
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800397 // TODO only implement dma case
xuesong.jiangd91230d2021-10-20 15:51:10 +0800398 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(bsink);
xuesong.jiang7c724a52021-10-22 17:18:58 +0800399 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
400
xuesong.jiangd91230d2021-10-20 15:51:10 +0800401 GstCaps *caps;
402 GstBufferPool *pool = NULL;
403 gboolean need_pool;
xuesong.jiangd91230d2021-10-20 15:51:10 +0800404
405 gst_query_parse_allocation(query, &caps, &need_pool);
xuesong.jiangeb46f672021-11-19 19:05:56 +0800406 GST_DEBUG_OBJECT(bsink, "jxsaaa need_pool:%d", need_pool);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800407
408 if (need_pool)
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800409 // TODO 没有考虑secure场景
xuesong.jiang7c724a52021-10-22 17:18:58 +0800410 pool = gst_drm_bufferpool_new(FALSE, GST_DRM_BUFFERPOOL_TYPE_VIDEO_PLANE);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800411
xuesong.jiangb3f0f152021-12-23 20:19:08 +0800412 gst_query_add_allocation_pool(query, pool, sink_priv->video_info.size, DRMBP_EXTRA_BUF_SZIE_FOR_DISPLAY, DRMBP_LIMIT_MAX_BUFSIZE_TO_BUFSIZE);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800413 if (pool)
414 g_object_unref(pool);
415
416 gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
417
418 return TRUE;
xuesong.jiang1801e172021-10-11 10:56:41 +0800419}
420
421static GstCaps *gst_aml_video_sink_get_caps(GstBaseSink *bsink,
xuesong.jiangd91230d2021-10-20 15:51:10 +0800422 GstCaps *filter)
423{
424 GstAmlVideoSink *sink;
425 GstCaps *caps;
xuesong.jiang1801e172021-10-11 10:56:41 +0800426
xuesong.jiangd91230d2021-10-20 15:51:10 +0800427 sink = GST_AML_VIDEO_SINK(bsink);
xuesong.jiang1801e172021-10-11 10:56:41 +0800428
xuesong.jiangd91230d2021-10-20 15:51:10 +0800429 caps = gst_pad_get_pad_template_caps(GST_VIDEO_SINK_PAD(sink));
430 caps = gst_caps_make_writable(caps);
431 // TODO 这里是需要从template直接取出支持的caps还是要通过tunnel lib拿到caps?
xuesong.jiang1801e172021-10-11 10:56:41 +0800432
xuesong.jiangd91230d2021-10-20 15:51:10 +0800433 if (filter)
434 {
435 GstCaps *intersection;
xuesong.jiang1801e172021-10-11 10:56:41 +0800436
xuesong.jiangd91230d2021-10-20 15:51:10 +0800437 intersection =
438 gst_caps_intersect_full(filter, caps, GST_CAPS_INTERSECT_FIRST);
439 gst_caps_unref(caps);
440 caps = intersection;
441 }
xuesong.jiang1801e172021-10-11 10:56:41 +0800442
xuesong.jiangd91230d2021-10-20 15:51:10 +0800443 return caps;
xuesong.jiang1801e172021-10-11 10:56:41 +0800444}
445
xuesong.jiangd91230d2021-10-20 15:51:10 +0800446static gboolean gst_aml_video_sink_set_caps(GstBaseSink *bsink, GstCaps *caps)
447{
448 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(bsink);
449 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiangf190e2a2021-11-22 20:26:00 +0800450 // gboolean use_dmabuf;
xuesong.jiang91391f52021-11-19 15:42:30 +0800451 gboolean ret = TRUE;
xuesong.jiang1801e172021-10-11 10:56:41 +0800452
xuesong.jiangd91230d2021-10-20 15:51:10 +0800453 GST_OBJECT_LOCK(sink);
xuesong.jiang1801e172021-10-11 10:56:41 +0800454
xuesong.jiangd91230d2021-10-20 15:51:10 +0800455 GST_DEBUG_OBJECT(sink, "set caps %" GST_PTR_FORMAT, caps);
xuesong.jiangeb46f672021-11-19 19:05:56 +0800456 // use_dmabuf = gst_caps_features_contains(gst_caps_get_features(caps, 0), GST_CAPS_FEATURE_MEMORY_DMABUF);
457 // if (use_dmabuf == FALSE)
458 // {
459 // GST_ERROR_OBJECT(sink, "not support non dma buffer case");
460 // ret = FALSE;
461 // goto done;
462 // }
xuesong.jiang1801e172021-10-11 10:56:41 +0800463
xuesong.jiangd91230d2021-10-20 15:51:10 +0800464 /* extract info from caps */
465 if (!gst_video_info_from_caps(&sink_priv->video_info, caps))
466 {
467 GST_ERROR_OBJECT(sink, "can't get video info from caps");
xuesong.jiang91391f52021-11-19 15:42:30 +0800468 ret = FALSE;
469 goto done;
xuesong.jiangd91230d2021-10-20 15:51:10 +0800470 }
xuesong.jiang1801e172021-10-11 10:56:41 +0800471
xuesong.jiangd91230d2021-10-20 15:51:10 +0800472 sink_priv->video_info_changed = TRUE;
473
xuesong.jiang91391f52021-11-19 15:42:30 +0800474done:
xuesong.jiangd91230d2021-10-20 15:51:10 +0800475 GST_OBJECT_UNLOCK(sink);
xuesong.jiang91391f52021-11-19 15:42:30 +0800476 return ret;
xuesong.jiang1801e172021-10-11 10:56:41 +0800477}
478
xuesong.jiange90be372021-10-21 11:29:57 +0800479static GstFlowReturn gst_aml_video_sink_show_frame(GstVideoSink *vsink, GstBuffer *buffer)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800480{
xuesong.jiang7c724a52021-10-22 17:18:58 +0800481 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(vsink);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800482 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
483 GstFlowReturn ret = GST_FLOW_OK;
484 RenderBuffer *tunnel_lib_buf_wrap = NULL;
xuesong.jiang1801e172021-10-11 10:56:41 +0800485
xuesong.jiangd91230d2021-10-20 15:51:10 +0800486 GST_OBJECT_LOCK(vsink);
xuesong.jiangebd18352021-12-28 17:13:22 +0800487 GST_LOG_OBJECT(sink, "revice buffer:%p, from pool:%p, need_preroll:%d", buffer, buffer->pool, ((GstBaseSink *)sink)->need_preroll);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800488
xuesong.jiange90be372021-10-21 11:29:57 +0800489 if (!sink_priv->render_device_handle)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800490 {
491 GST_ERROR_OBJECT(sink, "flow error, render_device_handle == NULL");
492 goto error;
493 }
494
xuesong.jiangebd18352021-12-28 17:13:22 +0800495 if (sink_priv->preroll_buffer && sink_priv->preroll_buffer == buffer)
496 {
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800497 GST_LOG_OBJECT(sink, "get preroll buffer:%p 2nd time, goto ret", buffer);
xuesong.jiangebd18352021-12-28 17:13:22 +0800498 sink_priv->preroll_buffer = NULL;
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800499 goto ret;
xuesong.jiangebd18352021-12-28 17:13:22 +0800500 }
501 if (G_UNLIKELY(((GstBaseSink *)sink)->need_preroll))
502 {
503 GST_LOG_OBJECT(sink, "get preroll buffer 1st time, buf:%p", buffer);
504 sink_priv->preroll_buffer = buffer;
505 }
506
xuesong.jiangd91230d2021-10-20 15:51:10 +0800507 // TODO should call tunnel lib flush func
508 if (sink_priv->is_flushing)
509 {
510 gst_buffer_unref(buffer);
xuesong.jiange90be372021-10-21 11:29:57 +0800511 if (!render_flush(sink_priv->render_device_handle))
xuesong.jiangd91230d2021-10-20 15:51:10 +0800512 {
513 GST_ERROR_OBJECT(sink, "render lib: flush error");
514 goto error;
515 }
516 GST_DEBUG_OBJECT(sink, "in flushing flow, release the buffer directly");
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800517 goto flushing;
xuesong.jiangd91230d2021-10-20 15:51:10 +0800518 }
519
520 if (sink_priv->video_info_changed)
521 {
xuesong.jiang50a0f932021-11-15 15:18:51 +0800522 if (gst_render_set_params(vsink) == FALSE)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800523 {
524 GST_ERROR_OBJECT(sink, "render lib: set params fail");
525 goto error;
526 }
527 sink_priv->video_info_changed = FALSE;
528 }
529
xuesong.jiang50a0f932021-11-15 15:18:51 +0800530 tunnel_lib_buf_wrap = render_allocate_render_buffer_wrap(sink_priv->render_device_handle, BUFFER_FLAG_EXTER_DMA_BUFFER, 0);
xuesong.jiange90be372021-10-21 11:29:57 +0800531 if (!tunnel_lib_buf_wrap)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800532 {
533 GST_ERROR_OBJECT(sink, "render lib: alloc buffer wrap fail");
534 goto error;
535 }
xuesong.jiange90be372021-10-21 11:29:57 +0800536 if (!gst_aml_video_sink_tunnel_buf(sink, buffer, tunnel_lib_buf_wrap))
537 {
538 GST_ERROR_OBJECT(sink, "construc render buffer fail");
539 goto error;
540 }
541
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800542 GST_OBJECT_UNLOCK(vsink);
543
xuesong.jiangf190e2a2021-11-22 20:26:00 +0800544 if (render_display_frame(sink_priv->render_device_handle, tunnel_lib_buf_wrap) == -1)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800545 {
546 GST_ERROR_OBJECT(sink, "render lib: display frame fail");
547 goto error;
548 }
xuesong.jiangd91230d2021-10-20 15:51:10 +0800549
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800550 sink->queued++;
xuesong.jiangeb46f672021-11-19 19:05:56 +0800551 GST_DEBUG_OBJECT(sink, "GstBuffer:%p queued ok", buffer);
xuesong.jiang1801e172021-10-11 10:56:41 +0800552 return ret;
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800553
xuesong.jiangd91230d2021-10-20 15:51:10 +0800554error:
xuesong.jiangeb46f672021-11-19 19:05:56 +0800555 GST_DEBUG_OBJECT(sink, "GstBuffer:%p queued error", buffer);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800556 ret = GST_FLOW_CUSTOM_ERROR_2;
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800557 goto ret;
558flushing:
559 GST_DEBUG_OBJECT(sink, "flushing when buf:%p", buffer);
560 goto ret;
561ret:
562 GST_OBJECT_UNLOCK(vsink);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800563 return ret;
xuesong.jiang1801e172021-10-11 10:56:41 +0800564}
565
xuesong.jiang50a0f932021-11-15 15:18:51 +0800566static gboolean gst_aml_video_sink_pad_event(GstPad *pad, GstObject *parent, GstEvent *event)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800567{
568 gboolean result = TRUE;
xuesong.jiang7c724a52021-10-22 17:18:58 +0800569 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(parent);
570 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiang1801e172021-10-11 10:56:41 +0800571
xuesong.jiangd91230d2021-10-20 15:51:10 +0800572 switch (GST_EVENT_TYPE(event))
573 {
574 case GST_EVENT_FLUSH_START:
575 {
576 GST_INFO_OBJECT(sink, "flush start");
577 GST_OBJECT_LOCK(sink);
578 sink_priv->is_flushing = TRUE;
579 GST_OBJECT_UNLOCK(sink);
580 break;
581 }
582 case GST_EVENT_FLUSH_STOP:
583 {
584 GST_INFO_OBJECT(sink, "flush stop");
xuesong.jiang1801e172021-10-11 10:56:41 +0800585
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800586 gst_wait_eos_signal(sink);
587
xuesong.jiangd91230d2021-10-20 15:51:10 +0800588 GST_OBJECT_LOCK(sink);
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800589 sink->queued = 0;
590 sink->dequeued = 0;
591 sink->rendered = 0;
592 sink_priv->got_eos = FALSE;
xuesong.jiangd91230d2021-10-20 15:51:10 +0800593 sink_priv->is_flushing = FALSE;
594 GST_OBJECT_UNLOCK(sink);
595 break;
596 }
597 case GST_EVENT_SEGMENT:
598 {
599 GST_OBJECT_LOCK(sink);
600 gst_event_copy_segment(event, &sink_priv->segment);
601 GST_INFO_OBJECT(sink, "configured segment %" GST_SEGMENT_FORMAT, &sink_priv->segment);
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800602 // TODO set play rate to tunnel lib, 切换rate这部分是不是只需要audio那边set即可
xuesong.jiangd91230d2021-10-20 15:51:10 +0800603 GST_OBJECT_UNLOCK(sink);
604 break;
605 }
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800606 case GST_EVENT_EOS:
607 {
608 GST_OBJECT_LOCK(sink);
609 sink_priv->got_eos = TRUE;
610 GST_OBJECT_UNLOCK(sink);
611
612 gst_wait_eos_signal(sink);
613 }
xuesong.jiangd91230d2021-10-20 15:51:10 +0800614 default:
615 {
616 GST_DEBUG_OBJECT(sink, "pass to basesink");
xuesong.jiang7c724a52021-10-22 17:18:58 +0800617 return GST_BASE_SINK_CLASS(parent_class)->event((GstBaseSink *)sink, event);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800618 }
619 }
620 gst_event_unref(event);
621 return result;
xuesong.jiang1801e172021-10-11 10:56:41 +0800622}
623
624/* private interface definition */
xuesong.jiangd91230d2021-10-20 15:51:10 +0800625static void gst_aml_video_sink_reset_private(GstAmlVideoSink *sink)
xuesong.jiang1801e172021-10-11 10:56:41 +0800626{
xuesong.jiangd91230d2021-10-20 15:51:10 +0800627 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
628 memset(sink_priv, 0, sizeof(GstAmlVideoSinkPrivate));
629 sink_priv->render_device_name = RENDER_DEVICE_NAME;
630 sink_priv->use_dmabuf = USE_DMABUF;
xuesong.jiang50a0f932021-11-15 15:18:51 +0800631 sink_priv->mediasync_instanceid = -1;
xuesong.jiangd91230d2021-10-20 15:51:10 +0800632}
633
xuesong.jiang1700bab2021-11-17 17:11:11 +0800634void gst_render_msg_callback(void *userData, RenderMsgType type, void *msg)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800635{
xuesong.jiange90be372021-10-21 11:29:57 +0800636 GstAmlVideoSink *sink = (GstAmlVideoSink *)userData;
637 switch (type)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800638 {
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800639 case MSG_DISPLAYED_BUFFER:
640 {
641 GST_LOG_OBJECT(sink, "get message: MSG_DISPLAYED_BUFFER from tunnel lib");
642 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
643 RenderBuffer *tunnel_lib_buf_wrap = (RenderBuffer *)msg;
644 RenderDmaBuffer *dmabuf = &tunnel_lib_buf_wrap->dma;
645 GstBuffer *buffer = (GstBuffer *)tunnel_lib_buf_wrap->priv;
646 if (buffer)
647 {
648 sink->rendered++;
649 if ((sink_priv->got_eos || sink_priv->is_flushing) && sink->queued == sink->rendered)
650 {
651 gst_emit_eos_signal(sink);
652 }
653 }
654 else
655 {
656 GST_ERROR_OBJECT(sink, "tunnel lib: return void GstBuffer when MSG_DISPLAYED_BUFFER");
657 }
658
659 GST_DEBUG_OBJECT(sink, "buf out:%p\n\
660 planeCnt:%d, plane[0].fd:%d, plane[1].fd:%d\n\
661 pts:%lld, buf stat | queued:%d, dequeued:%d, rendered:%d",
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800662 buffer,
663 dmabuf->planeCnt, dmabuf->fd[0], dmabuf->fd[1],
664 buffer ? GST_BUFFER_PTS(buffer) : -1, sink->queued, sink->dequeued, sink->rendered);
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800665 break;
666 }
xuesong.jiang50a0f932021-11-15 15:18:51 +0800667 case MSG_RELEASE_BUFFER:
xuesong.jiangd91230d2021-10-20 15:51:10 +0800668 {
xuesong.jiang3e593432021-11-25 16:10:03 +0800669 GST_LOG_OBJECT(sink, "get message: MSG_RELEASE_BUFFER from tunnel lib");
xuesong.jiange90be372021-10-21 11:29:57 +0800670 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiang50a0f932021-11-15 15:18:51 +0800671 RenderBuffer *tunnel_lib_buf_wrap = (RenderBuffer *)msg;
672 GstBuffer *buffer = (GstBuffer *)tunnel_lib_buf_wrap->priv;
xuesong.jiange90be372021-10-21 11:29:57 +0800673
674 if (buffer)
675 {
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800676 GST_DEBUG_OBJECT(sink, "get message: MSG_RELEASE_BUFFER from tunnel lib, buffer:%p, from pool:%p", buffer, buffer->pool);
xuesong.jiange90be372021-10-21 11:29:57 +0800677 gst_buffer_unref(buffer);
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800678 sink->dequeued++;
xuesong.jiange90be372021-10-21 11:29:57 +0800679 }
680 else
681 {
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800682 GST_ERROR_OBJECT(sink, "tunnel lib: return void GstBuffer when MSG_RELEASE_BUFFER");
xuesong.jiange90be372021-10-21 11:29:57 +0800683 }
xuesong.jiang50a0f932021-11-15 15:18:51 +0800684 render_free_render_buffer_wrap(sink_priv->render_device_handle, tunnel_lib_buf_wrap);
685 break;
686 }
687 case MSG_CONNECTED_FAIL:
688 {
689 GST_ERROR_OBJECT(sink, "tunnel lib: should not send message:%d", type);
690 break;
691 }
692 case MSG_DISCONNECTED_FAIL:
693 {
694 GST_ERROR_OBJECT(sink, "tunnel lib: should not send message:%d", type);
xuesong.jiange90be372021-10-21 11:29:57 +0800695 break;
xuesong.jiangd91230d2021-10-20 15:51:10 +0800696 }
xuesong.jiange90be372021-10-21 11:29:57 +0800697 default:
698 {
699 GST_ERROR_OBJECT(sink, "tunnel lib: error message type");
700 }
701 }
702 return;
703}
704
xuesong.jiang50a0f932021-11-15 15:18:51 +0800705int gst_render_val_callback(void *userData, int key, void *value)
706{
707 GstAmlVideoSink *vsink = (GstAmlVideoSink *)userData;
708 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(vsink);
xuesong.jiang32d78282021-11-18 19:24:15 +0800709 int *val = (int *)value;
xuesong.jiang50a0f932021-11-15 15:18:51 +0800710 gint ret = 0;
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800711 switch (key)
xuesong.jiang50a0f932021-11-15 15:18:51 +0800712 {
xuesong.jiang75ef01c2021-12-09 17:08:52 +0800713 case KEY_MEDIASYNC_INSTANCE_ID:
xuesong.jiang50a0f932021-11-15 15:18:51 +0800714 {
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800715 if (render_set(sink_priv->render_device_handle, KEY_MEDIASYNC_SYNC_MODE, (void *)&vsink->avsync_mode) == -1)
716 {
717 GST_ERROR_OBJECT(vsink, "tunnel lib: set syncmode error");
718 ret = -1;
719 }
xuesong.jiang50a0f932021-11-15 15:18:51 +0800720 if (gst_get_mediasync_instanceid(vsink))
721 {
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800722 *val = sink_priv->mediasync_instanceid;
723 GST_DEBUG_OBJECT(vsink, "get mediasync instance id:%d", *val);
xuesong.jiang50a0f932021-11-15 15:18:51 +0800724 }
725 else
726 {
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800727 GST_ERROR_OBJECT(vsink, "can't get mediasync instance id, use vmaster");
xuesong.jiang50a0f932021-11-15 15:18:51 +0800728 ret = -1;
729 }
730 break;
731 }
732 case KEY_VIDEO_FORMAT:
733 {
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800734 if (sink_priv->video_info.finfo != NULL)
xuesong.jiang32d78282021-11-18 19:24:15 +0800735 {
736 *val = sink_priv->video_info.finfo->format;
737 GST_DEBUG_OBJECT(vsink, "get video format:%d", *val);
738 }
739 else
xuesong.jiang50a0f932021-11-15 15:18:51 +0800740 {
741 GST_ERROR_OBJECT(vsink, "get video format error");
xuesong.jiang32d78282021-11-18 19:24:15 +0800742 *val = GST_VIDEO_FORMAT_UNKNOWN;
xuesong.jiang50a0f932021-11-15 15:18:51 +0800743 ret = -1;
744 }
745 break;
746 }
747 default:
748 {
749 GST_ERROR_OBJECT(vsink, "tunnel lib: error key type");
750 ret = -1;
751 }
752 }
753 return ret;
754}
755
xuesong.jiang7c724a52021-10-22 17:18:58 +0800756static gboolean gst_aml_video_sink_tunnel_buf(GstAmlVideoSink *vsink, GstBuffer *gst_buf, RenderBuffer *tunnel_lib_buf_wrap)
xuesong.jiange90be372021-10-21 11:29:57 +0800757{
758 // only support dma buf
xuesong.jiangf190e2a2021-11-22 20:26:00 +0800759 RenderDmaBuffer *dmabuf = &tunnel_lib_buf_wrap->dma;
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800760 GstMemory *dma_mem = NULL;
761 GstVideoMeta *vmeta = NULL;
xuesong.jiange90be372021-10-21 11:29:57 +0800762 guint n_mem = 0;
xuesong.jiangf190e2a2021-11-22 20:26:00 +0800763 gboolean ret = TRUE;
xuesong.jiange90be372021-10-21 11:29:57 +0800764
xuesong.jiangeb46f672021-11-19 19:05:56 +0800765 if (gst_buf == NULL || tunnel_lib_buf_wrap == NULL || dmabuf == NULL)
xuesong.jiange90be372021-10-21 11:29:57 +0800766 {
767 GST_ERROR_OBJECT(vsink, "input params error");
xuesong.jiangf190e2a2021-11-22 20:26:00 +0800768 ret = FALSE;
xuesong.jiange90be372021-10-21 11:29:57 +0800769 goto error;
770 }
xuesong.jiang3e593432021-11-25 16:10:03 +0800771 gst_buffer_ref(gst_buf);
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800772 n_mem = gst_buffer_n_memory(gst_buf);
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800773 vmeta = gst_buffer_get_video_meta(gst_buf);
774 if (vmeta == NULL)
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800775 {
776 GST_ERROR_OBJECT(vsink, "not found video meta info");
xuesong.jiangf190e2a2021-11-22 20:26:00 +0800777 ret = FALSE;
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800778 goto error;
779 }
780 if (n_mem > RENDER_MAX_PLANES || vmeta->n_planes > RENDER_MAX_PLANES || n_mem != vmeta->n_planes)
xuesong.jiange90be372021-10-21 11:29:57 +0800781 {
782 GST_ERROR_OBJECT(vsink, "too many memorys in gst buffer");
783 goto error;
784 }
xuesong.jiangeb46f672021-11-19 19:05:56 +0800785 GST_DEBUG_OBJECT(vsink, "dbg3-0, dmabuf:%p", dmabuf);
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800786
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800787 dmabuf->planeCnt = n_mem;
788 dmabuf->width = vmeta->width;
789 dmabuf->height = vmeta->height;
xuesong.jiangf190e2a2021-11-22 20:26:00 +0800790
791 GST_DEBUG_OBJECT(vsink, "dbgjxs, vmeta->width:%d, dmabuf->width:%d", vmeta->width, dmabuf->width);
792
xuesong.jiang7c724a52021-10-22 17:18:58 +0800793 for (guint i = 0; i < n_mem; i++)
xuesong.jiange90be372021-10-21 11:29:57 +0800794 {
795 gint dmafd;
796 gsize size, offset, maxsize;
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800797 dma_mem = gst_buffer_peek_memory(gst_buf, i);
xuesong.jiangf190e2a2021-11-22 20:26:00 +0800798 guint mem_idx = 0;
799 guint length = 0;
800 gsize skip = 0;
801
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800802 if (!gst_is_dmabuf_memory(dma_mem))
xuesong.jiange90be372021-10-21 11:29:57 +0800803 {
804 GST_ERROR_OBJECT(vsink, "not support non-dma buf");
xuesong.jiangf190e2a2021-11-22 20:26:00 +0800805 ret = FALSE;
xuesong.jiange90be372021-10-21 11:29:57 +0800806 goto error;
807 }
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800808 size = gst_memory_get_sizes(dma_mem, &offset, &maxsize);
xuesong.jiang16983c92021-12-30 10:57:17 +0800809 GST_LOG_OBJECT(vsink, "get memory size:%d, offeset:%d, maxsize:%d", size, offset, maxsize);
810
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800811 dmafd = gst_dmabuf_memory_get_fd(dma_mem);
812 dmabuf->handle[i] = 0;
813 dmabuf->fd[i] = dmafd;
814 dmabuf->size[i] = dma_mem->size;
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800815 dmabuf->stride[i] = vmeta->stride[i];
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800816 if (gst_buffer_find_memory(gst_buf, vmeta->offset[i], 1, &mem_idx, &length, &skip) && mem_idx == i)
xuesong.jiangf190e2a2021-11-22 20:26:00 +0800817 {
818 dmabuf->offset[i] = dma_mem->offset + skip;
819 GST_DEBUG_OBJECT(vsink, "get skip from buffer:%d, offset[%d]:%d", skip, i, dmabuf->offset[i]);
820 }
821 else
822 {
823 GST_ERROR_OBJECT(vsink, "get skip from buffer error");
824 ret = FALSE;
825 goto error;
826 }
827
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800828 GST_DEBUG_OBJECT(vsink, "dma buffer layer:%d, handle:%d, fd:%d, size:%d, offset:%d, stride:%d",
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800829 i, dmabuf->handle[i], dmabuf->fd[i], dmabuf->size[i], dmabuf->offset[i], dmabuf->stride[i]);
xuesong.jiange90be372021-10-21 11:29:57 +0800830 }
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800831 tunnel_lib_buf_wrap->flag = BUFFER_FLAG_EXTER_DMA_BUFFER;
xuesong.jiange90be372021-10-21 11:29:57 +0800832 tunnel_lib_buf_wrap->pts = GST_BUFFER_PTS(gst_buf);
xuesong.jiang8e8a58a2021-11-15 17:02:41 +0800833 tunnel_lib_buf_wrap->priv = (void *)gst_buf;
xuesong.jiang3e593432021-11-25 16:10:03 +0800834 GST_DEBUG_OBJECT(vsink, "set tunnel lib buf priv:%p from pool:%p", tunnel_lib_buf_wrap->priv, gst_buf->pool);
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800835 GST_DEBUG_OBJECT(vsink, "dbg: buf in:%p, planeCnt:%d, plane[0].fd:%d, plane[1].fd:%d",
836 tunnel_lib_buf_wrap->priv,
837 dmabuf->planeCnt,
838 dmabuf->fd[0],
839 dmabuf->fd[1]);
840
xuesong.jiangf190e2a2021-11-22 20:26:00 +0800841 return ret;
xuesong.jiange90be372021-10-21 11:29:57 +0800842
843error:
xuesong.jiangf190e2a2021-11-22 20:26:00 +0800844 return ret;
xuesong.jiang1801e172021-10-11 10:56:41 +0800845}
846
xuesong.jiang50a0f932021-11-15 15:18:51 +0800847static gboolean gst_get_mediasync_instanceid(GstAmlVideoSink *vsink)
xuesong.jiangb4c09b52021-10-26 20:18:35 +0800848{
xuesong.jiang75ef01c2021-12-09 17:08:52 +0800849 GST_DEBUG_OBJECT(vsink, "trace in");
xuesong.jiang16983c92021-12-30 10:57:17 +0800850#if GST_USE_PLAYBIN
xuesong.jiang50a0f932021-11-15 15:18:51 +0800851 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(vsink);
852 GstElement *asink = gst_aml_video_sink_find_audio_sink(vsink);
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800853 if (!asink)
854 {
855 GST_DEBUG_OBJECT(vsink, "pipeline don't have audio sink element");
856 return FALSE;
857 }
xuesong.jiang50a0f932021-11-15 15:18:51 +0800858 GstClock *amlclock = gst_aml_hal_asink_get_clock((GstElement *)asink);
859 gboolean ret = TRUE;
xuesong.jiangb4c09b52021-10-26 20:18:35 +0800860 if (amlclock)
861 {
xuesong.jiang50a0f932021-11-15 15:18:51 +0800862 sink_priv->mediasync_instanceid = gst_aml_clock_get_session_id(amlclock);
863 GST_DEBUG_OBJECT(vsink, "get mediasync instance id:%d, from aml audio clock:%p. in aml audio sink:%p", sink_priv->mediasync_instanceid, amlclock, vsink);
864 if (sink_priv->mediasync_instanceid == -1)
865 {
866 GST_ERROR_OBJECT(vsink, "audio sink: don't have valid mediasync instance id");
867 ret = FALSE;
868 }
xuesong.jiangb4c09b52021-10-26 20:18:35 +0800869 }
870 else
871 {
xuesong.jiang50a0f932021-11-15 15:18:51 +0800872 GST_WARNING_OBJECT(vsink, "no clock: vmaster mode");
873 ret = FALSE;
xuesong.jiangb4c09b52021-10-26 20:18:35 +0800874 }
xuesong.jiang192316f2021-10-27 14:51:56 +0800875 gst_object_unref(asink);
xuesong.jiang75ef01c2021-12-09 17:08:52 +0800876#else
877 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(vsink);
878 gboolean ret = TRUE;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800879 FILE *fp;
xuesong.jiang75ef01c2021-12-09 17:08:52 +0800880 fp = fopen("/data/MediaSyncId", "r");
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800881 if (fp == NULL)
882 {
xuesong.jiang75ef01c2021-12-09 17:08:52 +0800883 GST_ERROR_OBJECT(vsink, "could not open file:/data/MediaSyncId failed");
884 ret = FALSE;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800885 }
886 else
887 {
xuesong.jiang16983c92021-12-30 10:57:17 +0800888 size_t read_size = 0;
889 read_size = fread(&sink_priv->mediasync_instanceid, sizeof(int), 1, fp);
890 if (read_size != sizeof(int))
891 {
892 GST_DEBUG_OBJECT(vsink, "get mediasync instance id read error");
893 }
xuesong.jiang75ef01c2021-12-09 17:08:52 +0800894 fclose(fp);
895 GST_DEBUG_OBJECT(vsink, "get mediasync instance id:0x%x", sink_priv->mediasync_instanceid);
896 }
897#endif
xuesong.jiang50a0f932021-11-15 15:18:51 +0800898 return ret;
xuesong.jiangb4c09b52021-10-26 20:18:35 +0800899}
900
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800901static void gst_emit_eos_signal(GstAmlVideoSink *vsink)
902{
903 GST_DEBUG_OBJECT(vsink, "emit eos signal");
904 g_mutex_lock(&vsink->eos_lock);
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800905 g_cond_signal(&vsink->eos_cond);
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800906 g_mutex_unlock(&vsink->eos_lock);
907}
908
909static void gst_wait_eos_signal(GstAmlVideoSink *vsink)
910{
911 GST_DEBUG_OBJECT(vsink, "waitting eos signal");
912 g_mutex_lock(&vsink->eos_lock);
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800913 g_cond_wait(&vsink->eos_cond, &vsink->eos_lock);
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800914 g_mutex_unlock(&vsink->eos_lock);
915 GST_DEBUG_OBJECT(vsink, "waitted eos signal");
916}
917
xuesong.jiang16983c92021-12-30 10:57:17 +0800918#if GST_USE_PLAYBIN
xuesong.jiang50a0f932021-11-15 15:18:51 +0800919static GstElement *gst_aml_video_sink_find_audio_sink(GstAmlVideoSink *sink)
xuesong.jiangb4c09b52021-10-26 20:18:35 +0800920{
xuesong.jiang75ef01c2021-12-09 17:08:52 +0800921 GST_DEBUG_OBJECT(sink, "trace in");
xuesong.jiang50a0f932021-11-15 15:18:51 +0800922 GstElement *audioSink = 0;
923 GstElement *pipeline = 0;
924 GstElement *element, *elementPrev = 0;
xuesong.jiangb4c09b52021-10-26 20:18:35 +0800925
xuesong.jiang50a0f932021-11-15 15:18:51 +0800926 element = GST_ELEMENT_CAST(sink);
927 do
928 {
929 if (elementPrev)
930 {
931 gst_object_unref(elementPrev);
932 }
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800933 // TODO use this func will ref elment,but when unref these element?
xuesong.jiang50a0f932021-11-15 15:18:51 +0800934 element = GST_ELEMENT_CAST(gst_element_get_parent(element));
935 if (element)
936 {
937 elementPrev = pipeline;
938 pipeline = element;
939 }
940 } while (element != 0);
xuesong.jiangb4c09b52021-10-26 20:18:35 +0800941
xuesong.jiang50a0f932021-11-15 15:18:51 +0800942 if (pipeline)
943 {
944 GstIterator *iterElement = gst_bin_iterate_recurse(GST_BIN(pipeline));
945 if (iterElement)
946 {
947 GValue itemElement = G_VALUE_INIT;
948 while (gst_iterator_next(iterElement, &itemElement) == GST_ITERATOR_OK)
xuesong.jiangb4c09b52021-10-26 20:18:35 +0800949 {
xuesong.jiang50a0f932021-11-15 15:18:51 +0800950 element = (GstElement *)g_value_get_object(&itemElement);
951 if (element && !GST_IS_BIN(element))
952 {
953 int numSrcPads = 0;
xuesong.jiangb4c09b52021-10-26 20:18:35 +0800954
xuesong.jiang50a0f932021-11-15 15:18:51 +0800955 GstIterator *iterPad = gst_element_iterate_src_pads(element);
956 if (iterPad)
957 {
958 GValue itemPad = G_VALUE_INIT;
959 while (gst_iterator_next(iterPad, &itemPad) == GST_ITERATOR_OK)
xuesong.jiangb4c09b52021-10-26 20:18:35 +0800960 {
xuesong.jiang50a0f932021-11-15 15:18:51 +0800961 GstPad *pad = (GstPad *)g_value_get_object(&itemPad);
962 if (pad)
963 {
964 ++numSrcPads;
965 }
966 g_value_reset(&itemPad);
xuesong.jiangb4c09b52021-10-26 20:18:35 +0800967 }
xuesong.jiang50a0f932021-11-15 15:18:51 +0800968 gst_iterator_free(iterPad);
969 }
xuesong.jiangb4c09b52021-10-26 20:18:35 +0800970
xuesong.jiang50a0f932021-11-15 15:18:51 +0800971 if (numSrcPads == 0)
972 {
973 GstElementClass *ec = GST_ELEMENT_GET_CLASS(element);
974 if (ec)
975 {
976 const gchar *meta = gst_element_class_get_metadata(ec, GST_ELEMENT_METADATA_KLASS);
977 if (meta && strstr(meta, "Sink") && strstr(meta, "Audio"))
978 {
979 audioSink = (GstElement *)gst_object_ref(element);
980 gchar *name = gst_element_get_name(element);
981 if (name)
982 {
983 GST_DEBUG("detected audio sink: name (%s)", name);
984 g_free(name);
985 }
986 g_value_reset(&itemElement);
987 break;
988 }
989 }
990 }
991 }
992 g_value_reset(&itemElement);
993 }
994 gst_iterator_free(iterElement);
995 }
996
997 gst_object_unref(pipeline);
998 }
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800999 GST_DEBUG_OBJECT(sink, "trace out get audioSink:%p", audioSink);
xuesong.jiang50a0f932021-11-15 15:18:51 +08001000 return audioSink;
1001}
xuesong.jiang16983c92021-12-30 10:57:17 +08001002#endif
xuesong.jiang50a0f932021-11-15 15:18:51 +08001003
1004static gboolean gst_render_set_params(GstVideoSink *vsink)
1005{
1006 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(vsink);
1007 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
1008 GstVideoInfo *video_info = &(sink_priv->video_info);
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08001009 int tunnelmode = 1; //1 for tunnel mode; 0 for non-tunnel mode
xuesong.jiang50a0f932021-11-15 15:18:51 +08001010
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001011 // RenderWindowSize window_size = {0, 0, video_info->width, video_info->height};
xuesong.jiang50a0f932021-11-15 15:18:51 +08001012 RenderFrameSize frame_size = {video_info->width, video_info->height};
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08001013 GstVideoFormat format = video_info->finfo ? video_info->finfo->format : GST_VIDEO_FORMAT_UNKNOWN;
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001014 // if (render_set(sink_priv->render_device_handle, KEY_WINDOW_SIZE, &window_size) == -1)
1015 // {
1016 // GST_ERROR_OBJECT(vsink, "tunnel lib: set window size error");
1017 // return FALSE;
1018 // }
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08001019 if (render_set(sink_priv->render_device_handle, KEY_MEDIASYNC_TUNNEL_MODE, (void *)&tunnelmode) == -1)
1020 {
1021 GST_ERROR_OBJECT(vsink, "tunnel lib: set tunnelmode error");
1022 return FALSE;
1023 }
xuesong.jiangf190e2a2021-11-22 20:26:00 +08001024 if (render_set(sink_priv->render_device_handle, KEY_FRAME_SIZE, &frame_size) == -1)
xuesong.jiang50a0f932021-11-15 15:18:51 +08001025 {
1026 GST_ERROR_OBJECT(vsink, "tunnel lib: set frame size error");
1027 return FALSE;
1028 }
xuesong.jiangf190e2a2021-11-22 20:26:00 +08001029 if (render_set(sink_priv->render_device_handle, KEY_VIDEO_FORMAT, &format) == -1)
xuesong.jiang32d78282021-11-18 19:24:15 +08001030 {
1031 GST_ERROR_OBJECT(vsink, "tunnel lib: set video format error");
1032 return FALSE;
1033 }
1034
xuesong.jiang50a0f932021-11-15 15:18:51 +08001035 return TRUE;
xuesong.jiangb4c09b52021-10-26 20:18:35 +08001036}
1037
xuesong.jiang1801e172021-10-11 10:56:41 +08001038/* plugin init */
xuesong.jiangd91230d2021-10-20 15:51:10 +08001039static gboolean plugin_init(GstPlugin *plugin)
1040{
xuesong.jiang1700bab2021-11-17 17:11:11 +08001041 GST_DEBUG_CATEGORY_INIT(gst_aml_video_sink_debug, "amlvideosink", 0,
1042 " aml video sink");
xuesong.jiang1801e172021-10-11 10:56:41 +08001043
xuesong.jiangf0ebebe2021-12-24 09:41:15 +08001044 gint rank = 1;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08001045 const char *rank_env = getenv("GST_AML_VIDEO_SINK_RANK");
1046 if (rank_env)
1047 {
1048 rank = atoi(rank_env);
1049 }
xuesong.jiangf0ebebe2021-12-24 09:41:15 +08001050
1051 return gst_element_register(plugin, "amlvideosink", rank,
xuesong.jiangd91230d2021-10-20 15:51:10 +08001052 GST_TYPE_AML_VIDEO_SINK);
xuesong.jiang1801e172021-10-11 10:56:41 +08001053}
1054
xuesong.jiang5c0d1b82021-11-16 19:30:56 +08001055#ifndef VERSION
1056#define VERSION "0.1.0"
1057#endif
1058#ifndef PACKAGE
1059#define PACKAGE "aml_package"
1060#endif
1061#ifndef PACKAGE_NAME
1062#define PACKAGE_NAME "aml_media"
1063#endif
1064#ifndef GST_PACKAGE_ORIGIN
1065#define GST_PACKAGE_ORIGIN "http://amlogic.com"
1066#endif
1067// GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR, amlvideosink,
1068// "aml Video Sink", plugin_init, VERSION, "LGPL",
1069// "gst-plugin-video-sink", "")
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08001070GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
1071 GST_VERSION_MINOR,
1072 amlvideosink,
1073 "Amlogic plugin for video decoding/rendering",
1074 plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN)