blob: 5d9f8b11666250d1239b4a9bd6ff71b8e5ff4405 [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 }
zengliang.li32cb11e2022-11-24 12:10:26 +08001301 else
1302 {
1303 group->buffer.timestamp.tv_sec= -1;
1304 group->buffer.timestamp.tv_usec= 0;
1305 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001306
1307 GST_OBJECT_LOCK(pool);
1308 g_atomic_int_inc(&pool->num_queued);
1309 pool->buffers[index] = buf;
1310
1311 if (!gst_aml_v4l2_allocator_qbuf(pool->vallocator, group))
1312 goto queue_failed;
1313
1314 if (!V4L2_TYPE_IS_OUTPUT(obj->type))
1315 {
1316 gst_aml_v4l2_buffer_pool_dump_stat(pool, GST_DUMP_CAPTURE_BP_STAT_FILENAME, 0);
1317 }
1318
1319 pool->empty = FALSE;
1320 g_cond_signal(&pool->empty_cond);
1321 GST_OBJECT_UNLOCK(pool);
1322
1323 return GST_FLOW_OK;
1324
1325already_queued:
1326{
1327 GST_ERROR_OBJECT(pool, "the buffer %i was already queued", index);
1328 return GST_FLOW_ERROR;
1329}
1330queue_failed:
1331{
1332 GST_ERROR_OBJECT(pool, "could not queue a buffer %i", index);
1333 /* Mark broken buffer to the allocator */
1334 GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_TAG_MEMORY);
1335 g_atomic_int_add(&pool->num_queued, -1);
1336 pool->buffers[index] = NULL;
1337 GST_OBJECT_UNLOCK(pool);
1338 return GST_FLOW_ERROR;
1339}
1340}
1341
1342static GstFlowReturn
1343gst_aml_v4l2_buffer_pool_dqevent(GstAmlV4l2BufferPool *pool)
1344{
1345 GstAmlV4l2Object *v4l2object = pool->obj;
1346 struct v4l2_event evt;
1347
1348 memset(&evt, 0x00, sizeof(struct v4l2_event));
1349 if (v4l2object->ioctl(pool->video_fd, VIDIOC_DQEVENT, &evt) < 0)
1350 goto dqevent_failed;
1351
1352 switch (evt.type)
1353 {
1354 case V4L2_EVENT_SOURCE_CHANGE:
sheng.liu8d18ed22022-05-26 17:28:15 +08001355
1356 if (evt.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION)
1357 return GST_AML_V4L2_FLOW_SOURCE_CHANGE;
1358 GST_WARNING_OBJECT (pool, "Unknown source change 0x%x - skipped", evt.u.src_change.changes);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001359 break;
1360 case V4L2_EVENT_EOS:
1361 return GST_AML_V4L2_FLOW_LAST_BUFFER;
1362 break;
1363 default:
1364 break;
1365 }
1366
1367 return GST_FLOW_OK;
1368
1369 /* ERRORS */
1370dqevent_failed:
1371{
1372 return GST_FLOW_ERROR;
1373}
1374}
1375
1376static GstFlowReturn
1377gst_aml_v4l2_buffer_pool_dqbuf(GstAmlV4l2BufferPool *pool, GstBuffer **buffer,
1378 gboolean wait)
1379{
1380 GstFlowReturn res;
1381 GstBuffer *outbuf = NULL;
1382 GstAmlV4l2Object *obj = pool->obj;
1383 GstClockTime timestamp;
1384 GstAmlV4l2MemoryGroup *group;
1385 GstVideoMeta *vmeta;
1386 gsize size;
1387 gint i;
1388
1389 res = gst_aml_v4l2_allocator_dqbuf(pool->vallocator, &group);
1390 if (res == GST_FLOW_EOS)
1391 goto eos;
1392 if (res != GST_FLOW_OK)
1393 goto dqbuf_failed;
1394
1395 /* get our GstBuffer with that index from the pool, if the buffer was
1396 * outstanding we have a serious problem.
1397 */
1398 outbuf = pool->buffers[group->buffer.index];
1399 if (outbuf == NULL)
1400 goto no_buffer;
1401
1402 /* mark the buffer outstanding */
1403 pool->buffers[group->buffer.index] = NULL;
1404 if (g_atomic_int_dec_and_test(&pool->num_queued))
1405 {
1406 GST_OBJECT_LOCK(pool);
1407 pool->empty = TRUE;
1408 GST_OBJECT_UNLOCK(pool);
1409 }
1410
1411 timestamp = GST_TIMEVAL_TO_TIME(group->buffer.timestamp);
1412
1413 size = 0;
1414 vmeta = gst_buffer_get_video_meta(outbuf);
1415 for (i = 0; i < group->n_mem; i++)
1416 {
1417 GST_LOG_OBJECT(pool,
1418 "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,
1419 group->buffer.sequence, group->buffer.index, group->mem[i],
1420 group->planes[i].bytesused, i, group->buffer.flags,
1421 GST_TIME_ARGS(timestamp), pool->num_queued, outbuf);
1422
1423 if (vmeta)
1424 {
1425 vmeta->offset[i] = size;
1426 size += gst_memory_get_sizes(group->mem[i], NULL, NULL);
1427 }
1428 }
1429
1430 /* Ignore timestamp and field for OUTPUT device */
1431 if (V4L2_TYPE_IS_OUTPUT(obj->type))
1432 goto done;
1433
1434 /* Check for driver bug in reporting feild */
1435 if (group->buffer.field == V4L2_FIELD_ANY)
1436 {
1437 /* Only warn once to avoid the spamming */
1438#ifndef GST_DISABLE_GST_DEBUG
1439 if (!pool->has_warned_on_buggy_field)
1440 {
1441 pool->has_warned_on_buggy_field = TRUE;
1442 GST_WARNING_OBJECT(pool,
1443 "Driver should never set v4l2_buffer.field to ANY");
1444 }
1445#endif
1446
1447 /* Use the value from the format (works for UVC bug) */
1448 group->buffer.field = obj->format.fmt.pix.field;
1449
1450 /* If driver also has buggy S_FMT, assume progressive */
1451 if (group->buffer.field == V4L2_FIELD_ANY)
1452 {
1453#ifndef GST_DISABLE_GST_DEBUG
1454 if (!pool->has_warned_on_buggy_field)
1455 {
1456 pool->has_warned_on_buggy_field = TRUE;
1457 GST_WARNING_OBJECT(pool,
1458 "Driver should never set v4l2_format.pix.field to ANY");
1459 }
1460#endif
1461
1462 group->buffer.field = V4L2_FIELD_NONE;
1463 }
1464 }
1465
1466 /* set top/bottom field first if v4l2_buffer has the information */
1467 switch (group->buffer.field)
1468 {
1469 case V4L2_FIELD_NONE:
1470 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1471 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1472 break;
1473 case V4L2_FIELD_INTERLACED_TB:
1474 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1475 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1476 break;
1477 case V4L2_FIELD_INTERLACED_BT:
1478 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1479 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1480 break;
1481 case V4L2_FIELD_INTERLACED:
1482 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1483 if (obj->tv_norm == V4L2_STD_NTSC_M ||
1484 obj->tv_norm == V4L2_STD_NTSC_M_JP ||
1485 obj->tv_norm == V4L2_STD_NTSC_M_KR)
1486 {
1487 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1488 }
1489 else
1490 {
1491 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1492 }
1493 break;
1494 default:
1495 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1496 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1497 GST_FIXME_OBJECT(pool,
1498 "Unhandled enum v4l2_field %d - treating as progressive",
1499 group->buffer.field);
1500 break;
1501 }
1502
1503 if (GST_VIDEO_INFO_FORMAT(&obj->info) == GST_VIDEO_FORMAT_ENCODED)
1504 {
1505 if ((group->buffer.flags & V4L2_BUF_FLAG_KEYFRAME) ||
1506 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_MJPEG ||
1507 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_JPEG ||
1508 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_PJPG)
1509 GST_BUFFER_FLAG_UNSET(outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1510 else
1511 GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1512 }
1513
1514 if (group->buffer.flags & V4L2_BUF_FLAG_ERROR)
1515 GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_FLAG_CORRUPTED);
1516
1517 GST_BUFFER_TIMESTAMP(outbuf) = timestamp;
1518 GST_BUFFER_OFFSET(outbuf) = group->buffer.sequence;
1519 GST_BUFFER_OFFSET_END(outbuf) = group->buffer.sequence + 1;
1520
1521done:
1522 *buffer = outbuf;
1523
1524 if (!V4L2_TYPE_IS_OUTPUT(obj->type))
1525 {
1526 gst_aml_v4l2_buffer_pool_dump_stat(pool, GST_DUMP_CAPTURE_BP_STAT_FILENAME, 0);
1527 }
1528
1529 return res;
1530
1531 /* ERRORS */
1532eos:
1533{
1534 return GST_FLOW_EOS;
1535}
1536dqbuf_failed:
1537{
1538 return GST_FLOW_ERROR;
1539}
1540no_buffer:
1541{
1542 GST_ERROR_OBJECT(pool, "No free buffer found in the pool at index %d.",
1543 group->buffer.index);
1544 return GST_FLOW_ERROR;
1545}
1546}
1547
1548static GstFlowReturn
1549gst_aml_v4l2_buffer_pool_dequeue(GstAmlV4l2BufferPool *pool, GstBuffer **buffer,
1550 gboolean wait)
1551{
1552 GstFlowReturn res;
1553 GstAmlV4l2Object *obj = pool->obj;
1554
1555 if ((res = gst_aml_v4l2_buffer_pool_poll(pool, wait)) != GST_FLOW_OK)
1556 goto poll_failed;
1557
1558 if (obj->can_wait_event && gst_poll_fd_can_read_pri(pool->poll, &pool->pollfd))
1559 {
sheng.liu8d18ed22022-05-26 17:28:15 +08001560 GstFlowReturn res_event = gst_aml_v4l2_buffer_pool_dqevent(pool);
1561 if (res_event != GST_FLOW_OK)
1562 return res_event;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001563 }
1564
1565 if (res == GST_FLOW_CUSTOM_SUCCESS)
1566 {
1567 GST_LOG_OBJECT(pool, "nothing to dequeue");
1568 *buffer = NULL;
1569 return res;
1570 }
1571
1572 GST_LOG_OBJECT(pool, "dequeueing a buffer");
1573 return gst_aml_v4l2_buffer_pool_dqbuf(pool, buffer, wait);
1574
1575 /* ERRORS */
1576poll_failed:
1577{
1578 GST_DEBUG_OBJECT(pool, "poll error %s", gst_flow_get_name(res));
1579 return res;
1580}
1581}
1582
1583static GstFlowReturn
1584gst_aml_v4l2_buffer_pool_acquire_buffer(GstBufferPool *bpool, GstBuffer **buffer,
1585 GstBufferPoolAcquireParams *params)
1586{
1587 GstFlowReturn ret;
1588 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1589 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
1590 GstAmlV4l2Object *obj = pool->obj;
1591
1592 GST_DEBUG_OBJECT(pool, "acquire");
1593
1594 /* If this is being called to resurrect a lost buffer */
1595 if (params && params->flags & GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT)
1596 {
1597 ret = pclass->acquire_buffer(bpool, buffer, params);
1598 goto done;
1599 }
1600
1601 switch (obj->type)
1602 {
1603 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1604 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1605 /* capture, This function should return a buffer with new captured data */
1606 switch (obj->mode)
1607 {
1608 case GST_V4L2_IO_RW:
1609 {
1610 /* take empty buffer from the pool */
1611 ret = pclass->acquire_buffer(bpool, buffer, params);
1612 break;
1613 }
1614 case GST_V4L2_IO_DMABUF:
1615 case GST_V4L2_IO_MMAP:
1616 case GST_V4L2_IO_USERPTR:
xuesong.jiang3df0f7b2022-11-29 14:52:45 +08001617 {
1618 /* just dequeue a buffer, we basically use the queue of v4l2 as the
1619 * storage for our buffers. This function does poll first so we can
1620 * interrupt it fine. */
1621 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, TRUE);
1622
1623 break;
1624 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001625 case GST_V4L2_IO_DMABUF_IMPORT:
1626 {
1627#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1628 GST_DEBUG_OBJECT(pool, "amlmodbuf return free buf before acquire buf");
1629 gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(bpool);
1630 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, FALSE);
1631#else
1632 /* just dequeue a buffer, we basically use the queue of v4l2 as the
1633 * storage for our buffers. This function does poll first so we can
1634 * interrupt it fine. */
1635 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, TRUE);
1636#endif
1637 break;
1638 }
1639 default:
1640 ret = GST_FLOW_ERROR;
1641 g_assert_not_reached();
1642 break;
1643 }
1644 break;
1645
1646 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1647 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1648 /* playback, This function should return an empty buffer */
1649 switch (obj->mode)
1650 {
1651 case GST_V4L2_IO_RW:
1652 /* get an empty buffer */
1653 ret = pclass->acquire_buffer(bpool, buffer, params);
1654 break;
1655
1656 case GST_V4L2_IO_MMAP:
1657 case GST_V4L2_IO_DMABUF:
1658 case GST_V4L2_IO_USERPTR:
1659 case GST_V4L2_IO_DMABUF_IMPORT:
1660 /* get a free unqueued buffer */
1661 ret = pclass->acquire_buffer(bpool, buffer, params);
1662 break;
1663
1664 default:
1665 ret = GST_FLOW_ERROR;
1666 g_assert_not_reached();
1667 break;
1668 }
1669 break;
1670
1671 default:
1672 ret = GST_FLOW_ERROR;
1673 g_assert_not_reached();
1674 break;
1675 }
1676done:
1677 return ret;
1678}
1679
1680static void
1681gst_aml_v4l2_buffer_pool_release_buffer(GstBufferPool *bpool, GstBuffer *buffer)
1682{
1683 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1684 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
1685 GstAmlV4l2Object *obj = pool->obj;
1686
1687 GST_DEBUG_OBJECT(pool, "release buffer %p", buffer);
1688
1689 /* If the buffer's pool has been orphaned, dispose of it so that
1690 * the pool resources can be freed */
1691 if (pool->orphaned)
1692 {
1693 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
1694 pclass->release_buffer(bpool, buffer);
1695 return;
1696 }
1697
1698 switch (obj->type)
1699 {
1700 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1701 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1702 /* capture, put the buffer back in the queue so that we can refill it
1703 * later. */
1704 switch (obj->mode)
1705 {
1706 case GST_V4L2_IO_RW:
1707 /* release back in the pool */
1708 pclass->release_buffer(bpool, buffer);
1709 break;
1710
1711 case GST_V4L2_IO_DMABUF:
1712 case GST_V4L2_IO_MMAP:
1713 case GST_V4L2_IO_USERPTR:
1714 case GST_V4L2_IO_DMABUF_IMPORT:
1715 {
1716 GstAmlV4l2MemoryGroup *group;
1717 if (gst_aml_v4l2_is_buffer_valid(buffer, &group))
1718 {
1719 GstFlowReturn ret = GST_FLOW_OK;
1720
1721 gst_aml_v4l2_allocator_reset_group(pool->vallocator, group);
1722
1723#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1724 GST_DEBUG_OBJECT(pool, "amlmodbuf trace in add flow with buf:%p index:%d", buffer, group->buffer.index);
1725 pool->read_to_free_bufs[group->buffer.index] = buffer;
1726 pool->ready_to_free_buf_num++;
1727 if (gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(bpool))
1728 {
1729 GST_DEBUG_OBJECT(pool, "amlmodbuf execute aml code logic, skip the following flow");
1730 return;
1731 }
1732#endif
1733 /* queue back in the device */
1734 if (pool->other_pool)
1735 ret = gst_aml_v4l2_buffer_pool_prepare_buffer(pool, buffer, NULL);
1736 if (ret != GST_FLOW_OK ||
1737 gst_aml_v4l2_buffer_pool_qbuf(pool, buffer, group) != GST_FLOW_OK)
1738 pclass->release_buffer(bpool, buffer);
1739 }
1740 else
1741 {
1742 /* Simply release invalide/modified buffer, the allocator will
1743 * give it back later */
1744 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
1745 pclass->release_buffer(bpool, buffer);
1746 }
1747 break;
1748 }
1749 default:
1750 g_assert_not_reached();
1751 break;
1752 }
1753 break;
1754
1755 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1756 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1757 switch (obj->mode)
1758 {
1759 case GST_V4L2_IO_RW:
1760 /* release back in the pool */
1761 pclass->release_buffer(bpool, buffer);
1762 break;
1763
1764 case GST_V4L2_IO_MMAP:
1765 case GST_V4L2_IO_DMABUF:
1766 case GST_V4L2_IO_USERPTR:
1767 case GST_V4L2_IO_DMABUF_IMPORT:
1768 {
1769 GstAmlV4l2MemoryGroup *group;
1770 guint index;
1771
1772 if (!gst_aml_v4l2_is_buffer_valid(buffer, &group))
1773 {
1774 /* Simply release invalide/modified buffer, the allocator will
1775 * give it back later */
1776 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
1777 pclass->release_buffer(bpool, buffer);
1778 break;
1779 }
1780
1781 index = group->buffer.index;
1782
1783 if (pool->buffers[index] == NULL)
1784 {
1785 GST_LOG_OBJECT(pool, "buffer %u not queued, putting on free list",
1786 index);
1787
1788 /* Remove qdata, this will unmap any map data in userptr */
1789 gst_mini_object_set_qdata(GST_MINI_OBJECT(buffer),
1790 GST_AML_V4L2_IMPORT_QUARK, NULL, NULL);
1791
1792 /* reset to default size */
1793 gst_aml_v4l2_allocator_reset_group(pool->vallocator, group);
1794
1795 /* playback, put the buffer back in the queue to refill later. */
1796 pclass->release_buffer(bpool, buffer);
1797 }
1798 else
1799 {
1800 /* the buffer is queued in the device but maybe not played yet. We just
1801 * leave it there and not make it available for future calls to acquire
1802 * for now. The buffer will be dequeued and reused later. */
1803 GST_LOG_OBJECT(pool, "buffer %u is queued", index);
1804 }
1805 break;
1806 }
1807
1808 default:
1809 g_assert_not_reached();
1810 break;
1811 }
1812 break;
1813
1814 default:
1815 g_assert_not_reached();
1816 break;
1817 }
1818}
1819
1820#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1821static gboolean
1822gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(GstBufferPool *bpool)
1823{
1824 GstFlowReturn ret = GST_FLOW_OK;
1825 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1826 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
1827 GstAmlV4l2Object *obj = pool->obj;
1828
1829 if (obj->mode == GST_V4L2_IO_DMABUF_IMPORT && pool->other_pool)
1830 {
1831 GstBuffer *src = NULL;
1832 GstBufferPoolAcquireParams params;
1833
1834 memset(&params, 0, sizeof(GstBufferPoolAcquireParams));
1835 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
1836 GST_DEBUG_OBJECT(pool, "amlmodbuf trace in aml release buf flow ready_to_free_buf_num:%d", pool->ready_to_free_buf_num);
1837 while (pool->ready_to_free_buf_num && gst_buffer_pool_acquire_buffer(pool->other_pool, &src, &params) != GST_FLOW_ERROR && src != NULL)
1838 {
1839 gint i = 0;
1840
1841 GST_DEBUG_OBJECT(pool, "amlmodbuf acquire buf:%p form other pool", src);
1842 for (; i < VIDEO_MAX_FRAME; i++)
1843 {
1844 GST_DEBUG_OBJECT(pool, "amlmodbuf check index:%d", i);
1845 if (pool->read_to_free_bufs[i])
1846 {
1847 GstBuffer *bind_drm_buf = gst_mini_object_get_qdata(GST_MINI_OBJECT(pool->read_to_free_bufs[i]), GST_AML_V4L2_IMPORT_QUARK);
1848 if (bind_drm_buf == NULL)
1849 {
1850 GST_DEBUG_OBJECT(pool, "init flow, bind v4l2 capture buf[%d]:%p with drm buf:%p", i, pool->read_to_free_bufs[i], src);
1851 }
1852 else if (src != bind_drm_buf)
1853 {
1854 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);
1855 continue;
1856 }
1857
1858 GST_DEBUG_OBJECT(pool, "v4l2 capture buf[%d]:%p found bind drm buf:%p", i, pool->read_to_free_bufs[i], src);
1859 GstFlowReturn isvalid = GST_FLOW_OK;
1860 GstAmlV4l2MemoryGroup *tmp_group = NULL;
1861
1862 // bind_drm_buf= gst_mini_object_steal_qdata(GST_MINI_OBJECT(pool->read_to_free_bufs[i]), GST_AML_V4L2_IMPORT_QUARK);
1863 ret = gst_aml_v4l2_buffer_pool_import_dmabuf(pool, pool->read_to_free_bufs[i], src);
1864 gst_buffer_unref(src);
1865 src = NULL;
1866 isvalid = gst_aml_v4l2_is_buffer_valid(pool->read_to_free_bufs[i], &tmp_group);
1867 if ((ret != GST_FLOW_OK && isvalid) || gst_aml_v4l2_buffer_pool_qbuf(pool, pool->read_to_free_bufs[i], tmp_group) != GST_FLOW_OK)
1868 {
1869 GST_DEBUG_OBJECT(pool, "amlmodbuf go into error flow");
1870 pclass->release_buffer(bpool, pool->read_to_free_bufs[i]);
1871 }
1872 pool->read_to_free_bufs[i] = NULL;
1873 pool->ready_to_free_buf_num--;
1874 GST_DEBUG_OBJECT(pool, "amlmodbuf queued buf:%d, into v4l2 bp", i);
1875 break;
1876 }
1877 }
1878 if (i == VIDEO_MAX_FRAME)
1879 {
1880 GST_ERROR_OBJECT(pool, "drm buf:%p can't match any v4l2 capture buf, error", src);
1881 gst_buffer_unref(src);
1882 src = NULL;
1883 return FALSE;
1884 }
1885 }
1886 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);
1887 return TRUE;
1888 }
1889 return FALSE;
1890}
1891#endif
1892
1893static void
1894gst_aml_v4l2_buffer_pool_dispose(GObject *object)
1895{
1896 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(object);
1897
1898 if (pool->vallocator)
1899 gst_object_unref(pool->vallocator);
1900 pool->vallocator = NULL;
1901
1902 if (pool->allocator)
1903 gst_object_unref(pool->allocator);
1904 pool->allocator = NULL;
1905
1906 if (pool->other_pool)
1907 gst_object_unref(pool->other_pool);
1908 pool->other_pool = NULL;
1909
1910 G_OBJECT_CLASS(parent_class)->dispose(object);
1911}
1912
1913static void
1914gst_aml_v4l2_buffer_pool_finalize(GObject *object)
1915{
1916 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(object);
1917
1918 if (pool->video_fd >= 0)
1919 pool->obj->close(pool->video_fd);
1920
1921 gst_poll_free(pool->poll);
1922
1923 /* This can't be done in dispose method because we must not set pointer
1924 * to NULL as it is part of the v4l2object and dispose could be called
1925 * multiple times */
1926 gst_object_unref(pool->obj->element);
1927
1928 g_cond_clear(&pool->empty_cond);
1929
1930 /* FIXME have we done enough here ? */
1931
1932 G_OBJECT_CLASS(parent_class)->finalize(object);
1933}
1934
1935static void
1936gst_aml_v4l2_buffer_pool_init(GstAmlV4l2BufferPool *pool)
1937{
1938 pool->poll = gst_poll_new(TRUE);
1939 pool->can_poll_device = TRUE;
1940 g_cond_init(&pool->empty_cond);
hanghang.luo3128f102022-08-18 10:36:19 +08001941 GST_OBJECT_LOCK(pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001942 pool->empty = TRUE;
hanghang.luo3128f102022-08-18 10:36:19 +08001943 GST_OBJECT_UNLOCK(pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001944 pool->orphaned = FALSE;
1945}
1946
1947static void
1948gst_aml_v4l2_buffer_pool_class_init(GstAmlV4l2BufferPoolClass *klass)
1949{
1950 GObjectClass *object_class = G_OBJECT_CLASS(klass);
1951 GstBufferPoolClass *bufferpool_class = GST_BUFFER_POOL_CLASS(klass);
1952
1953 object_class->dispose = gst_aml_v4l2_buffer_pool_dispose;
1954 object_class->finalize = gst_aml_v4l2_buffer_pool_finalize;
1955
1956 bufferpool_class->start = gst_aml_v4l2_buffer_pool_start;
1957 bufferpool_class->stop = gst_aml_v4l2_buffer_pool_stop;
1958 bufferpool_class->set_config = gst_aml_v4l2_buffer_pool_set_config;
1959 bufferpool_class->alloc_buffer = gst_aml_v4l2_buffer_pool_alloc_buffer;
1960 bufferpool_class->acquire_buffer = gst_aml_v4l2_buffer_pool_acquire_buffer;
1961 bufferpool_class->release_buffer = gst_aml_v4l2_buffer_pool_release_buffer;
1962 bufferpool_class->flush_start = gst_aml_v4l2_buffer_pool_flush_start;
1963 bufferpool_class->flush_stop = gst_aml_v4l2_buffer_pool_flush_stop;
1964
1965 GST_DEBUG_CATEGORY_INIT(amlv4l2bufferpool_debug, "amlv4l2bufferpool", 0,
1966 "V4L2 Buffer Pool");
1967 GST_DEBUG_CATEGORY_GET(CAT_PERFORMANCE, "GST_PERFORMANCE");
1968}
1969
1970/**
1971 * gst_aml_v4l2_buffer_pool_new:
1972 * @obj: the v4l2 object owning the pool
1973 *
1974 * Construct a new buffer pool.
1975 *
1976 * Returns: the new pool, use gst_object_unref() to free resources
1977 */
1978GstBufferPool *
1979gst_aml_v4l2_buffer_pool_new(GstAmlV4l2Object *obj, GstCaps *caps)
1980{
1981 GstAmlV4l2BufferPool *pool;
1982 GstStructure *config;
1983 gchar *name, *parent_name;
1984 gint fd;
1985
1986 fd = obj->dup(obj->video_fd);
1987 if (fd < 0)
1988 goto dup_failed;
1989
1990 /* setting a significant unique name */
1991 parent_name = gst_object_get_name(GST_OBJECT(obj->element));
1992 name = g_strconcat(parent_name, ":", "pool:",
1993 V4L2_TYPE_IS_OUTPUT(obj->type) ? "sink" : "src", NULL);
1994 g_free(parent_name);
1995
1996 pool = (GstAmlV4l2BufferPool *)g_object_new(GST_TYPE_AML_V4L2_BUFFER_POOL,
1997 "name", name, NULL);
1998 g_object_ref_sink(pool);
1999 g_free(name);
2000
2001 gst_poll_fd_init(&pool->pollfd);
2002 pool->pollfd.fd = fd;
2003 gst_poll_add_fd(pool->poll, &pool->pollfd);
2004 if (V4L2_TYPE_IS_OUTPUT(obj->type))
sheng.liu8d18ed22022-05-26 17:28:15 +08002005 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002006 gst_poll_fd_ctl_write(pool->poll, &pool->pollfd, TRUE);
sheng.liu8d18ed22022-05-26 17:28:15 +08002007 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002008 else
sheng.liu8d18ed22022-05-26 17:28:15 +08002009 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002010 gst_poll_fd_ctl_read(pool->poll, &pool->pollfd, TRUE);
sheng.liu8d18ed22022-05-26 17:28:15 +08002011 gst_poll_fd_ctl_pri (pool->poll, &pool->pollfd, TRUE);
2012 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002013
2014 pool->video_fd = fd;
2015 pool->obj = obj;
2016 pool->can_poll_device = TRUE;
2017
2018 pool->vallocator = gst_aml_v4l2_allocator_new(GST_OBJECT(pool), obj);
2019 if (pool->vallocator == NULL)
2020 goto allocator_failed;
2021
2022 gst_object_ref(obj->element);
2023
2024 config = gst_buffer_pool_get_config(GST_BUFFER_POOL_CAST(pool));
2025 gst_buffer_pool_config_set_params(config, caps, obj->info.size, 0, 0);
2026 /* This will simply set a default config, but will not configure the pool
2027 * because min and max are not valid */
hanghang.luo3128f102022-08-18 10:36:19 +08002028 (void)gst_buffer_pool_set_config(GST_BUFFER_POOL_CAST(pool), config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002029
2030 return GST_BUFFER_POOL(pool);
2031
2032 /* ERRORS */
2033dup_failed:
2034{
2035 GST_ERROR("failed to dup fd %d (%s)", errno, g_strerror(errno));
2036 return NULL;
2037}
2038allocator_failed:
2039{
2040 GST_ERROR_OBJECT(pool, "Failed to create V4L2 allocator");
2041 gst_object_unref(pool);
2042 return NULL;
2043}
2044}
2045
2046static GstFlowReturn
2047gst_aml_v4l2_do_read(GstAmlV4l2BufferPool *pool, GstBuffer *buf)
2048{
2049 GstFlowReturn res;
2050 GstAmlV4l2Object *obj = pool->obj;
2051 gint amount;
2052 GstMapInfo map;
2053 gint toread;
2054
2055 toread = obj->info.size;
2056
2057 GST_LOG_OBJECT(pool, "reading %d bytes into buffer %p", toread, buf);
2058
2059 gst_buffer_map(buf, &map, GST_MAP_WRITE);
2060
2061 do
2062 {
2063 if ((res = gst_aml_v4l2_buffer_pool_poll(pool, TRUE)) != GST_FLOW_OK)
2064 goto poll_error;
2065
2066 amount = obj->read(obj->video_fd, map.data, toread);
2067
2068 if (amount == toread)
2069 {
2070 break;
2071 }
2072 else if (amount == -1)
2073 {
2074 if (errno == EAGAIN || errno == EINTR)
2075 {
2076 continue;
2077 }
2078 else
2079 goto read_error;
2080 }
2081 else
2082 {
2083 /* short reads can happen if a signal interrupts the read */
2084 continue;
2085 }
2086 } while (TRUE);
2087
2088 GST_LOG_OBJECT(pool, "read %d bytes", amount);
2089 gst_buffer_unmap(buf, &map);
2090 gst_buffer_resize(buf, 0, amount);
2091
2092 return GST_FLOW_OK;
2093
2094 /* ERRORS */
2095poll_error:
2096{
2097 GST_DEBUG("poll error %s", gst_flow_get_name(res));
2098 goto cleanup;
2099}
2100read_error:
2101{
2102 GST_ELEMENT_ERROR(obj->element, RESOURCE, READ,
2103 (_("Error reading %d bytes from device '%s'."),
2104 toread, obj->videodev),
2105 GST_ERROR_SYSTEM);
2106 res = GST_FLOW_ERROR;
2107 goto cleanup;
2108}
2109cleanup:
2110{
2111 gst_buffer_unmap(buf, &map);
2112 gst_buffer_resize(buf, 0, 0);
2113 return res;
2114}
2115}
2116
2117/**
2118 * gst_aml_v4l2_buffer_pool_process:
2119 * @bpool: a #GstBufferPool
2120 * @buf: a #GstBuffer, maybe be replaced
2121 *
2122 * Process @buf in @bpool. For capture devices, this functions fills @buf with
2123 * data from the device. For output devices, this functions send the contents of
2124 * @buf to the device for playback.
2125 *
2126 * Returns: %GST_FLOW_OK on success.
2127 */
2128GstFlowReturn
2129gst_aml_v4l2_buffer_pool_process(GstAmlV4l2BufferPool *pool, GstBuffer **buf)
2130{
2131 GstFlowReturn ret = GST_FLOW_OK;
2132 GstBufferPool *bpool = GST_BUFFER_POOL_CAST(pool);
2133 GstAmlV4l2Object *obj = pool->obj;
2134
2135 GST_DEBUG_OBJECT(pool, "process buffer %p, buf_pool:%p, v4l2 output pool:%p", buf, (*buf)->pool, bpool);
2136
2137 if (GST_BUFFER_POOL_IS_FLUSHING(pool))
2138 return GST_FLOW_FLUSHING;
2139
2140 switch (obj->type)
2141 {
2142 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2143 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
2144 /* capture */
2145 switch (obj->mode)
2146 {
2147 case GST_V4L2_IO_RW:
2148 /* capture into the buffer */
2149 ret = gst_aml_v4l2_do_read(pool, *buf);
2150 break;
2151
2152 case GST_V4L2_IO_MMAP:
2153 case GST_V4L2_IO_DMABUF:
2154 {
2155 GstBuffer *tmp;
2156
2157 if ((*buf)->pool == bpool)
2158 {
2159 guint num_queued;
2160 gsize size = gst_buffer_get_size(*buf);
2161
2162 /* Legacy M2M devices return empty buffer when drained */
2163 if (size == 0 && GST_AML_V4L2_IS_M2M(obj->device_caps))
2164 goto eos;
2165
2166 if (GST_VIDEO_INFO_FORMAT(&pool->caps_info) !=
2167 GST_VIDEO_FORMAT_ENCODED &&
2168 size < pool->size)
2169 goto buffer_truncated;
2170
2171 num_queued = g_atomic_int_get(&pool->num_queued);
2172 GST_TRACE_OBJECT(pool, "Only %i buffer left in the capture queue.",
2173 num_queued);
2174
2175 /* If we have no more buffer, and can allocate it time to do so */
2176 if (num_queued == 0)
2177 {
2178 if (GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP))
2179 {
2180 ret = gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
2181 if (ret == GST_FLOW_OK)
2182 goto done;
2183 }
2184 }
2185
2186 /* start copying buffers when we are running low on buffers */
2187 if (num_queued < pool->copy_threshold)
2188 {
2189 GstBuffer *copy;
2190
2191 if (GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP))
2192 {
2193 ret = gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
2194 if (ret == GST_FLOW_OK)
2195 goto done;
2196 }
2197
2198 /* copy the buffer */
2199 copy = gst_buffer_copy_region(*buf,
2200 GST_BUFFER_COPY_ALL | GST_BUFFER_COPY_DEEP, 0, -1);
2201 GST_LOG_OBJECT(pool, "copy buffer %p->%p", *buf, copy);
2202
2203 /* and requeue so that we can continue capturing */
2204 gst_buffer_unref(*buf);
2205 *buf = copy;
2206 }
2207
2208 ret = GST_FLOW_OK;
2209 /* nothing, data was inside the buffer when we did _acquire() */
2210 goto done;
2211 }
2212
2213 /* buffer not from our pool, grab a frame and copy it into the target */
2214 if ((ret = gst_aml_v4l2_buffer_pool_dequeue(pool, &tmp, TRUE)) != GST_FLOW_OK)
2215 goto done;
2216
2217 if (obj->dumpframefile)
2218 {
2219 FILE *pFile = fopen(obj->dumpframefile, "ab");
2220 if (pFile)
2221 {
2222 int n = gst_buffer_n_memory(tmp);
2223 int i;
2224 GstMapInfo map_info;
2225 GstMemory *mem;
2226
2227 for (i = 0; i < n; ++i)
2228 {
2229 mem = gst_buffer_peek_memory(tmp, i);
2230 if (gst_memory_map(mem, &map_info, GST_MAP_READ))
2231 {
2232 fwrite(map_info.data, map_info.size, 1, pFile);
2233 gst_memory_unmap(mem, &map_info);
2234 }
2235 }
2236 fclose(pFile);
2237 }
2238 }
2239 /* An empty buffer on capture indicates the end of stream */
2240 if (gst_buffer_get_size(tmp) == 0)
2241 {
2242 gst_aml_v4l2_buffer_pool_release_buffer(bpool, tmp);
2243
2244 /* Legacy M2M devices return empty buffer when drained */
2245 if (GST_AML_V4L2_IS_M2M(obj->device_caps))
2246 goto eos;
2247 }
2248
2249 ret = gst_aml_v4l2_buffer_pool_copy_buffer(pool, *buf, tmp);
2250
2251 /* an queue the buffer again after the copy */
2252 gst_aml_v4l2_buffer_pool_release_buffer(bpool, tmp);
2253
2254 if (ret != GST_FLOW_OK)
2255 goto copy_failed;
2256 break;
2257 }
2258
2259 case GST_V4L2_IO_USERPTR:
2260 {
2261 struct UserPtrData *data;
2262 GstBuffer *tmp;
2263
2264 /* Replace our buffer with downstream allocated buffer */
2265 data = gst_mini_object_steal_qdata(GST_MINI_OBJECT(*buf),
2266 GST_AML_V4L2_IMPORT_QUARK);
2267 tmp = gst_buffer_ref(data->buffer);
2268 _unmap_userptr_frame(data);
2269
2270 /* Now tmp is writable, copy the flags and timestamp */
2271 gst_buffer_copy_into(tmp, *buf,
2272 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2273
2274 gst_buffer_replace(buf, tmp);
2275 gst_buffer_unref(tmp);
2276 break;
2277 }
2278
2279 case GST_V4L2_IO_DMABUF_IMPORT:
2280 {
2281 GstBuffer *tmp;
2282
2283 /* Replace our buffer with downstream allocated buffer */
2284 // tmp = gst_mini_object_steal_qdata(GST_MINI_OBJECT(*buf),
2285 // GST_AML_V4L2_IMPORT_QUARK);
2286 tmp = gst_mini_object_get_qdata(GST_MINI_OBJECT(*buf), GST_AML_V4L2_IMPORT_QUARK);
2287 GST_DEBUG("got v4l2 capture buf:%p, with qdata drm buf:%p", *buf, tmp);
2288
2289 gst_buffer_copy_into(tmp, *buf,
2290 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2291
2292 gst_buffer_replace(buf, tmp);
2293 gst_buffer_unref(tmp);
2294 break;
2295 }
2296
2297 default:
2298 g_assert_not_reached();
2299 break;
2300 }
2301 break;
2302
2303 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
2304 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
2305 /* playback */
2306 switch (obj->mode)
2307 {
2308 case GST_V4L2_IO_RW:
2309 /* FIXME, do write() */
2310 GST_WARNING_OBJECT(pool, "implement write()");
2311 break;
2312
2313 case GST_V4L2_IO_USERPTR:
2314 case GST_V4L2_IO_DMABUF_IMPORT:
2315 case GST_V4L2_IO_DMABUF:
2316 case GST_V4L2_IO_MMAP:
2317 {
2318 GstBuffer *to_queue = NULL;
2319 GstBuffer *buffer;
2320 GstAmlV4l2MemoryGroup *group;
2321 gint index;
2322
2323 if ((*buf)->pool != bpool)
2324 goto copying;
2325
2326 if (!gst_aml_v4l2_is_buffer_valid(*buf, &group))
2327 goto copying;
2328
2329 index = group->buffer.index;
2330
2331 GST_LOG_OBJECT(pool, "processing buffer %i from our pool", index);
2332
2333 if (pool->buffers[index] != NULL)
2334 {
2335 GST_LOG_OBJECT(pool, "buffer %i already queued, copying", index);
2336 goto copying;
2337 }
2338
2339 /* we can queue directly */
2340 to_queue = gst_buffer_ref(*buf);
2341
2342 copying:
2343 if (to_queue == NULL)
2344 {
2345 GstBufferPoolAcquireParams params = {0};
2346
2347 GST_LOG_OBJECT(pool, "alloc buffer from our pool");
2348
2349 /* this can return EOS if all buffers are outstanding which would
2350 * be strange because we would expect the upstream element to have
2351 * allocated them and returned to us.. */
2352 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
2353 ret = gst_buffer_pool_acquire_buffer(bpool, &to_queue, &params);
2354 if (ret != GST_FLOW_OK)
2355 goto acquire_failed;
2356
2357 ret = gst_aml_v4l2_buffer_pool_prepare_buffer(pool, to_queue, *buf);
2358 if (ret != GST_FLOW_OK)
2359 {
2360 gst_buffer_unref(to_queue);
2361 goto prepare_failed;
2362 }
2363
2364 /* retreive the group */
2365 gst_aml_v4l2_is_buffer_valid(to_queue, &group);
2366 }
2367
2368 if ((ret = gst_aml_v4l2_buffer_pool_qbuf(pool, to_queue, group)) != GST_FLOW_OK)
2369 goto queue_failed;
2370
2371 /* if we are not streaming yet (this is the first buffer, start
2372 * streaming now */
2373 if (!gst_aml_v4l2_buffer_pool_streamon(pool))
2374 {
2375 /* don't check return value because qbuf would have failed */
2376 gst_aml_v4l2_is_buffer_valid(to_queue, &group);
2377
2378 /* qbuf has stored to_queue buffer but we are not in
2379 * streaming state, so the flush logic won't be performed.
2380 * To avoid leaks, flush the allocator and restore the queued
2381 * buffer as non-queued */
2382 gst_aml_v4l2_allocator_flush(pool->vallocator);
2383
2384 pool->buffers[group->buffer.index] = NULL;
2385
2386 gst_mini_object_set_qdata(GST_MINI_OBJECT(to_queue),
2387 GST_AML_V4L2_IMPORT_QUARK, NULL, NULL);
2388 gst_buffer_unref(to_queue);
2389 g_atomic_int_add(&pool->num_queued, -1);
2390 goto start_failed;
2391 }
2392
2393 /* Remove our ref, we will still hold this buffer in acquire as needed,
2394 * otherwise the pool will think it is outstanding and will refuse to stop. */
2395 gst_buffer_unref(to_queue);
2396
2397 /* release as many buffer as possible */
2398 while (gst_aml_v4l2_buffer_pool_dequeue(pool, &buffer, FALSE) ==
2399 GST_FLOW_OK)
2400 {
2401 if (buffer->pool == NULL)
2402 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
2403 }
2404
2405 if (g_atomic_int_get(&pool->num_queued) >= pool->min_latency)
2406 {
2407 /* all buffers are queued, try to dequeue one and release it back
2408 * into the pool so that _acquire can get to it again. */
2409 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, &buffer, TRUE);
2410 if (ret == GST_FLOW_OK && buffer->pool == NULL)
2411 /* release the rendered buffer back into the pool. This wakes up any
2412 * thread waiting for a buffer in _acquire(). */
2413 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
2414 }
2415 break;
2416 }
2417 default:
2418 g_assert_not_reached();
2419 break;
2420 }
2421 break;
2422 default:
2423 g_assert_not_reached();
2424 break;
2425 }
2426done:
2427 return ret;
2428
2429 /* ERRORS */
2430copy_failed:
2431{
2432 GST_ERROR_OBJECT(pool, "failed to copy buffer");
2433 return ret;
2434}
2435buffer_truncated:
2436{
2437 GST_WARNING_OBJECT(pool,
2438 "Dropping truncated buffer, this is likely a driver bug.");
2439 gst_buffer_unref(*buf);
2440 *buf = NULL;
2441 return GST_AML_V4L2_FLOW_CORRUPTED_BUFFER;
2442}
2443eos:
2444{
2445 GST_DEBUG_OBJECT(pool, "end of stream reached");
2446 gst_buffer_unref(*buf);
2447 *buf = NULL;
2448 return GST_AML_V4L2_FLOW_LAST_BUFFER;
2449}
2450acquire_failed:
2451{
2452 if (ret == GST_FLOW_FLUSHING)
2453 GST_DEBUG_OBJECT(pool, "flushing");
2454 else
2455 GST_WARNING_OBJECT(pool, "failed to acquire a buffer: %s",
2456 gst_flow_get_name(ret));
2457 return ret;
2458}
2459prepare_failed:
2460{
2461 GST_ERROR_OBJECT(pool, "failed to prepare data");
2462 return ret;
2463}
2464queue_failed:
2465{
2466 GST_ERROR_OBJECT(pool, "failed to queue buffer");
2467 return ret;
2468}
2469start_failed:
2470{
2471 GST_ERROR_OBJECT(pool, "failed to start streaming");
2472 return GST_FLOW_ERROR;
2473}
2474}
2475
2476void gst_aml_v4l2_buffer_pool_set_other_pool(GstAmlV4l2BufferPool *pool,
2477 GstBufferPool *other_pool)
2478{
2479 g_return_if_fail(!gst_buffer_pool_is_active(GST_BUFFER_POOL(pool)));
2480
2481 if (pool->other_pool)
2482 gst_object_unref(pool->other_pool);
2483 pool->other_pool = gst_object_ref(other_pool);
2484}
2485
2486void gst_aml_v4l2_buffer_pool_copy_at_threshold(GstAmlV4l2BufferPool *pool, gboolean copy)
2487{
2488 GST_OBJECT_LOCK(pool);
2489 pool->enable_copy_threshold = copy;
2490 GST_OBJECT_UNLOCK(pool);
2491}
2492
2493gboolean
2494gst_aml_v4l2_buffer_pool_flush(GstBufferPool *bpool)
2495{
2496 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
2497 gboolean ret = TRUE;
2498
2499 gst_aml_v4l2_buffer_pool_streamoff(pool);
2500
2501 if (!V4L2_TYPE_IS_OUTPUT(pool->obj->type))
2502 ret = gst_aml_v4l2_buffer_pool_streamon(pool);
2503
2504 return ret;
2505}
2506
2507void gst_aml_v4l2_buffer_pool_dump_stat(GstAmlV4l2BufferPool *pool, const gchar *file_name, gint try_num)
2508{
2509 const gchar *dump_dir = NULL;
2510 gchar *full_file_name = NULL;
2511 FILE *out = NULL;
2512
2513 dump_dir = g_getenv("GST_DEBUG_DUMP_AMLV4L2DEC_STAT_DIR");
2514 if (G_LIKELY(dump_dir == NULL))
2515 return;
2516
2517 if (!file_name)
2518 {
2519 file_name = "unnamed";
2520 }
2521
2522 full_file_name = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s.stat", dump_dir, file_name);
2523
2524 if ((out = fopen(full_file_name, "w")))
2525 {
2526 GstStructure *config = NULL;
2527 config = gst_buffer_pool_get_config((GstBufferPool *)pool);
2528 if (config)
2529 {
2530 GstCaps *caps;
2531 guint size, min_buffers, max_buffers;
2532 if (gst_buffer_pool_config_get_params(config, &caps, &size, &min_buffers, &max_buffers))
2533 {
2534 gchar *stat_info;
2535
2536 /* set local pool info*/
2537 gint already_queued = 0;
2538 gint ready_to_queue_num = 0;
2539 for (gint i = 0; i < VIDEO_MAX_FRAME; i++)
2540 {
2541 if (pool->buffers[i])
2542 {
2543 already_queued++;
2544 }
2545 if (pool->read_to_free_bufs[i])
2546 {
2547 ready_to_queue_num++;
2548 }
2549 }
2550
2551 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",
2552 size, min_buffers, max_buffers,
2553 pool->num_queued, pool->num_allocated,
2554 already_queued, ready_to_queue_num, try_num);
2555 fputs(stat_info, out);
2556 g_free(stat_info);
2557
2558 /* set other pool info*/
2559 if (pool->other_pool)
2560 {
2561 GstStructure *other_config = NULL;
2562 other_config = gst_buffer_pool_get_config((GstBufferPool *)pool);
2563 if (other_config)
2564 {
2565 GstCaps *other_caps;
2566 guint other_size, other_min_buffers, other_max_buffers;
2567 if (gst_buffer_pool_config_get_params(config, &other_caps, &other_size, &other_min_buffers, &other_max_buffers))
2568 {
2569 stat_info = g_strdup_printf("other pool | size:%d, min_bufs:%d, max_bufs:%d\n",
2570 other_size, other_min_buffers, other_max_buffers);
2571
2572 // TODO:GstBufferPool中没有获取outstanding的接口,所以这里没有统计otherpool中在用buffer的状态,后续需要修改gstreamer-1.0中code新增接口
2573 fputs(stat_info, out);
2574 g_free(stat_info);
2575 }
2576 }
2577 }
2578 GST_INFO("wrote amlv4l2 bufferpool stat to : '%s' succ", full_file_name);
2579 }
2580 }
2581 else
2582 {
2583 GST_WARNING("Failed to get config for pool:%p", pool);
2584 }
2585 fclose(out);
2586 }
2587 else
2588 {
2589 GST_WARNING("Failed to open file '%s' for writing: %s", full_file_name, g_strerror(errno));
2590 }
2591 g_free(full_file_name);
2592}