gstv4l2bufferpool.c 37.7 KB
Newer Older
Rob Clark's avatar
Rob Clark committed
1 2 3 4 5 6
/* GStreamer
 *
 * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
 *               2006 Edgard Lima <edgard.lima@indt.org.br>
 *               2009 Texas Instruments, Inc - http://www.ti.com/
 *
7
 * gstv4l2bufferpool.c V4L2 buffer pool class
Rob Clark's avatar
Rob Clark committed
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
21 22
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
Rob Clark's avatar
Rob Clark committed
23 24 25 26 27 28
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

29 30 31
#ifndef _GNU_SOURCE
# define _GNU_SOURCE            /* O_CLOEXEC */
#endif
32
#include <fcntl.h>
Rob Clark's avatar
Rob Clark committed
33

34 35 36 37
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>

38
#include "gst/video/video.h"
Wim Taymans's avatar
Wim Taymans committed
39
#include "gst/video/gstvideometa.h"
Wim Taymans's avatar
Wim Taymans committed
40
#include "gst/video/gstvideopool.h"
41
#include "gst/allocators/gstdmabuf.h"
42

Rob Clark's avatar
Rob Clark committed
43
#include <gstv4l2bufferpool.h>
Wim Taymans's avatar
Wim Taymans committed
44

Rob Clark's avatar
Rob Clark committed
45 46
#include "v4l2_calls.h"
#include "gst/gst-i18n-plugin.h"
47
#include <gst/glib-compat-private.h>
Rob Clark's avatar
Rob Clark committed
48 49 50 51

GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
#define GST_CAT_DEFAULT v4l2_debug

Wim Taymans's avatar
Wim Taymans committed
52 53 54 55 56 57
/*
 * GstV4l2BufferPool:
 */
#define gst_v4l2_buffer_pool_parent_class parent_class
G_DEFINE_TYPE (GstV4l2BufferPool, gst_v4l2_buffer_pool, GST_TYPE_BUFFER_POOL);

58 59 60 61 62 63
enum _GstV4l2BufferPoolAcquireFlags
{
  GST_V4L2_POOL_ACQUIRE_FLAG_RESURECT = GST_BUFFER_POOL_ACQUIRE_FLAG_LAST,
  GST_V4L2_BUFFER_POOL_ACQUIRE_FAG_LAST
};

64 65 66
static void gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool,
    GstBuffer * buffer);

67 68
static gboolean
gst_v4l2_is_buffer_valid (GstBuffer * buffer, GstV4l2MemoryGroup ** group)
Rob Clark's avatar
Rob Clark committed
69
{
70 71
  GstMemory *mem = gst_buffer_peek_memory (buffer, 0);
  gboolean valid = FALSE;
Rob Clark's avatar
Rob Clark committed
72

73 74
  if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY))
    goto done;
Rob Clark's avatar
Rob Clark committed
75

76 77 78
  if (gst_is_dmabuf_memory (mem))
    mem = mem->parent;

79 80 81 82 83
  if (gst_is_v4l2_memory (mem)) {
    GstV4l2Memory *vmem = (GstV4l2Memory *) mem;
    valid = TRUE;
    if (group)
      *group = vmem->group;
Wim Taymans's avatar
Wim Taymans committed
84
  }
85 86 87

done:
  return valid;
Rob Clark's avatar
Rob Clark committed
88 89
}

Wim Taymans's avatar
Wim Taymans committed
90 91
static GstFlowReturn
gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
Wim Taymans's avatar
Wim Taymans committed
92
    GstBufferPoolAcquireParams * params)
Rob Clark's avatar
Rob Clark committed
93
{
Wim Taymans's avatar
Wim Taymans committed
94
  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
95 96
  GstV4l2MemoryGroup *group = NULL;
  GstBuffer *newbuf = NULL;
97
  GstV4l2Object *obj;
98
  GstVideoInfo *info;
99
  GstVideoAlignment *align;
100 101

  obj = pool->obj;
102
  info = &obj->info;
103
  align = &obj->align;
Rob Clark's avatar
Rob Clark committed
104

Wim Taymans's avatar
Wim Taymans committed
105 106 107
  switch (obj->mode) {
    case GST_V4L2_IO_RW:
      newbuf =
Wim Taymans's avatar
Wim Taymans committed
108
          gst_buffer_new_allocate (pool->allocator, pool->size, &pool->params);
Wim Taymans's avatar
Wim Taymans committed
109 110
      break;
    case GST_V4L2_IO_MMAP:
111 112
      group = gst_v4l2_allocator_alloc_mmap (pool->vallocator);
      break;
113
    case GST_V4L2_IO_DMABUF:
114 115
      group = gst_v4l2_allocator_alloc_dmabuf (pool->vallocator,
          pool->allocator);
Wim Taymans's avatar
Wim Taymans committed
116 117
      break;
    case GST_V4L2_IO_USERPTR:
118
    case GST_V4L2_IO_DMABUF_IMPORT:
Wim Taymans's avatar
Wim Taymans committed
119
    default:
120
      newbuf = NULL;
Wim Taymans's avatar
Wim Taymans committed
121
      g_assert_not_reached ();
122
      break;
123
  }
Wim Taymans's avatar
Wim Taymans committed
124

125 126 127
  if (group != NULL) {
    gint i;
    newbuf = gst_buffer_new ();
Wim Taymans's avatar
Wim Taymans committed
128

129 130 131 132 133
    for (i = 0; i < group->n_mem; i++)
      gst_buffer_append_memory (newbuf, group->mem[i]);
  } else if (newbuf == NULL) {
    goto allocation_failed;
  }
Wim Taymans's avatar
Wim Taymans committed
134

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
  /* add metadata to raw video buffers */
  if (pool->add_videometa && info->finfo) {
    const GstVideoFormatInfo *finfo = info->finfo;
    gsize offset[GST_VIDEO_MAX_PLANES];
    gint width, height, n_gst_planes, offs, i, stride[GST_VIDEO_MAX_PLANES];

    width = GST_VIDEO_INFO_WIDTH (info);
    height = GST_VIDEO_INFO_HEIGHT (info);

    /* n_gst_planes is the number of planes
     * (RGB: 1, YUY2: 1, NV12: 2, I420: 3)
     * It's greater or equal than the number of v4l2 planes. */
    n_gst_planes = GST_VIDEO_INFO_N_PLANES (info);

    /* the basic are common between MPLANE mode and non MPLANE mode
     * except a special case inside the loop at the end
     */
    offs = 0;
    for (i = 0; i < n_gst_planes; i++) {
      GST_DEBUG_OBJECT (pool, "adding video meta, bytesperline %d",
          obj->bytesperline[i]);

      offset[i] = offs;

      if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo)) {
        guint x_tiles, y_tiles, ws, hs, tile_height;

        ws = GST_VIDEO_FORMAT_INFO_TILE_WS (finfo);
        hs = GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
        tile_height = 1 << hs;

        x_tiles = obj->bytesperline[i] >> ws;
        y_tiles = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i,
            GST_ROUND_UP_N (height, tile_height) >> hs);
        stride[i] = GST_VIDEO_TILE_MAKE_STRIDE (x_tiles, y_tiles);
      } else {
        stride[i] = obj->bytesperline[i];
      }
Rob Clark's avatar
Rob Clark committed
173

174 175 176 177 178 179 180 181 182 183 184 185 186
      /* when using multiplanar mode and if there is more then one v4l
       * plane for each gst plane
       */
      if (V4L2_TYPE_IS_MULTIPLANAR (obj->type) && group->n_mem > 1)
        /* non_contiguous case here so we have to make sure that gst goes to the
         * next plane (using default gstvideometa.c::default_map).
         * And the next plane is after length bytes of the previous one from
         * the gst buffer point of view. */
        offs += gst_memory_get_sizes (group->mem[i], NULL, NULL);
      else
        offs += obj->bytesperline[i] *
            GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, i, height);
    }
187

188 189 190
    gst_buffer_add_video_meta_full (newbuf, GST_VIDEO_FRAME_FLAG_NONE,
        GST_VIDEO_INFO_FORMAT (info), width, height, n_gst_planes,
        offset, stride);
191
  }
Rob Clark's avatar
Rob Clark committed
192

193 194 195 196 197 198 199
  if (pool->add_cropmeta) {
    GstVideoCropMeta *crop;
    crop = gst_buffer_add_video_crop_meta (newbuf);
    crop->x = align->padding_left;
    crop->y = align->padding_top;
    crop->width = info->width;
    crop->width = info->height;
Rob Clark's avatar
Rob Clark committed
200 201
  }

202 203
  pool->num_allocated++;
  *buffer = newbuf;
204

205 206 207 208 209 210 211
  return GST_FLOW_OK;

  /* ERRORS */
allocation_failed:
  {
    GST_WARNING ("Failed to allocated buffer");
    return GST_FLOW_EOS;
212
  }
Rob Clark's avatar
Rob Clark committed
213 214
}

Wim Taymans's avatar
Wim Taymans committed
215 216
static gboolean
gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
Rob Clark's avatar
Rob Clark committed
217
{
Wim Taymans's avatar
Wim Taymans committed
218
  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
Wim Taymans's avatar
Wim Taymans committed
219
  GstV4l2Object *obj = pool->obj;
Wim Taymans's avatar
Wim Taymans committed
220
  GstCaps *caps;
221
  guint size, min_buffers, max_buffers;
Wim Taymans's avatar
Wim Taymans committed
222 223
  GstAllocator *allocator;
  GstAllocationParams params;
224 225 226
  gboolean can_allocate = FALSE;
  gboolean updated = FALSE;
  gboolean ret;
Rob Clark's avatar
Rob Clark committed
227

Wim Taymans's avatar
Wim Taymans committed
228
  pool->add_videometa =
Wim Taymans's avatar
Wim Taymans committed
229
      gst_buffer_pool_config_has_option (config,
Wim Taymans's avatar
Wim Taymans committed
230
      GST_BUFFER_POOL_OPTION_VIDEO_META);
Wim Taymans's avatar
Wim Taymans committed
231

232 233 234 235
  pool->add_cropmeta =
      gst_buffer_pool_config_has_option (config,
      GST_V4L2_BUFFER_POOL_OPTION_CROP_META);

236 237
  if (!pool->add_videometa && obj->need_video_meta)
    goto missing_video_api;
Wim Taymans's avatar
Wim Taymans committed
238

239 240 241
  if (!pool->add_cropmeta && obj->need_crop_meta)
    goto missing_crop_api;

Wim Taymans's avatar
Wim Taymans committed
242
  /* parse the config and keep around */
Wim Taymans's avatar
Wim Taymans committed
243 244 245 246 247
  if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers,
          &max_buffers))
    goto wrong_config;

  if (!gst_buffer_pool_config_get_allocator (config, &allocator, &params))
Wim Taymans's avatar
Wim Taymans committed
248
    goto wrong_config;
Rob Clark's avatar
Rob Clark committed
249

Wim Taymans's avatar
Wim Taymans committed
250
  GST_DEBUG_OBJECT (pool, "config %" GST_PTR_FORMAT, config);
Rob Clark's avatar
Rob Clark committed
251

252 253
  if (pool->allocator)
    gst_object_unref (pool->allocator);
254
  pool->allocator = NULL;
255

256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
  switch (obj->mode) {
    case GST_V4L2_IO_DMABUF:
      pool->allocator = gst_dmabuf_allocator_new ();
      can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP);
      break;
    case GST_V4L2_IO_MMAP:
      can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP);
      break;
    case GST_V4L2_IO_USERPTR:
      can_allocate =
          GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, USERPTR);
      break;
    case GST_V4L2_IO_RW:
      pool->allocator = g_object_ref (allocator);
      pool->params = params;
      /* No need to change the configuration */
      goto done;
      break;
274 275 276 277
    case GST_V4L2_IO_DMABUF_IMPORT:
    default:
      g_assert_not_reached ();
      break;
278
  }
279

280 281 282 283 284
  if (min_buffers < GST_V4L2_MIN_BUFFERS) {
    updated = TRUE;
    min_buffers = GST_V4L2_MIN_BUFFERS;
    GST_INFO_OBJECT (pool, "increasing minimum buffers to %u", min_buffers);
  }
285

286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
  if (max_buffers > VIDEO_MAX_FRAME || max_buffers == 0) {
    updated = TRUE;
    max_buffers = VIDEO_MAX_FRAME;
    GST_INFO_OBJECT (pool, "reducing maximum buffers to %u", max_buffers);
  }

  if (min_buffers > max_buffers) {
    updated = TRUE;
    min_buffers = max_buffers;
    GST_INFO_OBJECT (pool, "reducing minimum buffers to %u", min_buffers);
  } else if (min_buffers != max_buffers) {
    if (!can_allocate) {
      updated = TRUE;
      max_buffers = min_buffers;
      GST_INFO_OBJECT (pool, "can't allocate, setting maximum to minimum");
    }
  }

  if (updated)
    gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
        max_buffers);

done:
  ret = GST_BUFFER_POOL_CLASS (parent_class)->set_config (bpool, config);

  /* If anything was changed documentation recommand to return FALSE */
  return !updated && ret;
313 314 315 316

  /* ERRORS */
missing_video_api:
  {
317 318 319 320 321 322
    GST_ERROR_OBJECT (pool, "missing GstVideoMeta API in config");
    return FALSE;
  }
missing_crop_api:
  {
    GST_ERROR_OBJECT (pool, "missing GstVideoCropMeta API");
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
    return FALSE;
  }
wrong_config:
  {
    GST_ERROR_OBJECT (pool, "invalid config %" GST_PTR_FORMAT, config);
    return FALSE;
  }
}

static gboolean
start_streaming (GstV4l2BufferPool * pool)
{
  GstV4l2Object *obj = pool->obj;

  switch (obj->mode) {
    case GST_V4L2_IO_RW:
      break;
    case GST_V4L2_IO_MMAP:
    case GST_V4L2_IO_USERPTR:
    case GST_V4L2_IO_DMABUF:
343
    case GST_V4L2_IO_DMABUF_IMPORT:
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
      GST_DEBUG_OBJECT (pool, "STREAMON");
      if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
        goto start_failed;
      break;
    default:
      g_assert_not_reached ();
      break;
  }

  pool->streaming = TRUE;

  return TRUE;

  /* ERRORS */
start_failed:
  {
    GST_ERROR_OBJECT (pool, "error with STREAMON %d (%s)", errno,
        g_strerror (errno));
    return FALSE;
  }
}

366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
static void
gst_v4l2_buffer_pool_group_released (GstV4l2BufferPool * pool)
{
  GstBufferPoolAcquireParams params = { 0 };
  GstBuffer *buffer = NULL;
  GstFlowReturn ret;

  GST_DEBUG_OBJECT (pool, "A buffer was lost, reallocating it");

  params.flags = GST_V4L2_POOL_ACQUIRE_FLAG_RESURECT;
  ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (pool), &buffer,
      &params);

  if (ret == GST_FLOW_OK)
    gst_buffer_unref (buffer);
}

383 384 385 386 387 388 389
static gboolean
gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
{
  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
  GstV4l2Object *obj = pool->obj;
  GstStructure *config;
  GstCaps *caps;
390 391
  guint size, min_buffers, max_buffers;
  guint num_buffers = 0, copy_threshold = 0;
392 393 394 395 396 397

  config = gst_buffer_pool_get_config (bpool);
  if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers,
          &max_buffers))
    goto wrong_config;

Wim Taymans's avatar
Wim Taymans committed
398 399
  switch (obj->mode) {
    case GST_V4L2_IO_RW:
400 401 402
      /* this value also instructs the latency calculation to have min_buffers
       * frame latency max */
      num_buffers = min_buffers;
Wim Taymans's avatar
Wim Taymans committed
403
      break;
404
    case GST_V4L2_IO_DMABUF:
Wim Taymans's avatar
Wim Taymans committed
405 406
    case GST_V4L2_IO_MMAP:
    {
407 408 409 410 411
      guint count;

      if (GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP)) {
        num_buffers = min_buffers;
      } else {
Wim Taymans's avatar
Wim Taymans committed
412
        num_buffers = max_buffers;
413
      }
Wim Taymans's avatar
Wim Taymans committed
414 415

      /* first, lets request buffers, and see how many we can get: */
416
      GST_DEBUG_OBJECT (pool, "requesting %d MMAP buffers", num_buffers);
Wim Taymans's avatar
Wim Taymans committed
417

418 419
      count = gst_v4l2_allocator_start (pool->vallocator, num_buffers,
          V4L2_MEMORY_MMAP);
Wim Taymans's avatar
Wim Taymans committed
420

421 422
      if (count < GST_V4L2_MIN_BUFFERS) {
        num_buffers = count;
Wim Taymans's avatar
Wim Taymans committed
423 424
        goto no_buffers;
      }
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440

      /* V4L2 buffer pool are often very limited in the amount of buffers it
       * can offer. The copy_threshold will workaround this limitation by
       * falling back to copy if the pipeline needed more buffers. This also
       * prevent having to do REQBUFS(N)/REQBUFS(0) everytime configure is
       * called. */
      if (count != num_buffers) {
        GST_WARNING_OBJECT (pool, "using %u buffers instead of %u",
            count, num_buffers);
        num_buffers = count;
        copy_threshold =
            MAX (GST_V4L2_MIN_BUFFERS, obj->min_buffers_for_capture);

        /* Ensure GstBufferPool don't expect initial minimum */
        if (min_buffers > count)
          min_buffers = count;
Wim Taymans's avatar
Wim Taymans committed
441
      }
442

Wim Taymans's avatar
Wim Taymans committed
443 444 445
      break;
    }
    case GST_V4L2_IO_USERPTR:
446
    case GST_V4L2_IO_DMABUF_IMPORT:
Wim Taymans's avatar
Wim Taymans committed
447 448 449 450 451 452 453
    default:
      num_buffers = 0;
      copy_threshold = 0;
      g_assert_not_reached ();
      break;
  }

Wim Taymans's avatar
Wim Taymans committed
454
  pool->size = size;
Wim Taymans's avatar
Wim Taymans committed
455
  pool->copy_threshold = copy_threshold;
456 457 458
  pool->num_buffers = num_buffers;
  pool->num_allocated = 0;
  pool->num_queued = 0;
459

Wim Taymans's avatar
Wim Taymans committed
460 461
  gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
      max_buffers);
462
  GST_BUFFER_POOL_CLASS (parent_class)->set_config (bpool, config);
463
  gst_structure_free (config);
464 465 466 467 468 469 470 471 472 473 474

  /* now, allocate the buffers: */
  if (!GST_BUFFER_POOL_CLASS (parent_class)->start (bpool))
    goto start_failed;

  /* we can start capturing now, we wait for the playback case until we queued
   * the first buffer */
  if (!V4L2_TYPE_IS_OUTPUT (obj->type))
    if (!start_streaming (pool))
      goto start_failed;

475 476 477 478 479
  if (!V4L2_TYPE_IS_OUTPUT (obj->type))
    pool->group_released_handler =
        g_signal_connect_swapped (pool->vallocator, "group-released",
        G_CALLBACK (gst_v4l2_buffer_pool_group_released), pool);

480 481 482
  gst_poll_set_flushing (obj->poll, FALSE);

  return TRUE;
Rob Clark's avatar
Rob Clark committed
483

Wim Taymans's avatar
Wim Taymans committed
484
  /* ERRORS */
Wim Taymans's avatar
Wim Taymans committed
485 486
wrong_config:
  {
Wim Taymans's avatar
Wim Taymans committed
487
    GST_ERROR_OBJECT (pool, "invalid config %" GST_PTR_FORMAT, config);
Wim Taymans's avatar
Wim Taymans committed
488 489
    return FALSE;
  }
Wim Taymans's avatar
Wim Taymans committed
490 491 492
no_buffers:
  {
    GST_ERROR_OBJECT (pool,
493 494
        "we received %d buffer from device '%s', we want at least %d",
        num_buffers, obj->videodev, GST_V4L2_MIN_BUFFERS);
Wim Taymans's avatar
Wim Taymans committed
495 496
    return FALSE;
  }
Wim Taymans's avatar
Wim Taymans committed
497 498 499 500 501
start_failed:
  {
    GST_ERROR_OBJECT (pool, "failed to start streaming");
    return FALSE;
  }
Rob Clark's avatar
Rob Clark committed
502 503
}

504

505 506 507 508
static gboolean
stop_streaming (GstV4l2BufferPool * pool)
{
  GstV4l2Object *obj = pool->obj;
509
  gint i;
510 511 512 513 514

  GST_DEBUG_OBJECT (pool, "stopping stream");

  gst_poll_set_flushing (obj->poll, TRUE);

515 516 517 518 519 520 521
  if (!pool->streaming) {
    /* it avoid error: STREAMOFF 22 (Invalid argument) when
     * attempting to stop a stream not previously started */
    GST_DEBUG_OBJECT (pool, "no need to stop, was not previously started");
    return TRUE;
  }

522 523 524 525 526 527
  switch (obj->mode) {
    case GST_V4L2_IO_RW:
      break;
    case GST_V4L2_IO_MMAP:
    case GST_V4L2_IO_USERPTR:
    case GST_V4L2_IO_DMABUF:
528
    case GST_V4L2_IO_DMABUF_IMPORT:
529 530 531
      GST_DEBUG_OBJECT (pool, "STREAMOFF");
      if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0)
        goto stop_failed;
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552

      gst_v4l2_allocator_flush (pool->vallocator);

      for (i = 0; i < pool->num_allocated; i++) {
        if (pool->buffers[i]) {
          GstBufferPool *bpool = (GstBufferPool *) pool;
          GstBuffer *buffer = pool->buffers[i];

          pool->buffers[i] = NULL;
          pool->num_queued--;

          if (V4L2_TYPE_IS_OUTPUT (obj->type))
            gst_buffer_unref (buffer);
          else
            /* Give back the outstanding buffer to the pool */
            GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
                buffer);
        }
      }
      g_return_val_if_fail (pool->num_queued == 0, FALSE);

553 554
      break;
    default:
555
      g_return_val_if_reached (FALSE);
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
      break;
  }

  pool->streaming = FALSE;

  return TRUE;

  /* ERRORS */
stop_failed:
  {
    GST_ERROR_OBJECT (pool, "error with STREAMOFF %d (%s)", errno,
        g_strerror (errno));
    return FALSE;
  }
}

Wim Taymans's avatar
Wim Taymans committed
572 573
static gboolean
gst_v4l2_buffer_pool_stop (GstBufferPool * bpool)
Rob Clark's avatar
Rob Clark committed
574
{
Wim Taymans's avatar
Wim Taymans committed
575
  gboolean ret;
Wim Taymans's avatar
Wim Taymans committed
576
  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
Wim Taymans's avatar
Wim Taymans committed
577
  GstV4l2Object *obj = pool->obj;
Wim Taymans's avatar
Wim Taymans committed
578

Wim Taymans's avatar
Wim Taymans committed
579
  GST_DEBUG_OBJECT (pool, "stopping pool");
Rob Clark's avatar
Rob Clark committed
580

581 582 583 584
  if (pool->group_released_handler > 0) {
    g_signal_handler_disconnect (pool->vallocator,
        pool->group_released_handler);
    pool->group_released_handler = 0;
Wim Taymans's avatar
Wim Taymans committed
585 586
  }

587 588 589 590
  gst_poll_set_flushing (obj->poll, TRUE);
  if (!stop_streaming (pool))
    goto stop_failed;

Wim Taymans's avatar
Wim Taymans committed
591 592
  ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (bpool);

593 594 595 596
  if (ret) {
    GstV4l2Return vret;

    vret = gst_v4l2_allocator_stop (pool->vallocator);
597

598 599 600 601 602 603 604
    if (vret == GST_V4L2_BUSY) {
      GST_WARNING_OBJECT (pool, "allocated buffer need to be reclaimed");
      /* FIXME deal with reclaiming */
    } else if (vret == GST_V4L2_ERROR) {
      ret = FALSE;
    }
  }
605

Wim Taymans's avatar
Wim Taymans committed
606
  return ret;
Wim Taymans's avatar
Wim Taymans committed
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622

  /* ERRORS */
stop_failed:
  {
    GST_ERROR_OBJECT (pool, "error with STREAMOFF %d (%s)", errno,
        g_strerror (errno));
    return FALSE;
  }
}

static GstFlowReturn
gst_v4l2_object_poll (GstV4l2Object * v4l2object)
{
  gint ret;

  if (v4l2object->can_poll_device) {
623
    GST_LOG_OBJECT (v4l2object->element, "polling device");
Wim Taymans's avatar
Wim Taymans committed
624 625 626 627 628
    ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
    if (G_UNLIKELY (ret < 0)) {
      if (errno == EBUSY)
        goto stopped;
      if (errno == ENXIO) {
629
        GST_WARNING_OBJECT (v4l2object->element,
Wim Taymans's avatar
Wim Taymans committed
630 631 632 633 634 635 636 637 638 639 640 641 642 643
            "v4l2 device doesn't support polling. Disabling");
        v4l2object->can_poll_device = FALSE;
      } else {
        if (errno != EAGAIN && errno != EINTR)
          goto select_error;
      }
    }
  }
  return GST_FLOW_OK;

  /* ERRORS */
stopped:
  {
    GST_DEBUG ("stop called");
644
    return GST_FLOW_FLUSHING;
Wim Taymans's avatar
Wim Taymans committed
645 646 647 648 649 650 651 652 653 654
  }
select_error:
  {
    GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ, (NULL),
        ("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
    return GST_FLOW_ERROR;
  }
}

static GstFlowReturn
655
gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf)
Wim Taymans's avatar
Wim Taymans committed
656
{
657
  GstV4l2MemoryGroup *group = NULL;
Wim Taymans's avatar
Wim Taymans committed
658 659
  gint index;

660 661
  if (!gst_v4l2_is_buffer_valid (buf, &group)) {
    GST_LOG_OBJECT (pool, "unref copied/invalid buffer %p", buf);
Wim Taymans's avatar
Wim Taymans committed
662 663 664
    gst_buffer_unref (buf);
    return GST_FLOW_OK;
  }
Wim Taymans's avatar
Wim Taymans committed
665

666
  index = group->buffer.index;
Wim Taymans's avatar
Wim Taymans committed
667 668 669 670

  if (pool->buffers[index] != NULL)
    goto already_queued;

671 672 673
  GST_LOG_OBJECT (pool, "queuing buffer %i", index);

  if (!gst_v4l2_allocator_qbuf (pool->vallocator, group))
Wim Taymans's avatar
Wim Taymans committed
674 675 676 677 678 679 680 681 682
    goto queue_failed;

  pool->buffers[index] = buf;
  pool->num_queued++;

  return GST_FLOW_OK;

already_queued:
  {
683 684
    GST_ERROR_OBJECT (pool, "the buffer %i was already queued", index);
    gst_buffer_unref (buf);
Wim Taymans's avatar
Wim Taymans committed
685 686 687 688
    return GST_FLOW_ERROR;
  }
queue_failed:
  {
689 690 691 692
    GST_ERROR_OBJECT (pool, "could not queue a buffer %i", index);
    /* Return broken buffer to the allocator */
    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_TAG_MEMORY);
    gst_buffer_unref (buf);
Wim Taymans's avatar
Wim Taymans committed
693 694
    return GST_FLOW_ERROR;
  }
