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