blob: 5c2054d903218f332c87398a945a5c2c5d3b50bb [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
71static gboolean
72gst_aml_v4l2_is_buffer_valid(GstBuffer *buffer, GstAmlV4l2MemoryGroup **out_group)
73{
74 GstMemory *mem = gst_buffer_peek_memory(buffer, 0);
75 gboolean valid = FALSE;
76
77 if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY))
78 goto done;
79
80 if (gst_is_dmabuf_memory(mem))
81 mem = gst_mini_object_get_qdata(GST_MINI_OBJECT(mem),
82 GST_AML_V4L2_MEMORY_QUARK);
83
84 if (mem && gst_is_aml_v4l2_memory(mem))
85 {
86 GstAmlV4l2Memory *vmem = (GstAmlV4l2Memory *)mem;
87 GstAmlV4l2MemoryGroup *group = vmem->group;
88 gint i;
89
90 if (group->n_mem != gst_buffer_n_memory(buffer))
91 goto done;
92
93 for (i = 0; i < group->n_mem; i++)
94 {
95 if (group->mem[i] != gst_buffer_peek_memory(buffer, i))
96 goto done;
97
98 if (!gst_memory_is_writable(group->mem[i]))
99 goto done;
100 }
101
102 valid = TRUE;
103 if (out_group)
104 *out_group = group;
105 }
106
107done:
108 return valid;
109}
110
111static GstFlowReturn
112gst_aml_v4l2_buffer_pool_copy_buffer(GstAmlV4l2BufferPool *pool, GstBuffer *dest,
113 GstBuffer *src)
114{
115 const GstVideoFormatInfo *finfo = pool->caps_info.finfo;
116
117 GST_LOG_OBJECT(pool, "copying buffer");
118
119 if (finfo && (finfo->format != GST_VIDEO_FORMAT_UNKNOWN &&
120 finfo->format != GST_VIDEO_FORMAT_ENCODED))
121 {
122 GstVideoFrame src_frame, dest_frame;
123
124 GST_DEBUG_OBJECT(pool, "copy video frame");
125
126 /* we have raw video, use videoframe copy to get strides right */
127 if (!gst_video_frame_map(&src_frame, &pool->caps_info, src, GST_MAP_READ))
128 goto invalid_buffer;
129
130 if (!gst_video_frame_map(&dest_frame, &pool->caps_info, dest,
131 GST_MAP_WRITE))
132 {
133 gst_video_frame_unmap(&src_frame);
134 goto invalid_buffer;
135 }
136
137 gst_video_frame_copy(&dest_frame, &src_frame);
138
139 gst_video_frame_unmap(&src_frame);
140 gst_video_frame_unmap(&dest_frame);
141 }
142 else
143 {
144 GstMapInfo map;
145
146 GST_DEBUG_OBJECT(pool, "copy raw bytes");
147
148 if (!gst_buffer_map(src, &map, GST_MAP_READ))
149 goto invalid_buffer;
150
151 gst_buffer_fill(dest, 0, map.data, gst_buffer_get_size(src));
152
153 gst_buffer_unmap(src, &map);
154 gst_buffer_resize(dest, 0, gst_buffer_get_size(src));
155 }
156
157 gst_buffer_copy_into(dest, src,
158 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
159
160 GST_CAT_LOG_OBJECT(CAT_PERFORMANCE, pool, "slow copy into buffer %p", dest);
161
162 return GST_FLOW_OK;
163
164invalid_buffer:
165{
166 GST_ERROR_OBJECT(pool, "could not map buffer");
167 return GST_FLOW_ERROR;
168}
169}
170
171struct UserPtrData
172{
173 GstBuffer *buffer;
174 gboolean is_frame;
175 GstVideoFrame frame;
176 GstMapInfo map;
177};
178
179static GQuark
180gst_aml_v4l2_buffer_pool_import_quark(void)
181{
182 static GQuark quark = 0;
183
184 if (quark == 0)
185 quark = g_quark_from_string("GstAmlV4l2BufferPoolUsePtrData");
186
187 return quark;
188}
189
190static void
191_unmap_userptr_frame(struct UserPtrData *data)
192{
193 if (data->is_frame)
194 gst_video_frame_unmap(&data->frame);
195 else
196 gst_buffer_unmap(data->buffer, &data->map);
197
198 if (data->buffer)
199 gst_buffer_unref(data->buffer);
200
201 g_slice_free(struct UserPtrData, data);
202}
203
204static GstFlowReturn
205gst_aml_v4l2_buffer_pool_import_userptr(GstAmlV4l2BufferPool *pool,
206 GstBuffer *dest, GstBuffer *src)
207{
208 GstFlowReturn ret = GST_FLOW_OK;
209 GstAmlV4l2MemoryGroup *group = NULL;
210 GstMapFlags flags;
211 const GstVideoFormatInfo *finfo = pool->caps_info.finfo;
212 struct UserPtrData *data = NULL;
213
214 GST_LOG_OBJECT(pool, "importing userptr");
215
216 /* get the group */
217 if (!gst_aml_v4l2_is_buffer_valid(dest, &group))
218 goto not_our_buffer;
219
220 if (V4L2_TYPE_IS_OUTPUT(pool->obj->type))
221 flags = GST_MAP_READ;
222 else
223 flags = GST_MAP_WRITE;
224
225 data = g_slice_new0(struct UserPtrData);
226
227 if (finfo && (finfo->format != GST_VIDEO_FORMAT_UNKNOWN &&
228 finfo->format != GST_VIDEO_FORMAT_ENCODED))
229 {
230 gsize size[GST_VIDEO_MAX_PLANES] = {
231 0,
232 };
233 gint i;
234
235 data->is_frame = TRUE;
236
237 if (!gst_video_frame_map(&data->frame, &pool->caps_info, src, flags))
238 goto invalid_buffer;
239
240 for (i = 0; i < GST_VIDEO_FORMAT_INFO_N_PLANES(finfo); i++)
241 {
242 if (GST_VIDEO_FORMAT_INFO_IS_TILED(finfo))
243 {
244 gint tinfo = GST_VIDEO_FRAME_PLANE_STRIDE(&data->frame, i);
245 gint pstride;
246 guint pheight;
247
248 pstride = GST_VIDEO_TILE_X_TILES(tinfo) << GST_VIDEO_FORMAT_INFO_TILE_WS(finfo);
249
250 pheight = GST_VIDEO_TILE_Y_TILES(tinfo) << GST_VIDEO_FORMAT_INFO_TILE_HS(finfo);
251
252 size[i] = pstride * pheight;
253 }
254 else
255 {
256 size[i] = GST_VIDEO_FRAME_PLANE_STRIDE(&data->frame, i) *
257 GST_VIDEO_FRAME_COMP_HEIGHT(&data->frame, i);
258 }
259 }
260
261 /* In the single planar API, planes must be contiguous in memory and
262 * therefore they must have expected size. ie: no padding.
263 * To check these conditions, we check that plane 'i' start address
264 * + plane 'i' size equals to plane 'i+1' start address */
265 if (!V4L2_TYPE_IS_MULTIPLANAR(pool->obj->type))
266 {
267 for (i = 0; i < (GST_VIDEO_FORMAT_INFO_N_PLANES(finfo) - 1); i++)
268 {
269 const struct v4l2_pix_format *pix_fmt = &pool->obj->format.fmt.pix;
270 gpointer tmp;
271 gint estride = gst_aml_v4l2_object_extrapolate_stride(finfo, i,
272 pix_fmt->bytesperline);
273 guint eheight = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(finfo, i,
274 pix_fmt->height);
275
276 tmp = ((guint8 *)data->frame.data[i]) + estride * eheight;
277 if (tmp != data->frame.data[i + 1])
278 goto non_contiguous_mem;
279 }
280 }
281
282 if (!gst_aml_v4l2_allocator_import_userptr(pool->vallocator, group,
283 data->frame.info.size, finfo->n_planes, data->frame.data, size))
284 goto import_failed;
285 }
286 else
287 {
288 gpointer ptr[1];
289 gsize size[1];
290
291 data->is_frame = FALSE;
292
293 if (!gst_buffer_map(src, &data->map, flags))
294 goto invalid_buffer;
295
296 ptr[0] = data->map.data;
297 size[0] = data->map.size;
298
299 if (!gst_aml_v4l2_allocator_import_userptr(pool->vallocator, group,
300 data->map.size, 1, ptr, size))
301 goto import_failed;
302 }
303
304 data->buffer = gst_buffer_ref(src);
305
306 gst_mini_object_set_qdata(GST_MINI_OBJECT(dest), GST_AML_V4L2_IMPORT_QUARK,
307 data, (GDestroyNotify)_unmap_userptr_frame);
308
309 gst_buffer_copy_into(dest, src,
310 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
311
312 return ret;
313
314not_our_buffer:
315{
316 GST_ERROR_OBJECT(pool, "destination buffer invalid or not from our pool");
317 return GST_FLOW_ERROR;
318}
319invalid_buffer:
320{
321 GST_ERROR_OBJECT(pool, "could not map buffer");
322 g_slice_free(struct UserPtrData, data);
323 return GST_FLOW_ERROR;
324}
325non_contiguous_mem:
326{
327 GST_ERROR_OBJECT(pool, "memory is not contiguous or plane size mismatch");
328 _unmap_userptr_frame(data);
329 return GST_FLOW_ERROR;
330}
331import_failed:
332{
333 GST_ERROR_OBJECT(pool, "failed to import data");
334 _unmap_userptr_frame(data);
335 return GST_FLOW_ERROR;
336}
337}
338
339static GstFlowReturn
340gst_aml_v4l2_buffer_pool_import_dmabuf(GstAmlV4l2BufferPool *pool,
341 GstBuffer *dest, GstBuffer *src)
342{
343 GstAmlV4l2MemoryGroup *group = NULL;
344 GstMemory *dma_mem[GST_VIDEO_MAX_PLANES] = {0};
345 guint n_mem = gst_buffer_n_memory(src);
346 gint i;
347
348 GST_LOG_OBJECT(pool, "importing dmabuf");
349
350 if (!gst_aml_v4l2_is_buffer_valid(dest, &group))
351 goto not_our_buffer;
352
353 if (n_mem > GST_VIDEO_MAX_PLANES)
354 goto too_many_mems;
355
356 for (i = 0; i < n_mem; i++)
357 dma_mem[i] = gst_buffer_peek_memory(src, i);
358
359 if (!gst_aml_v4l2_allocator_import_dmabuf(pool->vallocator, group, n_mem,
360 dma_mem))
361 goto import_failed;
362
sheng.liu01cd7b52022-06-09 18:12:11 +0800363 // Output buf is secure memory, Need to unref by itselt
364 // Capture buf is secure memory, Need to unref by downstreaming element gstvideosink
365 if (V4L2_TYPE_IS_OUTPUT (pool->obj->type))
366 gst_mini_object_set_qdata(GST_MINI_OBJECT(dest), GST_AML_V4L2_IMPORT_QUARK,
367 gst_buffer_ref(src), (GDestroyNotify)gst_buffer_unref);
368 else
369 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 +0800370
371 gst_buffer_copy_into(dest, src,
372 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
373
374 GST_DEBUG_OBJECT(pool, "v4l2 buf:%p, import buf:%p as qdata", dest, src);
375 return GST_FLOW_OK;
376
377not_our_buffer:
378{
379 GST_ERROR_OBJECT(pool, "destination buffer invalid or not from our pool");
380 return GST_FLOW_ERROR;
381}
382too_many_mems:
383{
384 GST_ERROR_OBJECT(pool, "could not map buffer");
385 return GST_FLOW_ERROR;
386}
387import_failed:
388{
389 GST_ERROR_OBJECT(pool, "failed to import dmabuf");
390 return GST_FLOW_ERROR;
391}
392}
393
394static GstFlowReturn
395gst_aml_v4l2_buffer_pool_prepare_buffer(GstAmlV4l2BufferPool *pool,
396 GstBuffer *dest, GstBuffer *src)
397{
398 GstFlowReturn ret = GST_FLOW_OK;
399 gboolean own_src = FALSE;
400
401 if (src == NULL)
402 {
403 if (pool->other_pool == NULL)
404 {
405 GST_ERROR_OBJECT(pool, "can't prepare buffer, source buffer missing");
406 return GST_FLOW_ERROR;
407 }
408
409 ret = gst_buffer_pool_acquire_buffer(pool->other_pool, &src, NULL);
410 if (ret != GST_FLOW_OK)
411 {
412 GST_ERROR_OBJECT(pool, "failed to acquire buffer from downstream pool");
413 goto done;
414 }
415
416 own_src = TRUE;
417 }
418
419 switch (pool->obj->mode)
420 {
421 case GST_V4L2_IO_MMAP:
422 case GST_V4L2_IO_DMABUF:
423 ret = gst_aml_v4l2_buffer_pool_copy_buffer(pool, dest, src);
424 break;
425 case GST_V4L2_IO_USERPTR:
426 ret = gst_aml_v4l2_buffer_pool_import_userptr(pool, dest, src);
427 break;
428 case GST_V4L2_IO_DMABUF_IMPORT:
429 ret = gst_aml_v4l2_buffer_pool_import_dmabuf(pool, dest, src);
430 break;
431 default:
432 break;
433 }
434
435 if (own_src)
436 gst_buffer_unref(src);
437
438done:
439 return ret;
440}
441
442static GstFlowReturn
443gst_aml_v4l2_buffer_pool_alloc_buffer(GstBufferPool *bpool, GstBuffer **buffer,
444 GstBufferPoolAcquireParams *params)
445{
446 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
447 GstAmlV4l2MemoryGroup *group = NULL;
448 GstBuffer *newbuf = NULL;
449 GstAmlV4l2Object *obj;
450 GstVideoInfo *info;
451
452 obj = pool->obj;
453 info = &obj->info;
454
455 switch (obj->mode)
456 {
457 case GST_V4L2_IO_RW:
458 newbuf =
459 gst_buffer_new_allocate(pool->allocator, pool->size, &pool->params);
460 break;
461 case GST_V4L2_IO_MMAP:
462 group = gst_aml_v4l2_allocator_alloc_mmap(pool->vallocator);
463 break;
464 case GST_V4L2_IO_DMABUF:
465 group = gst_aml_v4l2_allocator_alloc_dmabuf(pool->vallocator,
466 pool->allocator);
467 break;
468 case GST_V4L2_IO_USERPTR:
469 group = gst_aml_v4l2_allocator_alloc_userptr(pool->vallocator);
470 break;
471 case GST_V4L2_IO_DMABUF_IMPORT:
472 group = gst_aml_v4l2_allocator_alloc_dmabufin(pool->vallocator);
473 break;
474 default:
475 newbuf = NULL;
476 g_assert_not_reached();
477 break;
478 }
479
480 if (group != NULL)
481 {
482 gint i;
483 newbuf = gst_buffer_new();
484
485 for (i = 0; i < group->n_mem; i++)
486 gst_buffer_append_memory(newbuf, group->mem[i]);
487 }
488 else if (newbuf == NULL)
489 {
490 goto allocation_failed;
491 }
492
493 /* add metadata to raw video buffers */
494 if (pool->add_videometa)
495 gst_buffer_add_video_meta_full(newbuf, GST_VIDEO_FRAME_FLAG_NONE,
496 GST_VIDEO_INFO_FORMAT(info), GST_VIDEO_INFO_WIDTH(info),
497 GST_VIDEO_INFO_HEIGHT(info), GST_VIDEO_INFO_N_PLANES(info),
498 info->offset, info->stride);
499
500 *buffer = newbuf;
501
502 return GST_FLOW_OK;
503
504 /* ERRORS */
505allocation_failed:
506{
507 GST_ERROR_OBJECT(pool, "failed to allocate buffer");
508 return GST_FLOW_ERROR;
509}
510}
511
512static gboolean
513gst_aml_v4l2_buffer_pool_set_config(GstBufferPool *bpool, GstStructure *config)
514{
515 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
516 GstAmlV4l2Object *obj = pool->obj;
517 GstCaps *caps;
518 guint size, min_buffers, max_buffers;
519 GstAllocator *allocator;
520 GstAllocationParams params;
521 gboolean can_allocate = FALSE;
522 gboolean updated = FALSE;
523 gboolean ret;
524
525 pool->add_videometa =
526 gst_buffer_pool_config_has_option(config,
527 GST_BUFFER_POOL_OPTION_VIDEO_META);
528
529 /* parse the config and keep around */
530 if (!gst_buffer_pool_config_get_params(config, &caps, &size, &min_buffers,
531 &max_buffers))
532 goto wrong_config;
533
534 if (!gst_buffer_pool_config_get_allocator(config, &allocator, &params))
535 goto wrong_config;
536
537 GST_DEBUG_OBJECT(pool, "config %" GST_PTR_FORMAT, config);
538
539 if (pool->allocator)
540 gst_object_unref(pool->allocator);
541 pool->allocator = NULL;
542
543 switch (obj->mode)
544 {
545 case GST_V4L2_IO_DMABUF:
546 pool->allocator = gst_dmabuf_allocator_new();
547 can_allocate = GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP);
548 break;
549 case GST_V4L2_IO_MMAP:
550 can_allocate = GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP);
551 break;
552 case GST_V4L2_IO_USERPTR:
553 can_allocate =
554 GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, USERPTR);
555 break;
556 case GST_V4L2_IO_DMABUF_IMPORT:
557 can_allocate = GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, DMABUF);
558 break;
559 case GST_V4L2_IO_RW:
560 if (allocator)
561 pool->allocator = g_object_ref(allocator);
562 pool->params = params;
563 /* No need to change the configuration */
564 goto done;
565 break;
566 default:
567 g_assert_not_reached();
568 break;
569 }
570
571 /* libv4l2 conversion code does not handle CREATE_BUFS, and may lead to
572 * instability and crash, disable it for now */
573 if (can_allocate && obj->fmtdesc->flags & V4L2_FMT_FLAG_EMULATED)
574 {
575 GST_WARNING_OBJECT(pool,
576 "libv4l2 converter detected, disabling CREATE_BUFS");
577 can_allocate = FALSE;
578 GST_OBJECT_FLAG_UNSET(pool->vallocator,
579 GST_V4L2_ALLOCATOR_FLAG_MMAP_CREATE_BUFS | GST_V4L2_ALLOCATOR_FLAG_USERPTR_CREATE_BUFS | GST_V4L2_ALLOCATOR_FLAG_DMABUF_CREATE_BUFS);
580 }
581
582 if (min_buffers < GST_AML_V4L2_MIN_BUFFERS)
583 {
584 updated = TRUE;
585 min_buffers = GST_AML_V4L2_MIN_BUFFERS;
586 GST_INFO_OBJECT(pool, "increasing minimum buffers to %u", min_buffers);
587 }
588
589 /* respect driver requirements */
590 if (min_buffers < obj->min_buffers)
591 {
592 updated = TRUE;
593 min_buffers = obj->min_buffers;
594 GST_INFO_OBJECT(pool, "increasing minimum buffers to %u", min_buffers);
595 }
596
597 if (max_buffers > VIDEO_MAX_FRAME || max_buffers == 0)
598 {
599 updated = TRUE;
600 max_buffers = VIDEO_MAX_FRAME;
601 GST_INFO_OBJECT(pool, "reducing maximum buffers to %u", max_buffers);
602 }
603
604 if (min_buffers > max_buffers)
605 {
606 updated = TRUE;
607 min_buffers = max_buffers;
608 GST_INFO_OBJECT(pool, "reducing minimum buffers to %u", min_buffers);
609 }
610 else if (min_buffers != max_buffers)
611 {
612 if (!can_allocate)
613 {
614 updated = TRUE;
615 max_buffers = min_buffers;
616 GST_INFO_OBJECT(pool, "can't allocate, setting maximum to minimum");
617 }
618 }
619
620 if (!pool->add_videometa && obj->need_video_meta)
621 {
622 GST_INFO_OBJECT(pool, "adding needed video meta");
623 updated = TRUE;
624 gst_buffer_pool_config_add_option(config,
625 GST_BUFFER_POOL_OPTION_VIDEO_META);
626 }
627
628 /* Always update the config to ensure the configured size matches */
629 gst_buffer_pool_config_set_params(config, caps, obj->info.size, min_buffers,
630 max_buffers);
631
632 /* keep a GstVideoInfo with defaults for the when we need to copy */
633 gst_video_info_from_caps(&pool->caps_info, caps);
634
635done:
636 ret = GST_BUFFER_POOL_CLASS(parent_class)->set_config(bpool, config);
637
638 /* If anything was changed documentation recommand to return FALSE */
639 return !updated && ret;
640
641 /* ERRORS */
642wrong_config:
643{
644 GST_ERROR_OBJECT(pool, "invalid config %" GST_PTR_FORMAT, config);
645 return FALSE;
646}
647}
648
649static GstFlowReturn
650gst_aml_v4l2_buffer_pool_resurrect_buffer(GstAmlV4l2BufferPool *pool)
651{
652 GstBufferPoolAcquireParams params = {0};
653 GstBuffer *buffer = NULL;
654 GstFlowReturn ret;
655
656 GST_DEBUG_OBJECT(pool, "A buffer was lost, reallocating it");
657
658 /* block recursive calls to this function */
659 g_signal_handler_block(pool->vallocator, pool->group_released_handler);
660
661 params.flags =
662 (GstBufferPoolAcquireFlags)GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT |
663 GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
664 ret =
665 gst_buffer_pool_acquire_buffer(GST_BUFFER_POOL(pool), &buffer, &params);
666
667 if (ret == GST_FLOW_OK)
668 gst_buffer_unref(buffer);
669
670 g_signal_handler_unblock(pool->vallocator, pool->group_released_handler);
671
672 return ret;
673}
674
675static gboolean
676gst_aml_v4l2_buffer_pool_streamon(GstAmlV4l2BufferPool *pool)
677{
678 GstAmlV4l2Object *obj = pool->obj;
679
680 if (pool->streaming)
681 return TRUE;
682
683 switch (obj->mode)
684 {
685 case GST_V4L2_IO_MMAP:
686 case GST_V4L2_IO_USERPTR:
687 case GST_V4L2_IO_DMABUF:
688 case GST_V4L2_IO_DMABUF_IMPORT:
689 if (!V4L2_TYPE_IS_OUTPUT(pool->obj->type))
690 {
691 guint i;
692
693 /* For captures, we need to enqueue buffers before we start streaming,
694 * so the driver don't underflow immediatly. As we have put then back
695 * into the base class queue, resurrect them, then releasing will queue
696 * them back. */
697 for (i = 0; i < pool->num_allocated; i++)
698 gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
699 }
700
701 if (obj->ioctl(pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
702 goto streamon_failed;
703
704 pool->streaming = TRUE;
705
706 GST_DEBUG_OBJECT(pool, "Started streaming");
707 break;
708 default:
709 break;
710 }
711
712 return TRUE;
713
714streamon_failed:
715{
716 GST_ERROR_OBJECT(pool, "error with STREAMON %d (%s)", errno,
717 g_strerror(errno));
718 return FALSE;
719}
720}
721
722/* Call with streamlock held, or when streaming threads are down */
723static void
724gst_aml_v4l2_buffer_pool_streamoff(GstAmlV4l2BufferPool *pool)
725{
726 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
727 GstAmlV4l2Object *obj = pool->obj;
728 gint i;
729
730 if (!pool->streaming)
731 return;
732
733 switch (obj->mode)
734 {
735 case GST_V4L2_IO_MMAP:
736 case GST_V4L2_IO_USERPTR:
737 case GST_V4L2_IO_DMABUF:
738 case GST_V4L2_IO_DMABUF_IMPORT:
739
740 if (obj->ioctl(pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0)
741 GST_WARNING_OBJECT(pool, "STREAMOFF failed with errno %d (%s)",
742 errno, g_strerror(errno));
743
744 pool->streaming = FALSE;
745
746 GST_DEBUG_OBJECT(pool, "Stopped streaming");
747
748 if (pool->vallocator)
749 gst_aml_v4l2_allocator_flush(pool->vallocator);
750 break;
751 default:
752 break;
753 }
754
755 GstBufferPool *bpool = GST_BUFFER_POOL(pool);
756 if (V4L2_TYPE_IS_OUTPUT(pool->obj->type))
757 {
758 for (i = 0; i < VIDEO_MAX_FRAME; i++)
759 {
760 GST_INFO_OBJECT(pool, "deal with output buf index:%d, buf:%p", i, pool->buffers[i]);
761 if (pool->buffers[i])
762 {
763 GstBuffer *buffer = pool->buffers[i];
764 pool->buffers[i] = NULL;
765 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
766 g_atomic_int_add(&pool->num_queued, -1);
767 }
768 }
769 }
770 else
771 {
772#ifdef GST_AML_SPEC_FLOW_FOR_VBP
773 if (GST_V4L2_IO_DMABUF_IMPORT == obj->mode)
774 {
775 GST_DEBUG_OBJECT(pool, "have %d ready to free capture buffer", pool->ready_to_free_buf_num);
776 for (i = 0; i < VIDEO_MAX_FRAME; i++)
777 {
778 GST_DEBUG_OBJECT(pool, "buffers[%d]:%p, read_to_free_bufs[%d]:%p", i, pool->buffers[i], i, pool->read_to_free_bufs[i]);
779 if (pool->buffers[i])
780 {
781 if (pool->other_pool)
782 {
783 GstBuffer *other_pool_buf = gst_mini_object_get_qdata(GST_MINI_OBJECT(pool->buffers[i]), GST_AML_V4L2_IMPORT_QUARK);
784 GST_DEBUG_OBJECT(pool, "release v4l2 capture buf[%d]:%p other pool buf:%p", i, pool->buffers[i], other_pool_buf);
785 gst_buffer_unref(other_pool_buf);
786 }
787 }
788 else if (pool->read_to_free_bufs[i])
789 {
790 pool->buffers[i] = pool->read_to_free_bufs[i];
791 pool->read_to_free_bufs[i] = NULL;
792 pool->ready_to_free_buf_num--;
793 }
794 }
795 GST_DEBUG_OBJECT(pool, "%d ready to free capture buffer left", pool->ready_to_free_buf_num);
796 pool->num_queued = 0;
797 }
798#endif
799 for (i = 0; i < VIDEO_MAX_FRAME; i++)
800 {
801 GST_INFO_OBJECT(pool, "deal with caputre buf index:%d, buf:%p", i, pool->buffers[i]);
802 if (pool->buffers[i])
803 {
804 GstBuffer *buffer = pool->buffers[i];
805 pool->buffers[i] = NULL;
806 pclass->release_buffer(bpool, buffer);
807#ifndef GST_AML_SPEC_FLOW_FOR_VBP
808 g_atomic_int_add(&pool->num_queued, -1);
809#endif
810 }
811 }
812 }
813}
814
815static gboolean
816gst_aml_v4l2_buffer_pool_start(GstBufferPool *bpool)
817{
818 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
819 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
820 GstAmlV4l2Object *obj = pool->obj;
821 GstStructure *config;
822 GstCaps *caps;
823 guint size, min_buffers, max_buffers;
824 guint max_latency, min_latency, copy_threshold = 0;
825 gboolean can_allocate = FALSE, ret = TRUE;
826
827 GST_DEBUG_OBJECT(pool, "activating pool");
828
829 if (pool->other_pool)
830 {
831 GstBuffer *buffer;
832
833 if (!gst_buffer_pool_set_active(pool->other_pool, TRUE))
834 goto other_pool_failed;
835
836 if (gst_buffer_pool_acquire_buffer(pool->other_pool, &buffer, NULL) !=
837 GST_FLOW_OK)
838 goto other_pool_failed;
839
840 if (!gst_aml_v4l2_object_try_import(obj, buffer))
841 {
842 gst_buffer_unref(buffer);
843 goto cannot_import;
844 }
845 gst_buffer_unref(buffer);
846 }
847
848 config = gst_buffer_pool_get_config(bpool);
849 if (!gst_buffer_pool_config_get_params(config, &caps, &size, &min_buffers,
850 &max_buffers))
851 goto wrong_config;
852
853 min_latency = MAX(GST_AML_V4L2_MIN_BUFFERS, obj->min_buffers);
854
855 switch (obj->mode)
856 {
857 case GST_V4L2_IO_RW:
858 can_allocate = TRUE;
859#ifdef HAVE_LIBV4L2
860 /* This workaround a unfixable bug in libv4l2 when RW is emulated on top
861 * of MMAP. In this case, the first read initialize the queues, but the
862 * poll before that will always fail. Doing an empty read, forces the
863 * queue to be initialized now. We only do this if we have a streaming
864 * driver. */
865 if (obj->device_caps & V4L2_CAP_STREAMING)
866 obj->read(obj->video_fd, NULL, 0);
867#endif
868 break;
869 case GST_V4L2_IO_DMABUF:
870 case GST_V4L2_IO_MMAP:
871 {
872 guint count;
873
874 can_allocate = GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP);
875
876 /* first, lets request buffers, and see how many we can get: */
877 GST_DEBUG_OBJECT(pool, "requesting %d MMAP buffers", min_buffers);
878
879 count = gst_aml_v4l2_allocator_start(pool->vallocator, min_buffers,
880 V4L2_MEMORY_MMAP);
881 pool->num_allocated = count;
882
883 if (count < GST_AML_V4L2_MIN_BUFFERS)
884 {
885 min_buffers = count;
886 goto no_buffers;
887 }
888
889 /* V4L2 buffer pool are often very limited in the amount of buffers it
890 * can offer. The copy_threshold will workaround this limitation by
891 * falling back to copy if the pipeline needed more buffers. This also
892 * prevent having to do REQBUFS(N)/REQBUFS(0) everytime configure is
893 * called. */
894 if (count != min_buffers || pool->enable_copy_threshold)
895 {
896 GST_WARNING_OBJECT(pool,
897 "Uncertain or not enough buffers, enabling copy threshold");
898 min_buffers = count;
899 copy_threshold = min_latency;
900 }
901
902 break;
903 }
904 case GST_V4L2_IO_USERPTR:
905 {
906 guint count;
907
908 can_allocate =
909 GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, USERPTR);
910
911 GST_DEBUG_OBJECT(pool, "requesting %d USERPTR buffers", min_buffers);
912
913 count = gst_aml_v4l2_allocator_start(pool->vallocator, min_buffers,
914 V4L2_MEMORY_USERPTR);
915
916 /* There is no rational to not get what we asked */
917 if (count < min_buffers)
918 {
919 min_buffers = count;
920 goto no_buffers;
921 }
922
923 min_buffers = count;
924 break;
925 }
926 case GST_V4L2_IO_DMABUF_IMPORT:
927 {
928 guint count;
929
930 can_allocate = GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, DMABUF);
931
932 GST_DEBUG_OBJECT(pool, "requesting %d DMABUF buffers", min_buffers);
933
934 count = gst_aml_v4l2_allocator_start(pool->vallocator, min_buffers,
935 V4L2_MEMORY_DMABUF);
936
937 /* There is no rational to not get what we asked */
938 if (count < min_buffers)
939 {
940 min_buffers = count;
941 goto no_buffers;
942 }
943
944 min_buffers = count;
945 break;
946 }
947 default:
948 min_buffers = 0;
949 copy_threshold = 0;
950 g_assert_not_reached();
951 break;
952 }
953
954 if (can_allocate)
955 max_latency = max_buffers;
956 else
957 max_latency = min_buffers;
958
959 pool->size = size;
960 pool->copy_threshold = copy_threshold;
961 pool->max_latency = max_latency;
962 pool->min_latency = min_latency;
963 pool->num_queued = 0;
964
965 if (max_buffers != 0 && max_buffers < min_buffers)
966 max_buffers = min_buffers;
967
968 gst_buffer_pool_config_set_params(config, caps, size, min_buffers,
969 max_buffers);
970 pclass->set_config(bpool, config);
971 gst_structure_free(config);
972
973 /* now, allocate the buffers: */
974 if (!pclass->start(bpool))
975 goto start_failed;
976
977 if (!V4L2_TYPE_IS_OUTPUT(obj->type))
978 {
979 if (g_atomic_int_get(&pool->num_queued) < min_buffers)
980 goto queue_failed;
981
982 pool->group_released_handler =
983 g_signal_connect_swapped(pool->vallocator, "group-released",
984 G_CALLBACK(gst_aml_v4l2_buffer_pool_resurrect_buffer), pool);
985 ret = gst_aml_v4l2_buffer_pool_streamon(pool);
986 }
987
988 return ret;
989
990 /* ERRORS */
991wrong_config:
992{
993 GST_ERROR_OBJECT(pool, "invalid config %" GST_PTR_FORMAT, config);
994 gst_structure_free(config);
995 return FALSE;
996}
997no_buffers:
998{
999 GST_ERROR_OBJECT(pool,
1000 "we received %d buffer from device '%s', we want at least %d",
1001 min_buffers, obj->videodev, GST_AML_V4L2_MIN_BUFFERS);
1002 gst_structure_free(config);
1003 return FALSE;
1004}
1005start_failed:
1006{
1007 GST_ERROR_OBJECT(pool, "allocate failed");
1008 return FALSE;
1009}
1010other_pool_failed:
1011{
1012 GST_ERROR_OBJECT(pool, "failed to activate the other pool %" GST_PTR_FORMAT, pool->other_pool);
1013 return FALSE;
1014}
1015queue_failed:
1016{
1017 GST_ERROR_OBJECT(pool, "failed to queue buffers into the capture queue");
1018 return FALSE;
1019}
1020cannot_import:
1021{
1022 GST_ERROR_OBJECT(pool, "cannot import buffers from downstream pool");
1023 return FALSE;
1024}
1025}
1026
1027static gboolean
1028gst_aml_v4l2_buffer_pool_vallocator_stop(GstAmlV4l2BufferPool *pool)
1029{
1030 GstAmlV4l2Return vret;
1031
1032 if (!pool->vallocator)
1033 return TRUE;
1034
1035 vret = gst_aml_v4l2_allocator_stop(pool->vallocator);
1036
1037 if (vret == GST_V4L2_BUSY)
1038 GST_WARNING_OBJECT(pool, "some buffers are still outstanding");
1039
1040 return (vret == GST_V4L2_OK);
1041}
1042
1043static gboolean
1044gst_aml_v4l2_buffer_pool_stop(GstBufferPool *bpool)
1045{
1046 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1047 gboolean ret;
1048
1049 if (pool->orphaned)
1050 return gst_aml_v4l2_buffer_pool_vallocator_stop(pool);
1051
1052 GST_DEBUG_OBJECT(pool, "stopping pool");
1053
1054 if (pool->group_released_handler > 0)
1055 {
1056 g_signal_handler_disconnect(pool->vallocator,
1057 pool->group_released_handler);
1058 pool->group_released_handler = 0;
1059 }
1060
1061 gst_aml_v4l2_buffer_pool_streamoff(pool);
1062
1063 ret = GST_BUFFER_POOL_CLASS(parent_class)->stop(bpool);
1064
1065 if (ret)
1066 ret = gst_aml_v4l2_buffer_pool_vallocator_stop(pool);
1067
1068 GST_DEBUG_OBJECT(pool, "stopping other_pool");
1069 if (pool->other_pool)
1070 {
1071 gst_buffer_pool_set_active(pool->other_pool, FALSE);
1072 gst_object_unref(pool->other_pool);
1073 pool->other_pool = NULL;
1074 }
1075
1076 return ret;
1077}
1078
1079gboolean
1080gst_aml_v4l2_buffer_pool_orphan(GstBufferPool **bpool)
1081{
1082 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(*bpool);
1083 gboolean ret;
1084
1085 if (!GST_AML_V4L2_ALLOCATOR_CAN_ORPHAN_BUFS(pool->vallocator))
1086 return FALSE;
1087
1088 if (g_getenv("GST_V4L2_FORCE_DRAIN"))
1089 return FALSE;
1090
1091 GST_DEBUG_OBJECT(pool, "orphaning pool");
1092
1093 gst_buffer_pool_set_active(*bpool, FALSE);
1094 /*
1095 * If the buffer pool has outstanding buffers, it will not be stopped
1096 * by the base class when set inactive. Stop it manually and mark it
1097 * as orphaned
1098 */
1099 ret = gst_aml_v4l2_buffer_pool_stop(*bpool);
1100 if (!ret)
1101 ret = gst_aml_v4l2_allocator_orphan(pool->vallocator);
1102
1103 if (!ret)
1104 goto orphan_failed;
1105
1106 pool->orphaned = TRUE;
1107 gst_object_unref(*bpool);
1108 *bpool = NULL;
1109
1110orphan_failed:
1111 return ret;
1112}
1113
1114static void
1115gst_aml_v4l2_buffer_pool_flush_start(GstBufferPool *bpool)
1116{
1117 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1118
1119 GST_DEBUG_OBJECT(pool, "start flushing");
1120
1121 gst_poll_set_flushing(pool->poll, TRUE);
1122
1123 GST_OBJECT_LOCK(pool);
1124 pool->empty = FALSE;
1125 g_cond_broadcast(&pool->empty_cond);
1126 GST_OBJECT_UNLOCK(pool);
1127
1128 if (pool->other_pool)
1129 gst_buffer_pool_set_flushing(pool->other_pool, TRUE);
1130}
1131
1132static void
1133gst_aml_v4l2_buffer_pool_flush_stop(GstBufferPool *bpool)
1134{
1135 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1136
1137 GST_DEBUG_OBJECT(pool, "stop flushing");
1138
1139 if (pool->other_pool)
1140 gst_buffer_pool_set_flushing(pool->other_pool, FALSE);
1141
1142 gst_poll_set_flushing(pool->poll, FALSE);
1143}
1144
1145static GstFlowReturn
1146gst_aml_v4l2_buffer_pool_poll(GstAmlV4l2BufferPool *pool, gboolean wait)
1147{
1148 gint ret;
1149 GstClockTime timeout;
1150 gint try_num = 0;
1151
1152 if (wait)
1153 timeout = GST_CLOCK_TIME_NONE;
1154 else
1155 timeout = 0;
1156
1157 /* In RW mode there is no queue, hence no need to wait while the queue is
1158 * empty */
xuesong.jiang93f2dcb2022-07-15 14:24:55 +08001159
1160 if ((pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
1161 pool->obj->mode == GST_V4L2_IO_DMABUF_IMPORT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001162 {
xuesong.jiang93f2dcb2022-07-15 14:24:55 +08001163 GST_LOG_OBJECT(pool, "CAPTURE DMA don't quit when empty buf");
1164 }
1165 else
1166 {
1167 if (pool->obj->mode != GST_V4L2_IO_RW)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001168 {
xuesong.jiang93f2dcb2022-07-15 14:24:55 +08001169 GST_OBJECT_LOCK(pool);
1170
1171 if (!wait && pool->empty)
1172 {
1173 GST_OBJECT_UNLOCK(pool);
1174 goto no_buffers;
1175 }
1176
1177 while (pool->empty)
1178 g_cond_wait(&pool->empty_cond, GST_OBJECT_GET_LOCK(pool));
1179
xuesong.jiangae1548e2022-05-06 16:38:46 +08001180 GST_OBJECT_UNLOCK(pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001181 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001182 }
1183
1184 if (!pool->can_poll_device)
1185 {
1186 if (wait)
1187 goto done;
1188 else
1189 goto no_buffers;
1190 }
1191
1192 GST_LOG_OBJECT(pool, "polling device");
1193
1194again:
1195 ret = gst_poll_wait(pool->poll, timeout);
1196#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1197 GST_DEBUG_OBJECT(pool, "amlmodbuf poll timeout:%lld, ret:%d, errno:%d", timeout, ret, errno);
1198#endif
1199 if (G_UNLIKELY(ret < 0))
1200 {
1201 switch (errno)
1202 {
1203 case EBUSY:
1204 goto stopped;
1205 case EAGAIN:
1206 case EINTR:
1207 goto again;
1208 case ENXIO:
1209 GST_WARNING_OBJECT(pool,
1210 "v4l2 device doesn't support polling. Disabling"
1211 " using libv4l2 in this case may cause deadlocks");
1212 pool->can_poll_device = FALSE;
1213 goto done;
1214 default:
1215 goto select_error;
1216 }
1217 }
1218
1219 if (gst_poll_fd_has_error(pool->poll, &pool->pollfd))
1220 goto select_error;
1221
1222 if (ret == 0)
1223 {
1224#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1225 if ((pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
1226 pool->obj->mode == GST_V4L2_IO_DMABUF_IMPORT)
1227 {
1228 GST_DEBUG_OBJECT(pool, "amlmodbuf can't get buffer in capture obj dmaimport mode, try release buf from other pool");
1229 gst_aml_v4l2_buffer_pool_dump_stat(pool, GST_DUMP_CAPTURE_BP_STAT_FILENAME, try_num++);
1230 gst_aml_v4l2_buffer_pool_release_buffer_aml_patch((GstBufferPool *)pool);
1231 goto again;
1232 }
1233 else
1234#endif
1235 goto no_buffers;
1236 }
1237
1238done:
1239 return GST_FLOW_OK;
1240
1241 /* ERRORS */
1242stopped:
1243{
1244 GST_DEBUG_OBJECT(pool, "stop called");
1245 return GST_FLOW_FLUSHING;
1246}
1247select_error:
1248{
1249 GST_ELEMENT_ERROR(pool->obj->element, RESOURCE, READ, (NULL),
1250 ("poll error %d: %s (%d)", ret, g_strerror(errno), errno));
1251 return GST_FLOW_ERROR;
1252}
1253no_buffers:
1254 return GST_FLOW_CUSTOM_SUCCESS;
1255}
1256
1257static GstFlowReturn
1258gst_aml_v4l2_buffer_pool_qbuf(GstAmlV4l2BufferPool *pool, GstBuffer *buf,
1259 GstAmlV4l2MemoryGroup *group)
1260{
1261 const GstAmlV4l2Object *obj = pool->obj;
1262 GstClockTime timestamp;
1263 gint index;
1264
1265 index = group->buffer.index;
1266
1267 if (pool->buffers[index] != NULL)
1268 goto already_queued;
1269
1270 GST_LOG_OBJECT(pool, "queuing buffer %i", index);
1271
1272 if (V4L2_TYPE_IS_OUTPUT(obj->type))
1273 {
1274 enum v4l2_field field;
1275
1276 /* Except when field is set to alternate, buffer field is the same as
1277 * the one defined in format */
1278 if (V4L2_TYPE_IS_MULTIPLANAR(obj->type))
1279 field = obj->format.fmt.pix_mp.field;
1280 else
1281 field = obj->format.fmt.pix.field;
1282
1283 /* NB: At this moment, we can't have alternate mode because it not handled
1284 * yet */
1285 if (field == V4L2_FIELD_ALTERNATE)
1286 {
1287 if (GST_BUFFER_FLAG_IS_SET(buf, GST_VIDEO_FRAME_FLAG_TFF))
1288 field = V4L2_FIELD_TOP;
1289 else
1290 field = V4L2_FIELD_BOTTOM;
1291 }
1292
1293 group->buffer.field = field;
1294 }
1295
1296 if (GST_BUFFER_TIMESTAMP_IS_VALID(buf))
1297 {
1298 timestamp = GST_BUFFER_TIMESTAMP(buf);
1299 GST_TIME_TO_TIMEVAL(timestamp, group->buffer.timestamp);
1300 }
1301
1302 GST_OBJECT_LOCK(pool);
1303 g_atomic_int_inc(&pool->num_queued);
1304 pool->buffers[index] = buf;
1305
1306 if (!gst_aml_v4l2_allocator_qbuf(pool->vallocator, group))
1307 goto queue_failed;
1308
1309 if (!V4L2_TYPE_IS_OUTPUT(obj->type))
1310 {
1311 gst_aml_v4l2_buffer_pool_dump_stat(pool, GST_DUMP_CAPTURE_BP_STAT_FILENAME, 0);
1312 }
1313
1314 pool->empty = FALSE;
1315 g_cond_signal(&pool->empty_cond);
1316 GST_OBJECT_UNLOCK(pool);
1317
1318 return GST_FLOW_OK;
1319
1320already_queued:
1321{
1322 GST_ERROR_OBJECT(pool, "the buffer %i was already queued", index);
1323 return GST_FLOW_ERROR;
1324}
1325queue_failed:
1326{
1327 GST_ERROR_OBJECT(pool, "could not queue a buffer %i", index);
1328 /* Mark broken buffer to the allocator */
1329 GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_TAG_MEMORY);
1330 g_atomic_int_add(&pool->num_queued, -1);
1331 pool->buffers[index] = NULL;
1332 GST_OBJECT_UNLOCK(pool);
1333 return GST_FLOW_ERROR;
1334}
1335}
1336
1337static GstFlowReturn
1338gst_aml_v4l2_buffer_pool_dqevent(GstAmlV4l2BufferPool *pool)
1339{
1340 GstAmlV4l2Object *v4l2object = pool->obj;
1341 struct v4l2_event evt;
1342
1343 memset(&evt, 0x00, sizeof(struct v4l2_event));
1344 if (v4l2object->ioctl(pool->video_fd, VIDIOC_DQEVENT, &evt) < 0)
1345 goto dqevent_failed;
1346
1347 switch (evt.type)
1348 {
1349 case V4L2_EVENT_SOURCE_CHANGE:
sheng.liu8d18ed22022-05-26 17:28:15 +08001350
1351 if (evt.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION)
1352 return GST_AML_V4L2_FLOW_SOURCE_CHANGE;
1353 GST_WARNING_OBJECT (pool, "Unknown source change 0x%x - skipped", evt.u.src_change.changes);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001354 break;
1355 case V4L2_EVENT_EOS:
1356 return GST_AML_V4L2_FLOW_LAST_BUFFER;
1357 break;
1358 default:
1359 break;
1360 }
1361
1362 return GST_FLOW_OK;
1363
1364 /* ERRORS */
1365dqevent_failed:
1366{
1367 return GST_FLOW_ERROR;
1368}
1369}
1370
1371static GstFlowReturn
1372gst_aml_v4l2_buffer_pool_dqbuf(GstAmlV4l2BufferPool *pool, GstBuffer **buffer,
1373 gboolean wait)
1374{
1375 GstFlowReturn res;
1376 GstBuffer *outbuf = NULL;
1377 GstAmlV4l2Object *obj = pool->obj;
1378 GstClockTime timestamp;
1379 GstAmlV4l2MemoryGroup *group;
1380 GstVideoMeta *vmeta;
1381 gsize size;
1382 gint i;
1383
1384 res = gst_aml_v4l2_allocator_dqbuf(pool->vallocator, &group);
1385 if (res == GST_FLOW_EOS)
1386 goto eos;
1387 if (res != GST_FLOW_OK)
1388 goto dqbuf_failed;
1389
1390 /* get our GstBuffer with that index from the pool, if the buffer was
1391 * outstanding we have a serious problem.
1392 */
1393 outbuf = pool->buffers[group->buffer.index];
1394 if (outbuf == NULL)
1395 goto no_buffer;
1396
1397 /* mark the buffer outstanding */
1398 pool->buffers[group->buffer.index] = NULL;
1399 if (g_atomic_int_dec_and_test(&pool->num_queued))
1400 {
1401 GST_OBJECT_LOCK(pool);
1402 pool->empty = TRUE;
1403 GST_OBJECT_UNLOCK(pool);
1404 }
1405
1406 timestamp = GST_TIMEVAL_TO_TIME(group->buffer.timestamp);
1407
1408 size = 0;
1409 vmeta = gst_buffer_get_video_meta(outbuf);
1410 for (i = 0; i < group->n_mem; i++)
1411 {
1412 GST_LOG_OBJECT(pool,
1413 "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,
1414 group->buffer.sequence, group->buffer.index, group->mem[i],
1415 group->planes[i].bytesused, i, group->buffer.flags,
1416 GST_TIME_ARGS(timestamp), pool->num_queued, outbuf);
1417
1418 if (vmeta)
1419 {
1420 vmeta->offset[i] = size;
1421 size += gst_memory_get_sizes(group->mem[i], NULL, NULL);
1422 }
1423 }
1424
1425 /* Ignore timestamp and field for OUTPUT device */
1426 if (V4L2_TYPE_IS_OUTPUT(obj->type))
1427 goto done;
1428
1429 /* Check for driver bug in reporting feild */
1430 if (group->buffer.field == V4L2_FIELD_ANY)
1431 {
1432 /* Only warn once to avoid the spamming */
1433#ifndef GST_DISABLE_GST_DEBUG
1434 if (!pool->has_warned_on_buggy_field)
1435 {
1436 pool->has_warned_on_buggy_field = TRUE;
1437 GST_WARNING_OBJECT(pool,
1438 "Driver should never set v4l2_buffer.field to ANY");
1439 }
1440#endif
1441
1442 /* Use the value from the format (works for UVC bug) */
1443 group->buffer.field = obj->format.fmt.pix.field;
1444
1445 /* If driver also has buggy S_FMT, assume progressive */
1446 if (group->buffer.field == V4L2_FIELD_ANY)
1447 {
1448#ifndef GST_DISABLE_GST_DEBUG
1449 if (!pool->has_warned_on_buggy_field)
1450 {
1451 pool->has_warned_on_buggy_field = TRUE;
1452 GST_WARNING_OBJECT(pool,
1453 "Driver should never set v4l2_format.pix.field to ANY");
1454 }
1455#endif
1456
1457 group->buffer.field = V4L2_FIELD_NONE;
1458 }
1459 }
1460
1461 /* set top/bottom field first if v4l2_buffer has the information */
1462 switch (group->buffer.field)
1463 {
1464 case V4L2_FIELD_NONE:
1465 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1466 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1467 break;
1468 case V4L2_FIELD_INTERLACED_TB:
1469 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1470 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1471 break;
1472 case V4L2_FIELD_INTERLACED_BT:
1473 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1474 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1475 break;
1476 case V4L2_FIELD_INTERLACED:
1477 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1478 if (obj->tv_norm == V4L2_STD_NTSC_M ||
1479 obj->tv_norm == V4L2_STD_NTSC_M_JP ||
1480 obj->tv_norm == V4L2_STD_NTSC_M_KR)
1481 {
1482 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1483 }
1484 else
1485 {
1486 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1487 }
1488 break;
1489 default:
1490 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1491 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1492 GST_FIXME_OBJECT(pool,
1493 "Unhandled enum v4l2_field %d - treating as progressive",
1494 group->buffer.field);
1495 break;
1496 }
1497
1498 if (GST_VIDEO_INFO_FORMAT(&obj->info) == GST_VIDEO_FORMAT_ENCODED)
1499 {
1500 if ((group->buffer.flags & V4L2_BUF_FLAG_KEYFRAME) ||
1501 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_MJPEG ||
1502 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_JPEG ||
1503 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_PJPG)
1504 GST_BUFFER_FLAG_UNSET(outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1505 else
1506 GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1507 }
1508
1509 if (group->buffer.flags & V4L2_BUF_FLAG_ERROR)
1510 GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_FLAG_CORRUPTED);
1511
1512 GST_BUFFER_TIMESTAMP(outbuf) = timestamp;
1513 GST_BUFFER_OFFSET(outbuf) = group->buffer.sequence;
1514 GST_BUFFER_OFFSET_END(outbuf) = group->buffer.sequence + 1;
1515
1516done:
1517 *buffer = outbuf;
1518
1519 if (!V4L2_TYPE_IS_OUTPUT(obj->type))
1520 {
1521 gst_aml_v4l2_buffer_pool_dump_stat(pool, GST_DUMP_CAPTURE_BP_STAT_FILENAME, 0);
1522 }
1523
1524 return res;
1525
1526 /* ERRORS */
1527eos:
1528{
1529 return GST_FLOW_EOS;
1530}
1531dqbuf_failed:
1532{
1533 return GST_FLOW_ERROR;
1534}
1535no_buffer:
1536{
1537 GST_ERROR_OBJECT(pool, "No free buffer found in the pool at index %d.",
1538 group->buffer.index);
1539 return GST_FLOW_ERROR;
1540}
1541}
1542
1543static GstFlowReturn
1544gst_aml_v4l2_buffer_pool_dequeue(GstAmlV4l2BufferPool *pool, GstBuffer **buffer,
1545 gboolean wait)
1546{
1547 GstFlowReturn res;
1548 GstAmlV4l2Object *obj = pool->obj;
1549
1550 if ((res = gst_aml_v4l2_buffer_pool_poll(pool, wait)) != GST_FLOW_OK)
1551 goto poll_failed;
1552
1553 if (obj->can_wait_event && gst_poll_fd_can_read_pri(pool->poll, &pool->pollfd))
1554 {
sheng.liu8d18ed22022-05-26 17:28:15 +08001555 GstFlowReturn res_event = gst_aml_v4l2_buffer_pool_dqevent(pool);
1556 if (res_event != GST_FLOW_OK)
1557 return res_event;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001558 }
1559
1560 if (res == GST_FLOW_CUSTOM_SUCCESS)
1561 {
1562 GST_LOG_OBJECT(pool, "nothing to dequeue");
1563 *buffer = NULL;
1564 return res;
1565 }
1566
1567 GST_LOG_OBJECT(pool, "dequeueing a buffer");
1568 return gst_aml_v4l2_buffer_pool_dqbuf(pool, buffer, wait);
1569
1570 /* ERRORS */
1571poll_failed:
1572{
1573 GST_DEBUG_OBJECT(pool, "poll error %s", gst_flow_get_name(res));
1574 return res;
1575}
1576}
1577
1578static GstFlowReturn
1579gst_aml_v4l2_buffer_pool_acquire_buffer(GstBufferPool *bpool, GstBuffer **buffer,
1580 GstBufferPoolAcquireParams *params)
1581{
1582 GstFlowReturn ret;
1583 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1584 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
1585 GstAmlV4l2Object *obj = pool->obj;
1586
1587 GST_DEBUG_OBJECT(pool, "acquire");
1588
1589 /* If this is being called to resurrect a lost buffer */
1590 if (params && params->flags & GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT)
1591 {
1592 ret = pclass->acquire_buffer(bpool, buffer, params);
1593 goto done;
1594 }
1595
1596 switch (obj->type)
1597 {
1598 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1599 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1600 /* capture, This function should return a buffer with new captured data */
1601 switch (obj->mode)
1602 {
1603 case GST_V4L2_IO_RW:
1604 {
1605 /* take empty buffer from the pool */
1606 ret = pclass->acquire_buffer(bpool, buffer, params);
1607 break;
1608 }
1609 case GST_V4L2_IO_DMABUF:
1610 case GST_V4L2_IO_MMAP:
1611 case GST_V4L2_IO_USERPTR:
1612 case GST_V4L2_IO_DMABUF_IMPORT:
1613 {
1614#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1615 GST_DEBUG_OBJECT(pool, "amlmodbuf return free buf before acquire buf");
1616 gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(bpool);
1617 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, FALSE);
1618#else
1619 /* just dequeue a buffer, we basically use the queue of v4l2 as the
1620 * storage for our buffers. This function does poll first so we can
1621 * interrupt it fine. */
1622 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, TRUE);
1623#endif
1624 break;
1625 }
1626 default:
1627 ret = GST_FLOW_ERROR;
1628 g_assert_not_reached();
1629 break;
1630 }
1631 break;
1632
1633 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1634 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1635 /* playback, This function should return an empty buffer */
1636 switch (obj->mode)
1637 {
1638 case GST_V4L2_IO_RW:
1639 /* get an empty buffer */
1640 ret = pclass->acquire_buffer(bpool, buffer, params);
1641 break;
1642
1643 case GST_V4L2_IO_MMAP:
1644 case GST_V4L2_IO_DMABUF:
1645 case GST_V4L2_IO_USERPTR:
1646 case GST_V4L2_IO_DMABUF_IMPORT:
1647 /* get a free unqueued buffer */
1648 ret = pclass->acquire_buffer(bpool, buffer, params);
1649 break;
1650
1651 default:
1652 ret = GST_FLOW_ERROR;
1653 g_assert_not_reached();
1654 break;
1655 }
1656 break;
1657
1658 default:
1659 ret = GST_FLOW_ERROR;
1660 g_assert_not_reached();
1661 break;
1662 }
1663done:
1664 return ret;
1665}
1666
1667static void
1668gst_aml_v4l2_buffer_pool_release_buffer(GstBufferPool *bpool, GstBuffer *buffer)
1669{
1670 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1671 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
1672 GstAmlV4l2Object *obj = pool->obj;
1673
1674 GST_DEBUG_OBJECT(pool, "release buffer %p", buffer);
1675
1676 /* If the buffer's pool has been orphaned, dispose of it so that
1677 * the pool resources can be freed */
1678 if (pool->orphaned)
1679 {
1680 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
1681 pclass->release_buffer(bpool, buffer);
1682 return;
1683 }
1684
1685 switch (obj->type)
1686 {
1687 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1688 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1689 /* capture, put the buffer back in the queue so that we can refill it
1690 * later. */
1691 switch (obj->mode)
1692 {
1693 case GST_V4L2_IO_RW:
1694 /* release back in the pool */
1695 pclass->release_buffer(bpool, buffer);
1696 break;
1697
1698 case GST_V4L2_IO_DMABUF:
1699 case GST_V4L2_IO_MMAP:
1700 case GST_V4L2_IO_USERPTR:
1701 case GST_V4L2_IO_DMABUF_IMPORT:
1702 {
1703 GstAmlV4l2MemoryGroup *group;
1704 if (gst_aml_v4l2_is_buffer_valid(buffer, &group))
1705 {
1706 GstFlowReturn ret = GST_FLOW_OK;
1707
1708 gst_aml_v4l2_allocator_reset_group(pool->vallocator, group);
1709
1710#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1711 GST_DEBUG_OBJECT(pool, "amlmodbuf trace in add flow with buf:%p index:%d", buffer, group->buffer.index);
1712 pool->read_to_free_bufs[group->buffer.index] = buffer;
1713 pool->ready_to_free_buf_num++;
1714 if (gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(bpool))
1715 {
1716 GST_DEBUG_OBJECT(pool, "amlmodbuf execute aml code logic, skip the following flow");
1717 return;
1718 }
1719#endif
1720 /* queue back in the device */
1721 if (pool->other_pool)
1722 ret = gst_aml_v4l2_buffer_pool_prepare_buffer(pool, buffer, NULL);
1723 if (ret != GST_FLOW_OK ||
1724 gst_aml_v4l2_buffer_pool_qbuf(pool, buffer, group) != GST_FLOW_OK)
1725 pclass->release_buffer(bpool, buffer);
1726 }
1727 else
1728 {
1729 /* Simply release invalide/modified buffer, the allocator will
1730 * give it back later */
1731 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
1732 pclass->release_buffer(bpool, buffer);
1733 }
1734 break;
1735 }
1736 default:
1737 g_assert_not_reached();
1738 break;
1739 }
1740 break;
1741
1742 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1743 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1744 switch (obj->mode)
1745 {
1746 case GST_V4L2_IO_RW:
1747 /* release back in the pool */
1748 pclass->release_buffer(bpool, buffer);
1749 break;
1750
1751 case GST_V4L2_IO_MMAP:
1752 case GST_V4L2_IO_DMABUF:
1753 case GST_V4L2_IO_USERPTR:
1754 case GST_V4L2_IO_DMABUF_IMPORT:
1755 {
1756 GstAmlV4l2MemoryGroup *group;
1757 guint index;
1758
1759 if (!gst_aml_v4l2_is_buffer_valid(buffer, &group))
1760 {
1761 /* Simply release invalide/modified buffer, the allocator will
1762 * give it back later */
1763 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
1764 pclass->release_buffer(bpool, buffer);
1765 break;
1766 }
1767
1768 index = group->buffer.index;
1769
1770 if (pool->buffers[index] == NULL)
1771 {
1772 GST_LOG_OBJECT(pool, "buffer %u not queued, putting on free list",
1773 index);
1774
1775 /* Remove qdata, this will unmap any map data in userptr */
1776 gst_mini_object_set_qdata(GST_MINI_OBJECT(buffer),
1777 GST_AML_V4L2_IMPORT_QUARK, NULL, NULL);
1778
1779 /* reset to default size */
1780 gst_aml_v4l2_allocator_reset_group(pool->vallocator, group);
1781
1782 /* playback, put the buffer back in the queue to refill later. */
1783 pclass->release_buffer(bpool, buffer);
1784 }
1785 else
1786 {
1787 /* the buffer is queued in the device but maybe not played yet. We just
1788 * leave it there and not make it available for future calls to acquire
1789 * for now. The buffer will be dequeued and reused later. */
1790 GST_LOG_OBJECT(pool, "buffer %u is queued", index);
1791 }
1792 break;
1793 }
1794
1795 default:
1796 g_assert_not_reached();
1797 break;
1798 }
1799 break;
1800
1801 default:
1802 g_assert_not_reached();
1803 break;
1804 }
1805}
1806
1807#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1808static gboolean
1809gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(GstBufferPool *bpool)
1810{
1811 GstFlowReturn ret = GST_FLOW_OK;
1812 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1813 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
1814 GstAmlV4l2Object *obj = pool->obj;
1815
1816 if (obj->mode == GST_V4L2_IO_DMABUF_IMPORT && pool->other_pool)
1817 {
1818 GstBuffer *src = NULL;
1819 GstBufferPoolAcquireParams params;
1820
1821 memset(&params, 0, sizeof(GstBufferPoolAcquireParams));
1822 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
1823 GST_DEBUG_OBJECT(pool, "amlmodbuf trace in aml release buf flow ready_to_free_buf_num:%d", pool->ready_to_free_buf_num);
1824 while (pool->ready_to_free_buf_num && gst_buffer_pool_acquire_buffer(pool->other_pool, &src, &params) != GST_FLOW_ERROR && src != NULL)
1825 {
1826 gint i = 0;
1827
1828 GST_DEBUG_OBJECT(pool, "amlmodbuf acquire buf:%p form other pool", src);
1829 for (; i < VIDEO_MAX_FRAME; i++)
1830 {
1831 GST_DEBUG_OBJECT(pool, "amlmodbuf check index:%d", i);
1832 if (pool->read_to_free_bufs[i])
1833 {
1834 GstBuffer *bind_drm_buf = gst_mini_object_get_qdata(GST_MINI_OBJECT(pool->read_to_free_bufs[i]), GST_AML_V4L2_IMPORT_QUARK);
1835 if (bind_drm_buf == NULL)
1836 {
1837 GST_DEBUG_OBJECT(pool, "init flow, bind v4l2 capture buf[%d]:%p with drm buf:%p", i, pool->read_to_free_bufs[i], src);
1838 }
1839 else if (src != bind_drm_buf)
1840 {
1841 GST_DEBUG_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);
1842 continue;
1843 }
1844
1845 GST_DEBUG_OBJECT(pool, "v4l2 capture buf[%d]:%p found bind drm buf:%p", i, pool->read_to_free_bufs[i], src);
1846 GstFlowReturn isvalid = GST_FLOW_OK;
1847 GstAmlV4l2MemoryGroup *tmp_group = NULL;
1848
1849 // bind_drm_buf= gst_mini_object_steal_qdata(GST_MINI_OBJECT(pool->read_to_free_bufs[i]), GST_AML_V4L2_IMPORT_QUARK);
1850 ret = gst_aml_v4l2_buffer_pool_import_dmabuf(pool, pool->read_to_free_bufs[i], src);
1851 gst_buffer_unref(src);
1852 src = NULL;
1853 isvalid = gst_aml_v4l2_is_buffer_valid(pool->read_to_free_bufs[i], &tmp_group);
1854 if ((ret != GST_FLOW_OK && isvalid) || gst_aml_v4l2_buffer_pool_qbuf(pool, pool->read_to_free_bufs[i], tmp_group) != GST_FLOW_OK)
1855 {
1856 GST_DEBUG_OBJECT(pool, "amlmodbuf go into error flow");
1857 pclass->release_buffer(bpool, pool->read_to_free_bufs[i]);
1858 }
1859 pool->read_to_free_bufs[i] = NULL;
1860 pool->ready_to_free_buf_num--;
1861 GST_DEBUG_OBJECT(pool, "amlmodbuf queued buf:%d, into v4l2 bp", i);
1862 break;
1863 }
1864 }
1865 if (i == VIDEO_MAX_FRAME)
1866 {
1867 GST_ERROR_OBJECT(pool, "drm buf:%p can't match any v4l2 capture buf, error", src);
1868 gst_buffer_unref(src);
1869 src = NULL;
1870 return FALSE;
1871 }
1872 }
1873 GST_DEBUG_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);
1874 return TRUE;
1875 }
1876 return FALSE;
1877}
1878#endif
1879
1880static void
1881gst_aml_v4l2_buffer_pool_dispose(GObject *object)
1882{
1883 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(object);
1884
1885 if (pool->vallocator)
1886 gst_object_unref(pool->vallocator);
1887 pool->vallocator = NULL;
1888
1889 if (pool->allocator)
1890 gst_object_unref(pool->allocator);
1891 pool->allocator = NULL;
1892
1893 if (pool->other_pool)
1894 gst_object_unref(pool->other_pool);
1895 pool->other_pool = NULL;
1896
1897 G_OBJECT_CLASS(parent_class)->dispose(object);
1898}
1899
1900static void
1901gst_aml_v4l2_buffer_pool_finalize(GObject *object)
1902{
1903 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(object);
1904
1905 if (pool->video_fd >= 0)
1906 pool->obj->close(pool->video_fd);
1907
1908 gst_poll_free(pool->poll);
1909
1910 /* This can't be done in dispose method because we must not set pointer
1911 * to NULL as it is part of the v4l2object and dispose could be called
1912 * multiple times */
1913 gst_object_unref(pool->obj->element);
1914
1915 g_cond_clear(&pool->empty_cond);
1916
1917 /* FIXME have we done enough here ? */
1918
1919 G_OBJECT_CLASS(parent_class)->finalize(object);
1920}
1921
1922static void
1923gst_aml_v4l2_buffer_pool_init(GstAmlV4l2BufferPool *pool)
1924{
1925 pool->poll = gst_poll_new(TRUE);
1926 pool->can_poll_device = TRUE;
1927 g_cond_init(&pool->empty_cond);
1928 pool->empty = TRUE;
1929 pool->orphaned = FALSE;
1930}
1931
1932static void
1933gst_aml_v4l2_buffer_pool_class_init(GstAmlV4l2BufferPoolClass *klass)
1934{
1935 GObjectClass *object_class = G_OBJECT_CLASS(klass);
1936 GstBufferPoolClass *bufferpool_class = GST_BUFFER_POOL_CLASS(klass);
1937
1938 object_class->dispose = gst_aml_v4l2_buffer_pool_dispose;
1939 object_class->finalize = gst_aml_v4l2_buffer_pool_finalize;
1940
1941 bufferpool_class->start = gst_aml_v4l2_buffer_pool_start;
1942 bufferpool_class->stop = gst_aml_v4l2_buffer_pool_stop;
1943 bufferpool_class->set_config = gst_aml_v4l2_buffer_pool_set_config;
1944 bufferpool_class->alloc_buffer = gst_aml_v4l2_buffer_pool_alloc_buffer;
1945 bufferpool_class->acquire_buffer = gst_aml_v4l2_buffer_pool_acquire_buffer;
1946 bufferpool_class->release_buffer = gst_aml_v4l2_buffer_pool_release_buffer;
1947 bufferpool_class->flush_start = gst_aml_v4l2_buffer_pool_flush_start;
1948 bufferpool_class->flush_stop = gst_aml_v4l2_buffer_pool_flush_stop;
1949
1950 GST_DEBUG_CATEGORY_INIT(amlv4l2bufferpool_debug, "amlv4l2bufferpool", 0,
1951 "V4L2 Buffer Pool");
1952 GST_DEBUG_CATEGORY_GET(CAT_PERFORMANCE, "GST_PERFORMANCE");
1953}
1954
1955/**
1956 * gst_aml_v4l2_buffer_pool_new:
1957 * @obj: the v4l2 object owning the pool
1958 *
1959 * Construct a new buffer pool.
1960 *
1961 * Returns: the new pool, use gst_object_unref() to free resources
1962 */
1963GstBufferPool *
1964gst_aml_v4l2_buffer_pool_new(GstAmlV4l2Object *obj, GstCaps *caps)
1965{
1966 GstAmlV4l2BufferPool *pool;
1967 GstStructure *config;
1968 gchar *name, *parent_name;
1969 gint fd;
1970
1971 fd = obj->dup(obj->video_fd);
1972 if (fd < 0)
1973 goto dup_failed;
1974
1975 /* setting a significant unique name */
1976 parent_name = gst_object_get_name(GST_OBJECT(obj->element));
1977 name = g_strconcat(parent_name, ":", "pool:",
1978 V4L2_TYPE_IS_OUTPUT(obj->type) ? "sink" : "src", NULL);
1979 g_free(parent_name);
1980
1981 pool = (GstAmlV4l2BufferPool *)g_object_new(GST_TYPE_AML_V4L2_BUFFER_POOL,
1982 "name", name, NULL);
1983 g_object_ref_sink(pool);
1984 g_free(name);
1985
1986 gst_poll_fd_init(&pool->pollfd);
1987 pool->pollfd.fd = fd;
1988 gst_poll_add_fd(pool->poll, &pool->pollfd);
1989 if (V4L2_TYPE_IS_OUTPUT(obj->type))
sheng.liu8d18ed22022-05-26 17:28:15 +08001990 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08001991 gst_poll_fd_ctl_write(pool->poll, &pool->pollfd, TRUE);
sheng.liu8d18ed22022-05-26 17:28:15 +08001992 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001993 else
sheng.liu8d18ed22022-05-26 17:28:15 +08001994 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08001995 gst_poll_fd_ctl_read(pool->poll, &pool->pollfd, TRUE);
sheng.liu8d18ed22022-05-26 17:28:15 +08001996 gst_poll_fd_ctl_pri (pool->poll, &pool->pollfd, TRUE);
1997 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001998
1999 pool->video_fd = fd;
2000 pool->obj = obj;
2001 pool->can_poll_device = TRUE;
2002
2003 pool->vallocator = gst_aml_v4l2_allocator_new(GST_OBJECT(pool), obj);
2004 if (pool->vallocator == NULL)
2005 goto allocator_failed;
2006
2007 gst_object_ref(obj->element);
2008
2009 config = gst_buffer_pool_get_config(GST_BUFFER_POOL_CAST(pool));
2010 gst_buffer_pool_config_set_params(config, caps, obj->info.size, 0, 0);
2011 /* This will simply set a default config, but will not configure the pool
2012 * because min and max are not valid */
2013 gst_buffer_pool_set_config(GST_BUFFER_POOL_CAST(pool), config);
2014
2015 return GST_BUFFER_POOL(pool);
2016
2017 /* ERRORS */
2018dup_failed:
2019{
2020 GST_ERROR("failed to dup fd %d (%s)", errno, g_strerror(errno));
2021 return NULL;
2022}
2023allocator_failed:
2024{
2025 GST_ERROR_OBJECT(pool, "Failed to create V4L2 allocator");
2026 gst_object_unref(pool);
2027 return NULL;
2028}
2029}
2030
2031static GstFlowReturn
2032gst_aml_v4l2_do_read(GstAmlV4l2BufferPool *pool, GstBuffer *buf)
2033{
2034 GstFlowReturn res;
2035 GstAmlV4l2Object *obj = pool->obj;
2036 gint amount;
2037 GstMapInfo map;
2038 gint toread;
2039
2040 toread = obj->info.size;
2041
2042 GST_LOG_OBJECT(pool, "reading %d bytes into buffer %p", toread, buf);
2043
2044 gst_buffer_map(buf, &map, GST_MAP_WRITE);
2045
2046 do
2047 {
2048 if ((res = gst_aml_v4l2_buffer_pool_poll(pool, TRUE)) != GST_FLOW_OK)
2049 goto poll_error;
2050
2051 amount = obj->read(obj->video_fd, map.data, toread);
2052
2053 if (amount == toread)
2054 {
2055 break;
2056 }
2057 else if (amount == -1)
2058 {
2059 if (errno == EAGAIN || errno == EINTR)
2060 {
2061 continue;
2062 }
2063 else
2064 goto read_error;
2065 }
2066 else
2067 {
2068 /* short reads can happen if a signal interrupts the read */
2069 continue;
2070 }
2071 } while (TRUE);
2072
2073 GST_LOG_OBJECT(pool, "read %d bytes", amount);
2074 gst_buffer_unmap(buf, &map);
2075 gst_buffer_resize(buf, 0, amount);
2076
2077 return GST_FLOW_OK;
2078
2079 /* ERRORS */
2080poll_error:
2081{
2082 GST_DEBUG("poll error %s", gst_flow_get_name(res));
2083 goto cleanup;
2084}
2085read_error:
2086{
2087 GST_ELEMENT_ERROR(obj->element, RESOURCE, READ,
2088 (_("Error reading %d bytes from device '%s'."),
2089 toread, obj->videodev),
2090 GST_ERROR_SYSTEM);
2091 res = GST_FLOW_ERROR;
2092 goto cleanup;
2093}
2094cleanup:
2095{
2096 gst_buffer_unmap(buf, &map);
2097 gst_buffer_resize(buf, 0, 0);
2098 return res;
2099}
2100}
2101
2102/**
2103 * gst_aml_v4l2_buffer_pool_process:
2104 * @bpool: a #GstBufferPool
2105 * @buf: a #GstBuffer, maybe be replaced
2106 *
2107 * Process @buf in @bpool. For capture devices, this functions fills @buf with
2108 * data from the device. For output devices, this functions send the contents of
2109 * @buf to the device for playback.
2110 *
2111 * Returns: %GST_FLOW_OK on success.
2112 */
2113GstFlowReturn
2114gst_aml_v4l2_buffer_pool_process(GstAmlV4l2BufferPool *pool, GstBuffer **buf)
2115{
2116 GstFlowReturn ret = GST_FLOW_OK;
2117 GstBufferPool *bpool = GST_BUFFER_POOL_CAST(pool);
2118 GstAmlV4l2Object *obj = pool->obj;
2119
2120 GST_DEBUG_OBJECT(pool, "process buffer %p, buf_pool:%p, v4l2 output pool:%p", buf, (*buf)->pool, bpool);
2121
2122 if (GST_BUFFER_POOL_IS_FLUSHING(pool))
2123 return GST_FLOW_FLUSHING;
2124
2125 switch (obj->type)
2126 {
2127 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2128 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
2129 /* capture */
2130 switch (obj->mode)
2131 {
2132 case GST_V4L2_IO_RW:
2133 /* capture into the buffer */
2134 ret = gst_aml_v4l2_do_read(pool, *buf);
2135 break;
2136
2137 case GST_V4L2_IO_MMAP:
2138 case GST_V4L2_IO_DMABUF:
2139 {
2140 GstBuffer *tmp;
2141
2142 if ((*buf)->pool == bpool)
2143 {
2144 guint num_queued;
2145 gsize size = gst_buffer_get_size(*buf);
2146
2147 /* Legacy M2M devices return empty buffer when drained */
2148 if (size == 0 && GST_AML_V4L2_IS_M2M(obj->device_caps))
2149 goto eos;
2150
2151 if (GST_VIDEO_INFO_FORMAT(&pool->caps_info) !=
2152 GST_VIDEO_FORMAT_ENCODED &&
2153 size < pool->size)
2154 goto buffer_truncated;
2155
2156 num_queued = g_atomic_int_get(&pool->num_queued);
2157 GST_TRACE_OBJECT(pool, "Only %i buffer left in the capture queue.",
2158 num_queued);
2159
2160 /* If we have no more buffer, and can allocate it time to do so */
2161 if (num_queued == 0)
2162 {
2163 if (GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP))
2164 {
2165 ret = gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
2166 if (ret == GST_FLOW_OK)
2167 goto done;
2168 }
2169 }
2170
2171 /* start copying buffers when we are running low on buffers */
2172 if (num_queued < pool->copy_threshold)
2173 {
2174 GstBuffer *copy;
2175
2176 if (GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP))
2177 {
2178 ret = gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
2179 if (ret == GST_FLOW_OK)
2180 goto done;
2181 }
2182
2183 /* copy the buffer */
2184 copy = gst_buffer_copy_region(*buf,
2185 GST_BUFFER_COPY_ALL | GST_BUFFER_COPY_DEEP, 0, -1);
2186 GST_LOG_OBJECT(pool, "copy buffer %p->%p", *buf, copy);
2187
2188 /* and requeue so that we can continue capturing */
2189 gst_buffer_unref(*buf);
2190 *buf = copy;
2191 }
2192
2193 ret = GST_FLOW_OK;
2194 /* nothing, data was inside the buffer when we did _acquire() */
2195 goto done;
2196 }
2197
2198 /* buffer not from our pool, grab a frame and copy it into the target */
2199 if ((ret = gst_aml_v4l2_buffer_pool_dequeue(pool, &tmp, TRUE)) != GST_FLOW_OK)
2200 goto done;
2201
2202 if (obj->dumpframefile)
2203 {
2204 FILE *pFile = fopen(obj->dumpframefile, "ab");
2205 if (pFile)
2206 {
2207 int n = gst_buffer_n_memory(tmp);
2208 int i;
2209 GstMapInfo map_info;
2210 GstMemory *mem;
2211
2212 for (i = 0; i < n; ++i)
2213 {
2214 mem = gst_buffer_peek_memory(tmp, i);
2215 if (gst_memory_map(mem, &map_info, GST_MAP_READ))
2216 {
2217 fwrite(map_info.data, map_info.size, 1, pFile);
2218 gst_memory_unmap(mem, &map_info);
2219 }
2220 }
2221 fclose(pFile);
2222 }
2223 }
2224 /* An empty buffer on capture indicates the end of stream */
2225 if (gst_buffer_get_size(tmp) == 0)
2226 {
2227 gst_aml_v4l2_buffer_pool_release_buffer(bpool, tmp);
2228
2229 /* Legacy M2M devices return empty buffer when drained */
2230 if (GST_AML_V4L2_IS_M2M(obj->device_caps))
2231 goto eos;
2232 }
2233
2234 ret = gst_aml_v4l2_buffer_pool_copy_buffer(pool, *buf, tmp);
2235
2236 /* an queue the buffer again after the copy */
2237 gst_aml_v4l2_buffer_pool_release_buffer(bpool, tmp);
2238
2239 if (ret != GST_FLOW_OK)
2240 goto copy_failed;
2241 break;
2242 }
2243
2244 case GST_V4L2_IO_USERPTR:
2245 {
2246 struct UserPtrData *data;
2247 GstBuffer *tmp;
2248
2249 /* Replace our buffer with downstream allocated buffer */
2250 data = gst_mini_object_steal_qdata(GST_MINI_OBJECT(*buf),
2251 GST_AML_V4L2_IMPORT_QUARK);
2252 tmp = gst_buffer_ref(data->buffer);
2253 _unmap_userptr_frame(data);
2254
2255 /* Now tmp is writable, copy the flags and timestamp */
2256 gst_buffer_copy_into(tmp, *buf,
2257 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2258
2259 gst_buffer_replace(buf, tmp);
2260 gst_buffer_unref(tmp);
2261 break;
2262 }
2263
2264 case GST_V4L2_IO_DMABUF_IMPORT:
2265 {
2266 GstBuffer *tmp;
2267
2268 /* Replace our buffer with downstream allocated buffer */
2269 // tmp = gst_mini_object_steal_qdata(GST_MINI_OBJECT(*buf),
2270 // GST_AML_V4L2_IMPORT_QUARK);
2271 tmp = gst_mini_object_get_qdata(GST_MINI_OBJECT(*buf), GST_AML_V4L2_IMPORT_QUARK);
2272 GST_DEBUG("got v4l2 capture buf:%p, with qdata drm buf:%p", *buf, tmp);
2273
2274 gst_buffer_copy_into(tmp, *buf,
2275 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2276
2277 gst_buffer_replace(buf, tmp);
2278 gst_buffer_unref(tmp);
2279 break;
2280 }
2281
2282 default:
2283 g_assert_not_reached();
2284 break;
2285 }
2286 break;
2287
2288 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
2289 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
2290 /* playback */
2291 switch (obj->mode)
2292 {
2293 case GST_V4L2_IO_RW:
2294 /* FIXME, do write() */
2295 GST_WARNING_OBJECT(pool, "implement write()");
2296 break;
2297
2298 case GST_V4L2_IO_USERPTR:
2299 case GST_V4L2_IO_DMABUF_IMPORT:
2300 case GST_V4L2_IO_DMABUF:
2301 case GST_V4L2_IO_MMAP:
2302 {
2303 GstBuffer *to_queue = NULL;
2304 GstBuffer *buffer;
2305 GstAmlV4l2MemoryGroup *group;
2306 gint index;
2307
2308 if ((*buf)->pool != bpool)
2309 goto copying;
2310
2311 if (!gst_aml_v4l2_is_buffer_valid(*buf, &group))
2312 goto copying;
2313
2314 index = group->buffer.index;
2315
2316 GST_LOG_OBJECT(pool, "processing buffer %i from our pool", index);
2317
2318 if (pool->buffers[index] != NULL)
2319 {
2320 GST_LOG_OBJECT(pool, "buffer %i already queued, copying", index);
2321 goto copying;
2322 }
2323
2324 /* we can queue directly */
2325 to_queue = gst_buffer_ref(*buf);
2326
2327 copying:
2328 if (to_queue == NULL)
2329 {
2330 GstBufferPoolAcquireParams params = {0};
2331
2332 GST_LOG_OBJECT(pool, "alloc buffer from our pool");
2333
2334 /* this can return EOS if all buffers are outstanding which would
2335 * be strange because we would expect the upstream element to have
2336 * allocated them and returned to us.. */
2337 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
2338 ret = gst_buffer_pool_acquire_buffer(bpool, &to_queue, &params);
2339 if (ret != GST_FLOW_OK)
2340 goto acquire_failed;
2341
2342 ret = gst_aml_v4l2_buffer_pool_prepare_buffer(pool, to_queue, *buf);
2343 if (ret != GST_FLOW_OK)
2344 {
2345 gst_buffer_unref(to_queue);
2346 goto prepare_failed;
2347 }
2348
2349 /* retreive the group */
2350 gst_aml_v4l2_is_buffer_valid(to_queue, &group);
2351 }
2352
2353 if ((ret = gst_aml_v4l2_buffer_pool_qbuf(pool, to_queue, group)) != GST_FLOW_OK)
2354 goto queue_failed;
2355
2356 /* if we are not streaming yet (this is the first buffer, start
2357 * streaming now */
2358 if (!gst_aml_v4l2_buffer_pool_streamon(pool))
2359 {
2360 /* don't check return value because qbuf would have failed */
2361 gst_aml_v4l2_is_buffer_valid(to_queue, &group);
2362
2363 /* qbuf has stored to_queue buffer but we are not in
2364 * streaming state, so the flush logic won't be performed.
2365 * To avoid leaks, flush the allocator and restore the queued
2366 * buffer as non-queued */
2367 gst_aml_v4l2_allocator_flush(pool->vallocator);
2368
2369 pool->buffers[group->buffer.index] = NULL;
2370
2371 gst_mini_object_set_qdata(GST_MINI_OBJECT(to_queue),
2372 GST_AML_V4L2_IMPORT_QUARK, NULL, NULL);
2373 gst_buffer_unref(to_queue);
2374 g_atomic_int_add(&pool->num_queued, -1);
2375 goto start_failed;
2376 }
2377
2378 /* Remove our ref, we will still hold this buffer in acquire as needed,
2379 * otherwise the pool will think it is outstanding and will refuse to stop. */
2380 gst_buffer_unref(to_queue);
2381
2382 /* release as many buffer as possible */
2383 while (gst_aml_v4l2_buffer_pool_dequeue(pool, &buffer, FALSE) ==
2384 GST_FLOW_OK)
2385 {
2386 if (buffer->pool == NULL)
2387 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
2388 }
2389
2390 if (g_atomic_int_get(&pool->num_queued) >= pool->min_latency)
2391 {
2392 /* all buffers are queued, try to dequeue one and release it back
2393 * into the pool so that _acquire can get to it again. */
2394 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, &buffer, TRUE);
2395 if (ret == GST_FLOW_OK && buffer->pool == NULL)
2396 /* release the rendered buffer back into the pool. This wakes up any
2397 * thread waiting for a buffer in _acquire(). */
2398 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
2399 }
2400 break;
2401 }
2402 default:
2403 g_assert_not_reached();
2404 break;
2405 }
2406 break;
2407 default:
2408 g_assert_not_reached();
2409 break;
2410 }
2411done:
2412 return ret;
2413
2414 /* ERRORS */
2415copy_failed:
2416{
2417 GST_ERROR_OBJECT(pool, "failed to copy buffer");
2418 return ret;
2419}
2420buffer_truncated:
2421{
2422 GST_WARNING_OBJECT(pool,
2423 "Dropping truncated buffer, this is likely a driver bug.");
2424 gst_buffer_unref(*buf);
2425 *buf = NULL;
2426 return GST_AML_V4L2_FLOW_CORRUPTED_BUFFER;
2427}
2428eos:
2429{
2430 GST_DEBUG_OBJECT(pool, "end of stream reached");
2431 gst_buffer_unref(*buf);
2432 *buf = NULL;
2433 return GST_AML_V4L2_FLOW_LAST_BUFFER;
2434}
2435acquire_failed:
2436{
2437 if (ret == GST_FLOW_FLUSHING)
2438 GST_DEBUG_OBJECT(pool, "flushing");
2439 else
2440 GST_WARNING_OBJECT(pool, "failed to acquire a buffer: %s",
2441 gst_flow_get_name(ret));
2442 return ret;
2443}
2444prepare_failed:
2445{
2446 GST_ERROR_OBJECT(pool, "failed to prepare data");
2447 return ret;
2448}
2449queue_failed:
2450{
2451 GST_ERROR_OBJECT(pool, "failed to queue buffer");
2452 return ret;
2453}
2454start_failed:
2455{
2456 GST_ERROR_OBJECT(pool, "failed to start streaming");
2457 return GST_FLOW_ERROR;
2458}
2459}
2460
2461void gst_aml_v4l2_buffer_pool_set_other_pool(GstAmlV4l2BufferPool *pool,
2462 GstBufferPool *other_pool)
2463{
2464 g_return_if_fail(!gst_buffer_pool_is_active(GST_BUFFER_POOL(pool)));
2465
2466 if (pool->other_pool)
2467 gst_object_unref(pool->other_pool);
2468 pool->other_pool = gst_object_ref(other_pool);
2469}
2470
2471void gst_aml_v4l2_buffer_pool_copy_at_threshold(GstAmlV4l2BufferPool *pool, gboolean copy)
2472{
2473 GST_OBJECT_LOCK(pool);
2474 pool->enable_copy_threshold = copy;
2475 GST_OBJECT_UNLOCK(pool);
2476}
2477
2478gboolean
2479gst_aml_v4l2_buffer_pool_flush(GstBufferPool *bpool)
2480{
2481 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
2482 gboolean ret = TRUE;
2483
2484 gst_aml_v4l2_buffer_pool_streamoff(pool);
2485
2486 if (!V4L2_TYPE_IS_OUTPUT(pool->obj->type))
2487 ret = gst_aml_v4l2_buffer_pool_streamon(pool);
2488
2489 return ret;
2490}
2491
2492void gst_aml_v4l2_buffer_pool_dump_stat(GstAmlV4l2BufferPool *pool, const gchar *file_name, gint try_num)
2493{
2494 const gchar *dump_dir = NULL;
2495 gchar *full_file_name = NULL;
2496 FILE *out = NULL;
2497
2498 dump_dir = g_getenv("GST_DEBUG_DUMP_AMLV4L2DEC_STAT_DIR");
2499 if (G_LIKELY(dump_dir == NULL))
2500 return;
2501
2502 if (!file_name)
2503 {
2504 file_name = "unnamed";
2505 }
2506
2507 full_file_name = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s.stat", dump_dir, file_name);
2508
2509 if ((out = fopen(full_file_name, "w")))
2510 {
2511 GstStructure *config = NULL;
2512 config = gst_buffer_pool_get_config((GstBufferPool *)pool);
2513 if (config)
2514 {
2515 GstCaps *caps;
2516 guint size, min_buffers, max_buffers;
2517 if (gst_buffer_pool_config_get_params(config, &caps, &size, &min_buffers, &max_buffers))
2518 {
2519 gchar *stat_info;
2520
2521 /* set local pool info*/
2522 gint already_queued = 0;
2523 gint ready_to_queue_num = 0;
2524 for (gint i = 0; i < VIDEO_MAX_FRAME; i++)
2525 {
2526 if (pool->buffers[i])
2527 {
2528 already_queued++;
2529 }
2530 if (pool->read_to_free_bufs[i])
2531 {
2532 ready_to_queue_num++;
2533 }
2534 }
2535
2536 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",
2537 size, min_buffers, max_buffers,
2538 pool->num_queued, pool->num_allocated,
2539 already_queued, ready_to_queue_num, try_num);
2540 fputs(stat_info, out);
2541 g_free(stat_info);
2542
2543 /* set other pool info*/
2544 if (pool->other_pool)
2545 {
2546 GstStructure *other_config = NULL;
2547 other_config = gst_buffer_pool_get_config((GstBufferPool *)pool);
2548 if (other_config)
2549 {
2550 GstCaps *other_caps;
2551 guint other_size, other_min_buffers, other_max_buffers;
2552 if (gst_buffer_pool_config_get_params(config, &other_caps, &other_size, &other_min_buffers, &other_max_buffers))
2553 {
2554 stat_info = g_strdup_printf("other pool | size:%d, min_bufs:%d, max_bufs:%d\n",
2555 other_size, other_min_buffers, other_max_buffers);
2556
2557 // TODO:GstBufferPool中没有获取outstanding的接口,所以这里没有统计otherpool中在用buffer的状态,后续需要修改gstreamer-1.0中code新增接口
2558 fputs(stat_info, out);
2559 g_free(stat_info);
2560 }
2561 }
2562 }
2563 GST_INFO("wrote amlv4l2 bufferpool stat to : '%s' succ", full_file_name);
2564 }
2565 }
2566 else
2567 {
2568 GST_WARNING("Failed to get config for pool:%p", pool);
2569 }
2570 fclose(out);
2571 }
2572 else
2573 {
2574 GST_WARNING("Failed to open file '%s' for writing: %s", full_file_name, g_strerror(errno));
2575 }
2576 g_free(full_file_name);
2577}