blob: fcc890dc10104664ca9a8ebfa8f8091cea9f1520 [file] [log] [blame]
xuesong.jiang16983c92021-12-30 10:57:17 +08001/* GStreamer
xuesong.jiangf6734c62022-04-26 13:46:11 +08002 * Copyright (C) 2022 <xuesong.jiang@amlogic.com>
xuesong.jiang16983c92021-12-30 10:57:17 +08003 *
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"
fei.dengbdb18e52023-08-16 06:42:34 +000034#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)
xuesong.jiang75ef01c2021-12-09 17:08:52 +080038#include <stdio.h>
fei.deng10e3d502023-05-10 06:52:46 +000039#include <unistd.h>
xuesong.jiang192316f2021-10-27 14:51:56 +080040// #endif
41// #endif
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +080042#include "ge2drotation.h"
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 { \
fei.dengbdb18e52023-08-16 06:42:34 +000048 GST_TRACE("dbg basesink ctxt lock | aml | locking | %p", obj); \
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +080049 g_mutex_lock(GST_OBJECT_GET_LOCK(obj)); \
fei.dengbdb18e52023-08-16 06:42:34 +000050 GST_TRACE("dbg basesink ctxt lock | aml | locked | %p", obj); \
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +080051 }
xuesong.jiang91391f52021-11-19 15:42:30 +080052#endif
53
54#ifdef GST_OBJECT_UNLOCK
55#undef GST_OBJECT_UNLOCK
xuesong.jiang8e09c742022-07-27 16:38:32 +080056#define GST_OBJECT_UNLOCK(obj) \
57 { \
fei.dengbdb18e52023-08-16 06:42:34 +000058 GST_TRACE("dbg basesink ctxt lock | aml | unlocking | %p", obj); \
xuesong.jiang8e09c742022-07-27 16:38:32 +080059 g_mutex_unlock(GST_OBJECT_GET_LOCK(obj)); \
fei.dengbdb18e52023-08-16 06:42:34 +000060 GST_TRACE("dbg basesink ctxt lock | aml | unlocked | %p", obj); \
xuesong.jiang58e75f82022-06-30 19:23:20 +080061 }
62#endif
63
64#ifdef GST_BASE_SINK_PREROLL_LOCK
65#undef GST_BASE_SINK_PREROLL_LOCK
xuesong.jiang8e09c742022-07-27 16:38:32 +080066#define GST_BASE_SINK_PREROLL_LOCK(obj) \
67 { \
fei.dengbdb18e52023-08-16 06:42:34 +000068 GST_TRACE("dbg basesink preroll lock | aml | locking | %p", obj); \
xuesong.jiang8e09c742022-07-27 16:38:32 +080069 g_mutex_lock(GST_BASE_SINK_GET_PREROLL_LOCK(obj)); \
fei.dengbdb18e52023-08-16 06:42:34 +000070 GST_TRACE("dbg basesink preroll lock | aml | locked | %p", obj); \
xuesong.jiang58e75f82022-06-30 19:23:20 +080071 }
72#endif
73
74#ifdef GST_BASE_SINK_PREROLL_UNLOCK
75#undef GST_BASE_SINK_PREROLL_UNLOCK
xuesong.jiang8e09c742022-07-27 16:38:32 +080076#define GST_BASE_SINK_PREROLL_UNLOCK(obj) \
77 { \
fei.dengbdb18e52023-08-16 06:42:34 +000078 GST_TRACE("dbg basesink preroll lock | aml | unlocking | %p", obj); \
xuesong.jiang8e09c742022-07-27 16:38:32 +080079 g_mutex_unlock(GST_BASE_SINK_GET_PREROLL_LOCK(obj)); \
fei.dengbdb18e52023-08-16 06:42:34 +000080 GST_TRACE("dbg basesink preroll lock | aml | unlocked | %p", obj); \
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +080081 }
xuesong.jiang91391f52021-11-19 15:42:30 +080082#endif
83
xuesong.jiangc26425b2022-05-12 20:37:22 +080084#define GST_IMPORT_LGE_PROP 0
85
xuesong.jiang1801e172021-10-11 10:56:41 +080086/* signals */
xuesong.jiangd91230d2021-10-20 15:51:10 +080087enum
88{
fei.dengbdb18e52023-08-16 06:42:34 +000089 SIGNAL_FIRSTFRAME,
90 SIGNAL_UNDERFLOW,
hanghang.luo39bed672024-04-19 02:50:50 +000091 SIGNAL_DECODEDBUFFER,
le.han7bb29b62024-08-07 03:17:09 +000092 SIGNAL_FRAMEFREEZE,
93 SIGNAL_RESYNC,
94 SIGNAL_FRAMEDROP,
xuesong.jiangd91230d2021-10-20 15:51:10 +080095 LAST_SIGNAL
xuesong.jiang1801e172021-10-11 10:56:41 +080096};
97
xuesong.jiangd91230d2021-10-20 15:51:10 +080098/* Properties */
99enum
100{
101 PROP_0,
102 PROP_FULLSCREEN,
103 PROP_SETMUTE,
xuesong.jianga507a4b2022-10-28 16:28:29 +0800104 PROP_DEFAULT_SYNC,
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800105 PROP_AVSYNC_MODE,
xuesong.jiang62ed50e2022-04-13 16:55:47 +0800106 PROP_VIDEO_FRAME_DROP_NUM,
xuesong.jiang1a9c2822022-04-24 11:35:07 +0800107 PROP_WINDOW_SET,
xuesong.jiang16ae3212022-07-12 15:32:10 +0800108 PROP_RES_USAGE,
xuesong.jiang5eb01712022-10-21 19:47:54 +0800109 PROP_DISPLAY_OUTPUT,
fei.deng978b2422023-11-30 10:33:23 +0000110 PROP_SHOW_FIRST_FRAME_ASAP,
le.hanb62dfce2024-02-28 03:23:12 +0000111 PROP_KEEP_LAST_FRAME_ON_FLUSH,
hanghang.luo39bed672024-04-19 02:50:50 +0000112 PROP_ENABLE_USER_RENDERING,
le.hande92b682024-05-30 07:18:19 +0000113 PROP_IMMEDIATELY_RENDER,
114 PROP_VIDEO_FRAME_DISPLAY_NUM,
kaiqiang.xiang5581e8e2024-07-23 10:39:41 +0800115 PROP_VIDEO_PTS,
fei.deng6fdfab72024-08-05 16:54:58 +0800116 PROP_ZORDER,
fei.deng56733472024-09-19 20:12:43 +0800117 PROP_FRAME_STEP_ON_PREROLL,
fei.deng3a374e52024-10-29 17:04:42 +0800118 PRO_VIDEO_LATENCY,
fei.deng053f4072024-11-20 19:05:43 +0800119 PROP_FORCE_ASPECT_RATIO,
xuesong.jiangc26425b2022-05-12 20:37:22 +0800120#if GST_IMPORT_LGE_PROP
121 PROP_LGE_RESOURCE_INFO,
122 PROP_LGE_CURRENT_PTS,
123 PROP_LGE_INTERLEAVING_TYPE,
124 PROP_LGE_APP_TYPE,
125 PROP_LGE_SYNC,
126 PROP_LGE_DISH_TRICK,
127 PROP_LGE_DISH_TRICK_IGNORE_RATE,
128#endif
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800129 PROP_VIDEO_ROTATION,
xuesong.jiangd91230d2021-10-20 15:51:10 +0800130};
131
fei.deng56733472024-09-19 20:12:43 +0800132typedef enum {
133 VIDEO_TRICK_MODE_NONE = 0, // Disable trick mode
134 VIDEO_TRICK_MODE_PAUSE = 1, // Pause the video decoder
135 VIDEO_TRICK_MODE_PAUSE_NEXT = 2, // Pause the video decoder when a new frame displayed
136 VIDEO_TRICK_MODE_IONLY = 3 // Decoding and out I frame only
137} video_trick_mode;
138
xuesong.jiangfa8903d2022-02-11 15:13:05 +0800139#define AML_VIDEO_FORMATS "{ NV21 }"
140
xuesong.jiangd91230d2021-10-20 15:51:10 +0800141#define GST_CAPS_FEATURE_MEMORY_DMABUF "memory:DMABuf"
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800142#define GST_USE_PLAYBIN 1
xuesong.jiange0c6c542022-04-11 16:10:23 +0800143#define GST_DEFAULT_AVSYNC_MODE 1 // 0:v master, 1:a master
xuesong.jiang5d2761f2022-05-05 11:43:21 +0800144#define GST_DUMP_STAT_FILENAME "amlvideosink_buf_stat"
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800145
xuesong.jiangd91230d2021-10-20 15:51:10 +0800146#define USE_DMABUF TRUE
147
bo.xiao611b8e42024-07-18 11:33:46 +0800148#define DRMBP_EXTRA_BUF_SIZE_FOR_DISPLAY 1
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800149#define DRMBP_LIMIT_MAX_BUFSIZE_TO_BUFSIZE 1
150#define DRMBP_UNLIMIT_MAX_BUFSIZE 0
hanghang.luo39bed672024-04-19 02:50:50 +0000151#define GST_AML_WAIT_TIME 5000
152#define FORMAT_NV21 0x3231564e // this value is used to be same as cobalt
xuesong.jiangb3f0f152021-12-23 20:19:08 +0800153
kaiqiang.xiangecbc1712024-07-24 15:29:38 +0800154#define PTS_90K (90000)
155
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800156#define ROT_BUFFER_MAX (5)
157#define ROT_QUEUE_MAX (20)
158
xuesong.jiang1a9c2822022-04-24 11:35:07 +0800159typedef struct _GstAmlVideoSinkWindowSet
160{
161 gboolean window_change;
162 gint x;
163 gint y;
164 gint w;
165 gint h;
166} GstAmlVideoSinkWindowSet;
167
xuesong.jiangc26425b2022-05-12 20:37:22 +0800168#if GST_IMPORT_LGE_PROP
169typedef struct _GstAmlResourceInfo
170{
171 gchar *coretype;
172 gint videoport;
173 gint audioport;
174 gint maxwidth;
175 gint maxheight;
176 gint mixerport;
177} GstAmlResourceInfo;
178
179typedef struct _GstAmlVideoSinkLgeCtxt
180{
181 GstAmlResourceInfo res_info;
182 guint interleaving_type;
183 gchar *app_type;
184 gboolean sync;
185 gboolean dish_trick;
186 gboolean dish_trick_ignore_rate;
187} GstAmlVideoSinkLgeCtxt;
188#endif
189
le.han7bb29b62024-08-07 03:17:09 +0000190typedef struct ReportInfo
191{
192 gint msg;
193 FrameDisplayInfo info;
194} ReportInfo;
195
xuesong.jiangd91230d2021-10-20 15:51:10 +0800196struct _GstAmlVideoSinkPrivate
197{
xuesong.jiang1a9c2822022-04-24 11:35:07 +0800198 GstAmlVideoSinkWindowSet window_set;
xuesong.jiangebd18352021-12-28 17:13:22 +0800199 GstBuffer *preroll_buffer;
xuesong.jiange90be372021-10-21 11:29:57 +0800200 void *render_device_handle;
xuesong.jiangd91230d2021-10-20 15:51:10 +0800201 gboolean video_info_changed;
202 gboolean use_dmabuf;
203 gboolean is_flushing;
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800204 gboolean got_eos;
xuesong.jiang50a0f932021-11-15 15:18:51 +0800205 gint mediasync_instanceid;
xuesong.jiang7c724a52021-10-22 17:18:58 +0800206 GstSegment segment;
le.han7bb29b62024-08-07 03:17:09 +0000207 GList *reportInfos;
fei.deng56733472024-09-19 20:12:43 +0800208 gboolean frame_step_on_preroll;
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800209
xuesong.jiangd91230d2021-10-20 15:51:10 +0800210 /* property params */
211 gboolean fullscreen;
212 gboolean mute;
fei.deng978b2422023-11-30 10:33:23 +0000213 gboolean show_first_frame_asap;
fei.deng68c63342023-12-05 07:37:33 +0000214 gboolean emitUnderflowSignal;
xuesong.jiangc26425b2022-05-12 20:37:22 +0800215
bo.xiao611b8e42024-07-18 11:33:46 +0800216 /* video info from caps */
217 GstVideoFormat format;
218 gboolean interlace;
219 gint dw_width;
220 gint dw_height;
221 gint src_width;
222 gint src_height;
223 gsize dw_size;
le.han30f126e2024-10-09 02:42:55 +0000224 gint dw_mode;
225 gint stride;
bo.xiao611b8e42024-07-18 11:33:46 +0800226 gint par_n;
227 gint par_d;
228 gint fps_n;
229 gint fps_d;
fei.deng3a374e52024-10-29 17:04:42 +0800230 gint video_latency;
231 gboolean set_video_latency;
fei.deng053f4072024-11-20 19:05:43 +0800232 gboolean force_aspect_ratio;
bo.xiao611b8e42024-07-18 11:33:46 +0800233
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800234 /* rotation and ge2d */
235 aml_ge2d_info_t *pge2dinfo;
236 aml_ge2d_t amlge2d;
237 ROTBuffer* rot_buffer;
238 ROTATION_DEGREE rot_degree;
239 gboolean rot_changed;
240 gboolean rot_enable_property;
241
xuesong.jiangc26425b2022-05-12 20:37:22 +0800242#if GST_IMPORT_LGE_PROP
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800243 GstAmlVideoSinkLgeCtxt lge_ctxt;
xuesong.jiangc26425b2022-05-12 20:37:22 +0800244#endif
xuesong.jiang1801e172021-10-11 10:56:41 +0800245};
246
hanghang.luo39bed672024-04-19 02:50:50 +0000247typedef struct bufferInfo
248{
249 GstAmlVideoSink *sink;
250 GstBuffer *buf;
251} bufferInfo;
252
fei.dengbdb18e52023-08-16 06:42:34 +0000253static guint g_signals[LAST_SIGNAL]= {0};
254
xuesong.jiang1801e172021-10-11 10:56:41 +0800255static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE(
256 "sink", GST_PAD_SINK, GST_PAD_ALWAYS,
257 GST_STATIC_CAPS(
258 GST_VIDEO_CAPS_MAKE(AML_VIDEO_FORMATS) ";" GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
259 GST_CAPS_FEATURE_MEMORY_DMABUF, AML_VIDEO_FORMATS)));
260
261GST_DEBUG_CATEGORY(gst_aml_video_sink_debug);
262#define GST_CAT_DEFAULT gst_aml_video_sink_debug
263#define gst_aml_video_sink_parent_class parent_class
xuesong.jiang192316f2021-10-27 14:51:56 +0800264// #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 +0800265G_DEFINE_TYPE_WITH_CODE(GstAmlVideoSink, gst_aml_video_sink,
266 GST_TYPE_VIDEO_SINK, G_ADD_PRIVATE(GstAmlVideoSink));
267
268/* public interface define */
269static void gst_aml_video_sink_get_property(GObject *object, guint prop_id,
270 GValue *value, GParamSpec *pspec);
271static void gst_aml_video_sink_set_property(GObject *object, guint prop_id,
272 const GValue *value,
273 GParamSpec *pspec);
274static void gst_aml_video_sink_finalize(GObject *object);
xuesong.jiang69031992022-06-09 19:30:35 +0800275static GstStateChangeReturn gst_aml_video_sink_change_state(GstElement *element, GstStateChange transition);
xuesong.jiang9ae8f882022-04-18 20:15:06 +0800276static gboolean gst_aml_video_sink_query(GstElement *element, GstQuery *query);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800277static gboolean gst_aml_video_sink_propose_allocation(GstBaseSink *bsink, GstQuery *query);
xuesong.jiang1801e172021-10-11 10:56:41 +0800278static GstCaps *gst_aml_video_sink_get_caps(GstBaseSink *bsink,
279 GstCaps *filter);
280static gboolean gst_aml_video_sink_set_caps(GstBaseSink *bsink, GstCaps *caps);
xuesong.jiang7c724a52021-10-22 17:18:58 +0800281static gboolean gst_aml_video_sink_show_frame(GstVideoSink *bsink, GstBuffer *buffer);
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800282static GstFlowReturn gst_aml_video_sink_show_frame_ex(GstVideoSink *vsink, GstBuffer *buffer);
xuesong.jiang22afe862022-11-09 16:27:33 +0800283static gboolean gst_aml_video_sink_pad_event (GstBaseSink *basesink, GstEvent *event);
xuesong.jiang69031992022-06-09 19:30:35 +0800284static gboolean gst_aml_video_sink_send_event(GstElement *element, GstEvent *event);
xuesong.jiang1801e172021-10-11 10:56:41 +0800285
286/* private interface define */
xuesong.jiang8e09c742022-07-27 16:38:32 +0800287static gboolean gst_aml_video_sink_check_buf(GstAmlVideoSink *sink, GstBuffer *buffer);
xuesong.jiang1801e172021-10-11 10:56:41 +0800288static void gst_aml_video_sink_reset_private(GstAmlVideoSink *sink);
fei.dengbdb18e52023-08-16 06:42:34 +0000289static void gst_render_msg_callback(void *userData, RenderMsgType type, void *msg);
290static int gst_render_val_callback(void *userData, int key, void *value);
291static gboolean gst_aml_video_sink_tunnel_buf(GstAmlVideoSink *vsink, GstBuffer *gst_buf, RenderBuffer *tunnel_lib_buf_wrap);
xuesong.jiang50a0f932021-11-15 15:18:51 +0800292static gboolean gst_get_mediasync_instanceid(GstAmlVideoSink *vsink);
le.han9ff888d2024-09-09 03:04:31 +0000293static void gst_set_report_info(void *userData, RenderMsgType type, int64_t pts, int64_t duration);
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800294static int get_rotation_buffer_idx(GstAmlVideoSink *vsink);
le.han7bb29b62024-08-07 03:17:09 +0000295
xuesong.jiang16983c92021-12-30 10:57:17 +0800296#if GST_USE_PLAYBIN
xuesong.jiang50a0f932021-11-15 15:18:51 +0800297static GstElement *gst_aml_video_sink_find_audio_sink(GstAmlVideoSink *sink);
xuesong.jiang16983c92021-12-30 10:57:17 +0800298#endif
xuesong.jiang50a0f932021-11-15 15:18:51 +0800299static gboolean gst_render_set_params(GstVideoSink *vsink);
fei.dengab16ff12024-08-07 17:58:07 +0800300//static void gst_aml_video_sink_dump_stat(GstAmlVideoSink *sink, const gchar *file_name);
le.han7bb29b62024-08-07 03:17:09 +0000301static gpointer detection_thread(gpointer data);
xuesong.jiang1801e172021-10-11 10:56:41 +0800302
303/* public interface definition */
xuesong.jiang7c724a52021-10-22 17:18:58 +0800304static void gst_aml_video_sink_class_init(GstAmlVideoSinkClass *klass)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800305{
306 GObjectClass *gobject_class;
307 GstElementClass *gstelement_class;
308 GstBaseSinkClass *gstbasesink_class;
309 GstVideoSinkClass *gstvideosink_class;
xuesong.jiang1801e172021-10-11 10:56:41 +0800310
xuesong.jiangd91230d2021-10-20 15:51:10 +0800311 gobject_class = (GObjectClass *)klass;
312 gstelement_class = (GstElementClass *)klass;
313 gstbasesink_class = (GstBaseSinkClass *)klass;
314 gstvideosink_class = (GstVideoSinkClass *)klass;
xuesong.jiang1801e172021-10-11 10:56:41 +0800315
xuesong.jiangd91230d2021-10-20 15:51:10 +0800316 gobject_class->set_property = gst_aml_video_sink_set_property;
317 gobject_class->get_property = gst_aml_video_sink_get_property;
318 gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_aml_video_sink_finalize);
xuesong.jiang1801e172021-10-11 10:56:41 +0800319
xuesong.jiangd91230d2021-10-20 15:51:10 +0800320 gst_element_class_add_static_pad_template(gstelement_class, &sink_template);
xuesong.jiang1801e172021-10-11 10:56:41 +0800321
xuesong.jiangd91230d2021-10-20 15:51:10 +0800322 gst_element_class_set_static_metadata(
323 gstelement_class, "aml video sink", "Sink/Video",
324 "Output to video tunnel lib",
325 "Xuesong.Jiang@amlogic.com<Xuesong.Jiang@amlogic.com>");
xuesong.jiang1801e172021-10-11 10:56:41 +0800326
xuesong.jiang9ae8f882022-04-18 20:15:06 +0800327 gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_aml_video_sink_change_state);
328 gstelement_class->query = GST_DEBUG_FUNCPTR(gst_aml_video_sink_query);
xuesong.jiang69031992022-06-09 19:30:35 +0800329 gstelement_class->send_event = GST_DEBUG_FUNCPTR(gst_aml_video_sink_send_event);
xuesong.jiang1801e172021-10-11 10:56:41 +0800330
xuesong.jiangd91230d2021-10-20 15:51:10 +0800331 gstbasesink_class->propose_allocation = GST_DEBUG_FUNCPTR(gst_aml_video_sink_propose_allocation);
332 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR(gst_aml_video_sink_get_caps);
333 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR(gst_aml_video_sink_set_caps);
xuesong.jiang22afe862022-11-09 16:27:33 +0800334 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_aml_video_sink_pad_event);
xuesong.jiang1801e172021-10-11 10:56:41 +0800335
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800336 gstvideosink_class->show_frame = GST_DEBUG_FUNCPTR(gst_aml_video_sink_show_frame_ex);
xuesong.jiang1801e172021-10-11 10:56:41 +0800337
xuesong.jiangd91230d2021-10-20 15:51:10 +0800338 g_object_class_install_property(
339 gobject_class, PROP_FULLSCREEN,
340 g_param_spec_boolean("fullscreen", "Fullscreen",
341 "Whether the surface should be made fullscreen ",
342 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
xuesong.jiang1801e172021-10-11 10:56:41 +0800343
xuesong.jiangd91230d2021-10-20 15:51:10 +0800344 g_object_class_install_property(
xuesong.jianga507a4b2022-10-28 16:28:29 +0800345 gobject_class, PROP_DEFAULT_SYNC,
346 g_param_spec_boolean("set-sync", "use basesink avsync",
347 "Whether use basesink sync flow. Configure when make element ",
348 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
349
350 g_object_class_install_property(
le.hande92b682024-05-30 07:18:19 +0000351 gobject_class, PROP_IMMEDIATELY_RENDER,
352 g_param_spec_int("set-immediately-render", "set immediately render",
353 "set renderlib immediately render ",
354 G_MININT, G_MAXINT, 0, G_PARAM_READWRITE));
355
356 g_object_class_install_property(
xuesong.jiangd91230d2021-10-20 15:51:10 +0800357 gobject_class, PROP_SETMUTE,
358 g_param_spec_boolean("set mute", "set mute params",
359 "Whether set screen mute ",
360 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800361
le.hanb62dfce2024-02-28 03:23:12 +0000362 g_object_class_install_property (
363 gobject_class, PROP_KEEP_LAST_FRAME_ON_FLUSH,
364 g_param_spec_boolean ("keep-last-frame-on-flush",
365 "set keep last frame on flush or not,default is keep last frame",
366 "0: clean; 1: keep", TRUE, G_PARAM_READWRITE));
367
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800368 g_object_class_install_property(
369 G_OBJECT_CLASS(klass), PROP_AVSYNC_MODE,
370 g_param_spec_int("avsync-mode", "avsync mode",
371 "Vmaster(0) Amaster(1) PCRmaster(2) IPTV(3) FreeRun(4)",
372 G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE));
xuesong.jiang62ed50e2022-04-13 16:55:47 +0800373
xuesong.jiang9ae8f882022-04-18 20:15:06 +0800374 g_object_class_install_property(
375 G_OBJECT_CLASS(klass), PROP_VIDEO_FRAME_DROP_NUM,
376 g_param_spec_int("frames-dropped", "frames-dropped",
377 "number of dropped frames",
378 0, G_MAXINT32, 0, G_PARAM_READABLE));
xuesong.jiang1a9c2822022-04-24 11:35:07 +0800379
380 g_object_class_install_property(
le.hande92b682024-05-30 07:18:19 +0000381 gobject_class, PROP_VIDEO_FRAME_DISPLAY_NUM,
382 g_param_spec_int("display-frame-num", "display frame num",
383 "number of displayed frames ",
384 0, G_MAXINT32, 0, G_PARAM_READABLE));
385
386 g_object_class_install_property(
kaiqiang.xiang5581e8e2024-07-23 10:39:41 +0800387 G_OBJECT_CLASS (klass), PROP_VIDEO_PTS,
kaiqiang.xiangecbc1712024-07-24 15:29:38 +0800388 g_param_spec_int64 ("video-pts", "video PTS",
kaiqiang.xiang5581e8e2024-07-23 10:39:41 +0800389 "current video PTS value",
390 G_MININT64, G_MAXINT64, 0, G_PARAM_READABLE));
391
392 g_object_class_install_property(
xuesong.jiang1a9c2822022-04-24 11:35:07 +0800393 G_OBJECT_CLASS(klass), PROP_WINDOW_SET,
394 g_param_spec_string("rectangle", "rectangle",
395 "Window Set Format: x,y,width,height",
396 NULL, G_PARAM_WRITABLE));
xuesong.jiangc26425b2022-05-12 20:37:22 +0800397
xuesong.jiang8e09c742022-07-27 16:38:32 +0800398 g_object_class_install_property(
xuesong.jiang16ae3212022-07-12 15:32:10 +0800399 G_OBJECT_CLASS(klass), PROP_RES_USAGE,
xuesong.jiang8e09c742022-07-27 16:38:32 +0800400 g_param_spec_int("res-usage", "res-usage",
401 "Flags to indicate intended usage",
402 G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE));
xuesong.jiang16ae3212022-07-12 15:32:10 +0800403
xuesong.jiang5eb01712022-10-21 19:47:54 +0800404 g_object_class_install_property(
405 G_OBJECT_CLASS(klass), PROP_DISPLAY_OUTPUT,
406 g_param_spec_int("display-output", "display output index",
407 "display output index, 0 is primary output and default value; 1 is extend display output",
408 G_MININT, G_MAXINT, 0, G_PARAM_READWRITE));
409
fei.deng978b2422023-11-30 10:33:23 +0000410 g_object_class_install_property(
411 G_OBJECT_CLASS(klass), PROP_SHOW_FIRST_FRAME_ASAP,
412 g_param_spec_boolean("show-first-frame-asap", "show first video frame asap",
413 "Whether showing first video frame asap, default is disable",
414 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
hanghang.luo39bed672024-04-19 02:50:50 +0000415 g_object_class_install_property (
416 G_OBJECT_CLASS(klass), PROP_ENABLE_USER_RENDERING,
417 g_param_spec_boolean ("enable-user-rendering",
418 "enable signal decoded buffer to user to rendering",
419 "0: disable; 1: enable",
420 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
fei.deng978b2422023-11-30 10:33:23 +0000421
fei.deng6fdfab72024-08-05 16:54:58 +0800422 g_object_class_install_property(
423 G_OBJECT_CLASS(klass), PROP_ZORDER,
424 g_param_spec_int("zorder", "video plane zorder",
425 "video plane zorder",
426 G_MININT, G_MAXINT, 0, G_PARAM_READWRITE));
427
fei.deng3a374e52024-10-29 17:04:42 +0800428 g_object_class_install_property(
429 G_OBJECT_CLASS(klass), PRO_VIDEO_LATENCY,
430 g_param_spec_int("video-latency", "video latency",
431 "video extra latency,the unit of value is us",
432 G_MININT, G_MAXINT, 0, G_PARAM_READWRITE));
433
fei.deng56733472024-09-19 20:12:43 +0800434 /*
435 * frame-step-on-preroll is for nts case VPEEK-001-TC2
436 * case step:
437 * 1.change pipeline state from null to pause
438 * 2.send a frame
439 * 3.invoke frame-step-on-preroll property
440 */
441 g_object_class_install_property (
442 G_OBJECT_CLASS(klass), PROP_FRAME_STEP_ON_PREROLL,
443 g_param_spec_boolean ("frame-step-on-preroll",
444 "frame step on preroll",
445 "allow frame stepping on preroll into pause",
446 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
447
fei.deng053f4072024-11-20 19:05:43 +0800448 g_object_class_install_property (
449 G_OBJECT_CLASS(klass), PROP_FORCE_ASPECT_RATIO,
450 g_param_spec_boolean ("force-aspect-ratio",
451 "force aspect ratio",
452 "When enabled scaling respects source aspect ratio", FALSE, G_PARAM_READWRITE));
453
fei.dengbdb18e52023-08-16 06:42:34 +0000454 g_signals[SIGNAL_FIRSTFRAME]= g_signal_new( "first-video-frame-callback",
455 G_TYPE_FROM_CLASS(GST_ELEMENT_CLASS(klass)),
456 (GSignalFlags) (G_SIGNAL_RUN_LAST),
457 0, /* class offset */
458 NULL, /* accumulator */
459 NULL, /* accu data */
460 g_cclosure_marshal_VOID__UINT_POINTER,
461 G_TYPE_NONE,
462 2,
463 G_TYPE_UINT,
464 G_TYPE_POINTER );
465
466 g_signals[SIGNAL_UNDERFLOW]= g_signal_new( "buffer-underflow-callback",
467 G_TYPE_FROM_CLASS(GST_ELEMENT_CLASS(klass)),
468 (GSignalFlags) (G_SIGNAL_RUN_LAST),
469 0, // class offset
470 NULL, // accumulator
471 NULL, // accu data
472 g_cclosure_marshal_VOID__UINT_POINTER,
473 G_TYPE_NONE,
474 2,
475 G_TYPE_UINT,
476 G_TYPE_POINTER );
hanghang.luo39bed672024-04-19 02:50:50 +0000477 g_signals[SIGNAL_DECODEDBUFFER]= g_signal_new ("decoded-buffer-callback",
478 G_TYPE_FROM_CLASS(GST_ELEMENT_CLASS(klass)),
479 (GSignalFlags) (G_SIGNAL_RUN_FIRST),
480 0, /* class offset */
481 NULL, /* accumulator */
482 NULL, /* accu data */
483 NULL,
484 G_TYPE_NONE,
485 1,
486 GST_TYPE_BUFFER);
le.han7bb29b62024-08-07 03:17:09 +0000487 g_signals[SIGNAL_FRAMEFREEZE]= g_signal_new( "video-frame-freeze",
488 G_TYPE_FROM_CLASS(GST_ELEMENT_CLASS(klass)),
489 (GSignalFlags) (G_SIGNAL_RUN_LAST),
490 0, /* class offset */
491 NULL, /* accumulator */
492 NULL, /* accu data */
493 NULL,
494 G_TYPE_NONE,
495 2,
496 G_TYPE_INT64,
497 G_TYPE_INT64);
498 g_signals[SIGNAL_RESYNC]= g_signal_new( "av-resync",
499 G_TYPE_FROM_CLASS(GST_ELEMENT_CLASS(klass)),
500 (GSignalFlags) (G_SIGNAL_RUN_LAST),
501 0, /* class offset */
502 NULL, /* accumulator */
503 NULL, /* accu data */
504 NULL,
505 G_TYPE_NONE,
506 2,
507 G_TYPE_INT64,
508 G_TYPE_INT64);
509 g_signals[SIGNAL_FRAMEDROP]= g_signal_new( "video-frame-drop",
510 G_TYPE_FROM_CLASS(GST_ELEMENT_CLASS(klass)),
511 (GSignalFlags) (G_SIGNAL_RUN_LAST),
512 0, /* class offset */
513 NULL, /* accumulator */
514 NULL, /* accu data */
515 NULL,
516 G_TYPE_NONE,
517 1,
518 G_TYPE_INT64);
xuesong.jiangc26425b2022-05-12 20:37:22 +0800519#if GST_IMPORT_LGE_PROP
520 g_object_class_install_property(
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800521 G_OBJECT_CLASS(klass), PROP_LGE_RESOURCE_INFO,
xuesong.jiangc26425b2022-05-12 20:37:22 +0800522 g_param_spec_object("resource-info", "resource-info",
523 "After acquisition of H/W resources is completed, allocated resource information must be delivered to the decoder and the sink",
524 GST_TYPE_STRUCTURE,
525 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
526
527 g_object_class_install_property(
528 G_OBJECT_CLASS(klass), PROP_LGE_CURRENT_PTS,
529 g_param_spec_uint64("current-pts", "current pts",
530 "get rendering timing video position",
531 0, G_MAXUINT64,
532 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
533
534 g_object_class_install_property(
535 G_OBJECT_CLASS(klass), PROP_LGE_INTERLEAVING_TYPE,
536 g_param_spec_uint("interleaving-type", "interleaving type",
537 "set 3D type",
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800538 0, G_MAXUINT,
xuesong.jiangc26425b2022-05-12 20:37:22 +0800539 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
540
541 g_object_class_install_property(
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800542 G_OBJECT_CLASS(klass), PROP_LGE_APP_TYPE,
xuesong.jiangc26425b2022-05-12 20:37:22 +0800543 g_param_spec_string("app-type", "app-type",
544 "set application type.",
545 "default_app",
546 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
547
548 g_object_class_install_property(
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800549 G_OBJECT_CLASS(klass), PROP_LGE_SYNC,
xuesong.jiangc26425b2022-05-12 20:37:22 +0800550 g_param_spec_boolean("sync", "sync",
551 "M16, H15, K2L",
552 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
553
554 g_object_class_install_property(
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800555 G_OBJECT_CLASS(klass), PROP_LGE_DISH_TRICK,
xuesong.jiangc26425b2022-05-12 20:37:22 +0800556 g_param_spec_boolean("dish-trick", "dish trick",
557 "H15, M16",
558 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
559
560 g_object_class_install_property(
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800561 G_OBJECT_CLASS(klass), PROP_LGE_DISH_TRICK_IGNORE_RATE,
xuesong.jiangc26425b2022-05-12 20:37:22 +0800562 g_param_spec_boolean("dish-trick-ignore-rate", "dish trick ignore rate",
563 "H15, M16",
564 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
565#endif
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800566
567 g_object_class_install_property (
568 G_OBJECT_CLASS (klass), PROP_VIDEO_ROTATION,
569 g_param_spec_int ("video-rotation", "video-rotation",
570 "video rotation",
571 0, 3, 0, G_PARAM_WRITABLE));
xuesong.jiang1801e172021-10-11 10:56:41 +0800572}
573
xuesong.jiangd91230d2021-10-20 15:51:10 +0800574static void gst_aml_video_sink_init(GstAmlVideoSink *sink)
575{
576 GstBaseSink *basesink = (GstBaseSink *)sink;
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800577
xuesong.jiang9ae8f882022-04-18 20:15:06 +0800578 sink->last_displayed_buf_pts = 0;
fei.deng68c63342023-12-05 07:37:33 +0000579 sink->last_dec_buf_pts = GST_CLOCK_TIME_NONE;
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800580 /* init eos detect */
581 sink->queued = 0;
582 sink->dequeued = 0;
583 sink->rendered = 0;
fei.deng6fdfab72024-08-05 16:54:58 +0800584 sink->dropped = 0;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800585 sink->avsync_mode = GST_DEFAULT_AVSYNC_MODE;
xuesong.jianga507a4b2022-10-28 16:28:29 +0800586 sink->default_sync = FALSE;
le.hande92b682024-05-30 07:18:19 +0000587 sink->immediately_render = 0;
xuesong.jiang16ae3212022-07-12 15:32:10 +0800588 sink->pip_mode = 0;
xuesong.jiang5eb01712022-10-21 19:47:54 +0800589 sink->display_output_index = 0;
sheng.liuc9f34962022-06-17 21:42:48 +0800590 sink->secure_mode = FALSE;
le.han7bb29b62024-08-07 03:17:09 +0000591 sink->detect_thread_handle = NULL;
fei.deng2f462142023-05-24 03:07:29 +0000592 sink->quit_eos_detect_thread = FALSE;
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800593 sink->rotation_thread_handle = NULL;
594 sink->quit_rotation_thread = FALSE;
595 sink->buffer_queue = gst_queue_array_new (ROT_QUEUE_MAX);
fei.deng68c63342023-12-05 07:37:33 +0000596 sink->frame_rate_num = 0;
597 sink->frame_rate_denom = 0;
598 sink->frame_rate_changed = FALSE;
599 sink->frame_rate = 0.0;
sheng.liu1a079692023-12-26 06:33:41 +0000600 sink->pixel_aspect_ratio_changed = FALSE;
601 sink->pixel_aspect_ratio = 1.0;
le.hanb62dfce2024-02-28 03:23:12 +0000602 sink->keep_last_frame_on_flush = TRUE;
hanghang.luo39bed672024-04-19 02:50:50 +0000603 //sink->enable_decoded_buffer_signal = FALSE;
fei.deng6fdfab72024-08-05 16:54:58 +0800604 sink->zorder = 0;
605 sink->update_zorder = FALSE;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800606 g_mutex_init(&sink->eos_lock);
607 g_cond_init(&sink->eos_cond);
le.han7bb29b62024-08-07 03:17:09 +0000608 g_mutex_init(&sink->report_info_lock);
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +0800609 g_mutex_init(&sink->rotation_buffer_lock);
xuesong.jiang4a832aa2022-01-06 16:44:26 +0800610
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800611 GST_AML_VIDEO_SINK_GET_PRIVATE(sink) = malloc(sizeof(GstAmlVideoSinkPrivate));
xuesong.jiangd91230d2021-10-20 15:51:10 +0800612 gst_aml_video_sink_reset_private(sink);
xuesong.jiangd2619562021-12-23 16:38:50 +0800613 gst_base_sink_set_sync(basesink, FALSE);
xuesong.jiangfc27c272022-05-11 17:09:02 +0800614
615 gst_base_sink_set_qos_enabled(basesink, FALSE);
xuesong.jiang41e0e122023-02-02 19:25:16 +0800616 gst_base_sink_set_last_sample_enabled(basesink, FALSE);
xuesong.jiang1801e172021-10-11 10:56:41 +0800617}
618
619static void gst_aml_video_sink_get_property(GObject *object, guint prop_id,
xuesong.jiangd91230d2021-10-20 15:51:10 +0800620 GValue *value, GParamSpec *pspec)
621{
622 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(object);
623 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiang1801e172021-10-11 10:56:41 +0800624
xuesong.jiangd91230d2021-10-20 15:51:10 +0800625 switch (prop_id)
626 {
627 case PROP_FULLSCREEN:
628 GST_OBJECT_LOCK(sink);
629 g_value_set_boolean(value, sink_priv->fullscreen);
630 GST_OBJECT_UNLOCK(sink);
631 break;
632 case PROP_SETMUTE:
633 GST_OBJECT_LOCK(sink);
xuesong.jiang7c724a52021-10-22 17:18:58 +0800634 g_value_set_boolean(value, sink_priv->mute);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800635 GST_OBJECT_UNLOCK(sink);
636 break;
xuesong.jianga507a4b2022-10-28 16:28:29 +0800637 case PROP_DEFAULT_SYNC:
638 GST_OBJECT_LOCK(sink);
639 g_value_set_boolean(value, sink->default_sync);
640 GST_OBJECT_UNLOCK(sink);
641 break;
le.hande92b682024-05-30 07:18:19 +0000642 case PROP_IMMEDIATELY_RENDER:
643 GST_OBJECT_LOCK(sink);
644 g_value_set_int(value, sink->immediately_render);
645 GST_OBJECT_UNLOCK(sink);
646 break;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800647 case PROP_AVSYNC_MODE:
648 GST_OBJECT_LOCK(sink);
649 g_value_set_boolean(value, sink->avsync_mode);
650 GST_OBJECT_UNLOCK(sink);
651 break;
xuesong.jiang9ae8f882022-04-18 20:15:06 +0800652 case PROP_VIDEO_FRAME_DROP_NUM:
xuesong.jiang62ed50e2022-04-13 16:55:47 +0800653 GST_OBJECT_LOCK(sink);
fei.deng6fdfab72024-08-05 16:54:58 +0800654 GST_DEBUG_OBJECT(sink, "app get frame drop num | queued:%d, dequeued:%d, dropped:%d, rendered:%d",
655 sink->queued, sink->dequeued, sink->dropped, sink->rendered);
656 g_value_set_int(value, sink->dropped);
xuesong.jiang62ed50e2022-04-13 16:55:47 +0800657 GST_OBJECT_UNLOCK(sink);
xuesong.jiang9ae8f882022-04-18 20:15:06 +0800658 break;
kaiqiang.xiang5581e8e2024-07-23 10:39:41 +0800659 case PROP_VIDEO_PTS:
660 {
661 GST_OBJECT_LOCK(sink);
662 gint64 currentPTS = sink->last_displayed_buf_pts;
663 GST_OBJECT_UNLOCK(sink);
kaiqiang.xiangecbc1712024-07-24 15:29:38 +0800664 //90K
665 currentPTS = gst_util_uint64_scale_int (currentPTS, PTS_90K, GST_SECOND);
kaiqiang.xiang5581e8e2024-07-23 10:39:41 +0800666 g_value_set_int64(value, currentPTS);
667 break;
668 }
le.hande92b682024-05-30 07:18:19 +0000669 case PROP_VIDEO_FRAME_DISPLAY_NUM:
670 GST_OBJECT_LOCK(sink);
671 GST_DEBUG_OBJECT(sink, "displayed frame num: %d", sink->queued);
672 g_value_set_int(value, sink->queued);
673 GST_OBJECT_UNLOCK(sink);
674 break;
xuesong.jiang5eb01712022-10-21 19:47:54 +0800675 case PROP_DISPLAY_OUTPUT:
676 {
677 GST_OBJECT_LOCK(sink);
678 g_value_set_int(value, sink->display_output_index);
679 GST_OBJECT_UNLOCK(sink);
680 break;
681 }
le.hanb62dfce2024-02-28 03:23:12 +0000682 case PROP_KEEP_LAST_FRAME_ON_FLUSH:
683 {
684 GST_OBJECT_LOCK(sink);
685 g_value_set_boolean(value, sink->keep_last_frame_on_flush);
686 GST_OBJECT_UNLOCK(sink);
687 break;
688 }
hanghang.luo39bed672024-04-19 02:50:50 +0000689 case PROP_ENABLE_USER_RENDERING:
690 {
691 GST_OBJECT_LOCK(sink);
692 g_value_set_boolean(value, sink->enable_decoded_buffer_signal);
693 GST_OBJECT_UNLOCK(sink);
694 break;
695 }
fei.deng6fdfab72024-08-05 16:54:58 +0800696 case PROP_ZORDER:
697 {
698 GST_OBJECT_LOCK(sink);
699 g_value_set_int(value, sink->zorder);
700 GST_OBJECT_UNLOCK(sink);
701 break;
702 }
fei.deng56733472024-09-19 20:12:43 +0800703 case PROP_FRAME_STEP_ON_PREROLL:
704 {
705 GST_OBJECT_LOCK(sink);
706 g_value_set_boolean(value, sink_priv->frame_step_on_preroll);
707 GST_OBJECT_UNLOCK(sink);
708 break;
709 }
fei.deng3a374e52024-10-29 17:04:42 +0800710 case PRO_VIDEO_LATENCY:
711 {
712 GST_OBJECT_LOCK(sink);
713 g_value_set_int(value, sink_priv->video_latency);
714 GST_OBJECT_UNLOCK(sink);
715 break;
716 }
fei.deng053f4072024-11-20 19:05:43 +0800717 case PROP_FORCE_ASPECT_RATIO:
718 {
719 g_value_set_boolean(value, sink_priv->force_aspect_ratio);
720 break;
721 }
xuesong.jiangc26425b2022-05-12 20:37:22 +0800722#if GST_IMPORT_LGE_PROP
723 case PROP_LGE_CURRENT_PTS:
724 {
725 GST_OBJECT_LOCK(sink);
726 g_value_set_uint64(value, sink->last_displayed_buf_pts);
727 GST_OBJECT_UNLOCK(sink);
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800728 break;
xuesong.jiangc26425b2022-05-12 20:37:22 +0800729 }
730#endif
xuesong.jiangd91230d2021-10-20 15:51:10 +0800731 default:
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800732 // G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800733 break;
734 }
xuesong.jiang1801e172021-10-11 10:56:41 +0800735}
736
737static void gst_aml_video_sink_set_property(GObject *object, guint prop_id,
738 const GValue *value,
xuesong.jiangd91230d2021-10-20 15:51:10 +0800739 GParamSpec *pspec)
740{
741 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(object);
742 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiang1801e172021-10-11 10:56:41 +0800743
xuesong.jiangd91230d2021-10-20 15:51:10 +0800744 switch (prop_id)
745 {
746 case PROP_FULLSCREEN:
747 GST_OBJECT_LOCK(sink);
748 gboolean is_fullscreen = g_value_get_boolean(value);
xuesong.jiange90be372021-10-21 11:29:57 +0800749 if (sink_priv->fullscreen != is_fullscreen)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800750 {
751 sink_priv->fullscreen = is_fullscreen;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800752 // TODO set full screen to tunnel lib
xuesong.jiangd91230d2021-10-20 15:51:10 +0800753 }
754 GST_OBJECT_UNLOCK(sink);
755 break;
756 case PROP_SETMUTE:
757 GST_OBJECT_LOCK(sink);
758 gboolean is_mute = g_value_get_boolean(value);
xuesong.jiange90be372021-10-21 11:29:57 +0800759 if (sink_priv->mute != is_mute)
xuesong.jiangd91230d2021-10-20 15:51:10 +0800760 {
xuesong.jiang75ef01c2021-12-09 17:08:52 +0800761 sink_priv->mute = is_mute;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800762 // TODO set full screen to tunnel lib
763 }
764 GST_OBJECT_UNLOCK(sink);
765 break;
xuesong.jianga507a4b2022-10-28 16:28:29 +0800766 case PROP_DEFAULT_SYNC:
767 {
768 GST_OBJECT_LOCK(sink);
769 sink->default_sync = g_value_get_boolean(value);
770 GST_OBJECT_UNLOCK(sink);
xuesong.jiang22afe862022-11-09 16:27:33 +0800771 gst_base_sink_set_sync(GST_BASE_SINK(sink), sink->default_sync);
xuesong.jianga507a4b2022-10-28 16:28:29 +0800772 GST_DEBUG_OBJECT(sink, "use basessink avsync flow %d", sink->default_sync);
773 break;
774 }
le.hande92b682024-05-30 07:18:19 +0000775 case PROP_IMMEDIATELY_RENDER:
776 {
777 GST_OBJECT_LOCK(sink);
778 sink->immediately_render = g_value_get_int(value);
779 GST_OBJECT_UNLOCK(sink);
780 GST_DEBUG_OBJECT(sink, "set renderlib immediately render %d", sink->immediately_render);
781 break;
782 }
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +0800783 case PROP_AVSYNC_MODE:
784 GST_OBJECT_LOCK(sink);
785 gint mode = g_value_get_int(value);
786 if (mode >= 0)
787 {
788 sink->avsync_mode = mode;
xuesong.jiang16ae3212022-07-12 15:32:10 +0800789 GST_DEBUG_OBJECT(sink, "AV sync mode %d", mode);
xuesong.jiangd91230d2021-10-20 15:51:10 +0800790 }
791 GST_OBJECT_UNLOCK(sink);
792 break;
xuesong.jiang1a9c2822022-04-24 11:35:07 +0800793 case PROP_WINDOW_SET:
794 {
795 const gchar *str = g_value_get_string(value);
796 gchar **parts = g_strsplit(str, ",", 4);
797
798 if (!parts[0] || !parts[1] || !parts[2] || !parts[3])
799 {
800 GST_ERROR("Bad window properties string");
801 }
802 else
803 {
804 int nx, ny, nw, nh;
805 nx = atoi(parts[0]);
806 ny = atoi(parts[1]);
807 nw = atoi(parts[2]);
808 nh = atoi(parts[3]);
809
810 if ((nx != sink_priv->window_set.x) ||
811 (ny != sink_priv->window_set.y) ||
812 (nw != sink_priv->window_set.w) ||
813 (nh != sink_priv->window_set.h))
814 {
815 GST_OBJECT_LOCK(sink);
816 sink_priv->window_set.window_change = true;
817 sink_priv->window_set.x = nx;
818 sink_priv->window_set.y = ny;
819 sink_priv->window_set.w = nw;
820 sink_priv->window_set.h = nh;
821
822 GST_DEBUG("set window rect (%d,%d,%d,%d)\n",
823 sink_priv->window_set.x,
824 sink_priv->window_set.y,
825 sink_priv->window_set.w,
826 sink_priv->window_set.h);
827 GST_OBJECT_UNLOCK(sink);
828 }
829 }
830
831 g_strfreev(parts);
832 break;
833 }
xuesong.jiang16ae3212022-07-12 15:32:10 +0800834 case PROP_RES_USAGE:
835 {
836 GST_OBJECT_LOCK(sink);
837 sink->pip_mode = 1;
838 GST_DEBUG_OBJECT(sink, "play video in sub layer(pip)");
839 GST_OBJECT_UNLOCK(sink);
840 break;
841 }
xuesong.jiang5eb01712022-10-21 19:47:54 +0800842 case PROP_DISPLAY_OUTPUT:
843 {
844 GST_OBJECT_LOCK(sink);
845 gint index = g_value_get_int(value);
846 if (index == 0 || index == 1)
847 {
848 sink->display_output_index = index;
849 if (sink_priv->render_device_handle)
850 {
fei.dengbdb18e52023-08-16 06:42:34 +0000851 if (render_set_value(sink_priv->render_device_handle, KEY_SELECT_DISPLAY_OUTPUT, &sink->display_output_index) == -1)
852 GST_ERROR_OBJECT(sink, "render lib update output index error");
xuesong.jiang5eb01712022-10-21 19:47:54 +0800853 }
854 }
855 GST_DEBUG_OBJECT(sink, "update display output index to:%d", sink->display_output_index);
856 GST_OBJECT_UNLOCK(sink);
857 break;
858 }
fei.deng978b2422023-11-30 10:33:23 +0000859 case PROP_SHOW_FIRST_FRAME_ASAP:
860 {
861 sink_priv->show_first_frame_asap = g_value_get_boolean(value);
862 GST_DEBUG_OBJECT(sink, "set show first frame asap %d",sink_priv->show_first_frame_asap);
863 break;
864 }
le.hanb62dfce2024-02-28 03:23:12 +0000865 case PROP_KEEP_LAST_FRAME_ON_FLUSH:
866 {
867 GST_OBJECT_LOCK(sink);
868 sink->keep_last_frame_on_flush = g_value_get_boolean(value);
869 GST_DEBUG_OBJECT(sink, "keep last frame on flush %d", sink->keep_last_frame_on_flush);
870 GST_OBJECT_UNLOCK(sink);
871 break;
872 }
hanghang.luo39bed672024-04-19 02:50:50 +0000873 case PROP_ENABLE_USER_RENDERING:
874 {
875 sink->enable_decoded_buffer_signal = g_value_get_boolean(value);
876 GST_DEBUG("set enable decoded buffer signal %d", sink->enable_decoded_buffer_signal);
fei.deng6fdfab72024-08-05 16:54:58 +0800877 } break;
878 case PROP_ZORDER:
879 {
880 GST_OBJECT_LOCK(sink);
881 sink->zorder = g_value_get_int(value);
882 sink->update_zorder = TRUE;
883 GST_DEBUG_OBJECT(sink, "set video plane zorder:%d",sink->zorder);
884 GST_OBJECT_UNLOCK(sink);
885 if (sink_priv->render_device_handle)
886 {
887 sink->update_zorder = FALSE;
888 render_set_value(sink_priv->render_device_handle, KEY_ZORDER, &sink->zorder);
889 }
890 } break;
fei.deng56733472024-09-19 20:12:43 +0800891 case PROP_FRAME_STEP_ON_PREROLL:
892 {
893 GstBaseSink *basesink;
894 basesink= GST_BASE_SINK(sink);
895 sink_priv->frame_step_on_preroll = g_value_get_boolean(value);
896 GST_ERROR_OBJECT(sink, "frame step on preroll:%d",sink_priv->frame_step_on_preroll);
897
898 GST_BASE_SINK_PREROLL_LOCK(basesink);
899 if (GST_BASE_SINK(sink)->need_preroll &&
900 GST_BASE_SINK(sink)->have_preroll )
901 {
902 GST_ERROR_OBJECT(sink,"frame step on preroll,Already prerolled");
903 GST_BASE_SINK(sink)->need_preroll= FALSE;
904 GST_BASE_SINK(sink)->have_preroll= TRUE;
905 }
906 GST_BASE_SINK_PREROLL_UNLOCK(basesink);
907
908 if (sink_priv->render_device_handle)
909 {
910 int trick_mode = VIDEO_TRICK_MODE_NONE;
911 if (sink_priv->frame_step_on_preroll) {
912 trick_mode = VIDEO_TRICK_MODE_PAUSE_NEXT;
913 }
914 render_set_value(sink_priv->render_device_handle, KEY_VIDEO_TRICK_MODE, &trick_mode);
915 if (sink->video_playing == FALSE) {
916 render_resume(sink_priv->render_device_handle);
917 }
918 }
919 } break;
fei.deng3a374e52024-10-29 17:04:42 +0800920 case PRO_VIDEO_LATENCY:
921 {
922 GST_OBJECT_LOCK(sink);
923 sink_priv->video_latency = g_value_get_int(value);
924 sink_priv->set_video_latency = TRUE;
925 GST_DEBUG_OBJECT(sink, "set video latency:%d us",sink_priv->video_latency);
926 GST_OBJECT_UNLOCK(sink);
927 } break;
fei.deng053f4072024-11-20 19:05:43 +0800928 case PROP_FORCE_ASPECT_RATIO:
929 {
930 sink_priv->force_aspect_ratio = g_value_get_boolean(value);
931 GST_DEBUG_OBJECT(sink, "set force aspect ratio:%d",sink_priv->force_aspect_ratio);
932 if (sink_priv->render_device_handle)
933 {
934 int force = sink_priv->force_aspect_ratio? 1: 0;
935 render_set_value(sink_priv->render_device_handle, KEY_FORCE_ASPECT_RATIO, &force);
936 }
937 } break;
xuesong.jiangc26425b2022-05-12 20:37:22 +0800938#if GST_IMPORT_LGE_PROP
939 case PROP_LGE_RESOURCE_INFO:
940 {
941 GST_OBJECT_LOCK(sink);
942 GstStructure *r_info = g_value_get_object(value);
943 if (r_info)
944 {
945 if (gst_structure_has_field(r_info, "coretype"))
946 {
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800947 if (sink_priv->lge_ctxt.res_info.coretype)
948 {
949 g_free(sink_priv->lge_ctxt.res_info.coretype);
950 sink_priv->lge_ctxt.res_info.coretype = NULL;
951 }
952 sink_priv->lge_ctxt.res_info.coretype = g_strdup(gst_structure_get_string(r_info, "coretype"));
xuesong.jiangc26425b2022-05-12 20:37:22 +0800953 }
954 if (gst_structure_has_field(r_info, "videoport"))
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800955 gst_structure_get_int(r_info, "videoport", &(sink_priv->lge_ctxt.res_info.videoport));
xuesong.jiangc26425b2022-05-12 20:37:22 +0800956 if (gst_structure_has_field(r_info, "audioport"))
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800957 gst_structure_get_int(r_info, "audioport", &(sink_priv->lge_ctxt.res_info.audioport));
xuesong.jiangc26425b2022-05-12 20:37:22 +0800958 if (gst_structure_has_field(r_info, "maxwidth"))
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800959 gst_structure_get_int(r_info, "maxwidth", &(sink_priv->lge_ctxt.res_info.maxwidth));
xuesong.jiangc26425b2022-05-12 20:37:22 +0800960 if (gst_structure_has_field(r_info, "maxheight"))
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800961 gst_structure_get_int(r_info, "maxheight", &(sink_priv->lge_ctxt.res_info.maxheight));
xuesong.jiangc26425b2022-05-12 20:37:22 +0800962 if (gst_structure_has_field(r_info, "mixerport"))
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800963 gst_structure_get_int(r_info, "mixerport", &(sink_priv->lge_ctxt.res_info.mixerport));
xuesong.jiangc26425b2022-05-12 20:37:22 +0800964 }
965 GST_OBJECT_UNLOCK(sink);
966 break;
967 }
968 case PROP_LGE_INTERLEAVING_TYPE:
969 {
970 GST_OBJECT_LOCK(sink);
971 guint interlv_type = g_value_get_uint(value);
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800972 sink_priv->lge_ctxt.interleaving_type = interlv_type;
xuesong.jiangc26425b2022-05-12 20:37:22 +0800973 GST_OBJECT_UNLOCK(sink);
974 break;
975 }
976 case PROP_LGE_APP_TYPE:
977 {
978 GST_OBJECT_LOCK(sink);
979 GST_DEBUG_OBJECT(sink, "LGE up layer set app type");
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800980 if (sink_priv->lge_ctxt.app_type)
981 g_free(sink_priv->lge_ctxt.app_type);
982 sink_priv->lge_ctxt.app_type = g_strdup(g_value_get_string(value));
xuesong.jiangc26425b2022-05-12 20:37:22 +0800983 GST_OBJECT_UNLOCK(sink);
984 break;
985 }
986 case PROP_LGE_SYNC:
987 {
988 GST_OBJECT_LOCK(sink);
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800989 sink_priv->lge_ctxt.sync = g_value_get_boolean(value);
xuesong.jiangc26425b2022-05-12 20:37:22 +0800990 GST_OBJECT_UNLOCK(sink);
991 break;
992 }
993 case PROP_LGE_DISH_TRICK:
994 {
995 GST_OBJECT_LOCK(sink);
xuesong.jianga52aa5b2022-05-13 16:00:32 +0800996 sink_priv->lge_ctxt.dish_trick = g_value_get_boolean(value);
xuesong.jiangc26425b2022-05-12 20:37:22 +0800997 GST_OBJECT_UNLOCK(sink);
998 break;
999 }
1000 case PROP_LGE_DISH_TRICK_IGNORE_RATE:
1001 {
1002 GST_OBJECT_LOCK(sink);
xuesong.jianga52aa5b2022-05-13 16:00:32 +08001003 sink_priv->lge_ctxt.dish_trick_ignore_rate = g_value_get_boolean(value);
xuesong.jiangc26425b2022-05-12 20:37:22 +08001004 GST_OBJECT_UNLOCK(sink);
1005 break;
1006 }
1007#endif
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08001008 case PROP_VIDEO_ROTATION:
1009 {
1010 int rotationDegree = g_value_get_int(value);
kaiqiang.xiange5044f22024-12-20 11:43:33 +08001011 // dw=0 only AFBC, don't support rotation
1012 if (sink_priv->dw_mode != 0 && rotationDegree >= WST_ROTATION_0 && rotationDegree <= WST_ROTATION_270)
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08001013 {
1014 GST_DEBUG_OBJECT(sink, "set rotation degree %d", rotationDegree);
1015 sink_priv->rot_degree = (ROTATION_DEGREE)rotationDegree;
1016 sink_priv->rot_changed = TRUE;
1017 sink_priv->rot_enable_property = TRUE;
1018 }
1019 break;
1020 }
xuesong.jiangd91230d2021-10-20 15:51:10 +08001021 default:
xuesong.jianga52aa5b2022-05-13 16:00:32 +08001022 // G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001023 break;
1024 }
xuesong.jiang1801e172021-10-11 10:56:41 +08001025}
1026
xuesong.jiangd91230d2021-10-20 15:51:10 +08001027static void gst_aml_video_sink_finalize(GObject *object)
1028{
1029 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(object);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001030 GST_DEBUG_OBJECT(sink, "Finalizing aml video sink..");
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001031
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08001032 if (sink->buffer_queue)
1033 {
1034 gst_queue_array_free (sink->buffer_queue);
1035 sink->buffer_queue = NULL;
1036 }
1037
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08001038 g_mutex_clear(&sink->eos_lock);
1039 g_cond_clear(&sink->eos_cond);
le.han7bb29b62024-08-07 03:17:09 +00001040 g_mutex_clear(&sink->report_info_lock);
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08001041 g_mutex_clear(&sink->rotation_buffer_lock);
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001042
xuesong.jiangd91230d2021-10-20 15:51:10 +08001043 gst_aml_video_sink_reset_private(sink);
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08001044 if (GST_AML_VIDEO_SINK_GET_PRIVATE(sink))
xuesong.jiang5c0d1b82021-11-16 19:30:56 +08001045 free(GST_AML_VIDEO_SINK_GET_PRIVATE(sink));
xuesong.jiangd91230d2021-10-20 15:51:10 +08001046 G_OBJECT_CLASS(parent_class)->finalize(object);
xuesong.jiang1801e172021-10-11 10:56:41 +08001047}
1048
1049static GstStateChangeReturn
1050gst_aml_video_sink_change_state(GstElement *element,
xuesong.jiangd91230d2021-10-20 15:51:10 +08001051 GstStateChange transition)
1052{
1053 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(element);
1054 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001055 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
xuesong.jiang9d55c672022-05-09 18:33:03 +08001056 GstState state, next;
1057
1058 state = (GstState)GST_STATE_TRANSITION_CURRENT(transition);
1059 next = GST_STATE_TRANSITION_NEXT(transition);
fei.dengbdb18e52023-08-16 06:42:34 +00001060 GST_DEBUG_OBJECT(sink,
xuesong.jiangc26425b2022-05-12 20:37:22 +08001061 "amlvideosink handler tries setting state from %s to %s (%04x)",
1062 gst_element_state_get_name(state),
1063 gst_element_state_get_name(next), transition);
xuesong.jiang1801e172021-10-11 10:56:41 +08001064
xuesong.jiangd91230d2021-10-20 15:51:10 +08001065 GST_OBJECT_LOCK(sink);
1066 switch (transition)
1067 {
1068 case GST_STATE_CHANGE_NULL_TO_READY:
1069 {
fei.deng88a6f022024-04-10 02:23:55 +00001070 //set env to enable essos
1071 setenv("ENABLE_WST_ESSOS","1",1);
fei.dengbdb18e52023-08-16 06:42:34 +00001072 sink_priv->render_device_handle = render_open();
1073 if (sink_priv->render_device_handle == NULL)
1074 {
1075 GST_ERROR_OBJECT(sink, "render lib: open device fail");
1076 goto error;
1077 }
1078 RenderCallback cb = {gst_render_msg_callback, gst_render_val_callback};
1079 render_set_callback(sink_priv->render_device_handle, sink, &cb);
xuesong.jiangc26425b2022-05-12 20:37:22 +08001080
fei.dengbdb18e52023-08-16 06:42:34 +00001081 GST_DEBUG_OBJECT(sink, "tunnel lib: set pip mode %d",sink->pip_mode);
1082 int pip = 1;
1083 if (sink->pip_mode && render_set_value(sink_priv->render_device_handle, KEY_VIDEO_PIP, &pip) == -1)
1084 {
1085 GST_ERROR_OBJECT(sink, "tunnel lib: set pip error");
1086 goto error;
1087 }
fei.deng978b2422023-11-30 10:33:23 +00001088 //check if showing first frame no sync
le.han9ff888d2024-09-09 03:04:31 +00001089 int show_frame_asap = sink_priv->show_first_frame_asap ? 1 : 0;
1090 if (render_set_value(sink_priv->render_device_handle, KEY_SHOW_FRIST_FRAME_NOSYNC, &show_frame_asap))
1091 {
1092 GST_ERROR_OBJECT(sink, "tunnel lib: set show first frame no sync error");
1093 goto error;
fei.deng978b2422023-11-30 10:33:23 +00001094 }
xuesong.jiang16ae3212022-07-12 15:32:10 +08001095
xuesong.jiangfc27c272022-05-11 17:09:02 +08001096 GST_DEBUG_OBJECT(sink, "set qos fail");
1097 gst_base_sink_set_qos_enabled((GstBaseSink *)sink, FALSE);
xuesong.jiang1801e172021-10-11 10:56:41 +08001098
xuesong.jiangd91230d2021-10-20 15:51:10 +08001099 break;
1100 }
1101 case GST_STATE_CHANGE_READY_TO_PAUSED:
1102 {
xuesong.jiang5eb01712022-10-21 19:47:54 +08001103
fei.dengbdb18e52023-08-16 06:42:34 +00001104 if (render_set_value(sink_priv->render_device_handle, KEY_SELECT_DISPLAY_OUTPUT, &sink->display_output_index) == -1)
1105 {
1106 GST_ERROR_OBJECT(sink, "render lib first set output index error");
1107 goto error;
1108 }
xuesong.jianga507a4b2022-10-28 16:28:29 +08001109
fei.dengbdb18e52023-08-16 06:42:34 +00001110 if (render_connect(sink_priv->render_device_handle) == -1)
1111 {
1112 GST_ERROR_OBJECT(sink, "render lib connect device fail");
1113 goto error;
1114 }
xuesong.jianga507a4b2022-10-28 16:28:29 +08001115
le.hande92b682024-05-30 07:18:19 +00001116 if (render_set_value(sink_priv->render_device_handle, KEY_IMMEDIATELY_OUTPUT, &sink->immediately_render) == -1)
1117 {
1118 GST_ERROR_OBJECT(sink, "render lib set immediately output error");
1119 goto error;
1120 }
fei.deng053f4072024-11-20 19:05:43 +08001121 if (sink_priv->force_aspect_ratio)
1122 {
1123 int force = 1;
1124 render_set_value(sink_priv->render_device_handle, KEY_FORCE_ASPECT_RATIO, &force);
1125 }
le.hande92b682024-05-30 07:18:19 +00001126
fei.dengbdb18e52023-08-16 06:42:34 +00001127 if (render_pause(sink_priv->render_device_handle) == -1)
1128 {
1129 GST_ERROR_OBJECT(sink, "render lib pause device fail when first into paused state");
1130 goto error;
1131 }
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08001132 rotation_init(&sink_priv->amlge2d, &sink_priv->pge2dinfo);
xuesong.jiang69031992022-06-09 19:30:35 +08001133 break;
1134 }
1135 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1136 {
fei.deng2f462142023-05-24 03:07:29 +00001137 sink->video_playing = TRUE;
fei.dengbdb18e52023-08-16 06:42:34 +00001138 if (render_resume(sink_priv->render_device_handle) == -1)
1139 {
1140 GST_ERROR_OBJECT(sink, "render lib resume device fail");
1141 goto error;
1142 }
fei.deng053f4072024-11-20 19:05:43 +08001143 //drop all frames thoes donot rendered
1144 if (sink_priv->got_eos) {
1145 sink->rendered = sink->queued - sink->dropped;
1146 }
xuesong.jiangd91230d2021-10-20 15:51:10 +08001147 break;
1148 }
xuesong.jiang58e75f82022-06-30 19:23:20 +08001149 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1150 {
fei.deng2f462142023-05-24 03:07:29 +00001151 sink->video_playing = FALSE;
xuesong.jiang58e75f82022-06-30 19:23:20 +08001152 if (gst_base_sink_is_async_enabled(GST_BASE_SINK(sink)))
1153 {
xuesong.jiang8e09c742022-07-27 16:38:32 +08001154 GST_OBJECT_UNLOCK(sink);
xuesong.jiang58e75f82022-06-30 19:23:20 +08001155 GstBaseSink *basesink;
1156 basesink = GST_BASE_SINK(sink);
fei.deng2dee9402023-05-06 08:21:21 +00001157 //GST_BASE_SINK_PREROLL_LOCK(basesink);
xuesong.jiang58e75f82022-06-30 19:23:20 +08001158 basesink->have_preroll = 1;
fei.deng2dee9402023-05-06 08:21:21 +00001159 //GST_BASE_SINK_PREROLL_UNLOCK(basesink);
xuesong.jiang8e09c742022-07-27 16:38:32 +08001160 GST_OBJECT_LOCK(sink);
xuesong.jiang58e75f82022-06-30 19:23:20 +08001161 }
1162 break;
1163 }
xuesong.jiangd91230d2021-10-20 15:51:10 +08001164 default:
1165 break;
1166 }
1167 GST_OBJECT_UNLOCK(sink);
xuesong.jiang1801e172021-10-11 10:56:41 +08001168
xuesong.jiang1700bab2021-11-17 17:11:11 +08001169 GST_LOG_OBJECT(sink, "amlvideosink deal state change ok, goto basesink state change");
xuesong.jiangd91230d2021-10-20 15:51:10 +08001170 ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
1171
1172 GST_OBJECT_LOCK(sink);
1173 if (ret == GST_STATE_CHANGE_FAILURE)
1174 goto error;
1175
1176 switch (transition)
1177 {
xuesong.jiang69031992022-06-09 19:30:35 +08001178 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1179 {
xuesong.jiang22afe862022-11-09 16:27:33 +08001180 // GstBaseSink *basesink;
1181 // basesink = GST_BASE_SINK(sink);
xuesong.jiang69031992022-06-09 19:30:35 +08001182
fei.dengbdb18e52023-08-16 06:42:34 +00001183 if (render_pause(sink_priv->render_device_handle) == -1)
1184 {
1185 GST_ERROR_OBJECT(sink, "render lib pause device fail");
1186 goto error;
1187 }
xuesong.jiang69031992022-06-09 19:30:35 +08001188
1189 // GST_BASE_SINK_PREROLL_LOCK(basesink);
1190 // basesink->have_preroll = 1;
1191 // GST_BASE_SINK_PREROLL_UNLOCK(basesink);
1192 break;
1193 }
xuesong.jiangd91230d2021-10-20 15:51:10 +08001194 case GST_STATE_CHANGE_PAUSED_TO_READY:
1195 {
le.han7bb29b62024-08-07 03:17:09 +00001196 if ( sink->detect_thread_handle )
fei.deng10e3d502023-05-10 06:52:46 +00001197 {
hanghang.luo39bed672024-04-19 02:50:50 +00001198 sink->quit_eos_detect_thread = TRUE;
le.han7bb29b62024-08-07 03:17:09 +00001199 g_thread_join(sink->detect_thread_handle);
1200 sink->detect_thread_handle = NULL;
fei.deng10e3d502023-05-10 06:52:46 +00001201 }
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08001202 if (sink->rotation_thread_handle)
1203 {
1204 sink->quit_rotation_thread = TRUE;
1205 GST_OBJECT_UNLOCK(sink);
1206 g_thread_join(sink->rotation_thread_handle);
1207 GST_OBJECT_LOCK(sink);
1208 sink->rotation_thread_handle = NULL;
1209 }
xuesong.jiangaed30942022-06-17 14:27:27 +08001210 GST_DEBUG_OBJECT(sink, "before disconnect rlib");
fei.dengbdb18e52023-08-16 06:42:34 +00001211 render_disconnect(sink_priv->render_device_handle);
xuesong.jiangaed30942022-06-17 14:27:27 +08001212 GST_DEBUG_OBJECT(sink, "after disconnect rlib");
fei.deng6fdfab72024-08-05 16:54:58 +08001213 GST_DEBUG_OBJECT(sink, "buf stat | queued:%d, dequeued:%d, dropped:%d, rendered:%d",
1214 sink->queued, sink->dequeued, sink->dropped, sink->rendered);
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08001215
1216 if (sink_priv->rot_buffer)
1217 {
1218 rotation_buffer_teardown(sink_priv->rot_buffer, ROT_BUFFER_MAX);
1219 sink_priv->rot_buffer = NULL;
1220 }
1221 rotation_exit(&sink_priv->amlge2d);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001222 break;
1223 }
1224 case GST_STATE_CHANGE_READY_TO_NULL:
1225 {
xuesong.jiange90be372021-10-21 11:29:57 +08001226 if (sink_priv->render_device_handle)
xuesong.jiangd91230d2021-10-20 15:51:10 +08001227 {
fei.dengbdb18e52023-08-16 06:42:34 +00001228 render_close(sink_priv->render_device_handle);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001229 }
1230 gst_aml_video_sink_reset_private(sink);
fei.deng88a6f022024-04-10 02:23:55 +00001231 //set env to invalid essos
1232 setenv("ENABLE_WST_ESSOS","0",1);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001233
1234 break;
1235 }
1236 default:
1237 break;
1238 }
xuesong.jiang8e09c742022-07-27 16:38:32 +08001239
fei.dengbdb18e52023-08-16 06:42:34 +00001240 //gst_aml_video_sink_dump_stat(sink, GST_DUMP_STAT_FILENAME);
xuesong.jiang8e09c742022-07-27 16:38:32 +08001241
xuesong.jiangd91230d2021-10-20 15:51:10 +08001242 GST_OBJECT_UNLOCK(sink);
fei.dengbdb18e52023-08-16 06:42:34 +00001243 GST_DEBUG_OBJECT(sink, "done");
xuesong.jiang1801e172021-10-11 10:56:41 +08001244 return ret;
1245
xuesong.jiangd91230d2021-10-20 15:51:10 +08001246error:
1247 GST_OBJECT_UNLOCK(sink);
1248 ret = GST_STATE_CHANGE_FAILURE;
1249 return ret;
1250}
xuesong.jiang1801e172021-10-11 10:56:41 +08001251
xuesong.jiang9ae8f882022-04-18 20:15:06 +08001252static gboolean gst_aml_video_sink_query(GstElement *element, GstQuery *query)
1253{
1254 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(element);
1255
1256 switch (GST_QUERY_TYPE(query))
1257 {
1258 case GST_QUERY_POSITION:
1259 {
1260 GstFormat format;
1261 gst_query_parse_position(query, &format, NULL);
1262 if (GST_FORMAT_BYTES == format)
1263 {
1264 return GST_ELEMENT_CLASS(parent_class)->query(element, query);
1265 }
1266 else
1267 {
1268 GST_OBJECT_LOCK(sink);
1269 gint64 position = sink->last_displayed_buf_pts;
xuesong.jiangaed30942022-06-17 14:27:27 +08001270 // gint64 position = sink->last_dec_buf_pts;
xuesong.jiang9ae8f882022-04-18 20:15:06 +08001271 GST_OBJECT_UNLOCK(sink);
xuesong.jiang0ebc0332022-07-05 10:58:02 +08001272 GST_DEBUG_OBJECT(sink, "got position: %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
xuesong.jiang9ae8f882022-04-18 20:15:06 +08001273 gst_query_set_position(query, GST_FORMAT_TIME, position);
1274 return TRUE;
1275 }
1276 break;
1277 }
1278 default:
1279 return GST_ELEMENT_CLASS(parent_class)->query(element, query);
1280 }
1281}
1282
xuesong.jiangd91230d2021-10-20 15:51:10 +08001283static gboolean gst_aml_video_sink_propose_allocation(GstBaseSink *bsink, GstQuery *query)
1284{
xuesong.jiangeb46f672021-11-19 19:05:56 +08001285 GST_DEBUG_OBJECT(bsink, "trace in");
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08001286 // TODO only implement dma case
xuesong.jiangd91230d2021-10-20 15:51:10 +08001287 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(bsink);
xuesong.jiang7c724a52021-10-22 17:18:58 +08001288 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
1289
xuesong.jiangd91230d2021-10-20 15:51:10 +08001290 GstCaps *caps;
1291 GstBufferPool *pool = NULL;
1292 gboolean need_pool;
xuesong.jiangd91230d2021-10-20 15:51:10 +08001293
1294 gst_query_parse_allocation(query, &caps, &need_pool);
bo.xiao611b8e42024-07-18 11:33:46 +08001295 GST_DEBUG_OBJECT(bsink, "need_pool: %d, secure_mode: %d, size=%d", need_pool, sink->secure_mode, sink_priv->dw_size);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001296
1297 if (need_pool)
sheng.liuc9f34962022-06-17 21:42:48 +08001298 pool = gst_drm_bufferpool_new(sink->secure_mode, GST_DRM_BUFFERPOOL_TYPE_VIDEO_PLANE);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001299
sheng.liubbb893b2022-06-24 15:49:04 +08001300 // Do not store the last received sample if it is secure_mode
1301 if (TRUE == sink->secure_mode)
1302 gst_base_sink_set_last_sample_enabled(bsink, FALSE);
1303
bo.xiao611b8e42024-07-18 11:33:46 +08001304 gst_query_add_allocation_pool(query, pool, sink_priv->dw_size, DRMBP_EXTRA_BUF_SIZE_FOR_DISPLAY, DRMBP_LIMIT_MAX_BUFSIZE_TO_BUFSIZE);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001305 if (pool)
1306 g_object_unref(pool);
1307
1308 gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
1309
1310 return TRUE;
xuesong.jiang1801e172021-10-11 10:56:41 +08001311}
1312
1313static GstCaps *gst_aml_video_sink_get_caps(GstBaseSink *bsink,
xuesong.jiangd91230d2021-10-20 15:51:10 +08001314 GstCaps *filter)
1315{
1316 GstAmlVideoSink *sink;
1317 GstCaps *caps;
xuesong.jiang1801e172021-10-11 10:56:41 +08001318
xuesong.jiangd91230d2021-10-20 15:51:10 +08001319 sink = GST_AML_VIDEO_SINK(bsink);
xuesong.jiang1801e172021-10-11 10:56:41 +08001320
xuesong.jiangd91230d2021-10-20 15:51:10 +08001321 caps = gst_pad_get_pad_template_caps(GST_VIDEO_SINK_PAD(sink));
1322 caps = gst_caps_make_writable(caps);
xuesong.jiang1801e172021-10-11 10:56:41 +08001323
xuesong.jiangd91230d2021-10-20 15:51:10 +08001324 if (filter)
1325 {
1326 GstCaps *intersection;
xuesong.jiang1801e172021-10-11 10:56:41 +08001327
xuesong.jiangd91230d2021-10-20 15:51:10 +08001328 intersection =
1329 gst_caps_intersect_full(filter, caps, GST_CAPS_INTERSECT_FIRST);
1330 gst_caps_unref(caps);
1331 caps = intersection;
1332 }
xuesong.jiang22afe862022-11-09 16:27:33 +08001333 GST_DEBUG_OBJECT(sink, "filter caps: %" GST_PTR_FORMAT, filter);
1334 GST_DEBUG_OBJECT(sink, "final caps: %" GST_PTR_FORMAT, caps);
xuesong.jiang1801e172021-10-11 10:56:41 +08001335
xuesong.jiangd91230d2021-10-20 15:51:10 +08001336 return caps;
xuesong.jiang1801e172021-10-11 10:56:41 +08001337}
1338
xuesong.jiangd91230d2021-10-20 15:51:10 +08001339static gboolean gst_aml_video_sink_set_caps(GstBaseSink *bsink, GstCaps *caps)
1340{
1341 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(bsink);
1342 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiangf190e2a2021-11-22 20:26:00 +08001343 // gboolean use_dmabuf;
xuesong.jiang91391f52021-11-19 15:42:30 +08001344 gboolean ret = TRUE;
bo.xiao611b8e42024-07-18 11:33:46 +08001345 GstStructure *structure;
1346 const gchar *s;
xuesong.jiang1801e172021-10-11 10:56:41 +08001347
bo.xiao611b8e42024-07-18 11:33:46 +08001348 g_return_val_if_fail (caps != NULL, FALSE);
xuesong.jiang1801e172021-10-11 10:56:41 +08001349
xuesong.jiangd91230d2021-10-20 15:51:10 +08001350 GST_DEBUG_OBJECT(sink, "set caps %" GST_PTR_FORMAT, caps);
bo.xiao611b8e42024-07-18 11:33:46 +08001351
1352 GST_OBJECT_LOCK(sink);
xuesong.jiangeb46f672021-11-19 19:05:56 +08001353 // use_dmabuf = gst_caps_features_contains(gst_caps_get_features(caps, 0), GST_CAPS_FEATURE_MEMORY_DMABUF);
1354 // if (use_dmabuf == FALSE)
1355 // {
1356 // GST_ERROR_OBJECT(sink, "not support non dma buffer case");
1357 // ret = FALSE;
1358 // goto done;
1359 // }
xuesong.jiang1801e172021-10-11 10:56:41 +08001360
bo.xiao611b8e42024-07-18 11:33:46 +08001361 structure = gst_caps_get_structure (caps, 0);
1362
1363 if (!(s = gst_structure_get_string (structure, "format"))) {
1364 GST_WARNING_OBJECT(sink, "can't get format from caps");
1365 } else {
1366 sink_priv->format = gst_video_format_from_string (s);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001367 }
xuesong.jiang1801e172021-10-11 10:56:41 +08001368
bo.xiao611b8e42024-07-18 11:33:46 +08001369 if (!gst_structure_get_int (structure, "width", &sink_priv->dw_width)) {
1370 GST_WARNING_OBJECT(sink, "can't get width from caps");
1371 }
1372 if (!gst_structure_get_int (structure, "height", &sink_priv->dw_height)) {
1373 GST_WARNING_OBJECT(sink, "can't get height from caps");
1374 }
1375 if (!gst_structure_get_int (structure, "src_width", &sink_priv->src_width)) {
1376 GST_WARNING_OBJECT(sink, "can't get src_width from caps");
1377 }
1378 if (!gst_structure_get_int (structure, "src_height", &sink_priv->src_height)) {
1379 GST_WARNING_OBJECT(sink, "can't get src_height from caps");
1380 }
le.han30f126e2024-10-09 02:42:55 +00001381 if (!gst_structure_get_int (structure, "dw_mode", &sink_priv->dw_mode)) {
1382 GST_WARNING_OBJECT(sink, "can't get dw_mode from caps");
1383 }
1384 if (!gst_structure_get_int (structure, "stride", &sink_priv->stride)) {
1385 GST_WARNING_OBJECT(sink, "can't get stride from caps");
1386 }
bo.xiao611b8e42024-07-18 11:33:46 +08001387
1388 sink_priv->dw_size = sink_priv->dw_width*sink_priv->dw_height*3/2;
1389
1390 if (!gst_structure_get_fraction (structure, "framerate", &sink_priv->fps_n, &sink_priv->fps_d)) {
1391 GST_WARNING_OBJECT(sink, "can't get fps from caps");
1392 sink_priv->fps_n = 0;
1393 sink_priv->fps_d = 1;
1394 }
1395 if (!gst_structure_get_fraction (structure, "pixel-aspect-ratio", &sink_priv->par_n, &sink_priv->par_d)) {
1396 GST_WARNING_OBJECT(sink, "can't get par from caps");
1397 sink_priv->par_n = 1;
1398 sink_priv->par_d = 1;
1399 }
1400
1401 if (!(s = gst_structure_get_string (structure, "interlace-mode"))) {
1402 GST_WARNING_OBJECT(sink, "can't get interlace-mode from caps");
1403 } else {
1404 sink_priv->interlace = !g_str_equal ("progressive", s);
1405 }
xuesong.jiangc26425b2022-05-12 20:37:22 +08001406
xuesong.jiangd91230d2021-10-20 15:51:10 +08001407 sink_priv->video_info_changed = TRUE;
1408
1409 GST_OBJECT_UNLOCK(sink);
xuesong.jiang91391f52021-11-19 15:42:30 +08001410 return ret;
xuesong.jiang1801e172021-10-11 10:56:41 +08001411}
1412
hanghang.luo39bed672024-04-19 02:50:50 +00001413
1414static void gst_show_vr_cb(gpointer data)
1415{
1416 bufferInfo *binfo = (bufferInfo*)data;
1417 GstAmlVideoSink *sink = binfo->sink;
1418 GST_DEBUG("unref vr360 buffer %p ",binfo->buf);
1419 sink->rendered++;
1420 if (binfo->buf)
1421 gst_buffer_unref(binfo->buf);
1422 free(binfo);
1423}
1424
1425static gboolean gst_aml_video_sink_show_vr_frame(GstAmlVideoSink *sink, GstBuffer *buffer)
1426{
bo.xiao611b8e42024-07-18 11:33:46 +08001427 bufferInfo *binfo = NULL;
hanghang.luo39bed672024-04-19 02:50:50 +00001428 GstStructure *s;
1429 GstBuffer *buf;
1430 gint fd0 = -1, fd1 = -1, fd2 = -1;
bo.xiao611b8e42024-07-18 11:33:46 +08001431 gint stride0 = 0, stride1 = 0, stride2 = 0;
hanghang.luo39bed672024-04-19 02:50:50 +00001432 GstVideoMeta *vmeta = NULL;
bo.xiao611b8e42024-07-18 11:33:46 +08001433 int offset1= 0, offset2 = 0;
1434 guint n_mem = 0;
1435 GstMemory *dma_mem0 = NULL;
1436 GstMemory *dma_mem1 = NULL;
1437
hanghang.luo39bed672024-04-19 02:50:50 +00001438 GST_DEBUG("pts: %lld %p", GST_BUFFER_PTS (buffer),buffer);
1439
1440 binfo= (bufferInfo*)malloc( sizeof(bufferInfo) );
bo.xiao611b8e42024-07-18 11:33:46 +08001441 if (!binfo) {
1442 GST_ERROR_OBJECT(sink, "malloc bufferInfo fail.");
1443 return FALSE;
1444 }
1445
1446 gst_buffer_ref(buffer);
1447 binfo->sink= sink;
1448 binfo->buf = buffer;
1449 n_mem = gst_buffer_n_memory(buffer);
1450 vmeta = gst_buffer_get_video_meta(buffer);
1451 if (vmeta == NULL)
hanghang.luo39bed672024-04-19 02:50:50 +00001452 {
bo.xiao611b8e42024-07-18 11:33:46 +08001453 GST_ERROR_OBJECT(sink, "not found video meta info");
1454 gst_buffer_unref(binfo->buf);
1455 free(binfo);
1456 return FALSE;
1457 }
1458 GST_DEBUG("height:%d,width:%d,n_mem:%d",vmeta->height,vmeta->width,n_mem);
hanghang.luo39bed672024-04-19 02:50:50 +00001459
bo.xiao611b8e42024-07-18 11:33:46 +08001460 if (n_mem > 1)
1461 {
1462 dma_mem0 = gst_buffer_peek_memory(buffer, 0);
1463 dma_mem1 = gst_buffer_peek_memory(buffer, 1);
1464 fd0 = gst_dmabuf_memory_get_fd(dma_mem0);
1465 fd1 = gst_dmabuf_memory_get_fd(dma_mem1);
1466 GST_DEBUG("fd0:%d,fd1:%d,fd2:%d",fd0,fd1,fd2);
1467 stride0 = vmeta->stride[0];
1468 stride1 = vmeta->stride[1];
1469 stride2 = 0;
1470 if ( fd1 < 0 )
hanghang.luo39bed672024-04-19 02:50:50 +00001471 {
bo.xiao611b8e42024-07-18 11:33:46 +08001472 stride1= stride0;
hanghang.luo39bed672024-04-19 02:50:50 +00001473 offset1= stride0*vmeta->height;
1474 }
bo.xiao611b8e42024-07-18 11:33:46 +08001475 if ( fd2 < 0 )
1476 {
1477 offset2= offset1+(vmeta->width*vmeta->height)/2;
1478 stride2= stride0;
1479 }
1480 GST_DEBUG("stride0:%d,stride1:%d,stride2:%d",stride0,stride1,stride2);
1481 GST_DEBUG("offset0:%d,offset1:%d,offset2:%d",offset2,offset2,offset2);
hanghang.luo39bed672024-04-19 02:50:50 +00001482 }
bo.xiao611b8e42024-07-18 11:33:46 +08001483 else
1484 {
1485 GST_DEBUG("single plane");
1486 dma_mem0 = gst_buffer_peek_memory(buffer, 0);
1487 fd0 = gst_dmabuf_memory_get_fd(dma_mem0);
1488 stride0 = vmeta->stride[0];
1489 offset1= stride0*vmeta->height;
1490 }
1491
hanghang.luo39bed672024-04-19 02:50:50 +00001492 s = gst_structure_new ("drmbuffer_info",
1493 "fd0", G_TYPE_INT, fd0,
1494 "fd1", G_TYPE_INT, fd1,
1495 "fd2", G_TYPE_INT, fd2,
1496 "stride0", G_TYPE_INT, stride0,
1497 "stride1", G_TYPE_INT, stride1,
1498 "stride2", G_TYPE_INT, stride2,
1499 "width", G_TYPE_INT, vmeta->width,
1500 "height", G_TYPE_INT, vmeta->height,
1501 "format", G_TYPE_INT, FORMAT_NV21,
1502 NULL);
1503 GST_DEBUG("structure: %" GST_PTR_FORMAT,s);
1504
1505 buf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
1506 (gpointer) binfo, sizeof(bufferInfo), 0, sizeof(bufferInfo),
1507 (gpointer) binfo, gst_show_vr_cb);
1508 if (!buf)
1509 {
1510 GST_ERROR_OBJECT(sink, "new buffer fail!");
1511 gst_buffer_unref(buf);
1512 gst_buffer_unref(binfo->buf);
1513 free(binfo);
1514 return FALSE;;
1515 }
bo.xiao611b8e42024-07-18 11:33:46 +08001516
hanghang.luo39bed672024-04-19 02:50:50 +00001517 gst_buffer_add_protection_meta(buf, s);
1518 GST_BUFFER_PTS (buf) = GST_BUFFER_PTS(buffer);
1519 GST_DEBUG("pts: %lld, %p", GST_BUFFER_PTS (buf),buf);
1520 g_signal_emit (G_OBJECT(sink),g_signals[SIGNAL_DECODEDBUFFER],0,buf);
1521 gst_buffer_unref(buf);
bo.xiao611b8e42024-07-18 11:33:46 +08001522
hanghang.luo39bed672024-04-19 02:50:50 +00001523 return TRUE;
hanghang.luo39bed672024-04-19 02:50:50 +00001524}
1525
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08001526static void rotation_flush_buffer(GstAmlVideoSink *vsink)
1527{
1528 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(vsink);
1529
1530 g_mutex_lock(&sink->rotation_buffer_lock);
1531 if (sink->buffer_queue)
1532 {
1533 while (!gst_queue_array_is_empty(sink->buffer_queue))
1534 {
1535 GstBuffer* buffer = (GstBuffer *)gst_queue_array_pop_head(sink->buffer_queue);
1536 gst_buffer_unref(buffer);
1537 GST_DEBUG_OBJECT(sink, "reset pop head buffer_queue len:%d", gst_queue_array_get_length(sink->buffer_queue));
1538 }
1539 }
1540 g_mutex_unlock(&sink->rotation_buffer_lock);
1541 GST_DEBUG_OBJECT(sink, "flush over buffer_queue len:%d", gst_queue_array_get_length(sink->buffer_queue));
1542}
1543
1544static gpointer rotation_thread(gpointer data)
1545{
1546 GstAmlVideoSink *sink = (GstAmlVideoSink *)data;
1547 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
1548
1549 while (!sink->quit_rotation_thread)
1550 {
1551 if (sink_priv->rot_buffer && -1 == get_rotation_buffer_idx(sink))
1552 {
1553 usleep(5000);
1554 continue;
1555 }
1556
1557 if (sink->buffer_queue && !gst_queue_array_is_empty(sink->buffer_queue))
1558 {
1559 // pop queue
1560 g_mutex_lock(&sink->rotation_buffer_lock);
1561 GstBuffer *buffer = (GstBuffer *)gst_queue_array_pop_head(sink->buffer_queue);
1562 g_mutex_unlock(&sink->rotation_buffer_lock);
1563
1564 // show frame
1565 gst_aml_video_sink_show_frame((GstVideoSink*)sink, buffer);
1566 gst_buffer_unref(buffer);
1567 }
1568 else
1569 {
1570 usleep(10000);
1571 }
1572 }
1573
1574 // thread join, unref all gst buffer
1575 rotation_flush_buffer(sink);
1576
1577 if (!sink->quit_rotation_thread)
1578 {
1579 g_thread_unref( sink->rotation_thread_handle );
1580 sink->rotation_thread_handle= NULL;
1581 }
1582 GST_DEBUG("rotation_thread: exit");
1583 return NULL;
1584}
1585
1586static GstFlowReturn gst_aml_video_sink_push_queue(GstVideoSink *vsink, GstBuffer *buffer)
1587{
1588 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(vsink);
1589 if (sink->rotation_thread_handle == NULL )
1590 {
1591 sink->quit_rotation_thread = FALSE;
1592 GST_DEBUG_OBJECT(sink, "start rotation thread");
1593 sink->rotation_thread_handle = g_thread_new("video_sink_rotation", rotation_thread, sink);
1594 }
1595
1596 g_mutex_lock(&sink->rotation_buffer_lock);
1597 // push queue
1598 if (sink->buffer_queue)
1599 {
1600 gst_queue_array_push_tail (sink->buffer_queue, buffer);
1601 gst_buffer_ref(buffer);
1602 }
1603 g_mutex_unlock(&sink->rotation_buffer_lock);
1604 return GST_FLOW_OK;
1605}
1606
1607
1608static GstFlowReturn gst_aml_video_sink_show_frame_ex(GstVideoSink *vsink, GstBuffer *buffer)
1609{
1610 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(vsink);
1611 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
1612
1613 if (sink_priv->rot_degree == WST_ROTATION_90 || sink_priv->rot_degree == WST_ROTATION_270)
1614 {
1615 return gst_aml_video_sink_push_queue(vsink, buffer);
1616 }
1617 return gst_aml_video_sink_show_frame(vsink, buffer);
1618}
1619
xuesong.jiange90be372021-10-21 11:29:57 +08001620static GstFlowReturn gst_aml_video_sink_show_frame(GstVideoSink *vsink, GstBuffer *buffer)
xuesong.jiangd91230d2021-10-20 15:51:10 +08001621{
xuesong.jiang7c724a52021-10-22 17:18:58 +08001622 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(vsink);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001623 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
1624 GstFlowReturn ret = GST_FLOW_OK;
fei.dengbdb18e52023-08-16 06:42:34 +00001625 RenderBuffer *tunnel_lib_buf_wrap = NULL;
xuesong.jiang103d2922022-04-26 13:37:20 +08001626
xuesong.jiang5d2761f2022-05-05 11:43:21 +08001627 GST_LOG_OBJECT(sink, "revice buffer:%p (start: %" GST_TIME_FORMAT ", end: %" GST_TIME_FORMAT "), from pool:%p, need_preroll:%d",
1628 buffer, GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), GST_TIME_ARGS(GST_BUFFER_DURATION(buffer)),
xuesong.jiang103d2922022-04-26 13:37:20 +08001629 buffer->pool, ((GstBaseSink *)sink)->need_preroll);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001630
fei.dengbdb18e52023-08-16 06:42:34 +00001631 GST_OBJECT_LOCK(vsink);
xuesong.jiangaed30942022-06-17 14:27:27 +08001632 sink->last_dec_buf_pts = GST_BUFFER_PTS(buffer);
1633 GST_DEBUG_OBJECT(sink, "set last_dec_buf_pts %" GST_TIME_FORMAT, GST_TIME_ARGS(sink->last_dec_buf_pts));
1634
xuesong.jiange90be372021-10-21 11:29:57 +08001635 if (!sink_priv->render_device_handle)
xuesong.jiangd91230d2021-10-20 15:51:10 +08001636 {
1637 GST_ERROR_OBJECT(sink, "flow error, render_device_handle == NULL");
1638 goto error;
1639 }
1640
xuesong.jiangebd18352021-12-28 17:13:22 +08001641 if (sink_priv->preroll_buffer && sink_priv->preroll_buffer == buffer)
1642 {
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001643 GST_LOG_OBJECT(sink, "get preroll buffer:%p 2nd time, goto ret", buffer);
xuesong.jiangebd18352021-12-28 17:13:22 +08001644 sink_priv->preroll_buffer = NULL;
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001645 goto ret;
xuesong.jiangebd18352021-12-28 17:13:22 +08001646 }
1647 if (G_UNLIKELY(((GstBaseSink *)sink)->need_preroll))
1648 {
1649 GST_LOG_OBJECT(sink, "get preroll buffer 1st time, buf:%p", buffer);
1650 sink_priv->preroll_buffer = buffer;
xuesong.jiangd91230d2021-10-20 15:51:10 +08001651 }
fei.deng56733472024-09-19 20:12:43 +08001652
hanghang.luo39bed672024-04-19 02:50:50 +00001653 GST_INFO_OBJECT(sink, "sink->enable_decoded_buffer_signal:%d",
1654 sink->enable_decoded_buffer_signal);
1655
1656 if (sink->enable_decoded_buffer_signal)
1657 {
1658 if (!gst_aml_video_sink_check_buf(sink, buffer))
1659 {
1660 GST_ERROR_OBJECT(sink, "buf out of segment return");
1661 goto ret;
1662 }
1663
1664 if (!gst_aml_video_sink_show_vr_frame(sink,buffer))
1665 {
1666 GST_ERROR_OBJECT(sink, "can't play vr360 file!");
1667 goto ret;
1668 }
1669 sink->queued++;
1670 sink->quit_eos_detect_thread = FALSE;
le.han7bb29b62024-08-07 03:17:09 +00001671 if (sink->detect_thread_handle == NULL )
hanghang.luo39bed672024-04-19 02:50:50 +00001672 {
le.han7bb29b62024-08-07 03:17:09 +00001673 GST_DEBUG_OBJECT(sink, "start detect thread");
1674 sink->detect_thread_handle = g_thread_new("video_sink_detection", detection_thread, sink);
hanghang.luo39bed672024-04-19 02:50:50 +00001675 }
1676 goto ret;
1677 }
1678
1679 if (!gst_aml_video_sink_check_buf(sink, buffer))
1680 {
1681 GST_ERROR_OBJECT(sink, "buf out of segment return");
1682 goto ret;
1683 }
xuesong.jiangd91230d2021-10-20 15:51:10 +08001684
xuesong.jiang5d2761f2022-05-05 11:43:21 +08001685 if (sink_priv->window_set.window_change)
xuesong.jiang1a9c2822022-04-24 11:35:07 +08001686 {
fei.dengbdb18e52023-08-16 06:42:34 +00001687 RenderRect window_size = {sink_priv->window_set.x, sink_priv->window_set.y, sink_priv->window_set.w, sink_priv->window_set.h};
1688 if (render_set_value(sink_priv->render_device_handle, KEY_WINDOW_SIZE, &window_size) == -1)
1689 {
1690 GST_ERROR_OBJECT(vsink, "tunnel lib: set window size error");
1691 return FALSE;
1692 }
1693 sink_priv->window_set.window_change = FALSE;
xuesong.jiang16ae3212022-07-12 15:32:10 +08001694
fei.dengbdb18e52023-08-16 06:42:34 +00001695 GST_DEBUG_OBJECT(sink, "tunnel lib: set window size to %d,%d,%d,%d",
1696 sink_priv->window_set.x,
1697 sink_priv->window_set.y,
1698 sink_priv->window_set.w,
1699 sink_priv->window_set.h);
xuesong.jiang1a9c2822022-04-24 11:35:07 +08001700 }
1701
xuesong.jiangd91230d2021-10-20 15:51:10 +08001702 if (sink_priv->video_info_changed)
1703 {
fei.dengbdb18e52023-08-16 06:42:34 +00001704 if (gst_render_set_params(vsink) == FALSE)
1705 {
1706 GST_ERROR_OBJECT(sink, "render lib: set params fail");
1707 goto error;
1708 }
xuesong.jiangd91230d2021-10-20 15:51:10 +08001709 sink_priv->video_info_changed = FALSE;
1710 }
1711
fei.deng68c63342023-12-05 07:37:33 +00001712 if (sink->frame_rate_changed) {
1713 sink->frame_rate_changed = FALSE;
1714 RenderFraction frame_rate_fraction;
1715 frame_rate_fraction.num = sink->frame_rate_num;
1716 frame_rate_fraction.denom = sink->frame_rate_denom;
sheng.liu639d4742024-01-24 02:11:48 +00001717 render_set_value(sink_priv->render_device_handle, KEY_VIDEO_FRAME_RATE, &frame_rate_fraction);
fei.deng68c63342023-12-05 07:37:33 +00001718 }
1719
sheng.liu1a079692023-12-26 06:33:41 +00001720 if (sink->pixel_aspect_ratio_changed)
1721 {
1722 sink->pixel_aspect_ratio_changed = FALSE;
1723 render_set_value(sink_priv->render_device_handle, KEY_PIXEL_ASPECT_RATIO, &sink->pixel_aspect_ratio);
1724 }
fei.deng6fdfab72024-08-05 16:54:58 +08001725 if (sink->update_zorder) {
1726 sink->update_zorder = FALSE;
1727 render_set_value(sink_priv->render_device_handle, KEY_ZORDER, &sink->zorder);
1728 }
fei.deng3a374e52024-10-29 17:04:42 +08001729 if (sink_priv->set_video_latency) {
1730 sink_priv->set_video_latency = FALSE;
1731 render_set_value(sink_priv->render_device_handle, KEY_MEDIASYNC_VIDEOLATENCY, &sink_priv->video_latency);
1732 }
xuesong.jiang8e09c742022-07-27 16:38:32 +08001733
fei.dengbdb18e52023-08-16 06:42:34 +00001734 tunnel_lib_buf_wrap = render_allocate_render_buffer_wrap(sink_priv->render_device_handle, BUFFER_FLAG_DMA_BUFFER);
1735 if (!tunnel_lib_buf_wrap)
1736 {
1737 GST_ERROR_OBJECT(sink, "render lib: alloc buffer wrap fail");
1738 goto error;
1739 }
hanghang.luob21ed192023-11-28 03:34:17 +00001740
fei.dengbdb18e52023-08-16 06:42:34 +00001741 if (!gst_aml_video_sink_tunnel_buf(sink, buffer, tunnel_lib_buf_wrap))
1742 {
1743 GST_ERROR_OBJECT(sink, "construc render buffer fail");
1744 goto error;
1745 }
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001746 GST_OBJECT_UNLOCK(vsink);
fei.dengbdb18e52023-08-16 06:42:34 +00001747 if (render_display_frame(sink_priv->render_device_handle, tunnel_lib_buf_wrap) == -1)
1748 {
1749 GST_ERROR_OBJECT(sink, "render lib: display frame fail");
hanghang.luob21ed192023-11-28 03:34:17 +00001750 return GST_FLOW_CUSTOM_ERROR_2;
fei.dengbdb18e52023-08-16 06:42:34 +00001751 }
xuesong.jiangd91230d2021-10-20 15:51:10 +08001752
hanghang.luob21ed192023-11-28 03:34:17 +00001753 GST_OBJECT_LOCK(vsink);
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001754 sink->queued++;
hanghang.luob21ed192023-11-28 03:34:17 +00001755 if (sink_priv->is_flushing)
1756 {
1757 if (render_flush(sink_priv->render_device_handle) == 0)
1758 {
1759 GST_DEBUG_OBJECT(sink, "in flushing flow, release the buffer directly");
1760 goto flushing;
1761 }
1762 else
1763 {
1764 GST_ERROR_OBJECT(sink, "render lib: flush error");
1765 goto error;
1766 }
1767 }
1768
fei.dengbdb18e52023-08-16 06:42:34 +00001769 //gst_aml_video_sink_dump_stat(sink, GST_DUMP_STAT_FILENAME);
xuesong.jiang8e09c742022-07-27 16:38:32 +08001770 GST_DEBUG_OBJECT(sink, "GstBuffer:%p, pts: %" GST_TIME_FORMAT " queued ok, queued:%d", buffer, GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), sink->queued);
fei.deng2f462142023-05-24 03:07:29 +00001771 sink->quit_eos_detect_thread = FALSE;
le.han7bb29b62024-08-07 03:17:09 +00001772 if (sink->detect_thread_handle == NULL )
fei.deng10e3d502023-05-10 06:52:46 +00001773 {
le.han7bb29b62024-08-07 03:17:09 +00001774 GST_DEBUG_OBJECT(sink, "start detect thread");
1775 sink->detect_thread_handle = g_thread_new("video_sink_detection", detection_thread, sink);
fei.deng10e3d502023-05-10 06:52:46 +00001776 }
hanghang.luob21ed192023-11-28 03:34:17 +00001777 goto ret;
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001778
xuesong.jiangd91230d2021-10-20 15:51:10 +08001779error:
xuesong.jiangeb46f672021-11-19 19:05:56 +08001780 GST_DEBUG_OBJECT(sink, "GstBuffer:%p queued error", buffer);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001781 ret = GST_FLOW_CUSTOM_ERROR_2;
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001782 goto ret;
1783flushing:
1784 GST_DEBUG_OBJECT(sink, "flushing when buf:%p", buffer);
hanghang.luob21ed192023-11-28 03:34:17 +00001785 ret = GST_FLOW_FLUSHING;
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001786 goto ret;
1787ret:
1788 GST_OBJECT_UNLOCK(vsink);
xuesong.jiangd91230d2021-10-20 15:51:10 +08001789 return ret;
xuesong.jiang1801e172021-10-11 10:56:41 +08001790}
1791
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08001792void gst_aml_video_sink_tag_event(GstAmlVideoSink *vsink, GstTagList *list )
1793{
1794 if (NULL == vsink || NULL == list)
1795 {
1796 return;
1797 }
1798
1799 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(vsink);
1800 gchar *rotation_tag = NULL;
1801 gint tagDegree = 0;
1802 ROTATION_DEGREE rotationDegree = WST_ROTATION_0;
1803
kaiqiang.xiange5044f22024-12-20 11:43:33 +08001804 // dw=0 only AFBC, don't support rotation
1805 if ((!sink_priv->rot_enable_property) && (sink_priv->dw_mode != 0) &&
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08001806 (gst_tag_list_get_string(list, GST_TAG_IMAGE_ORIENTATION, &rotation_tag)))
1807 {
1808 if (sscanf(rotation_tag, "rotate-%d", &tagDegree))
1809 {
1810 rotationDegree = (ROTATION_DEGREE)(tagDegree/90);
1811
1812 if (rotationDegree >= WST_ROTATION_0 && rotationDegree <= WST_ROTATION_270)
1813 {
1814 sink_priv->rot_changed = TRUE;
1815 sink_priv->rot_degree = rotationDegree;
1816 GST_DEBUG_OBJECT(vsink, "set rotation degree %d", rotationDegree);
1817 }
1818 }
1819 else if (sscanf(rotation_tag, "flip-rotate-%d", &tagDegree))
1820 {
1821 // not support flip right now, need support later
1822 }
1823 }
1824}
1825
xuesong.jiang22afe862022-11-09 16:27:33 +08001826static gboolean gst_aml_video_sink_pad_event (GstBaseSink *basesink, GstEvent *event)
xuesong.jiangd91230d2021-10-20 15:51:10 +08001827{
1828 gboolean result = TRUE;
xuesong.jiang22afe862022-11-09 16:27:33 +08001829 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(basesink);
xuesong.jiang7c724a52021-10-22 17:18:58 +08001830 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiang1801e172021-10-11 10:56:41 +08001831
xuesong.jiang8e09c742022-07-27 16:38:32 +08001832 GST_DEBUG_OBJECT(sink, "received event %p %" GST_PTR_FORMAT, event, event);
xuesong.jiang0ebc0332022-07-05 10:58:02 +08001833
xuesong.jiangd91230d2021-10-20 15:51:10 +08001834 switch (GST_EVENT_TYPE(event))
1835 {
1836 case GST_EVENT_FLUSH_START:
1837 {
1838 GST_INFO_OBJECT(sink, "flush start");
1839 GST_OBJECT_LOCK(sink);
1840 sink_priv->is_flushing = TRUE;
le.hanb62dfce2024-02-28 03:23:12 +00001841 render_set_value(sink_priv->render_device_handle, KEY_KEEP_LAST_FRAME_ON_FLUSH, &sink->keep_last_frame_on_flush);
1842
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08001843 rotation_flush_buffer(sink);
1844
fei.dengbdb18e52023-08-16 06:42:34 +00001845 if (render_flush(sink_priv->render_device_handle) == 0)
1846 {
1847 GST_INFO_OBJECT(sink, "recv flush start and set render lib flushing succ");
1848 }
xuesong.jiangaed30942022-06-17 14:27:27 +08001849 GST_INFO_OBJECT(sink, "flush start done");
xuesong.jiangd91230d2021-10-20 15:51:10 +08001850 GST_OBJECT_UNLOCK(sink);
1851 break;
1852 }
1853 case GST_EVENT_FLUSH_STOP:
1854 {
1855 GST_INFO_OBJECT(sink, "flush stop");
fei.deng6fdfab72024-08-05 16:54:58 +08001856 GST_DEBUG_OBJECT(sink, "flushing need waitting display render all buf, queued:%d, rendered:%d, dropped:%d",
xuesong.jiang9ae8f882022-04-18 20:15:06 +08001857 sink->queued,
1858 sink->rendered,
fei.deng6fdfab72024-08-05 16:54:58 +08001859 sink->dropped);
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001860
xuesong.jiangd91230d2021-10-20 15:51:10 +08001861 GST_OBJECT_LOCK(sink);
xuesong.jiang28a82172022-04-28 15:05:46 +08001862 GST_INFO_OBJECT(sink, "flush all count num to zero");
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001863 sink->queued = 0;
1864 sink->dequeued = 0;
1865 sink->rendered = 0;
fei.deng6fdfab72024-08-05 16:54:58 +08001866 sink->dropped = 0;
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001867 sink_priv->got_eos = FALSE;
xuesong.jiangd91230d2021-10-20 15:51:10 +08001868 sink_priv->is_flushing = FALSE;
xuesong.jiangaed30942022-06-17 14:27:27 +08001869 GST_INFO_OBJECT(sink, "flush stop done");
xuesong.jiangd91230d2021-10-20 15:51:10 +08001870 GST_OBJECT_UNLOCK(sink);
1871 break;
1872 }
1873 case GST_EVENT_SEGMENT:
1874 {
1875 GST_OBJECT_LOCK(sink);
1876 gst_event_copy_segment(event, &sink_priv->segment);
1877 GST_INFO_OBJECT(sink, "configured segment %" GST_SEGMENT_FORMAT, &sink_priv->segment);
xuesong.jiangaed30942022-06-17 14:27:27 +08001878 sink->last_displayed_buf_pts = sink_priv->segment.position;
1879 GST_INFO_OBJECT(sink, "update cur pos to %" GST_TIME_FORMAT, GST_TIME_ARGS(sink->last_displayed_buf_pts));
xuesong.jiangd91230d2021-10-20 15:51:10 +08001880 GST_OBJECT_UNLOCK(sink);
1881 break;
1882 }
sheng.liu5c98a4e2022-06-21 10:27:43 +08001883 case GST_EVENT_CUSTOM_DOWNSTREAM:
xuesong.jiang16ae3212022-07-12 15:32:10 +08001884 case GST_EVENT_CUSTOM_DOWNSTREAM_STICKY:
sheng.liu5c98a4e2022-06-21 10:27:43 +08001885 {
xuesong.jiang8e09c742022-07-27 16:38:32 +08001886 if (gst_event_has_name(event, "IS_SVP"))
sheng.liu5c98a4e2022-06-21 10:27:43 +08001887 {
1888 GST_OBJECT_LOCK(sink);
1889 GST_DEBUG_OBJECT(sink, "Got SVP Event");
1890 sink->secure_mode = TRUE;
1891 GST_OBJECT_UNLOCK(sink);
1892 }
hanghang.luoc3ef9852023-07-11 09:00:01 +00001893
xuesong.jiang16ae3212022-07-12 15:32:10 +08001894 gst_event_unref(event);
1895 return result;
xuesong.jiang0c1fb952022-06-24 21:20:16 +08001896 }
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001897 case GST_EVENT_EOS:
1898 {
1899 GST_OBJECT_LOCK(sink);
1900 sink_priv->got_eos = TRUE;
1901 GST_OBJECT_UNLOCK(sink);
1902
fei.deng10e3d502023-05-10 06:52:46 +00001903 //some frames aren't displayed,so don't pass this event to basesink
fei.deng6fdfab72024-08-05 16:54:58 +08001904 if (sink->queued > (sink->rendered + sink->dropped))
xuesong.jiang62ed50e2022-04-13 16:55:47 +08001905 {
fei.deng6fdfab72024-08-05 16:54:58 +08001906 GST_DEBUG_OBJECT(sink, "display render all buf, queued:%d, rendered:%d, dropped:%d",
xuesong.jiang9ae8f882022-04-18 20:15:06 +08001907 sink->queued,
1908 sink->rendered,
fei.deng6fdfab72024-08-05 16:54:58 +08001909 sink->dropped);
fei.deng10e3d502023-05-10 06:52:46 +00001910 gst_event_unref(event);
1911 return result;
xuesong.jiang62ed50e2022-04-13 16:55:47 +08001912 }
fei.deng2f462142023-05-24 03:07:29 +00001913 break;
xuesong.jiang4a832aa2022-01-06 16:44:26 +08001914 }
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08001915 case GST_EVENT_TAG:
1916 {
1917 GstTagList *list = NULL;
1918 gst_event_parse_tag (event, &list);
1919 if (list)
1920 {
1921 gst_aml_video_sink_tag_event(sink, list);
1922 }
1923 break;
1924 }
fei.deng10e3d502023-05-10 06:52:46 +00001925 case GST_EVENT_CAPS:
1926 {
1927 GstCaps *caps;
1928 GstStructure *structure;
1929 gst_event_parse_caps(event, &caps);
1930
1931 structure= gst_caps_get_structure(caps, 0);
1932 if (structure)
1933 {
1934 gint num, denom;
1935 if (gst_structure_get_fraction( structure, "framerate", &num, &denom ))
1936 {
fei.deng68c63342023-12-05 07:37:33 +00001937 GST_DEBUG_OBJECT(sink, "framerate num:%d,denom:%d",num,denom);
fei.deng10e3d502023-05-10 06:52:46 +00001938 if ( denom == 0 ) denom= 1;
fei.deng2f462142023-05-24 03:07:29 +00001939 sink->frame_rate= (double)num/(double)denom;
1940 if ( sink->frame_rate <= 0.0 )
fei.deng10e3d502023-05-10 06:52:46 +00001941 {
1942 GST_DEBUG_OBJECT(sink, "caps have framerate of 0 - assume 60");
fei.deng2f462142023-05-24 03:07:29 +00001943 sink->frame_rate= 60.0;
fei.deng10e3d502023-05-10 06:52:46 +00001944 }
fei.deng68c63342023-12-05 07:37:33 +00001945 if (sink->frame_rate_num != num || sink->frame_rate_denom != denom) {
1946 sink->frame_rate_num = num;
1947 sink->frame_rate_denom = denom;
1948 sink->frame_rate_changed = TRUE;
1949 }
sheng.liu1a079692023-12-26 06:33:41 +00001950
1951 if ( gst_structure_get_fraction( structure, "pixel-aspect-ratio", &num, &denom ) )
1952 {
1953 if ( (num <= 0) || (denom <= 0))
1954 {
1955 num = denom = 1;
1956 }
1957 sink->pixel_aspect_ratio = (double)num/(double)denom;
1958 sink->pixel_aspect_ratio_changed = TRUE;
1959 }
fei.deng10e3d502023-05-10 06:52:46 +00001960 }
1961 }
1962 } break;
xuesong.jiangd91230d2021-10-20 15:51:10 +08001963 default:
1964 {
xuesong.jiang0ebc0332022-07-05 10:58:02 +08001965 break;
xuesong.jiangd91230d2021-10-20 15:51:10 +08001966 }
1967 }
xuesong.jiang0ebc0332022-07-05 10:58:02 +08001968
1969 GST_DEBUG_OBJECT(sink, "pass to basesink");
1970 result = GST_BASE_SINK_CLASS(parent_class)->event((GstBaseSink *)sink, event);
fei.deng68c63342023-12-05 07:37:33 +00001971 GST_DEBUG_OBJECT(sink, "done");
xuesong.jiangd91230d2021-10-20 15:51:10 +08001972 return result;
xuesong.jiang1801e172021-10-11 10:56:41 +08001973}
1974
xuesong.jiang69031992022-06-09 19:30:35 +08001975static gboolean gst_aml_video_sink_send_event(GstElement *element, GstEvent *event)
1976{
1977 GstPad *pad = NULL;
1978 GstBaseSink *basesink = GST_BASE_SINK(element);
1979 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(element);
1980 GstAmlVideoSinkClass *sink_class = GST_AML_VIDEO_SINK_GET_CLASS(sink);
1981 GstVideoSinkClass *sink_p_class = parent_class;
1982 GstBaseSinkClass *sink_pp_class = g_type_class_peek_parent(sink_p_class);
1983 gboolean result = TRUE;
1984 GstPadMode mode = GST_PAD_MODE_NONE;
1985
1986 GST_DEBUG_OBJECT(sink, "amlvideosink_class:%p, videosink_class:%p, basesink_class:%p", sink_class, sink_p_class, sink_pp_class);
1987 GST_DEBUG_OBJECT(sink, "handling event %p %" GST_PTR_FORMAT, event, event);
1988
1989 switch (GST_EVENT_TYPE(event))
1990 {
1991 case GST_EVENT_SEEK:
1992 {
1993 GST_OBJECT_LOCK(element);
1994 /* get the pad and the scheduling mode */
1995 pad = gst_object_ref(basesink->sinkpad);
1996 mode = basesink->pad_mode;
1997 GST_OBJECT_UNLOCK(element);
1998
1999 if (mode == GST_PAD_MODE_PUSH)
2000 {
2001 GST_BASE_SINK_PREROLL_LOCK(basesink);
2002 if (GST_BASE_SINK(sink)->need_preroll && GST_BASE_SINK(sink)->have_preroll)
2003 {
2004 GST_DEBUG_OBJECT(sink, "reset preroll when recived seek event");
2005 GST_BASE_SINK(sink)->need_preroll = FALSE;
2006 GST_BASE_SINK(sink)->have_preroll = FALSE;
2007 GST_BASE_SINK_PREROLL_SIGNAL(basesink);
2008 }
2009 GST_BASE_SINK_PREROLL_UNLOCK(basesink);
2010 }
2011
2012 gst_object_unref(pad);
2013 break;
2014 }
2015 default:
2016 break;
2017 }
2018
2019 if (GST_ELEMENT_CLASS(sink_pp_class)->send_event)
2020 {
2021 GST_DEBUG_OBJECT(sink, "use basesink class send event func handle event");
2022 result = GST_ELEMENT_CLASS(sink_pp_class)->send_event(element, event);
2023 }
2024 else
2025 {
2026 GST_ERROR_OBJECT(sink, "can't find basesink send event func");
2027 result = FALSE;
2028 }
2029
2030 GST_DEBUG_OBJECT(sink, "handled event: %d", result);
2031
2032 return result;
2033}
2034
xuesong.jiang1801e172021-10-11 10:56:41 +08002035/* private interface definition */
xuesong.jiang8e09c742022-07-27 16:38:32 +08002036static gboolean gst_aml_video_sink_check_buf(GstAmlVideoSink *sink, GstBuffer *buf)
2037{
2038 gboolean ret = TRUE;
2039 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
2040 guint64 start, stop;
2041 guint64 cstart, cstop;
2042 GstSegment *segment;
2043 GstClockTime duration;
2044
2045 /* Check for clipping */
2046 start = GST_BUFFER_PTS(buf);
2047 duration = GST_BUFFER_DURATION(buf);
2048 stop = GST_CLOCK_TIME_NONE;
2049
2050 if (GST_CLOCK_TIME_IS_VALID (start) && GST_CLOCK_TIME_IS_VALID (duration))
2051 {
2052 stop = start + duration;
2053 }
2054 else if (GST_CLOCK_TIME_IS_VALID (start) && !GST_CLOCK_TIME_IS_VALID (duration))
2055 {
fei.dengab16ff12024-08-07 17:58:07 +08002056 if (start < sink_priv->segment.start)
2057 {
2058 ret = FALSE;
2059 goto drop;
2060 }
bo.xiao611b8e42024-07-18 11:33:46 +08002061 if (sink_priv->fps_n != 0)
xuesong.jiang8e09c742022-07-27 16:38:32 +08002062 {
2063 //TODO calc with framerate
2064 stop = start + 40 * GST_MSECOND;
2065 }
2066 else
2067 {
2068 /* If we don't clip away buffers that far before the segment we
2069 * can cause the pipeline to lockup. This can happen if audio is
2070 * properly clipped, and thus the audio sink does not preroll yet
2071 * but the video sink prerolls because we already outputted a
2072 * buffer here... and then queues run full.
2073 *
2074 * In the worst case we will clip one buffer too many here now if no
2075 * framerate is given, no buffer duration is given and the actual
2076 * framerate is lower than 25fps */
2077 stop = start + 40 * GST_MSECOND;
2078 }
2079 }
2080
2081 segment = &sink_priv->segment;
2082 GST_LOG_OBJECT(sink, "check buffer start: %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT "fps_n:%d, fps_d:%d",
bo.xiao611b8e42024-07-18 11:33:46 +08002083 GST_TIME_ARGS(start), GST_TIME_ARGS(stop), sink_priv->fps_n, sink_priv->fps_d);
xuesong.jiang8e09c742022-07-27 16:38:32 +08002084 if (gst_segment_clip(segment, GST_FORMAT_TIME, start, stop, &cstart, &cstop))
2085 {
2086 GST_BUFFER_PTS(buf) = cstart;
2087
2088 if (stop != GST_CLOCK_TIME_NONE && GST_CLOCK_TIME_IS_VALID(duration))
2089 GST_BUFFER_DURATION(buf) = cstop - cstart;
2090
2091 GST_LOG_OBJECT(sink,
2092 "accepting buffer inside segment: %" GST_TIME_FORMAT " %" GST_TIME_FORMAT " seg %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT
2093 " time %" GST_TIME_FORMAT,
2094 GST_TIME_ARGS(cstart),
2095 GST_TIME_ARGS(cstop),
2096 GST_TIME_ARGS(segment->start), GST_TIME_ARGS(segment->stop),
2097 GST_TIME_ARGS(segment->time));
2098 }
2099 else
2100 {
2101 GST_LOG_OBJECT(sink,
2102 "dropping buffer outside segment: %" GST_TIME_FORMAT
2103 " %" GST_TIME_FORMAT
2104 " seg %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT
2105 " time %" GST_TIME_FORMAT,
2106 GST_TIME_ARGS(start), GST_TIME_ARGS(stop),
2107 GST_TIME_ARGS(segment->start),
2108 GST_TIME_ARGS(segment->stop), GST_TIME_ARGS(segment->time));
2109
2110 ret = FALSE;
2111 }
fei.dengab16ff12024-08-07 17:58:07 +08002112drop:
xuesong.jiang8e09c742022-07-27 16:38:32 +08002113 return ret;
2114}
2115
xuesong.jiangd91230d2021-10-20 15:51:10 +08002116static void gst_aml_video_sink_reset_private(GstAmlVideoSink *sink)
xuesong.jiang1801e172021-10-11 10:56:41 +08002117{
xuesong.jiangd91230d2021-10-20 15:51:10 +08002118 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jianga52aa5b2022-05-13 16:00:32 +08002119#if GST_IMPORT_LGE_PROP
2120 if (sink_priv->lge_ctxt.app_type)
2121 g_free(sink_priv->lge_ctxt.app_type);
2122 if (sink_priv->lge_ctxt.res_info.coretype)
2123 g_free(sink_priv->lge_ctxt.res_info.coretype);
2124#endif
xuesong.jiangd91230d2021-10-20 15:51:10 +08002125 memset(sink_priv, 0, sizeof(GstAmlVideoSinkPrivate));
xuesong.jiangd91230d2021-10-20 15:51:10 +08002126 sink_priv->use_dmabuf = USE_DMABUF;
xuesong.jiang50a0f932021-11-15 15:18:51 +08002127 sink_priv->mediasync_instanceid = -1;
fei.deng978b2422023-11-30 10:33:23 +00002128 sink_priv->show_first_frame_asap = FALSE;
fei.deng68c63342023-12-05 07:37:33 +00002129 sink_priv->emitUnderflowSignal = FALSE;
le.han7bb29b62024-08-07 03:17:09 +00002130 if (sink_priv->reportInfos) {
2131 g_list_free(sink_priv->reportInfos);
2132 }
2133 sink_priv->reportInfos = NULL;
fei.deng56733472024-09-19 20:12:43 +08002134 sink_priv->frame_step_on_preroll = FALSE;
bo.xiao611b8e42024-07-18 11:33:46 +08002135
2136 sink_priv->format = GST_VIDEO_FORMAT_UNKNOWN;
2137 sink_priv->interlace = FALSE;
2138 sink_priv->dw_width = 0;
2139 sink_priv->dw_height = 0;
2140 sink_priv->src_width = 0;
2141 sink_priv->src_height = 0;
2142 sink_priv->dw_size = 0;
le.han30f126e2024-10-09 02:42:55 +00002143 sink_priv->dw_mode = -1;
2144 sink_priv->stride = 0;
bo.xiao611b8e42024-07-18 11:33:46 +08002145 sink_priv->par_n = 0;
2146 sink_priv->par_d = 0;
2147 sink_priv->fps_n = 0;
2148 sink_priv->fps_d = 0;
fei.deng3a374e52024-10-29 17:04:42 +08002149 sink_priv->video_latency = 0;
2150 sink_priv->set_video_latency = FALSE;
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002151 sink_priv->rot_buffer = NULL;
2152 sink_priv->rot_degree = WST_ROTATION_0;
2153 sink_priv->rot_changed = FALSE;
2154 sink_priv->rot_enable_property = FALSE;
fei.deng053f4072024-11-20 19:05:43 +08002155 sink_priv->force_aspect_ratio = FALSE;
xuesong.jiangd91230d2021-10-20 15:51:10 +08002156}
fei.dengbdb18e52023-08-16 06:42:34 +00002157
le.han9ff888d2024-09-09 03:04:31 +00002158static void gst_set_report_info(void *userData, RenderMsgType type, int64_t pts, int64_t duration)
le.han7bb29b62024-08-07 03:17:09 +00002159{
2160 GstAmlVideoSink *sink = (GstAmlVideoSink *)userData;
2161 g_mutex_lock(&sink->report_info_lock);
2162 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
2163 ReportInfo *report_info = g_new(ReportInfo, 1);
2164 report_info->msg = type;
2165 report_info->info.pts = pts;
2166 report_info->info.duration = duration;
2167 sink_priv->reportInfos = g_list_append(sink_priv->reportInfos, report_info);
2168 GST_LOG_OBJECT(sink, "msg:%d pts:%lld duration:%lld", type, pts, duration);
2169 g_mutex_unlock(&sink->report_info_lock);
2170}
2171
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002172static gboolean is_rotation_buffer(void *userData, void* pbuf)
2173{
2174 GstAmlVideoSink *sink = (GstAmlVideoSink *)userData;
2175 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
2176
2177 // no rotation buffer
2178 if (!sink_priv->rot_buffer)
2179 {
2180 return FALSE;
2181 }
2182
2183 ROTBuffer* rotation_buffer = (ROTBuffer*)pbuf;
2184 for (int i = 0; i < ROT_BUFFER_MAX; i++)
2185 {
2186 if (rotation_buffer == &sink_priv->rot_buffer[i])
2187 {
2188 return TRUE;
2189 }
2190 }
2191 return FALSE;
2192}
2193
fei.dengbdb18e52023-08-16 06:42:34 +00002194static void gst_render_msg_callback(void *userData, RenderMsgType type, void *msg)
xuesong.jiangd91230d2021-10-20 15:51:10 +08002195{
xuesong.jiange90be372021-10-21 11:29:57 +08002196 GstAmlVideoSink *sink = (GstAmlVideoSink *)userData;
fei.deng56733472024-09-19 20:12:43 +08002197 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiange90be372021-10-21 11:29:57 +08002198 switch (type)
xuesong.jiangd91230d2021-10-20 15:51:10 +08002199 {
xuesong.jiang28a82172022-04-28 15:05:46 +08002200 case MSG_DROPED_BUFFER:
xuesong.jiang4a832aa2022-01-06 16:44:26 +08002201 case MSG_DISPLAYED_BUFFER:
2202 {
xuesong.jiang4a832aa2022-01-06 16:44:26 +08002203 RenderBuffer *tunnel_lib_buf_wrap = (RenderBuffer *)msg;
2204 RenderDmaBuffer *dmabuf = &tunnel_lib_buf_wrap->dma;
xuesong.jiang28a82172022-04-28 15:05:46 +08002205
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002206 if (tunnel_lib_buf_wrap->priv)
2207 {
2208 sink->last_displayed_buf_pts = tunnel_lib_buf_wrap->pts;
2209 if (type == MSG_DROPED_BUFFER)
2210 {
2211 GST_LOG_OBJECT(sink, "get message: MSG_DROPED_BUFFER from tunnel lib");
2212 sink->dropped++;
2213 gst_set_report_info(userData, type, tunnel_lib_buf_wrap->pts, 0);
2214 }
2215 else if (type == MSG_DISPLAYED_BUFFER)
2216 {
2217 GST_LOG_OBJECT(sink, "get message: MSG_DISPLAYED_BUFFER from tunnel lib");
2218 sink->rendered++;
2219 if (sink_priv->frame_step_on_preroll && sink->video_playing == FALSE) {
2220 render_pause(sink_priv->render_device_handle);
2221 }
2222 }
2223 GST_DEBUG_OBJECT(sink, "buf:%p planeCnt:%d, plane[0].fd:%d, plane[1].fd:%d pts:%lld, buf stat | queued:%d, dequeued:%d, dropped:%d, rendered:%d",
2224 tunnel_lib_buf_wrap->priv,
2225 dmabuf->planeCnt, dmabuf->fd[0], dmabuf->fd[1],
2226 tunnel_lib_buf_wrap->priv ? tunnel_lib_buf_wrap->pts : -1, sink->queued, sink->dequeued, sink->dropped, sink->rendered);
2227 //gst_aml_video_sink_dump_stat(sink, GST_DUMP_STAT_FILENAME);
xuesong.jiang4a832aa2022-01-06 16:44:26 +08002228 }
2229 else
2230 {
xuesong.jiang28a82172022-04-28 15:05:46 +08002231 GST_ERROR_OBJECT(sink, "tunnel lib: return void GstBuffer when MSG_DISPLAYED_BUFFER or MSG_DROPED_BUFFER");
xuesong.jiang4a832aa2022-01-06 16:44:26 +08002232 }
xuesong.jiang4a832aa2022-01-06 16:44:26 +08002233 break;
2234 }
xuesong.jiang50a0f932021-11-15 15:18:51 +08002235 case MSG_RELEASE_BUFFER:
xuesong.jiangd91230d2021-10-20 15:51:10 +08002236 {
xuesong.jiange90be372021-10-21 11:29:57 +08002237 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiang50a0f932021-11-15 15:18:51 +08002238 RenderBuffer *tunnel_lib_buf_wrap = (RenderBuffer *)msg;
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002239 GST_LOG_OBJECT(sink, "get message: MSG_RELEASE_BUFFER from tunnel lib,%p, pts:%lld ns",tunnel_lib_buf_wrap->priv, tunnel_lib_buf_wrap->pts);
2240 if (tunnel_lib_buf_wrap->priv)
xuesong.jiange90be372021-10-21 11:29:57 +08002241 {
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002242 if (is_rotation_buffer(userData, tunnel_lib_buf_wrap->priv))
2243 {
2244 ROTBuffer* rotation_buffer = (ROTBuffer*)tunnel_lib_buf_wrap->priv;
2245 rotation_buffer->used = FALSE;
2246 /*printf("release [%d][%d][%d][%d][%d]\n", sink_priv->rot_buffer[0].used, sink_priv->rot_buffer[1].used,
2247 sink_priv->rot_buffer[2].used, sink_priv->rot_buffer[3].used, sink_priv->rot_buffer[4].used);*/
2248 }
2249 else
2250 {
2251 GstBuffer *buffer = (GstBuffer *)tunnel_lib_buf_wrap->priv;
xuesong.jiang4a832aa2022-01-06 16:44:26 +08002252 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 +08002253 gst_buffer_unref(buffer);
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002254 }
2255 sink->dequeued++;
2256 //gst_aml_video_sink_dump_stat(sink, GST_DUMP_STAT_FILENAME);
xuesong.jiange90be372021-10-21 11:29:57 +08002257 }
2258 else
2259 {
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002260 GST_ERROR_OBJECT(sink, "tunnel lib: return void GstBuffer when MSG_RELEASE_BUFFER");
xuesong.jiange90be372021-10-21 11:29:57 +08002261 }
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002262
xuesong.jiang50a0f932021-11-15 15:18:51 +08002263 render_free_render_buffer_wrap(sink_priv->render_device_handle, tunnel_lib_buf_wrap);
2264 break;
2265 }
fei.dengbdb18e52023-08-16 06:42:34 +00002266 case MSG_FIRST_FRAME: {
2267 GST_LOG_OBJECT(sink, "signal first frame");
2268 g_signal_emit (G_OBJECT (sink), g_signals[SIGNAL_FIRSTFRAME], 0, 2, NULL);
2269 } break;
2270 case MSG_UNDER_FLOW: {
fei.deng520f8cf2023-11-15 06:31:06 +00002271 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
fei.deng68c63342023-12-05 07:37:33 +00002272 if (sink->video_playing && !sink_priv->got_eos) {
fei.deng520f8cf2023-11-15 06:31:06 +00002273 GST_LOG_OBJECT(sink, "signal under flow");
fei.deng68c63342023-12-05 07:37:33 +00002274 sink_priv->emitUnderflowSignal = TRUE;
fei.deng520f8cf2023-11-15 06:31:06 +00002275 }
fei.dengbdb18e52023-08-16 06:42:34 +00002276 } break;
le.han7bb29b62024-08-07 03:17:09 +00002277 case MSG_FRAME_FREEZE: {
2278 FrameDisplayInfo *info = (FrameDisplayInfo *) msg;
2279 gst_set_report_info(userData, type, info->pts, info->duration);
2280 } break;
2281 case MSG_AV_RESYNC: {
2282 FrameDisplayInfo *info = (FrameDisplayInfo *) msg;
2283 gst_set_report_info(userData, type, info->pts, info->duration);
2284 } break;
xuesong.jiange90be372021-10-21 11:29:57 +08002285 default:
2286 {
le.han7bb29b62024-08-07 03:17:09 +00002287 GST_ERROR_OBJECT(sink, "tunnel lib: error message type:%d", type);
xuesong.jiange90be372021-10-21 11:29:57 +08002288 }
2289 }
2290 return;
2291}
2292
fei.dengbdb18e52023-08-16 06:42:34 +00002293static int gst_render_val_callback(void *userData, int key, void *value)
xuesong.jiang50a0f932021-11-15 15:18:51 +08002294{
2295 GstAmlVideoSink *vsink = (GstAmlVideoSink *)userData;
2296 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(vsink);
xuesong.jiang32d78282021-11-18 19:24:15 +08002297 int *val = (int *)value;
xuesong.jiang50a0f932021-11-15 15:18:51 +08002298 gint ret = 0;
xuesong.jiang8e8a58a2021-11-15 17:02:41 +08002299 switch (key)
xuesong.jiang50a0f932021-11-15 15:18:51 +08002300 {
xuesong.jiang75ef01c2021-12-09 17:08:52 +08002301 case KEY_MEDIASYNC_INSTANCE_ID:
xuesong.jiang50a0f932021-11-15 15:18:51 +08002302 {
2303 if (gst_get_mediasync_instanceid(vsink))
2304 {
fei.deng2f462142023-05-24 03:07:29 +00002305 int hasAudio = 1;
xuesong.jiang8e8a58a2021-11-15 17:02:41 +08002306 *val = sink_priv->mediasync_instanceid;
2307 GST_DEBUG_OBJECT(vsink, "get mediasync instance id:%d", *val);
fei.dengbdb18e52023-08-16 06:42:34 +00002308 render_set_value(sink_priv->render_device_handle, KEY_MEDIASYNC_SYNC_MODE, (void *)&vsink->avsync_mode);
2309 render_set_value(sink_priv->render_device_handle, KEY_MEDIASYNC_HAS_AUDIO, (void *)&hasAudio);
xuesong.jiang50a0f932021-11-15 15:18:51 +08002310 }
2311 else
2312 {
fei.dengbdb18e52023-08-16 06:42:34 +00002313 int hasAudio = 0;
2314 vsink->avsync_mode = 0;// 0:v master, 1:a master
2315 render_set_value(sink_priv->render_device_handle, KEY_MEDIASYNC_SYNC_MODE, (void *)&vsink->avsync_mode);
2316 render_set_value(sink_priv->render_device_handle, KEY_MEDIASYNC_HAS_AUDIO, (void *)&hasAudio);
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08002317 GST_ERROR_OBJECT(vsink, "can't get mediasync instance id, use vmaster");
xuesong.jiang50a0f932021-11-15 15:18:51 +08002318 ret = -1;
2319 }
2320 break;
2321 }
2322 case KEY_VIDEO_FORMAT:
2323 {
bo.xiao611b8e42024-07-18 11:33:46 +08002324 *val = sink_priv->format;
2325 GST_DEBUG_OBJECT(vsink, "get video format:%d", *val);
xuesong.jiang50a0f932021-11-15 15:18:51 +08002326 break;
2327 }
2328 default:
2329 {
2330 GST_ERROR_OBJECT(vsink, "tunnel lib: error key type");
2331 ret = -1;
2332 }
2333 }
2334 return ret;
2335}
2336
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002337static int get_rotation_buffer_idx(GstAmlVideoSink *vsink)
2338{
2339 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(vsink);
2340
2341 if (sink_priv->rot_buffer)
2342 {
2343 for (int i = 0; i < ROT_BUFFER_MAX; i++)
2344 {
2345 if (!sink_priv->rot_buffer[i].used)
2346 {
2347 /*printf("ok [%d][%d][%d][%d][%d]\n", sink_priv->rot_buffer[0].used, sink_priv->rot_buffer[1].used,
2348 sink_priv->rot_buffer[2].used, sink_priv->rot_buffer[3].used, sink_priv->rot_buffer[4].used);*/
2349 return i;
2350 }
2351 }
2352 /*printf("fail [%d][%d][%d][%d][%d]\n", sink_priv->rot_buffer[0].used, sink_priv->rot_buffer[1].used,
2353 sink_priv->rot_buffer[2].used, sink_priv->rot_buffer[3].used, sink_priv->rot_buffer[4].used);*/
2354 }
2355
2356 return -1;
2357}
2358
2359static void set_video_reversal(GstAmlVideoSink *vsink)
2360{
2361 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(vsink);
2362 sink_priv->video_info_changed = TRUE;
2363 int degree = (sink_priv->rot_degree == WST_ROTATION_180 ? 180 : 0);
2364 if (render_set_value(sink_priv->render_device_handle, KEY_ROTATE_VIDEO, &degree) != -1)
2365 {
2366 GST_ERROR_OBJECT(vsink, "tunnel lib: set render video rotation success:%d", degree);
2367 sink_priv->rot_changed = FALSE;
2368 }
2369 else
2370 {
2371 GST_ERROR_OBJECT(vsink, "tunnel lib: set render video rotation failed:%d", degree);
2372 }
2373}
2374
xuesong.jiang7c724a52021-10-22 17:18:58 +08002375static gboolean gst_aml_video_sink_tunnel_buf(GstAmlVideoSink *vsink, GstBuffer *gst_buf, RenderBuffer *tunnel_lib_buf_wrap)
xuesong.jiange90be372021-10-21 11:29:57 +08002376{
le.han30f126e2024-10-09 02:42:55 +00002377 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(vsink);
xuesong.jiange90be372021-10-21 11:29:57 +08002378 // only support dma buf
xuesong.jiangf190e2a2021-11-22 20:26:00 +08002379 RenderDmaBuffer *dmabuf = &tunnel_lib_buf_wrap->dma;
xuesong.jiang8e8a58a2021-11-15 17:02:41 +08002380 GstMemory *dma_mem = NULL;
2381 GstVideoMeta *vmeta = NULL;
xuesong.jiange90be372021-10-21 11:29:57 +08002382 guint n_mem = 0;
xuesong.jiangf190e2a2021-11-22 20:26:00 +08002383 gboolean ret = TRUE;
xuesong.jiange90be372021-10-21 11:29:57 +08002384
xuesong.jiangeb46f672021-11-19 19:05:56 +08002385 if (gst_buf == NULL || tunnel_lib_buf_wrap == NULL || dmabuf == NULL)
xuesong.jiange90be372021-10-21 11:29:57 +08002386 {
2387 GST_ERROR_OBJECT(vsink, "input params error");
xuesong.jiangf190e2a2021-11-22 20:26:00 +08002388 ret = FALSE;
xuesong.jiange90be372021-10-21 11:29:57 +08002389 goto error;
2390 }
xuesong.jiang3e593432021-11-25 16:10:03 +08002391 gst_buffer_ref(gst_buf);
xuesong.jiang8e8a58a2021-11-15 17:02:41 +08002392 n_mem = gst_buffer_n_memory(gst_buf);
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08002393 vmeta = gst_buffer_get_video_meta(gst_buf);
2394 if (vmeta == NULL)
xuesong.jiang8e8a58a2021-11-15 17:02:41 +08002395 {
2396 GST_ERROR_OBJECT(vsink, "not found video meta info");
xuesong.jiangf190e2a2021-11-22 20:26:00 +08002397 ret = FALSE;
xuesong.jiang8e8a58a2021-11-15 17:02:41 +08002398 goto error;
2399 }
2400 if (n_mem > RENDER_MAX_PLANES || vmeta->n_planes > RENDER_MAX_PLANES || n_mem != vmeta->n_planes)
xuesong.jiange90be372021-10-21 11:29:57 +08002401 {
2402 GST_ERROR_OBJECT(vsink, "too many memorys in gst buffer");
2403 goto error;
2404 }
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08002405
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002406 // weston do rotation, set rotation 180 or 0
2407 if (sink_priv->rot_changed)
xuesong.jiange90be372021-10-21 11:29:57 +08002408 {
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002409 set_video_reversal(vsink);
2410 }
2411 dmabuf->planeCnt = n_mem;
2412 if (sink_priv->rot_degree == WST_ROTATION_90 || sink_priv->rot_degree == WST_ROTATION_270)
2413 {
2414 // get output size, and align 32byte
2415 get_rotation_size(vmeta->height, vmeta->width, &dmabuf->width, &dmabuf->height);
2416 // create ROT buf
2417 if (!sink_priv->rot_buffer)
2418 {
2419 sink_priv->video_info_changed = TRUE;
2420 GST_ERROR_OBJECT(vsink, "planeCnt:%d, width:%d, height:%d", dmabuf->planeCnt, dmabuf->width, dmabuf->height);
2421 sink_priv->rot_buffer = rotation_buffer_setup(dmabuf->planeCnt, dmabuf->width, dmabuf->height, ROT_BUFFER_MAX);
2422 }
xuesong.jiangf190e2a2021-11-22 20:26:00 +08002423
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002424 // get ROT buf
2425 int index = get_rotation_buffer_idx(vsink);
2426 if (-1 == index)
2427 {
2428 GST_ERROR_OBJECT(vsink, "cant get rotation buffer");
2429 vsink->dropped++;
2430 goto error;
2431 }
2432 // do transform
2433 if (GST_FLOW_OK == rotation_transform(sink_priv->pge2dinfo, gst_buf, &sink_priv->rot_buffer[index], sink_priv->rot_degree))
2434 {
2435 sink_priv->rot_buffer[index].used = TRUE;
2436 }
xuesong.jiang16983c92021-12-30 10:57:17 +08002437
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002438 // ROT buffer trans to RenderBuffer
2439 for (guint i = 0; i < dmabuf->planeCnt; i++)
2440 {
xuesong.jiang8e8a58a2021-11-15 17:02:41 +08002441 dmabuf->handle[i] = 0;
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002442 dmabuf->fd[i] = sink_priv->rot_buffer[index].gemBuf.fd[i];
2443 if ( i == 0 )
xuesong.jiangf190e2a2021-11-22 20:26:00 +08002444 {
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002445 dmabuf->size[i] = sink_priv->rot_buffer[index].gemBuf.width * sink_priv->rot_buffer[index].gemBuf.height;
xuesong.jiangf190e2a2021-11-22 20:26:00 +08002446 }
2447 else
2448 {
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002449 dmabuf->size[i] = sink_priv->rot_buffer[index].gemBuf.width * sink_priv->rot_buffer[index].gemBuf.height/2;
xuesong.jiangf190e2a2021-11-22 20:26:00 +08002450 }
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002451 dmabuf->stride[i] = sink_priv->rot_buffer[index].gemBuf.stride[i];
2452 dmabuf->offset[i] = sink_priv->rot_buffer[index].gemBuf.offset[i];
2453 }
2454 tunnel_lib_buf_wrap->flag = BUFFER_FLAG_DMA_BUFFER;
2455 tunnel_lib_buf_wrap->priv = (void *)&sink_priv->rot_buffer[index];
2456 tunnel_lib_buf_wrap->pts = GST_BUFFER_PTS(gst_buf);
2457 // unref gstbuf
2458 gst_buffer_unref(gst_buf);
xuesong.jiange90be372021-10-21 11:29:57 +08002459 }
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002460 else
2461 {
2462 dmabuf->width = vmeta->width;
2463 dmabuf->height = vmeta->height;
2464 if (sink_priv->dw_mode == 0) {
2465 dmabuf->width = sink_priv->src_width;
2466 dmabuf->height = sink_priv->src_height;
2467 }
2468 // gstbuffer trans to RenderBuffer
2469 for (guint i = 0; i < n_mem; i++)
2470 {
2471 gint dmafd;
2472 gsize size, offset, maxsize;
2473 dma_mem = gst_buffer_peek_memory(gst_buf, i);
2474 guint mem_idx = 0;
2475 guint length = 0;
2476 gsize skip = 0;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08002477
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002478 if (!gst_is_dmabuf_memory(dma_mem))
2479 {
2480 GST_ERROR_OBJECT(vsink, "not support non-dma buf");
2481 ret = FALSE;
2482 goto error;
2483 }
2484 size = gst_memory_get_sizes(dma_mem, &offset, &maxsize);
2485 GST_LOG_OBJECT(vsink, "get memory size:%d, offset:%d, maxsize:%d", size, offset, maxsize);
2486
2487 dmafd = gst_dmabuf_memory_get_fd(dma_mem);
2488 dmabuf->handle[i] = 0;
2489 dmabuf->fd[i] = dmafd;
2490 dmabuf->size[i] = dma_mem->size;
2491 dmabuf->stride[i] = vmeta->stride[i];
2492 if (sink_priv->dw_mode == 0) {
2493 dmabuf->stride[i] = sink_priv->stride;
2494 }
2495 if (gst_buffer_find_memory(gst_buf, vmeta->offset[i], 1, &mem_idx, &length, &skip) && mem_idx == i)
2496 {
2497 dmabuf->offset[i] = dma_mem->offset + skip;
2498 //GST_DEBUG_OBJECT(vsink, "get skip from buffer:%d, offset[%d]:%d", skip, i, dmabuf->offset[i]);
2499 }
2500 else
2501 {
2502 GST_ERROR_OBJECT(vsink, "get skip from buffer error");
2503 }
2504 GST_LOG_OBJECT(vsink, "dma buffer layer:%d, handle:%d, fd:%d, size:%d, offset:%d, stride:%d",
2505 i, dmabuf->handle[i], dmabuf->fd[i], dmabuf->size[i], dmabuf->offset[i], dmabuf->stride[i]);
2506 }
2507 tunnel_lib_buf_wrap->flag = BUFFER_FLAG_DMA_BUFFER;
2508 tunnel_lib_buf_wrap->priv = (void *)gst_buf;
2509 tunnel_lib_buf_wrap->pts = GST_BUFFER_PTS(gst_buf);
2510 GST_LOG_OBJECT(vsink, "set tunnel lib buf priv:%p from pool:%p, pts:%lld", tunnel_lib_buf_wrap->priv, gst_buf->pool, tunnel_lib_buf_wrap->pts);
2511 }
xuesong.jiange90be372021-10-21 11:29:57 +08002512
2513error:
xuesong.jiangf190e2a2021-11-22 20:26:00 +08002514 return ret;
xuesong.jiang1801e172021-10-11 10:56:41 +08002515}
fei.dengbdb18e52023-08-16 06:42:34 +00002516
xuesong.jiang50a0f932021-11-15 15:18:51 +08002517static gboolean gst_get_mediasync_instanceid(GstAmlVideoSink *vsink)
xuesong.jiangb4c09b52021-10-26 20:18:35 +08002518{
xuesong.jiang75ef01c2021-12-09 17:08:52 +08002519 GST_DEBUG_OBJECT(vsink, "trace in");
xuesong.jiang50a0f932021-11-15 15:18:51 +08002520 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(vsink);
2521 GstElement *asink = gst_aml_video_sink_find_audio_sink(vsink);
xuesong.jiang4a832aa2022-01-06 16:44:26 +08002522 if (!asink)
2523 {
2524 GST_DEBUG_OBJECT(vsink, "pipeline don't have audio sink element");
2525 return FALSE;
2526 }
xuesong.jiang50a0f932021-11-15 15:18:51 +08002527 gboolean ret = TRUE;
fei.deng2dee9402023-05-06 08:21:21 +00002528 GParamSpec* spec = NULL;
2529 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(asink)), "avsync-session");
2530 GST_DEBUG_OBJECT(vsink, "check amlhalasink has avsync-session property %p", spec);
2531 if (spec)
2532 g_object_get (G_OBJECT(asink), "avsync-session", &sink_priv->mediasync_instanceid, NULL);
2533
2534 GST_DEBUG_OBJECT(vsink, "get mediasync instance id:%d, from amlhalasink:%p", sink_priv->mediasync_instanceid, asink);
2535
2536 if (sink_priv->mediasync_instanceid == -1)
xuesong.jiangb4c09b52021-10-26 20:18:35 +08002537 {
fei.deng2dee9402023-05-06 08:21:21 +00002538 GST_ERROR_OBJECT(vsink, "audio sink: don't have valid mediasync instance id");
xuesong.jiang50a0f932021-11-15 15:18:51 +08002539 ret = FALSE;
xuesong.jiangb4c09b52021-10-26 20:18:35 +08002540 }
xuesong.jiang192316f2021-10-27 14:51:56 +08002541 gst_object_unref(asink);
xuesong.jiang50a0f932021-11-15 15:18:51 +08002542 return ret;
xuesong.jiangb4c09b52021-10-26 20:18:35 +08002543}
2544
xuesong.jiang50a0f932021-11-15 15:18:51 +08002545static GstElement *gst_aml_video_sink_find_audio_sink(GstAmlVideoSink *sink)
xuesong.jiangb4c09b52021-10-26 20:18:35 +08002546{
xuesong.jiang75ef01c2021-12-09 17:08:52 +08002547 GST_DEBUG_OBJECT(sink, "trace in");
xuesong.jiang50a0f932021-11-15 15:18:51 +08002548 GstElement *audioSink = 0;
2549 GstElement *pipeline = 0;
2550 GstElement *element, *elementPrev = 0;
xuesong.jiangb4c09b52021-10-26 20:18:35 +08002551
xuesong.jiang50a0f932021-11-15 15:18:51 +08002552 element = GST_ELEMENT_CAST(sink);
2553 do
2554 {
2555 if (elementPrev)
2556 {
2557 gst_object_unref(elementPrev);
2558 }
fei.dengeb170e22023-11-08 04:24:19 +00002559 // TODO use this func will ref element,unref when done
xuesong.jiang50a0f932021-11-15 15:18:51 +08002560 element = GST_ELEMENT_CAST(gst_element_get_parent(element));
2561 if (element)
2562 {
2563 elementPrev = pipeline;
2564 pipeline = element;
2565 }
2566 } while (element != 0);
xuesong.jiangb4c09b52021-10-26 20:18:35 +08002567
xuesong.jiang50a0f932021-11-15 15:18:51 +08002568 if (pipeline)
2569 {
2570 GstIterator *iterElement = gst_bin_iterate_recurse(GST_BIN(pipeline));
2571 if (iterElement)
2572 {
2573 GValue itemElement = G_VALUE_INIT;
2574 while (gst_iterator_next(iterElement, &itemElement) == GST_ITERATOR_OK)
xuesong.jiangb4c09b52021-10-26 20:18:35 +08002575 {
xuesong.jiang50a0f932021-11-15 15:18:51 +08002576 element = (GstElement *)g_value_get_object(&itemElement);
2577 if (element && !GST_IS_BIN(element))
2578 {
2579 int numSrcPads = 0;
xuesong.jiangb4c09b52021-10-26 20:18:35 +08002580
xuesong.jiang50a0f932021-11-15 15:18:51 +08002581 GstIterator *iterPad = gst_element_iterate_src_pads(element);
2582 if (iterPad)
2583 {
2584 GValue itemPad = G_VALUE_INIT;
2585 while (gst_iterator_next(iterPad, &itemPad) == GST_ITERATOR_OK)
xuesong.jiangb4c09b52021-10-26 20:18:35 +08002586 {
xuesong.jiang50a0f932021-11-15 15:18:51 +08002587 GstPad *pad = (GstPad *)g_value_get_object(&itemPad);
2588 if (pad)
2589 {
2590 ++numSrcPads;
2591 }
2592 g_value_reset(&itemPad);
xuesong.jiangb4c09b52021-10-26 20:18:35 +08002593 }
xuesong.jiang50a0f932021-11-15 15:18:51 +08002594 gst_iterator_free(iterPad);
2595 }
xuesong.jiangb4c09b52021-10-26 20:18:35 +08002596
xuesong.jiang50a0f932021-11-15 15:18:51 +08002597 if (numSrcPads == 0)
2598 {
2599 GstElementClass *ec = GST_ELEMENT_GET_CLASS(element);
2600 if (ec)
2601 {
2602 const gchar *meta = gst_element_class_get_metadata(ec, GST_ELEMENT_METADATA_KLASS);
2603 if (meta && strstr(meta, "Sink") && strstr(meta, "Audio"))
2604 {
2605 audioSink = (GstElement *)gst_object_ref(element);
2606 gchar *name = gst_element_get_name(element);
2607 if (name)
2608 {
2609 GST_DEBUG("detected audio sink: name (%s)", name);
2610 g_free(name);
2611 }
2612 g_value_reset(&itemElement);
2613 break;
2614 }
2615 }
2616 }
2617 }
2618 g_value_reset(&itemElement);
2619 }
2620 gst_iterator_free(iterElement);
2621 }
2622
2623 gst_object_unref(pipeline);
2624 }
xuesong.jiang4a832aa2022-01-06 16:44:26 +08002625 GST_DEBUG_OBJECT(sink, "trace out get audioSink:%p", audioSink);
xuesong.jiang50a0f932021-11-15 15:18:51 +08002626 return audioSink;
2627}
2628
2629static gboolean gst_render_set_params(GstVideoSink *vsink)
2630{
2631 GstAmlVideoSink *sink = GST_AML_VIDEO_SINK(vsink);
2632 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
xuesong.jiangbb769f02022-05-17 15:04:40 +08002633 int tunnelmode = 0; // 1 for tunnel mode; 0 for non-tunnel mode
xuesong.jiang50a0f932021-11-15 15:18:51 +08002634
bo.xiao611b8e42024-07-18 11:33:46 +08002635 RenderFrameSize frame_size = {sink_priv->src_width, sink_priv->src_height};
kaiqiang.xiangd8184ff2024-10-09 14:35:02 +08002636 if ((sink_priv->rot_degree == WST_ROTATION_90 || sink_priv->rot_degree == WST_ROTATION_270) && sink_priv->rot_buffer)
2637 {
2638 frame_size.width = sink_priv->rot_buffer[0].gemBuf.width;
2639 frame_size.height = sink_priv->rot_buffer[0].gemBuf.height;
2640 }
2641
bo.xiao611b8e42024-07-18 11:33:46 +08002642 GstVideoFormat format = sink_priv->format;
fei.dengbdb18e52023-08-16 06:42:34 +00002643
2644 if (render_set_value(sink_priv->render_device_handle, KEY_MEDIASYNC_TUNNEL_MODE, (void *)&tunnelmode) == -1)
2645 {
2646 GST_ERROR_OBJECT(vsink, "tunnel lib: set tunnelmode error");
2647 return FALSE;
2648 }
2649 if (render_set_value(sink_priv->render_device_handle, KEY_FRAME_SIZE, &frame_size) == -1)
2650 {
2651 GST_ERROR_OBJECT(vsink, "tunnel lib: set frame size error");
2652 return FALSE;
2653 }
2654 if (render_set_value(sink_priv->render_device_handle, KEY_VIDEO_FORMAT, &format) == -1)
2655 {
2656 GST_ERROR_OBJECT(vsink, "tunnel lib: set video format error");
2657 return FALSE;
2658 }
xuesong.jiang32d78282021-11-18 19:24:15 +08002659
xuesong.jiang50a0f932021-11-15 15:18:51 +08002660 return TRUE;
xuesong.jiangb4c09b52021-10-26 20:18:35 +08002661}
2662
le.han7bb29b62024-08-07 03:17:09 +00002663static gpointer detection_thread(gpointer data)
fei.deng10e3d502023-05-10 06:52:46 +00002664{
2665 GstAmlVideoSink *sink = (GstAmlVideoSink *)data;
2666 GstAmlVideoSinkPrivate *sink_priv = GST_AML_VIDEO_SINK_GET_PRIVATE(sink);
2667 int eosCountDown;
fei.deng68c63342023-12-05 07:37:33 +00002668 double frameRate = (sink->frame_rate > 0.0 ? sink->frame_rate : 30.0);
le.han7bb29b62024-08-07 03:17:09 +00002669 GST_DEBUG("detection_thread: enter");
fei.deng10e3d502023-05-10 06:52:46 +00002670
2671 eosCountDown = 2;
fei.deng2f462142023-05-24 03:07:29 +00002672 while (!sink->quit_eos_detect_thread )
fei.deng10e3d502023-05-10 06:52:46 +00002673 {
fei.deng68c63342023-12-05 07:37:33 +00002674 usleep(1000000/frameRate);
2675 if (sink->video_playing && sink_priv->emitUnderflowSignal) {
2676 sink_priv->emitUnderflowSignal = FALSE;
2677 g_signal_emit (G_OBJECT (sink), g_signals[SIGNAL_UNDERFLOW], 0, 0, NULL);
2678 }
le.han7bb29b62024-08-07 03:17:09 +00002679 g_mutex_lock(&sink->report_info_lock);
2680 if (sink->video_playing && (sink_priv->reportInfos != NULL)) {
2681 GList *l;
2682 for (l = sink_priv->reportInfos; l != NULL; l = l->next) {
2683 ReportInfo *report_info = l->data;
2684 if (report_info->msg == MSG_FRAME_FREEZE)
2685 {
2686 g_signal_emit (G_OBJECT (sink), g_signals[SIGNAL_FRAMEFREEZE], 0, report_info->info.pts, report_info->info.duration, NULL);
2687 }
2688 else if (report_info->msg == MSG_AV_RESYNC)
2689 {
2690 g_signal_emit (G_OBJECT (sink), g_signals[SIGNAL_RESYNC], 0, report_info->info.pts, report_info->info.duration, NULL);
2691 }
2692 else if (report_info->msg == MSG_DROPED_BUFFER)
2693 {
2694 g_signal_emit (G_OBJECT (sink), g_signals[SIGNAL_FRAMEDROP], 0, report_info->info.pts, NULL);
2695 }
2696 GST_DEBUG("emit FREEZE/RESYNC/DROP signal:%d, pts:%lld, duration:%lld", report_info->msg, report_info->info.pts, report_info->info.duration);
2697 g_free(report_info);
2698 }
2699 g_list_free(sink_priv->reportInfos);
2700 sink_priv->reportInfos = NULL;
2701 }
2702 g_mutex_unlock(&sink->report_info_lock);
fei.deng2f462142023-05-24 03:07:29 +00002703 if (sink->video_playing && sink_priv->got_eos)
fei.deng10e3d502023-05-10 06:52:46 +00002704 {
fei.deng053f4072024-11-20 19:05:43 +08002705 if (sink->queued <= sink->rendered + sink->dropped)
fei.deng10e3d502023-05-10 06:52:46 +00002706 {
2707 --eosCountDown;
2708 if ( eosCountDown == 0 )
2709 {
2710 GST_DEBUG("EOS detected");
2711 GstBaseSink *bs;
2712 bs= GST_BASE_SINK(sink);
2713 GST_BASE_SINK_PREROLL_LOCK(bs);
2714 GST_DEBUG("EOS: need_preroll %d have_preroll %d", bs->need_preroll, bs->have_preroll);
Le Han5534b5a2024-07-25 02:35:18 -07002715 if ( bs->need_preroll )
2716 {
2717 GstState cur, nxt, pend;
2718 /* complete preroll and commit state */
2719 GST_DEBUG("EOS signal preroll\n");
2720 bs->need_preroll= FALSE;
2721 bs->have_preroll= TRUE;
2722 GST_OBJECT_LOCK(bs);
2723 cur= GST_STATE(bs);
2724 nxt= GST_STATE_NEXT(bs);
2725 GST_STATE(bs)= pend= GST_STATE_PENDING(bs);
2726 GST_STATE_NEXT(bs)= GST_STATE_PENDING(bs)= GST_STATE_VOID_PENDING;
2727 GST_STATE_RETURN(bs)= GST_STATE_CHANGE_SUCCESS;
2728 GST_OBJECT_UNLOCK(bs);
2729 GST_DEBUG("EOS posting state change: curr(%s) next(%s) pending(%s)",
2730 gst_element_state_get_name(cur),
2731 gst_element_state_get_name(nxt),
2732 gst_element_state_get_name(pend));
2733 gst_element_post_message(GST_ELEMENT_CAST(bs), gst_message_new_state_changed(GST_OBJECT_CAST(bs), cur, nxt, pend));
2734 GST_DEBUG("EOS posting async done");
2735 gst_element_post_message(GST_ELEMENT_CAST(bs), gst_message_new_async_done(GST_OBJECT_CAST(bs), GST_CLOCK_TIME_NONE));
2736 GST_STATE_BROADCAST(bs)
2737 }
fei.deng10e3d502023-05-10 06:52:46 +00002738 GST_BASE_SINK_PREROLL_UNLOCK(bs);
2739 GST_DEBUG("EOS: calling eos detected: need_preroll %d have_preroll %d", bs->need_preroll, bs->have_preroll);
2740 gst_element_post_message (GST_ELEMENT_CAST(sink), gst_message_new_eos(GST_OBJECT_CAST(sink)));
2741 GST_DEBUG("EOS: done calling eos detected,posted eos msg, need_preroll %d have_preroll %d", bs->need_preroll, bs->have_preroll);
2742 break;
2743 }
2744 }
2745 else
2746 {
2747 eosCountDown = 2;
2748 }
2749 }
2750 }
2751
fei.dengbcd880e2023-06-19 02:19:26 +00002752 if (!sink->quit_eos_detect_thread)
2753 {
le.han7bb29b62024-08-07 03:17:09 +00002754 g_thread_unref( sink->detect_thread_handle );
2755 sink->detect_thread_handle= NULL;
fei.dengbcd880e2023-06-19 02:19:26 +00002756 }
le.han7bb29b62024-08-07 03:17:09 +00002757 GST_DEBUG("detection_thread: exit");
fei.deng10e3d502023-05-10 06:52:46 +00002758 return NULL;
2759}
2760
fei.dengab16ff12024-08-07 17:58:07 +08002761#if 0
xuesong.jiang5d2761f2022-05-05 11:43:21 +08002762static void gst_aml_video_sink_dump_stat(GstAmlVideoSink *sink, const gchar *file_name)
2763{
2764 const gchar *dump_dir = NULL;
2765 gchar *full_file_name = NULL;
2766 FILE *out = NULL;
2767
2768 dump_dir = g_getenv("GST_DEBUG_DUMP_AMLVIDEOSINK_STAT_DIR");
2769 if (G_LIKELY(dump_dir == NULL))
2770 return;
2771
2772 if (!file_name)
2773 {
2774 file_name = "unnamed";
2775 }
2776
2777 full_file_name = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s.stat", dump_dir, file_name);
2778
2779 if ((out = fopen(full_file_name, "w")))
2780 {
2781 gchar *stat_info;
fei.deng6fdfab72024-08-05 16:54:58 +08002782 stat_info = g_strdup_printf("Stat:%d | Q:%d, Dq:%d, Render:%d, Drop:%d\n", GST_STATE(sink), sink->queued, sink->dequeued, sink->rendered, sink->dropped);
xuesong.jiang5d2761f2022-05-05 11:43:21 +08002783 fputs(stat_info, out);
2784 g_free(stat_info);
2785 fclose(out);
2786 GST_INFO("wrote amlvideosink stat to : '%s' succ", full_file_name);
2787 }
2788 else
2789 {
2790 GST_WARNING("Failed to open file '%s' for writing: %s", full_file_name, g_strerror(errno));
2791 }
2792 g_free(full_file_name);
2793}
fei.dengab16ff12024-08-07 17:58:07 +08002794#endif
xuesong.jiang5d2761f2022-05-05 11:43:21 +08002795
xuesong.jiang1801e172021-10-11 10:56:41 +08002796/* plugin init */
xuesong.jiangd91230d2021-10-20 15:51:10 +08002797static gboolean plugin_init(GstPlugin *plugin)
2798{
xuesong.jiang1700bab2021-11-17 17:11:11 +08002799 GST_DEBUG_CATEGORY_INIT(gst_aml_video_sink_debug, "amlvideosink", 0,
2800 " aml video sink");
xuesong.jiang1801e172021-10-11 10:56:41 +08002801
xuesong.jiangf0ebebe2021-12-24 09:41:15 +08002802 gint rank = 1;
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08002803 const char *rank_env = getenv("GST_AML_VIDEO_SINK_RANK");
2804 if (rank_env)
2805 {
2806 rank = atoi(rank_env);
2807 }
xuesong.jiangf0ebebe2021-12-24 09:41:15 +08002808
2809 return gst_element_register(plugin, "amlvideosink", rank,
xuesong.jiangd91230d2021-10-20 15:51:10 +08002810 GST_TYPE_AML_VIDEO_SINK);
xuesong.jiang1801e172021-10-11 10:56:41 +08002811}
2812
xuesong.jiang5c0d1b82021-11-16 19:30:56 +08002813#ifndef VERSION
2814#define VERSION "0.1.0"
2815#endif
2816#ifndef PACKAGE
2817#define PACKAGE "aml_package"
2818#endif
2819#ifndef PACKAGE_NAME
2820#define PACKAGE_NAME "aml_media"
2821#endif
2822#ifndef GST_PACKAGE_ORIGIN
2823#define GST_PACKAGE_ORIGIN "http://amlogic.com"
2824#endif
2825// GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR, amlvideosink,
2826// "aml Video Sink", plugin_init, VERSION, "LGPL",
2827// "gst-plugin-video-sink", "")
xuesong.jiang7ec9f8f2022-03-14 15:03:04 +08002828GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
2829 GST_VERSION_MINOR,
2830 amlvideosink,
2831 "Amlogic plugin for video decoding/rendering",
2832 plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN)