blob: 6766ac4aea710fcf0af048f11d428d7a38b4d93a [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 <fcntl.h>
25
26#include <sys/mman.h>
27#include <string.h>
28#include <unistd.h>
29#include <stdio.h>
30
31#include "gst/video/video.h"
32#include "gst/video/gstvideometa.h"
33#include "gst/video/gstvideopool.h"
34#include "gst/allocators/gstdmabuf.h"
35
36#include <gstamlv4l2bufferpool.h>
37
38#include "gstamlv4l2object.h"
39#include "gst/gst-i18n-plugin.h"
40#include <gst/glib-compat-private.h>
41
42#define GST_DUMP_CAPTURE_BP_STAT_FILENAME "amlv4l2dec_capture_bp_buf_stat"
43#define GST_DUMP_OUTPUT_BP_STAT_FILENAME "amlv4l2dec_output_bp_buf_stat"
44
45GST_DEBUG_CATEGORY_STATIC(amlv4l2bufferpool_debug);
46GST_DEBUG_CATEGORY_STATIC(CAT_PERFORMANCE);
47#define GST_CAT_DEFAULT amlv4l2bufferpool_debug
48
49#define GST_AML_V4L2_IMPORT_QUARK gst_aml_v4l2_buffer_pool_import_quark()
50
51/*
52 * GstAmlV4l2BufferPool:
53 */
54#define gst_aml_v4l2_buffer_pool_parent_class parent_class
55G_DEFINE_TYPE(GstAmlV4l2BufferPool, gst_aml_v4l2_buffer_pool, GST_TYPE_BUFFER_POOL);
56
57enum _GstAmlV4l2BufferPoolAcquireFlags
58{
59 GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT =
60 GST_BUFFER_POOL_ACQUIRE_FLAG_LAST,
61 GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_LAST
62};
63
64static void gst_aml_v4l2_buffer_pool_release_buffer(GstBufferPool *bpool,
65 GstBuffer *buffer);
66
67#ifdef GST_AML_SPEC_FLOW_FOR_VBP
68static gboolean gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(GstBufferPool *bpool);
69#endif
70
zengliang.lidcd41462024-06-19 16:05:12 +080071#define MAX_CC_LEN 72
72#ifndef V4L2_CID_USER_AMLOGIC_BASE
73#define V4L2_CID_USER_AMLOGIC_BASE (V4L2_CID_USER_BASE + 0x1100)
74#define AML_V4L2_GET_DECINFO_SET (V4L2_CID_USER_AMLOGIC_BASE + 13)
75#endif
76
77enum E_DECINFO_CMD_GET {
78AML_DECINFO_GET_STREAM_TYPE = 0,
79AML_DECINFO_GET_STATISTIC_TYPE,
80AML_DECINFO_GET_AFD_TYPE,
81AML_DECINFO_GET_CC_TYPE,
82AML_DECINFO_GET_HDR10_TYPE,
83AML_DECINFO_GET_HDR10P_TYPE,
84AML_DECINFO_GET_CUVA_TYPE,
85AML_DECINFO_GET_DV_TYPE,
86AML_DECINFO_GET_FRAME_TYPE,
87AML_DECINFO_GET_COMPOSITE_TYPE = 30,
88AML_DECINFO_GET_CMD_BOTTOM = 31,
89};
90
91struct v4l_userdata_meta_data_t {
92__u32 poc_number;
93__u16 flags;
94__u16 video_format;
95__u16 extension_data;
96__u16 frame_type;
97__u32 vpts;
98__u32 vpts_valid;
99__u64 timestamp;
100__u32 records_in_que;
101unsigned long long priv_data;
102__u32 padding_data[64];
103};
104
105struct sei_usd_param_s {
106__u32 info_type; /* CC or AFD or aux data*/
107__u32 data_size; /* size of the data domain */
108__u64 data; /* pointer to data domain */
109__u64 v_addr; /* used for kernelspace data */
110struct v4l_userdata_meta_data_t meta_data; /* meta_data */
111};
112
113enum E_ASPECT_RATIO {
114ASPECT_RATIO_4_3,
115ASPECT_RATIO_16_9,
116ASPECT_UNDEFINED = 255
117};
118
119struct aspect_ratio_size {
120__s32 sar_width;
121__s32 sar_height;
122__s32 dar_width;
123__s32 dar_height;
124};
125
126struct dec_stream_info_s {
127__u32 info_type;
128char vdec_name[32];
129__u32 vdec_type;
130__u32 dual_core_flag;
131__u32 is_secure;
132__u32 profile_idc;
133__u32 level_idc;
134__u32 filed_flag;
135__u32 frame_width;
136__u32 frame_height;
137__u32 crop_top;
138__u32 crop_bottom;
139__u32 crop_left;
140__u32 crop_right;
141__u32 frame_rate;
142__u32 fence_enable;
143__u32 fast_output_enable;
144__u32 trick_mode;
145__u32 bit_depth;
146__u32 double_write_mode;
147__u32 error_handle_policy;
148enum E_ASPECT_RATIO eu_aspect_ratio;
149struct aspect_ratio_size ratio_size;
150char reserved[64];
151};
152
153struct dec_statistics_info_s {
154__u32 info_ype;
155__u32 total_decoded_frames;
156__u32 error_frames;
157__u32 drop_frames;
158__u32 i_decoded_frames;
159__u32 i_drop_frames;
160__u32 i_error_frames;
161__u32 p_decoded_frames;
162__u32 p_drop_frames;
163__u32 p_error_frames;
164__u32 b_decoded_frames;
165__u32 b_drop_frames;
166__u32 b_error_frames;
167__u32 av_resynch_counter;
168__u64 total_decoded_datasize;
169char reserved[64];
170};
171
172struct vframe_qos_s {
173__u32 num;
174__u32 type;
175__u32 size;
176__u32 pts;
177int max_qp;
178int avg_qp;
179int min_qp;
180int max_skip;
181int avg_skip;
182int min_skip;
183int max_mv;
184int min_mv;
185int avg_mv;
186int decode_buffer;
187} /*vframe_qos */;
188
189struct dec_frame_info_s {
190__u32 info_type;
191struct vframe_qos_s qos; /* qos */
192__u32 num;
193__u32 type;
194__s32 frame_poc;
195__u32 decode_time_cost;
196__u32 pic_width;
197__u32 pic_height;
198__u32 error_flag;
199__u32 status;
200__u32 bitrate;
201__u32 field_output_order;
202__u32 offset;
203__u32 ratio_control;
204__u32 vf_type;
205__u32 signal_type;
206__u32 ext_signal_type;
207__u32 pts;
208__u64 pts_us64;
209__u64 timestamp;
210__u32 frame_size;
211char reserved[64];
212};
213
214struct aux_data_static_t {
215__u32 info_type; /* HDR10 HLG FMM or IMAX */
216struct aml_vdec_hdr_infos hdr_info;
217};
218
219struct v4l_dec_data_extension {
220ulong ptr; /* for future extension */
221__u32 data_size;
222};
223
224/**
225* struct vdec_common_s - Structure used to receive infos from decoder
226*/
227struct vdec_common_s {
228 __u32 version_magic;
229 __u32 vdec_id;
230 __u32 type;
231 union {
232 struct dec_stream_info_s stream_info;
233 struct dec_frame_info_s frame_info;
234 struct dec_statistics_info_s decoder_statistics;
235 struct sei_usd_param_s usd_param;
236 struct aux_data_static_t aux_data;
237 struct v4l_dec_data_extension data_ext;
238 char raw_data[512];
239 } u;
240 __u32 size;
241};
242
xuesong.jiangae1548e2022-05-06 16:38:46 +0800243static gboolean
244gst_aml_v4l2_is_buffer_valid(GstBuffer *buffer, GstAmlV4l2MemoryGroup **out_group)
245{
246 GstMemory *mem = gst_buffer_peek_memory(buffer, 0);
247 gboolean valid = FALSE;
248
249 if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY))
250 goto done;
251
252 if (gst_is_dmabuf_memory(mem))
253 mem = gst_mini_object_get_qdata(GST_MINI_OBJECT(mem),
254 GST_AML_V4L2_MEMORY_QUARK);
255
256 if (mem && gst_is_aml_v4l2_memory(mem))
257 {
258 GstAmlV4l2Memory *vmem = (GstAmlV4l2Memory *)mem;
259 GstAmlV4l2MemoryGroup *group = vmem->group;
260 gint i;
261
262 if (group->n_mem != gst_buffer_n_memory(buffer))
263 goto done;
264
265 for (i = 0; i < group->n_mem; i++)
266 {
267 if (group->mem[i] != gst_buffer_peek_memory(buffer, i))
268 goto done;
269
270 if (!gst_memory_is_writable(group->mem[i]))
271 goto done;
272 }
273
274 valid = TRUE;
275 if (out_group)
276 *out_group = group;
277 }
278
279done:
280 return valid;
281}
282
283static GstFlowReturn
284gst_aml_v4l2_buffer_pool_copy_buffer(GstAmlV4l2BufferPool *pool, GstBuffer *dest,
285 GstBuffer *src)
286{
287 const GstVideoFormatInfo *finfo = pool->caps_info.finfo;
288
289 GST_LOG_OBJECT(pool, "copying buffer");
290
291 if (finfo && (finfo->format != GST_VIDEO_FORMAT_UNKNOWN &&
292 finfo->format != GST_VIDEO_FORMAT_ENCODED))
293 {
294 GstVideoFrame src_frame, dest_frame;
295
296 GST_DEBUG_OBJECT(pool, "copy video frame");
297
298 /* we have raw video, use videoframe copy to get strides right */
299 if (!gst_video_frame_map(&src_frame, &pool->caps_info, src, GST_MAP_READ))
300 goto invalid_buffer;
301
302 if (!gst_video_frame_map(&dest_frame, &pool->caps_info, dest,
303 GST_MAP_WRITE))
304 {
305 gst_video_frame_unmap(&src_frame);
306 goto invalid_buffer;
307 }
308
309 gst_video_frame_copy(&dest_frame, &src_frame);
310
311 gst_video_frame_unmap(&src_frame);
312 gst_video_frame_unmap(&dest_frame);
313 }
314 else
315 {
316 GstMapInfo map;
317
xuesong.jiangc5dac0f2023-02-01 14:42:24 +0800318 GST_DEBUG_OBJECT(pool, "copy raw bytes size:%d", gst_buffer_get_size(src));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800319
320 if (!gst_buffer_map(src, &map, GST_MAP_READ))
321 goto invalid_buffer;
322
323 gst_buffer_fill(dest, 0, map.data, gst_buffer_get_size(src));
324
325 gst_buffer_unmap(src, &map);
326 gst_buffer_resize(dest, 0, gst_buffer_get_size(src));
327 }
328
329 gst_buffer_copy_into(dest, src,
330 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
331
332 GST_CAT_LOG_OBJECT(CAT_PERFORMANCE, pool, "slow copy into buffer %p", dest);
333
334 return GST_FLOW_OK;
335
336invalid_buffer:
337{
338 GST_ERROR_OBJECT(pool, "could not map buffer");
339 return GST_FLOW_ERROR;
340}
341}
342
343struct UserPtrData
344{
345 GstBuffer *buffer;
346 gboolean is_frame;
347 GstVideoFrame frame;
348 GstMapInfo map;
349};
350
351static GQuark
352gst_aml_v4l2_buffer_pool_import_quark(void)
353{
354 static GQuark quark = 0;
355
356 if (quark == 0)
357 quark = g_quark_from_string("GstAmlV4l2BufferPoolUsePtrData");
358
359 return quark;
360}
361
362static void
363_unmap_userptr_frame(struct UserPtrData *data)
364{
365 if (data->is_frame)
366 gst_video_frame_unmap(&data->frame);
367 else
368 gst_buffer_unmap(data->buffer, &data->map);
369
370 if (data->buffer)
371 gst_buffer_unref(data->buffer);
372
373 g_slice_free(struct UserPtrData, data);
374}
375
376static GstFlowReturn
377gst_aml_v4l2_buffer_pool_import_userptr(GstAmlV4l2BufferPool *pool,
378 GstBuffer *dest, GstBuffer *src)
379{
380 GstFlowReturn ret = GST_FLOW_OK;
381 GstAmlV4l2MemoryGroup *group = NULL;
382 GstMapFlags flags;
383 const GstVideoFormatInfo *finfo = pool->caps_info.finfo;
384 struct UserPtrData *data = NULL;
385
386 GST_LOG_OBJECT(pool, "importing userptr");
387
388 /* get the group */
389 if (!gst_aml_v4l2_is_buffer_valid(dest, &group))
390 goto not_our_buffer;
391
392 if (V4L2_TYPE_IS_OUTPUT(pool->obj->type))
393 flags = GST_MAP_READ;
394 else
395 flags = GST_MAP_WRITE;
396
397 data = g_slice_new0(struct UserPtrData);
398
399 if (finfo && (finfo->format != GST_VIDEO_FORMAT_UNKNOWN &&
400 finfo->format != GST_VIDEO_FORMAT_ENCODED))
401 {
402 gsize size[GST_VIDEO_MAX_PLANES] = {
403 0,
404 };
405 gint i;
406
407 data->is_frame = TRUE;
408
409 if (!gst_video_frame_map(&data->frame, &pool->caps_info, src, flags))
410 goto invalid_buffer;
411
412 for (i = 0; i < GST_VIDEO_FORMAT_INFO_N_PLANES(finfo); i++)
413 {
414 if (GST_VIDEO_FORMAT_INFO_IS_TILED(finfo))
415 {
416 gint tinfo = GST_VIDEO_FRAME_PLANE_STRIDE(&data->frame, i);
417 gint pstride;
418 guint pheight;
419
420 pstride = GST_VIDEO_TILE_X_TILES(tinfo) << GST_VIDEO_FORMAT_INFO_TILE_WS(finfo);
421
422 pheight = GST_VIDEO_TILE_Y_TILES(tinfo) << GST_VIDEO_FORMAT_INFO_TILE_HS(finfo);
423
424 size[i] = pstride * pheight;
425 }
426 else
427 {
428 size[i] = GST_VIDEO_FRAME_PLANE_STRIDE(&data->frame, i) *
429 GST_VIDEO_FRAME_COMP_HEIGHT(&data->frame, i);
430 }
431 }
432
433 /* In the single planar API, planes must be contiguous in memory and
434 * therefore they must have expected size. ie: no padding.
435 * To check these conditions, we check that plane 'i' start address
436 * + plane 'i' size equals to plane 'i+1' start address */
437 if (!V4L2_TYPE_IS_MULTIPLANAR(pool->obj->type))
438 {
439 for (i = 0; i < (GST_VIDEO_FORMAT_INFO_N_PLANES(finfo) - 1); i++)
440 {
441 const struct v4l2_pix_format *pix_fmt = &pool->obj->format.fmt.pix;
442 gpointer tmp;
443 gint estride = gst_aml_v4l2_object_extrapolate_stride(finfo, i,
444 pix_fmt->bytesperline);
445 guint eheight = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(finfo, i,
446 pix_fmt->height);
447
448 tmp = ((guint8 *)data->frame.data[i]) + estride * eheight;
449 if (tmp != data->frame.data[i + 1])
450 goto non_contiguous_mem;
451 }
452 }
453
454 if (!gst_aml_v4l2_allocator_import_userptr(pool->vallocator, group,
455 data->frame.info.size, finfo->n_planes, data->frame.data, size))
456 goto import_failed;
457 }
458 else
459 {
460 gpointer ptr[1];
461 gsize size[1];
462
463 data->is_frame = FALSE;
464
465 if (!gst_buffer_map(src, &data->map, flags))
466 goto invalid_buffer;
467
468 ptr[0] = data->map.data;
469 size[0] = data->map.size;
470
471 if (!gst_aml_v4l2_allocator_import_userptr(pool->vallocator, group,
472 data->map.size, 1, ptr, size))
473 goto import_failed;
474 }
475
476 data->buffer = gst_buffer_ref(src);
477
478 gst_mini_object_set_qdata(GST_MINI_OBJECT(dest), GST_AML_V4L2_IMPORT_QUARK,
479 data, (GDestroyNotify)_unmap_userptr_frame);
480
481 gst_buffer_copy_into(dest, src,
482 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
483
484 return ret;
485
486not_our_buffer:
487{
488 GST_ERROR_OBJECT(pool, "destination buffer invalid or not from our pool");
489 return GST_FLOW_ERROR;
490}
491invalid_buffer:
492{
493 GST_ERROR_OBJECT(pool, "could not map buffer");
494 g_slice_free(struct UserPtrData, data);
495 return GST_FLOW_ERROR;
496}
497non_contiguous_mem:
498{
499 GST_ERROR_OBJECT(pool, "memory is not contiguous or plane size mismatch");
500 _unmap_userptr_frame(data);
501 return GST_FLOW_ERROR;
502}
503import_failed:
504{
505 GST_ERROR_OBJECT(pool, "failed to import data");
506 _unmap_userptr_frame(data);
507 return GST_FLOW_ERROR;
508}
509}
510
511static GstFlowReturn
512gst_aml_v4l2_buffer_pool_import_dmabuf(GstAmlV4l2BufferPool *pool,
513 GstBuffer *dest, GstBuffer *src)
514{
515 GstAmlV4l2MemoryGroup *group = NULL;
516 GstMemory *dma_mem[GST_VIDEO_MAX_PLANES] = {0};
517 guint n_mem = gst_buffer_n_memory(src);
518 gint i;
519
520 GST_LOG_OBJECT(pool, "importing dmabuf");
521
522 if (!gst_aml_v4l2_is_buffer_valid(dest, &group))
523 goto not_our_buffer;
524
525 if (n_mem > GST_VIDEO_MAX_PLANES)
526 goto too_many_mems;
527
528 for (i = 0; i < n_mem; i++)
529 dma_mem[i] = gst_buffer_peek_memory(src, i);
530
531 if (!gst_aml_v4l2_allocator_import_dmabuf(pool->vallocator, group, n_mem,
532 dma_mem))
533 goto import_failed;
534
sheng.liu01cd7b52022-06-09 18:12:11 +0800535 // Output buf is secure memory, Need to unref by itselt
536 // Capture buf is secure memory, Need to unref by downstreaming element gstvideosink
537 if (V4L2_TYPE_IS_OUTPUT (pool->obj->type))
538 gst_mini_object_set_qdata(GST_MINI_OBJECT(dest), GST_AML_V4L2_IMPORT_QUARK,
539 gst_buffer_ref(src), (GDestroyNotify)gst_buffer_unref);
540 else
541 gst_mini_object_set_qdata(GST_MINI_OBJECT(dest), GST_AML_V4L2_IMPORT_QUARK, gst_buffer_ref(src), NULL);
xuesong.jiangae1548e2022-05-06 16:38:46 +0800542
543 gst_buffer_copy_into(dest, src,
544 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
545
546 GST_DEBUG_OBJECT(pool, "v4l2 buf:%p, import buf:%p as qdata", dest, src);
547 return GST_FLOW_OK;
548
549not_our_buffer:
550{
551 GST_ERROR_OBJECT(pool, "destination buffer invalid or not from our pool");
552 return GST_FLOW_ERROR;
553}
554too_many_mems:
555{
556 GST_ERROR_OBJECT(pool, "could not map buffer");
557 return GST_FLOW_ERROR;
558}
559import_failed:
560{
561 GST_ERROR_OBJECT(pool, "failed to import dmabuf");
562 return GST_FLOW_ERROR;
563}
564}
565
566static GstFlowReturn
567gst_aml_v4l2_buffer_pool_prepare_buffer(GstAmlV4l2BufferPool *pool,
568 GstBuffer *dest, GstBuffer *src)
569{
570 GstFlowReturn ret = GST_FLOW_OK;
571 gboolean own_src = FALSE;
572
573 if (src == NULL)
574 {
575 if (pool->other_pool == NULL)
576 {
577 GST_ERROR_OBJECT(pool, "can't prepare buffer, source buffer missing");
578 return GST_FLOW_ERROR;
579 }
580
581 ret = gst_buffer_pool_acquire_buffer(pool->other_pool, &src, NULL);
582 if (ret != GST_FLOW_OK)
583 {
584 GST_ERROR_OBJECT(pool, "failed to acquire buffer from downstream pool");
585 goto done;
586 }
587
588 own_src = TRUE;
589 }
590
591 switch (pool->obj->mode)
592 {
593 case GST_V4L2_IO_MMAP:
594 case GST_V4L2_IO_DMABUF:
595 ret = gst_aml_v4l2_buffer_pool_copy_buffer(pool, dest, src);
596 break;
597 case GST_V4L2_IO_USERPTR:
598 ret = gst_aml_v4l2_buffer_pool_import_userptr(pool, dest, src);
599 break;
600 case GST_V4L2_IO_DMABUF_IMPORT:
601 ret = gst_aml_v4l2_buffer_pool_import_dmabuf(pool, dest, src);
602 break;
603 default:
604 break;
605 }
606
607 if (own_src)
608 gst_buffer_unref(src);
609
610done:
611 return ret;
612}
613
614static GstFlowReturn
615gst_aml_v4l2_buffer_pool_alloc_buffer(GstBufferPool *bpool, GstBuffer **buffer,
616 GstBufferPoolAcquireParams *params)
617{
618 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
619 GstAmlV4l2MemoryGroup *group = NULL;
620 GstBuffer *newbuf = NULL;
621 GstAmlV4l2Object *obj;
622 GstVideoInfo *info;
623
624 obj = pool->obj;
625 info = &obj->info;
626
627 switch (obj->mode)
628 {
629 case GST_V4L2_IO_RW:
630 newbuf =
631 gst_buffer_new_allocate(pool->allocator, pool->size, &pool->params);
632 break;
633 case GST_V4L2_IO_MMAP:
634 group = gst_aml_v4l2_allocator_alloc_mmap(pool->vallocator);
635 break;
636 case GST_V4L2_IO_DMABUF:
637 group = gst_aml_v4l2_allocator_alloc_dmabuf(pool->vallocator,
638 pool->allocator);
639 break;
640 case GST_V4L2_IO_USERPTR:
641 group = gst_aml_v4l2_allocator_alloc_userptr(pool->vallocator);
642 break;
643 case GST_V4L2_IO_DMABUF_IMPORT:
644 group = gst_aml_v4l2_allocator_alloc_dmabufin(pool->vallocator);
645 break;
646 default:
647 newbuf = NULL;
648 g_assert_not_reached();
649 break;
650 }
651
652 if (group != NULL)
653 {
654 gint i;
655 newbuf = gst_buffer_new();
656
657 for (i = 0; i < group->n_mem; i++)
658 gst_buffer_append_memory(newbuf, group->mem[i]);
659 }
660 else if (newbuf == NULL)
661 {
662 goto allocation_failed;
663 }
664
665 /* add metadata to raw video buffers */
666 if (pool->add_videometa)
667 gst_buffer_add_video_meta_full(newbuf, GST_VIDEO_FRAME_FLAG_NONE,
668 GST_VIDEO_INFO_FORMAT(info), GST_VIDEO_INFO_WIDTH(info),
669 GST_VIDEO_INFO_HEIGHT(info), GST_VIDEO_INFO_N_PLANES(info),
670 info->offset, info->stride);
671
672 *buffer = newbuf;
673
674 return GST_FLOW_OK;
675
676 /* ERRORS */
677allocation_failed:
678{
679 GST_ERROR_OBJECT(pool, "failed to allocate buffer");
680 return GST_FLOW_ERROR;
681}
682}
683
684static gboolean
685gst_aml_v4l2_buffer_pool_set_config(GstBufferPool *bpool, GstStructure *config)
686{
687 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
688 GstAmlV4l2Object *obj = pool->obj;
689 GstCaps *caps;
690 guint size, min_buffers, max_buffers;
691 GstAllocator *allocator;
692 GstAllocationParams params;
693 gboolean can_allocate = FALSE;
694 gboolean updated = FALSE;
695 gboolean ret;
696
697 pool->add_videometa =
698 gst_buffer_pool_config_has_option(config,
699 GST_BUFFER_POOL_OPTION_VIDEO_META);
700
701 /* parse the config and keep around */
702 if (!gst_buffer_pool_config_get_params(config, &caps, &size, &min_buffers,
703 &max_buffers))
704 goto wrong_config;
705
706 if (!gst_buffer_pool_config_get_allocator(config, &allocator, &params))
707 goto wrong_config;
708
709 GST_DEBUG_OBJECT(pool, "config %" GST_PTR_FORMAT, config);
710
711 if (pool->allocator)
712 gst_object_unref(pool->allocator);
713 pool->allocator = NULL;
714
715 switch (obj->mode)
716 {
717 case GST_V4L2_IO_DMABUF:
718 pool->allocator = gst_dmabuf_allocator_new();
719 can_allocate = GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP);
720 break;
721 case GST_V4L2_IO_MMAP:
722 can_allocate = GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP);
723 break;
724 case GST_V4L2_IO_USERPTR:
725 can_allocate =
726 GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, USERPTR);
727 break;
728 case GST_V4L2_IO_DMABUF_IMPORT:
729 can_allocate = GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, DMABUF);
730 break;
731 case GST_V4L2_IO_RW:
732 if (allocator)
733 pool->allocator = g_object_ref(allocator);
734 pool->params = params;
735 /* No need to change the configuration */
736 goto done;
737 break;
738 default:
739 g_assert_not_reached();
740 break;
741 }
742
743 /* libv4l2 conversion code does not handle CREATE_BUFS, and may lead to
744 * instability and crash, disable it for now */
745 if (can_allocate && obj->fmtdesc->flags & V4L2_FMT_FLAG_EMULATED)
746 {
747 GST_WARNING_OBJECT(pool,
748 "libv4l2 converter detected, disabling CREATE_BUFS");
749 can_allocate = FALSE;
750 GST_OBJECT_FLAG_UNSET(pool->vallocator,
751 GST_V4L2_ALLOCATOR_FLAG_MMAP_CREATE_BUFS | GST_V4L2_ALLOCATOR_FLAG_USERPTR_CREATE_BUFS | GST_V4L2_ALLOCATOR_FLAG_DMABUF_CREATE_BUFS);
752 }
753
754 if (min_buffers < GST_AML_V4L2_MIN_BUFFERS)
755 {
756 updated = TRUE;
757 min_buffers = GST_AML_V4L2_MIN_BUFFERS;
758 GST_INFO_OBJECT(pool, "increasing minimum buffers to %u", min_buffers);
759 }
760
761 /* respect driver requirements */
762 if (min_buffers < obj->min_buffers)
763 {
764 updated = TRUE;
765 min_buffers = obj->min_buffers;
766 GST_INFO_OBJECT(pool, "increasing minimum buffers to %u", min_buffers);
767 }
768
769 if (max_buffers > VIDEO_MAX_FRAME || max_buffers == 0)
770 {
771 updated = TRUE;
772 max_buffers = VIDEO_MAX_FRAME;
773 GST_INFO_OBJECT(pool, "reducing maximum buffers to %u", max_buffers);
774 }
775
776 if (min_buffers > max_buffers)
777 {
778 updated = TRUE;
779 min_buffers = max_buffers;
780 GST_INFO_OBJECT(pool, "reducing minimum buffers to %u", min_buffers);
781 }
782 else if (min_buffers != max_buffers)
783 {
784 if (!can_allocate)
785 {
786 updated = TRUE;
787 max_buffers = min_buffers;
788 GST_INFO_OBJECT(pool, "can't allocate, setting maximum to minimum");
789 }
790 }
791
792 if (!pool->add_videometa && obj->need_video_meta)
793 {
794 GST_INFO_OBJECT(pool, "adding needed video meta");
795 updated = TRUE;
796 gst_buffer_pool_config_add_option(config,
797 GST_BUFFER_POOL_OPTION_VIDEO_META);
798 }
799
800 /* Always update the config to ensure the configured size matches */
801 gst_buffer_pool_config_set_params(config, caps, obj->info.size, min_buffers,
802 max_buffers);
803
804 /* keep a GstVideoInfo with defaults for the when we need to copy */
805 gst_video_info_from_caps(&pool->caps_info, caps);
806
807done:
808 ret = GST_BUFFER_POOL_CLASS(parent_class)->set_config(bpool, config);
809
810 /* If anything was changed documentation recommand to return FALSE */
811 return !updated && ret;
812
813 /* ERRORS */
814wrong_config:
815{
816 GST_ERROR_OBJECT(pool, "invalid config %" GST_PTR_FORMAT, config);
817 return FALSE;
818}
819}
820
821static GstFlowReturn
822gst_aml_v4l2_buffer_pool_resurrect_buffer(GstAmlV4l2BufferPool *pool)
823{
824 GstBufferPoolAcquireParams params = {0};
825 GstBuffer *buffer = NULL;
826 GstFlowReturn ret;
827
828 GST_DEBUG_OBJECT(pool, "A buffer was lost, reallocating it");
829
830 /* block recursive calls to this function */
831 g_signal_handler_block(pool->vallocator, pool->group_released_handler);
832
833 params.flags =
834 (GstBufferPoolAcquireFlags)GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT |
835 GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
836 ret =
837 gst_buffer_pool_acquire_buffer(GST_BUFFER_POOL(pool), &buffer, &params);
838
839 if (ret == GST_FLOW_OK)
840 gst_buffer_unref(buffer);
841
842 g_signal_handler_unblock(pool->vallocator, pool->group_released_handler);
843
844 return ret;
845}
846
847static gboolean
848gst_aml_v4l2_buffer_pool_streamon(GstAmlV4l2BufferPool *pool)
849{
850 GstAmlV4l2Object *obj = pool->obj;
851
852 if (pool->streaming)
853 return TRUE;
854
855 switch (obj->mode)
856 {
857 case GST_V4L2_IO_MMAP:
858 case GST_V4L2_IO_USERPTR:
859 case GST_V4L2_IO_DMABUF:
860 case GST_V4L2_IO_DMABUF_IMPORT:
861 if (!V4L2_TYPE_IS_OUTPUT(pool->obj->type))
862 {
863 guint i;
864
865 /* For captures, we need to enqueue buffers before we start streaming,
866 * so the driver don't underflow immediatly. As we have put then back
867 * into the base class queue, resurrect them, then releasing will queue
868 * them back. */
869 for (i = 0; i < pool->num_allocated; i++)
870 gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
871 }
872
873 if (obj->ioctl(pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
874 goto streamon_failed;
875
876 pool->streaming = TRUE;
877
878 GST_DEBUG_OBJECT(pool, "Started streaming");
879 break;
880 default:
881 break;
882 }
883
884 return TRUE;
885
886streamon_failed:
887{
888 GST_ERROR_OBJECT(pool, "error with STREAMON %d (%s)", errno,
889 g_strerror(errno));
890 return FALSE;
891}
892}
893
894/* Call with streamlock held, or when streaming threads are down */
895static void
896gst_aml_v4l2_buffer_pool_streamoff(GstAmlV4l2BufferPool *pool)
897{
898 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
899 GstAmlV4l2Object *obj = pool->obj;
900 gint i;
901
902 if (!pool->streaming)
903 return;
904
905 switch (obj->mode)
906 {
907 case GST_V4L2_IO_MMAP:
908 case GST_V4L2_IO_USERPTR:
909 case GST_V4L2_IO_DMABUF:
910 case GST_V4L2_IO_DMABUF_IMPORT:
911
912 if (obj->ioctl(pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0)
913 GST_WARNING_OBJECT(pool, "STREAMOFF failed with errno %d (%s)",
914 errno, g_strerror(errno));
915
xuesong.jiangae1548e2022-05-06 16:38:46 +0800916 GST_DEBUG_OBJECT(pool, "Stopped streaming");
917
918 if (pool->vallocator)
919 gst_aml_v4l2_allocator_flush(pool->vallocator);
920 break;
921 default:
922 break;
923 }
924
925 GstBufferPool *bpool = GST_BUFFER_POOL(pool);
926 if (V4L2_TYPE_IS_OUTPUT(pool->obj->type))
927 {
928 for (i = 0; i < VIDEO_MAX_FRAME; i++)
929 {
930 GST_INFO_OBJECT(pool, "deal with output buf index:%d, buf:%p", i, pool->buffers[i]);
931 if (pool->buffers[i])
932 {
933 GstBuffer *buffer = pool->buffers[i];
934 pool->buffers[i] = NULL;
935 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
936 g_atomic_int_add(&pool->num_queued, -1);
937 }
938 }
939 }
940 else
941 {
942#ifdef GST_AML_SPEC_FLOW_FOR_VBP
943 if (GST_V4L2_IO_DMABUF_IMPORT == obj->mode)
944 {
945 GST_DEBUG_OBJECT(pool, "have %d ready to free capture buffer", pool->ready_to_free_buf_num);
946 for (i = 0; i < VIDEO_MAX_FRAME; i++)
947 {
948 GST_DEBUG_OBJECT(pool, "buffers[%d]:%p, read_to_free_bufs[%d]:%p", i, pool->buffers[i], i, pool->read_to_free_bufs[i]);
949 if (pool->buffers[i])
950 {
951 if (pool->other_pool)
952 {
953 GstBuffer *other_pool_buf = gst_mini_object_get_qdata(GST_MINI_OBJECT(pool->buffers[i]), GST_AML_V4L2_IMPORT_QUARK);
954 GST_DEBUG_OBJECT(pool, "release v4l2 capture buf[%d]:%p other pool buf:%p", i, pool->buffers[i], other_pool_buf);
955 gst_buffer_unref(other_pool_buf);
956 }
957 }
958 else if (pool->read_to_free_bufs[i])
959 {
960 pool->buffers[i] = pool->read_to_free_bufs[i];
961 pool->read_to_free_bufs[i] = NULL;
962 pool->ready_to_free_buf_num--;
963 }
964 }
965 GST_DEBUG_OBJECT(pool, "%d ready to free capture buffer left", pool->ready_to_free_buf_num);
966 pool->num_queued = 0;
967 }
968#endif
969 for (i = 0; i < VIDEO_MAX_FRAME; i++)
970 {
971 GST_INFO_OBJECT(pool, "deal with caputre buf index:%d, buf:%p", i, pool->buffers[i]);
972 if (pool->buffers[i])
973 {
974 GstBuffer *buffer = pool->buffers[i];
975 pool->buffers[i] = NULL;
976 pclass->release_buffer(bpool, buffer);
977#ifndef GST_AML_SPEC_FLOW_FOR_VBP
978 g_atomic_int_add(&pool->num_queued, -1);
979#endif
980 }
981 }
982 }
fei.deng08cb2dc2023-11-08 04:21:41 +0000983 pool->streaming = FALSE;
xuesong.jiangae1548e2022-05-06 16:38:46 +0800984}
985
986static gboolean
987gst_aml_v4l2_buffer_pool_start(GstBufferPool *bpool)
988{
989 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
990 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
991 GstAmlV4l2Object *obj = pool->obj;
992 GstStructure *config;
993 GstCaps *caps;
994 guint size, min_buffers, max_buffers;
995 guint max_latency, min_latency, copy_threshold = 0;
996 gboolean can_allocate = FALSE, ret = TRUE;
997
998 GST_DEBUG_OBJECT(pool, "activating pool");
999
1000 if (pool->other_pool)
1001 {
1002 GstBuffer *buffer;
1003
1004 if (!gst_buffer_pool_set_active(pool->other_pool, TRUE))
1005 goto other_pool_failed;
1006
1007 if (gst_buffer_pool_acquire_buffer(pool->other_pool, &buffer, NULL) !=
1008 GST_FLOW_OK)
1009 goto other_pool_failed;
1010
1011 if (!gst_aml_v4l2_object_try_import(obj, buffer))
1012 {
1013 gst_buffer_unref(buffer);
1014 goto cannot_import;
1015 }
1016 gst_buffer_unref(buffer);
1017 }
1018
1019 config = gst_buffer_pool_get_config(bpool);
1020 if (!gst_buffer_pool_config_get_params(config, &caps, &size, &min_buffers,
1021 &max_buffers))
1022 goto wrong_config;
1023
1024 min_latency = MAX(GST_AML_V4L2_MIN_BUFFERS, obj->min_buffers);
1025
1026 switch (obj->mode)
1027 {
1028 case GST_V4L2_IO_RW:
1029 can_allocate = TRUE;
1030#ifdef HAVE_LIBV4L2
1031 /* This workaround a unfixable bug in libv4l2 when RW is emulated on top
1032 * of MMAP. In this case, the first read initialize the queues, but the
1033 * poll before that will always fail. Doing an empty read, forces the
1034 * queue to be initialized now. We only do this if we have a streaming
1035 * driver. */
1036 if (obj->device_caps & V4L2_CAP_STREAMING)
1037 obj->read(obj->video_fd, NULL, 0);
1038#endif
1039 break;
1040 case GST_V4L2_IO_DMABUF:
1041 case GST_V4L2_IO_MMAP:
1042 {
1043 guint count;
1044
1045 can_allocate = GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP);
1046
1047 /* first, lets request buffers, and see how many we can get: */
1048 GST_DEBUG_OBJECT(pool, "requesting %d MMAP buffers", min_buffers);
1049
1050 count = gst_aml_v4l2_allocator_start(pool->vallocator, min_buffers,
1051 V4L2_MEMORY_MMAP);
1052 pool->num_allocated = count;
1053
1054 if (count < GST_AML_V4L2_MIN_BUFFERS)
1055 {
1056 min_buffers = count;
1057 goto no_buffers;
1058 }
1059
1060 /* V4L2 buffer pool are often very limited in the amount of buffers it
1061 * can offer. The copy_threshold will workaround this limitation by
1062 * falling back to copy if the pipeline needed more buffers. This also
1063 * prevent having to do REQBUFS(N)/REQBUFS(0) everytime configure is
1064 * called. */
1065 if (count != min_buffers || pool->enable_copy_threshold)
1066 {
1067 GST_WARNING_OBJECT(pool,
1068 "Uncertain or not enough buffers, enabling copy threshold");
1069 min_buffers = count;
1070 copy_threshold = min_latency;
1071 }
1072
1073 break;
1074 }
1075 case GST_V4L2_IO_USERPTR:
1076 {
1077 guint count;
1078
1079 can_allocate =
1080 GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, USERPTR);
1081
1082 GST_DEBUG_OBJECT(pool, "requesting %d USERPTR buffers", min_buffers);
1083
1084 count = gst_aml_v4l2_allocator_start(pool->vallocator, min_buffers,
1085 V4L2_MEMORY_USERPTR);
1086
1087 /* There is no rational to not get what we asked */
1088 if (count < min_buffers)
1089 {
1090 min_buffers = count;
1091 goto no_buffers;
1092 }
1093
1094 min_buffers = count;
1095 break;
1096 }
1097 case GST_V4L2_IO_DMABUF_IMPORT:
1098 {
1099 guint count;
1100
1101 can_allocate = GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, DMABUF);
1102
1103 GST_DEBUG_OBJECT(pool, "requesting %d DMABUF buffers", min_buffers);
1104
1105 count = gst_aml_v4l2_allocator_start(pool->vallocator, min_buffers,
1106 V4L2_MEMORY_DMABUF);
1107
1108 /* There is no rational to not get what we asked */
1109 if (count < min_buffers)
1110 {
1111 min_buffers = count;
1112 goto no_buffers;
1113 }
1114
1115 min_buffers = count;
1116 break;
1117 }
1118 default:
1119 min_buffers = 0;
1120 copy_threshold = 0;
1121 g_assert_not_reached();
1122 break;
1123 }
1124
1125 if (can_allocate)
1126 max_latency = max_buffers;
1127 else
1128 max_latency = min_buffers;
1129
1130 pool->size = size;
1131 pool->copy_threshold = copy_threshold;
1132 pool->max_latency = max_latency;
1133 pool->min_latency = min_latency;
1134 pool->num_queued = 0;
1135
1136 if (max_buffers != 0 && max_buffers < min_buffers)
1137 max_buffers = min_buffers;
1138
1139 gst_buffer_pool_config_set_params(config, caps, size, min_buffers,
1140 max_buffers);
1141 pclass->set_config(bpool, config);
1142 gst_structure_free(config);
1143
1144 /* now, allocate the buffers: */
1145 if (!pclass->start(bpool))
1146 goto start_failed;
1147
1148 if (!V4L2_TYPE_IS_OUTPUT(obj->type))
1149 {
1150 if (g_atomic_int_get(&pool->num_queued) < min_buffers)
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001151 {
1152 if (obj->old_other_pool || obj->old_old_other_pool)
1153 GST_DEBUG_OBJECT(pool, "resolution switching flow, need to wait other pool recycle");
1154 else
1155 goto queue_failed;
1156 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001157
1158 pool->group_released_handler =
1159 g_signal_connect_swapped(pool->vallocator, "group-released",
1160 G_CALLBACK(gst_aml_v4l2_buffer_pool_resurrect_buffer), pool);
1161 ret = gst_aml_v4l2_buffer_pool_streamon(pool);
1162 }
1163
1164 return ret;
1165
1166 /* ERRORS */
1167wrong_config:
1168{
1169 GST_ERROR_OBJECT(pool, "invalid config %" GST_PTR_FORMAT, config);
1170 gst_structure_free(config);
1171 return FALSE;
1172}
1173no_buffers:
1174{
1175 GST_ERROR_OBJECT(pool,
1176 "we received %d buffer from device '%s', we want at least %d",
1177 min_buffers, obj->videodev, GST_AML_V4L2_MIN_BUFFERS);
1178 gst_structure_free(config);
1179 return FALSE;
1180}
1181start_failed:
1182{
1183 GST_ERROR_OBJECT(pool, "allocate failed");
1184 return FALSE;
1185}
1186other_pool_failed:
1187{
1188 GST_ERROR_OBJECT(pool, "failed to activate the other pool %" GST_PTR_FORMAT, pool->other_pool);
1189 return FALSE;
1190}
1191queue_failed:
1192{
1193 GST_ERROR_OBJECT(pool, "failed to queue buffers into the capture queue");
1194 return FALSE;
1195}
1196cannot_import:
1197{
1198 GST_ERROR_OBJECT(pool, "cannot import buffers from downstream pool");
1199 return FALSE;
1200}
1201}
1202
1203static gboolean
1204gst_aml_v4l2_buffer_pool_vallocator_stop(GstAmlV4l2BufferPool *pool)
1205{
1206 GstAmlV4l2Return vret;
1207
1208 if (!pool->vallocator)
1209 return TRUE;
1210
1211 vret = gst_aml_v4l2_allocator_stop(pool->vallocator);
1212
1213 if (vret == GST_V4L2_BUSY)
1214 GST_WARNING_OBJECT(pool, "some buffers are still outstanding");
1215
1216 return (vret == GST_V4L2_OK);
1217}
1218
1219static gboolean
1220gst_aml_v4l2_buffer_pool_stop(GstBufferPool *bpool)
1221{
1222 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1223 gboolean ret;
1224
1225 if (pool->orphaned)
1226 return gst_aml_v4l2_buffer_pool_vallocator_stop(pool);
1227
1228 GST_DEBUG_OBJECT(pool, "stopping pool");
1229
1230 if (pool->group_released_handler > 0)
1231 {
1232 g_signal_handler_disconnect(pool->vallocator,
1233 pool->group_released_handler);
1234 pool->group_released_handler = 0;
1235 }
1236
1237 gst_aml_v4l2_buffer_pool_streamoff(pool);
1238
1239 ret = GST_BUFFER_POOL_CLASS(parent_class)->stop(bpool);
1240
1241 if (ret)
1242 ret = gst_aml_v4l2_buffer_pool_vallocator_stop(pool);
1243
1244 GST_DEBUG_OBJECT(pool, "stopping other_pool");
1245 if (pool->other_pool)
1246 {
1247 gst_buffer_pool_set_active(pool->other_pool, FALSE);
1248 gst_object_unref(pool->other_pool);
1249 pool->other_pool = NULL;
1250 }
1251
1252 return ret;
1253}
1254
1255gboolean
1256gst_aml_v4l2_buffer_pool_orphan(GstBufferPool **bpool)
1257{
1258 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(*bpool);
1259 gboolean ret;
1260
1261 if (!GST_AML_V4L2_ALLOCATOR_CAN_ORPHAN_BUFS(pool->vallocator))
1262 return FALSE;
1263
1264 if (g_getenv("GST_V4L2_FORCE_DRAIN"))
1265 return FALSE;
1266
1267 GST_DEBUG_OBJECT(pool, "orphaning pool");
1268
1269 gst_buffer_pool_set_active(*bpool, FALSE);
1270 /*
1271 * If the buffer pool has outstanding buffers, it will not be stopped
1272 * by the base class when set inactive. Stop it manually and mark it
1273 * as orphaned
1274 */
1275 ret = gst_aml_v4l2_buffer_pool_stop(*bpool);
1276 if (!ret)
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001277 {
1278 GST_DEBUG_OBJECT(pool, "stop poll fail, try to orphaning allocator");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001279 ret = gst_aml_v4l2_allocator_orphan(pool->vallocator);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001280 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001281
1282 if (!ret)
1283 goto orphan_failed;
1284
1285 pool->orphaned = TRUE;
1286 gst_object_unref(*bpool);
1287 *bpool = NULL;
1288
1289orphan_failed:
1290 return ret;
1291}
1292
1293static void
1294gst_aml_v4l2_buffer_pool_flush_start(GstBufferPool *bpool)
1295{
1296 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1297
1298 GST_DEBUG_OBJECT(pool, "start flushing");
1299
1300 gst_poll_set_flushing(pool->poll, TRUE);
1301
1302 GST_OBJECT_LOCK(pool);
1303 pool->empty = FALSE;
1304 g_cond_broadcast(&pool->empty_cond);
1305 GST_OBJECT_UNLOCK(pool);
1306
1307 if (pool->other_pool)
1308 gst_buffer_pool_set_flushing(pool->other_pool, TRUE);
1309}
1310
1311static void
1312gst_aml_v4l2_buffer_pool_flush_stop(GstBufferPool *bpool)
1313{
1314 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1315
1316 GST_DEBUG_OBJECT(pool, "stop flushing");
1317
1318 if (pool->other_pool)
1319 gst_buffer_pool_set_flushing(pool->other_pool, FALSE);
1320
1321 gst_poll_set_flushing(pool->poll, FALSE);
1322}
1323
1324static GstFlowReturn
1325gst_aml_v4l2_buffer_pool_poll(GstAmlV4l2BufferPool *pool, gboolean wait)
1326{
1327 gint ret;
1328 GstClockTime timeout;
1329 gint try_num = 0;
1330
1331 if (wait)
1332 timeout = GST_CLOCK_TIME_NONE;
1333 else
1334 timeout = 0;
1335
1336 /* In RW mode there is no queue, hence no need to wait while the queue is
1337 * empty */
xuesong.jiang93f2dcb2022-07-15 14:24:55 +08001338
1339 if ((pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
1340 pool->obj->mode == GST_V4L2_IO_DMABUF_IMPORT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001341 {
fei.denge9458472023-04-18 02:05:48 +00001342 GST_TRACE_OBJECT(pool, "CAPTURE DMA don't quit when empty buf");
fei.deng08cb2dc2023-11-08 04:21:41 +00001343 timeout = 5*1000*1000; //5ms
xuesong.jiang93f2dcb2022-07-15 14:24:55 +08001344 }
1345 else
1346 {
1347 if (pool->obj->mode != GST_V4L2_IO_RW)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001348 {
xuesong.jiang93f2dcb2022-07-15 14:24:55 +08001349 GST_OBJECT_LOCK(pool);
1350
1351 if (!wait && pool->empty)
1352 {
1353 GST_OBJECT_UNLOCK(pool);
1354 goto no_buffers;
1355 }
1356
1357 while (pool->empty)
1358 g_cond_wait(&pool->empty_cond, GST_OBJECT_GET_LOCK(pool));
1359
xuesong.jiangae1548e2022-05-06 16:38:46 +08001360 GST_OBJECT_UNLOCK(pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001361 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001362 }
1363
1364 if (!pool->can_poll_device)
1365 {
1366 if (wait)
1367 goto done;
1368 else
1369 goto no_buffers;
1370 }
1371
fei.denge9458472023-04-18 02:05:48 +00001372 GST_TRACE_OBJECT(pool, "polling device");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001373
1374again:
1375 ret = gst_poll_wait(pool->poll, timeout);
1376#ifdef GST_AML_SPEC_FLOW_FOR_VBP
fei.denge9458472023-04-18 02:05:48 +00001377 GST_TRACE_OBJECT(pool, "amlmodbuf poll timeout:%lld, ret:%d, errno:%d", timeout, ret, errno);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001378#endif
1379 if (G_UNLIKELY(ret < 0))
1380 {
1381 switch (errno)
1382 {
1383 case EBUSY:
1384 goto stopped;
1385 case EAGAIN:
1386 case EINTR:
1387 goto again;
1388 case ENXIO:
1389 GST_WARNING_OBJECT(pool,
1390 "v4l2 device doesn't support polling. Disabling"
1391 " using libv4l2 in this case may cause deadlocks");
1392 pool->can_poll_device = FALSE;
1393 goto done;
1394 default:
1395 goto select_error;
1396 }
1397 }
1398
1399 if (gst_poll_fd_has_error(pool->poll, &pool->pollfd))
fei.deng08cb2dc2023-11-08 04:21:41 +00001400 {
1401 //if v4l2 don't have capture buffer, we will poll a error,it cause v4l2dec loop thread exit
1402 //so we should wait capture buffer release and queue it to v4l2,after this,we try poll again
1403 if ((pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
1404 pool->obj->mode == GST_V4L2_IO_DMABUF_IMPORT)
1405 {
1406 if (pool->num_queued == 0)
1407 {
1408 ret = 0;
1409 GST_TRACE_OBJECT(pool,"ignore error when no capture buffer on v4l2");
1410 g_usleep(4000);
1411 goto wait_buffer_queue;
1412 }
1413 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001414 goto select_error;
fei.deng08cb2dc2023-11-08 04:21:41 +00001415 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001416
fei.deng08cb2dc2023-11-08 04:21:41 +00001417wait_buffer_queue:
xuesong.jiangae1548e2022-05-06 16:38:46 +08001418 if (ret == 0)
1419 {
1420#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1421 if ((pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
1422 pool->obj->mode == GST_V4L2_IO_DMABUF_IMPORT)
1423 {
fei.denge9458472023-04-18 02:05:48 +00001424 GST_TRACE_OBJECT(pool, "amlmodbuf can't get buffer in capture obj dmaimport mode, try release buf from other pool");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001425 gst_aml_v4l2_buffer_pool_dump_stat(pool, GST_DUMP_CAPTURE_BP_STAT_FILENAME, try_num++);
1426 gst_aml_v4l2_buffer_pool_release_buffer_aml_patch((GstBufferPool *)pool);
1427 goto again;
1428 }
1429 else
1430#endif
1431 goto no_buffers;
1432 }
1433
1434done:
1435 return GST_FLOW_OK;
1436
1437 /* ERRORS */
1438stopped:
1439{
1440 GST_DEBUG_OBJECT(pool, "stop called");
1441 return GST_FLOW_FLUSHING;
1442}
1443select_error:
1444{
1445 GST_ELEMENT_ERROR(pool->obj->element, RESOURCE, READ, (NULL),
1446 ("poll error %d: %s (%d)", ret, g_strerror(errno), errno));
1447 return GST_FLOW_ERROR;
1448}
1449no_buffers:
1450 return GST_FLOW_CUSTOM_SUCCESS;
1451}
1452
1453static GstFlowReturn
1454gst_aml_v4l2_buffer_pool_qbuf(GstAmlV4l2BufferPool *pool, GstBuffer *buf,
1455 GstAmlV4l2MemoryGroup *group)
1456{
1457 const GstAmlV4l2Object *obj = pool->obj;
1458 GstClockTime timestamp;
1459 gint index;
1460
1461 index = group->buffer.index;
1462
1463 if (pool->buffers[index] != NULL)
1464 goto already_queued;
1465
1466 GST_LOG_OBJECT(pool, "queuing buffer %i", index);
1467
1468 if (V4L2_TYPE_IS_OUTPUT(obj->type))
1469 {
1470 enum v4l2_field field;
1471
1472 /* Except when field is set to alternate, buffer field is the same as
1473 * the one defined in format */
1474 if (V4L2_TYPE_IS_MULTIPLANAR(obj->type))
1475 field = obj->format.fmt.pix_mp.field;
1476 else
1477 field = obj->format.fmt.pix.field;
1478
1479 /* NB: At this moment, we can't have alternate mode because it not handled
1480 * yet */
1481 if (field == V4L2_FIELD_ALTERNATE)
1482 {
1483 if (GST_BUFFER_FLAG_IS_SET(buf, GST_VIDEO_FRAME_FLAG_TFF))
1484 field = V4L2_FIELD_TOP;
1485 else
1486 field = V4L2_FIELD_BOTTOM;
1487 }
1488
1489 group->buffer.field = field;
1490 }
1491
1492 if (GST_BUFFER_TIMESTAMP_IS_VALID(buf))
1493 {
1494 timestamp = GST_BUFFER_TIMESTAMP(buf);
1495 GST_TIME_TO_TIMEVAL(timestamp, group->buffer.timestamp);
1496 }
zengliang.li32cb11e2022-11-24 12:10:26 +08001497 else
1498 {
1499 group->buffer.timestamp.tv_sec= -1;
1500 group->buffer.timestamp.tv_usec= 0;
1501 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001502
1503 GST_OBJECT_LOCK(pool);
1504 g_atomic_int_inc(&pool->num_queued);
1505 pool->buffers[index] = buf;
1506
1507 if (!gst_aml_v4l2_allocator_qbuf(pool->vallocator, group))
1508 goto queue_failed;
1509
1510 if (!V4L2_TYPE_IS_OUTPUT(obj->type))
1511 {
1512 gst_aml_v4l2_buffer_pool_dump_stat(pool, GST_DUMP_CAPTURE_BP_STAT_FILENAME, 0);
1513 }
1514
1515 pool->empty = FALSE;
1516 g_cond_signal(&pool->empty_cond);
1517 GST_OBJECT_UNLOCK(pool);
1518
1519 return GST_FLOW_OK;
1520
1521already_queued:
1522{
1523 GST_ERROR_OBJECT(pool, "the buffer %i was already queued", index);
1524 return GST_FLOW_ERROR;
1525}
1526queue_failed:
1527{
1528 GST_ERROR_OBJECT(pool, "could not queue a buffer %i", index);
1529 /* Mark broken buffer to the allocator */
1530 GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_TAG_MEMORY);
1531 g_atomic_int_add(&pool->num_queued, -1);
1532 pool->buffers[index] = NULL;
1533 GST_OBJECT_UNLOCK(pool);
1534 return GST_FLOW_ERROR;
1535}
1536}
1537
1538static GstFlowReturn
1539gst_aml_v4l2_buffer_pool_dqevent(GstAmlV4l2BufferPool *pool)
1540{
1541 GstAmlV4l2Object *v4l2object = pool->obj;
1542 struct v4l2_event evt;
1543
1544 memset(&evt, 0x00, sizeof(struct v4l2_event));
1545 if (v4l2object->ioctl(pool->video_fd, VIDIOC_DQEVENT, &evt) < 0)
1546 goto dqevent_failed;
1547
1548 switch (evt.type)
1549 {
1550 case V4L2_EVENT_SOURCE_CHANGE:
sheng.liu8d18ed22022-05-26 17:28:15 +08001551
1552 if (evt.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION)
1553 return GST_AML_V4L2_FLOW_SOURCE_CHANGE;
1554 GST_WARNING_OBJECT (pool, "Unknown source change 0x%x - skipped", evt.u.src_change.changes);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001555 break;
1556 case V4L2_EVENT_EOS:
1557 return GST_AML_V4L2_FLOW_LAST_BUFFER;
1558 break;
zengliang.lidcd41462024-06-19 16:05:12 +08001559 case V4L2_EVENT_PRIVATE_EXT_REPORT_DECINFO:
1560 if (evt.id == AML_DECINFO_EVENT_CC)
1561 {
1562 struct v4l2_ext_control control;
1563 struct v4l2_ext_controls ctrls;
1564 struct vdec_common_s vdec_comm;
1565 char cc_data[MAX_CC_LEN] = {0};
1566
1567 memset(&ctrls, 0, sizeof(ctrls));
1568 memset(&control, 0, sizeof(control));
1569 memset(&vdec_comm, 0, sizeof(vdec_comm));
1570
1571 vdec_comm.type = AML_DECINFO_GET_CC_TYPE;
1572 vdec_comm.u.usd_param.data = (void *)cc_data;
1573 vdec_comm.u.usd_param.data_size = MAX_CC_LEN;
1574
1575 control.ptr = &vdec_comm;
1576 control.id = AML_V4L2_GET_DECINFO_SET;
1577 control.size = sizeof(struct vdec_common_s);
1578
1579 ctrls.count = 1;
1580 ctrls.controls = &control;
1581
1582 if (v4l2object->ioctl (pool->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
1583 {
1584 GST_DEBUG("VIDIOC_S_EXT_CTRLS fail");
1585 }
1586 else
1587 {
1588 if (v4l2object->ioctl (pool->video_fd, VIDIOC_G_EXT_CTRLS, &ctrls) == 0)
1589 {
1590 GstBuffer *cc_buffer = gst_buffer_new ();
1591 GstMemory *mem = gst_allocator_alloc (NULL, MAX_CC_LEN, NULL);
1592 gst_buffer_insert_memory (cc_buffer, -1, mem);
1593 gsize cc_size = gst_buffer_fill (cc_buffer, 0, vdec_comm.u.usd_param.data, vdec_comm.u.usd_param.data_size);
1594 GST_DEBUG("copy cc data size:%d",cc_size);
1595 cc_buffer->pts = vdec_comm.u.usd_param.meta_data.timestamp;
1596 pool->cc_buffer_list = g_list_append (pool->cc_buffer_list,cc_buffer);
1597 GST_DEBUG("cc_buffer_list size:%d",g_list_length(pool->cc_buffer_list));
1598 #if 0
1599 //dump decoder metadata
1600 GST_DEBUG("cc pack pts:%lld",vdec_comm.u.usd_param.meta_data.timestamp);
1601 int fd=open("/data/test/cc0.data",O_RDWR |O_CREAT|O_APPEND,0777);
1602 write(fd,vdec_comm.u.usd_param.data,vdec_comm.u.usd_param.data_size);
1603 close(fd);
1604 #endif
1605 }
1606 else
1607 {
1608 GST_DEBUG("VIDIOC_G_EXT_CTRLS fail");
1609 }
1610 }
1611 return GST_AML_V4L2_FLOW_CC_DATA;
1612 }
1613 break;
fei.dengaf682762024-06-24 19:06:03 +08001614 case V4L2_EVENT_PRIVATE_EXT_REPORT_ERROR_FRAME:
1615 {
1616 guint64 pts = 0;
1617 memcpy(&pts, &(evt.u.data[0]), sizeof(guint64));
1618 v4l2object->num_error_frames += 1;
1619 GST_WARNING_OBJECT (pool, "decoding video frame error,pts:%" GST_TIME_FORMAT ",total %d",
1620 GST_TIME_ARGS(pts),v4l2object->num_error_frames);
1621 return GST_AML_V4L2_FLOW_DECODING_ERROR;
1622 } break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001623 default:
1624 break;
1625 }
1626
1627 return GST_FLOW_OK;
1628
1629 /* ERRORS */
1630dqevent_failed:
1631{
1632 return GST_FLOW_ERROR;
1633}
1634}
1635
1636static GstFlowReturn
1637gst_aml_v4l2_buffer_pool_dqbuf(GstAmlV4l2BufferPool *pool, GstBuffer **buffer,
1638 gboolean wait)
1639{
1640 GstFlowReturn res;
1641 GstBuffer *outbuf = NULL;
1642 GstAmlV4l2Object *obj = pool->obj;
1643 GstClockTime timestamp;
1644 GstAmlV4l2MemoryGroup *group;
1645 GstVideoMeta *vmeta;
1646 gsize size;
1647 gint i;
1648
1649 res = gst_aml_v4l2_allocator_dqbuf(pool->vallocator, &group);
1650 if (res == GST_FLOW_EOS)
1651 goto eos;
1652 if (res != GST_FLOW_OK)
1653 goto dqbuf_failed;
1654
1655 /* get our GstBuffer with that index from the pool, if the buffer was
1656 * outstanding we have a serious problem.
1657 */
1658 outbuf = pool->buffers[group->buffer.index];
1659 if (outbuf == NULL)
1660 goto no_buffer;
1661
1662 /* mark the buffer outstanding */
1663 pool->buffers[group->buffer.index] = NULL;
1664 if (g_atomic_int_dec_and_test(&pool->num_queued))
1665 {
1666 GST_OBJECT_LOCK(pool);
1667 pool->empty = TRUE;
1668 GST_OBJECT_UNLOCK(pool);
1669 }
1670
xuesong.jiang08cb00d2023-05-17 09:18:48 +00001671 if (-1== group->buffer.timestamp.tv_sec)
1672 timestamp = GST_CLOCK_TIME_NONE;
1673 else
1674 timestamp = GST_TIMEVAL_TO_TIME(group->buffer.timestamp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001675
1676 size = 0;
1677 vmeta = gst_buffer_get_video_meta(outbuf);
1678 for (i = 0; i < group->n_mem; i++)
1679 {
1680 GST_LOG_OBJECT(pool,
1681 "dequeued buffer %p seq:%d (ix=%d), mem %p used %d, plane=%d, flags %08x, ts %" GST_TIME_FORMAT ", pool-queued=%d, buffer=%p", outbuf,
1682 group->buffer.sequence, group->buffer.index, group->mem[i],
1683 group->planes[i].bytesused, i, group->buffer.flags,
1684 GST_TIME_ARGS(timestamp), pool->num_queued, outbuf);
1685
1686 if (vmeta)
1687 {
1688 vmeta->offset[i] = size;
1689 size += gst_memory_get_sizes(group->mem[i], NULL, NULL);
1690 }
1691 }
1692
1693 /* Ignore timestamp and field for OUTPUT device */
1694 if (V4L2_TYPE_IS_OUTPUT(obj->type))
1695 goto done;
1696
1697 /* Check for driver bug in reporting feild */
1698 if (group->buffer.field == V4L2_FIELD_ANY)
1699 {
1700 /* Only warn once to avoid the spamming */
1701#ifndef GST_DISABLE_GST_DEBUG
1702 if (!pool->has_warned_on_buggy_field)
1703 {
1704 pool->has_warned_on_buggy_field = TRUE;
1705 GST_WARNING_OBJECT(pool,
1706 "Driver should never set v4l2_buffer.field to ANY");
1707 }
1708#endif
1709
1710 /* Use the value from the format (works for UVC bug) */
1711 group->buffer.field = obj->format.fmt.pix.field;
1712
1713 /* If driver also has buggy S_FMT, assume progressive */
1714 if (group->buffer.field == V4L2_FIELD_ANY)
1715 {
1716#ifndef GST_DISABLE_GST_DEBUG
1717 if (!pool->has_warned_on_buggy_field)
1718 {
1719 pool->has_warned_on_buggy_field = TRUE;
1720 GST_WARNING_OBJECT(pool,
1721 "Driver should never set v4l2_format.pix.field to ANY");
1722 }
1723#endif
1724
1725 group->buffer.field = V4L2_FIELD_NONE;
1726 }
1727 }
1728
1729 /* set top/bottom field first if v4l2_buffer has the information */
1730 switch (group->buffer.field)
1731 {
1732 case V4L2_FIELD_NONE:
1733 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1734 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1735 break;
1736 case V4L2_FIELD_INTERLACED_TB:
1737 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1738 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1739 break;
1740 case V4L2_FIELD_INTERLACED_BT:
1741 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1742 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1743 break;
1744 case V4L2_FIELD_INTERLACED:
1745 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1746 if (obj->tv_norm == V4L2_STD_NTSC_M ||
1747 obj->tv_norm == V4L2_STD_NTSC_M_JP ||
1748 obj->tv_norm == V4L2_STD_NTSC_M_KR)
1749 {
1750 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1751 }
1752 else
1753 {
1754 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1755 }
1756 break;
1757 default:
1758 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1759 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1760 GST_FIXME_OBJECT(pool,
1761 "Unhandled enum v4l2_field %d - treating as progressive",
1762 group->buffer.field);
1763 break;
1764 }
1765
1766 if (GST_VIDEO_INFO_FORMAT(&obj->info) == GST_VIDEO_FORMAT_ENCODED)
1767 {
1768 if ((group->buffer.flags & V4L2_BUF_FLAG_KEYFRAME) ||
1769 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_MJPEG ||
1770 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_JPEG ||
1771 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_PJPG)
1772 GST_BUFFER_FLAG_UNSET(outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1773 else
1774 GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1775 }
1776
1777 if (group->buffer.flags & V4L2_BUF_FLAG_ERROR)
1778 GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_FLAG_CORRUPTED);
1779
1780 GST_BUFFER_TIMESTAMP(outbuf) = timestamp;
1781 GST_BUFFER_OFFSET(outbuf) = group->buffer.sequence;
1782 GST_BUFFER_OFFSET_END(outbuf) = group->buffer.sequence + 1;
1783
1784done:
1785 *buffer = outbuf;
fei.deng594df4b2023-06-26 07:03:29 +00001786 if ( (group->buffer.flags & V4L2_BUF_FLAG_LAST) &&(group->buffer.bytesused == 0) )
1787 {
1788 GST_DEBUG_OBJECT (pool,"dequeued empty buffer");
1789 GST_BUFFER_FLAG_SET(*buffer, GST_AML_V4L2_BUFFER_FLAG_LAST_EMPTY);
1790 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001791
1792 if (!V4L2_TYPE_IS_OUTPUT(obj->type))
1793 {
1794 gst_aml_v4l2_buffer_pool_dump_stat(pool, GST_DUMP_CAPTURE_BP_STAT_FILENAME, 0);
1795 }
1796
1797 return res;
1798
1799 /* ERRORS */
1800eos:
1801{
1802 return GST_FLOW_EOS;
1803}
1804dqbuf_failed:
1805{
1806 return GST_FLOW_ERROR;
1807}
1808no_buffer:
1809{
1810 GST_ERROR_OBJECT(pool, "No free buffer found in the pool at index %d.",
1811 group->buffer.index);
1812 return GST_FLOW_ERROR;
1813}
1814}
1815
1816static GstFlowReturn
1817gst_aml_v4l2_buffer_pool_dequeue(GstAmlV4l2BufferPool *pool, GstBuffer **buffer,
1818 gboolean wait)
1819{
1820 GstFlowReturn res;
1821 GstAmlV4l2Object *obj = pool->obj;
1822
1823 if ((res = gst_aml_v4l2_buffer_pool_poll(pool, wait)) != GST_FLOW_OK)
1824 goto poll_failed;
1825
1826 if (obj->can_wait_event && gst_poll_fd_can_read_pri(pool->poll, &pool->pollfd))
1827 {
sheng.liu8d18ed22022-05-26 17:28:15 +08001828 GstFlowReturn res_event = gst_aml_v4l2_buffer_pool_dqevent(pool);
1829 if (res_event != GST_FLOW_OK)
hanghang.luob216ac42023-05-12 02:56:54 +00001830 {
1831 /* when drive V4l2 receive cmd_stop, it will finish current decoding frame, then creat
1832 * a EOS event and a empty buff. if gstreamer dq EOS event first ,the last frame will be drop,
1833 * this a question
1834 */
1835 if (res_event == GST_AML_V4L2_FLOW_LAST_BUFFER)
1836 {
1837 GST_DEBUG_OBJECT(pool," reiceive EOS event, drop it");
1838 }
1839 else
1840 return res_event;
1841 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001842 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001843 if (res == GST_FLOW_CUSTOM_SUCCESS)
1844 {
1845 GST_LOG_OBJECT(pool, "nothing to dequeue");
1846 *buffer = NULL;
1847 return res;
1848 }
1849
1850 GST_LOG_OBJECT(pool, "dequeueing a buffer");
1851 return gst_aml_v4l2_buffer_pool_dqbuf(pool, buffer, wait);
1852
1853 /* ERRORS */
1854poll_failed:
1855{
1856 GST_DEBUG_OBJECT(pool, "poll error %s", gst_flow_get_name(res));
1857 return res;
1858}
1859}
1860
1861static GstFlowReturn
1862gst_aml_v4l2_buffer_pool_acquire_buffer(GstBufferPool *bpool, GstBuffer **buffer,
1863 GstBufferPoolAcquireParams *params)
1864{
1865 GstFlowReturn ret;
1866 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1867 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
1868 GstAmlV4l2Object *obj = pool->obj;
1869
1870 GST_DEBUG_OBJECT(pool, "acquire");
1871
1872 /* If this is being called to resurrect a lost buffer */
1873 if (params && params->flags & GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT)
1874 {
1875 ret = pclass->acquire_buffer(bpool, buffer, params);
1876 goto done;
1877 }
1878
1879 switch (obj->type)
1880 {
1881 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1882 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1883 /* capture, This function should return a buffer with new captured data */
1884 switch (obj->mode)
1885 {
1886 case GST_V4L2_IO_RW:
1887 {
1888 /* take empty buffer from the pool */
1889 ret = pclass->acquire_buffer(bpool, buffer, params);
1890 break;
1891 }
1892 case GST_V4L2_IO_DMABUF:
1893 case GST_V4L2_IO_MMAP:
1894 case GST_V4L2_IO_USERPTR:
xuesong.jiang3df0f7b2022-11-29 14:52:45 +08001895 {
1896 /* just dequeue a buffer, we basically use the queue of v4l2 as the
1897 * storage for our buffers. This function does poll first so we can
1898 * interrupt it fine. */
1899 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, TRUE);
1900
1901 break;
1902 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001903 case GST_V4L2_IO_DMABUF_IMPORT:
1904 {
1905#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1906 GST_DEBUG_OBJECT(pool, "amlmodbuf return free buf before acquire buf");
1907 gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(bpool);
1908 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, FALSE);
xuesong.jiang22a9b112023-05-24 09:01:59 +00001909 GST_DEBUG_OBJECT(pool, "amlmodbuf dequeue return ret:%d", ret);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001910#else
1911 /* just dequeue a buffer, we basically use the queue of v4l2 as the
1912 * storage for our buffers. This function does poll first so we can
1913 * interrupt it fine. */
1914 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, TRUE);
1915#endif
1916 break;
1917 }
1918 default:
1919 ret = GST_FLOW_ERROR;
1920 g_assert_not_reached();
1921 break;
1922 }
1923 break;
1924
1925 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1926 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1927 /* playback, This function should return an empty buffer */
1928 switch (obj->mode)
1929 {
1930 case GST_V4L2_IO_RW:
1931 /* get an empty buffer */
1932 ret = pclass->acquire_buffer(bpool, buffer, params);
1933 break;
1934
1935 case GST_V4L2_IO_MMAP:
1936 case GST_V4L2_IO_DMABUF:
1937 case GST_V4L2_IO_USERPTR:
1938 case GST_V4L2_IO_DMABUF_IMPORT:
1939 /* get a free unqueued buffer */
1940 ret = pclass->acquire_buffer(bpool, buffer, params);
1941 break;
1942
1943 default:
1944 ret = GST_FLOW_ERROR;
1945 g_assert_not_reached();
1946 break;
1947 }
1948 break;
1949
1950 default:
1951 ret = GST_FLOW_ERROR;
1952 g_assert_not_reached();
1953 break;
1954 }
1955done:
1956 return ret;
1957}
1958
1959static void
1960gst_aml_v4l2_buffer_pool_release_buffer(GstBufferPool *bpool, GstBuffer *buffer)
1961{
1962 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1963 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
1964 GstAmlV4l2Object *obj = pool->obj;
1965
1966 GST_DEBUG_OBJECT(pool, "release buffer %p", buffer);
1967
1968 /* If the buffer's pool has been orphaned, dispose of it so that
1969 * the pool resources can be freed */
1970 if (pool->orphaned)
1971 {
1972 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
1973 pclass->release_buffer(bpool, buffer);
1974 return;
1975 }
1976
1977 switch (obj->type)
1978 {
1979 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1980 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1981 /* capture, put the buffer back in the queue so that we can refill it
1982 * later. */
1983 switch (obj->mode)
1984 {
1985 case GST_V4L2_IO_RW:
1986 /* release back in the pool */
1987 pclass->release_buffer(bpool, buffer);
1988 break;
1989
1990 case GST_V4L2_IO_DMABUF:
1991 case GST_V4L2_IO_MMAP:
1992 case GST_V4L2_IO_USERPTR:
1993 case GST_V4L2_IO_DMABUF_IMPORT:
1994 {
1995 GstAmlV4l2MemoryGroup *group;
1996 if (gst_aml_v4l2_is_buffer_valid(buffer, &group))
1997 {
1998 GstFlowReturn ret = GST_FLOW_OK;
1999
2000 gst_aml_v4l2_allocator_reset_group(pool->vallocator, group);
2001
2002#ifdef GST_AML_SPEC_FLOW_FOR_VBP
2003 GST_DEBUG_OBJECT(pool, "amlmodbuf trace in add flow with buf:%p index:%d", buffer, group->buffer.index);
2004 pool->read_to_free_bufs[group->buffer.index] = buffer;
2005 pool->ready_to_free_buf_num++;
2006 if (gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(bpool))
2007 {
2008 GST_DEBUG_OBJECT(pool, "amlmodbuf execute aml code logic, skip the following flow");
2009 return;
2010 }
2011#endif
2012 /* queue back in the device */
2013 if (pool->other_pool)
2014 ret = gst_aml_v4l2_buffer_pool_prepare_buffer(pool, buffer, NULL);
2015 if (ret != GST_FLOW_OK ||
2016 gst_aml_v4l2_buffer_pool_qbuf(pool, buffer, group) != GST_FLOW_OK)
2017 pclass->release_buffer(bpool, buffer);
2018 }
2019 else
2020 {
2021 /* Simply release invalide/modified buffer, the allocator will
2022 * give it back later */
2023 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
2024 pclass->release_buffer(bpool, buffer);
2025 }
2026 break;
2027 }
2028 default:
2029 g_assert_not_reached();
2030 break;
2031 }
2032 break;
2033
2034 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
2035 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
2036 switch (obj->mode)
2037 {
2038 case GST_V4L2_IO_RW:
2039 /* release back in the pool */
2040 pclass->release_buffer(bpool, buffer);
2041 break;
2042
2043 case GST_V4L2_IO_MMAP:
2044 case GST_V4L2_IO_DMABUF:
2045 case GST_V4L2_IO_USERPTR:
2046 case GST_V4L2_IO_DMABUF_IMPORT:
2047 {
2048 GstAmlV4l2MemoryGroup *group;
2049 guint index;
2050
2051 if (!gst_aml_v4l2_is_buffer_valid(buffer, &group))
2052 {
2053 /* Simply release invalide/modified buffer, the allocator will
2054 * give it back later */
2055 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
2056 pclass->release_buffer(bpool, buffer);
2057 break;
2058 }
2059
2060 index = group->buffer.index;
2061
2062 if (pool->buffers[index] == NULL)
2063 {
2064 GST_LOG_OBJECT(pool, "buffer %u not queued, putting on free list",
2065 index);
2066
2067 /* Remove qdata, this will unmap any map data in userptr */
2068 gst_mini_object_set_qdata(GST_MINI_OBJECT(buffer),
2069 GST_AML_V4L2_IMPORT_QUARK, NULL, NULL);
2070
2071 /* reset to default size */
2072 gst_aml_v4l2_allocator_reset_group(pool->vallocator, group);
2073
2074 /* playback, put the buffer back in the queue to refill later. */
2075 pclass->release_buffer(bpool, buffer);
2076 }
2077 else
2078 {
2079 /* the buffer is queued in the device but maybe not played yet. We just
2080 * leave it there and not make it available for future calls to acquire
2081 * for now. The buffer will be dequeued and reused later. */
2082 GST_LOG_OBJECT(pool, "buffer %u is queued", index);
2083 }
2084 break;
2085 }
2086
2087 default:
2088 g_assert_not_reached();
2089 break;
2090 }
2091 break;
2092
2093 default:
2094 g_assert_not_reached();
2095 break;
2096 }
2097}
2098
2099#ifdef GST_AML_SPEC_FLOW_FOR_VBP
2100static gboolean
2101gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(GstBufferPool *bpool)
2102{
2103 GstFlowReturn ret = GST_FLOW_OK;
2104 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
2105 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
2106 GstAmlV4l2Object *obj = pool->obj;
2107
2108 if (obj->mode == GST_V4L2_IO_DMABUF_IMPORT && pool->other_pool)
2109 {
2110 GstBuffer *src = NULL;
2111 GstBufferPoolAcquireParams params;
2112
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08002113 if (obj->old_other_pool || obj->old_old_other_pool)
2114 {
2115 guint outstanding_buf_num = 0;
2116
2117 outstanding_buf_num = gst_aml_v4l2_object_get_outstanding_capture_buf_num(obj);
2118 GST_DEBUG_OBJECT(pool, "amlmodbuf oop outstanding buf num %d", outstanding_buf_num);
2119 if (outstanding_buf_num != obj->outstanding_buf_num)
2120 {
2121 guint update = 0;
fei.deng7f79b0e2024-07-26 15:18:22 +08002122 GstStructure *config = NULL;
2123 guint size, min_buffers = 0, old_max_buffers = 0;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08002124
2125 if (outstanding_buf_num > obj->outstanding_buf_num)
2126 {
2127 GST_ERROR_OBJECT(pool, "amlmodbuf old other pool recycle buffer error, outstanding from %d to %d", obj->outstanding_buf_num, outstanding_buf_num);
2128 return FALSE;
2129 }
2130 GST_DEBUG_OBJECT(pool, "amlmodbuf oop outstanding buf num from %d reduce to %d", obj->outstanding_buf_num, outstanding_buf_num);
2131
2132 update = obj->outstanding_buf_num - outstanding_buf_num;
fei.deng7f79b0e2024-07-26 15:18:22 +08002133 /*get buffer pool config to calculate max buffer count*/
2134 config = gst_buffer_pool_get_config(pool->other_pool);
2135 if (config) { //have outstanding buffer
2136 if (gst_buffer_pool_config_get_params(config, NULL, &size, &min_buffers, &old_max_buffers) != FALSE) {
2137 //obj->min_buffers is driver request min buffers count
2138 int diff = obj->min_buffers - old_max_buffers;
2139 update = diff >= update ? update : diff;
2140 //all outstanding buffers had freed,increase all left buffer
2141 if (outstanding_buf_num == 0) {
2142 update = obj->min_buffers - old_max_buffers;
2143 }
2144 }
2145 }
2146 if (update > 0 && !gst_buffer_pool_increase_max_num(pool->other_pool, update))
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08002147 {
2148 GST_ERROR_OBJECT(pool, "amlmodbuf update other pool max buffer num error");
2149 return FALSE;
2150 }
2151
2152 obj->outstanding_buf_num = outstanding_buf_num;
2153 }
2154 }
2155
xuesong.jiangae1548e2022-05-06 16:38:46 +08002156 memset(&params, 0, sizeof(GstBufferPoolAcquireParams));
2157 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
fei.denge9458472023-04-18 02:05:48 +00002158 GST_TRACE_OBJECT(pool, "amlmodbuf trace in aml release buf flow ready_to_free_buf_num:%d", pool->ready_to_free_buf_num);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002159 while (pool->ready_to_free_buf_num && gst_buffer_pool_acquire_buffer(pool->other_pool, &src, &params) != GST_FLOW_ERROR && src != NULL)
2160 {
2161 gint i = 0;
2162
fei.denge9458472023-04-18 02:05:48 +00002163 GST_TRACE_OBJECT(pool, "amlmodbuf acquire buf:%p form other pool", src);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002164 for (; i < VIDEO_MAX_FRAME; i++)
2165 {
2166 GST_DEBUG_OBJECT(pool, "amlmodbuf check index:%d", i);
2167 if (pool->read_to_free_bufs[i])
2168 {
2169 GstBuffer *bind_drm_buf = gst_mini_object_get_qdata(GST_MINI_OBJECT(pool->read_to_free_bufs[i]), GST_AML_V4L2_IMPORT_QUARK);
2170 if (bind_drm_buf == NULL)
2171 {
fei.denge9458472023-04-18 02:05:48 +00002172 GST_TRACE_OBJECT(pool, "init flow, bind v4l2 capture buf[%d]:%p with drm buf:%p", i, pool->read_to_free_bufs[i], src);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002173 }
2174 else if (src != bind_drm_buf)
2175 {
fei.denge9458472023-04-18 02:05:48 +00002176 GST_TRACE_OBJECT(pool, "v4l2 capture buf[%d]:%p bind drm buf:%p, not this one:%p, continue match", i, pool->read_to_free_bufs[i], bind_drm_buf, src);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002177 continue;
2178 }
2179
fei.denge9458472023-04-18 02:05:48 +00002180 GST_TRACE_OBJECT(pool, "v4l2 capture buf[%d]:%p found bind drm buf:%p", i, pool->read_to_free_bufs[i], src);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002181 GstFlowReturn isvalid = GST_FLOW_OK;
2182 GstAmlV4l2MemoryGroup *tmp_group = NULL;
2183
2184 // bind_drm_buf= gst_mini_object_steal_qdata(GST_MINI_OBJECT(pool->read_to_free_bufs[i]), GST_AML_V4L2_IMPORT_QUARK);
2185 ret = gst_aml_v4l2_buffer_pool_import_dmabuf(pool, pool->read_to_free_bufs[i], src);
2186 gst_buffer_unref(src);
2187 src = NULL;
2188 isvalid = gst_aml_v4l2_is_buffer_valid(pool->read_to_free_bufs[i], &tmp_group);
2189 if ((ret != GST_FLOW_OK && isvalid) || gst_aml_v4l2_buffer_pool_qbuf(pool, pool->read_to_free_bufs[i], tmp_group) != GST_FLOW_OK)
2190 {
fei.denge9458472023-04-18 02:05:48 +00002191 GST_TRACE_OBJECT(pool, "amlmodbuf go into error flow");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002192 pclass->release_buffer(bpool, pool->read_to_free_bufs[i]);
2193 }
2194 pool->read_to_free_bufs[i] = NULL;
2195 pool->ready_to_free_buf_num--;
fei.denge9458472023-04-18 02:05:48 +00002196 GST_TRACE_OBJECT(pool, "amlmodbuf queued buf:%d, into v4l2 bp", i);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002197 break;
2198 }
2199 }
2200 if (i == VIDEO_MAX_FRAME)
2201 {
2202 GST_ERROR_OBJECT(pool, "drm buf:%p can't match any v4l2 capture buf, error", src);
2203 gst_buffer_unref(src);
2204 src = NULL;
2205 return FALSE;
2206 }
2207 }
fei.denge9458472023-04-18 02:05:48 +00002208 GST_TRACE_OBJECT(pool, "update all free drm buf into v4l2 capture buf pool, now ready_to_free_buf_num:%d", pool->ready_to_free_buf_num);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002209 return TRUE;
2210 }
2211 return FALSE;
2212}
2213#endif
2214
2215static void
2216gst_aml_v4l2_buffer_pool_dispose(GObject *object)
2217{
2218 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(object);
2219
2220 if (pool->vallocator)
2221 gst_object_unref(pool->vallocator);
2222 pool->vallocator = NULL;
2223
2224 if (pool->allocator)
2225 gst_object_unref(pool->allocator);
2226 pool->allocator = NULL;
2227
2228 if (pool->other_pool)
2229 gst_object_unref(pool->other_pool);
2230 pool->other_pool = NULL;
2231
2232 G_OBJECT_CLASS(parent_class)->dispose(object);
2233}
2234
2235static void
2236gst_aml_v4l2_buffer_pool_finalize(GObject *object)
2237{
2238 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(object);
2239
zengliang.lidcd41462024-06-19 16:05:12 +08002240 if (g_list_length (pool->cc_buffer_list) > 0)
2241 {
2242 g_list_free_full (pool->cc_buffer_list, (GDestroyNotify) gst_buffer_unref);
2243 pool->cc_buffer_list = NULL;
2244 }
2245
xuesong.jiangae1548e2022-05-06 16:38:46 +08002246 if (pool->video_fd >= 0)
2247 pool->obj->close(pool->video_fd);
2248
2249 gst_poll_free(pool->poll);
2250
2251 /* This can't be done in dispose method because we must not set pointer
2252 * to NULL as it is part of the v4l2object and dispose could be called
2253 * multiple times */
2254 gst_object_unref(pool->obj->element);
2255
2256 g_cond_clear(&pool->empty_cond);
2257
2258 /* FIXME have we done enough here ? */
2259
2260 G_OBJECT_CLASS(parent_class)->finalize(object);
2261}
2262
2263static void
2264gst_aml_v4l2_buffer_pool_init(GstAmlV4l2BufferPool *pool)
2265{
2266 pool->poll = gst_poll_new(TRUE);
2267 pool->can_poll_device = TRUE;
2268 g_cond_init(&pool->empty_cond);
hanghang.luo3128f102022-08-18 10:36:19 +08002269 GST_OBJECT_LOCK(pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002270 pool->empty = TRUE;
hanghang.luo3128f102022-08-18 10:36:19 +08002271 GST_OBJECT_UNLOCK(pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002272 pool->orphaned = FALSE;
zengliang.lidcd41462024-06-19 16:05:12 +08002273 pool->cc_buffer_list = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002274}
2275
2276static void
2277gst_aml_v4l2_buffer_pool_class_init(GstAmlV4l2BufferPoolClass *klass)
2278{
2279 GObjectClass *object_class = G_OBJECT_CLASS(klass);
2280 GstBufferPoolClass *bufferpool_class = GST_BUFFER_POOL_CLASS(klass);
2281
2282 object_class->dispose = gst_aml_v4l2_buffer_pool_dispose;
2283 object_class->finalize = gst_aml_v4l2_buffer_pool_finalize;
2284
2285 bufferpool_class->start = gst_aml_v4l2_buffer_pool_start;
2286 bufferpool_class->stop = gst_aml_v4l2_buffer_pool_stop;
2287 bufferpool_class->set_config = gst_aml_v4l2_buffer_pool_set_config;
2288 bufferpool_class->alloc_buffer = gst_aml_v4l2_buffer_pool_alloc_buffer;
2289 bufferpool_class->acquire_buffer = gst_aml_v4l2_buffer_pool_acquire_buffer;
2290 bufferpool_class->release_buffer = gst_aml_v4l2_buffer_pool_release_buffer;
2291 bufferpool_class->flush_start = gst_aml_v4l2_buffer_pool_flush_start;
2292 bufferpool_class->flush_stop = gst_aml_v4l2_buffer_pool_flush_stop;
2293
2294 GST_DEBUG_CATEGORY_INIT(amlv4l2bufferpool_debug, "amlv4l2bufferpool", 0,
2295 "V4L2 Buffer Pool");
2296 GST_DEBUG_CATEGORY_GET(CAT_PERFORMANCE, "GST_PERFORMANCE");
2297}
2298
2299/**
2300 * gst_aml_v4l2_buffer_pool_new:
2301 * @obj: the v4l2 object owning the pool
2302 *
2303 * Construct a new buffer pool.
2304 *
2305 * Returns: the new pool, use gst_object_unref() to free resources
2306 */
2307GstBufferPool *
2308gst_aml_v4l2_buffer_pool_new(GstAmlV4l2Object *obj, GstCaps *caps)
2309{
2310 GstAmlV4l2BufferPool *pool;
2311 GstStructure *config;
2312 gchar *name, *parent_name;
2313 gint fd;
2314
2315 fd = obj->dup(obj->video_fd);
2316 if (fd < 0)
2317 goto dup_failed;
2318
2319 /* setting a significant unique name */
2320 parent_name = gst_object_get_name(GST_OBJECT(obj->element));
2321 name = g_strconcat(parent_name, ":", "pool:",
2322 V4L2_TYPE_IS_OUTPUT(obj->type) ? "sink" : "src", NULL);
2323 g_free(parent_name);
2324
2325 pool = (GstAmlV4l2BufferPool *)g_object_new(GST_TYPE_AML_V4L2_BUFFER_POOL,
2326 "name", name, NULL);
2327 g_object_ref_sink(pool);
2328 g_free(name);
2329
2330 gst_poll_fd_init(&pool->pollfd);
2331 pool->pollfd.fd = fd;
2332 gst_poll_add_fd(pool->poll, &pool->pollfd);
2333 if (V4L2_TYPE_IS_OUTPUT(obj->type))
sheng.liu8d18ed22022-05-26 17:28:15 +08002334 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002335 gst_poll_fd_ctl_write(pool->poll, &pool->pollfd, TRUE);
sheng.liu8d18ed22022-05-26 17:28:15 +08002336 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002337 else
sheng.liu8d18ed22022-05-26 17:28:15 +08002338 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002339 gst_poll_fd_ctl_read(pool->poll, &pool->pollfd, TRUE);
sheng.liu8d18ed22022-05-26 17:28:15 +08002340 gst_poll_fd_ctl_pri (pool->poll, &pool->pollfd, TRUE);
2341 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002342
2343 pool->video_fd = fd;
2344 pool->obj = obj;
2345 pool->can_poll_device = TRUE;
2346
2347 pool->vallocator = gst_aml_v4l2_allocator_new(GST_OBJECT(pool), obj);
2348 if (pool->vallocator == NULL)
2349 goto allocator_failed;
2350
2351 gst_object_ref(obj->element);
2352
2353 config = gst_buffer_pool_get_config(GST_BUFFER_POOL_CAST(pool));
2354 gst_buffer_pool_config_set_params(config, caps, obj->info.size, 0, 0);
2355 /* This will simply set a default config, but will not configure the pool
2356 * because min and max are not valid */
hanghang.luo3128f102022-08-18 10:36:19 +08002357 (void)gst_buffer_pool_set_config(GST_BUFFER_POOL_CAST(pool), config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002358
2359 return GST_BUFFER_POOL(pool);
2360
2361 /* ERRORS */
2362dup_failed:
2363{
2364 GST_ERROR("failed to dup fd %d (%s)", errno, g_strerror(errno));
2365 return NULL;
2366}
2367allocator_failed:
2368{
2369 GST_ERROR_OBJECT(pool, "Failed to create V4L2 allocator");
2370 gst_object_unref(pool);
2371 return NULL;
2372}
2373}
2374
2375static GstFlowReturn
2376gst_aml_v4l2_do_read(GstAmlV4l2BufferPool *pool, GstBuffer *buf)
2377{
2378 GstFlowReturn res;
2379 GstAmlV4l2Object *obj = pool->obj;
2380 gint amount;
2381 GstMapInfo map;
2382 gint toread;
2383
2384 toread = obj->info.size;
2385
2386 GST_LOG_OBJECT(pool, "reading %d bytes into buffer %p", toread, buf);
2387
2388 gst_buffer_map(buf, &map, GST_MAP_WRITE);
2389
2390 do
2391 {
2392 if ((res = gst_aml_v4l2_buffer_pool_poll(pool, TRUE)) != GST_FLOW_OK)
2393 goto poll_error;
2394
2395 amount = obj->read(obj->video_fd, map.data, toread);
2396
2397 if (amount == toread)
2398 {
2399 break;
2400 }
2401 else if (amount == -1)
2402 {
2403 if (errno == EAGAIN || errno == EINTR)
2404 {
2405 continue;
2406 }
2407 else
2408 goto read_error;
2409 }
2410 else
2411 {
2412 /* short reads can happen if a signal interrupts the read */
2413 continue;
2414 }
2415 } while (TRUE);
2416
2417 GST_LOG_OBJECT(pool, "read %d bytes", amount);
2418 gst_buffer_unmap(buf, &map);
2419 gst_buffer_resize(buf, 0, amount);
2420
2421 return GST_FLOW_OK;
2422
2423 /* ERRORS */
2424poll_error:
2425{
2426 GST_DEBUG("poll error %s", gst_flow_get_name(res));
2427 goto cleanup;
2428}
2429read_error:
2430{
2431 GST_ELEMENT_ERROR(obj->element, RESOURCE, READ,
2432 (_("Error reading %d bytes from device '%s'."),
2433 toread, obj->videodev),
2434 GST_ERROR_SYSTEM);
2435 res = GST_FLOW_ERROR;
2436 goto cleanup;
2437}
2438cleanup:
2439{
2440 gst_buffer_unmap(buf, &map);
2441 gst_buffer_resize(buf, 0, 0);
2442 return res;
2443}
2444}
2445
2446/**
2447 * gst_aml_v4l2_buffer_pool_process:
2448 * @bpool: a #GstBufferPool
2449 * @buf: a #GstBuffer, maybe be replaced
2450 *
2451 * Process @buf in @bpool. For capture devices, this functions fills @buf with
2452 * data from the device. For output devices, this functions send the contents of
2453 * @buf to the device for playback.
2454 *
2455 * Returns: %GST_FLOW_OK on success.
2456 */
2457GstFlowReturn
2458gst_aml_v4l2_buffer_pool_process(GstAmlV4l2BufferPool *pool, GstBuffer **buf)
2459{
2460 GstFlowReturn ret = GST_FLOW_OK;
2461 GstBufferPool *bpool = GST_BUFFER_POOL_CAST(pool);
2462 GstAmlV4l2Object *obj = pool->obj;
2463
fei.deng594df4b2023-06-26 07:03:29 +00002464 GST_DEBUG_OBJECT(pool, "process buffer %p, buf_pool:%p, v4l2 output pool:%p", *buf, (*buf)->pool, bpool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002465
2466 if (GST_BUFFER_POOL_IS_FLUSHING(pool))
2467 return GST_FLOW_FLUSHING;
2468
2469 switch (obj->type)
2470 {
2471 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2472 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
2473 /* capture */
2474 switch (obj->mode)
2475 {
2476 case GST_V4L2_IO_RW:
2477 /* capture into the buffer */
2478 ret = gst_aml_v4l2_do_read(pool, *buf);
2479 break;
2480
2481 case GST_V4L2_IO_MMAP:
2482 case GST_V4L2_IO_DMABUF:
2483 {
2484 GstBuffer *tmp;
2485
2486 if ((*buf)->pool == bpool)
2487 {
2488 guint num_queued;
2489 gsize size = gst_buffer_get_size(*buf);
2490
2491 /* Legacy M2M devices return empty buffer when drained */
2492 if (size == 0 && GST_AML_V4L2_IS_M2M(obj->device_caps))
2493 goto eos;
2494
2495 if (GST_VIDEO_INFO_FORMAT(&pool->caps_info) !=
2496 GST_VIDEO_FORMAT_ENCODED &&
2497 size < pool->size)
2498 goto buffer_truncated;
2499
2500 num_queued = g_atomic_int_get(&pool->num_queued);
2501 GST_TRACE_OBJECT(pool, "Only %i buffer left in the capture queue.",
2502 num_queued);
2503
2504 /* If we have no more buffer, and can allocate it time to do so */
2505 if (num_queued == 0)
2506 {
2507 if (GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP))
2508 {
2509 ret = gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
2510 if (ret == GST_FLOW_OK)
2511 goto done;
2512 }
2513 }
2514
2515 /* start copying buffers when we are running low on buffers */
2516 if (num_queued < pool->copy_threshold)
2517 {
2518 GstBuffer *copy;
2519
2520 if (GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP))
2521 {
2522 ret = gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
2523 if (ret == GST_FLOW_OK)
2524 goto done;
2525 }
2526
2527 /* copy the buffer */
2528 copy = gst_buffer_copy_region(*buf,
2529 GST_BUFFER_COPY_ALL | GST_BUFFER_COPY_DEEP, 0, -1);
2530 GST_LOG_OBJECT(pool, "copy buffer %p->%p", *buf, copy);
2531
2532 /* and requeue so that we can continue capturing */
2533 gst_buffer_unref(*buf);
2534 *buf = copy;
2535 }
2536
2537 ret = GST_FLOW_OK;
2538 /* nothing, data was inside the buffer when we did _acquire() */
2539 goto done;
2540 }
2541
2542 /* buffer not from our pool, grab a frame and copy it into the target */
2543 if ((ret = gst_aml_v4l2_buffer_pool_dequeue(pool, &tmp, TRUE)) != GST_FLOW_OK)
2544 goto done;
2545
2546 if (obj->dumpframefile)
2547 {
2548 FILE *pFile = fopen(obj->dumpframefile, "ab");
2549 if (pFile)
2550 {
2551 int n = gst_buffer_n_memory(tmp);
2552 int i;
2553 GstMapInfo map_info;
2554 GstMemory *mem;
2555
2556 for (i = 0; i < n; ++i)
2557 {
2558 mem = gst_buffer_peek_memory(tmp, i);
2559 if (gst_memory_map(mem, &map_info, GST_MAP_READ))
2560 {
2561 fwrite(map_info.data, map_info.size, 1, pFile);
2562 gst_memory_unmap(mem, &map_info);
2563 }
2564 }
2565 fclose(pFile);
2566 }
2567 }
2568 /* An empty buffer on capture indicates the end of stream */
2569 if (gst_buffer_get_size(tmp) == 0)
2570 {
2571 gst_aml_v4l2_buffer_pool_release_buffer(bpool, tmp);
2572
2573 /* Legacy M2M devices return empty buffer when drained */
2574 if (GST_AML_V4L2_IS_M2M(obj->device_caps))
2575 goto eos;
2576 }
2577
2578 ret = gst_aml_v4l2_buffer_pool_copy_buffer(pool, *buf, tmp);
hanghang.luo185a3372023-06-06 02:35:33 +00002579 if (obj->mode == GST_V4L2_IO_DMABUF && (GST_VIDEO_FORMAT_NV12 == pool->caps_info.finfo->format || GST_VIDEO_FORMAT_NV21 == pool->caps_info.finfo->format) && gst_buffer_get_size (*buf) > (pool->caps_info.width * pool->caps_info.height * 3 / 2))
2580 {
2581 GST_DEBUG_OBJECT (pool, "resizebuf. format:%d [%d, %d] W:%d, H:%d", pool->caps_info.finfo->format, GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV21, pool->caps_info.width, pool->caps_info.height);
2582 gst_buffer_resize (*buf, 0, pool->caps_info.width * pool->caps_info.height * 3 / 2);
2583 }
2584
xuesong.jiangae1548e2022-05-06 16:38:46 +08002585
2586 /* an queue the buffer again after the copy */
2587 gst_aml_v4l2_buffer_pool_release_buffer(bpool, tmp);
2588
2589 if (ret != GST_FLOW_OK)
2590 goto copy_failed;
2591 break;
2592 }
2593
2594 case GST_V4L2_IO_USERPTR:
2595 {
2596 struct UserPtrData *data;
2597 GstBuffer *tmp;
2598
2599 /* Replace our buffer with downstream allocated buffer */
2600 data = gst_mini_object_steal_qdata(GST_MINI_OBJECT(*buf),
2601 GST_AML_V4L2_IMPORT_QUARK);
2602 tmp = gst_buffer_ref(data->buffer);
2603 _unmap_userptr_frame(data);
2604
2605 /* Now tmp is writable, copy the flags and timestamp */
2606 gst_buffer_copy_into(tmp, *buf,
2607 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2608
2609 gst_buffer_replace(buf, tmp);
2610 gst_buffer_unref(tmp);
2611 break;
2612 }
2613
2614 case GST_V4L2_IO_DMABUF_IMPORT:
2615 {
2616 GstBuffer *tmp;
2617
2618 /* Replace our buffer with downstream allocated buffer */
2619 // tmp = gst_mini_object_steal_qdata(GST_MINI_OBJECT(*buf),
2620 // GST_AML_V4L2_IMPORT_QUARK);
2621 tmp = gst_mini_object_get_qdata(GST_MINI_OBJECT(*buf), GST_AML_V4L2_IMPORT_QUARK);
2622 GST_DEBUG("got v4l2 capture buf:%p, with qdata drm buf:%p", *buf, tmp);
2623
2624 gst_buffer_copy_into(tmp, *buf,
2625 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2626
2627 gst_buffer_replace(buf, tmp);
2628 gst_buffer_unref(tmp);
2629 break;
2630 }
2631
2632 default:
2633 g_assert_not_reached();
2634 break;
2635 }
2636 break;
2637
2638 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
2639 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
2640 /* playback */
2641 switch (obj->mode)
2642 {
2643 case GST_V4L2_IO_RW:
2644 /* FIXME, do write() */
2645 GST_WARNING_OBJECT(pool, "implement write()");
2646 break;
2647
2648 case GST_V4L2_IO_USERPTR:
2649 case GST_V4L2_IO_DMABUF_IMPORT:
2650 case GST_V4L2_IO_DMABUF:
2651 case GST_V4L2_IO_MMAP:
2652 {
2653 GstBuffer *to_queue = NULL;
2654 GstBuffer *buffer;
2655 GstAmlV4l2MemoryGroup *group;
2656 gint index;
2657
2658 if ((*buf)->pool != bpool)
2659 goto copying;
2660
2661 if (!gst_aml_v4l2_is_buffer_valid(*buf, &group))
2662 goto copying;
2663
2664 index = group->buffer.index;
2665
2666 GST_LOG_OBJECT(pool, "processing buffer %i from our pool", index);
2667
2668 if (pool->buffers[index] != NULL)
2669 {
2670 GST_LOG_OBJECT(pool, "buffer %i already queued, copying", index);
2671 goto copying;
2672 }
2673
2674 /* we can queue directly */
2675 to_queue = gst_buffer_ref(*buf);
2676
2677 copying:
2678 if (to_queue == NULL)
2679 {
2680 GstBufferPoolAcquireParams params = {0};
2681
2682 GST_LOG_OBJECT(pool, "alloc buffer from our pool");
2683
2684 /* this can return EOS if all buffers are outstanding which would
2685 * be strange because we would expect the upstream element to have
2686 * allocated them and returned to us.. */
2687 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
2688 ret = gst_buffer_pool_acquire_buffer(bpool, &to_queue, &params);
2689 if (ret != GST_FLOW_OK)
2690 goto acquire_failed;
2691
2692 ret = gst_aml_v4l2_buffer_pool_prepare_buffer(pool, to_queue, *buf);
2693 if (ret != GST_FLOW_OK)
2694 {
2695 gst_buffer_unref(to_queue);
2696 goto prepare_failed;
2697 }
2698
2699 /* retreive the group */
2700 gst_aml_v4l2_is_buffer_valid(to_queue, &group);
2701 }
2702
2703 if ((ret = gst_aml_v4l2_buffer_pool_qbuf(pool, to_queue, group)) != GST_FLOW_OK)
2704 goto queue_failed;
2705
2706 /* if we are not streaming yet (this is the first buffer, start
2707 * streaming now */
2708 if (!gst_aml_v4l2_buffer_pool_streamon(pool))
2709 {
2710 /* don't check return value because qbuf would have failed */
2711 gst_aml_v4l2_is_buffer_valid(to_queue, &group);
2712
2713 /* qbuf has stored to_queue buffer but we are not in
2714 * streaming state, so the flush logic won't be performed.
2715 * To avoid leaks, flush the allocator and restore the queued
2716 * buffer as non-queued */
2717 gst_aml_v4l2_allocator_flush(pool->vallocator);
2718
2719 pool->buffers[group->buffer.index] = NULL;
2720
2721 gst_mini_object_set_qdata(GST_MINI_OBJECT(to_queue),
2722 GST_AML_V4L2_IMPORT_QUARK, NULL, NULL);
2723 gst_buffer_unref(to_queue);
2724 g_atomic_int_add(&pool->num_queued, -1);
2725 goto start_failed;
2726 }
2727
2728 /* Remove our ref, we will still hold this buffer in acquire as needed,
2729 * otherwise the pool will think it is outstanding and will refuse to stop. */
2730 gst_buffer_unref(to_queue);
2731
2732 /* release as many buffer as possible */
2733 while (gst_aml_v4l2_buffer_pool_dequeue(pool, &buffer, FALSE) ==
2734 GST_FLOW_OK)
2735 {
2736 if (buffer->pool == NULL)
2737 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
2738 }
2739
2740 if (g_atomic_int_get(&pool->num_queued) >= pool->min_latency)
2741 {
2742 /* all buffers are queued, try to dequeue one and release it back
2743 * into the pool so that _acquire can get to it again. */
2744 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, &buffer, TRUE);
2745 if (ret == GST_FLOW_OK && buffer->pool == NULL)
2746 /* release the rendered buffer back into the pool. This wakes up any
2747 * thread waiting for a buffer in _acquire(). */
2748 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
2749 }
2750 break;
2751 }
2752 default:
2753 g_assert_not_reached();
2754 break;
2755 }
2756 break;
2757 default:
2758 g_assert_not_reached();
2759 break;
2760 }
2761done:
2762 return ret;
2763
2764 /* ERRORS */
2765copy_failed:
2766{
2767 GST_ERROR_OBJECT(pool, "failed to copy buffer");
2768 return ret;
2769}
2770buffer_truncated:
2771{
2772 GST_WARNING_OBJECT(pool,
2773 "Dropping truncated buffer, this is likely a driver bug.");
2774 gst_buffer_unref(*buf);
2775 *buf = NULL;
2776 return GST_AML_V4L2_FLOW_CORRUPTED_BUFFER;
2777}
2778eos:
2779{
2780 GST_DEBUG_OBJECT(pool, "end of stream reached");
2781 gst_buffer_unref(*buf);
2782 *buf = NULL;
2783 return GST_AML_V4L2_FLOW_LAST_BUFFER;
2784}
2785acquire_failed:
2786{
2787 if (ret == GST_FLOW_FLUSHING)
2788 GST_DEBUG_OBJECT(pool, "flushing");
2789 else
2790 GST_WARNING_OBJECT(pool, "failed to acquire a buffer: %s",
2791 gst_flow_get_name(ret));
2792 return ret;
2793}
2794prepare_failed:
2795{
2796 GST_ERROR_OBJECT(pool, "failed to prepare data");
2797 return ret;
2798}
2799queue_failed:
2800{
2801 GST_ERROR_OBJECT(pool, "failed to queue buffer");
2802 return ret;
2803}
2804start_failed:
2805{
2806 GST_ERROR_OBJECT(pool, "failed to start streaming");
2807 return GST_FLOW_ERROR;
2808}
2809}
2810
2811void gst_aml_v4l2_buffer_pool_set_other_pool(GstAmlV4l2BufferPool *pool,
2812 GstBufferPool *other_pool)
2813{
2814 g_return_if_fail(!gst_buffer_pool_is_active(GST_BUFFER_POOL(pool)));
2815
2816 if (pool->other_pool)
2817 gst_object_unref(pool->other_pool);
2818 pool->other_pool = gst_object_ref(other_pool);
2819}
2820
2821void gst_aml_v4l2_buffer_pool_copy_at_threshold(GstAmlV4l2BufferPool *pool, gboolean copy)
2822{
2823 GST_OBJECT_LOCK(pool);
2824 pool->enable_copy_threshold = copy;
2825 GST_OBJECT_UNLOCK(pool);
2826}
2827
2828gboolean
2829gst_aml_v4l2_buffer_pool_flush(GstBufferPool *bpool)
2830{
2831 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
2832 gboolean ret = TRUE;
2833
2834 gst_aml_v4l2_buffer_pool_streamoff(pool);
2835
2836 if (!V4L2_TYPE_IS_OUTPUT(pool->obj->type))
2837 ret = gst_aml_v4l2_buffer_pool_streamon(pool);
2838
2839 return ret;
2840}
2841
2842void gst_aml_v4l2_buffer_pool_dump_stat(GstAmlV4l2BufferPool *pool, const gchar *file_name, gint try_num)
2843{
2844 const gchar *dump_dir = NULL;
2845 gchar *full_file_name = NULL;
2846 FILE *out = NULL;
2847
2848 dump_dir = g_getenv("GST_DEBUG_DUMP_AMLV4L2DEC_STAT_DIR");
2849 if (G_LIKELY(dump_dir == NULL))
2850 return;
2851
2852 if (!file_name)
2853 {
2854 file_name = "unnamed";
2855 }
2856
2857 full_file_name = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s.stat", dump_dir, file_name);
2858
2859 if ((out = fopen(full_file_name, "w")))
2860 {
2861 GstStructure *config = NULL;
2862 config = gst_buffer_pool_get_config((GstBufferPool *)pool);
2863 if (config)
2864 {
2865 GstCaps *caps;
2866 guint size, min_buffers, max_buffers;
2867 if (gst_buffer_pool_config_get_params(config, &caps, &size, &min_buffers, &max_buffers))
2868 {
2869 gchar *stat_info;
2870
2871 /* set local pool info*/
2872 gint already_queued = 0;
2873 gint ready_to_queue_num = 0;
2874 for (gint i = 0; i < VIDEO_MAX_FRAME; i++)
2875 {
2876 if (pool->buffers[i])
2877 {
2878 already_queued++;
2879 }
2880 if (pool->read_to_free_bufs[i])
2881 {
2882 ready_to_queue_num++;
2883 }
2884 }
2885
2886 stat_info = g_strdup_printf("local pool | size:%d, min_bufs:%d, max_bufs:%d | queued:%d, allocated:%d | already_queued:%d, ready_to_queue:%d | try_num:%d\n",
2887 size, min_buffers, max_buffers,
2888 pool->num_queued, pool->num_allocated,
2889 already_queued, ready_to_queue_num, try_num);
2890 fputs(stat_info, out);
2891 g_free(stat_info);
2892
2893 /* set other pool info*/
2894 if (pool->other_pool)
2895 {
2896 GstStructure *other_config = NULL;
2897 other_config = gst_buffer_pool_get_config((GstBufferPool *)pool);
2898 if (other_config)
2899 {
2900 GstCaps *other_caps;
2901 guint other_size, other_min_buffers, other_max_buffers;
2902 if (gst_buffer_pool_config_get_params(config, &other_caps, &other_size, &other_min_buffers, &other_max_buffers))
2903 {
2904 stat_info = g_strdup_printf("other pool | size:%d, min_bufs:%d, max_bufs:%d\n",
2905 other_size, other_min_buffers, other_max_buffers);
2906
2907 // TODO:GstBufferPool中没有获取outstanding的接口,所以这里没有统计otherpool中在用buffer的状态,后续需要修改gstreamer-1.0中code新增接口
2908 fputs(stat_info, out);
2909 g_free(stat_info);
2910 }
2911 }
2912 }
2913 GST_INFO("wrote amlv4l2 bufferpool stat to : '%s' succ", full_file_name);
2914 }
2915 }
2916 else
2917 {
2918 GST_WARNING("Failed to get config for pool:%p", pool);
2919 }
2920 fclose(out);
2921 }
2922 else
2923 {
2924 GST_WARNING("Failed to open file '%s' for writing: %s", full_file_name, g_strerror(errno));
2925 }
2926 g_free(full_file_name);
2927}