Rob Clark's avatar
Rob Clark committed
695 696
}

Wim Taymans's avatar
Wim Taymans committed
697
static GstFlowReturn
698
gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer)
Rob Clark's avatar
Rob Clark committed
699
{
Wim Taymans's avatar
Wim Taymans committed
700
  GstFlowReturn res;
Wim Taymans's avatar
Wim Taymans committed
701
  GstBuffer *outbuf;
702
  GstV4l2Object *obj = pool->obj;
Wim Taymans's avatar
Wim Taymans committed
703
  GstClockTime timestamp;
704
  GstV4l2MemoryGroup *group;
705
  gint i;
Rob Clark's avatar
Rob Clark committed
706

707
  if ((res = gst_v4l2_object_poll (obj)) != GST_FLOW_OK)
708
    goto poll_failed;
709

710 711 712 713 714
  GST_LOG_OBJECT (pool, "dequeueing a buffer");

  group = gst_v4l2_allocator_dqbuf (pool->vallocator);
  if (group == NULL)
    goto dqbuf_failed;
Rob Clark's avatar
Rob Clark committed
715

Wim Taymans's avatar
Wim Taymans committed
716 717 718
  /* get our GstBuffer with that index from the pool, if the buffer was
   * outstanding we have a serious problem.
   */
719
  outbuf = pool->buffers[group->buffer.index];
Wim Taymans's avatar
Wim Taymans committed
720
  if (outbuf == NULL)
721
    goto no_buffer;
Rob Clark's avatar
Rob Clark committed
722

Wim Taymans's avatar
Wim Taymans committed
723
  /* mark the buffer outstanding */
724
  pool->buffers[group->buffer.index] = NULL;
Wim Taymans's avatar
Wim Taymans committed
725
  pool->num_queued--;
Wim Taymans's avatar
Wim Taymans committed
726

727 728
  timestamp = GST_TIMEVAL_TO_TIME (group->buffer.timestamp);

729
#ifndef GST_DISABLE_GST_DEBUG
730
  for (i = 0; i < group->n_mem; i++) {
731
    GST_LOG_OBJECT (pool,
732 733
        "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,
734 735
        group->buffer.sequence, group->buffer.index, group->mem[i],
        group->planes[i].bytesused, i, group->buffer.flags,
736 737 738
        GST_TIME_ARGS (timestamp), pool->num_queued, outbuf);
  }
#endif
Rob Clark's avatar
Rob Clark committed
739

Wim Taymans's avatar
Wim Taymans committed
740
  /* set top/bottom field first if v4l2_buffer has the information */
741
  if (group->buffer.field == V4L2_FIELD_INTERLACED_TB) {
742
    GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
Wim Taymans's avatar
Wim Taymans committed
743
    GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
744
  } else if (group->buffer.field == V4L2_FIELD_INTERLACED_BT) {
745
    GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
Wim Taymans's avatar
Wim Taymans committed
746
    GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
747 748 749
  } else {
    GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
    GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
750
  }
751

752
  if (GST_VIDEO_INFO_FORMAT (&obj->info) == GST_VIDEO_FORMAT_ENCODED) {
753
    if (group->buffer.flags & V4L2_BUF_FLAG_KEYFRAME)
754 755 756 757
      GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
    else
      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
  }
Rob Clark's avatar
Rob Clark committed
758

Wim Taymans's avatar
Wim Taymans committed
759 760
  GST_BUFFER_TIMESTAMP (outbuf) = timestamp;

Wim Taymans's avatar
Wim Taymans committed
761
  *buffer = outbuf;
Rob Clark's avatar
Rob Clark committed
762

Wim Taymans's avatar
Wim Taymans committed
763
  return GST_FLOW_OK;
Rob Clark's avatar
Rob Clark committed
764

Wim Taymans's avatar
Wim Taymans committed
765
  /* ERRORS */
766
poll_failed:
Wim Taymans's avatar
Wim Taymans committed
767
  {
768
    GST_DEBUG_OBJECT (pool, "poll error %s", gst_flow_get_name (res));
Wim Taymans's avatar
Wim Taymans committed
769 770
    return res;
  }
771
dqbuf_failed:
Wim Taymans's avatar
Wim Taymans committed
772
  {
Wim Taymans's avatar
Wim Taymans committed
773
    return GST_FLOW_ERROR;
Wim Taymans's avatar
Wim Taymans committed
774
  }
775
no_buffer:
Wim Taymans's avatar
Wim Taymans committed
776
  {
777
    GST_ERROR_OBJECT (pool, "No free buffer found in the pool at index %d.",
778
        group->buffer.index);
Wim Taymans's avatar
Wim Taymans committed
779 780 781 782
    return GST_FLOW_ERROR;
  }
}

783 784
static GstFlowReturn
gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
Wim Taymans's avatar
Wim Taymans committed
785
    GstBufferPoolAcquireParams * params)
