blob: b7cc3b58e66a3795bc4edf1ffbc3d1c50b6058d5 [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;
bo.xiaob6afda52024-08-02 16:08:30 +08001543 GstFlowReturn ret = GST_AML_V4L2_FLOW_UNKNOWN_EVENT;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001544
1545 memset(&evt, 0x00, sizeof(struct v4l2_event));
1546 if (v4l2object->ioctl(pool->video_fd, VIDIOC_DQEVENT, &evt) < 0)
1547 goto dqevent_failed;
1548
1549 switch (evt.type)
1550 {
1551 case V4L2_EVENT_SOURCE_CHANGE:
sheng.liu8d18ed22022-05-26 17:28:15 +08001552 if (evt.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION)
bo.xiaoe978c3b2024-08-01 20:57:15 +08001553 ret = GST_AML_V4L2_FLOW_SOURCE_CHANGE;
1554 else
1555 {
1556 GST_WARNING_OBJECT (pool, "Unknown source change 0x%x - skipped", evt.u.src_change.changes);
bo.xiaob6afda52024-08-02 16:08:30 +08001557 ret = GST_AML_V4L2_FLOW_UNKNOWN_EVENT;
bo.xiaoe978c3b2024-08-01 20:57:15 +08001558 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001559 break;
1560 case V4L2_EVENT_EOS:
bo.xiaoe978c3b2024-08-01 20:57:15 +08001561 ret = GST_AML_V4L2_FLOW_LAST_BUFFER;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001562 break;
zengliang.lidcd41462024-06-19 16:05:12 +08001563 case V4L2_EVENT_PRIVATE_EXT_REPORT_DECINFO:
1564 if (evt.id == AML_DECINFO_EVENT_CC)
1565 {
1566 struct v4l2_ext_control control;
1567 struct v4l2_ext_controls ctrls;
1568 struct vdec_common_s vdec_comm;
1569 char cc_data[MAX_CC_LEN] = {0};
1570
1571 memset(&ctrls, 0, sizeof(ctrls));
1572 memset(&control, 0, sizeof(control));
1573 memset(&vdec_comm, 0, sizeof(vdec_comm));
1574
1575 vdec_comm.type = AML_DECINFO_GET_CC_TYPE;
1576 vdec_comm.u.usd_param.data = (void *)cc_data;
1577 vdec_comm.u.usd_param.data_size = MAX_CC_LEN;
1578
1579 control.ptr = &vdec_comm;
1580 control.id = AML_V4L2_GET_DECINFO_SET;
1581 control.size = sizeof(struct vdec_common_s);
1582
1583 ctrls.count = 1;
1584 ctrls.controls = &control;
1585
1586 if (v4l2object->ioctl (pool->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
1587 {
1588 GST_DEBUG("VIDIOC_S_EXT_CTRLS fail");
1589 }
1590 else
1591 {
1592 if (v4l2object->ioctl (pool->video_fd, VIDIOC_G_EXT_CTRLS, &ctrls) == 0)
1593 {
1594 GstBuffer *cc_buffer = gst_buffer_new ();
1595 GstMemory *mem = gst_allocator_alloc (NULL, MAX_CC_LEN, NULL);
1596 gst_buffer_insert_memory (cc_buffer, -1, mem);
1597 gsize cc_size = gst_buffer_fill (cc_buffer, 0, vdec_comm.u.usd_param.data, vdec_comm.u.usd_param.data_size);
1598 GST_DEBUG("copy cc data size:%d",cc_size);
1599 cc_buffer->pts = vdec_comm.u.usd_param.meta_data.timestamp;
1600 pool->cc_buffer_list = g_list_append (pool->cc_buffer_list,cc_buffer);
1601 GST_DEBUG("cc_buffer_list size:%d",g_list_length(pool->cc_buffer_list));
1602 #if 0
1603 //dump decoder metadata
1604 GST_DEBUG("cc pack pts:%lld",vdec_comm.u.usd_param.meta_data.timestamp);
1605 int fd=open("/data/test/cc0.data",O_RDWR |O_CREAT|O_APPEND,0777);
1606 write(fd,vdec_comm.u.usd_param.data,vdec_comm.u.usd_param.data_size);
1607 close(fd);
1608 #endif
1609 }
1610 else
1611 {
1612 GST_DEBUG("VIDIOC_G_EXT_CTRLS fail");
1613 }
1614 }
bo.xiaoe978c3b2024-08-01 20:57:15 +08001615 ret = GST_AML_V4L2_FLOW_CC_DATA;
1616 }
1617 else
1618 {
1619 GST_WARNING_OBJECT (pool, "Unknown DECINFO 0x%x - skipped", evt.id);
bo.xiaob6afda52024-08-02 16:08:30 +08001620 ret = GST_AML_V4L2_FLOW_UNKNOWN_EVENT;
zengliang.lidcd41462024-06-19 16:05:12 +08001621 }
1622 break;
fei.dengaf682762024-06-24 19:06:03 +08001623 case V4L2_EVENT_PRIVATE_EXT_REPORT_ERROR_FRAME:
1624 {
1625 guint64 pts = 0;
1626 memcpy(&pts, &(evt.u.data[0]), sizeof(guint64));
1627 v4l2object->num_error_frames += 1;
1628 GST_WARNING_OBJECT (pool, "decoding video frame error,pts:%" GST_TIME_FORMAT ",total %d",
1629 GST_TIME_ARGS(pts),v4l2object->num_error_frames);
bo.xiaoe978c3b2024-08-01 20:57:15 +08001630 ret = GST_AML_V4L2_FLOW_DECODING_ERROR;
fei.dengaf682762024-06-24 19:06:03 +08001631 } break;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001632 default:
bo.xiaoe978c3b2024-08-01 20:57:15 +08001633 GST_WARNING_OBJECT (pool, "Unknown evt.type 0x%x - skipped", evt.type);
bo.xiaob6afda52024-08-02 16:08:30 +08001634 ret = GST_AML_V4L2_FLOW_UNKNOWN_EVENT;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001635 break;
1636 }
1637
bo.xiaoe978c3b2024-08-01 20:57:15 +08001638 return ret;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001639
1640 /* ERRORS */
1641dqevent_failed:
1642{
1643 return GST_FLOW_ERROR;
1644}
1645}
1646
1647static GstFlowReturn
1648gst_aml_v4l2_buffer_pool_dqbuf(GstAmlV4l2BufferPool *pool, GstBuffer **buffer,
1649 gboolean wait)
1650{
1651 GstFlowReturn res;
1652 GstBuffer *outbuf = NULL;
1653 GstAmlV4l2Object *obj = pool->obj;
1654 GstClockTime timestamp;
1655 GstAmlV4l2MemoryGroup *group;
1656 GstVideoMeta *vmeta;
1657 gsize size;
1658 gint i;
1659
1660 res = gst_aml_v4l2_allocator_dqbuf(pool->vallocator, &group);
1661 if (res == GST_FLOW_EOS)
1662 goto eos;
1663 if (res != GST_FLOW_OK)
1664 goto dqbuf_failed;
1665
1666 /* get our GstBuffer with that index from the pool, if the buffer was
1667 * outstanding we have a serious problem.
1668 */
1669 outbuf = pool->buffers[group->buffer.index];
1670 if (outbuf == NULL)
1671 goto no_buffer;
1672
1673 /* mark the buffer outstanding */
1674 pool->buffers[group->buffer.index] = NULL;
1675 if (g_atomic_int_dec_and_test(&pool->num_queued))
1676 {
1677 GST_OBJECT_LOCK(pool);
1678 pool->empty = TRUE;
1679 GST_OBJECT_UNLOCK(pool);
1680 }
1681
xuesong.jiang08cb00d2023-05-17 09:18:48 +00001682 if (-1== group->buffer.timestamp.tv_sec)
1683 timestamp = GST_CLOCK_TIME_NONE;
1684 else
1685 timestamp = GST_TIMEVAL_TO_TIME(group->buffer.timestamp);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001686
1687 size = 0;
1688 vmeta = gst_buffer_get_video_meta(outbuf);
1689 for (i = 0; i < group->n_mem; i++)
1690 {
1691 GST_LOG_OBJECT(pool,
1692 "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,
1693 group->buffer.sequence, group->buffer.index, group->mem[i],
1694 group->planes[i].bytesused, i, group->buffer.flags,
1695 GST_TIME_ARGS(timestamp), pool->num_queued, outbuf);
1696
1697 if (vmeta)
1698 {
1699 vmeta->offset[i] = size;
1700 size += gst_memory_get_sizes(group->mem[i], NULL, NULL);
1701 }
1702 }
1703
1704 /* Ignore timestamp and field for OUTPUT device */
1705 if (V4L2_TYPE_IS_OUTPUT(obj->type))
1706 goto done;
1707
1708 /* Check for driver bug in reporting feild */
1709 if (group->buffer.field == V4L2_FIELD_ANY)
1710 {
1711 /* Only warn once to avoid the spamming */
1712#ifndef GST_DISABLE_GST_DEBUG
1713 if (!pool->has_warned_on_buggy_field)
1714 {
1715 pool->has_warned_on_buggy_field = TRUE;
1716 GST_WARNING_OBJECT(pool,
1717 "Driver should never set v4l2_buffer.field to ANY");
1718 }
1719#endif
1720
1721 /* Use the value from the format (works for UVC bug) */
1722 group->buffer.field = obj->format.fmt.pix.field;
1723
1724 /* If driver also has buggy S_FMT, assume progressive */
1725 if (group->buffer.field == V4L2_FIELD_ANY)
1726 {
1727#ifndef GST_DISABLE_GST_DEBUG
1728 if (!pool->has_warned_on_buggy_field)
1729 {
1730 pool->has_warned_on_buggy_field = TRUE;
1731 GST_WARNING_OBJECT(pool,
1732 "Driver should never set v4l2_format.pix.field to ANY");
1733 }
1734#endif
1735
1736 group->buffer.field = V4L2_FIELD_NONE;
1737 }
1738 }
1739
1740 /* set top/bottom field first if v4l2_buffer has the information */
1741 switch (group->buffer.field)
1742 {
1743 case V4L2_FIELD_NONE:
1744 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1745 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1746 break;
1747 case V4L2_FIELD_INTERLACED_TB:
1748 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1749 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1750 break;
1751 case V4L2_FIELD_INTERLACED_BT:
1752 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1753 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1754 break;
1755 case V4L2_FIELD_INTERLACED:
1756 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1757 if (obj->tv_norm == V4L2_STD_NTSC_M ||
1758 obj->tv_norm == V4L2_STD_NTSC_M_JP ||
1759 obj->tv_norm == V4L2_STD_NTSC_M_KR)
1760 {
1761 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1762 }
1763 else
1764 {
1765 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1766 }
1767 break;
1768 default:
1769 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1770 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1771 GST_FIXME_OBJECT(pool,
1772 "Unhandled enum v4l2_field %d - treating as progressive",
1773 group->buffer.field);
1774 break;
1775 }
1776
1777 if (GST_VIDEO_INFO_FORMAT(&obj->info) == GST_VIDEO_FORMAT_ENCODED)
1778 {
1779 if ((group->buffer.flags & V4L2_BUF_FLAG_KEYFRAME) ||
1780 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_MJPEG ||
1781 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_JPEG ||
1782 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_PJPG)
1783 GST_BUFFER_FLAG_UNSET(outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1784 else
1785 GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1786 }
1787
1788 if (group->buffer.flags & V4L2_BUF_FLAG_ERROR)
1789 GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_FLAG_CORRUPTED);
1790
1791 GST_BUFFER_TIMESTAMP(outbuf) = timestamp;
1792 GST_BUFFER_OFFSET(outbuf) = group->buffer.sequence;
1793 GST_BUFFER_OFFSET_END(outbuf) = group->buffer.sequence + 1;
1794
1795done:
1796 *buffer = outbuf;
fei.deng594df4b2023-06-26 07:03:29 +00001797 if ( (group->buffer.flags & V4L2_BUF_FLAG_LAST) &&(group->buffer.bytesused == 0) )
1798 {
1799 GST_DEBUG_OBJECT (pool,"dequeued empty buffer");
1800 GST_BUFFER_FLAG_SET(*buffer, GST_AML_V4L2_BUFFER_FLAG_LAST_EMPTY);
1801 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001802
1803 if (!V4L2_TYPE_IS_OUTPUT(obj->type))
1804 {
1805 gst_aml_v4l2_buffer_pool_dump_stat(pool, GST_DUMP_CAPTURE_BP_STAT_FILENAME, 0);
1806 }
1807
1808 return res;
1809
1810 /* ERRORS */
1811eos:
1812{
1813 return GST_FLOW_EOS;
1814}
1815dqbuf_failed:
1816{
1817 return GST_FLOW_ERROR;
1818}
1819no_buffer:
1820{
1821 GST_ERROR_OBJECT(pool, "No free buffer found in the pool at index %d.",
1822 group->buffer.index);
1823 return GST_FLOW_ERROR;
1824}
1825}
1826
1827static GstFlowReturn
1828gst_aml_v4l2_buffer_pool_dequeue(GstAmlV4l2BufferPool *pool, GstBuffer **buffer,
1829 gboolean wait)
1830{
1831 GstFlowReturn res;
1832 GstAmlV4l2Object *obj = pool->obj;
1833
1834 if ((res = gst_aml_v4l2_buffer_pool_poll(pool, wait)) != GST_FLOW_OK)
1835 goto poll_failed;
1836
1837 if (obj->can_wait_event && gst_poll_fd_can_read_pri(pool->poll, &pool->pollfd))
1838 {
sheng.liu8d18ed22022-05-26 17:28:15 +08001839 GstFlowReturn res_event = gst_aml_v4l2_buffer_pool_dqevent(pool);
1840 if (res_event != GST_FLOW_OK)
hanghang.luob216ac42023-05-12 02:56:54 +00001841 {
1842 /* when drive V4l2 receive cmd_stop, it will finish current decoding frame, then creat
1843 * a EOS event and a empty buff. if gstreamer dq EOS event first ,the last frame will be drop,
1844 * this a question
1845 */
1846 if (res_event == GST_AML_V4L2_FLOW_LAST_BUFFER)
1847 {
1848 GST_DEBUG_OBJECT(pool," reiceive EOS event, drop it");
1849 }
1850 else
1851 return res_event;
1852 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001853 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001854 if (res == GST_FLOW_CUSTOM_SUCCESS)
1855 {
1856 GST_LOG_OBJECT(pool, "nothing to dequeue");
1857 *buffer = NULL;
1858 return res;
1859 }
1860
1861 GST_LOG_OBJECT(pool, "dequeueing a buffer");
1862 return gst_aml_v4l2_buffer_pool_dqbuf(pool, buffer, wait);
1863
1864 /* ERRORS */
1865poll_failed:
1866{
1867 GST_DEBUG_OBJECT(pool, "poll error %s", gst_flow_get_name(res));
1868 return res;
1869}
1870}
1871
1872static GstFlowReturn
1873gst_aml_v4l2_buffer_pool_acquire_buffer(GstBufferPool *bpool, GstBuffer **buffer,
1874 GstBufferPoolAcquireParams *params)
1875{
1876 GstFlowReturn ret;
1877 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1878 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
1879 GstAmlV4l2Object *obj = pool->obj;
1880
1881 GST_DEBUG_OBJECT(pool, "acquire");
1882
1883 /* If this is being called to resurrect a lost buffer */
1884 if (params && params->flags & GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT)
1885 {
1886 ret = pclass->acquire_buffer(bpool, buffer, params);
1887 goto done;
1888 }
1889
1890 switch (obj->type)
1891 {
1892 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1893 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1894 /* capture, This function should return a buffer with new captured data */
1895 switch (obj->mode)
1896 {
1897 case GST_V4L2_IO_RW:
1898 {
1899 /* take empty buffer from the pool */
1900 ret = pclass->acquire_buffer(bpool, buffer, params);
1901 break;
1902 }
1903 case GST_V4L2_IO_DMABUF:
1904 case GST_V4L2_IO_MMAP:
1905 case GST_V4L2_IO_USERPTR:
xuesong.jiang3df0f7b2022-11-29 14:52:45 +08001906 {
1907 /* just dequeue a buffer, we basically use the queue of v4l2 as the
1908 * storage for our buffers. This function does poll first so we can
1909 * interrupt it fine. */
1910 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, TRUE);
1911
1912 break;
1913 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001914 case GST_V4L2_IO_DMABUF_IMPORT:
1915 {
1916#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1917 GST_DEBUG_OBJECT(pool, "amlmodbuf return free buf before acquire buf");
1918 gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(bpool);
1919 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, FALSE);
xuesong.jiang22a9b112023-05-24 09:01:59 +00001920 GST_DEBUG_OBJECT(pool, "amlmodbuf dequeue return ret:%d", ret);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001921#else
1922 /* just dequeue a buffer, we basically use the queue of v4l2 as the
1923 * storage for our buffers. This function does poll first so we can
1924 * interrupt it fine. */
1925 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, TRUE);
1926#endif
1927 break;
1928 }
1929 default:
1930 ret = GST_FLOW_ERROR;
1931 g_assert_not_reached();
1932 break;
1933 }
1934 break;
1935
1936 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1937 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1938 /* playback, This function should return an empty buffer */
1939 switch (obj->mode)
1940 {
1941 case GST_V4L2_IO_RW:
1942 /* get an empty buffer */
1943 ret = pclass->acquire_buffer(bpool, buffer, params);
1944 break;
1945
1946 case GST_V4L2_IO_MMAP:
1947 case GST_V4L2_IO_DMABUF:
1948 case GST_V4L2_IO_USERPTR:
1949 case GST_V4L2_IO_DMABUF_IMPORT:
1950 /* get a free unqueued buffer */
1951 ret = pclass->acquire_buffer(bpool, buffer, params);
1952 break;
1953
1954 default:
1955 ret = GST_FLOW_ERROR;
1956 g_assert_not_reached();
1957 break;
1958 }
1959 break;
1960
1961 default:
1962 ret = GST_FLOW_ERROR;
1963 g_assert_not_reached();
1964 break;
1965 }
1966done:
1967 return ret;
1968}
1969
1970static void
1971gst_aml_v4l2_buffer_pool_release_buffer(GstBufferPool *bpool, GstBuffer *buffer)
1972{
1973 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1974 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
1975 GstAmlV4l2Object *obj = pool->obj;
1976
1977 GST_DEBUG_OBJECT(pool, "release buffer %p", buffer);
1978
1979 /* If the buffer's pool has been orphaned, dispose of it so that
1980 * the pool resources can be freed */
1981 if (pool->orphaned)
1982 {
1983 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
1984 pclass->release_buffer(bpool, buffer);
1985 return;
1986 }
1987
1988 switch (obj->type)
1989 {
1990 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1991 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1992 /* capture, put the buffer back in the queue so that we can refill it
1993 * later. */
1994 switch (obj->mode)
1995 {
1996 case GST_V4L2_IO_RW:
1997 /* release back in the pool */
1998 pclass->release_buffer(bpool, buffer);
1999 break;
2000
2001 case GST_V4L2_IO_DMABUF:
2002 case GST_V4L2_IO_MMAP:
2003 case GST_V4L2_IO_USERPTR:
2004 case GST_V4L2_IO_DMABUF_IMPORT:
2005 {
2006 GstAmlV4l2MemoryGroup *group;
2007 if (gst_aml_v4l2_is_buffer_valid(buffer, &group))
2008 {
2009 GstFlowReturn ret = GST_FLOW_OK;
2010
2011 gst_aml_v4l2_allocator_reset_group(pool->vallocator, group);
2012
2013#ifdef GST_AML_SPEC_FLOW_FOR_VBP
2014 GST_DEBUG_OBJECT(pool, "amlmodbuf trace in add flow with buf:%p index:%d", buffer, group->buffer.index);
2015 pool->read_to_free_bufs[group->buffer.index] = buffer;
2016 pool->ready_to_free_buf_num++;
2017 if (gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(bpool))
2018 {
2019 GST_DEBUG_OBJECT(pool, "amlmodbuf execute aml code logic, skip the following flow");
2020 return;
2021 }
2022#endif
2023 /* queue back in the device */
2024 if (pool->other_pool)
2025 ret = gst_aml_v4l2_buffer_pool_prepare_buffer(pool, buffer, NULL);
2026 if (ret != GST_FLOW_OK ||
2027 gst_aml_v4l2_buffer_pool_qbuf(pool, buffer, group) != GST_FLOW_OK)
2028 pclass->release_buffer(bpool, buffer);
2029 }
2030 else
2031 {
2032 /* Simply release invalide/modified buffer, the allocator will
2033 * give it back later */
2034 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
2035 pclass->release_buffer(bpool, buffer);
2036 }
2037 break;
2038 }
2039 default:
2040 g_assert_not_reached();
2041 break;
2042 }
2043 break;
2044
2045 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
2046 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
2047 switch (obj->mode)
2048 {
2049 case GST_V4L2_IO_RW:
2050 /* release back in the pool */
2051 pclass->release_buffer(bpool, buffer);
2052 break;
2053
2054 case GST_V4L2_IO_MMAP:
2055 case GST_V4L2_IO_DMABUF:
2056 case GST_V4L2_IO_USERPTR:
2057 case GST_V4L2_IO_DMABUF_IMPORT:
2058 {
2059 GstAmlV4l2MemoryGroup *group;
2060 guint index;
2061
2062 if (!gst_aml_v4l2_is_buffer_valid(buffer, &group))
2063 {
2064 /* Simply release invalide/modified buffer, the allocator will
2065 * give it back later */
2066 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
2067 pclass->release_buffer(bpool, buffer);
2068 break;
2069 }
2070
2071 index = group->buffer.index;
2072
2073 if (pool->buffers[index] == NULL)
2074 {
2075 GST_LOG_OBJECT(pool, "buffer %u not queued, putting on free list",
2076 index);
2077
2078 /* Remove qdata, this will unmap any map data in userptr */
2079 gst_mini_object_set_qdata(GST_MINI_OBJECT(buffer),
2080 GST_AML_V4L2_IMPORT_QUARK, NULL, NULL);
2081
2082 /* reset to default size */
2083 gst_aml_v4l2_allocator_reset_group(pool->vallocator, group);
2084
2085 /* playback, put the buffer back in the queue to refill later. */
2086 pclass->release_buffer(bpool, buffer);
2087 }
2088 else
2089 {
2090 /* the buffer is queued in the device but maybe not played yet. We just
2091 * leave it there and not make it available for future calls to acquire
2092 * for now. The buffer will be dequeued and reused later. */
2093 GST_LOG_OBJECT(pool, "buffer %u is queued", index);
2094 }
2095 break;
2096 }
2097
2098 default:
2099 g_assert_not_reached();
2100 break;
2101 }
2102 break;
2103
2104 default:
2105 g_assert_not_reached();
2106 break;
2107 }
2108}
2109
2110#ifdef GST_AML_SPEC_FLOW_FOR_VBP
2111static gboolean
2112gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(GstBufferPool *bpool)
2113{
2114 GstFlowReturn ret = GST_FLOW_OK;
2115 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
2116 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
2117 GstAmlV4l2Object *obj = pool->obj;
2118
2119 if (obj->mode == GST_V4L2_IO_DMABUF_IMPORT && pool->other_pool)
2120 {
2121 GstBuffer *src = NULL;
2122 GstBufferPoolAcquireParams params;
2123
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08002124 if (obj->old_other_pool || obj->old_old_other_pool)
2125 {
2126 guint outstanding_buf_num = 0;
2127
2128 outstanding_buf_num = gst_aml_v4l2_object_get_outstanding_capture_buf_num(obj);
2129 GST_DEBUG_OBJECT(pool, "amlmodbuf oop outstanding buf num %d", outstanding_buf_num);
2130 if (outstanding_buf_num != obj->outstanding_buf_num)
2131 {
2132 guint update = 0;
fei.deng7f79b0e2024-07-26 15:18:22 +08002133 GstStructure *config = NULL;
2134 guint size, min_buffers = 0, old_max_buffers = 0;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08002135
2136 if (outstanding_buf_num > obj->outstanding_buf_num)
2137 {
2138 GST_ERROR_OBJECT(pool, "amlmodbuf old other pool recycle buffer error, outstanding from %d to %d", obj->outstanding_buf_num, outstanding_buf_num);
2139 return FALSE;
2140 }
2141 GST_DEBUG_OBJECT(pool, "amlmodbuf oop outstanding buf num from %d reduce to %d", obj->outstanding_buf_num, outstanding_buf_num);
2142
2143 update = obj->outstanding_buf_num - outstanding_buf_num;
fei.deng7f79b0e2024-07-26 15:18:22 +08002144 /*get buffer pool config to calculate max buffer count*/
2145 config = gst_buffer_pool_get_config(pool->other_pool);
2146 if (config) { //have outstanding buffer
2147 if (gst_buffer_pool_config_get_params(config, NULL, &size, &min_buffers, &old_max_buffers) != FALSE) {
2148 //obj->min_buffers is driver request min buffers count
2149 int diff = obj->min_buffers - old_max_buffers;
2150 update = diff >= update ? update : diff;
2151 //all outstanding buffers had freed,increase all left buffer
2152 if (outstanding_buf_num == 0) {
2153 update = obj->min_buffers - old_max_buffers;
2154 }
2155 }
2156 }
2157 if (update > 0 && !gst_buffer_pool_increase_max_num(pool->other_pool, update))
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08002158 {
2159 GST_ERROR_OBJECT(pool, "amlmodbuf update other pool max buffer num error");
2160 return FALSE;
2161 }
2162
2163 obj->outstanding_buf_num = outstanding_buf_num;
2164 }
2165 }
2166
xuesong.jiangae1548e2022-05-06 16:38:46 +08002167 memset(&params, 0, sizeof(GstBufferPoolAcquireParams));
2168 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
bo.xiaob6afda52024-08-02 16:08:30 +08002169 GST_DEBUG_OBJECT(pool, "amlmodbuf ready_to_free_buf_num:%d", pool->ready_to_free_buf_num);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002170 while (pool->ready_to_free_buf_num && gst_buffer_pool_acquire_buffer(pool->other_pool, &src, &params) != GST_FLOW_ERROR && src != NULL)
2171 {
2172 gint i = 0;
2173
bo.xiaob6afda52024-08-02 16:08:30 +08002174 GST_TRACE_OBJECT(pool, "amlmodbuf acquire buf:%p form other pool", src);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002175 for (; i < VIDEO_MAX_FRAME; i++)
2176 {
bo.xiaob6afda52024-08-02 16:08:30 +08002177 GST_TRACE_OBJECT(pool, "amlmodbuf check index:%d", i);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002178 if (pool->read_to_free_bufs[i])
2179 {
2180 GstBuffer *bind_drm_buf = gst_mini_object_get_qdata(GST_MINI_OBJECT(pool->read_to_free_bufs[i]), GST_AML_V4L2_IMPORT_QUARK);
2181 if (bind_drm_buf == NULL)
2182 {
bo.xiaob6afda52024-08-02 16:08:30 +08002183 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 +08002184 }
2185 else if (src != bind_drm_buf)
2186 {
bo.xiaob6afda52024-08-02 16:08:30 +08002187 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 +08002188 continue;
2189 }
2190
bo.xiaob6afda52024-08-02 16:08:30 +08002191 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 +08002192 GstFlowReturn isvalid = GST_FLOW_OK;
2193 GstAmlV4l2MemoryGroup *tmp_group = NULL;
2194
2195 // bind_drm_buf= gst_mini_object_steal_qdata(GST_MINI_OBJECT(pool->read_to_free_bufs[i]), GST_AML_V4L2_IMPORT_QUARK);
2196 ret = gst_aml_v4l2_buffer_pool_import_dmabuf(pool, pool->read_to_free_bufs[i], src);
2197 gst_buffer_unref(src);
2198 src = NULL;
2199 isvalid = gst_aml_v4l2_is_buffer_valid(pool->read_to_free_bufs[i], &tmp_group);
2200 if ((ret != GST_FLOW_OK && isvalid) || gst_aml_v4l2_buffer_pool_qbuf(pool, pool->read_to_free_bufs[i], tmp_group) != GST_FLOW_OK)
2201 {
bo.xiaob6afda52024-08-02 16:08:30 +08002202 GST_ERROR_OBJECT(pool, "amlmodbuf go into error flow");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002203 pclass->release_buffer(bpool, pool->read_to_free_bufs[i]);
2204 }
2205 pool->read_to_free_bufs[i] = NULL;
2206 pool->ready_to_free_buf_num--;
bo.xiaob6afda52024-08-02 16:08:30 +08002207 GST_TRACE_OBJECT(pool, "amlmodbuf queued buf:%d, into v4l2 bp", i);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002208 break;
2209 }
2210 }
2211 if (i == VIDEO_MAX_FRAME)
2212 {
2213 GST_ERROR_OBJECT(pool, "drm buf:%p can't match any v4l2 capture buf, error", src);
2214 gst_buffer_unref(src);
2215 src = NULL;
2216 return FALSE;
2217 }
2218 }
bo.xiaob6afda52024-08-02 16:08:30 +08002219 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 +08002220 return TRUE;
2221 }
2222 return FALSE;
2223}
2224#endif
2225
2226static void
2227gst_aml_v4l2_buffer_pool_dispose(GObject *object)
2228{
2229 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(object);
2230
2231 if (pool->vallocator)
2232 gst_object_unref(pool->vallocator);
2233 pool->vallocator = NULL;
2234
2235 if (pool->allocator)
2236 gst_object_unref(pool->allocator);
2237 pool->allocator = NULL;
2238
2239 if (pool->other_pool)
2240 gst_object_unref(pool->other_pool);
2241 pool->other_pool = NULL;
2242
2243 G_OBJECT_CLASS(parent_class)->dispose(object);
2244}
2245
2246static void
2247gst_aml_v4l2_buffer_pool_finalize(GObject *object)
2248{
2249 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(object);
2250
zengliang.lidcd41462024-06-19 16:05:12 +08002251 if (g_list_length (pool->cc_buffer_list) > 0)
2252 {
2253 g_list_free_full (pool->cc_buffer_list, (GDestroyNotify) gst_buffer_unref);
2254 pool->cc_buffer_list = NULL;
2255 }
2256
xuesong.jiangae1548e2022-05-06 16:38:46 +08002257 if (pool->video_fd >= 0)
2258 pool->obj->close(pool->video_fd);
2259
2260 gst_poll_free(pool->poll);
2261
2262 /* This can't be done in dispose method because we must not set pointer
2263 * to NULL as it is part of the v4l2object and dispose could be called
2264 * multiple times */
2265 gst_object_unref(pool->obj->element);
2266
2267 g_cond_clear(&pool->empty_cond);
2268
2269 /* FIXME have we done enough here ? */
2270
2271 G_OBJECT_CLASS(parent_class)->finalize(object);
2272}
2273
2274static void
2275gst_aml_v4l2_buffer_pool_init(GstAmlV4l2BufferPool *pool)
2276{
2277 pool->poll = gst_poll_new(TRUE);
2278 pool->can_poll_device = TRUE;
2279 g_cond_init(&pool->empty_cond);
hanghang.luo3128f102022-08-18 10:36:19 +08002280 GST_OBJECT_LOCK(pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002281 pool->empty = TRUE;
hanghang.luo3128f102022-08-18 10:36:19 +08002282 GST_OBJECT_UNLOCK(pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002283 pool->orphaned = FALSE;
zengliang.lidcd41462024-06-19 16:05:12 +08002284 pool->cc_buffer_list = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002285}
2286
2287static void
2288gst_aml_v4l2_buffer_pool_class_init(GstAmlV4l2BufferPoolClass *klass)
2289{
2290 GObjectClass *object_class = G_OBJECT_CLASS(klass);
2291 GstBufferPoolClass *bufferpool_class = GST_BUFFER_POOL_CLASS(klass);
2292
2293 object_class->dispose = gst_aml_v4l2_buffer_pool_dispose;
2294 object_class->finalize = gst_aml_v4l2_buffer_pool_finalize;
2295
2296 bufferpool_class->start = gst_aml_v4l2_buffer_pool_start;
2297 bufferpool_class->stop = gst_aml_v4l2_buffer_pool_stop;
2298 bufferpool_class->set_config = gst_aml_v4l2_buffer_pool_set_config;
2299 bufferpool_class->alloc_buffer = gst_aml_v4l2_buffer_pool_alloc_buffer;
2300 bufferpool_class->acquire_buffer = gst_aml_v4l2_buffer_pool_acquire_buffer;
2301 bufferpool_class->release_buffer = gst_aml_v4l2_buffer_pool_release_buffer;
2302 bufferpool_class->flush_start = gst_aml_v4l2_buffer_pool_flush_start;
2303 bufferpool_class->flush_stop = gst_aml_v4l2_buffer_pool_flush_stop;
2304
2305 GST_DEBUG_CATEGORY_INIT(amlv4l2bufferpool_debug, "amlv4l2bufferpool", 0,
2306 "V4L2 Buffer Pool");
2307 GST_DEBUG_CATEGORY_GET(CAT_PERFORMANCE, "GST_PERFORMANCE");
2308}
2309
2310/**
2311 * gst_aml_v4l2_buffer_pool_new:
2312 * @obj: the v4l2 object owning the pool
2313 *
2314 * Construct a new buffer pool.
2315 *
2316 * Returns: the new pool, use gst_object_unref() to free resources
2317 */
2318GstBufferPool *
2319gst_aml_v4l2_buffer_pool_new(GstAmlV4l2Object *obj, GstCaps *caps)
2320{
2321 GstAmlV4l2BufferPool *pool;
2322 GstStructure *config;
2323 gchar *name, *parent_name;
2324 gint fd;
2325
2326 fd = obj->dup(obj->video_fd);
2327 if (fd < 0)
2328 goto dup_failed;
2329
2330 /* setting a significant unique name */
2331 parent_name = gst_object_get_name(GST_OBJECT(obj->element));
2332 name = g_strconcat(parent_name, ":", "pool:",
2333 V4L2_TYPE_IS_OUTPUT(obj->type) ? "sink" : "src", NULL);
2334 g_free(parent_name);
2335
2336 pool = (GstAmlV4l2BufferPool *)g_object_new(GST_TYPE_AML_V4L2_BUFFER_POOL,
2337 "name", name, NULL);
2338 g_object_ref_sink(pool);
2339 g_free(name);
2340
2341 gst_poll_fd_init(&pool->pollfd);
2342 pool->pollfd.fd = fd;
2343 gst_poll_add_fd(pool->poll, &pool->pollfd);
2344 if (V4L2_TYPE_IS_OUTPUT(obj->type))
sheng.liu8d18ed22022-05-26 17:28:15 +08002345 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002346 gst_poll_fd_ctl_write(pool->poll, &pool->pollfd, TRUE);
sheng.liu8d18ed22022-05-26 17:28:15 +08002347 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002348 else
sheng.liu8d18ed22022-05-26 17:28:15 +08002349 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002350 gst_poll_fd_ctl_read(pool->poll, &pool->pollfd, TRUE);
sheng.liu8d18ed22022-05-26 17:28:15 +08002351 gst_poll_fd_ctl_pri (pool->poll, &pool->pollfd, TRUE);
2352 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002353
2354 pool->video_fd = fd;
2355 pool->obj = obj;
2356 pool->can_poll_device = TRUE;
2357
2358 pool->vallocator = gst_aml_v4l2_allocator_new(GST_OBJECT(pool), obj);
2359 if (pool->vallocator == NULL)
2360 goto allocator_failed;
2361
2362 gst_object_ref(obj->element);
2363
2364 config = gst_buffer_pool_get_config(GST_BUFFER_POOL_CAST(pool));
2365 gst_buffer_pool_config_set_params(config, caps, obj->info.size, 0, 0);
2366 /* This will simply set a default config, but will not configure the pool
2367 * because min and max are not valid */
hanghang.luo3128f102022-08-18 10:36:19 +08002368 (void)gst_buffer_pool_set_config(GST_BUFFER_POOL_CAST(pool), config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002369
2370 return GST_BUFFER_POOL(pool);
2371
2372 /* ERRORS */
2373dup_failed:
2374{
2375 GST_ERROR("failed to dup fd %d (%s)", errno, g_strerror(errno));
2376 return NULL;
2377}
2378allocator_failed:
2379{
2380 GST_ERROR_OBJECT(pool, "Failed to create V4L2 allocator");
2381 gst_object_unref(pool);
2382 return NULL;
2383}
2384}
2385
2386static GstFlowReturn
2387gst_aml_v4l2_do_read(GstAmlV4l2BufferPool *pool, GstBuffer *buf)
2388{
2389 GstFlowReturn res;
2390 GstAmlV4l2Object *obj = pool->obj;
2391 gint amount;
2392 GstMapInfo map;
2393 gint toread;
2394
2395 toread = obj->info.size;
2396
2397 GST_LOG_OBJECT(pool, "reading %d bytes into buffer %p", toread, buf);
2398
2399 gst_buffer_map(buf, &map, GST_MAP_WRITE);
2400
2401 do
2402 {
2403 if ((res = gst_aml_v4l2_buffer_pool_poll(pool, TRUE)) != GST_FLOW_OK)
2404 goto poll_error;
2405
2406 amount = obj->read(obj->video_fd, map.data, toread);
2407
2408 if (amount == toread)
2409 {
2410 break;
2411 }
2412 else if (amount == -1)
2413 {
2414 if (errno == EAGAIN || errno == EINTR)
2415 {
2416 continue;
2417 }
2418 else
2419 goto read_error;
2420 }
2421 else
2422 {
2423 /* short reads can happen if a signal interrupts the read */
2424 continue;
2425 }
2426 } while (TRUE);
2427
2428 GST_LOG_OBJECT(pool, "read %d bytes", amount);
2429 gst_buffer_unmap(buf, &map);
2430 gst_buffer_resize(buf, 0, amount);
2431
2432 return GST_FLOW_OK;
2433
2434 /* ERRORS */
2435poll_error:
2436{
2437 GST_DEBUG("poll error %s", gst_flow_get_name(res));
2438 goto cleanup;
2439}
2440read_error:
2441{
2442 GST_ELEMENT_ERROR(obj->element, RESOURCE, READ,
2443 (_("Error reading %d bytes from device '%s'."),
2444 toread, obj->videodev),
2445 GST_ERROR_SYSTEM);
2446 res = GST_FLOW_ERROR;
2447 goto cleanup;
2448}
2449cleanup:
2450{
2451 gst_buffer_unmap(buf, &map);
2452 gst_buffer_resize(buf, 0, 0);
2453 return res;
2454}
2455}
2456
2457/**
2458 * gst_aml_v4l2_buffer_pool_process:
2459 * @bpool: a #GstBufferPool
2460 * @buf: a #GstBuffer, maybe be replaced
2461 *
2462 * Process @buf in @bpool. For capture devices, this functions fills @buf with
2463 * data from the device. For output devices, this functions send the contents of
2464 * @buf to the device for playback.
2465 *
2466 * Returns: %GST_FLOW_OK on success.
2467 */
2468GstFlowReturn
2469gst_aml_v4l2_buffer_pool_process(GstAmlV4l2BufferPool *pool, GstBuffer **buf)
2470{
2471 GstFlowReturn ret = GST_FLOW_OK;
2472 GstBufferPool *bpool = GST_BUFFER_POOL_CAST(pool);
2473 GstAmlV4l2Object *obj = pool->obj;
2474
fei.deng594df4b2023-06-26 07:03:29 +00002475 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 +08002476
2477 if (GST_BUFFER_POOL_IS_FLUSHING(pool))
2478 return GST_FLOW_FLUSHING;
2479
2480 switch (obj->type)
2481 {
2482 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2483 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
2484 /* capture */
2485 switch (obj->mode)
2486 {
2487 case GST_V4L2_IO_RW:
2488 /* capture into the buffer */
2489 ret = gst_aml_v4l2_do_read(pool, *buf);
2490 break;
2491
2492 case GST_V4L2_IO_MMAP:
2493 case GST_V4L2_IO_DMABUF:
2494 {
2495 GstBuffer *tmp;
2496
2497 if ((*buf)->pool == bpool)
2498 {
2499 guint num_queued;
2500 gsize size = gst_buffer_get_size(*buf);
2501
2502 /* Legacy M2M devices return empty buffer when drained */
2503 if (size == 0 && GST_AML_V4L2_IS_M2M(obj->device_caps))
2504 goto eos;
2505
2506 if (GST_VIDEO_INFO_FORMAT(&pool->caps_info) !=
2507 GST_VIDEO_FORMAT_ENCODED &&
2508 size < pool->size)
2509 goto buffer_truncated;
2510
2511 num_queued = g_atomic_int_get(&pool->num_queued);
2512 GST_TRACE_OBJECT(pool, "Only %i buffer left in the capture queue.",
2513 num_queued);
2514
2515 /* If we have no more buffer, and can allocate it time to do so */
2516 if (num_queued == 0)
2517 {
2518 if (GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP))
2519 {
2520 ret = gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
2521 if (ret == GST_FLOW_OK)
2522 goto done;
2523 }
2524 }
2525
2526 /* start copying buffers when we are running low on buffers */
2527 if (num_queued < pool->copy_threshold)
2528 {
2529 GstBuffer *copy;
2530
2531 if (GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP))
2532 {
2533 ret = gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
2534 if (ret == GST_FLOW_OK)
2535 goto done;
2536 }
2537
2538 /* copy the buffer */
2539 copy = gst_buffer_copy_region(*buf,
2540 GST_BUFFER_COPY_ALL | GST_BUFFER_COPY_DEEP, 0, -1);
2541 GST_LOG_OBJECT(pool, "copy buffer %p->%p", *buf, copy);
2542
2543 /* and requeue so that we can continue capturing */
2544 gst_buffer_unref(*buf);
2545 *buf = copy;
2546 }
2547
2548 ret = GST_FLOW_OK;
2549 /* nothing, data was inside the buffer when we did _acquire() */
2550 goto done;
2551 }
2552
2553 /* buffer not from our pool, grab a frame and copy it into the target */
2554 if ((ret = gst_aml_v4l2_buffer_pool_dequeue(pool, &tmp, TRUE)) != GST_FLOW_OK)
2555 goto done;
2556
2557 if (obj->dumpframefile)
2558 {
2559 FILE *pFile = fopen(obj->dumpframefile, "ab");
2560 if (pFile)
2561 {
2562 int n = gst_buffer_n_memory(tmp);
2563 int i;
2564 GstMapInfo map_info;
2565 GstMemory *mem;
2566
2567 for (i = 0; i < n; ++i)
2568 {
2569 mem = gst_buffer_peek_memory(tmp, i);
2570 if (gst_memory_map(mem, &map_info, GST_MAP_READ))
2571 {
2572 fwrite(map_info.data, map_info.size, 1, pFile);
2573 gst_memory_unmap(mem, &map_info);
2574 }
2575 }
2576 fclose(pFile);
2577 }
2578 }
2579 /* An empty buffer on capture indicates the end of stream */
2580 if (gst_buffer_get_size(tmp) == 0)
2581 {
2582 gst_aml_v4l2_buffer_pool_release_buffer(bpool, tmp);
2583
2584 /* Legacy M2M devices return empty buffer when drained */
2585 if (GST_AML_V4L2_IS_M2M(obj->device_caps))
2586 goto eos;
2587 }
2588
2589 ret = gst_aml_v4l2_buffer_pool_copy_buffer(pool, *buf, tmp);
hanghang.luo185a3372023-06-06 02:35:33 +00002590 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))
2591 {
2592 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);
2593 gst_buffer_resize (*buf, 0, pool->caps_info.width * pool->caps_info.height * 3 / 2);
2594 }
2595
xuesong.jiangae1548e2022-05-06 16:38:46 +08002596
2597 /* an queue the buffer again after the copy */
2598 gst_aml_v4l2_buffer_pool_release_buffer(bpool, tmp);
2599
2600 if (ret != GST_FLOW_OK)
2601 goto copy_failed;
2602 break;
2603 }
2604
2605 case GST_V4L2_IO_USERPTR:
2606 {
2607 struct UserPtrData *data;
2608 GstBuffer *tmp;
2609
2610 /* Replace our buffer with downstream allocated buffer */
2611 data = gst_mini_object_steal_qdata(GST_MINI_OBJECT(*buf),
2612 GST_AML_V4L2_IMPORT_QUARK);
2613 tmp = gst_buffer_ref(data->buffer);
2614 _unmap_userptr_frame(data);
2615
2616 /* Now tmp is writable, copy the flags and timestamp */
2617 gst_buffer_copy_into(tmp, *buf,
2618 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2619
2620 gst_buffer_replace(buf, tmp);
2621 gst_buffer_unref(tmp);
2622 break;
2623 }
2624
2625 case GST_V4L2_IO_DMABUF_IMPORT:
2626 {
2627 GstBuffer *tmp;
2628
2629 /* Replace our buffer with downstream allocated buffer */
2630 // tmp = gst_mini_object_steal_qdata(GST_MINI_OBJECT(*buf),
2631 // GST_AML_V4L2_IMPORT_QUARK);
2632 tmp = gst_mini_object_get_qdata(GST_MINI_OBJECT(*buf), GST_AML_V4L2_IMPORT_QUARK);
2633 GST_DEBUG("got v4l2 capture buf:%p, with qdata drm buf:%p", *buf, tmp);
2634
2635 gst_buffer_copy_into(tmp, *buf,
2636 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2637
2638 gst_buffer_replace(buf, tmp);
2639 gst_buffer_unref(tmp);
2640 break;
2641 }
2642
2643 default:
2644 g_assert_not_reached();
2645 break;
2646 }
2647 break;
2648
2649 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
2650 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
2651 /* playback */
2652 switch (obj->mode)
2653 {
2654 case GST_V4L2_IO_RW:
2655 /* FIXME, do write() */
2656 GST_WARNING_OBJECT(pool, "implement write()");
2657 break;
2658
2659 case GST_V4L2_IO_USERPTR:
2660 case GST_V4L2_IO_DMABUF_IMPORT:
2661 case GST_V4L2_IO_DMABUF:
2662 case GST_V4L2_IO_MMAP:
2663 {
2664 GstBuffer *to_queue = NULL;
2665 GstBuffer *buffer;
2666 GstAmlV4l2MemoryGroup *group;
2667 gint index;
2668
2669 if ((*buf)->pool != bpool)
2670 goto copying;
2671
2672 if (!gst_aml_v4l2_is_buffer_valid(*buf, &group))
2673 goto copying;
2674
2675 index = group->buffer.index;
2676
2677 GST_LOG_OBJECT(pool, "processing buffer %i from our pool", index);
2678
2679 if (pool->buffers[index] != NULL)
2680 {
2681 GST_LOG_OBJECT(pool, "buffer %i already queued, copying", index);
2682 goto copying;
2683 }
2684
2685 /* we can queue directly */
2686 to_queue = gst_buffer_ref(*buf);
2687
2688 copying:
2689 if (to_queue == NULL)
2690 {
2691 GstBufferPoolAcquireParams params = {0};
2692
2693 GST_LOG_OBJECT(pool, "alloc buffer from our pool");
2694
2695 /* this can return EOS if all buffers are outstanding which would
2696 * be strange because we would expect the upstream element to have
2697 * allocated them and returned to us.. */
2698 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
2699 ret = gst_buffer_pool_acquire_buffer(bpool, &to_queue, &params);
2700 if (ret != GST_FLOW_OK)
2701 goto acquire_failed;
2702
2703 ret = gst_aml_v4l2_buffer_pool_prepare_buffer(pool, to_queue, *buf);
2704 if (ret != GST_FLOW_OK)
2705 {
2706 gst_buffer_unref(to_queue);
2707 goto prepare_failed;
2708 }
2709
2710 /* retreive the group */
2711 gst_aml_v4l2_is_buffer_valid(to_queue, &group);
2712 }
2713
2714 if ((ret = gst_aml_v4l2_buffer_pool_qbuf(pool, to_queue, group)) != GST_FLOW_OK)
2715 goto queue_failed;
2716
2717 /* if we are not streaming yet (this is the first buffer, start
2718 * streaming now */
2719 if (!gst_aml_v4l2_buffer_pool_streamon(pool))
2720 {
2721 /* don't check return value because qbuf would have failed */
2722 gst_aml_v4l2_is_buffer_valid(to_queue, &group);
2723
2724 /* qbuf has stored to_queue buffer but we are not in
2725 * streaming state, so the flush logic won't be performed.
2726 * To avoid leaks, flush the allocator and restore the queued
2727 * buffer as non-queued */
2728 gst_aml_v4l2_allocator_flush(pool->vallocator);
2729
2730 pool->buffers[group->buffer.index] = NULL;
2731
2732 gst_mini_object_set_qdata(GST_MINI_OBJECT(to_queue),
2733 GST_AML_V4L2_IMPORT_QUARK, NULL, NULL);
2734 gst_buffer_unref(to_queue);
2735 g_atomic_int_add(&pool->num_queued, -1);
2736 goto start_failed;
2737 }
2738
2739 /* Remove our ref, we will still hold this buffer in acquire as needed,
2740 * otherwise the pool will think it is outstanding and will refuse to stop. */
2741 gst_buffer_unref(to_queue);
2742
2743 /* release as many buffer as possible */
2744 while (gst_aml_v4l2_buffer_pool_dequeue(pool, &buffer, FALSE) ==
2745 GST_FLOW_OK)
2746 {
2747 if (buffer->pool == NULL)
2748 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
2749 }
2750
2751 if (g_atomic_int_get(&pool->num_queued) >= pool->min_latency)
2752 {
2753 /* all buffers are queued, try to dequeue one and release it back
2754 * into the pool so that _acquire can get to it again. */
2755 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, &buffer, TRUE);
2756 if (ret == GST_FLOW_OK && buffer->pool == NULL)
2757 /* release the rendered buffer back into the pool. This wakes up any
2758 * thread waiting for a buffer in _acquire(). */
2759 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
2760 }
2761 break;
2762 }
2763 default:
2764 g_assert_not_reached();
2765 break;
2766 }
2767 break;
2768 default:
2769 g_assert_not_reached();
2770 break;
2771 }
2772done:
2773 return ret;
2774
2775 /* ERRORS */
2776copy_failed:
2777{
2778 GST_ERROR_OBJECT(pool, "failed to copy buffer");
2779 return ret;
2780}
2781buffer_truncated:
2782{
2783 GST_WARNING_OBJECT(pool,
2784 "Dropping truncated buffer, this is likely a driver bug.");
2785 gst_buffer_unref(*buf);
2786 *buf = NULL;
2787 return GST_AML_V4L2_FLOW_CORRUPTED_BUFFER;
2788}
2789eos:
2790{
2791 GST_DEBUG_OBJECT(pool, "end of stream reached");
2792 gst_buffer_unref(*buf);
2793 *buf = NULL;
2794 return GST_AML_V4L2_FLOW_LAST_BUFFER;
2795}
2796acquire_failed:
2797{
2798 if (ret == GST_FLOW_FLUSHING)
2799 GST_DEBUG_OBJECT(pool, "flushing");
2800 else
2801 GST_WARNING_OBJECT(pool, "failed to acquire a buffer: %s",
2802 gst_flow_get_name(ret));
2803 return ret;
2804}
2805prepare_failed:
2806{
2807 GST_ERROR_OBJECT(pool, "failed to prepare data");
2808 return ret;
2809}
2810queue_failed:
2811{
2812 GST_ERROR_OBJECT(pool, "failed to queue buffer");
2813 return ret;
2814}
2815start_failed:
2816{
2817 GST_ERROR_OBJECT(pool, "failed to start streaming");
2818 return GST_FLOW_ERROR;
2819}
2820}
2821
2822void gst_aml_v4l2_buffer_pool_set_other_pool(GstAmlV4l2BufferPool *pool,
2823 GstBufferPool *other_pool)
2824{
2825 g_return_if_fail(!gst_buffer_pool_is_active(GST_BUFFER_POOL(pool)));
2826
2827 if (pool->other_pool)
2828 gst_object_unref(pool->other_pool);
2829 pool->other_pool = gst_object_ref(other_pool);
2830}
2831
2832void gst_aml_v4l2_buffer_pool_copy_at_threshold(GstAmlV4l2BufferPool *pool, gboolean copy)
2833{
2834 GST_OBJECT_LOCK(pool);
2835 pool->enable_copy_threshold = copy;
2836 GST_OBJECT_UNLOCK(pool);
2837}
2838
2839gboolean
2840gst_aml_v4l2_buffer_pool_flush(GstBufferPool *bpool)
2841{
2842 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
2843 gboolean ret = TRUE;
2844
2845 gst_aml_v4l2_buffer_pool_streamoff(pool);
2846
2847 if (!V4L2_TYPE_IS_OUTPUT(pool->obj->type))
2848 ret = gst_aml_v4l2_buffer_pool_streamon(pool);
2849
2850 return ret;
2851}
2852
2853void gst_aml_v4l2_buffer_pool_dump_stat(GstAmlV4l2BufferPool *pool, const gchar *file_name, gint try_num)
2854{
2855 const gchar *dump_dir = NULL;
2856 gchar *full_file_name = NULL;
2857 FILE *out = NULL;
2858
2859 dump_dir = g_getenv("GST_DEBUG_DUMP_AMLV4L2DEC_STAT_DIR");
2860 if (G_LIKELY(dump_dir == NULL))
2861 return;
2862
2863 if (!file_name)
2864 {
2865 file_name = "unnamed";
2866 }
2867
2868 full_file_name = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s.stat", dump_dir, file_name);
2869
2870 if ((out = fopen(full_file_name, "w")))
2871 {
2872 GstStructure *config = NULL;
2873 config = gst_buffer_pool_get_config((GstBufferPool *)pool);
2874 if (config)
2875 {
2876 GstCaps *caps;
2877 guint size, min_buffers, max_buffers;
2878 if (gst_buffer_pool_config_get_params(config, &caps, &size, &min_buffers, &max_buffers))
2879 {
2880 gchar *stat_info;
2881
2882 /* set local pool info*/
2883 gint already_queued = 0;
2884 gint ready_to_queue_num = 0;
2885 for (gint i = 0; i < VIDEO_MAX_FRAME; i++)
2886 {
2887 if (pool->buffers[i])
2888 {
2889 already_queued++;
2890 }
2891 if (pool->read_to_free_bufs[i])
2892 {
2893 ready_to_queue_num++;
2894 }
2895 }
2896
2897 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",
2898 size, min_buffers, max_buffers,
2899 pool->num_queued, pool->num_allocated,
2900 already_queued, ready_to_queue_num, try_num);
2901 fputs(stat_info, out);
2902 g_free(stat_info);
2903
2904 /* set other pool info*/
2905 if (pool->other_pool)
2906 {
2907 GstStructure *other_config = NULL;
2908 other_config = gst_buffer_pool_get_config((GstBufferPool *)pool);
2909 if (other_config)
2910 {
2911 GstCaps *other_caps;
2912 guint other_size, other_min_buffers, other_max_buffers;
2913 if (gst_buffer_pool_config_get_params(config, &other_caps, &other_size, &other_min_buffers, &other_max_buffers))
2914 {
2915 stat_info = g_strdup_printf("other pool | size:%d, min_bufs:%d, max_bufs:%d\n",
2916 other_size, other_min_buffers, other_max_buffers);
2917
2918 // TODO:GstBufferPool中没有获取outstanding的接口,所以这里没有统计otherpool中在用buffer的状态,后续需要修改gstreamer-1.0中code新增接口
2919 fputs(stat_info, out);
2920 g_free(stat_info);
2921 }
2922 }
2923 }
2924 GST_INFO("wrote amlv4l2 bufferpool stat to : '%s' succ", full_file_name);
2925 }
2926 }
2927 else
2928 {
2929 GST_WARNING("Failed to get config for pool:%p", pool);
2930 }
2931 fclose(out);
2932 }
2933 else
2934 {
2935 GST_WARNING("Failed to open file '%s' for writing: %s", full_file_name, g_strerror(errno));
2936 }
2937 g_free(full_file_name);
2938}