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