786 787
{
  GstFlowReturn ret;
Wim Taymans's avatar
Wim Taymans committed
788 789
  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
  GstV4l2Object *obj = pool->obj;
790 791 792 793 794 795

  GST_DEBUG_OBJECT (pool, "acquire");

  if (GST_BUFFER_POOL_IS_FLUSHING (bpool))
    goto flushing;

Wim Taymans's avatar
Wim Taymans committed
796 797
  switch (obj->type) {
    case V4L2_BUF_TYPE_VIDEO_CAPTURE:
798
    case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
Wim Taymans's avatar
Wim Taymans committed
799 800 801 802 803 804 805
      /* capture, This function should return a buffer with new captured data */
      switch (obj->mode) {
        case GST_V4L2_IO_RW:
          /* take empty buffer from the pool */
          ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
              buffer, params);
          break;
806
        case GST_V4L2_IO_DMABUF:
Wim Taymans's avatar
Wim Taymans committed
807
        case GST_V4L2_IO_MMAP:
808 809 810 811 812 813 814
          /* If this is being called to resurect a lost buffer */
          if (params && params->flags & GST_V4L2_POOL_ACQUIRE_FLAG_RESURECT) {
            ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
                buffer, params);
            break;
          }

Wim Taymans's avatar
Wim Taymans committed
815
          /* just dequeue a buffer, we basically use the queue of v4l2 as the
816 817
           * storage for our buffers. This function does poll first so we can
           * interrupt it fine. */
818
          ret = gst_v4l2_buffer_pool_dqbuf (pool, buffer);
Wim Taymans's avatar
Wim Taymans committed
819 820 821 822 823 824
          if (G_UNLIKELY (ret != GST_FLOW_OK))
            goto done;

          /* start copying buffers when we are running low on buffers */
          if (pool->num_queued < pool->copy_threshold) {
            GstBuffer *copy;
825

826
            if (GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP)) {
827 828 829 830 831 832
              if (GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
                      &copy, params) == GST_FLOW_OK) {
                gst_v4l2_buffer_pool_release_buffer (bpool, copy);
                break;
              }
            }
Wim Taymans's avatar
Wim Taymans committed
833

834 835 836
            /* copy the buffer */
            copy = gst_buffer_copy_region (*buffer,
                GST_BUFFER_COPY_ALL | GST_BUFFER_COPY_DEEP, 0, -1);
Wim Taymans's avatar
Wim Taymans committed
837 838 839 840 841 842
            GST_LOG_OBJECT (pool, "copy buffer %p->%p", *buffer, copy);

            /* and requeue so that we can continue capturing */
            ret = gst_v4l2_buffer_pool_qbuf (pool, *buffer);
            *buffer = copy;
          }
Wim Taymans's avatar
Wim Taymans committed
843 844 845
          break;

        case GST_V4L2_IO_USERPTR:
846
        case GST_V4L2_IO_DMABUF_IMPORT:
Wim Taymans's avatar
Wim Taymans committed
847
        default:
848
          ret = GST_FLOW_ERROR;
Wim Taymans's avatar
Wim Taymans committed
849 850 851 852 853 854
          g_assert_not_reached ();
          break;
      }
      break;

    case V4L2_BUF_TYPE_VIDEO_OUTPUT:
855
    case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
Wim Taymans's avatar
Wim Taymans committed
856 857 858 859 860 861 862 863 864
      /* playback, This function should return an empty buffer */
      switch (obj->mode) {
        case GST_V4L2_IO_RW:
          /* get an empty buffer */
          ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
              buffer, params);
          break;

        case GST_V4L2_IO_MMAP:
865
        case GST_V4L2_IO_DMABUF:
866
          /* get a free unqueued buffer */
Wim Taymans's avatar
Wim Taymans committed
867
          ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
868
              buffer, params);
Wim Taymans's avatar
Wim Taymans committed
869 870 871
          break;

        case GST_V4L2_IO_USERPTR:
872
        case GST_V4L2_IO_DMABUF_IMPORT:
Wim Taymans's avatar
Wim Taymans committed
873
        default:
874
          ret = GST_FLOW_ERROR;
Wim Taymans's avatar
Wim Taymans committed
875 876 877 878 879 880
          g_assert_not_reached ();
          break;
      }
      break;

    default:
881
      ret = GST_FLOW_ERROR;
Wim Taymans's avatar
Wim Taymans committed
882 883
      g_assert_not_reached ();
      break;
884
  }
Wim Taymans's avatar
Wim Taymans committed
885
done:
886 887 888 889 890
  return ret;

  /* ERRORS */
flushing:
  {
891
    GST_DEBUG_OBJECT (pool, "We are flushing");
892
    return GST_FLOW_FLUSHING;
893 894 895
  }
}

Wim Taymans's avatar
Wim Taymans committed
896 897 898 899
static void
gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
{
  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
Wim Taymans's avatar
Wim Taymans committed
900
  GstV4l2Object *obj = pool->obj;
Wim Taymans's avatar
Wim Taymans committed
901

902
  GST_DEBUG_OBJECT (pool, "release buffer %p", buffer);
Wim Taymans's avatar
Wim Taymans committed
903

Wim Taymans's avatar
Wim Taymans committed
904 905
  switch (obj->type) {
    case V4L2_BUF_TYPE_VIDEO_CAPTURE:
906
    case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
Wim Taymans's avatar
Wim Taymans committed
907 908 909 910 911 912 913 914
      /* capture, put the buffer back in the queue so that we can refill it
       * later. */
      switch (obj->mode) {
        case GST_V4L2_IO_RW:
          /* release back in the pool */
          GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer);
          break;

915
        case GST_V4L2_IO_DMABUF:
Wim Taymans's avatar
Wim Taymans committed
916
        case GST_V4L2_IO_MMAP:
917 918 919 920 921 922 923 924 925 926 927
        {
          if (gst_v4l2_is_buffer_valid (buffer, NULL)) {
            /* queue back in the device */
            gst_v4l2_buffer_pool_qbuf (pool, buffer);
          } else {
            /* Simply release invalide/modified buffer, the allocator will
             * give it back later */
            GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
            GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
                buffer);
          }
Wim Taymans's avatar
Wim Taymans committed
928
          break;
929
        }
Wim Taymans's avatar
Wim Taymans committed
930
        case GST_V4L2_IO_USERPTR:
931
        case GST_V4L2_IO_DMABUF_IMPORT:
Wim Taymans's avatar
Wim Taymans committed
932 933 934 935 936 937 938
        default:
          g_assert_not_reached ();
          break;
      }
      break;

    case V4L2_BUF_TYPE_VIDEO_OUTPUT:
