blob: 95af7216a256b4b97b7254af943b40b7c8add949 [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;
2122
2123 if (outstanding_buf_num > obj->outstanding_buf_num)
2124 {
2125 GST_ERROR_OBJECT(pool, "amlmodbuf old other pool recycle buffer error, outstanding from %d to %d", obj->outstanding_buf_num, outstanding_buf_num);
2126 return FALSE;
2127 }
2128 GST_DEBUG_OBJECT(pool, "amlmodbuf oop outstanding buf num from %d reduce to %d", obj->outstanding_buf_num, outstanding_buf_num);
2129
2130 update = obj->outstanding_buf_num - outstanding_buf_num;
2131 if (!gst_buffer_pool_increase_max_num(pool->other_pool, update))
2132 {
2133 GST_ERROR_OBJECT(pool, "amlmodbuf update other pool max buffer num error");
2134 return FALSE;
2135 }
2136
2137 obj->outstanding_buf_num = outstanding_buf_num;
2138 }
2139 }
2140
xuesong.jiangae1548e2022-05-06 16:38:46 +08002141 memset(&params, 0, sizeof(GstBufferPoolAcquireParams));
2142 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
fei.denge9458472023-04-18 02:05:48 +00002143 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 +08002144 while (pool->ready_to_free_buf_num && gst_buffer_pool_acquire_buffer(pool->other_pool, &src, &params) != GST_FLOW_ERROR && src != NULL)
2145 {
2146 gint i = 0;
2147
fei.denge9458472023-04-18 02:05:48 +00002148 GST_TRACE_OBJECT(pool, "amlmodbuf acquire buf:%p form other pool", src);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002149 for (; i < VIDEO_MAX_FRAME; i++)
2150 {
2151 GST_DEBUG_OBJECT(pool, "amlmodbuf check index:%d", i);
2152 if (pool->read_to_free_bufs[i])
2153 {
2154 GstBuffer *bind_drm_buf = gst_mini_object_get_qdata(GST_MINI_OBJECT(pool->read_to_free_bufs[i]), GST_AML_V4L2_IMPORT_QUARK);
2155 if (bind_drm_buf == NULL)
2156 {
fei.denge9458472023-04-18 02:05:48 +00002157 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 +08002158 }
2159 else if (src != bind_drm_buf)
2160 {
fei.denge9458472023-04-18 02:05:48 +00002161 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 +08002162 continue;
2163 }
2164
fei.denge9458472023-04-18 02:05:48 +00002165 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 +08002166 GstFlowReturn isvalid = GST_FLOW_OK;
2167 GstAmlV4l2MemoryGroup *tmp_group = NULL;
2168
2169 // bind_drm_buf= gst_mini_object_steal_qdata(GST_MINI_OBJECT(pool->read_to_free_bufs[i]), GST_AML_V4L2_IMPORT_QUARK);
2170 ret = gst_aml_v4l2_buffer_pool_import_dmabuf(pool, pool->read_to_free_bufs[i], src);
2171 gst_buffer_unref(src);
2172 src = NULL;
2173 isvalid = gst_aml_v4l2_is_buffer_valid(pool->read_to_free_bufs[i], &tmp_group);
2174 if ((ret != GST_FLOW_OK && isvalid) || gst_aml_v4l2_buffer_pool_qbuf(pool, pool->read_to_free_bufs[i], tmp_group) != GST_FLOW_OK)
2175 {
fei.denge9458472023-04-18 02:05:48 +00002176 GST_TRACE_OBJECT(pool, "amlmodbuf go into error flow");
xuesong.jiangae1548e2022-05-06 16:38:46 +08002177 pclass->release_buffer(bpool, pool->read_to_free_bufs[i]);
2178 }
2179 pool->read_to_free_bufs[i] = NULL;
2180 pool->ready_to_free_buf_num--;
fei.denge9458472023-04-18 02:05:48 +00002181 GST_TRACE_OBJECT(pool, "amlmodbuf queued buf:%d, into v4l2 bp", i);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002182 break;
2183 }
2184 }
2185 if (i == VIDEO_MAX_FRAME)
2186 {
2187 GST_ERROR_OBJECT(pool, "drm buf:%p can't match any v4l2 capture buf, error", src);
2188 gst_buffer_unref(src);
2189 src = NULL;
2190 return FALSE;
2191 }
2192 }
fei.denge9458472023-04-18 02:05:48 +00002193 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 +08002194 return TRUE;
2195 }
2196 return FALSE;
2197}
2198#endif
2199
2200static void
2201gst_aml_v4l2_buffer_pool_dispose(GObject *object)
2202{
2203 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(object);
2204
2205 if (pool->vallocator)
2206 gst_object_unref(pool->vallocator);
2207 pool->vallocator = NULL;
2208
2209 if (pool->allocator)
2210 gst_object_unref(pool->allocator);
2211 pool->allocator = NULL;
2212
2213 if (pool->other_pool)
2214 gst_object_unref(pool->other_pool);
2215 pool->other_pool = NULL;
2216
2217 G_OBJECT_CLASS(parent_class)->dispose(object);
2218}
2219
2220static void
2221gst_aml_v4l2_buffer_pool_finalize(GObject *object)
2222{
2223 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(object);
2224
zengliang.lidcd41462024-06-19 16:05:12 +08002225 if (g_list_length (pool->cc_buffer_list) > 0)
2226 {
2227 g_list_free_full (pool->cc_buffer_list, (GDestroyNotify) gst_buffer_unref);
2228 pool->cc_buffer_list = NULL;
2229 }
2230
xuesong.jiangae1548e2022-05-06 16:38:46 +08002231 if (pool->video_fd >= 0)
2232 pool->obj->close(pool->video_fd);
2233
2234 gst_poll_free(pool->poll);
2235
2236 /* This can't be done in dispose method because we must not set pointer
2237 * to NULL as it is part of the v4l2object and dispose could be called
2238 * multiple times */
2239 gst_object_unref(pool->obj->element);
2240
2241 g_cond_clear(&pool->empty_cond);
2242
2243 /* FIXME have we done enough here ? */
2244
2245 G_OBJECT_CLASS(parent_class)->finalize(object);
2246}
2247
2248static void
2249gst_aml_v4l2_buffer_pool_init(GstAmlV4l2BufferPool *pool)
2250{
2251 pool->poll = gst_poll_new(TRUE);
2252 pool->can_poll_device = TRUE;
2253 g_cond_init(&pool->empty_cond);
hanghang.luo3128f102022-08-18 10:36:19 +08002254 GST_OBJECT_LOCK(pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002255 pool->empty = TRUE;
hanghang.luo3128f102022-08-18 10:36:19 +08002256 GST_OBJECT_UNLOCK(pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002257 pool->orphaned = FALSE;
zengliang.lidcd41462024-06-19 16:05:12 +08002258 pool->cc_buffer_list = NULL;
xuesong.jiangae1548e2022-05-06 16:38:46 +08002259}
2260
2261static void
2262gst_aml_v4l2_buffer_pool_class_init(GstAmlV4l2BufferPoolClass *klass)
2263{
2264 GObjectClass *object_class = G_OBJECT_CLASS(klass);
2265 GstBufferPoolClass *bufferpool_class = GST_BUFFER_POOL_CLASS(klass);
2266
2267 object_class->dispose = gst_aml_v4l2_buffer_pool_dispose;
2268 object_class->finalize = gst_aml_v4l2_buffer_pool_finalize;
2269
2270 bufferpool_class->start = gst_aml_v4l2_buffer_pool_start;
2271 bufferpool_class->stop = gst_aml_v4l2_buffer_pool_stop;
2272 bufferpool_class->set_config = gst_aml_v4l2_buffer_pool_set_config;
2273 bufferpool_class->alloc_buffer = gst_aml_v4l2_buffer_pool_alloc_buffer;
2274 bufferpool_class->acquire_buffer = gst_aml_v4l2_buffer_pool_acquire_buffer;
2275 bufferpool_class->release_buffer = gst_aml_v4l2_buffer_pool_release_buffer;
2276 bufferpool_class->flush_start = gst_aml_v4l2_buffer_pool_flush_start;
2277 bufferpool_class->flush_stop = gst_aml_v4l2_buffer_pool_flush_stop;
2278
2279 GST_DEBUG_CATEGORY_INIT(amlv4l2bufferpool_debug, "amlv4l2bufferpool", 0,
2280 "V4L2 Buffer Pool");
2281 GST_DEBUG_CATEGORY_GET(CAT_PERFORMANCE, "GST_PERFORMANCE");
2282}
2283
2284/**
2285 * gst_aml_v4l2_buffer_pool_new:
2286 * @obj: the v4l2 object owning the pool
2287 *
2288 * Construct a new buffer pool.
2289 *
2290 * Returns: the new pool, use gst_object_unref() to free resources
2291 */
2292GstBufferPool *
2293gst_aml_v4l2_buffer_pool_new(GstAmlV4l2Object *obj, GstCaps *caps)
2294{
2295 GstAmlV4l2BufferPool *pool;
2296 GstStructure *config;
2297 gchar *name, *parent_name;
2298 gint fd;
2299
2300 fd = obj->dup(obj->video_fd);
2301 if (fd < 0)
2302 goto dup_failed;
2303
2304 /* setting a significant unique name */
2305 parent_name = gst_object_get_name(GST_OBJECT(obj->element));
2306 name = g_strconcat(parent_name, ":", "pool:",
2307 V4L2_TYPE_IS_OUTPUT(obj->type) ? "sink" : "src", NULL);
2308 g_free(parent_name);
2309
2310 pool = (GstAmlV4l2BufferPool *)g_object_new(GST_TYPE_AML_V4L2_BUFFER_POOL,
2311 "name", name, NULL);
2312 g_object_ref_sink(pool);
2313 g_free(name);
2314
2315 gst_poll_fd_init(&pool->pollfd);
2316 pool->pollfd.fd = fd;
2317 gst_poll_add_fd(pool->poll, &pool->pollfd);
2318 if (V4L2_TYPE_IS_OUTPUT(obj->type))
sheng.liu8d18ed22022-05-26 17:28:15 +08002319 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002320 gst_poll_fd_ctl_write(pool->poll, &pool->pollfd, TRUE);
sheng.liu8d18ed22022-05-26 17:28:15 +08002321 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002322 else
sheng.liu8d18ed22022-05-26 17:28:15 +08002323 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002324 gst_poll_fd_ctl_read(pool->poll, &pool->pollfd, TRUE);
sheng.liu8d18ed22022-05-26 17:28:15 +08002325 gst_poll_fd_ctl_pri (pool->poll, &pool->pollfd, TRUE);
2326 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002327
2328 pool->video_fd = fd;
2329 pool->obj = obj;
2330 pool->can_poll_device = TRUE;
2331
2332 pool->vallocator = gst_aml_v4l2_allocator_new(GST_OBJECT(pool), obj);
2333 if (pool->vallocator == NULL)
2334 goto allocator_failed;
2335
2336 gst_object_ref(obj->element);
2337
2338 config = gst_buffer_pool_get_config(GST_BUFFER_POOL_CAST(pool));
2339 gst_buffer_pool_config_set_params(config, caps, obj->info.size, 0, 0);
2340 /* This will simply set a default config, but will not configure the pool
2341 * because min and max are not valid */
hanghang.luo3128f102022-08-18 10:36:19 +08002342 (void)gst_buffer_pool_set_config(GST_BUFFER_POOL_CAST(pool), config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002343
2344 return GST_BUFFER_POOL(pool);
2345
2346 /* ERRORS */
2347dup_failed:
2348{
2349 GST_ERROR("failed to dup fd %d (%s)", errno, g_strerror(errno));
2350 return NULL;
2351}
2352allocator_failed:
2353{
2354 GST_ERROR_OBJECT(pool, "Failed to create V4L2 allocator");
2355 gst_object_unref(pool);
2356 return NULL;
2357}
2358}
2359
2360static GstFlowReturn
2361gst_aml_v4l2_do_read(GstAmlV4l2BufferPool *pool, GstBuffer *buf)
2362{
2363 GstFlowReturn res;
2364 GstAmlV4l2Object *obj = pool->obj;
2365 gint amount;
2366 GstMapInfo map;
2367 gint toread;
2368
2369 toread = obj->info.size;
2370
2371 GST_LOG_OBJECT(pool, "reading %d bytes into buffer %p", toread, buf);
2372
2373 gst_buffer_map(buf, &map, GST_MAP_WRITE);
2374
2375 do
2376 {
2377 if ((res = gst_aml_v4l2_buffer_pool_poll(pool, TRUE)) != GST_FLOW_OK)
2378 goto poll_error;
2379
2380 amount = obj->read(obj->video_fd, map.data, toread);
2381
2382 if (amount == toread)
2383 {
2384 break;
2385 }
2386 else if (amount == -1)
2387 {
2388 if (errno == EAGAIN || errno == EINTR)
2389 {
2390 continue;
2391 }
2392 else
2393 goto read_error;
2394 }
2395 else
2396 {
2397 /* short reads can happen if a signal interrupts the read */
2398 continue;
2399 }
2400 } while (TRUE);
2401
2402 GST_LOG_OBJECT(pool, "read %d bytes", amount);
2403 gst_buffer_unmap(buf, &map);
2404 gst_buffer_resize(buf, 0, amount);
2405
2406 return GST_FLOW_OK;
2407
2408 /* ERRORS */
2409poll_error:
2410{
2411 GST_DEBUG("poll error %s", gst_flow_get_name(res));
2412 goto cleanup;
2413}
2414read_error:
2415{
2416 GST_ELEMENT_ERROR(obj->element, RESOURCE, READ,
2417 (_("Error reading %d bytes from device '%s'."),
2418 toread, obj->videodev),
2419 GST_ERROR_SYSTEM);
2420 res = GST_FLOW_ERROR;
2421 goto cleanup;
2422}
2423cleanup:
2424{
2425 gst_buffer_unmap(buf, &map);
2426 gst_buffer_resize(buf, 0, 0);
2427 return res;
2428}
2429}
2430
2431/**
2432 * gst_aml_v4l2_buffer_pool_process:
2433 * @bpool: a #GstBufferPool
2434 * @buf: a #GstBuffer, maybe be replaced
2435 *
2436 * Process @buf in @bpool. For capture devices, this functions fills @buf with
2437 * data from the device. For output devices, this functions send the contents of
2438 * @buf to the device for playback.
2439 *
2440 * Returns: %GST_FLOW_OK on success.
2441 */
2442GstFlowReturn
2443gst_aml_v4l2_buffer_pool_process(GstAmlV4l2BufferPool *pool, GstBuffer **buf)
2444{
2445 GstFlowReturn ret = GST_FLOW_OK;
2446 GstBufferPool *bpool = GST_BUFFER_POOL_CAST(pool);
2447 GstAmlV4l2Object *obj = pool->obj;
2448
fei.deng594df4b2023-06-26 07:03:29 +00002449 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 +08002450
2451 if (GST_BUFFER_POOL_IS_FLUSHING(pool))
2452 return GST_FLOW_FLUSHING;
2453
2454 switch (obj->type)
2455 {
2456 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2457 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
2458 /* capture */
2459 switch (obj->mode)
2460 {
2461 case GST_V4L2_IO_RW:
2462 /* capture into the buffer */
2463 ret = gst_aml_v4l2_do_read(pool, *buf);
2464 break;
2465
2466 case GST_V4L2_IO_MMAP:
2467 case GST_V4L2_IO_DMABUF:
2468 {
2469 GstBuffer *tmp;
2470
2471 if ((*buf)->pool == bpool)
2472 {
2473 guint num_queued;
2474 gsize size = gst_buffer_get_size(*buf);
2475
2476 /* Legacy M2M devices return empty buffer when drained */
2477 if (size == 0 && GST_AML_V4L2_IS_M2M(obj->device_caps))
2478 goto eos;
2479
2480 if (GST_VIDEO_INFO_FORMAT(&pool->caps_info) !=
2481 GST_VIDEO_FORMAT_ENCODED &&
2482 size < pool->size)
2483 goto buffer_truncated;
2484
2485 num_queued = g_atomic_int_get(&pool->num_queued);
2486 GST_TRACE_OBJECT(pool, "Only %i buffer left in the capture queue.",
2487 num_queued);
2488
2489 /* If we have no more buffer, and can allocate it time to do so */
2490 if (num_queued == 0)
2491 {
2492 if (GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP))
2493 {
2494 ret = gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
2495 if (ret == GST_FLOW_OK)
2496 goto done;
2497 }
2498 }
2499
2500 /* start copying buffers when we are running low on buffers */
2501 if (num_queued < pool->copy_threshold)
2502 {
2503 GstBuffer *copy;
2504
2505 if (GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP))
2506 {
2507 ret = gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
2508 if (ret == GST_FLOW_OK)
2509 goto done;
2510 }
2511
2512 /* copy the buffer */
2513 copy = gst_buffer_copy_region(*buf,
2514 GST_BUFFER_COPY_ALL | GST_BUFFER_COPY_DEEP, 0, -1);
2515 GST_LOG_OBJECT(pool, "copy buffer %p->%p", *buf, copy);
2516
2517 /* and requeue so that we can continue capturing */
2518 gst_buffer_unref(*buf);
2519 *buf = copy;
2520 }
2521
2522 ret = GST_FLOW_OK;
2523 /* nothing, data was inside the buffer when we did _acquire() */
2524 goto done;
2525 }
2526
2527 /* buffer not from our pool, grab a frame and copy it into the target */
2528 if ((ret = gst_aml_v4l2_buffer_pool_dequeue(pool, &tmp, TRUE)) != GST_FLOW_OK)
2529 goto done;
2530
2531 if (obj->dumpframefile)
2532 {
2533 FILE *pFile = fopen(obj->dumpframefile, "ab");
2534 if (pFile)
2535 {
2536 int n = gst_buffer_n_memory(tmp);
2537 int i;
2538 GstMapInfo map_info;
2539 GstMemory *mem;
2540
2541 for (i = 0; i < n; ++i)
2542 {
2543 mem = gst_buffer_peek_memory(tmp, i);
2544 if (gst_memory_map(mem, &map_info, GST_MAP_READ))
2545 {
2546 fwrite(map_info.data, map_info.size, 1, pFile);
2547 gst_memory_unmap(mem, &map_info);
2548 }
2549 }
2550 fclose(pFile);
2551 }
2552 }
2553 /* An empty buffer on capture indicates the end of stream */
2554 if (gst_buffer_get_size(tmp) == 0)
2555 {
2556 gst_aml_v4l2_buffer_pool_release_buffer(bpool, tmp);
2557
2558 /* Legacy M2M devices return empty buffer when drained */
2559 if (GST_AML_V4L2_IS_M2M(obj->device_caps))
2560 goto eos;
2561 }
2562
2563 ret = gst_aml_v4l2_buffer_pool_copy_buffer(pool, *buf, tmp);
hanghang.luo185a3372023-06-06 02:35:33 +00002564 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))
2565 {
2566 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);
2567 gst_buffer_resize (*buf, 0, pool->caps_info.width * pool->caps_info.height * 3 / 2);
2568 }
2569
xuesong.jiangae1548e2022-05-06 16:38:46 +08002570
2571 /* an queue the buffer again after the copy */
2572 gst_aml_v4l2_buffer_pool_release_buffer(bpool, tmp);
2573
2574 if (ret != GST_FLOW_OK)
2575 goto copy_failed;
2576 break;
2577 }
2578
2579 case GST_V4L2_IO_USERPTR:
2580 {
2581 struct UserPtrData *data;
2582 GstBuffer *tmp;
2583
2584 /* Replace our buffer with downstream allocated buffer */
2585 data = gst_mini_object_steal_qdata(GST_MINI_OBJECT(*buf),
2586 GST_AML_V4L2_IMPORT_QUARK);
2587 tmp = gst_buffer_ref(data->buffer);
2588 _unmap_userptr_frame(data);
2589
2590 /* Now tmp is writable, copy the flags and timestamp */
2591 gst_buffer_copy_into(tmp, *buf,
2592 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2593
2594 gst_buffer_replace(buf, tmp);
2595 gst_buffer_unref(tmp);
2596 break;
2597 }
2598
2599 case GST_V4L2_IO_DMABUF_IMPORT:
2600 {
2601 GstBuffer *tmp;
2602
2603 /* Replace our buffer with downstream allocated buffer */
2604 // tmp = gst_mini_object_steal_qdata(GST_MINI_OBJECT(*buf),
2605 // GST_AML_V4L2_IMPORT_QUARK);
2606 tmp = gst_mini_object_get_qdata(GST_MINI_OBJECT(*buf), GST_AML_V4L2_IMPORT_QUARK);
2607 GST_DEBUG("got v4l2 capture buf:%p, with qdata drm buf:%p", *buf, tmp);
2608
2609 gst_buffer_copy_into(tmp, *buf,
2610 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2611
2612 gst_buffer_replace(buf, tmp);
2613 gst_buffer_unref(tmp);
2614 break;
2615 }
2616
2617 default:
2618 g_assert_not_reached();
2619 break;
2620 }
2621 break;
2622
2623 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
2624 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
2625 /* playback */
2626 switch (obj->mode)
2627 {
2628 case GST_V4L2_IO_RW:
2629 /* FIXME, do write() */
2630 GST_WARNING_OBJECT(pool, "implement write()");
2631 break;
2632
2633 case GST_V4L2_IO_USERPTR:
2634 case GST_V4L2_IO_DMABUF_IMPORT:
2635 case GST_V4L2_IO_DMABUF:
2636 case GST_V4L2_IO_MMAP:
2637 {
2638 GstBuffer *to_queue = NULL;
2639 GstBuffer *buffer;
2640 GstAmlV4l2MemoryGroup *group;
2641 gint index;
2642
2643 if ((*buf)->pool != bpool)
2644 goto copying;
2645
2646 if (!gst_aml_v4l2_is_buffer_valid(*buf, &group))
2647 goto copying;
2648
2649 index = group->buffer.index;
2650
2651 GST_LOG_OBJECT(pool, "processing buffer %i from our pool", index);
2652
2653 if (pool->buffers[index] != NULL)
2654 {
2655 GST_LOG_OBJECT(pool, "buffer %i already queued, copying", index);
2656 goto copying;
2657 }
2658
2659 /* we can queue directly */
2660 to_queue = gst_buffer_ref(*buf);
2661
2662 copying:
2663 if (to_queue == NULL)
2664 {
2665 GstBufferPoolAcquireParams params = {0};
2666
2667 GST_LOG_OBJECT(pool, "alloc buffer from our pool");
2668
2669 /* this can return EOS if all buffers are outstanding which would
2670 * be strange because we would expect the upstream element to have
2671 * allocated them and returned to us.. */
2672 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
2673 ret = gst_buffer_pool_acquire_buffer(bpool, &to_queue, &params);
2674 if (ret != GST_FLOW_OK)
2675 goto acquire_failed;
2676
2677 ret = gst_aml_v4l2_buffer_pool_prepare_buffer(pool, to_queue, *buf);
2678 if (ret != GST_FLOW_OK)
2679 {
2680 gst_buffer_unref(to_queue);
2681 goto prepare_failed;
2682 }
2683
2684 /* retreive the group */
2685 gst_aml_v4l2_is_buffer_valid(to_queue, &group);
2686 }
2687
2688 if ((ret = gst_aml_v4l2_buffer_pool_qbuf(pool, to_queue, group)) != GST_FLOW_OK)
2689 goto queue_failed;
2690
2691 /* if we are not streaming yet (this is the first buffer, start
2692 * streaming now */
2693 if (!gst_aml_v4l2_buffer_pool_streamon(pool))
2694 {
2695 /* don't check return value because qbuf would have failed */
2696 gst_aml_v4l2_is_buffer_valid(to_queue, &group);
2697
2698 /* qbuf has stored to_queue buffer but we are not in
2699 * streaming state, so the flush logic won't be performed.
2700 * To avoid leaks, flush the allocator and restore the queued
2701 * buffer as non-queued */
2702 gst_aml_v4l2_allocator_flush(pool->vallocator);
2703
2704 pool->buffers[group->buffer.index] = NULL;
2705
2706 gst_mini_object_set_qdata(GST_MINI_OBJECT(to_queue),
2707 GST_AML_V4L2_IMPORT_QUARK, NULL, NULL);
2708 gst_buffer_unref(to_queue);
2709 g_atomic_int_add(&pool->num_queued, -1);
2710 goto start_failed;
2711 }
2712
2713 /* Remove our ref, we will still hold this buffer in acquire as needed,
2714 * otherwise the pool will think it is outstanding and will refuse to stop. */
2715 gst_buffer_unref(to_queue);
2716
2717 /* release as many buffer as possible */
2718 while (gst_aml_v4l2_buffer_pool_dequeue(pool, &buffer, FALSE) ==
2719 GST_FLOW_OK)
2720 {
2721 if (buffer->pool == NULL)
2722 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
2723 }
2724
2725 if (g_atomic_int_get(&pool->num_queued) >= pool->min_latency)
2726 {
2727 /* all buffers are queued, try to dequeue one and release it back
2728 * into the pool so that _acquire can get to it again. */
2729 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, &buffer, TRUE);
2730 if (ret == GST_FLOW_OK && buffer->pool == NULL)
2731 /* release the rendered buffer back into the pool. This wakes up any
2732 * thread waiting for a buffer in _acquire(). */
2733 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
2734 }
2735 break;
2736 }
2737 default:
2738 g_assert_not_reached();
2739 break;
2740 }
2741 break;
2742 default:
2743 g_assert_not_reached();
2744 break;
2745 }
2746done:
2747 return ret;
2748
2749 /* ERRORS */
2750copy_failed:
2751{
2752 GST_ERROR_OBJECT(pool, "failed to copy buffer");
2753 return ret;
2754}
2755buffer_truncated:
2756{
2757 GST_WARNING_OBJECT(pool,
2758 "Dropping truncated buffer, this is likely a driver bug.");
2759 gst_buffer_unref(*buf);
2760 *buf = NULL;
2761 return GST_AML_V4L2_FLOW_CORRUPTED_BUFFER;
2762}
2763eos:
2764{
2765 GST_DEBUG_OBJECT(pool, "end of stream reached");
2766 gst_buffer_unref(*buf);
2767 *buf = NULL;
2768 return GST_AML_V4L2_FLOW_LAST_BUFFER;
2769}
2770acquire_failed:
2771{
2772 if (ret == GST_FLOW_FLUSHING)
2773 GST_DEBUG_OBJECT(pool, "flushing");
2774 else
2775 GST_WARNING_OBJECT(pool, "failed to acquire a buffer: %s",
2776 gst_flow_get_name(ret));
2777 return ret;
2778}
2779prepare_failed:
2780{
2781 GST_ERROR_OBJECT(pool, "failed to prepare data");
2782 return ret;
2783}
2784queue_failed:
2785{
2786 GST_ERROR_OBJECT(pool, "failed to queue buffer");
2787 return ret;
2788}
2789start_failed:
2790{
2791 GST_ERROR_OBJECT(pool, "failed to start streaming");
2792 return GST_FLOW_ERROR;
2793}
2794}
2795
2796void gst_aml_v4l2_buffer_pool_set_other_pool(GstAmlV4l2BufferPool *pool,
2797 GstBufferPool *other_pool)
2798{
2799 g_return_if_fail(!gst_buffer_pool_is_active(GST_BUFFER_POOL(pool)));
2800
2801 if (pool->other_pool)
2802 gst_object_unref(pool->other_pool);
2803 pool->other_pool = gst_object_ref(other_pool);
2804}
2805
2806void gst_aml_v4l2_buffer_pool_copy_at_threshold(GstAmlV4l2BufferPool *pool, gboolean copy)
2807{
2808 GST_OBJECT_LOCK(pool);
2809 pool->enable_copy_threshold = copy;
2810 GST_OBJECT_UNLOCK(pool);
2811}
2812
2813gboolean
2814gst_aml_v4l2_buffer_pool_flush(GstBufferPool *bpool)
2815{
2816 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
2817 gboolean ret = TRUE;
2818
2819 gst_aml_v4l2_buffer_pool_streamoff(pool);
2820
2821 if (!V4L2_TYPE_IS_OUTPUT(pool->obj->type))
2822 ret = gst_aml_v4l2_buffer_pool_streamon(pool);
2823
2824 return ret;
2825}
2826
2827void gst_aml_v4l2_buffer_pool_dump_stat(GstAmlV4l2BufferPool *pool, const gchar *file_name, gint try_num)
2828{
2829 const gchar *dump_dir = NULL;
2830 gchar *full_file_name = NULL;
2831 FILE *out = NULL;
2832
2833 dump_dir = g_getenv("GST_DEBUG_DUMP_AMLV4L2DEC_STAT_DIR");
2834 if (G_LIKELY(dump_dir == NULL))
2835 return;
2836
2837 if (!file_name)
2838 {
2839 file_name = "unnamed";
2840 }
2841
2842 full_file_name = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s.stat", dump_dir, file_name);
2843
2844 if ((out = fopen(full_file_name, "w")))
2845 {
2846 GstStructure *config = NULL;
2847 config = gst_buffer_pool_get_config((GstBufferPool *)pool);
2848 if (config)
2849 {
2850 GstCaps *caps;
2851 guint size, min_buffers, max_buffers;
2852 if (gst_buffer_pool_config_get_params(config, &caps, &size, &min_buffers, &max_buffers))
2853 {
2854 gchar *stat_info;
2855
2856 /* set local pool info*/
2857 gint already_queued = 0;
2858 gint ready_to_queue_num = 0;
2859 for (gint i = 0; i < VIDEO_MAX_FRAME; i++)
2860 {
2861 if (pool->buffers[i])
2862 {
2863 already_queued++;
2864 }
2865 if (pool->read_to_free_bufs[i])
2866 {
2867 ready_to_queue_num++;
2868 }
2869 }
2870
2871 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",
2872 size, min_buffers, max_buffers,
2873 pool->num_queued, pool->num_allocated,
2874 already_queued, ready_to_queue_num, try_num);
2875 fputs(stat_info, out);
2876 g_free(stat_info);
2877
2878 /* set other pool info*/
2879 if (pool->other_pool)
2880 {
2881 GstStructure *other_config = NULL;
2882 other_config = gst_buffer_pool_get_config((GstBufferPool *)pool);
2883 if (other_config)
2884 {
2885 GstCaps *other_caps;
2886 guint other_size, other_min_buffers, other_max_buffers;
2887 if (gst_buffer_pool_config_get_params(config, &other_caps, &other_size, &other_min_buffers, &other_max_buffers))
2888 {
2889 stat_info = g_strdup_printf("other pool | size:%d, min_bufs:%d, max_bufs:%d\n",
2890 other_size, other_min_buffers, other_max_buffers);
2891
2892 // TODO:GstBufferPool中没有获取outstanding的接口,所以这里没有统计otherpool中在用buffer的状态,后续需要修改gstreamer-1.0中code新增接口
2893 fputs(stat_info, out);
2894 g_free(stat_info);
2895 }
2896 }
2897 }
2898 GST_INFO("wrote amlv4l2 bufferpool stat to : '%s' succ", full_file_name);
2899 }
2900 }
2901 else
2902 {
2903 GST_WARNING("Failed to get config for pool:%p", pool);
2904 }
2905 fclose(out);
2906 }
2907 else
2908 {
2909 GST_WARNING("Failed to open file '%s' for writing: %s", full_file_name, g_strerror(errno));
2910 }
2911 g_free(full_file_name);
2912}