blob: b5283347bf2f8c3067271bea236a8cac16a4739d [file] [log] [blame]
xuesong.jiangae1548e2022-05-06 16:38:46 +08001/* GStreamer
2 * Copyright (C) 2022 <xuesong.jiang@amlogic.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
17 * Boston, MA 02110-1335, USA.
18 */
19
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
24#include <sys/stat.h>
25#include <fcntl.h>
26#include <errno.h>
27#include <unistd.h>
28#include <string.h>
29
30#include "gstamlv4l2object.h"
31#include "gstamlv4l2videodec.h"
32
33#include <string.h>
34#include <gst/gst-i18n-plugin.h>
35#include <gst/allocators/gstdmabuf.h>
36
37GST_DEBUG_CATEGORY_STATIC(gst_aml_v4l2_video_dec_debug);
38#define GST_CAT_DEFAULT gst_aml_v4l2_video_dec_debug
39
40#ifdef GST_VIDEO_DECODER_STREAM_LOCK
41#undef GST_VIDEO_DECODER_STREAM_LOCK
42#define GST_VIDEO_DECODER_STREAM_LOCK(decoder) \
43 { \
fei.denge9458472023-04-18 02:05:48 +000044 GST_TRACE("aml v4l2 dec locking"); \
xuesong.jiangae1548e2022-05-06 16:38:46 +080045 g_rec_mutex_lock(&GST_VIDEO_DECODER(decoder)->stream_lock); \
fei.denge9458472023-04-18 02:05:48 +000046 GST_TRACE("aml v4l2 dec locked"); \
xuesong.jiangae1548e2022-05-06 16:38:46 +080047 }
48#endif
49
50#ifdef GST_VIDEO_DECODER_STREAM_UNLOCK
51#undef GST_VIDEO_DECODER_STREAM_UNLOCK
52#define GST_VIDEO_DECODER_STREAM_UNLOCK(decoder) \
53 { \
fei.denge9458472023-04-18 02:05:48 +000054 GST_TRACE("aml v4l2 dec unlocking"); \
xuesong.jiangae1548e2022-05-06 16:38:46 +080055 g_rec_mutex_unlock(&GST_VIDEO_DECODER(decoder)->stream_lock); \
fei.denge9458472023-04-18 02:05:48 +000056 GST_TRACE("aml v4l2 dec unlocked"); \
xuesong.jiangae1548e2022-05-06 16:38:46 +080057 }
58#endif
xuesong.jiang61ea8012022-05-12 15:38:17 +080059
zengliang.lidcd41462024-06-19 16:05:12 +080060#define GST_AML_V4L2_CC_IMPORT_QUARK gst_aml_v4l2_buffer_pool_cc_import_quark ()
61
hanghang.luo36df2852022-08-24 15:02:27 +080062#ifndef ABSDIFF
63#define ABSDIFF(a,b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))
64#endif
65
xuesong.jiang61ea8012022-05-12 15:38:17 +080066#if GST_IMPORT_LGE_PROP
67typedef struct _GstAmlResourceInfo
68{
69 gchar *coretype;
70 gint videoport;
71 gint audioport;
72 gint maxwidth;
73 gint maxheight;
74 gint mixerport;
75} GstAmlResourceInfo;
76
77struct _GstAmlV4l2VideoDecLgeCtxt
78{
79 GstAmlResourceInfo res_info;
80 guint64 dec_size;
81 guint64 undec_size;
82 gchar *app_type;
83 gboolean clip_mode;
84};
85#endif
86
xuesong.jiangae1548e2022-05-06 16:38:46 +080087typedef struct
88{
89 gchar *device;
90 GstCaps *sink_caps;
91 GstCaps *src_caps;
92 const gchar *longname;
93 const gchar *description;
94} GstAmlV4l2VideoDecCData;
95
96enum
97{
98 PROP_0,
xuesong.jiang61ea8012022-05-12 15:38:17 +080099 V4L2_STD_OBJECT_PROPS,
100#if GST_IMPORT_LGE_PROP
101 LGE_RESOURCE_INFO,
102 LGE_DECODE_SIZE,
103 LGE_UNDECODE_SIZE,
104 LGE_APP_TYPE,
105 LGE_CLIP_MODE
106#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +0800107};
108
xuesong.jiang406ee302023-06-28 03:45:22 +0000109enum
110{
111 SIGNAL_DECODED_PTS,
112 MAX_SIGNAL
113};
114
115static guint g_signals[MAX_SIGNAL]= {0};
116
xuesong.jiangae1548e2022-05-06 16:38:46 +0800117#define gst_aml_v4l2_video_dec_parent_class parent_class
118G_DEFINE_ABSTRACT_TYPE(GstAmlV4l2VideoDec, gst_aml_v4l2_video_dec,
119 GST_TYPE_VIDEO_DECODER);
120
121static GstFlowReturn gst_aml_v4l2_video_dec_finish(GstVideoDecoder *decoder);
xuesong.jiang61ea8012022-05-12 15:38:17 +0800122#if GST_IMPORT_LGE_PROP
123static void gst_aml_v4l2_video_dec_install_lge_properties_helper(GObjectClass *gobject_class);
124#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +0800125
126static void
127gst_aml_v4l2_video_dec_set_property(GObject *object,
128 guint prop_id, const GValue *value, GParamSpec *pspec)
129{
130 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(object);
131
132 switch (prop_id)
133 {
134 case PROP_CAPTURE_IO_MODE:
135 if (!gst_aml_v4l2_object_set_property_helper(self->v4l2capture,
136 prop_id, value, pspec))
137 {
138 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
139 }
140 break;
141 case PROP_DUMP_FRAME_LOCATION:
142 if (!gst_aml_v4l2_object_set_property_helper(self->v4l2capture,
143 prop_id, value, pspec))
144 {
145 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
146 }
147 break;
zengliang.lidcd41462024-06-19 16:05:12 +0800148 case PROP_CC_DATA:
149 if (!gst_aml_v4l2_object_set_property_helper(self->v4l2capture,
150 prop_id, value, pspec))
151 {
152 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
153 }
154 break;
xuesong.jiang61ea8012022-05-12 15:38:17 +0800155#if GST_IMPORT_LGE_PROP
156 case LGE_RESOURCE_INFO:
157 {
158 GST_DEBUG_OBJECT(self, "LGE up layer set res info");
159 GstStructure *r_info = g_value_get_object(value);
160 if (r_info)
161 {
162 if (gst_structure_has_field(r_info, "coretype"))
163 {
164 if (self->lge_ctxt->res_info.coretype)
165 g_free(self->lge_ctxt->res_info.coretype);
166 self->lge_ctxt->res_info.coretype = g_strdup(gst_structure_get_string(r_info, "coretype"));
167 }
168 if (gst_structure_has_field(r_info, "videoport"))
169 gst_structure_get_int(r_info, "videoport", &(self->lge_ctxt->res_info.videoport));
170 if (gst_structure_has_field(r_info, "audioport"))
171 gst_structure_get_int(r_info, "audioport", &(self->lge_ctxt->res_info.audioport));
172 if (gst_structure_has_field(r_info, "maxwidth"))
173 gst_structure_get_int(r_info, "maxwidth", &(self->lge_ctxt->res_info.maxwidth));
174 if (gst_structure_has_field(r_info, "maxheight"))
175 gst_structure_get_int(r_info, "maxheight", &(self->lge_ctxt->res_info.maxheight));
176 if (gst_structure_has_field(r_info, "mixerport"))
177 gst_structure_get_int(r_info, "mixerport", &(self->lge_ctxt->res_info.mixerport));
178 }
179 break;
180 }
181 case LGE_APP_TYPE:
182 {
183 GST_DEBUG_OBJECT(self, "LGE up layer set app type");
184 if (self->lge_ctxt->app_type)
185 g_free(self->lge_ctxt->app_type);
186 self->lge_ctxt->app_type = g_strdup(g_value_get_string(value));
187 break;
188 }
189 case LGE_CLIP_MODE:
190 {
191 GST_DEBUG_OBJECT(self, "LGE up layer set clip mode");
192 self->lge_ctxt->clip_mode = g_strdup(g_value_get_boolean(value));
193 break;
194 }
195#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +0800196 /* By default, only set on output */
197 default:
198 if (!gst_aml_v4l2_object_set_property_helper(self->v4l2output,
199 prop_id, value, pspec))
200 {
201 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
202 }
203 break;
204 }
205}
206
207static void
208gst_aml_v4l2_video_dec_get_property(GObject *object,
209 guint prop_id, GValue *value, GParamSpec *pspec)
210{
211 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(object);
212
213 switch (prop_id)
214 {
215 case PROP_CAPTURE_IO_MODE:
216 if (!gst_aml_v4l2_object_get_property_helper(self->v4l2capture,
217 prop_id, value, pspec))
218 {
219 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
220 }
221 break;
zengliang.lidcd41462024-06-19 16:05:12 +0800222 case PROP_CC_DATA:
223 if (!gst_aml_v4l2_object_get_property_helper(self->v4l2capture,
224 prop_id, value, pspec))
225 {
226 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
227 }
228 break;
xuesong.jiang61ea8012022-05-12 15:38:17 +0800229#if GST_IMPORT_LGE_PROP
230 case LGE_DECODE_SIZE:
231 {
232 GST_DEBUG_OBJECT(self, "LGE up layer get dec size");
233 self->lge_ctxt->dec_size = -1;
234 g_value_set_int(value, self->lge_ctxt->dec_size);
235 break;
236 }
237 case LGE_UNDECODE_SIZE:
238 {
239 GST_DEBUG_OBJECT(self, "LGE up layer get undec size");
240 self->lge_ctxt->undec_size = -1;
241 g_value_set_int(value, self->lge_ctxt->undec_size);
242 break;
243 }
244#endif
245
xuesong.jiangae1548e2022-05-06 16:38:46 +0800246 /* By default read from output */
247 default:
248 if (!gst_aml_v4l2_object_get_property_helper(self->v4l2output,
249 prop_id, value, pspec))
250 {
251 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
252 }
253 break;
254 }
255}
256
257static gboolean
258gst_aml_v4l2_video_dec_open(GstVideoDecoder *decoder)
259{
260 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
261 GstCaps *codec_caps;
262
263 GST_DEBUG_OBJECT(self, "Opening");
264
265 if (!gst_aml_v4l2_object_open(self->v4l2output))
266 goto failure;
267
268 if (!gst_aml_v4l2_object_open_shared(self->v4l2capture, self->v4l2output))
269 goto failure;
270
271 codec_caps = gst_pad_get_pad_template_caps(decoder->sinkpad);
272 self->probed_sinkcaps = gst_aml_v4l2_object_probe_caps(self->v4l2output,
273 codec_caps);
274 gst_caps_unref(codec_caps);
275
276 if (gst_caps_is_empty(self->probed_sinkcaps))
277 goto no_encoded_format;
278
279 return TRUE;
280
281no_encoded_format:
282 GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
283 (_("Decoder on device %s has no supported input format"),
284 self->v4l2output->videodev),
285 (NULL));
286 goto failure;
287
288failure:
289 if (GST_AML_V4L2_IS_OPEN(self->v4l2output))
290 gst_aml_v4l2_object_close(self->v4l2output);
291
292 if (GST_AML_V4L2_IS_OPEN(self->v4l2capture))
293 gst_aml_v4l2_object_close(self->v4l2capture);
294
295 gst_caps_replace(&self->probed_srccaps, NULL);
296 gst_caps_replace(&self->probed_sinkcaps, NULL);
297
298 return FALSE;
299}
300
301static gboolean
302gst_aml_v4l2_video_dec_close(GstVideoDecoder *decoder)
303{
304 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
305
306 GST_DEBUG_OBJECT(self, "Closing");
307
308 gst_aml_v4l2_object_close(self->v4l2output);
309 gst_aml_v4l2_object_close(self->v4l2capture);
310 gst_caps_replace(&self->probed_srccaps, NULL);
311 gst_caps_replace(&self->probed_sinkcaps, NULL);
312
313 return TRUE;
314}
315
316static gboolean
317gst_aml_v4l2_video_dec_start(GstVideoDecoder *decoder)
318{
319 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
320
321 GST_DEBUG_OBJECT(self, "Starting");
322
323 gst_aml_v4l2_object_unlock(self->v4l2output);
324 g_atomic_int_set(&self->active, TRUE);
325 self->output_flow = GST_FLOW_OK;
326
327 return TRUE;
328}
329
330static gboolean
331gst_aml_v4l2_video_dec_stop(GstVideoDecoder *decoder)
332{
333 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
334
335 GST_DEBUG_OBJECT(self, "Stopping");
336
337 gst_aml_v4l2_object_unlock(self->v4l2output);
338 gst_aml_v4l2_object_unlock(self->v4l2capture);
339
340 /* Wait for capture thread to stop */
341 gst_pad_stop_task(decoder->srcpad);
342
343 GST_VIDEO_DECODER_STREAM_LOCK(decoder);
344 self->output_flow = GST_FLOW_OK;
345 GST_VIDEO_DECODER_STREAM_UNLOCK(decoder);
346
347 /* Should have been flushed already */
348 g_assert(g_atomic_int_get(&self->active) == FALSE);
349
350 gst_aml_v4l2_object_stop(self->v4l2output);
351 gst_aml_v4l2_object_stop(self->v4l2capture);
352
353 if (self->input_state)
354 {
355 gst_video_codec_state_unref(self->input_state);
356 self->input_state = NULL;
357 }
358
359 GST_DEBUG_OBJECT(self, "Stopped");
360
361 return TRUE;
362}
363
364static gboolean
hanghang.luo8e1225b2023-10-10 08:54:28 +0000365gst_aml_v4l2_video_dec_codec_chg(GstVideoDecoder *decoder,
366 GstVideoCodecState *state)
367{
368 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
369 GstStructure *s_old = NULL;
370 GstStructure *s_new = NULL;
371
372 // first play, must set foramt;
373 if (!self->input_state)
374 return TRUE;
375
376 if (self->input_state->caps)
377 s_old = gst_caps_get_structure(self->input_state->caps,0);
378 if (state->caps)
379 s_new = gst_caps_get_structure(state->caps,0);
380
381 if (s_new && s_old && strcmp(gst_structure_get_name(s_new),gst_structure_get_name(s_old)))
382 return TRUE;
383 return FALSE;
384}
385
386static gboolean
387gst_aml_v4l2_video_dec_res_chg(GstVideoDecoder *decoder,
388 GstVideoCodecState *state)
389{
390 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
391 gboolean ret = FALSE;
392 gint width_new = -1,height_new = -1,width_old = -1,height_old = -1;
393 GstStructure *s_old = NULL;
394 GstStructure *s_new = NULL;
395
396 // first play, must set foramt;
397 if (!self->input_state)
398 {
399 ret = TRUE;
400 goto done;
401 }
402
403 if (self->input_state->caps)
404 s_old = gst_caps_get_structure(self->input_state->caps,0);
405 if (state->caps)
406 s_new = gst_caps_get_structure(state->caps,0);
407
408 if (s_new && gst_structure_has_field(s_new,"width") && gst_structure_has_field(s_new,"height"))
409 {
410 gst_structure_get_int(s_new,"width",&width_new);
411 gst_structure_get_int(s_new,"height",&height_new);
412 }
413 if (s_old && gst_structure_has_field(s_old,"width") && gst_structure_has_field(s_old,"height"))
414 {
415 gst_structure_get_int(s_old,"width",&width_old);
416 gst_structure_get_int(s_old,"height",&height_old);
417 }
418
419 if (width_new != width_old || height_new != height_old)
420 ret = TRUE;
421
422done:
423 GST_DEBUG_OBJECT(self, "ret is %d",ret);
424 return ret;
425}
426
427static gboolean
xuesong.jiangae1548e2022-05-06 16:38:46 +0800428gst_aml_v4l2_video_dec_set_format(GstVideoDecoder *decoder,
429 GstVideoCodecState *state)
430{
431 GstAmlV4l2Error error = GST_AML_V4L2_ERROR_INIT;
432 gboolean ret = TRUE;
433 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
434 GstCaps *caps;
435
436 GST_DEBUG_OBJECT(self, "Setting format: %" GST_PTR_FORMAT, state->caps);
hanghang.luo8e1225b2023-10-10 08:54:28 +0000437 if (self->input_state)
438 {
439 if (gst_aml_v4l2_video_dec_res_chg(decoder,state) || gst_aml_v4l2_video_dec_codec_chg(decoder,state))
440 GST_DEBUG_OBJECT(self, "resolution or codec changed");
441 else
442 goto done;
443 }
444
xuesong.jiangae1548e2022-05-06 16:38:46 +0800445 GstCapsFeatures *const features = gst_caps_get_features(state->caps, 0);
hanghang.luoc54208e2023-09-22 02:43:54 +0000446 GstStructure *s = gst_caps_get_structure(state->caps,0);
447 if (s && gst_structure_has_field(s,"format"))
448 {
449 if (!strcmp("XVID",gst_structure_get_string(s,"format")))
450 {
451 GST_DEBUG_OBJECT(self, "This is a DIVX file, cannot support");
452 ret = FALSE;
453 goto done;
454 }
455 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800456
457 if (gst_caps_features_contains(features, GST_CAPS_FEATURE_MEMORY_DMABUF))
458 self->v4l2output->req_mode = GST_V4L2_IO_DMABUF_IMPORT;
459
460 if (self->input_state)
461 {
462 if (gst_aml_v4l2_object_caps_equal(self->v4l2output, state->caps))
463 {
464 GST_DEBUG_OBJECT(self, "Compatible caps");
465 goto done;
466 }
467 gst_video_codec_state_unref(self->input_state);
468 self->input_state = NULL;
469
470 gst_aml_v4l2_video_dec_finish(decoder);
471 gst_aml_v4l2_object_stop(self->v4l2output);
472
473 /* The renegotiation flow don't blend with the base class flow. To properly
474 * stop the capture pool, if the buffers can't be orphaned, we need to
475 * reclaim our buffers, which will happend through the allocation query.
476 * The allocation query is triggered by gst_video_decoder_negotiate() which
477 * requires the output caps to be set, but we can't know this information
478 * as we rely on the decoder, which requires the capture queue to be
479 * stopped.
480 *
481 * To workaround this issue, we simply run an allocation query with the
482 * old negotiated caps in order to drain/reclaim our buffers. That breaks
483 * the complexity and should not have much impact in performance since the
484 * following allocation query will happen on a drained pipeline and won't
485 * block. */
486 if (self->v4l2capture->pool &&
487 !gst_aml_v4l2_buffer_pool_orphan(&self->v4l2capture->pool))
488 {
489 GstCaps *caps = gst_pad_get_current_caps(decoder->srcpad);
490 if (caps)
491 {
492 GstQuery *query = gst_query_new_allocation(caps, FALSE);
493 gst_pad_peer_query(decoder->srcpad, query);
494 gst_query_unref(query);
495 gst_caps_unref(caps);
496 }
497 }
498
499 gst_aml_v4l2_object_stop(self->v4l2capture);
500 self->output_flow = GST_FLOW_OK;
501 }
502
503 if ((ret = gst_aml_v4l2_set_drm_mode(self->v4l2output)) == FALSE)
504 {
505 GST_ERROR_OBJECT(self, "config output drm mode error");
506 goto done;
507 }
508
xuesong.jiang22a9b112023-05-24 09:01:59 +0000509 if ((ret = gst_aml_v4l2_set_stream_mode(self->v4l2output)) == FALSE)
510 {
511 GST_ERROR_OBJECT(self, "config output stream mode error");
512 goto done;
513 }
514
xuesong.jiangae1548e2022-05-06 16:38:46 +0800515 ret = gst_aml_v4l2_object_set_format(self->v4l2output, state->caps, &error);
516
517 gst_caps_replace(&self->probed_srccaps, NULL);
518 self->probed_srccaps = gst_aml_v4l2_object_probe_caps(self->v4l2capture,
519 gst_aml_v4l2_object_get_raw_caps());
520
521 if (gst_caps_is_empty(self->probed_srccaps))
522 goto no_raw_format;
523
524 caps = gst_caps_copy(self->probed_srccaps);
525 gst_caps_set_features_simple(caps, gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_DMABUF));
526 gst_caps_append(self->probed_srccaps, caps);
527 if (ret)
528 self->input_state = gst_video_codec_state_ref(state);
529 else
530 gst_aml_v4l2_error(self, &error);
531
532done:
533 return ret;
534
535no_raw_format:
536 GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
537 (_("Decoder on device %s has no supported output format"),
538 self->v4l2output->videodev),
539 (NULL));
540 return GST_FLOW_ERROR;
541}
542
543static gboolean
544gst_aml_v4l2_video_dec_flush(GstVideoDecoder *decoder)
545{
546 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
547
548 GST_DEBUG_OBJECT(self, "Flushed");
549
550 /* Ensure the processing thread has stopped for the reverse playback
551 * discount case */
552 if (gst_pad_get_task_state(decoder->srcpad) == GST_TASK_STARTED)
553 {
554 GST_VIDEO_DECODER_STREAM_UNLOCK(decoder);
555
556 gst_aml_v4l2_object_unlock(self->v4l2output);
557 gst_aml_v4l2_object_unlock(self->v4l2capture);
558 gst_pad_stop_task(decoder->srcpad);
559 GST_VIDEO_DECODER_STREAM_LOCK(decoder);
560 }
561
562 self->output_flow = GST_FLOW_OK;
563
564 gst_aml_v4l2_object_unlock_stop(self->v4l2output);
565 gst_aml_v4l2_object_unlock_stop(self->v4l2capture);
566
567 if (self->v4l2output->pool)
568 gst_aml_v4l2_buffer_pool_flush(self->v4l2output->pool);
569
570 /* gst_aml_v4l2_buffer_pool_flush() calls streamon the capture pool and must be
571 * called after gst_aml_v4l2_object_unlock_stop() stopped flushing the buffer
572 * pool. */
573 if (self->v4l2capture->pool)
574 gst_aml_v4l2_buffer_pool_flush(self->v4l2capture->pool);
575
576 return TRUE;
577}
578
579static gboolean
580gst_aml_v4l2_video_dec_negotiate(GstVideoDecoder *decoder)
581{
582 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
583
xuesong.jiang681d3602022-06-24 21:23:35 +0800584 if (TRUE == self->v4l2output->is_svp)
585 {
586 GstStructure *s;
587 GstEvent *event;
588
589 s = gst_structure_new_empty ("IS_SVP");
590 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_STICKY, s);
591 GST_DEBUG_OBJECT(self, "before Send SVP Event :%p", event);
592 gst_pad_push_event (decoder->srcpad, event);
593 GST_DEBUG_OBJECT(self, "after Send SVP Event :%p", event);
594 }
595
xuesong.jiangae1548e2022-05-06 16:38:46 +0800596 /* We don't allow renegotiation without carefull disabling the pool */
597 if (self->v4l2capture->pool &&
598 gst_buffer_pool_is_active(GST_BUFFER_POOL(self->v4l2capture->pool)))
599 return TRUE;
600
601 return GST_VIDEO_DECODER_CLASS(parent_class)->negotiate(decoder);
602}
603
604static gboolean
605gst_aml_v4l2_decoder_cmd(GstAmlV4l2Object *v4l2object, guint cmd, guint flags)
606{
607 struct v4l2_decoder_cmd dcmd = {
608 0,
609 };
610
611 GST_DEBUG_OBJECT(v4l2object->element,
612 "sending v4l2 decoder command %u with flags %u", cmd, flags);
613
614 if (!GST_AML_V4L2_IS_OPEN(v4l2object))
615 return FALSE;
616
617 dcmd.cmd = cmd;
618 dcmd.flags = flags;
619 if (v4l2object->ioctl(v4l2object->video_fd, VIDIOC_DECODER_CMD, &dcmd) < 0)
620 goto dcmd_failed;
621
622 return TRUE;
623
624dcmd_failed:
625 if (errno == ENOTTY)
626 {
627 GST_INFO_OBJECT(v4l2object->element,
628 "Failed to send decoder command %u with flags %u for '%s'. (%s)",
629 cmd, flags, v4l2object->videodev, g_strerror(errno));
630 }
631 else
632 {
633 GST_ERROR_OBJECT(v4l2object->element,
634 "Failed to send decoder command %u with flags %u for '%s'. (%s)",
635 cmd, flags, v4l2object->videodev, g_strerror(errno));
636 }
637 return FALSE;
638}
639
640static GstFlowReturn
641gst_aml_v4l2_video_dec_finish(GstVideoDecoder *decoder)
642{
643 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
644 GstFlowReturn ret = GST_FLOW_OK;
645 GstBuffer *buffer;
646
647 if (gst_pad_get_task_state(decoder->srcpad) != GST_TASK_STARTED)
648 goto done;
649
650 GST_DEBUG_OBJECT(self, "Finishing decoding");
651
652 GST_VIDEO_DECODER_STREAM_UNLOCK(decoder);
653
654 if (gst_aml_v4l2_decoder_cmd(self->v4l2output, V4L2_DEC_CMD_STOP, 0))
655 {
656 GstTask *task = decoder->srcpad->task;
657
658 /* If the decoder stop command succeeded, just wait until processing is
659 * finished */
660 GST_DEBUG_OBJECT(self, "Waiting for decoder stop");
661 GST_OBJECT_LOCK(task);
662 while (GST_TASK_STATE(task) == GST_TASK_STARTED)
663 GST_TASK_WAIT(task);
664 GST_OBJECT_UNLOCK(task);
665 ret = GST_FLOW_FLUSHING;
666 }
667 else
668 {
669 /* otherwise keep queuing empty buffers until the processing thread has
670 * stopped, _pool_process() will return FLUSHING when that happened */
671 while (ret == GST_FLOW_OK)
672 {
xuesong.jiangc5dac0f2023-02-01 14:42:24 +0800673 GST_DEBUG_OBJECT(self, "queue empty output buf");
xuesong.jiangae1548e2022-05-06 16:38:46 +0800674 buffer = gst_buffer_new();
675 ret =
676 gst_aml_v4l2_buffer_pool_process(GST_AML_V4L2_BUFFER_POOL(self->v4l2output->pool), &buffer);
677 gst_buffer_unref(buffer);
678 }
679 }
680
681 /* and ensure the processing thread has stopped in case another error
682 * occured. */
683 gst_aml_v4l2_object_unlock(self->v4l2capture);
684 gst_pad_stop_task(decoder->srcpad);
685 GST_VIDEO_DECODER_STREAM_LOCK(decoder);
686
687 if (ret == GST_FLOW_FLUSHING)
688 ret = self->output_flow;
689
690 GST_DEBUG_OBJECT(decoder, "Done draining buffers");
691
692 /* TODO Shall we cleanup any reffed frame to workaround broken decoders ? */
693
694done:
695 return ret;
696}
697
698static GstFlowReturn
699gst_aml_v4l2_video_dec_drain(GstVideoDecoder *decoder)
700{
701 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
702
703 GST_DEBUG_OBJECT(self, "Draining...");
704 gst_aml_v4l2_video_dec_finish(decoder);
705 gst_aml_v4l2_video_dec_flush(decoder);
706
707 return GST_FLOW_OK;
708}
709
710static GstVideoCodecFrame *
711gst_aml_v4l2_video_dec_get_oldest_frame(GstVideoDecoder *decoder)
712{
713 GstVideoCodecFrame *frame = NULL;
714 GList *frames, *l;
715 gint count = 0;
716
717 frames = gst_video_decoder_get_frames(decoder);
718
719 for (l = frames; l != NULL; l = l->next)
720 {
721 GstVideoCodecFrame *f = l->data;
722
723 if (!frame || (GST_CLOCK_TIME_IS_VALID(frame->pts) && GST_CLOCK_TIME_IS_VALID(f->pts) && (frame->pts > f->pts)))
724 frame = f;
725
726 count++;
727 }
728
729 if (frame)
730 {
731 GST_LOG_OBJECT(decoder,
732 "Oldest frame is %d %" GST_TIME_FORMAT " and %d frames left",
733 frame->system_frame_number, GST_TIME_ARGS(frame->pts), count - 1);
734 gst_video_codec_frame_ref(frame);
735 }
736
737 g_list_free_full(frames, (GDestroyNotify)gst_video_codec_frame_unref);
738
739 return frame;
740}
741
fei.dengbee20862022-06-14 14:59:48 +0800742static GstVideoCodecFrame *
xuesong.jiange24aef92023-06-16 06:39:10 +0000743gst_aml_v4l2_video_dec_get_right_frame_for_frame_mode(GstVideoDecoder *decoder, GstClockTime pts)
fei.dengbee20862022-06-14 14:59:48 +0800744{
745 GstVideoCodecFrame *frame = NULL;
746 GList *frames, *l;
747 gint count = 0;
748
xuesong.jiange24aef92023-06-16 06:39:10 +0000749 GST_LOG_OBJECT (decoder, "trace in with pts: %" GST_TIME_FORMAT, GST_TIME_ARGS(pts));
750
fei.dengbee20862022-06-14 14:59:48 +0800751 frames = gst_video_decoder_get_frames(decoder);
752
753 for (l = frames; l != NULL; l = l->next)
754 {
755 GstVideoCodecFrame *f = l->data;
fei.denge9458472023-04-18 02:05:48 +0000756
xuesong.jiangc5dac0f2023-02-01 14:42:24 +0800757 if (GST_CLOCK_TIME_IS_VALID(pts) && (ABSDIFF(f->pts,pts)) < 1000) {
fei.dengbee20862022-06-14 14:59:48 +0800758 frame = f;
fei.dengbee20862022-06-14 14:59:48 +0800759 }
fei.dengbee20862022-06-14 14:59:48 +0800760 count++;
761 }
762
zengliang.liddee2da2023-07-14 07:27:05 +0000763 if (!frame)
764 {
765 for (l = frames; l != NULL; l = l->next)
766 {
767 GstVideoCodecFrame *f = l->data;
768 if (!GST_CLOCK_TIME_IS_VALID(f->pts))
769 {
770 frame = f;
771 }
772 GST_DEBUG("The pts of the expected output frame is invalid");
773 }
774 }
775
fei.dengbee20862022-06-14 14:59:48 +0800776 if (frame)
777 {
778 GST_LOG_OBJECT(decoder,
779 "frame is %d %" GST_TIME_FORMAT " and %d frames left",
780 frame->system_frame_number, GST_TIME_ARGS(frame->pts), count - 1);
781 gst_video_codec_frame_ref(frame);
782 }
783
784 g_list_free_full(frames, (GDestroyNotify)gst_video_codec_frame_unref);
785
xuesong.jiange24aef92023-06-16 06:39:10 +0000786 GST_LOG_OBJECT (decoder, "trace out ret:%p", frame);
fei.dengbee20862022-06-14 14:59:48 +0800787 return frame;
788}
789
xuesong.jiange24aef92023-06-16 06:39:10 +0000790static GstVideoCodecFrame *
791gst_aml_v4l2_video_dec_get_right_frame_for_stream_mode(GstVideoDecoder *decoder, GstClockTime pts)
792{
793 GstVideoCodecFrame *frame = NULL;
794 GList *frames, *l;
795 gint count = 0;
796
797 GST_LOG_OBJECT (decoder, "trace in with pts: %" GST_TIME_FORMAT, GST_TIME_ARGS(pts));
798
799 frames = gst_video_decoder_get_frames(decoder);
800 guint frames_len = 0;
801 frames_len = g_list_length(frames);
802 GST_LOG_OBJECT (decoder, "got frames list len:%d", frames_len);
803
804 frame = frames->data;
805
806 for (l = frames; l != NULL; l = l->next)
807 {
808 GstVideoCodecFrame *f = l->data;
809
810 if (GST_CLOCK_TIME_IS_VALID(pts) && (ABSDIFF(f->pts, pts)) < 1000)
811 {
812 /* found the right frame */
813 frame = f;
814 break;
815 }
816 else if(GST_CLOCK_TIME_IS_VALID(pts) && (f->pts < pts))
817 {
818 GST_LOG_OBJECT(decoder,
819 "stream mode drop frame %d %" GST_TIME_FORMAT,
820 frame->system_frame_number, GST_TIME_ARGS(frame->pts));
821
822 gst_video_codec_frame_ref(f);
823 // gst_video_decoder_drop_frame(decoder, f);
824 gst_video_decoder_release_frame(decoder, f);
825 }
826 else
827 {
828 GST_LOG_OBJECT (decoder, "dbg");
829 }
830 }
831
832 if (frame)
833 {
834 guint l_len = 0;
835 l = gst_video_decoder_get_frames(decoder);
836 l_len = g_list_length(l);
837 g_list_free_full(l, (GDestroyNotify)gst_video_codec_frame_unref);
838
839 GST_LOG_OBJECT(decoder,
840 "frame is %d %" GST_TIME_FORMAT " and %d frames left",
841 frame->system_frame_number, GST_TIME_ARGS(frame->pts), l_len);
842 gst_video_codec_frame_ref(frame);
843 }
844
845 g_list_free_full(frames, (GDestroyNotify)gst_video_codec_frame_unref);
846
847 GST_LOG_OBJECT (decoder, "trace out ret:%p", frame);
848 return frame;
849}
850
851static GstVideoCodecFrame *
852gst_aml_v4l2_video_dec_get_right_frame(GstVideoDecoder *decoder, GstClockTime pts)
853{
854 GstAmlV4l2VideoDec *self = (GstAmlV4l2VideoDec *)decoder;
855 if (self->v4l2output->stream_mode)
856 return gst_aml_v4l2_video_dec_get_right_frame_for_stream_mode(decoder, pts);
857 else
858 return gst_aml_v4l2_video_dec_get_right_frame_for_frame_mode(decoder, pts);
859}
860
xuesong.jiangae1548e2022-05-06 16:38:46 +0800861static gboolean
862gst_aml_v4l2_video_remove_padding(GstCapsFeatures *features,
863 GstStructure *structure, gpointer user_data)
864{
865 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(user_data);
866 GstVideoAlignment *align = &self->v4l2capture->align;
867 GstVideoInfo *info = &self->v4l2capture->info;
868 int width, height;
869
870 if (!gst_structure_get_int(structure, "width", &width))
871 return TRUE;
872
873 if (!gst_structure_get_int(structure, "height", &height))
874 return TRUE;
875
876 if (align->padding_left != 0 || align->padding_top != 0 ||
877 height != info->height + align->padding_bottom)
878 return TRUE;
879
880 if (height == info->height + align->padding_bottom)
881 {
882 /* Some drivers may round up width to the padded with */
883 if (width == info->width + align->padding_right)
884 gst_structure_set(structure,
885 "width", G_TYPE_INT, width - align->padding_right,
886 "height", G_TYPE_INT, height - align->padding_bottom, NULL);
887 /* Some drivers may keep visible width and only round up bytesperline */
888 else if (width == info->width)
889 gst_structure_set(structure,
890 "height", G_TYPE_INT, height - align->padding_bottom, NULL);
891 }
892
893 return TRUE;
894}
895
896static void
sheng.liubcf036c2022-06-21 15:55:42 +0800897gst_v4l2_drop_event (GstAmlV4l2Object * v4l2object)
sheng.liub56bbc52022-06-21 11:02:33 +0800898{
899 struct v4l2_event evt;
900 gint ret;
901
902 memset (&evt, 0x00, sizeof (struct v4l2_event));
903 ret = v4l2object->ioctl (v4l2object->video_fd, VIDIOC_DQEVENT, &evt);
904 if (ret < 0)
905 {
906 GST_DEBUG_OBJECT (v4l2object, "dqevent failed");
907 return;
908 }
909
910 switch (evt.type)
911 {
912 case V4L2_EVENT_SOURCE_CHANGE:
913 GST_DEBUG_OBJECT (v4l2object, "Drop GST_V4L2_FLOW_SOURCE_CHANGE");
914 break;
915 case V4L2_EVENT_EOS:
916 GST_DEBUG_OBJECT (v4l2object, "Drop GST_V4L2_FLOW_LAST_BUFFER");
917 break;
918 default:
919 break;
920 }
921
922 return;
923}
924
925static void
hanghang.luo2eec4892023-07-18 06:44:42 +0000926gst_aml_v4l2_video_dec_set_output_status(GstVideoDecoder *decoder,GstVideoInfo info)
927{
928 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
929 GstVideoCodecState *output_state;
hanghang.luo9b60a3c2023-08-01 16:01:47 +0000930 struct v4l2_selection sel;
931 struct v4l2_rect *r = NULL;
932 GstStructure *s;
933 gint width = 0;
934 gint height = 0;
hanghang.luo2eec4892023-07-18 06:44:42 +0000935 output_state = gst_video_decoder_set_output_state(decoder,
936 info.finfo->format, info.width, info.height, self->input_state);
hanghang.luo9b60a3c2023-08-01 16:01:47 +0000937 memset(&sel, 0, sizeof(struct v4l2_selection));
938 sel.type = self->v4l2capture->type;
939 sel.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
940 if (self->v4l2capture->ioctl(self->v4l2capture->video_fd, VIDIOC_G_SELECTION, &sel) >= 0)
941 {
942 r = &sel.r;
943 width = (r->width/2)*2;
944 height = (r->height/2)*2;
945 GST_DEBUG_OBJECT(self, "w:%d h:%d ",width,height);
946 }
947 else
948 GST_DEBUG_OBJECT(self, "iotcl error");
hanghang.luo2eec4892023-07-18 06:44:42 +0000949 if (output_state)
950 {
951 output_state->info.interlace_mode = info.interlace_mode;
952 output_state->allocation_caps =gst_video_info_to_caps(&info);
hanghang.luo2eec4892023-07-18 06:44:42 +0000953 output_state->caps =gst_video_info_to_caps(&info);
hanghang.luo9b60a3c2023-08-01 16:01:47 +0000954 s = gst_caps_get_structure(output_state->caps, 0);
955 if (s)
956 {
957 gst_structure_set(s,"coded_width",G_TYPE_INT,info.width,NULL);
958 gst_structure_set(s,"coded_height",G_TYPE_INT,info.height,NULL);
959 gst_structure_set(s,"width",G_TYPE_INT,width,NULL);
960 gst_structure_set(s,"height",G_TYPE_INT,height,NULL);
961 GST_DEBUG_OBJECT(self, "output_state->caps: %" GST_PTR_FORMAT, output_state->caps);
962 gst_video_codec_state_unref(output_state);
963 }
hanghang.luo2eec4892023-07-18 06:44:42 +0000964 }
965}
966
zengliang.lidcd41462024-06-19 16:05:12 +0800967static GQuark
968gst_aml_v4l2_buffer_pool_cc_import_quark (void)
969{
970 static GQuark quark = 0;
971
972 if (quark == 0)
973 quark = g_quark_from_string ("GstAmlV4l2BufferPoolCcUsePtrData");
974
975 return quark;
976}
977
978static gboolean
979foreach_cc_buffer_list_match_pts_func(GList *list , GstVideoCodecFrame *frame)
980{
981 GList *l;
982 if (g_list_length (list) > 0)
983 {
984 for (l = list; l != NULL; l = l->next)
985 {
986 GstBuffer *cc_buffer = l->data;
987 if (GST_BUFFER_TIMESTAMP (frame->output_buffer) == GST_BUFFER_TIMESTAMP (cc_buffer))
988 {
989 gst_mini_object_set_qdata (GST_MINI_OBJECT (frame->output_buffer), GST_AML_V4L2_CC_IMPORT_QUARK,
990 gst_buffer_ref(cc_buffer), (GDestroyNotify) gst_buffer_unref);
991 #if 0
992 //Debug code:dump cc data
993 GstMapInfo gst_map;
994 gst_buffer_map(cc_buffer,&gst_map,GST_MAP_READ);
995 int fd=open("/data/test/cc1.data",O_RDWR |O_CREAT|O_APPEND,0777);
996 if (gst_map.size>0)
997 write(fd,gst_map.data,gst_map.size);
998 close(fd);
999 gst_buffer_unmap(cc_buffer,&gst_map);
1000 #endif
1001 GST_DEBUG("match success");
1002 return TRUE;
1003 }
1004 else
1005 {
1006 GST_DEBUG("match fail");
1007 }
1008 }
1009 GST_WARNING("no match frame in the bufferlist");
1010 }
1011 else
1012 {
1013 GST_WARNING("list is null,can not foreach");
1014 }
1015 return FALSE;
1016}
1017
hanghang.luo2eec4892023-07-18 06:44:42 +00001018static void
xuesong.jiangae1548e2022-05-06 16:38:46 +08001019gst_aml_v4l2_video_dec_loop(GstVideoDecoder *decoder)
1020{
1021 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
1022 GstAmlV4l2BufferPool *v4l2_pool;
1023 GstAmlV4l2Error error = GST_AML_V4L2_ERROR_INIT;
1024 GstBufferPool *pool;
1025 GstVideoCodecFrame *frame;
1026 GstBuffer *buffer = NULL;
1027 GstFlowReturn ret;
1028
1029 if (G_UNLIKELY(!GST_AML_V4L2_IS_ACTIVE(self->v4l2capture)))
1030 {
1031 GstVideoInfo info;
xuesong.jiang282ca572023-05-05 09:03:32 +00001032 GstCaps *acquired_caps, *available_caps, *caps, *filter;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001033 GstStructure *st;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001034 GST_DEBUG_OBJECT(self, "waitting source change event");
1035 /* Wait until received SOURCE_CHANGE event to get right video format */
1036 while (self->v4l2capture->can_wait_event && self->v4l2capture->need_wait_event)
1037 {
1038 ret = gst_aml_v4l2_object_dqevent(self->v4l2capture);
1039 if (ret == GST_AML_V4L2_FLOW_SOURCE_CHANGE)
1040 {
fei.deng2a06e042023-10-10 03:09:45 +00001041 //let flush start event blocked until capture buffer pool actived
1042 self->is_res_chg = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001043 GST_DEBUG_OBJECT(self, "Received source change event");
1044 break;
1045 }
1046 else if (ret == GST_AML_V4L2_FLOW_LAST_BUFFER)
1047 {
1048 GST_DEBUG_OBJECT(self, "Received eos event");
1049 goto beach;
1050 }
1051 else if (ret != GST_FLOW_OK)
1052 {
1053 GST_ERROR_OBJECT(self, "dqevent error");
1054 goto beach;
1055 }
1056 }
1057 self->v4l2capture->need_wait_event = FALSE;
1058
sheng.liu0c77f6c2022-06-17 21:33:20 +08001059 if (TRUE == self->v4l2output->is_svp)
1060 {
1061 GstPad *peer;
1062 GstStructure *s;
1063 GstEvent *event;
1064
1065 peer = gst_pad_get_peer (decoder->srcpad);
1066 if (peer)
1067 {
hanghang.luo70f07ef2023-07-13 02:23:06 +00001068 s = gst_structure_new_empty ("IS_SVP");
1069 if (s)
1070 {
1071 event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
1072 gst_pad_send_event (peer, event);
1073 GST_DEBUG_OBJECT(self, "Send SVP Event");
1074 }
1075 gst_object_unref (peer);
sheng.liu0c77f6c2022-06-17 21:33:20 +08001076 }
1077 }
1078
sheng.liub56bbc52022-06-21 11:02:33 +08001079 if (self->v4l2capture->need_drop_event)
1080 {
1081 // drop V4L2_EVENT_SOURCE_CHANGE
1082 gst_v4l2_drop_event(self->v4l2capture);
1083 self->v4l2capture->need_drop_event = FALSE;
1084 }
1085
xuesong.jiangae1548e2022-05-06 16:38:46 +08001086 if (!gst_aml_v4l2_object_acquire_format(self->v4l2capture, &info))
1087 goto not_negotiated;
hanghang.luo8ec04e92023-10-09 08:14:24 +00001088
xuesong.jiangae1548e2022-05-06 16:38:46 +08001089 /* Create caps from the acquired format, remove the format field */
1090 acquired_caps = gst_video_info_to_caps(&info);
1091 GST_DEBUG_OBJECT(self, "Acquired caps: %" GST_PTR_FORMAT, acquired_caps);
1092 st = gst_caps_get_structure(acquired_caps, 0);
xuesong.jiang282ca572023-05-05 09:03:32 +00001093 gst_structure_remove_fields(st, "format", "colorimetry", "chroma-site", NULL);
1094
1095 /* Probe currently available pixel formats */
1096 available_caps = gst_caps_copy(self->probed_srccaps);
1097 GST_DEBUG_OBJECT(self, "Available caps: %" GST_PTR_FORMAT, available_caps);
1098
1099 /* Replace coded size with visible size, we want to negotiate visible size
1100 * with downstream, not coded size. */
1101 gst_caps_map_in_place(available_caps, gst_aml_v4l2_video_remove_padding, self);
1102
1103 filter = gst_caps_intersect_full(available_caps, acquired_caps, GST_CAPS_INTERSECT_FIRST);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001104 caps = gst_caps_copy(filter);
1105 gst_caps_set_features_simple(caps, gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_DMABUF));
1106 gst_caps_append(filter, caps);
1107
1108 GST_DEBUG_OBJECT(self, "Filtered caps: %" GST_PTR_FORMAT, filter);
1109 gst_caps_unref(acquired_caps);
xuesong.jiang282ca572023-05-05 09:03:32 +00001110 gst_caps_unref(available_caps);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001111 caps = gst_pad_peer_query_caps(decoder->srcpad, filter);
1112 gst_caps_unref(filter);
1113
1114 GST_DEBUG_OBJECT(self, "Possible decoded caps: %" GST_PTR_FORMAT, caps);
1115 if (gst_caps_is_empty(caps))
1116 {
1117 gst_caps_unref(caps);
1118 goto not_negotiated;
1119 }
1120
1121 /* Fixate pixel format */
1122 caps = gst_caps_fixate(caps);
1123
1124 GST_DEBUG_OBJECT(self, "Chosen decoded caps: %" GST_PTR_FORMAT, caps);
1125
1126 /* Try to set negotiated format, on success replace acquired format */
1127 if (gst_aml_v4l2_object_set_format(self->v4l2capture, caps, &error))
1128 gst_video_info_from_caps(&info, caps);
1129 else
1130 gst_aml_v4l2_clear_error(&error);
1131 gst_caps_unref(caps);
hanghang.luo2eec4892023-07-18 06:44:42 +00001132 gst_aml_v4l2_video_dec_set_output_status(decoder,info);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001133 if (!gst_video_decoder_negotiate(decoder))
1134 {
1135 if (GST_PAD_IS_FLUSHING(decoder->srcpad))
1136 goto flushing;
1137 else
1138 goto not_negotiated;
1139 }
1140
1141 /* Ensure our internal pool is activated */
1142 if (!gst_buffer_pool_set_active(GST_BUFFER_POOL(self->v4l2capture->pool),
1143 TRUE))
1144 goto activate_failed;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001145
1146 g_mutex_lock(&self->res_chg_lock);
1147 GST_LOG_OBJECT(decoder, "signal resolution changed");
1148 self->is_res_chg = FALSE;
1149 g_cond_signal(&self->res_chg_cond);
1150 g_mutex_unlock(&self->res_chg_lock);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001151 }
1152
1153 GST_LOG_OBJECT(decoder, "Allocate output buffer");
1154
1155 v4l2_pool = GST_AML_V4L2_BUFFER_POOL(self->v4l2capture->pool);
1156
1157 self->output_flow = GST_FLOW_OK;
1158 do
1159 {
1160 /* We cannot use the base class allotate helper since it taking the internal
1161 * stream lock. we know that the acquire may need to poll until more frames
1162 * comes in and holding this lock would prevent that.
1163 */
1164 pool = gst_video_decoder_get_buffer_pool(decoder);
1165
1166 /* Pool may be NULL if we started going to READY state */
1167 if (pool == NULL)
1168 {
fei.dengbee20862022-06-14 14:59:48 +08001169 GST_WARNING_OBJECT(decoder, "gst_video_decoder_get_buffer_pool goto beach");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001170 ret = GST_FLOW_FLUSHING;
1171 goto beach;
1172 }
1173
1174 ret = gst_buffer_pool_acquire_buffer(pool, &buffer, NULL);
zengliang.lidcd41462024-06-19 16:05:12 +08001175
fei.dengccc89632022-07-15 19:10:17 +08001176 //calculate a new pts for interlace stream
hanghang.luo8ec04e92023-10-09 08:14:24 +00001177 if (ret == GST_FLOW_OK && self->v4l2capture->info.interlace_mode == GST_VIDEO_INTERLACE_MODE_INTERLEAVED)
fei.dengccc89632022-07-15 19:10:17 +08001178 {
1179 //if buffer pts is valid, reduce 1/2 duration
1180 if (GST_BUFFER_DURATION_IS_VALID(buffer))
1181 {
1182 GST_BUFFER_DURATION(buffer) = GST_BUFFER_DURATION(buffer)/2;
1183 }
1184 GST_BUFFER_FLAG_UNSET(buffer, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1185 //reset pts
hanghang.luo6a5bdff2024-04-15 06:29:43 +00001186 if (GST_BUFFER_TIMESTAMP (buffer) == 0LL)
fei.dengccc89632022-07-15 19:10:17 +08001187 {
1188 double rate = ((double)self->input_state->info.fps_n/(double)self->input_state->info.fps_d)*2;
1189 GST_BUFFER_TIMESTAMP(buffer) = self->last_out_pts + 1000000000LL/rate;
1190 }
1191 }
1192
xuesong.jiangae1548e2022-05-06 16:38:46 +08001193 g_object_unref(pool);
1194
fei.deng9a5cd6e2023-06-30 12:09:18 +00001195 if (ret == GST_FLOW_OK && GST_BUFFER_FLAG_IS_SET(buffer,GST_AML_V4L2_BUFFER_FLAG_LAST_EMPTY)) {
fei.deng990965a2023-11-15 07:03:15 +00001196 GST_LOG_OBJECT(decoder, "Get GST_AML_V4L2_FLOW_LAST_BUFFER");
1197 self->v4l2capture->need_drop_event = TRUE;
1198 gst_aml_v4l2_buffer_pool_process(v4l2_pool, &buffer);
1199 if (self->is_res_chg) {
1200 //we must release last buffer
1201 gst_buffer_unref(buffer);
1202 //if resolution changed event received,we should set need_drop_event to false
1203 self->v4l2capture->need_drop_event = FALSE;
1204 gst_aml_v4l2_object_stop(self->v4l2capture);
1205 //unblock flush start event
1206 g_mutex_lock(&self->res_chg_lock);
1207 self->is_res_chg = FALSE;
1208 g_cond_signal(&self->res_chg_cond);
1209 g_mutex_unlock(&self->res_chg_lock);
1210 return;
1211 } else {
1212 goto beach;
1213 }
sheng.liub56bbc52022-06-21 11:02:33 +08001214 }
1215
zengliang.lidcd41462024-06-19 16:05:12 +08001216 if (ret == GST_AML_V4L2_FLOW_CC_DATA)
1217 {
1218 GST_DEBUG_OBJECT(decoder, "continue get cc data ");
1219 continue;
1220 }
1221
sheng.liu8d18ed22022-05-26 17:28:15 +08001222 if (ret == GST_AML_V4L2_FLOW_SOURCE_CHANGE)
1223 {
1224 GST_LOG_OBJECT(decoder, "Get GST_AML_V4L2_FLOW_SOURCE_CHANGE");
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001225
1226 g_mutex_lock (&self->res_chg_lock);
1227 self->is_res_chg = TRUE;
1228 g_mutex_unlock (&self->res_chg_lock);
sheng.liu8d18ed22022-05-26 17:28:15 +08001229 return;
1230 }
1231
fei.dengbee20862022-06-14 14:59:48 +08001232 if (ret != GST_FLOW_OK) {
1233 GST_WARNING_OBJECT(decoder, "gst_buffer_pool_acquire_buffer goto beach ret:%d",ret);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001234 goto beach;
fei.dengbee20862022-06-14 14:59:48 +08001235 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001236
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001237 GST_LOG_OBJECT(decoder, "Process output buffer (switching flow outstanding num:%d)", self->v4l2capture->outstanding_buf_num);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001238 ret = gst_aml_v4l2_buffer_pool_process(v4l2_pool, &buffer);
xuesong.jiang406ee302023-06-28 03:45:22 +00001239
1240 GST_DEBUG_OBJECT(decoder, "send pts:%lld - %" GST_TIME_FORMAT, GST_BUFFER_PTS(buffer), GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));
1241 g_signal_emit (self, g_signals[SIGNAL_DECODED_PTS], 0, GST_BUFFER_PTS(buffer));
1242
xuesong.jiangae1548e2022-05-06 16:38:46 +08001243 if (ret == GST_AML_V4L2_FLOW_SOURCE_CHANGE)
1244 {
1245 gst_aml_v4l2_object_stop(self->v4l2capture);
1246 return;
1247 }
1248
zengliang.lidcd41462024-06-19 16:05:12 +08001249 } while ((ret == GST_AML_V4L2_FLOW_CORRUPTED_BUFFER) || (ret == GST_AML_V4L2_FLOW_CC_DATA));
xuesong.jiangae1548e2022-05-06 16:38:46 +08001250
1251 if (ret != GST_FLOW_OK)
1252 goto beach;
1253
fei.dengbee20862022-06-14 14:59:48 +08001254 frame = gst_aml_v4l2_video_dec_get_right_frame(decoder, GST_BUFFER_TIMESTAMP (buffer));
xuesong.jiangae1548e2022-05-06 16:38:46 +08001255 if (frame)
1256 {
zengliang.li32cb11e2022-11-24 12:10:26 +08001257 if (!GST_CLOCK_TIME_IS_VALID(frame->pts))
1258 {
zengliang.li92ff6822023-06-06 07:12:52 +00001259 if (!GST_CLOCK_TIME_IS_VALID(self->last_out_pts))
1260 {
1261 if (GST_CLOCK_TIME_IS_VALID(frame->dts))
1262 {
1263 GST_BUFFER_TIMESTAMP(buffer) = frame->dts;
1264 }
1265 else
1266 {
1267 GST_WARNING_OBJECT (decoder,"sorry,we have no baseline to calculate pts");
1268 goto beach;
1269 }
1270 }
1271 else
1272 {
1273 double rate = ((double)self->input_state->info.fps_n/(double)self->input_state->info.fps_d);
1274 GST_BUFFER_TIMESTAMP(buffer) = self->last_out_pts + 1000000000LL/rate;
1275 }
zengliang.li32cb11e2022-11-24 12:10:26 +08001276 }
fei.dengccc89632022-07-15 19:10:17 +08001277 self->last_out_pts = GST_BUFFER_TIMESTAMP(buffer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001278 frame->output_buffer = buffer;
fei.dengccc89632022-07-15 19:10:17 +08001279 frame->pts = GST_BUFFER_TIMESTAMP(buffer);
1280 frame->duration = GST_BUFFER_DURATION(buffer);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001281 buffer = NULL;
zengliang.lidcd41462024-06-19 16:05:12 +08001282
1283 GST_DEBUG_OBJECT (decoder,"enable_cc_data:%d",self->v4l2capture->enable_cc_data);
1284 if (self->v4l2capture->enable_cc_data)
1285 {
1286 if (foreach_cc_buffer_list_match_pts_func(v4l2_pool->cc_buffer_list, frame))
1287 {
1288 GST_DEBUG("cc buffer and frame bind success");
1289 GstBuffer *cc_buffer = gst_mini_object_get_qdata (GST_MINI_OBJECT (frame->output_buffer),
1290 GST_AML_V4L2_CC_IMPORT_QUARK);
1291 #if 0
1292 //Debug code:dump cc data
1293 GstMapInfo gst_map;
1294 gst_buffer_map(cc_buffer,&gst_map,GST_MAP_READ);
1295 int fd=open("/data/test/cc2.data",O_RDWR |O_CREAT|O_APPEND,0777);
1296 if (gst_map.size>0)
1297 write(fd,gst_map.data,gst_map.size);
1298 close(fd);
1299 gst_buffer_unmap(cc_buffer,&gst_map);
1300 #endif
1301 v4l2_pool->cc_buffer_list = g_list_remove(v4l2_pool->cc_buffer_list,cc_buffer);
1302 gst_buffer_unref(cc_buffer);
1303 }
1304 else
1305 {
1306 GST_WARNING("bufferlist is empty or no match frame in the bufferlist");
1307 }
1308 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001309 ret = gst_video_decoder_finish_frame(decoder, frame);
1310
1311 if (ret != GST_FLOW_OK)
1312 goto beach;
1313 }
1314 else
1315 {
1316 GST_WARNING_OBJECT(decoder, "Decoder is producing too many buffers");
1317 gst_buffer_unref(buffer);
1318 }
1319
1320 return;
1321 /* ERRORS */
1322not_negotiated:
1323{
1324 GST_ERROR_OBJECT(self, "not negotiated");
1325 ret = GST_FLOW_NOT_NEGOTIATED;
1326 goto beach;
1327}
1328activate_failed:
1329{
1330 GST_ERROR_OBJECT(self, "Buffer pool activation failed");
1331 GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
1332 (_("Failed to allocate required memory.")),
1333 ("Buffer pool activation failed"));
1334 ret = GST_FLOW_ERROR;
1335 goto beach;
1336}
1337flushing:
1338{
1339 ret = GST_FLOW_FLUSHING;
1340 goto beach;
1341}
1342beach:
1343 GST_DEBUG_OBJECT(decoder, "Leaving output thread: %s",
1344 gst_flow_get_name(ret));
fei.deng2a06e042023-10-10 03:09:45 +00001345 if (self->is_res_chg) {
1346 //unblock flush start event
1347 g_mutex_lock(&self->res_chg_lock);
1348 self->is_res_chg = FALSE;
1349 g_cond_signal(&self->res_chg_cond);
1350 g_mutex_unlock(&self->res_chg_lock);
1351 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001352 gst_buffer_replace(&buffer, NULL);
1353 self->output_flow = ret;
1354 gst_aml_v4l2_object_unlock(self->v4l2output);
1355 gst_pad_pause_task(decoder->srcpad);
1356}
1357
1358static GstFlowReturn
1359gst_aml_v4l2_video_dec_handle_frame(GstVideoDecoder *decoder,
1360 GstVideoCodecFrame *frame)
1361{
1362 GstAmlV4l2Error error = GST_AML_V4L2_ERROR_INIT;
1363 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
1364 GstBufferPool *pool = GST_BUFFER_POOL(self->v4l2output->pool);
1365 GstFlowReturn ret = GST_FLOW_OK;
1366 gboolean processed = FALSE;
1367 GstBuffer *tmp;
1368 GstTaskState task_state;
1369 GstCaps *caps;
1370
1371 GST_DEBUG_OBJECT(self, "Handling frame %d", frame->system_frame_number);
1372
1373 if (G_UNLIKELY(!g_atomic_int_get(&self->active)))
1374 goto flushing;
1375
1376 if (G_UNLIKELY(!GST_AML_V4L2_IS_ACTIVE(self->v4l2output)))
1377 {
1378 if (!self->input_state)
1379 goto not_negotiated;
1380 if (!gst_aml_v4l2_object_set_format(self->v4l2output, self->input_state->caps,
1381 &error))
1382 goto not_negotiated;
1383 }
1384
1385 if (G_UNLIKELY(!GST_AML_V4L2_IS_ACTIVE(self->v4l2capture)))
1386 {
1387 GstBuffer *codec_data;
sheng.liu0c77f6c2022-06-17 21:33:20 +08001388 GstCapsFeatures *features = NULL;
1389
1390 features = gst_caps_get_features(self->input_state->caps, 0);
1391 if (features && gst_caps_features_contains(features, GST_CAPS_FEATURE_MEMORY_DMABUF))
1392 {
1393 GST_DEBUG_OBJECT(self, "Is SVP");
1394 self->v4l2output->is_svp = TRUE;
1395 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001396
1397 GST_DEBUG_OBJECT(self, "Sending header");
1398
1399 codec_data = self->input_state->codec_data;
1400
1401 /* We are running in byte-stream mode, so we don't know the headers, but
1402 * we need to send something, otherwise the decoder will refuse to
1403 * intialize.
1404 */
1405 if (codec_data)
1406 {
1407 gst_buffer_ref(codec_data);
1408 }
1409 else
1410 {
1411 codec_data = gst_buffer_ref(frame->input_buffer);
1412 processed = TRUE;
1413 }
1414
1415 /* Ensure input internal pool is active */
1416 if (!gst_buffer_pool_is_active(pool))
1417 {
1418 GstStructure *config = gst_buffer_pool_get_config(pool);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001419 // guint min = MAX(self->v4l2output->min_buffers, GST_AML_V4L2_MIN_BUFFERS);
1420 // guint max = VIDEO_MAX_FRAME;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001421 // gst_buffer_pool_config_set_params (config, self->input_state->caps,
1422 // self->v4l2output->info.size, min, max);
1423 gst_buffer_pool_config_set_params(config, self->input_state->caps, self->v4l2output->info.size, self->v4l2output->min_buffers, self->v4l2output->min_buffers);
1424
1425 /* There is no reason to refuse this config */
1426 if (!gst_buffer_pool_set_config(pool, config))
1427 goto activate_failed;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001428 GST_DEBUG_OBJECT(self, "setting output pool config to %" GST_PTR_FORMAT, config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001429
1430 if (!gst_buffer_pool_set_active(pool, TRUE))
1431 goto activate_failed;
1432 }
1433
1434 GST_VIDEO_DECODER_STREAM_UNLOCK(decoder);
1435 ret =
1436 gst_aml_v4l2_buffer_pool_process(GST_AML_V4L2_BUFFER_POOL(self->v4l2output->pool), &codec_data);
hanghang.luoc54208e2023-09-22 02:43:54 +00001437 self->codec_data_inject = TRUE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001438 GST_VIDEO_DECODER_STREAM_LOCK(decoder);
1439
1440 gst_buffer_unref(codec_data);
1441
1442 /* For decoders G_FMT returns coded size, G_SELECTION returns visible size
1443 * in the compose rectangle. gst_aml_v4l2_object_acquire_format() checks both
1444 * and returns the visible size as with/height and the coded size as
1445 * padding. */
1446 }
1447
1448 task_state = gst_pad_get_task_state(GST_VIDEO_DECODER_SRC_PAD(self));
1449 if (task_state == GST_TASK_STOPPED || task_state == GST_TASK_PAUSED)
1450 {
1451 /* It's possible that the processing thread stopped due to an error */
1452 if (self->output_flow != GST_FLOW_OK &&
1453 self->output_flow != GST_FLOW_FLUSHING)
1454 {
1455 GST_DEBUG_OBJECT(self, "Processing loop stopped with error, leaving");
1456 ret = self->output_flow;
1457 goto drop;
1458 }
1459
1460 GST_DEBUG_OBJECT(self, "Starting decoding thread");
1461
1462 /* Start the processing task, when it quits, the task will disable input
1463 * processing to unlock input if draining, or prevent potential block */
1464 self->output_flow = GST_FLOW_FLUSHING;
1465 if (!gst_pad_start_task(decoder->srcpad,
1466 (GstTaskFunction)gst_aml_v4l2_video_dec_loop, self, NULL))
1467 goto start_task_failed;
1468 }
1469
1470 if (!processed)
1471 {
1472 GST_VIDEO_DECODER_STREAM_UNLOCK(decoder);
hanghang.luoc54208e2023-09-22 02:43:54 +00001473 if (!self->codec_data_inject && self->input_state->codec_data)
1474 {
1475 ret = gst_aml_v4l2_buffer_pool_process
1476 (GST_AML_V4L2_BUFFER_POOL(self->v4l2output->pool), &self->input_state->codec_data);
1477 self->codec_data_inject = TRUE;
1478 if (ret != GST_FLOW_OK)
1479 goto send_codec_failed;
1480 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001481 ret =
1482 gst_aml_v4l2_buffer_pool_process(GST_AML_V4L2_BUFFER_POOL(self->v4l2output->pool), &frame->input_buffer);
1483 GST_VIDEO_DECODER_STREAM_LOCK(decoder);
1484
1485 if (ret == GST_FLOW_FLUSHING)
1486 {
1487 if (gst_pad_get_task_state(GST_VIDEO_DECODER_SRC_PAD(self)) !=
1488 GST_TASK_STARTED)
1489 ret = self->output_flow;
1490 goto drop;
1491 }
1492 else if (ret != GST_FLOW_OK)
1493 {
1494 goto process_failed;
1495 }
1496 }
1497
1498 /* No need to keep input arround */
1499 tmp = frame->input_buffer;
1500 frame->input_buffer = gst_buffer_new();
1501 gst_buffer_copy_into(frame->input_buffer, tmp,
1502 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
1503 GST_BUFFER_COPY_META,
1504 0, 0);
1505 gst_buffer_unref(tmp);
1506
1507 gst_video_codec_frame_unref(frame);
1508 return ret;
1509
1510 /* ERRORS */
hanghang.luoc54208e2023-09-22 02:43:54 +00001511send_codec_failed:
1512 GST_ERROR_OBJECT(self, "send codec_date fialed.ret is %d",ret);
1513 goto drop;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001514not_negotiated:
1515{
1516 GST_ERROR_OBJECT(self, "not negotiated");
1517 ret = GST_FLOW_NOT_NEGOTIATED;
1518 gst_aml_v4l2_error(self, &error);
1519 goto drop;
1520}
1521activate_failed:
1522{
1523 GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
1524 (_("Failed to allocate required memory.")),
1525 ("Buffer pool activation failed"));
1526 ret = GST_FLOW_ERROR;
1527 goto drop;
1528}
1529flushing:
1530{
1531 ret = GST_FLOW_FLUSHING;
1532 goto drop;
1533}
1534
1535start_task_failed:
1536{
1537 GST_ELEMENT_ERROR(self, RESOURCE, FAILED,
1538 (_("Failed to start decoding thread.")), (NULL));
1539 ret = GST_FLOW_ERROR;
1540 goto drop;
1541}
1542process_failed:
1543{
1544 GST_ELEMENT_ERROR(self, RESOURCE, FAILED,
1545 (_("Failed to process frame.")),
1546 ("Maybe be due to not enough memory or failing driver"));
1547 ret = GST_FLOW_ERROR;
1548 goto drop;
1549}
1550drop:
1551{
1552 gst_video_decoder_drop_frame(decoder, frame);
1553 return ret;
1554}
1555}
1556
1557static gboolean
1558gst_aml_v4l2_video_dec_decide_allocation(GstVideoDecoder *decoder,
1559 GstQuery *query)
1560{
1561 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
1562 GstClockTime latency;
1563 gboolean ret = FALSE;
1564
1565 if (gst_aml_v4l2_object_decide_allocation(self->v4l2capture, query))
1566 ret = GST_VIDEO_DECODER_CLASS(parent_class)->decide_allocation(decoder, query);
1567
1568 if (GST_CLOCK_TIME_IS_VALID(self->v4l2capture->duration))
1569 {
1570 latency = self->v4l2capture->min_buffers * self->v4l2capture->duration;
1571 GST_DEBUG_OBJECT(self, "Setting latency: %" GST_TIME_FORMAT " (%" G_GUINT32_FORMAT " * %" G_GUINT64_FORMAT, GST_TIME_ARGS(latency),
1572 self->v4l2capture->min_buffers, self->v4l2capture->duration);
1573 gst_video_decoder_set_latency(decoder, latency, latency);
1574 }
1575 else
1576 {
1577 GST_WARNING_OBJECT(self, "Duration invalid, not setting latency");
1578 }
1579
1580 return ret;
1581}
1582
1583static gboolean
1584gst_aml_v4l2_video_dec_src_query(GstVideoDecoder *decoder, GstQuery *query)
1585{
1586 gboolean ret = TRUE;
1587 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
1588
1589 switch (GST_QUERY_TYPE(query))
1590 {
1591 case GST_QUERY_CAPS:
1592 {
1593 GstCaps *filter, *result = NULL;
1594 GstPad *pad = GST_VIDEO_DECODER_SRC_PAD(decoder);
1595
1596 gst_query_parse_caps(query, &filter);
1597
1598 if (self->probed_srccaps)
1599 result = gst_caps_ref(self->probed_srccaps);
1600 else
1601 result = gst_pad_get_pad_template_caps(pad);
1602
1603 if (filter)
1604 {
1605 GstCaps *tmp = result;
1606 result =
1607 gst_caps_intersect_full(filter, tmp, GST_CAPS_INTERSECT_FIRST);
1608 gst_caps_unref(tmp);
1609 }
1610
1611 GST_DEBUG_OBJECT(self, "Returning src caps %" GST_PTR_FORMAT, result);
1612
1613 gst_query_set_caps_result(query, result);
1614 gst_caps_unref(result);
1615 break;
1616 }
1617
1618 default:
1619 ret = GST_VIDEO_DECODER_CLASS(parent_class)->src_query(decoder, query);
1620 break;
1621 }
1622
1623 return ret;
1624}
1625
1626static GstCaps *
1627gst_aml_v4l2_video_dec_sink_getcaps(GstVideoDecoder *decoder, GstCaps *filter)
1628{
1629 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
1630 GstCaps *result;
1631
1632 result = gst_video_decoder_proxy_getcaps(decoder, self->probed_sinkcaps,
1633 filter);
1634
1635 GST_DEBUG_OBJECT(self, "Returning sink caps %" GST_PTR_FORMAT, result);
1636
1637 return result;
1638}
1639
1640static gboolean
1641gst_aml_v4l2_video_dec_sink_event(GstVideoDecoder *decoder, GstEvent *event)
1642{
1643 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(decoder);
1644 gboolean ret;
1645 GstEventType type = GST_EVENT_TYPE(event);
1646
1647 switch (type)
1648 {
xuesong.jiang406ee302023-06-28 03:45:22 +00001649 case GST_EVENT_STREAM_START:
1650 {
1651 GstStructure *s;
1652 GstEvent *event;
1653 GST_DEBUG_OBJECT(self, "new private event");
1654 s = gst_structure_new("private_signal", "obj_ptr", G_TYPE_POINTER, self, "sig_name", G_TYPE_STRING, "decoded-pts", NULL);
1655 event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, s);
1656 GST_DEBUG_OBJECT(self, "before Send private_signal Event :%p", event);
1657 gst_pad_push_event (decoder->sinkpad, event);
1658 GST_DEBUG_OBJECT(self, "after Send private_signal Event :%p", event);
1659 break;
1660 }
zengliang.li51f54b62023-10-10 12:14:49 +00001661 case GST_EVENT_CAPS:
1662 {
1663 GstCaps *caps;
1664 GstStructure *structure;
sheng.liu641aa422023-12-26 07:05:59 +00001665 gint num, denom;
zengliang.li51f54b62023-10-10 12:14:49 +00001666
1667 gst_event_parse_caps (event, &caps);
1668 structure= gst_caps_get_structure(caps, 0);
1669 if ( gst_structure_has_field(structure, "parsed") )
1670 {
1671 gboolean parsed = TRUE;
1672 if ( gst_structure_get_boolean( structure, "parsed", &parsed ) )
1673 {
1674 self->v4l2output->stream_mode = !parsed;
1675 GST_DEBUG("frame parsed:%d, set stream_mode to %d", parsed, self->v4l2output->stream_mode);
1676 }
1677 }
sheng.liu641aa422023-12-26 07:05:59 +00001678
sheng.liudb26f7d2024-01-22 11:24:23 +00001679 if ( gst_structure_get_fraction( structure, "framerate", &num, &denom ) )
1680 {
1681 if ( denom == 0 ) denom= 1;
1682
1683 if (self->v4l2capture->fps)
1684 {
1685 g_value_unset(self->v4l2capture->fps);
1686 g_free(self->v4l2capture->fps);
1687 }
1688
1689 self->v4l2capture->fps = g_new0(GValue, 1);
1690 g_value_init(self->v4l2capture->fps, GST_TYPE_FRACTION);
1691 gst_value_set_fraction(self->v4l2capture->fps, num, denom);
1692
1693 GST_DEBUG_OBJECT(self, "get framerate ratio %d:%d", num, denom);
1694 }
1695
sheng.liu641aa422023-12-26 07:05:59 +00001696 if (( gst_structure_get_fraction( structure, "pixel-aspect-ratio", &num, &denom ) ) &&
1697 ( !self->v4l2capture->have_set_par ) )
1698 {
1699 if ( (num <= 0) || (denom <= 0) )
1700 {
1701 num= denom= 1;
1702 }
1703
1704 if ( self->v4l2capture->par )
1705 {
1706 g_value_unset(self->v4l2capture->par);
1707 g_free(self->v4l2capture->par);
1708 }
1709
1710 self->v4l2capture->par = g_new0(GValue, 1);
1711 g_value_init(self->v4l2capture->par, GST_TYPE_FRACTION);
1712 gst_value_set_fraction(self->v4l2capture->par, num, denom);
1713 GST_DEBUG_OBJECT(self, "get pixel aspect ratio %d:%d", num, denom);
1714 }
zengliang.li51f54b62023-10-10 12:14:49 +00001715 break;
1716 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001717 case GST_EVENT_FLUSH_START:
1718 GST_DEBUG_OBJECT(self, "flush start");
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001719
1720 g_mutex_lock (&self->res_chg_lock);
1721 while (self->is_res_chg)
1722 {
1723 GST_LOG_OBJECT(decoder, "wait resolution change finish");
1724 g_cond_wait(&self->res_chg_cond, &self->res_chg_lock);
1725 }
1726 g_mutex_unlock (&self->res_chg_lock);
1727
zengliang.li92ff6822023-06-06 07:12:52 +00001728 self->last_out_pts = GST_CLOCK_TIME_NONE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001729 gst_aml_v4l2_object_unlock(self->v4l2output);
1730 gst_aml_v4l2_object_unlock(self->v4l2capture);
1731 break;
1732 default:
1733 break;
1734 }
1735
1736 ret = GST_VIDEO_DECODER_CLASS(parent_class)->sink_event(decoder, event);
1737
1738 switch (type)
1739 {
1740 case GST_EVENT_FLUSH_START:
1741 /* The processing thread should stop now, wait for it */
1742 gst_pad_stop_task(decoder->srcpad);
hanghang.luoc54208e2023-09-22 02:43:54 +00001743 self->codec_data_inject = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001744 GST_DEBUG_OBJECT(self, "flush start done");
1745 break;
1746 default:
1747 break;
1748 }
1749
1750 return ret;
1751}
1752
1753static GstStateChangeReturn
1754gst_aml_v4l2_video_dec_change_state(GstElement *element,
1755 GstStateChange transition)
1756{
1757 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(element);
1758 GstVideoDecoder *decoder = GST_VIDEO_DECODER(element);
1759
1760 if (transition == GST_STATE_CHANGE_PAUSED_TO_READY)
1761 {
1762 g_atomic_int_set(&self->active, FALSE);
1763 gst_aml_v4l2_object_unlock(self->v4l2output);
1764 gst_aml_v4l2_object_unlock(self->v4l2capture);
1765 gst_pad_stop_task(decoder->srcpad);
1766 }
1767
1768 return GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
1769}
1770
1771static void
1772gst_aml_v4l2_video_dec_dispose(GObject *object)
1773{
1774 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(object);
1775
1776 gst_caps_replace(&self->probed_sinkcaps, NULL);
1777 gst_caps_replace(&self->probed_srccaps, NULL);
1778
1779 G_OBJECT_CLASS(parent_class)->dispose(object);
1780}
1781
1782static void
1783gst_aml_v4l2_video_dec_finalize(GObject *object)
1784{
1785 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(object);
1786
1787 gst_aml_v4l2_object_destroy(self->v4l2capture);
1788 gst_aml_v4l2_object_destroy(self->v4l2output);
1789
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001790 g_mutex_clear(&self->res_chg_lock);
1791 g_cond_clear(&self->res_chg_cond);
1792
xuesong.jiang61ea8012022-05-12 15:38:17 +08001793#if GST_IMPORT_LGE_PROP
1794 if (self->lge_ctxt)
1795 {
1796 if (self->lge_ctxt->app_type)
1797 g_free(self->lge_ctxt->app_type);
1798 if (self->lge_ctxt->res_info.coretype)
1799 g_free(self->lge_ctxt->res_info.coretype);
1800 free(self->lge_ctxt);
1801 }
1802
1803#endif
1804
xuesong.jiangae1548e2022-05-06 16:38:46 +08001805 G_OBJECT_CLASS(parent_class)->finalize(object);
1806}
1807
1808static void
1809gst_aml_v4l2_video_dec_init(GstAmlV4l2VideoDec *self)
1810{
1811 /* V4L2 object are created in subinstance_init */
zengliang.li92ff6822023-06-06 07:12:52 +00001812 self->last_out_pts = GST_CLOCK_TIME_NONE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001813 self->is_secure_path = FALSE;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001814 self->is_res_chg = FALSE;
hanghang.luoc54208e2023-09-22 02:43:54 +00001815 self->codec_data_inject = FALSE;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001816 g_mutex_init(&self->res_chg_lock);
1817 g_cond_init(&self->res_chg_cond);
xuesong.jiang61ea8012022-05-12 15:38:17 +08001818#if GST_IMPORT_LGE_PROP
1819 self->lge_ctxt = malloc(sizeof(GstAmlV4l2VideoDecLgeCtxt));
1820 memset(self->lge_ctxt, 0, sizeof(GstAmlV4l2VideoDecLgeCtxt));
1821#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08001822}
1823
1824static void
1825gst_aml_v4l2_video_dec_subinstance_init(GTypeInstance *instance, gpointer g_class)
1826{
1827 GstAmlV4l2VideoDecClass *klass = GST_AML_V4L2_VIDEO_DEC_CLASS(g_class);
1828 GstAmlV4l2VideoDec *self = GST_AML_V4L2_VIDEO_DEC(instance);
1829 GstVideoDecoder *decoder = GST_VIDEO_DECODER(instance);
1830
1831 gst_video_decoder_set_packetized(decoder, TRUE);
1832
1833 self->v4l2output = gst_aml_v4l2_object_new(GST_ELEMENT(self),
1834 GST_OBJECT(GST_VIDEO_DECODER_SINK_PAD(self)),
1835 V4L2_BUF_TYPE_VIDEO_OUTPUT, klass->default_device,
1836 gst_aml_v4l2_get_output, gst_aml_v4l2_set_output, NULL);
1837 self->v4l2output->no_initial_format = TRUE;
1838 self->v4l2output->keep_aspect = FALSE;
sheng.liu0c77f6c2022-06-17 21:33:20 +08001839 self->v4l2output->is_svp = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001840
1841 self->v4l2capture = gst_aml_v4l2_object_new(GST_ELEMENT(self),
1842 GST_OBJECT(GST_VIDEO_DECODER_SRC_PAD(self)),
1843 V4L2_BUF_TYPE_VIDEO_CAPTURE, klass->default_device,
1844 gst_aml_v4l2_get_input, gst_aml_v4l2_set_input, NULL);
1845 self->v4l2capture->need_wait_event = TRUE;
sheng.liub56bbc52022-06-21 11:02:33 +08001846 self->v4l2capture->need_drop_event = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001847}
1848
1849static void
1850gst_aml_v4l2_video_dec_class_init(GstAmlV4l2VideoDecClass *klass)
1851{
1852 GstElementClass *element_class;
1853 GObjectClass *gobject_class;
1854 GstVideoDecoderClass *video_decoder_class;
1855
1856 parent_class = g_type_class_peek_parent(klass);
1857
1858 element_class = (GstElementClass *)klass;
1859 gobject_class = (GObjectClass *)klass;
1860 video_decoder_class = (GstVideoDecoderClass *)klass;
1861
1862 GST_DEBUG_CATEGORY_INIT(gst_aml_v4l2_video_dec_debug, "amlv4l2videodec", 0,
1863 "AML V4L2 Video Decoder");
1864
1865 gobject_class->dispose = GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_dispose);
1866 gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_finalize);
1867 gobject_class->set_property =
1868 GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_set_property);
1869 gobject_class->get_property =
1870 GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_get_property);
1871
1872 video_decoder_class->open = GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_open);
1873 video_decoder_class->close = GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_close);
1874 video_decoder_class->start = GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_start);
1875 video_decoder_class->stop = GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_stop);
1876 video_decoder_class->finish = GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_finish);
1877 video_decoder_class->flush = GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_flush);
1878 video_decoder_class->drain = GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_drain);
1879 video_decoder_class->set_format =
1880 GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_set_format);
1881 video_decoder_class->negotiate =
1882 GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_negotiate);
1883 video_decoder_class->decide_allocation =
1884 GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_decide_allocation);
1885 /* FIXME propose_allocation or not ? */
1886 video_decoder_class->handle_frame =
1887 GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_handle_frame);
1888 video_decoder_class->getcaps =
1889 GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_sink_getcaps);
1890 video_decoder_class->src_query =
1891 GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_src_query);
1892 video_decoder_class->sink_event =
1893 GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_sink_event);
1894
1895 element_class->change_state =
1896 GST_DEBUG_FUNCPTR(gst_aml_v4l2_video_dec_change_state);
1897
xuesong.jiang406ee302023-06-28 03:45:22 +00001898 g_signals[SIGNAL_DECODED_PTS] = g_signal_new ("decoded-pts",
1899 G_TYPE_FROM_CLASS(GST_ELEMENT_CLASS(klass)),
1900 G_SIGNAL_RUN_LAST,
1901 0, /* class offset */
1902 NULL, /* accumulator */
1903 NULL, /* accu data */
1904 g_cclosure_marshal_generic,
1905 G_TYPE_NONE,
1906 1,
1907 G_TYPE_UINT64);
1908
xuesong.jiangae1548e2022-05-06 16:38:46 +08001909 gst_aml_v4l2_object_install_m2m_properties_helper(gobject_class);
xuesong.jiang61ea8012022-05-12 15:38:17 +08001910#if GST_IMPORT_LGE_PROP
1911 gst_aml_v4l2_video_dec_install_lge_properties_helper(gobject_class);
1912#endif
xuesong.jiangae1548e2022-05-06 16:38:46 +08001913}
1914
1915static void
1916gst_aml_v4l2_video_dec_subclass_init(gpointer g_class, gpointer data)
1917{
1918 GstAmlV4l2VideoDecClass *klass = GST_AML_V4L2_VIDEO_DEC_CLASS(g_class);
1919 GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
1920 GstAmlV4l2VideoDecCData *cdata = data;
1921
1922 klass->default_device = cdata->device;
1923
1924 /* Note: gst_pad_template_new() take the floating ref from the caps */
1925 gst_element_class_add_pad_template(element_class,
1926 gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
1927 cdata->sink_caps));
1928 gst_element_class_add_pad_template(element_class,
1929 gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS,
1930 cdata->src_caps));
1931
1932 gst_element_class_set_metadata(element_class, cdata->longname,
1933 "Codec/Decoder/Video/Hardware", cdata->description,
1934 "Xuesong Jiang <Xuesong.Jiang@amlogic.com>");
1935
1936 gst_caps_unref(cdata->sink_caps);
1937 gst_caps_unref(cdata->src_caps);
1938 g_free(cdata);
1939}
1940
1941/* Probing functions */
1942gboolean
1943gst_aml_v4l2_is_video_dec(GstCaps *sink_caps, GstCaps *src_caps)
1944{
1945 gboolean ret = FALSE;
1946
1947 if (gst_caps_is_subset(sink_caps, gst_aml_v4l2_object_get_codec_caps()) && gst_caps_is_subset(src_caps, gst_aml_v4l2_object_get_raw_caps()))
1948 ret = TRUE;
1949
1950 return ret;
1951}
1952
1953static gchar *
1954gst_aml_v4l2_video_dec_set_metadata(GstStructure *s, GstAmlV4l2VideoDecCData *cdata,
1955 const gchar *basename)
1956{
1957 gchar *codec_name = NULL;
1958 gchar *type_name = NULL;
1959 gboolean got_value = FALSE;
1960
1961#define SET_META(codec) \
1962 G_STMT_START \
1963 { \
1964 cdata->longname = "AML V4L2 " codec " Decoder"; \
1965 cdata->description = "Decodes " codec " streams via V4L2 API"; \
1966 codec_name = g_ascii_strdown(codec, -1); \
1967 } \
1968 G_STMT_END
1969
1970 if (gst_structure_has_name(s, "image/jpeg"))
1971 {
1972 SET_META("JPEG");
1973 }
1974 else if (gst_structure_has_name(s, "video/mpeg"))
1975 {
1976 gint mpegversion = 0;
1977 gint *list = NULL;
1978 got_value = gst_structure_get_int(s, "mpegversion", &mpegversion);
1979 if (FALSE == got_value)
1980 {
1981 got_value = gst_structure_get_list(s, "mpegversion", &list);
1982 if (TRUE == got_value && (1 == *list || 2 == *list))
1983 {
1984 SET_META("MPEG2");
1985 }
1986 else
1987 {
1988 SET_META("MPEG4");
1989 }
1990 }
1991 else
1992 {
1993 SET_META("MPEG4");
1994 }
1995 }
1996 else if (gst_structure_has_name(s, "video/x-h263"))
1997 {
1998 SET_META("H263");
1999 }
2000 else if (gst_structure_has_name(s, "video/x-fwht"))
2001 {
2002 SET_META("FWHT");
2003 }
2004 else if (gst_structure_has_name(s, "video/x-h264"))
2005 {
2006 SET_META("H264");
2007 }
2008 else if (gst_structure_has_name(s, "video/x-h265"))
2009 {
2010 SET_META("H265");
2011 }
2012 else if (gst_structure_has_name(s, "video/x-wmv"))
2013 {
2014 SET_META("VC1");
2015 }
2016 else if (gst_structure_has_name(s, "video/x-vp8"))
2017 {
2018 SET_META("VP8");
2019 }
2020 else if (gst_structure_has_name(s, "video/x-vp9"))
2021 {
2022 SET_META("VP9");
2023 }
2024 else if (gst_structure_has_name(s, "video/x-av1"))
2025 {
2026 SET_META("AV1");
2027 }
zengliang.li51f54b62023-10-10 12:14:49 +00002028 else if (gst_structure_has_name(s, "video/x-avs"))
2029 {
2030 SET_META("AVS");
2031 }
2032 else if (gst_structure_has_name(s, "video/x-avs2"))
2033 {
2034 SET_META("AVS2");
2035 }
2036 else if (gst_structure_has_name(s, "video/x-avs3"))
2037 {
2038 SET_META("AVS3");
2039 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002040 else if (gst_structure_has_name(s, "video/x-bayer"))
2041 {
2042 SET_META("BAYER");
2043 }
2044 else if (gst_structure_has_name(s, "video/x-sonix"))
2045 {
2046 SET_META("SONIX");
2047 }
2048 else if (gst_structure_has_name(s, "video/x-pwc1"))
2049 {
2050 SET_META("PWC1");
2051 }
2052 else if (gst_structure_has_name(s, "video/x-pwc2"))
2053 {
2054 SET_META("PWC2");
2055 }
2056 else
2057 {
2058 /* This code should be kept on sync with the exposed CODEC type of format
2059 * from gstamlv4l2object.c. This warning will only occure in case we forget
2060 * to also add a format here. */
2061 gchar *s_str = gst_structure_to_string(s);
2062 g_warning("Missing fixed name mapping for caps '%s', this is a GStreamer "
2063 "bug, please report at https://bugs.gnome.org",
2064 s_str);
2065 g_free(s_str);
2066 }
2067
2068 if (codec_name)
2069 {
2070 type_name = g_strdup_printf("amlv4l2%sdec", codec_name);
2071 if (g_type_from_name(type_name) != 0)
2072 {
2073 g_free(type_name);
2074 type_name = g_strdup_printf("amlv4l2%s%sdec", basename, codec_name);
2075 }
2076
2077 g_free(codec_name);
2078 }
2079
2080 return type_name;
2081#undef SET_META
2082}
2083
2084void gst_aml_v4l2_video_dec_register(GstPlugin *plugin, const gchar *basename,
2085 const gchar *device_path, GstCaps *sink_caps, GstCaps *src_caps)
2086{
2087 gint i;
2088
2089 for (i = 0; i < gst_caps_get_size(sink_caps); i++)
2090 {
2091 GstAmlV4l2VideoDecCData *cdata;
2092 GstStructure *s;
2093 GTypeQuery type_query;
2094 GTypeInfo type_info = {
2095 0,
2096 };
2097 GType type, subtype;
2098 gchar *type_name;
2099
2100 s = gst_caps_get_structure(sink_caps, i);
2101
2102 cdata = g_new0(GstAmlV4l2VideoDecCData, 1);
2103 cdata->device = g_strdup(device_path);
2104 cdata->sink_caps = gst_caps_new_empty();
2105 gst_caps_append_structure(cdata->sink_caps, gst_structure_copy(s));
2106 gst_caps_append_structure(cdata->sink_caps, gst_structure_copy(s));
2107 gst_caps_set_features(cdata->sink_caps, 0, gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_DMABUF));
2108 cdata->src_caps = gst_caps_copy(src_caps);
2109 gst_caps_set_features_simple(cdata->src_caps, gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_DMABUF));
2110 gst_caps_append(cdata->src_caps, gst_caps_copy(src_caps));
2111 type_name = gst_aml_v4l2_video_dec_set_metadata(s, cdata, basename);
2112
2113 /* Skip over if we hit an unmapped type */
2114 if (!type_name)
2115 {
2116 g_free(cdata);
2117 continue;
2118 }
2119
2120 type = gst_aml_v4l2_video_dec_get_type();
2121 g_type_query(type, &type_query);
2122 memset(&type_info, 0, sizeof(type_info));
2123 type_info.class_size = type_query.class_size;
2124 type_info.instance_size = type_query.instance_size;
2125 type_info.class_init = gst_aml_v4l2_video_dec_subclass_init;
2126 type_info.class_data = cdata;
2127 type_info.instance_init = gst_aml_v4l2_video_dec_subinstance_init;
2128
2129 subtype = g_type_register_static(type, type_name, &type_info, 0);
2130 if (!gst_element_register(plugin, type_name, GST_RANK_PRIMARY + 1,
2131 subtype))
2132 GST_WARNING("Failed to register plugin '%s'", type_name);
2133
2134 g_free(type_name);
2135 }
2136}
xuesong.jiang61ea8012022-05-12 15:38:17 +08002137
2138#if GST_IMPORT_LGE_PROP
2139static void gst_aml_v4l2_video_dec_install_lge_properties_helper(GObjectClass *gobject_class)
2140{
2141 g_object_class_install_property(gobject_class, LGE_RESOURCE_INFO,
2142 g_param_spec_object("resource-info", "resource-info",
2143 "After acquisition of H/W resources is completed, allocated resource information must be delivered to the decoder and the sink",
2144 GST_TYPE_STRUCTURE,
2145 G_PARAM_READABLE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
2146
2147 g_object_class_install_property(gobject_class, LGE_DECODE_SIZE,
2148 g_param_spec_uint64("decoded-size", "decoded-size",
2149 "The total amount of decoder element's decoded video es after constructing pipeline or flushing pipeline update unit is byte.",
2150 0, G_MAXUINT64,
2151 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2152
2153 g_object_class_install_property(gobject_class, LGE_UNDECODE_SIZE,
2154 g_param_spec_uint64("undecoded-size", "undecoded-size",
2155 "video decoder element's total undecoded data update unit is byte.",
2156 0, G_MAXUINT64,
2157 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2158
2159 g_object_class_install_property(gobject_class, LGE_APP_TYPE,
2160 g_param_spec_string("app-type", "app-type",
2161 "set application type.",
2162 "default_app",
2163 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2164
2165 g_object_class_install_property(gobject_class, LGE_CLIP_MODE,
2166 g_param_spec_boolean("clip-mode", "clip-mode",
2167 "When seeking, Content is moving faster for a while to skip frames.",
2168 FALSE,
2169 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2170}
2171#endif