939
    case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
940 941 942 943 944
      switch (obj->mode) {
        case GST_V4L2_IO_RW:
          /* release back in the pool */
          GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer);
          break;
945

946
        case GST_V4L2_IO_MMAP:
947
        case GST_V4L2_IO_DMABUF:
948
        {
949
          GstV4l2MemoryGroup *group;
Wim Taymans's avatar
Wim Taymans committed
950
          guint index;
951

952 953 954 955 956 957 958 959
          if (!gst_v4l2_is_buffer_valid (buffer, &group)) {
            /* Simply release invalide/modified buffer, the allocator will
             * give it back later */
            GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
            GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
                buffer);
            break;
          }
960

961
          index = group->buffer.index;
Wim Taymans's avatar
Wim Taymans committed
962 963 964 965

          if (pool->buffers[index] == NULL) {
            GST_LOG_OBJECT (pool, "buffer %u not queued, putting on free list",
                index);
966

967 968
            /* reset to default size */
            gst_v4l2_allocator_reset_size (pool->vallocator, group);
969

970 971 972 973 974 975 976
            /* playback, put the buffer back in the queue to refill later. */
            GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
                buffer);
          } else {
            /* the buffer is queued in the device but maybe not played yet. We just
             * leave it there and not make it available for future calls to acquire
             * for now. The buffer will be dequeued and reused later. */
Wim Taymans's avatar
Wim Taymans committed
977
            GST_LOG_OBJECT (pool, "buffer %u is queued", index);
978 979 980
          }
          break;
        }
981

982
        case GST_V4L2_IO_USERPTR:
983
        case GST_V4L2_IO_DMABUF_IMPORT:
984 985 986
        default:
          g_assert_not_reached ();
          break;
987
      }
Wim Taymans's avatar
Wim Taymans committed
988 989 990 991 992 993
      break;

    default:
      g_assert_not_reached ();
      break;
  }
Wim Taymans's avatar
Wim Taymans committed
994 995 996 997 998 999
}

static void
gst_v4l2_buffer_pool_finalize (GObject * object)
{
  GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (object);
1000
  gint i;
Wim Taymans's avatar
Wim Taymans committed
1001

1002 1003 1004 1005
  for (i = 0; i < VIDEO_MAX_FRAME; i++) {
    if (pool->buffers[i])
      gst_buffer_replace (&(pool->buffers[i]), NULL);
  }
1006

Wim Taymans's avatar
Wim Taymans committed
1007 1008
  if (pool->video_fd >= 0)
    v4l2_close (pool->video_fd);
1009 1010
  if (pool->vallocator)
    gst_object_unref (pool->vallocator);
Wim Taymans's avatar
Wim Taymans committed
1011
  if (pool->allocator)
Wim Taymans's avatar
Wim Taymans committed
1012
    gst_object_unref (pool->allocator);
Wim Taymans's avatar
Wim Taymans committed
1013

1014
  /* FIXME Is this required to keep around ? */
1015 1016
  gst_object_unref (pool->obj->element);

1017 1018
  /* FIXME have we done enough here ? */

Wim Taymans's avatar
Wim Taymans committed
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
gst_v4l2_buffer_pool_init (GstV4l2BufferPool * pool)
{
}

static void
gst_v4l2_buffer_pool_class_init (GstV4l2BufferPoolClass * klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GstBufferPoolClass *bufferpool_class = GST_BUFFER_POOL_CLASS (klass);

  object_class->finalize = gst_v4l2_buffer_pool_finalize;

  bufferpool_class->start = gst_v4l2_buffer_pool_start;
  bufferpool_class->stop = gst_v4l2_buffer_pool_stop;
  bufferpool_class->set_config = gst_v4l2_buffer_pool_set_config;
  bufferpool_class->alloc_buffer = gst_v4l2_buffer_pool_alloc_buffer;
  bufferpool_class->acquire_buffer = gst_v4l2_buffer_pool_acquire_buffer;
  bufferpool_class->release_buffer = gst_v4l2_buffer_pool_release_buffer;
}

/**
 * gst_v4l2_buffer_pool_new:
 * @obj:  the v4l2 object owning the pool
 *
 * Construct a new buffer pool.
 *
1049
 * Returns: the new pool, use gst_object_unref() to free resources
Wim Taymans's avatar
Wim Taymans committed
1050
 */
1051 1052
GstBufferPool *
gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
Wim Taymans's avatar
Wim Taymans committed
1053 1054
{
  GstV4l2BufferPool *pool;
1055
  GstStructure *config;
1056
  gchar *name, *parent_name;
1057
  gint fd;
Wim Taymans's avatar
Wim Taymans committed
1058

1059 1060
  fd = v4l2_dup (obj->video_fd);
  if (fd < 0)
Wim Taymans's avatar
Wim Taymans committed
1061 1062
    goto dup_failed;

1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
  /* setting a significant unique name */
  parent_name = gst_object_get_name (GST_OBJECT (obj->element));
  name = g_strconcat (parent_name, ":", "pool:",
      V4L2_TYPE_IS_OUTPUT (obj->type) ? "sink" : "src", NULL);
  g_free (parent_name);

  pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL,
      "name", name, NULL);
  g_free (name);

<