blob: dcd6c7d46bab3697cbc6ae9c4258a20bff6ac830 [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
xuesong.jiangc5dac0f2023-02-01 14:42:24 +0800146 GST_DEBUG_OBJECT(pool, "copy raw bytes size:%d", gst_buffer_get_size(src));
xuesong.jiangae1548e2022-05-06 16:38:46 +0800147
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)
xuesong.jiangc5dac0f2023-02-01 14:42:24 +0800980 {
981 if (obj->old_other_pool || obj->old_old_other_pool)
982 GST_DEBUG_OBJECT(pool, "resolution switching flow, need to wait other pool recycle");
983 else
984 goto queue_failed;
985 }
xuesong.jiangae1548e2022-05-06 16:38:46 +0800986
987 pool->group_released_handler =
988 g_signal_connect_swapped(pool->vallocator, "group-released",
989 G_CALLBACK(gst_aml_v4l2_buffer_pool_resurrect_buffer), pool);
990 ret = gst_aml_v4l2_buffer_pool_streamon(pool);
991 }
992
993 return ret;
994
995 /* ERRORS */
996wrong_config:
997{
998 GST_ERROR_OBJECT(pool, "invalid config %" GST_PTR_FORMAT, config);
999 gst_structure_free(config);
1000 return FALSE;
1001}
1002no_buffers:
1003{
1004 GST_ERROR_OBJECT(pool,
1005 "we received %d buffer from device '%s', we want at least %d",
1006 min_buffers, obj->videodev, GST_AML_V4L2_MIN_BUFFERS);
1007 gst_structure_free(config);
1008 return FALSE;
1009}
1010start_failed:
1011{
1012 GST_ERROR_OBJECT(pool, "allocate failed");
1013 return FALSE;
1014}
1015other_pool_failed:
1016{
1017 GST_ERROR_OBJECT(pool, "failed to activate the other pool %" GST_PTR_FORMAT, pool->other_pool);
1018 return FALSE;
1019}
1020queue_failed:
1021{
1022 GST_ERROR_OBJECT(pool, "failed to queue buffers into the capture queue");
1023 return FALSE;
1024}
1025cannot_import:
1026{
1027 GST_ERROR_OBJECT(pool, "cannot import buffers from downstream pool");
1028 return FALSE;
1029}
1030}
1031
1032static gboolean
1033gst_aml_v4l2_buffer_pool_vallocator_stop(GstAmlV4l2BufferPool *pool)
1034{
1035 GstAmlV4l2Return vret;
1036
1037 if (!pool->vallocator)
1038 return TRUE;
1039
1040 vret = gst_aml_v4l2_allocator_stop(pool->vallocator);
1041
1042 if (vret == GST_V4L2_BUSY)
1043 GST_WARNING_OBJECT(pool, "some buffers are still outstanding");
1044
1045 return (vret == GST_V4L2_OK);
1046}
1047
1048static gboolean
1049gst_aml_v4l2_buffer_pool_stop(GstBufferPool *bpool)
1050{
1051 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1052 gboolean ret;
1053
1054 if (pool->orphaned)
1055 return gst_aml_v4l2_buffer_pool_vallocator_stop(pool);
1056
1057 GST_DEBUG_OBJECT(pool, "stopping pool");
1058
1059 if (pool->group_released_handler > 0)
1060 {
1061 g_signal_handler_disconnect(pool->vallocator,
1062 pool->group_released_handler);
1063 pool->group_released_handler = 0;
1064 }
1065
1066 gst_aml_v4l2_buffer_pool_streamoff(pool);
1067
1068 ret = GST_BUFFER_POOL_CLASS(parent_class)->stop(bpool);
1069
1070 if (ret)
1071 ret = gst_aml_v4l2_buffer_pool_vallocator_stop(pool);
1072
1073 GST_DEBUG_OBJECT(pool, "stopping other_pool");
1074 if (pool->other_pool)
1075 {
1076 gst_buffer_pool_set_active(pool->other_pool, FALSE);
1077 gst_object_unref(pool->other_pool);
1078 pool->other_pool = NULL;
1079 }
1080
1081 return ret;
1082}
1083
1084gboolean
1085gst_aml_v4l2_buffer_pool_orphan(GstBufferPool **bpool)
1086{
1087 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(*bpool);
1088 gboolean ret;
1089
1090 if (!GST_AML_V4L2_ALLOCATOR_CAN_ORPHAN_BUFS(pool->vallocator))
1091 return FALSE;
1092
1093 if (g_getenv("GST_V4L2_FORCE_DRAIN"))
1094 return FALSE;
1095
1096 GST_DEBUG_OBJECT(pool, "orphaning pool");
1097
1098 gst_buffer_pool_set_active(*bpool, FALSE);
1099 /*
1100 * If the buffer pool has outstanding buffers, it will not be stopped
1101 * by the base class when set inactive. Stop it manually and mark it
1102 * as orphaned
1103 */
1104 ret = gst_aml_v4l2_buffer_pool_stop(*bpool);
1105 if (!ret)
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001106 {
1107 GST_DEBUG_OBJECT(pool, "stop poll fail, try to orphaning allocator");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001108 ret = gst_aml_v4l2_allocator_orphan(pool->vallocator);
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001109 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001110
1111 if (!ret)
1112 goto orphan_failed;
1113
1114 pool->orphaned = TRUE;
1115 gst_object_unref(*bpool);
1116 *bpool = NULL;
1117
1118orphan_failed:
1119 return ret;
1120}
1121
1122static void
1123gst_aml_v4l2_buffer_pool_flush_start(GstBufferPool *bpool)
1124{
1125 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1126
1127 GST_DEBUG_OBJECT(pool, "start flushing");
1128
1129 gst_poll_set_flushing(pool->poll, TRUE);
1130
1131 GST_OBJECT_LOCK(pool);
1132 pool->empty = FALSE;
1133 g_cond_broadcast(&pool->empty_cond);
1134 GST_OBJECT_UNLOCK(pool);
1135
1136 if (pool->other_pool)
1137 gst_buffer_pool_set_flushing(pool->other_pool, TRUE);
1138}
1139
1140static void
1141gst_aml_v4l2_buffer_pool_flush_stop(GstBufferPool *bpool)
1142{
1143 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1144
1145 GST_DEBUG_OBJECT(pool, "stop flushing");
1146
1147 if (pool->other_pool)
1148 gst_buffer_pool_set_flushing(pool->other_pool, FALSE);
1149
1150 gst_poll_set_flushing(pool->poll, FALSE);
1151}
1152
1153static GstFlowReturn
1154gst_aml_v4l2_buffer_pool_poll(GstAmlV4l2BufferPool *pool, gboolean wait)
1155{
1156 gint ret;
1157 GstClockTime timeout;
1158 gint try_num = 0;
1159
1160 if (wait)
1161 timeout = GST_CLOCK_TIME_NONE;
1162 else
1163 timeout = 0;
1164
1165 /* In RW mode there is no queue, hence no need to wait while the queue is
1166 * empty */
xuesong.jiang93f2dcb2022-07-15 14:24:55 +08001167
1168 if ((pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
1169 pool->obj->mode == GST_V4L2_IO_DMABUF_IMPORT)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001170 {
fei.denge9458472023-04-18 02:05:48 +00001171 GST_TRACE_OBJECT(pool, "CAPTURE DMA don't quit when empty buf");
xuesong.jiang93f2dcb2022-07-15 14:24:55 +08001172 }
1173 else
1174 {
1175 if (pool->obj->mode != GST_V4L2_IO_RW)
xuesong.jiangae1548e2022-05-06 16:38:46 +08001176 {
xuesong.jiang93f2dcb2022-07-15 14:24:55 +08001177 GST_OBJECT_LOCK(pool);
1178
1179 if (!wait && pool->empty)
1180 {
1181 GST_OBJECT_UNLOCK(pool);
1182 goto no_buffers;
1183 }
1184
1185 while (pool->empty)
1186 g_cond_wait(&pool->empty_cond, GST_OBJECT_GET_LOCK(pool));
1187
xuesong.jiangae1548e2022-05-06 16:38:46 +08001188 GST_OBJECT_UNLOCK(pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001189 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001190 }
1191
1192 if (!pool->can_poll_device)
1193 {
1194 if (wait)
1195 goto done;
1196 else
1197 goto no_buffers;
1198 }
1199
fei.denge9458472023-04-18 02:05:48 +00001200 GST_TRACE_OBJECT(pool, "polling device");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001201
1202again:
1203 ret = gst_poll_wait(pool->poll, timeout);
1204#ifdef GST_AML_SPEC_FLOW_FOR_VBP
fei.denge9458472023-04-18 02:05:48 +00001205 GST_TRACE_OBJECT(pool, "amlmodbuf poll timeout:%lld, ret:%d, errno:%d", timeout, ret, errno);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001206#endif
1207 if (G_UNLIKELY(ret < 0))
1208 {
1209 switch (errno)
1210 {
1211 case EBUSY:
1212 goto stopped;
1213 case EAGAIN:
1214 case EINTR:
1215 goto again;
1216 case ENXIO:
1217 GST_WARNING_OBJECT(pool,
1218 "v4l2 device doesn't support polling. Disabling"
1219 " using libv4l2 in this case may cause deadlocks");
1220 pool->can_poll_device = FALSE;
1221 goto done;
1222 default:
1223 goto select_error;
1224 }
1225 }
1226
1227 if (gst_poll_fd_has_error(pool->poll, &pool->pollfd))
1228 goto select_error;
1229
1230 if (ret == 0)
1231 {
1232#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1233 if ((pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
1234 pool->obj->mode == GST_V4L2_IO_DMABUF_IMPORT)
1235 {
fei.denge9458472023-04-18 02:05:48 +00001236 GST_TRACE_OBJECT(pool, "amlmodbuf can't get buffer in capture obj dmaimport mode, try release buf from other pool");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001237 gst_aml_v4l2_buffer_pool_dump_stat(pool, GST_DUMP_CAPTURE_BP_STAT_FILENAME, try_num++);
1238 gst_aml_v4l2_buffer_pool_release_buffer_aml_patch((GstBufferPool *)pool);
fei.denge9458472023-04-18 02:05:48 +00001239 g_usleep(1000);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001240 goto again;
1241 }
1242 else
1243#endif
1244 goto no_buffers;
1245 }
1246
1247done:
1248 return GST_FLOW_OK;
1249
1250 /* ERRORS */
1251stopped:
1252{
1253 GST_DEBUG_OBJECT(pool, "stop called");
1254 return GST_FLOW_FLUSHING;
1255}
1256select_error:
1257{
1258 GST_ELEMENT_ERROR(pool->obj->element, RESOURCE, READ, (NULL),
1259 ("poll error %d: %s (%d)", ret, g_strerror(errno), errno));
1260 return GST_FLOW_ERROR;
1261}
1262no_buffers:
1263 return GST_FLOW_CUSTOM_SUCCESS;
1264}
1265
1266static GstFlowReturn
1267gst_aml_v4l2_buffer_pool_qbuf(GstAmlV4l2BufferPool *pool, GstBuffer *buf,
1268 GstAmlV4l2MemoryGroup *group)
1269{
1270 const GstAmlV4l2Object *obj = pool->obj;
1271 GstClockTime timestamp;
1272 gint index;
1273
1274 index = group->buffer.index;
1275
1276 if (pool->buffers[index] != NULL)
1277 goto already_queued;
1278
1279 GST_LOG_OBJECT(pool, "queuing buffer %i", index);
1280
1281 if (V4L2_TYPE_IS_OUTPUT(obj->type))
1282 {
1283 enum v4l2_field field;
1284
1285 /* Except when field is set to alternate, buffer field is the same as
1286 * the one defined in format */
1287 if (V4L2_TYPE_IS_MULTIPLANAR(obj->type))
1288 field = obj->format.fmt.pix_mp.field;
1289 else
1290 field = obj->format.fmt.pix.field;
1291
1292 /* NB: At this moment, we can't have alternate mode because it not handled
1293 * yet */
1294 if (field == V4L2_FIELD_ALTERNATE)
1295 {
1296 if (GST_BUFFER_FLAG_IS_SET(buf, GST_VIDEO_FRAME_FLAG_TFF))
1297 field = V4L2_FIELD_TOP;
1298 else
1299 field = V4L2_FIELD_BOTTOM;
1300 }
1301
1302 group->buffer.field = field;
1303 }
1304
1305 if (GST_BUFFER_TIMESTAMP_IS_VALID(buf))
1306 {
1307 timestamp = GST_BUFFER_TIMESTAMP(buf);
1308 GST_TIME_TO_TIMEVAL(timestamp, group->buffer.timestamp);
1309 }
zengliang.li32cb11e2022-11-24 12:10:26 +08001310 else
1311 {
1312 group->buffer.timestamp.tv_sec= -1;
1313 group->buffer.timestamp.tv_usec= 0;
1314 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001315
1316 GST_OBJECT_LOCK(pool);
1317 g_atomic_int_inc(&pool->num_queued);
1318 pool->buffers[index] = buf;
1319
1320 if (!gst_aml_v4l2_allocator_qbuf(pool->vallocator, group))
1321 goto queue_failed;
1322
1323 if (!V4L2_TYPE_IS_OUTPUT(obj->type))
1324 {
1325 gst_aml_v4l2_buffer_pool_dump_stat(pool, GST_DUMP_CAPTURE_BP_STAT_FILENAME, 0);
1326 }
1327
1328 pool->empty = FALSE;
1329 g_cond_signal(&pool->empty_cond);
1330 GST_OBJECT_UNLOCK(pool);
1331
1332 return GST_FLOW_OK;
1333
1334already_queued:
1335{
1336 GST_ERROR_OBJECT(pool, "the buffer %i was already queued", index);
1337 return GST_FLOW_ERROR;
1338}
1339queue_failed:
1340{
1341 GST_ERROR_OBJECT(pool, "could not queue a buffer %i", index);
1342 /* Mark broken buffer to the allocator */
1343 GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_TAG_MEMORY);
1344 g_atomic_int_add(&pool->num_queued, -1);
1345 pool->buffers[index] = NULL;
1346 GST_OBJECT_UNLOCK(pool);
1347 return GST_FLOW_ERROR;
1348}
1349}
1350
1351static GstFlowReturn
1352gst_aml_v4l2_buffer_pool_dqevent(GstAmlV4l2BufferPool *pool)
1353{
1354 GstAmlV4l2Object *v4l2object = pool->obj;
1355 struct v4l2_event evt;
1356
1357 memset(&evt, 0x00, sizeof(struct v4l2_event));
1358 if (v4l2object->ioctl(pool->video_fd, VIDIOC_DQEVENT, &evt) < 0)
1359 goto dqevent_failed;
1360
1361 switch (evt.type)
1362 {
1363 case V4L2_EVENT_SOURCE_CHANGE:
sheng.liu8d18ed22022-05-26 17:28:15 +08001364
1365 if (evt.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION)
1366 return GST_AML_V4L2_FLOW_SOURCE_CHANGE;
1367 GST_WARNING_OBJECT (pool, "Unknown source change 0x%x - skipped", evt.u.src_change.changes);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001368 break;
1369 case V4L2_EVENT_EOS:
1370 return GST_AML_V4L2_FLOW_LAST_BUFFER;
1371 break;
1372 default:
1373 break;
1374 }
1375
1376 return GST_FLOW_OK;
1377
1378 /* ERRORS */
1379dqevent_failed:
1380{
1381 return GST_FLOW_ERROR;
1382}
1383}
1384
1385static GstFlowReturn
1386gst_aml_v4l2_buffer_pool_dqbuf(GstAmlV4l2BufferPool *pool, GstBuffer **buffer,
1387 gboolean wait)
1388{
1389 GstFlowReturn res;
1390 GstBuffer *outbuf = NULL;
1391 GstAmlV4l2Object *obj = pool->obj;
1392 GstClockTime timestamp;
1393 GstAmlV4l2MemoryGroup *group;
1394 GstVideoMeta *vmeta;
1395 gsize size;
1396 gint i;
1397
1398 res = gst_aml_v4l2_allocator_dqbuf(pool->vallocator, &group);
1399 if (res == GST_FLOW_EOS)
1400 goto eos;
1401 if (res != GST_FLOW_OK)
1402 goto dqbuf_failed;
hanghang.luob216ac42023-05-12 02:56:54 +00001403 if ( (group->buffer.flags & V4L2_BUF_FLAG_LAST) &&(group->buffer.bytesused == 0) )
1404 {
1405 GST_LOG_OBJECT (pool,"dequeued empty buffer");
1406 return GST_AML_V4L2_FLOW_LAST_BUFFER;
1407 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001408
1409 /* get our GstBuffer with that index from the pool, if the buffer was
1410 * outstanding we have a serious problem.
1411 */
1412 outbuf = pool->buffers[group->buffer.index];
1413 if (outbuf == NULL)
1414 goto no_buffer;
1415
1416 /* mark the buffer outstanding */
1417 pool->buffers[group->buffer.index] = NULL;
1418 if (g_atomic_int_dec_and_test(&pool->num_queued))
1419 {
1420 GST_OBJECT_LOCK(pool);
1421 pool->empty = TRUE;
1422 GST_OBJECT_UNLOCK(pool);
1423 }
1424
1425 timestamp = GST_TIMEVAL_TO_TIME(group->buffer.timestamp);
1426
1427 size = 0;
1428 vmeta = gst_buffer_get_video_meta(outbuf);
1429 for (i = 0; i < group->n_mem; i++)
1430 {
1431 GST_LOG_OBJECT(pool,
1432 "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,
1433 group->buffer.sequence, group->buffer.index, group->mem[i],
1434 group->planes[i].bytesused, i, group->buffer.flags,
1435 GST_TIME_ARGS(timestamp), pool->num_queued, outbuf);
1436
1437 if (vmeta)
1438 {
1439 vmeta->offset[i] = size;
1440 size += gst_memory_get_sizes(group->mem[i], NULL, NULL);
1441 }
1442 }
1443
1444 /* Ignore timestamp and field for OUTPUT device */
1445 if (V4L2_TYPE_IS_OUTPUT(obj->type))
1446 goto done;
1447
1448 /* Check for driver bug in reporting feild */
1449 if (group->buffer.field == V4L2_FIELD_ANY)
1450 {
1451 /* Only warn once to avoid the spamming */
1452#ifndef GST_DISABLE_GST_DEBUG
1453 if (!pool->has_warned_on_buggy_field)
1454 {
1455 pool->has_warned_on_buggy_field = TRUE;
1456 GST_WARNING_OBJECT(pool,
1457 "Driver should never set v4l2_buffer.field to ANY");
1458 }
1459#endif
1460
1461 /* Use the value from the format (works for UVC bug) */
1462 group->buffer.field = obj->format.fmt.pix.field;
1463
1464 /* If driver also has buggy S_FMT, assume progressive */
1465 if (group->buffer.field == V4L2_FIELD_ANY)
1466 {
1467#ifndef GST_DISABLE_GST_DEBUG
1468 if (!pool->has_warned_on_buggy_field)
1469 {
1470 pool->has_warned_on_buggy_field = TRUE;
1471 GST_WARNING_OBJECT(pool,
1472 "Driver should never set v4l2_format.pix.field to ANY");
1473 }
1474#endif
1475
1476 group->buffer.field = V4L2_FIELD_NONE;
1477 }
1478 }
1479
1480 /* set top/bottom field first if v4l2_buffer has the information */
1481 switch (group->buffer.field)
1482 {
1483 case V4L2_FIELD_NONE:
1484 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1485 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1486 break;
1487 case V4L2_FIELD_INTERLACED_TB:
1488 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1489 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1490 break;
1491 case V4L2_FIELD_INTERLACED_BT:
1492 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1493 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1494 break;
1495 case V4L2_FIELD_INTERLACED:
1496 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1497 if (obj->tv_norm == V4L2_STD_NTSC_M ||
1498 obj->tv_norm == V4L2_STD_NTSC_M_JP ||
1499 obj->tv_norm == V4L2_STD_NTSC_M_KR)
1500 {
1501 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1502 }
1503 else
1504 {
1505 GST_BUFFER_FLAG_SET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1506 }
1507 break;
1508 default:
1509 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1510 GST_BUFFER_FLAG_UNSET(outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
1511 GST_FIXME_OBJECT(pool,
1512 "Unhandled enum v4l2_field %d - treating as progressive",
1513 group->buffer.field);
1514 break;
1515 }
1516
1517 if (GST_VIDEO_INFO_FORMAT(&obj->info) == GST_VIDEO_FORMAT_ENCODED)
1518 {
1519 if ((group->buffer.flags & V4L2_BUF_FLAG_KEYFRAME) ||
1520 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_MJPEG ||
1521 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_JPEG ||
1522 GST_AML_V4L2_PIXELFORMAT(obj) == V4L2_PIX_FMT_PJPG)
1523 GST_BUFFER_FLAG_UNSET(outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1524 else
1525 GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1526 }
1527
1528 if (group->buffer.flags & V4L2_BUF_FLAG_ERROR)
1529 GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_FLAG_CORRUPTED);
1530
1531 GST_BUFFER_TIMESTAMP(outbuf) = timestamp;
1532 GST_BUFFER_OFFSET(outbuf) = group->buffer.sequence;
1533 GST_BUFFER_OFFSET_END(outbuf) = group->buffer.sequence + 1;
1534
1535done:
1536 *buffer = outbuf;
1537
1538 if (!V4L2_TYPE_IS_OUTPUT(obj->type))
1539 {
1540 gst_aml_v4l2_buffer_pool_dump_stat(pool, GST_DUMP_CAPTURE_BP_STAT_FILENAME, 0);
1541 }
1542
1543 return res;
1544
1545 /* ERRORS */
1546eos:
1547{
1548 return GST_FLOW_EOS;
1549}
1550dqbuf_failed:
1551{
1552 return GST_FLOW_ERROR;
1553}
1554no_buffer:
1555{
1556 GST_ERROR_OBJECT(pool, "No free buffer found in the pool at index %d.",
1557 group->buffer.index);
1558 return GST_FLOW_ERROR;
1559}
1560}
1561
1562static GstFlowReturn
1563gst_aml_v4l2_buffer_pool_dequeue(GstAmlV4l2BufferPool *pool, GstBuffer **buffer,
1564 gboolean wait)
1565{
1566 GstFlowReturn res;
1567 GstAmlV4l2Object *obj = pool->obj;
1568
1569 if ((res = gst_aml_v4l2_buffer_pool_poll(pool, wait)) != GST_FLOW_OK)
1570 goto poll_failed;
1571
1572 if (obj->can_wait_event && gst_poll_fd_can_read_pri(pool->poll, &pool->pollfd))
1573 {
sheng.liu8d18ed22022-05-26 17:28:15 +08001574 GstFlowReturn res_event = gst_aml_v4l2_buffer_pool_dqevent(pool);
1575 if (res_event != GST_FLOW_OK)
hanghang.luob216ac42023-05-12 02:56:54 +00001576 {
1577 /* when drive V4l2 receive cmd_stop, it will finish current decoding frame, then creat
1578 * a EOS event and a empty buff. if gstreamer dq EOS event first ,the last frame will be drop,
1579 * this a question
1580 */
1581 if (res_event == GST_AML_V4L2_FLOW_LAST_BUFFER)
1582 {
1583 GST_DEBUG_OBJECT(pool," reiceive EOS event, drop it");
1584 }
1585 else
1586 return res_event;
1587 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001588 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001589 if (res == GST_FLOW_CUSTOM_SUCCESS)
1590 {
1591 GST_LOG_OBJECT(pool, "nothing to dequeue");
1592 *buffer = NULL;
1593 return res;
1594 }
1595
1596 GST_LOG_OBJECT(pool, "dequeueing a buffer");
1597 return gst_aml_v4l2_buffer_pool_dqbuf(pool, buffer, wait);
1598
1599 /* ERRORS */
1600poll_failed:
1601{
1602 GST_DEBUG_OBJECT(pool, "poll error %s", gst_flow_get_name(res));
1603 return res;
1604}
1605}
1606
1607static GstFlowReturn
1608gst_aml_v4l2_buffer_pool_acquire_buffer(GstBufferPool *bpool, GstBuffer **buffer,
1609 GstBufferPoolAcquireParams *params)
1610{
1611 GstFlowReturn ret;
1612 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1613 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
1614 GstAmlV4l2Object *obj = pool->obj;
1615
1616 GST_DEBUG_OBJECT(pool, "acquire");
1617
1618 /* If this is being called to resurrect a lost buffer */
1619 if (params && params->flags & GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT)
1620 {
1621 ret = pclass->acquire_buffer(bpool, buffer, params);
1622 goto done;
1623 }
1624
1625 switch (obj->type)
1626 {
1627 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1628 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1629 /* capture, This function should return a buffer with new captured data */
1630 switch (obj->mode)
1631 {
1632 case GST_V4L2_IO_RW:
1633 {
1634 /* take empty buffer from the pool */
1635 ret = pclass->acquire_buffer(bpool, buffer, params);
1636 break;
1637 }
1638 case GST_V4L2_IO_DMABUF:
1639 case GST_V4L2_IO_MMAP:
1640 case GST_V4L2_IO_USERPTR:
xuesong.jiang3df0f7b2022-11-29 14:52:45 +08001641 {
1642 /* just dequeue a buffer, we basically use the queue of v4l2 as the
1643 * storage for our buffers. This function does poll first so we can
1644 * interrupt it fine. */
1645 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, TRUE);
1646
1647 break;
1648 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08001649 case GST_V4L2_IO_DMABUF_IMPORT:
1650 {
1651#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1652 GST_DEBUG_OBJECT(pool, "amlmodbuf return free buf before acquire buf");
1653 gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(bpool);
1654 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, FALSE);
1655#else
1656 /* just dequeue a buffer, we basically use the queue of v4l2 as the
1657 * storage for our buffers. This function does poll first so we can
1658 * interrupt it fine. */
1659 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, buffer, TRUE);
1660#endif
1661 break;
1662 }
1663 default:
1664 ret = GST_FLOW_ERROR;
1665 g_assert_not_reached();
1666 break;
1667 }
1668 break;
1669
1670 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1671 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1672 /* playback, This function should return an empty buffer */
1673 switch (obj->mode)
1674 {
1675 case GST_V4L2_IO_RW:
1676 /* get an empty buffer */
1677 ret = pclass->acquire_buffer(bpool, buffer, params);
1678 break;
1679
1680 case GST_V4L2_IO_MMAP:
1681 case GST_V4L2_IO_DMABUF:
1682 case GST_V4L2_IO_USERPTR:
1683 case GST_V4L2_IO_DMABUF_IMPORT:
1684 /* get a free unqueued buffer */
1685 ret = pclass->acquire_buffer(bpool, buffer, params);
1686 break;
1687
1688 default:
1689 ret = GST_FLOW_ERROR;
1690 g_assert_not_reached();
1691 break;
1692 }
1693 break;
1694
1695 default:
1696 ret = GST_FLOW_ERROR;
1697 g_assert_not_reached();
1698 break;
1699 }
1700done:
1701 return ret;
1702}
1703
1704static void
1705gst_aml_v4l2_buffer_pool_release_buffer(GstBufferPool *bpool, GstBuffer *buffer)
1706{
1707 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1708 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
1709 GstAmlV4l2Object *obj = pool->obj;
1710
1711 GST_DEBUG_OBJECT(pool, "release buffer %p", buffer);
1712
1713 /* If the buffer's pool has been orphaned, dispose of it so that
1714 * the pool resources can be freed */
1715 if (pool->orphaned)
1716 {
1717 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
1718 pclass->release_buffer(bpool, buffer);
1719 return;
1720 }
1721
1722 switch (obj->type)
1723 {
1724 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1725 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1726 /* capture, put the buffer back in the queue so that we can refill it
1727 * later. */
1728 switch (obj->mode)
1729 {
1730 case GST_V4L2_IO_RW:
1731 /* release back in the pool */
1732 pclass->release_buffer(bpool, buffer);
1733 break;
1734
1735 case GST_V4L2_IO_DMABUF:
1736 case GST_V4L2_IO_MMAP:
1737 case GST_V4L2_IO_USERPTR:
1738 case GST_V4L2_IO_DMABUF_IMPORT:
1739 {
1740 GstAmlV4l2MemoryGroup *group;
1741 if (gst_aml_v4l2_is_buffer_valid(buffer, &group))
1742 {
1743 GstFlowReturn ret = GST_FLOW_OK;
1744
1745 gst_aml_v4l2_allocator_reset_group(pool->vallocator, group);
1746
1747#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1748 GST_DEBUG_OBJECT(pool, "amlmodbuf trace in add flow with buf:%p index:%d", buffer, group->buffer.index);
1749 pool->read_to_free_bufs[group->buffer.index] = buffer;
1750 pool->ready_to_free_buf_num++;
1751 if (gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(bpool))
1752 {
1753 GST_DEBUG_OBJECT(pool, "amlmodbuf execute aml code logic, skip the following flow");
1754 return;
1755 }
1756#endif
1757 /* queue back in the device */
1758 if (pool->other_pool)
1759 ret = gst_aml_v4l2_buffer_pool_prepare_buffer(pool, buffer, NULL);
1760 if (ret != GST_FLOW_OK ||
1761 gst_aml_v4l2_buffer_pool_qbuf(pool, buffer, group) != GST_FLOW_OK)
1762 pclass->release_buffer(bpool, buffer);
1763 }
1764 else
1765 {
1766 /* Simply release invalide/modified buffer, the allocator will
1767 * give it back later */
1768 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
1769 pclass->release_buffer(bpool, buffer);
1770 }
1771 break;
1772 }
1773 default:
1774 g_assert_not_reached();
1775 break;
1776 }
1777 break;
1778
1779 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1780 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1781 switch (obj->mode)
1782 {
1783 case GST_V4L2_IO_RW:
1784 /* release back in the pool */
1785 pclass->release_buffer(bpool, buffer);
1786 break;
1787
1788 case GST_V4L2_IO_MMAP:
1789 case GST_V4L2_IO_DMABUF:
1790 case GST_V4L2_IO_USERPTR:
1791 case GST_V4L2_IO_DMABUF_IMPORT:
1792 {
1793 GstAmlV4l2MemoryGroup *group;
1794 guint index;
1795
1796 if (!gst_aml_v4l2_is_buffer_valid(buffer, &group))
1797 {
1798 /* Simply release invalide/modified buffer, the allocator will
1799 * give it back later */
1800 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_TAG_MEMORY);
1801 pclass->release_buffer(bpool, buffer);
1802 break;
1803 }
1804
1805 index = group->buffer.index;
1806
1807 if (pool->buffers[index] == NULL)
1808 {
1809 GST_LOG_OBJECT(pool, "buffer %u not queued, putting on free list",
1810 index);
1811
1812 /* Remove qdata, this will unmap any map data in userptr */
1813 gst_mini_object_set_qdata(GST_MINI_OBJECT(buffer),
1814 GST_AML_V4L2_IMPORT_QUARK, NULL, NULL);
1815
1816 /* reset to default size */
1817 gst_aml_v4l2_allocator_reset_group(pool->vallocator, group);
1818
1819 /* playback, put the buffer back in the queue to refill later. */
1820 pclass->release_buffer(bpool, buffer);
1821 }
1822 else
1823 {
1824 /* the buffer is queued in the device but maybe not played yet. We just
1825 * leave it there and not make it available for future calls to acquire
1826 * for now. The buffer will be dequeued and reused later. */
1827 GST_LOG_OBJECT(pool, "buffer %u is queued", index);
1828 }
1829 break;
1830 }
1831
1832 default:
1833 g_assert_not_reached();
1834 break;
1835 }
1836 break;
1837
1838 default:
1839 g_assert_not_reached();
1840 break;
1841 }
1842}
1843
1844#ifdef GST_AML_SPEC_FLOW_FOR_VBP
1845static gboolean
1846gst_aml_v4l2_buffer_pool_release_buffer_aml_patch(GstBufferPool *bpool)
1847{
1848 GstFlowReturn ret = GST_FLOW_OK;
1849 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
1850 GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS(parent_class);
1851 GstAmlV4l2Object *obj = pool->obj;
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001852 GstAmlV4l2VideoDec *dec = (GstAmlV4l2VideoDec *)obj->element;
xuesong.jiangae1548e2022-05-06 16:38:46 +08001853
1854 if (obj->mode == GST_V4L2_IO_DMABUF_IMPORT && pool->other_pool)
1855 {
1856 GstBuffer *src = NULL;
1857 GstBufferPoolAcquireParams params;
1858
xuesong.jiangc5dac0f2023-02-01 14:42:24 +08001859 if (obj->old_other_pool || obj->old_old_other_pool)
1860 {
1861 guint outstanding_buf_num = 0;
1862
1863 outstanding_buf_num = gst_aml_v4l2_object_get_outstanding_capture_buf_num(obj);
1864 GST_DEBUG_OBJECT(pool, "amlmodbuf oop outstanding buf num %d", outstanding_buf_num);
1865 if (outstanding_buf_num != obj->outstanding_buf_num)
1866 {
1867 guint update = 0;
1868
1869 if (outstanding_buf_num > obj->outstanding_buf_num)
1870 {
1871 GST_ERROR_OBJECT(pool, "amlmodbuf old other pool recycle buffer error, outstanding from %d to %d", obj->outstanding_buf_num, outstanding_buf_num);
1872 return FALSE;
1873 }
1874 GST_DEBUG_OBJECT(pool, "amlmodbuf oop outstanding buf num from %d reduce to %d", obj->outstanding_buf_num, outstanding_buf_num);
1875
1876 update = obj->outstanding_buf_num - outstanding_buf_num;
1877 if (!gst_buffer_pool_increase_max_num(pool->other_pool, update))
1878 {
1879 GST_ERROR_OBJECT(pool, "amlmodbuf update other pool max buffer num error");
1880 return FALSE;
1881 }
1882
1883 obj->outstanding_buf_num = outstanding_buf_num;
1884 }
1885 }
1886
xuesong.jiangae1548e2022-05-06 16:38:46 +08001887 memset(&params, 0, sizeof(GstBufferPoolAcquireParams));
1888 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
fei.denge9458472023-04-18 02:05:48 +00001889 GST_TRACE_OBJECT(pool, "amlmodbuf trace in aml release buf flow ready_to_free_buf_num:%d", pool->ready_to_free_buf_num);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001890 while (pool->ready_to_free_buf_num && gst_buffer_pool_acquire_buffer(pool->other_pool, &src, &params) != GST_FLOW_ERROR && src != NULL)
1891 {
1892 gint i = 0;
1893
fei.denge9458472023-04-18 02:05:48 +00001894 GST_TRACE_OBJECT(pool, "amlmodbuf acquire buf:%p form other pool", src);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001895 for (; i < VIDEO_MAX_FRAME; i++)
1896 {
1897 GST_DEBUG_OBJECT(pool, "amlmodbuf check index:%d", i);
1898 if (pool->read_to_free_bufs[i])
1899 {
1900 GstBuffer *bind_drm_buf = gst_mini_object_get_qdata(GST_MINI_OBJECT(pool->read_to_free_bufs[i]), GST_AML_V4L2_IMPORT_QUARK);
1901 if (bind_drm_buf == NULL)
1902 {
fei.denge9458472023-04-18 02:05:48 +00001903 GST_TRACE_OBJECT(pool, "init flow, bind v4l2 capture buf[%d]:%p with drm buf:%p", i, pool->read_to_free_bufs[i], src);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001904 }
1905 else if (src != bind_drm_buf)
1906 {
fei.denge9458472023-04-18 02:05:48 +00001907 GST_TRACE_OBJECT(pool, "v4l2 capture buf[%d]:%p bind drm buf:%p, not this one:%p, continue match", i, pool->read_to_free_bufs[i], bind_drm_buf, src);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001908 continue;
1909 }
1910
fei.denge9458472023-04-18 02:05:48 +00001911 GST_TRACE_OBJECT(pool, "v4l2 capture buf[%d]:%p found bind drm buf:%p", i, pool->read_to_free_bufs[i], src);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001912 GstFlowReturn isvalid = GST_FLOW_OK;
1913 GstAmlV4l2MemoryGroup *tmp_group = NULL;
1914
1915 // bind_drm_buf= gst_mini_object_steal_qdata(GST_MINI_OBJECT(pool->read_to_free_bufs[i]), GST_AML_V4L2_IMPORT_QUARK);
1916 ret = gst_aml_v4l2_buffer_pool_import_dmabuf(pool, pool->read_to_free_bufs[i], src);
1917 gst_buffer_unref(src);
1918 src = NULL;
1919 isvalid = gst_aml_v4l2_is_buffer_valid(pool->read_to_free_bufs[i], &tmp_group);
1920 if ((ret != GST_FLOW_OK && isvalid) || gst_aml_v4l2_buffer_pool_qbuf(pool, pool->read_to_free_bufs[i], tmp_group) != GST_FLOW_OK)
1921 {
fei.denge9458472023-04-18 02:05:48 +00001922 GST_TRACE_OBJECT(pool, "amlmodbuf go into error flow");
xuesong.jiangae1548e2022-05-06 16:38:46 +08001923 pclass->release_buffer(bpool, pool->read_to_free_bufs[i]);
1924 }
1925 pool->read_to_free_bufs[i] = NULL;
1926 pool->ready_to_free_buf_num--;
fei.denge9458472023-04-18 02:05:48 +00001927 GST_TRACE_OBJECT(pool, "amlmodbuf queued buf:%d, into v4l2 bp", i);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001928 break;
1929 }
1930 }
1931 if (i == VIDEO_MAX_FRAME)
1932 {
1933 GST_ERROR_OBJECT(pool, "drm buf:%p can't match any v4l2 capture buf, error", src);
1934 gst_buffer_unref(src);
1935 src = NULL;
1936 return FALSE;
1937 }
1938 }
fei.denge9458472023-04-18 02:05:48 +00001939 GST_TRACE_OBJECT(pool, "update all free drm buf into v4l2 capture buf pool, now ready_to_free_buf_num:%d", pool->ready_to_free_buf_num);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001940 return TRUE;
1941 }
1942 return FALSE;
1943}
1944#endif
1945
1946static void
1947gst_aml_v4l2_buffer_pool_dispose(GObject *object)
1948{
1949 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(object);
1950
1951 if (pool->vallocator)
1952 gst_object_unref(pool->vallocator);
1953 pool->vallocator = NULL;
1954
1955 if (pool->allocator)
1956 gst_object_unref(pool->allocator);
1957 pool->allocator = NULL;
1958
1959 if (pool->other_pool)
1960 gst_object_unref(pool->other_pool);
1961 pool->other_pool = NULL;
1962
1963 G_OBJECT_CLASS(parent_class)->dispose(object);
1964}
1965
1966static void
1967gst_aml_v4l2_buffer_pool_finalize(GObject *object)
1968{
1969 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(object);
1970
1971 if (pool->video_fd >= 0)
1972 pool->obj->close(pool->video_fd);
1973
1974 gst_poll_free(pool->poll);
1975
1976 /* This can't be done in dispose method because we must not set pointer
1977 * to NULL as it is part of the v4l2object and dispose could be called
1978 * multiple times */
1979 gst_object_unref(pool->obj->element);
1980
1981 g_cond_clear(&pool->empty_cond);
1982
1983 /* FIXME have we done enough here ? */
1984
1985 G_OBJECT_CLASS(parent_class)->finalize(object);
1986}
1987
1988static void
1989gst_aml_v4l2_buffer_pool_init(GstAmlV4l2BufferPool *pool)
1990{
1991 pool->poll = gst_poll_new(TRUE);
1992 pool->can_poll_device = TRUE;
1993 g_cond_init(&pool->empty_cond);
hanghang.luo3128f102022-08-18 10:36:19 +08001994 GST_OBJECT_LOCK(pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001995 pool->empty = TRUE;
hanghang.luo3128f102022-08-18 10:36:19 +08001996 GST_OBJECT_UNLOCK(pool);
xuesong.jiangae1548e2022-05-06 16:38:46 +08001997 pool->orphaned = FALSE;
1998}
1999
2000static void
2001gst_aml_v4l2_buffer_pool_class_init(GstAmlV4l2BufferPoolClass *klass)
2002{
2003 GObjectClass *object_class = G_OBJECT_CLASS(klass);
2004 GstBufferPoolClass *bufferpool_class = GST_BUFFER_POOL_CLASS(klass);
2005
2006 object_class->dispose = gst_aml_v4l2_buffer_pool_dispose;
2007 object_class->finalize = gst_aml_v4l2_buffer_pool_finalize;
2008
2009 bufferpool_class->start = gst_aml_v4l2_buffer_pool_start;
2010 bufferpool_class->stop = gst_aml_v4l2_buffer_pool_stop;
2011 bufferpool_class->set_config = gst_aml_v4l2_buffer_pool_set_config;
2012 bufferpool_class->alloc_buffer = gst_aml_v4l2_buffer_pool_alloc_buffer;
2013 bufferpool_class->acquire_buffer = gst_aml_v4l2_buffer_pool_acquire_buffer;
2014 bufferpool_class->release_buffer = gst_aml_v4l2_buffer_pool_release_buffer;
2015 bufferpool_class->flush_start = gst_aml_v4l2_buffer_pool_flush_start;
2016 bufferpool_class->flush_stop = gst_aml_v4l2_buffer_pool_flush_stop;
2017
2018 GST_DEBUG_CATEGORY_INIT(amlv4l2bufferpool_debug, "amlv4l2bufferpool", 0,
2019 "V4L2 Buffer Pool");
2020 GST_DEBUG_CATEGORY_GET(CAT_PERFORMANCE, "GST_PERFORMANCE");
2021}
2022
2023/**
2024 * gst_aml_v4l2_buffer_pool_new:
2025 * @obj: the v4l2 object owning the pool
2026 *
2027 * Construct a new buffer pool.
2028 *
2029 * Returns: the new pool, use gst_object_unref() to free resources
2030 */
2031GstBufferPool *
2032gst_aml_v4l2_buffer_pool_new(GstAmlV4l2Object *obj, GstCaps *caps)
2033{
2034 GstAmlV4l2BufferPool *pool;
2035 GstStructure *config;
2036 gchar *name, *parent_name;
2037 gint fd;
2038
2039 fd = obj->dup(obj->video_fd);
2040 if (fd < 0)
2041 goto dup_failed;
2042
2043 /* setting a significant unique name */
2044 parent_name = gst_object_get_name(GST_OBJECT(obj->element));
2045 name = g_strconcat(parent_name, ":", "pool:",
2046 V4L2_TYPE_IS_OUTPUT(obj->type) ? "sink" : "src", NULL);
2047 g_free(parent_name);
2048
2049 pool = (GstAmlV4l2BufferPool *)g_object_new(GST_TYPE_AML_V4L2_BUFFER_POOL,
2050 "name", name, NULL);
2051 g_object_ref_sink(pool);
2052 g_free(name);
2053
2054 gst_poll_fd_init(&pool->pollfd);
2055 pool->pollfd.fd = fd;
2056 gst_poll_add_fd(pool->poll, &pool->pollfd);
2057 if (V4L2_TYPE_IS_OUTPUT(obj->type))
sheng.liu8d18ed22022-05-26 17:28:15 +08002058 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002059 gst_poll_fd_ctl_write(pool->poll, &pool->pollfd, TRUE);
sheng.liu8d18ed22022-05-26 17:28:15 +08002060 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002061 else
sheng.liu8d18ed22022-05-26 17:28:15 +08002062 {
xuesong.jiangae1548e2022-05-06 16:38:46 +08002063 gst_poll_fd_ctl_read(pool->poll, &pool->pollfd, TRUE);
sheng.liu8d18ed22022-05-26 17:28:15 +08002064 gst_poll_fd_ctl_pri (pool->poll, &pool->pollfd, TRUE);
2065 }
xuesong.jiangae1548e2022-05-06 16:38:46 +08002066
2067 pool->video_fd = fd;
2068 pool->obj = obj;
2069 pool->can_poll_device = TRUE;
2070
2071 pool->vallocator = gst_aml_v4l2_allocator_new(GST_OBJECT(pool), obj);
2072 if (pool->vallocator == NULL)
2073 goto allocator_failed;
2074
2075 gst_object_ref(obj->element);
2076
2077 config = gst_buffer_pool_get_config(GST_BUFFER_POOL_CAST(pool));
2078 gst_buffer_pool_config_set_params(config, caps, obj->info.size, 0, 0);
2079 /* This will simply set a default config, but will not configure the pool
2080 * because min and max are not valid */
hanghang.luo3128f102022-08-18 10:36:19 +08002081 (void)gst_buffer_pool_set_config(GST_BUFFER_POOL_CAST(pool), config);
xuesong.jiangae1548e2022-05-06 16:38:46 +08002082
2083 return GST_BUFFER_POOL(pool);
2084
2085 /* ERRORS */
2086dup_failed:
2087{
2088 GST_ERROR("failed to dup fd %d (%s)", errno, g_strerror(errno));
2089 return NULL;
2090}
2091allocator_failed:
2092{
2093 GST_ERROR_OBJECT(pool, "Failed to create V4L2 allocator");
2094 gst_object_unref(pool);
2095 return NULL;
2096}
2097}
2098
2099static GstFlowReturn
2100gst_aml_v4l2_do_read(GstAmlV4l2BufferPool *pool, GstBuffer *buf)
2101{
2102 GstFlowReturn res;
2103 GstAmlV4l2Object *obj = pool->obj;
2104 gint amount;
2105 GstMapInfo map;
2106 gint toread;
2107
2108 toread = obj->info.size;
2109
2110 GST_LOG_OBJECT(pool, "reading %d bytes into buffer %p", toread, buf);
2111
2112 gst_buffer_map(buf, &map, GST_MAP_WRITE);
2113
2114 do
2115 {
2116 if ((res = gst_aml_v4l2_buffer_pool_poll(pool, TRUE)) != GST_FLOW_OK)
2117 goto poll_error;
2118
2119 amount = obj->read(obj->video_fd, map.data, toread);
2120
2121 if (amount == toread)
2122 {
2123 break;
2124 }
2125 else if (amount == -1)
2126 {
2127 if (errno == EAGAIN || errno == EINTR)
2128 {
2129 continue;
2130 }
2131 else
2132 goto read_error;
2133 }
2134 else
2135 {
2136 /* short reads can happen if a signal interrupts the read */
2137 continue;
2138 }
2139 } while (TRUE);
2140
2141 GST_LOG_OBJECT(pool, "read %d bytes", amount);
2142 gst_buffer_unmap(buf, &map);
2143 gst_buffer_resize(buf, 0, amount);
2144
2145 return GST_FLOW_OK;
2146
2147 /* ERRORS */
2148poll_error:
2149{
2150 GST_DEBUG("poll error %s", gst_flow_get_name(res));
2151 goto cleanup;
2152}
2153read_error:
2154{
2155 GST_ELEMENT_ERROR(obj->element, RESOURCE, READ,
2156 (_("Error reading %d bytes from device '%s'."),
2157 toread, obj->videodev),
2158 GST_ERROR_SYSTEM);
2159 res = GST_FLOW_ERROR;
2160 goto cleanup;
2161}
2162cleanup:
2163{
2164 gst_buffer_unmap(buf, &map);
2165 gst_buffer_resize(buf, 0, 0);
2166 return res;
2167}
2168}
2169
2170/**
2171 * gst_aml_v4l2_buffer_pool_process:
2172 * @bpool: a #GstBufferPool
2173 * @buf: a #GstBuffer, maybe be replaced
2174 *
2175 * Process @buf in @bpool. For capture devices, this functions fills @buf with
2176 * data from the device. For output devices, this functions send the contents of
2177 * @buf to the device for playback.
2178 *
2179 * Returns: %GST_FLOW_OK on success.
2180 */
2181GstFlowReturn
2182gst_aml_v4l2_buffer_pool_process(GstAmlV4l2BufferPool *pool, GstBuffer **buf)
2183{
2184 GstFlowReturn ret = GST_FLOW_OK;
2185 GstBufferPool *bpool = GST_BUFFER_POOL_CAST(pool);
2186 GstAmlV4l2Object *obj = pool->obj;
2187
2188 GST_DEBUG_OBJECT(pool, "process buffer %p, buf_pool:%p, v4l2 output pool:%p", buf, (*buf)->pool, bpool);
2189
2190 if (GST_BUFFER_POOL_IS_FLUSHING(pool))
2191 return GST_FLOW_FLUSHING;
2192
2193 switch (obj->type)
2194 {
2195 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2196 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
2197 /* capture */
2198 switch (obj->mode)
2199 {
2200 case GST_V4L2_IO_RW:
2201 /* capture into the buffer */
2202 ret = gst_aml_v4l2_do_read(pool, *buf);
2203 break;
2204
2205 case GST_V4L2_IO_MMAP:
2206 case GST_V4L2_IO_DMABUF:
2207 {
2208 GstBuffer *tmp;
2209
2210 if ((*buf)->pool == bpool)
2211 {
2212 guint num_queued;
2213 gsize size = gst_buffer_get_size(*buf);
2214
2215 /* Legacy M2M devices return empty buffer when drained */
2216 if (size == 0 && GST_AML_V4L2_IS_M2M(obj->device_caps))
2217 goto eos;
2218
2219 if (GST_VIDEO_INFO_FORMAT(&pool->caps_info) !=
2220 GST_VIDEO_FORMAT_ENCODED &&
2221 size < pool->size)
2222 goto buffer_truncated;
2223
2224 num_queued = g_atomic_int_get(&pool->num_queued);
2225 GST_TRACE_OBJECT(pool, "Only %i buffer left in the capture queue.",
2226 num_queued);
2227
2228 /* If we have no more buffer, and can allocate it time to do so */
2229 if (num_queued == 0)
2230 {
2231 if (GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP))
2232 {
2233 ret = gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
2234 if (ret == GST_FLOW_OK)
2235 goto done;
2236 }
2237 }
2238
2239 /* start copying buffers when we are running low on buffers */
2240 if (num_queued < pool->copy_threshold)
2241 {
2242 GstBuffer *copy;
2243
2244 if (GST_AML_V4L2_ALLOCATOR_CAN_ALLOCATE(pool->vallocator, MMAP))
2245 {
2246 ret = gst_aml_v4l2_buffer_pool_resurrect_buffer(pool);
2247 if (ret == GST_FLOW_OK)
2248 goto done;
2249 }
2250
2251 /* copy the buffer */
2252 copy = gst_buffer_copy_region(*buf,
2253 GST_BUFFER_COPY_ALL | GST_BUFFER_COPY_DEEP, 0, -1);
2254 GST_LOG_OBJECT(pool, "copy buffer %p->%p", *buf, copy);
2255
2256 /* and requeue so that we can continue capturing */
2257 gst_buffer_unref(*buf);
2258 *buf = copy;
2259 }
2260
2261 ret = GST_FLOW_OK;
2262 /* nothing, data was inside the buffer when we did _acquire() */
2263 goto done;
2264 }
2265
2266 /* buffer not from our pool, grab a frame and copy it into the target */
2267 if ((ret = gst_aml_v4l2_buffer_pool_dequeue(pool, &tmp, TRUE)) != GST_FLOW_OK)
2268 goto done;
2269
2270 if (obj->dumpframefile)
2271 {
2272 FILE *pFile = fopen(obj->dumpframefile, "ab");
2273 if (pFile)
2274 {
2275 int n = gst_buffer_n_memory(tmp);
2276 int i;
2277 GstMapInfo map_info;
2278 GstMemory *mem;
2279
2280 for (i = 0; i < n; ++i)
2281 {
2282 mem = gst_buffer_peek_memory(tmp, i);
2283 if (gst_memory_map(mem, &map_info, GST_MAP_READ))
2284 {
2285 fwrite(map_info.data, map_info.size, 1, pFile);
2286 gst_memory_unmap(mem, &map_info);
2287 }
2288 }
2289 fclose(pFile);
2290 }
2291 }
2292 /* An empty buffer on capture indicates the end of stream */
2293 if (gst_buffer_get_size(tmp) == 0)
2294 {
2295 gst_aml_v4l2_buffer_pool_release_buffer(bpool, tmp);
2296
2297 /* Legacy M2M devices return empty buffer when drained */
2298 if (GST_AML_V4L2_IS_M2M(obj->device_caps))
2299 goto eos;
2300 }
2301
2302 ret = gst_aml_v4l2_buffer_pool_copy_buffer(pool, *buf, tmp);
2303
2304 /* an queue the buffer again after the copy */
2305 gst_aml_v4l2_buffer_pool_release_buffer(bpool, tmp);
2306
2307 if (ret != GST_FLOW_OK)
2308 goto copy_failed;
2309 break;
2310 }
2311
2312 case GST_V4L2_IO_USERPTR:
2313 {
2314 struct UserPtrData *data;
2315 GstBuffer *tmp;
2316
2317 /* Replace our buffer with downstream allocated buffer */
2318 data = gst_mini_object_steal_qdata(GST_MINI_OBJECT(*buf),
2319 GST_AML_V4L2_IMPORT_QUARK);
2320 tmp = gst_buffer_ref(data->buffer);
2321 _unmap_userptr_frame(data);
2322
2323 /* Now tmp is writable, copy the flags and timestamp */
2324 gst_buffer_copy_into(tmp, *buf,
2325 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2326
2327 gst_buffer_replace(buf, tmp);
2328 gst_buffer_unref(tmp);
2329 break;
2330 }
2331
2332 case GST_V4L2_IO_DMABUF_IMPORT:
2333 {
2334 GstBuffer *tmp;
2335
2336 /* Replace our buffer with downstream allocated buffer */
2337 // tmp = gst_mini_object_steal_qdata(GST_MINI_OBJECT(*buf),
2338 // GST_AML_V4L2_IMPORT_QUARK);
2339 tmp = gst_mini_object_get_qdata(GST_MINI_OBJECT(*buf), GST_AML_V4L2_IMPORT_QUARK);
2340 GST_DEBUG("got v4l2 capture buf:%p, with qdata drm buf:%p", *buf, tmp);
2341
2342 gst_buffer_copy_into(tmp, *buf,
2343 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
2344
2345 gst_buffer_replace(buf, tmp);
2346 gst_buffer_unref(tmp);
2347 break;
2348 }
2349
2350 default:
2351 g_assert_not_reached();
2352 break;
2353 }
2354 break;
2355
2356 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
2357 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
2358 /* playback */
2359 switch (obj->mode)
2360 {
2361 case GST_V4L2_IO_RW:
2362 /* FIXME, do write() */
2363 GST_WARNING_OBJECT(pool, "implement write()");
2364 break;
2365
2366 case GST_V4L2_IO_USERPTR:
2367 case GST_V4L2_IO_DMABUF_IMPORT:
2368 case GST_V4L2_IO_DMABUF:
2369 case GST_V4L2_IO_MMAP:
2370 {
2371 GstBuffer *to_queue = NULL;
2372 GstBuffer *buffer;
2373 GstAmlV4l2MemoryGroup *group;
2374 gint index;
2375
2376 if ((*buf)->pool != bpool)
2377 goto copying;
2378
2379 if (!gst_aml_v4l2_is_buffer_valid(*buf, &group))
2380 goto copying;
2381
2382 index = group->buffer.index;
2383
2384 GST_LOG_OBJECT(pool, "processing buffer %i from our pool", index);
2385
2386 if (pool->buffers[index] != NULL)
2387 {
2388 GST_LOG_OBJECT(pool, "buffer %i already queued, copying", index);
2389 goto copying;
2390 }
2391
2392 /* we can queue directly */
2393 to_queue = gst_buffer_ref(*buf);
2394
2395 copying:
2396 if (to_queue == NULL)
2397 {
2398 GstBufferPoolAcquireParams params = {0};
2399
2400 GST_LOG_OBJECT(pool, "alloc buffer from our pool");
2401
2402 /* this can return EOS if all buffers are outstanding which would
2403 * be strange because we would expect the upstream element to have
2404 * allocated them and returned to us.. */
2405 params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
2406 ret = gst_buffer_pool_acquire_buffer(bpool, &to_queue, &params);
2407 if (ret != GST_FLOW_OK)
2408 goto acquire_failed;
2409
2410 ret = gst_aml_v4l2_buffer_pool_prepare_buffer(pool, to_queue, *buf);
2411 if (ret != GST_FLOW_OK)
2412 {
2413 gst_buffer_unref(to_queue);
2414 goto prepare_failed;
2415 }
2416
2417 /* retreive the group */
2418 gst_aml_v4l2_is_buffer_valid(to_queue, &group);
2419 }
2420
2421 if ((ret = gst_aml_v4l2_buffer_pool_qbuf(pool, to_queue, group)) != GST_FLOW_OK)
2422 goto queue_failed;
2423
2424 /* if we are not streaming yet (this is the first buffer, start
2425 * streaming now */
2426 if (!gst_aml_v4l2_buffer_pool_streamon(pool))
2427 {
2428 /* don't check return value because qbuf would have failed */
2429 gst_aml_v4l2_is_buffer_valid(to_queue, &group);
2430
2431 /* qbuf has stored to_queue buffer but we are not in
2432 * streaming state, so the flush logic won't be performed.
2433 * To avoid leaks, flush the allocator and restore the queued
2434 * buffer as non-queued */
2435 gst_aml_v4l2_allocator_flush(pool->vallocator);
2436
2437 pool->buffers[group->buffer.index] = NULL;
2438
2439 gst_mini_object_set_qdata(GST_MINI_OBJECT(to_queue),
2440 GST_AML_V4L2_IMPORT_QUARK, NULL, NULL);
2441 gst_buffer_unref(to_queue);
2442 g_atomic_int_add(&pool->num_queued, -1);
2443 goto start_failed;
2444 }
2445
2446 /* Remove our ref, we will still hold this buffer in acquire as needed,
2447 * otherwise the pool will think it is outstanding and will refuse to stop. */
2448 gst_buffer_unref(to_queue);
2449
2450 /* release as many buffer as possible */
2451 while (gst_aml_v4l2_buffer_pool_dequeue(pool, &buffer, FALSE) ==
2452 GST_FLOW_OK)
2453 {
2454 if (buffer->pool == NULL)
2455 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
2456 }
2457
2458 if (g_atomic_int_get(&pool->num_queued) >= pool->min_latency)
2459 {
2460 /* all buffers are queued, try to dequeue one and release it back
2461 * into the pool so that _acquire can get to it again. */
2462 ret = gst_aml_v4l2_buffer_pool_dequeue(pool, &buffer, TRUE);
2463 if (ret == GST_FLOW_OK && buffer->pool == NULL)
2464 /* release the rendered buffer back into the pool. This wakes up any
2465 * thread waiting for a buffer in _acquire(). */
2466 gst_aml_v4l2_buffer_pool_release_buffer(bpool, buffer);
2467 }
2468 break;
2469 }
2470 default:
2471 g_assert_not_reached();
2472 break;
2473 }
2474 break;
2475 default:
2476 g_assert_not_reached();
2477 break;
2478 }
2479done:
2480 return ret;
2481
2482 /* ERRORS */
2483copy_failed:
2484{
2485 GST_ERROR_OBJECT(pool, "failed to copy buffer");
2486 return ret;
2487}
2488buffer_truncated:
2489{
2490 GST_WARNING_OBJECT(pool,
2491 "Dropping truncated buffer, this is likely a driver bug.");
2492 gst_buffer_unref(*buf);
2493 *buf = NULL;
2494 return GST_AML_V4L2_FLOW_CORRUPTED_BUFFER;
2495}
2496eos:
2497{
2498 GST_DEBUG_OBJECT(pool, "end of stream reached");
2499 gst_buffer_unref(*buf);
2500 *buf = NULL;
2501 return GST_AML_V4L2_FLOW_LAST_BUFFER;
2502}
2503acquire_failed:
2504{
2505 if (ret == GST_FLOW_FLUSHING)
2506 GST_DEBUG_OBJECT(pool, "flushing");
2507 else
2508 GST_WARNING_OBJECT(pool, "failed to acquire a buffer: %s",
2509 gst_flow_get_name(ret));
2510 return ret;
2511}
2512prepare_failed:
2513{
2514 GST_ERROR_OBJECT(pool, "failed to prepare data");
2515 return ret;
2516}
2517queue_failed:
2518{
2519 GST_ERROR_OBJECT(pool, "failed to queue buffer");
2520 return ret;
2521}
2522start_failed:
2523{
2524 GST_ERROR_OBJECT(pool, "failed to start streaming");
2525 return GST_FLOW_ERROR;
2526}
2527}
2528
2529void gst_aml_v4l2_buffer_pool_set_other_pool(GstAmlV4l2BufferPool *pool,
2530 GstBufferPool *other_pool)
2531{
2532 g_return_if_fail(!gst_buffer_pool_is_active(GST_BUFFER_POOL(pool)));
2533
2534 if (pool->other_pool)
2535 gst_object_unref(pool->other_pool);
2536 pool->other_pool = gst_object_ref(other_pool);
2537}
2538
2539void gst_aml_v4l2_buffer_pool_copy_at_threshold(GstAmlV4l2BufferPool *pool, gboolean copy)
2540{
2541 GST_OBJECT_LOCK(pool);
2542 pool->enable_copy_threshold = copy;
2543 GST_OBJECT_UNLOCK(pool);
2544}
2545
2546gboolean
2547gst_aml_v4l2_buffer_pool_flush(GstBufferPool *bpool)
2548{
2549 GstAmlV4l2BufferPool *pool = GST_AML_V4L2_BUFFER_POOL(bpool);
2550 gboolean ret = TRUE;
2551
2552 gst_aml_v4l2_buffer_pool_streamoff(pool);
2553
2554 if (!V4L2_TYPE_IS_OUTPUT(pool->obj->type))
2555 ret = gst_aml_v4l2_buffer_pool_streamon(pool);
2556
2557 return ret;
2558}
2559
2560void gst_aml_v4l2_buffer_pool_dump_stat(GstAmlV4l2BufferPool *pool, const gchar *file_name, gint try_num)
2561{
2562 const gchar *dump_dir = NULL;
2563 gchar *full_file_name = NULL;
2564 FILE *out = NULL;
2565
2566 dump_dir = g_getenv("GST_DEBUG_DUMP_AMLV4L2DEC_STAT_DIR");
2567 if (G_LIKELY(dump_dir == NULL))
2568 return;
2569
2570 if (!file_name)
2571 {
2572 file_name = "unnamed";
2573 }
2574
2575 full_file_name = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s.stat", dump_dir, file_name);
2576
2577 if ((out = fopen(full_file_name, "w")))
2578 {
2579 GstStructure *config = NULL;
2580 config = gst_buffer_pool_get_config((GstBufferPool *)pool);
2581 if (config)
2582 {
2583 GstCaps *caps;
2584 guint size, min_buffers, max_buffers;
2585 if (gst_buffer_pool_config_get_params(config, &caps, &size, &min_buffers, &max_buffers))
2586 {
2587 gchar *stat_info;
2588
2589 /* set local pool info*/
2590 gint already_queued = 0;
2591 gint ready_to_queue_num = 0;
2592 for (gint i = 0; i < VIDEO_MAX_FRAME; i++)
2593 {
2594 if (pool->buffers[i])
2595 {
2596 already_queued++;
2597 }
2598 if (pool->read_to_free_bufs[i])
2599 {
2600 ready_to_queue_num++;
2601 }
2602 }
2603
2604 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",
2605 size, min_buffers, max_buffers,
2606 pool->num_queued, pool->num_allocated,
2607 already_queued, ready_to_queue_num, try_num);
2608 fputs(stat_info, out);
2609 g_free(stat_info);
2610
2611 /* set other pool info*/
2612 if (pool->other_pool)
2613 {
2614 GstStructure *other_config = NULL;
2615 other_config = gst_buffer_pool_get_config((GstBufferPool *)pool);
2616 if (other_config)
2617 {
2618 GstCaps *other_caps;
2619 guint other_size, other_min_buffers, other_max_buffers;
2620 if (gst_buffer_pool_config_get_params(config, &other_caps, &other_size, &other_min_buffers, &other_max_buffers))
2621 {
2622 stat_info = g_strdup_printf("other pool | size:%d, min_bufs:%d, max_bufs:%d\n",
2623 other_size, other_min_buffers, other_max_buffers);
2624
2625 // TODO:GstBufferPool中没有获取outstanding的接口,所以这里没有统计otherpool中在用buffer的状态,后续需要修改gstreamer-1.0中code新增接口
2626 fputs(stat_info, out);
2627 g_free(stat_info);
2628 }
2629 }
2630 }
2631 GST_INFO("wrote amlv4l2 bufferpool stat to : '%s' succ", full_file_name);
2632 }
2633 }
2634 else
2635 {
2636 GST_WARNING("Failed to get config for pool:%p", pool);
2637 }
2638 fclose(out);
2639 }
2640 else
2641 {
2642 GST_WARNING("Failed to open file '%s' for writing: %s", full_file_name, g_strerror(errno));
2643 }
2644 g_free(full_file_name);
2645}