v4l2slh264dec: Add output format negotiation
[platform/upstream/gstreamer.git] / sys / v4l2codecs / gstv4l2decoder.c
1 /* GStreamer
2  * Copyright (C) 2020 Nicolas Dufresne <nicolas.dufresne@collabora.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include "gstv4l2codecallocator.h"
25 #include "gstv4l2codecpool.h"
26 #include "gstv4l2decoder.h"
27 #include "gstv4l2format.h"
28 #include "linux/media.h"
29 #include "linux/videodev2.h"
30
31 #include <fcntl.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35
36 GST_DEBUG_CATEGORY (v4l2_decoder_debug);
37 #define GST_CAT_DEFAULT v4l2_decoder_debug
38
39 enum
40 {
41   PROP_0,
42   PROP_MEDIA_DEVICE,
43   PROP_VIDEO_DEVICE,
44 };
45
46 struct _GstV4l2Request
47 {
48   GstV4l2Decoder *decoder;
49   gint fd;
50   GstMemory *bitstream;
51   GstPoll *poll;
52   GstPollFD pollfd;
53   gboolean pending;
54 };
55
56 struct _GstV4l2Decoder
57 {
58   GstObject parent;
59
60   gboolean opened;
61   gint media_fd;
62   gint video_fd;
63   GstAtomicQueue *request_pool;
64
65   /* properties */
66   gchar *media_device;
67   gchar *video_device;
68 };
69
70 G_DEFINE_TYPE_WITH_CODE (GstV4l2Decoder, gst_v4l2_decoder, GST_TYPE_OBJECT,
71     GST_DEBUG_CATEGORY_INIT (v4l2_decoder_debug, "v4l2codecs-decoder", 0,
72         "V4L2 stateless decoder helper"));
73
74 static guint32
75 direction_to_buffer_type (GstPadDirection direction)
76 {
77   if (direction == GST_PAD_SRC)
78     return V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
79   else
80     return V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
81 }
82
83 static void
84 gst_v4l2_decoder_finalize (GObject * obj)
85 {
86   GstV4l2Decoder *self = GST_V4L2_DECODER (obj);
87
88   gst_v4l2_decoder_close (self);
89
90   g_free (self->media_device);
91   g_free (self->video_device);
92   gst_atomic_queue_unref (self->request_pool);
93
94   G_OBJECT_CLASS (gst_v4l2_decoder_parent_class)->finalize (obj);
95 }
96
97 static void
98 gst_v4l2_decoder_init (GstV4l2Decoder * self)
99 {
100   self->request_pool = gst_atomic_queue_new (16);
101 }
102
103 static void
104 gst_v4l2_decoder_class_init (GstV4l2DecoderClass * klass)
105 {
106   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
107
108   gobject_class->finalize = gst_v4l2_decoder_finalize;
109   gobject_class->get_property = gst_v4l2_decoder_get_property;
110   gobject_class->set_property = gst_v4l2_decoder_set_property;
111
112   gst_v4l2_decoder_install_properties (gobject_class, 0, NULL);
113 }
114
115 GstV4l2Decoder *
116 gst_v4l2_decoder_new (GstV4l2CodecDevice * device)
117 {
118   GstV4l2Decoder *decoder;
119
120   g_return_val_if_fail (device->function == MEDIA_ENT_F_PROC_VIDEO_DECODER,
121       NULL);
122
123   decoder = g_object_new (GST_TYPE_V4L2_DECODER,
124       "media-device", device->media_device_path,
125       "video-device", device->video_device_path, NULL);
126
127   return gst_object_ref_sink (decoder);
128 }
129
130 gboolean
131 gst_v4l2_decoder_open (GstV4l2Decoder * self)
132 {
133   self->media_fd = open (self->media_device, 0);
134   if (self->media_fd < 0) {
135     GST_ERROR_OBJECT (self, "Failed to open '%s': %s",
136         self->media_device, g_strerror (errno));
137     return FALSE;
138   }
139
140   self->video_fd = open (self->video_device, O_NONBLOCK);
141   if (self->video_fd < 0) {
142     GST_ERROR_OBJECT (self, "Failed to open '%s': %s",
143         self->video_device, g_strerror (errno));
144     return FALSE;
145   }
146
147   self->opened = TRUE;
148
149   return TRUE;
150 }
151
152 gboolean
153 gst_v4l2_decoder_close (GstV4l2Decoder * self)
154 {
155   GstV4l2Request *request;
156
157   while ((request = gst_atomic_queue_pop (self->request_pool)))
158     gst_v4l2_request_free (request);
159
160   if (self->media_fd)
161     close (self->media_fd);
162   if (self->video_fd)
163     close (self->media_fd);
164
165   self->media_fd = 0;
166   self->video_fd = 0;
167   self->opened = FALSE;
168
169   return TRUE;
170 }
171
172 gboolean
173 gst_v4l2_decoder_streamon (GstV4l2Decoder * self, GstPadDirection direction)
174 {
175   gint ret;
176   guint32 type = direction_to_buffer_type (direction);
177
178   ret = ioctl (self->video_fd, VIDIOC_STREAMON, &type);
179   if (ret < 0) {
180     GST_ERROR_OBJECT (self, "VIDIOC_STREAMON failed: %s", g_strerror (errno));
181     return FALSE;
182   }
183
184   return TRUE;
185 }
186
187 gboolean
188 gst_v4l2_decoder_streamoff (GstV4l2Decoder * self, GstPadDirection direction)
189 {
190   gint ret;
191   guint32 type = direction_to_buffer_type (direction);
192
193   ret = ioctl (self->video_fd, VIDIOC_STREAMOFF, &type);
194   if (ret < 0) {
195     GST_ERROR_OBJECT (self, "VIDIOC_STREAMOFF failed: %s", g_strerror (errno));
196     return FALSE;
197   }
198
199   return TRUE;
200 }
201
202 gboolean
203 gst_v4l2_decoder_enum_sink_fmt (GstV4l2Decoder * self, gint i,
204     guint32 * out_fmt)
205 {
206   struct v4l2_fmtdesc fmtdesc = { i, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, };
207   gint ret;
208
209   g_return_val_if_fail (self->opened, FALSE);
210
211   ret = ioctl (self->video_fd, VIDIOC_ENUM_FMT, &fmtdesc);
212   if (ret < 0) {
213     if (errno != EINVAL)
214       GST_ERROR_OBJECT (self, "VIDIOC_ENUM_FMT failed: %s", g_strerror (errno));
215     return FALSE;
216   }
217
218   GST_DEBUG_OBJECT (self, "Found format %" GST_FOURCC_FORMAT " (%s)",
219       GST_FOURCC_ARGS (fmtdesc.pixelformat), fmtdesc.description);
220   *out_fmt = fmtdesc.pixelformat;
221
222   return TRUE;
223 }
224
225 gboolean
226 gst_v4l2_decoder_set_sink_fmt (GstV4l2Decoder * self, guint32 pix_fmt,
227     gint width, gint height)
228 {
229   struct v4l2_format format = (struct v4l2_format) {
230     .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
231     .fmt.pix_mp = (struct v4l2_pix_format_mplane) {
232           .pixelformat = pix_fmt,
233           .width = width,
234           .height = height,
235         },
236   };
237   gint ret;
238
239   ret = ioctl (self->video_fd, VIDIOC_S_FMT, &format);
240   if (ret < 0) {
241     GST_ERROR_OBJECT (self, "VIDIOC_S_FMT failed: %s", g_strerror (errno));
242     return FALSE;
243   }
244
245   if (format.fmt.pix_mp.pixelformat != pix_fmt
246       || format.fmt.pix_mp.width != width
247       || format.fmt.pix_mp.height != height) {
248     GST_WARNING_OBJECT (self, "Failed to set sink format to %"
249         GST_FOURCC_FORMAT " %ix%i", GST_FOURCC_ARGS (pix_fmt), width, height);
250     errno = EINVAL;
251     return FALSE;
252   }
253
254   return TRUE;
255 }
256
257 GstCaps *
258 gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self)
259 {
260   gint ret;
261   struct v4l2_format fmt = {
262     .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
263   };
264   GstVideoFormat format;
265   GstCaps *caps;
266   GValue list = G_VALUE_INIT;
267   GValue value = G_VALUE_INIT;
268   gint i;
269
270   g_return_val_if_fail (self->opened, FALSE);
271
272   ret = ioctl (self->video_fd, VIDIOC_G_FMT, &fmt);
273   if (ret < 0) {
274     GST_ERROR_OBJECT (self, "VIDIOC_G_FMT failed: %s", g_strerror (errno));
275     return FALSE;
276   }
277
278   /* We first place a structure with the default pixel format */
279   if (gst_v4l2_format_to_video_format (fmt.fmt.pix_mp.pixelformat, &format))
280     caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING,
281         gst_video_format_to_string (format), NULL);
282   else
283     caps = gst_caps_new_empty ();
284
285   /* And then enumerate other possible formats and place that as a second
286    * structure in the caps */
287   g_value_init (&list, GST_TYPE_LIST);
288   g_value_init (&value, G_TYPE_STRING);
289
290   for (i = 0; ret >= 0; i++) {
291     struct v4l2_fmtdesc fmtdesc = { i, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, };
292
293     ret = ioctl (self->video_fd, VIDIOC_ENUM_FMT, &fmtdesc);
294     if (ret < 0) {
295       if (errno != EINVAL)
296         GST_ERROR_OBJECT (self, "VIDIOC_ENUM_FMT failed: %s",
297             g_strerror (errno));
298       continue;
299     }
300
301     if (gst_v4l2_format_to_video_format (fmtdesc.pixelformat, &format)) {
302       g_value_set_static_string (&value, gst_video_format_to_string (format));
303       gst_value_list_append_value (&list, &value);
304     }
305   }
306   g_value_reset (&value);
307
308   if (gst_value_list_get_size (&list) > 0) {
309     GstStructure *str = gst_structure_new_empty ("video/x-raw");
310     gst_structure_take_value (str, "format", &list);
311     gst_caps_append_structure (caps, str);
312   } else {
313     g_value_reset (&list);
314   }
315
316   return caps;
317 }
318
319 gboolean
320 gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps,
321     GstVideoInfo * info)
322 {
323   gint ret;
324   struct v4l2_format fmt = {
325     .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
326   };
327   GstStructure *str;
328   const gchar *format_str;
329   GstVideoFormat format;
330   guint32 pix_fmt;
331
332   if (gst_caps_is_empty (caps))
333     return FALSE;
334
335   ret = ioctl (self->video_fd, VIDIOC_G_FMT, &fmt);
336   if (ret < 0) {
337     GST_ERROR_OBJECT (self, "VIDIOC_G_FMT failed: %s", g_strerror (errno));
338     return FALSE;
339   }
340
341   caps = gst_caps_make_writable (caps);
342   str = gst_caps_get_structure (caps, 0);
343   gst_structure_fixate_field (str, "format");
344
345   format_str = gst_structure_get_string (str, "format");
346   format = gst_video_format_from_string (format_str);
347
348   if (gst_v4l2_format_from_video_format (format, &pix_fmt) &&
349       pix_fmt != fmt.fmt.pix_mp.pixelformat) {
350     GST_DEBUG_OBJECT (self, "Trying to use peer format: %s ", format_str);
351     fmt.fmt.pix_mp.pixelformat = pix_fmt;
352
353     ret = ioctl (self->video_fd, VIDIOC_S_FMT, &fmt);
354     if (ret < 0) {
355       GST_ERROR_OBJECT (self, "VIDIOC_S_FMT failed: %s", g_strerror (errno));
356       return FALSE;
357     }
358   }
359
360   if (!gst_v4l2_format_to_video_info (&fmt, info)) {
361     GST_ERROR_OBJECT (self, "Unsupported V4L2 pixelformat %" GST_FOURCC_FORMAT,
362         GST_FOURCC_ARGS (fmt.fmt.pix_mp.pixelformat));
363     return FALSE;
364   }
365
366   GST_INFO_OBJECT (self, "Selected format %s %ix%i",
367       gst_video_format_to_string (info->finfo->format),
368       info->width, info->height);
369
370   return TRUE;
371 }
372
373 gint
374 gst_v4l2_decoder_request_buffers (GstV4l2Decoder * self,
375     GstPadDirection direction, guint num_buffers)
376 {
377   gint ret;
378   struct v4l2_requestbuffers reqbufs = {
379     .count = num_buffers,
380     .memory = V4L2_MEMORY_MMAP,
381     .type = direction_to_buffer_type (direction),
382   };
383
384   GST_DEBUG_OBJECT (self, "Requesting %u buffers", num_buffers);
385
386   ret = ioctl (self->video_fd, VIDIOC_REQBUFS, &reqbufs);
387   if (ret < 0) {
388     GST_ERROR_OBJECT (self, "VIDIOC_REQBUFS failed: %s", g_strerror (errno));
389     return ret;
390   }
391
392   return reqbufs.count;
393 }
394
395 gboolean
396 gst_v4l2_decoder_export_buffer (GstV4l2Decoder * self,
397     GstPadDirection direction, gint index, gint * fds, gsize * sizes,
398     gsize * offsets, guint * num_fds)
399 {
400   gint i, ret;
401   struct v4l2_plane planes[GST_VIDEO_MAX_PLANES] = { {0} };
402   struct v4l2_buffer v4l2_buf = {
403     .index = 0,
404     .type = direction_to_buffer_type (direction),
405     .length = GST_VIDEO_MAX_PLANES,
406     .m.planes = planes,
407   };
408
409   ret = ioctl (self->video_fd, VIDIOC_QUERYBUF, &v4l2_buf);
410   if (ret < 0) {
411     GST_ERROR_OBJECT (self, "VIDIOC_QUERYBUF failed: %s", g_strerror (errno));
412     return FALSE;
413   }
414
415   *num_fds = v4l2_buf.length;
416   for (i = 0; i < v4l2_buf.length; i++) {
417     struct v4l2_plane *plane = v4l2_buf.m.planes + i;
418     struct v4l2_exportbuffer expbuf = {
419       .type = direction_to_buffer_type (direction),
420       .index = index,
421       .plane = i,
422       .flags = O_CLOEXEC | O_RDWR,
423     };
424
425     ret = ioctl (self->video_fd, VIDIOC_EXPBUF, &expbuf);
426     if (ret < 0) {
427       gint j;
428       GST_ERROR_OBJECT (self, "VIDIOC_EXPBUF failed: %s", g_strerror (errno));
429
430       for (j = i - 1; j >= 0; j--)
431         close (fds[j]);
432
433       return FALSE;
434     }
435
436     fds[i] = expbuf.fd;
437     sizes[i] = plane->length;
438     offsets[i] = plane->data_offset;
439   }
440
441   return TRUE;
442 }
443
444 gboolean
445 gst_v4l2_decoder_queue_sink_mem (GstV4l2Decoder * self,
446     GstV4l2Request * request, GstMemory * mem, guint32 frame_num,
447     gsize bytesused)
448 {
449   gint ret;
450   struct v4l2_plane plane = {
451     .bytesused = bytesused,
452   };
453   struct v4l2_buffer buf = {
454     .type = direction_to_buffer_type (GST_PAD_SINK),
455     .memory = V4L2_MEMORY_MMAP,
456     .index = gst_v4l2_codec_memory_get_index (mem),
457     .timestamp.tv_usec = frame_num,
458     .request_fd = request->fd,
459     .flags = V4L2_BUF_FLAG_REQUEST_FD,
460     .length = 1,
461     .m.planes = &plane,
462   };
463
464   ret = ioctl (self->video_fd, VIDIOC_QBUF, &buf);
465   if (ret < 0) {
466     GST_ERROR_OBJECT (self, "VIDIOC_QBUF failed: %s", g_strerror (errno));
467     return FALSE;
468   }
469
470   request->bitstream = gst_memory_ref (mem);
471
472   return TRUE;
473 }
474
475 gboolean
476 gst_v4l2_decoder_queue_src_buffer (GstV4l2Decoder * self, GstBuffer * buffer,
477     guint32 frame_num)
478 {
479   gint i, ret;
480   struct v4l2_plane plane[GST_VIDEO_MAX_PLANES];
481   struct v4l2_buffer buf = {
482     .type = direction_to_buffer_type (GST_PAD_SRC),
483     .memory = V4L2_MEMORY_MMAP,
484     .index = gst_v4l2_codec_buffer_get_index (buffer),
485     .length = gst_buffer_n_memory (buffer),
486     .m.planes = plane,
487   };
488
489   for (i = 0; i < buf.length; i++) {
490     GstMemory *mem = gst_buffer_peek_memory (buffer, i);
491     /* *INDENT-OFF* */
492     plane[i] = (struct v4l2_plane) {
493       .bytesused = gst_memory_get_sizes (mem, NULL, NULL),
494     };
495     /* *INDENT-ON* */
496   }
497
498   ret = ioctl (self->video_fd, VIDIOC_QBUF, &buf);
499   if (ret < 0) {
500     GST_ERROR_OBJECT (self, "VIDIOC_QBUF failed: %s", g_strerror (errno));
501     return FALSE;
502   }
503
504   return TRUE;
505 }
506
507 gboolean
508 gst_v4l2_decoder_dequeue_sink (GstV4l2Decoder * self)
509 {
510   gint ret;
511   struct v4l2_plane plane[GST_VIDEO_MAX_PLANES] = { {0} };
512   struct v4l2_buffer buf = {
513     .type = direction_to_buffer_type (GST_PAD_SINK),
514     .memory = V4L2_MEMORY_MMAP,
515     .length = GST_VIDEO_MAX_PLANES,
516     .m.planes = plane,
517   };
518
519   ret = ioctl (self->video_fd, VIDIOC_DQBUF, &buf);
520   if (ret < 0) {
521     GST_ERROR_OBJECT (self, "VIDIOC_DQBUF failed: %s", g_strerror (errno));
522     return FALSE;
523   }
524
525   return TRUE;
526 }
527
528 gboolean
529 gst_v4l2_decoder_dequeue_src (GstV4l2Decoder * self, guint32 * out_frame_num)
530 {
531   gint ret;
532   struct v4l2_plane plane[GST_VIDEO_MAX_PLANES] = { {0} };
533   struct v4l2_buffer buf = {
534     .type = direction_to_buffer_type (GST_PAD_SRC),
535     .memory = V4L2_MEMORY_MMAP,
536     .length = GST_VIDEO_MAX_PLANES,
537     .m.planes = plane,
538   };
539
540   ret = ioctl (self->video_fd, VIDIOC_DQBUF, &buf);
541   if (ret < 0) {
542     GST_ERROR_OBJECT (self, "VIDIOC_DQBUF failed: %s", g_strerror (errno));
543     return FALSE;
544   }
545
546   *out_frame_num = buf.timestamp.tv_usec;
547   return TRUE;
548 }
549
550 gboolean
551 gst_v4l2_decoder_set_controls (GstV4l2Decoder * self, GstV4l2Request * request,
552     struct v4l2_ext_control * control, guint count)
553 {
554   gint ret;
555   struct v4l2_ext_controls controls = {
556     .controls = control,
557     .count = count,
558     .request_fd = request ? request->fd : 0,
559     .which = request ? V4L2_CTRL_WHICH_REQUEST_VAL : 0,
560   };
561
562   ret = ioctl (self->video_fd, VIDIOC_S_EXT_CTRLS, &controls);
563   if (ret < 0) {
564     GST_ERROR_OBJECT (self, "VIDIOC_S_EXT_CTRLS failed: %s",
565         g_strerror (errno));
566     return FALSE;
567   }
568
569   return TRUE;
570 }
571
572 void
573 gst_v4l2_decoder_install_properties (GObjectClass * gobject_class,
574     gint prop_offset, GstV4l2CodecDevice * device)
575 {
576   const gchar *media_device_path = NULL;
577   const gchar *video_device_path = NULL;
578
579   if (device) {
580     media_device_path = device->media_device_path;
581     video_device_path = device->video_device_path;
582   }
583
584   g_object_class_install_property (gobject_class, PROP_MEDIA_DEVICE,
585       g_param_spec_string ("media-device", "Media Device Path",
586           "Path to the media device node", media_device_path,
587           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
588
589   g_object_class_install_property (gobject_class, PROP_VIDEO_DEVICE,
590       g_param_spec_string ("video-device", "Video Device Path",
591           "Path to the video device node", video_device_path,
592           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
593 }
594
595 void
596 gst_v4l2_decoder_set_property (GObject * object, guint prop_id,
597     const GValue * value, GParamSpec * pspec)
598 {
599   GstV4l2Decoder *self = GST_V4L2_DECODER (object);
600
601   switch (prop_id) {
602     case PROP_MEDIA_DEVICE:
603       g_free (self->media_device);
604       self->media_device = g_value_dup_string (value);
605       break;
606     case PROP_VIDEO_DEVICE:
607       g_free (self->video_device);
608       self->video_device = g_value_dup_string (value);
609       break;
610     default:
611       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
612       break;
613   }
614 }
615
616 void
617 gst_v4l2_decoder_get_property (GObject * object, guint prop_id,
618     GValue * value, GParamSpec * pspec)
619 {
620   GstV4l2Decoder *self = GST_V4L2_DECODER (object);
621
622   switch (prop_id) {
623     case PROP_MEDIA_DEVICE:
624       g_value_set_string (value, self->media_device);
625       break;
626     case PROP_VIDEO_DEVICE:
627       g_value_set_string (value, self->video_device);
628       break;
629     default:
630       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
631       break;
632   }
633 }
634
635 GstV4l2Request *
636 gst_v4l2_decoder_alloc_request (GstV4l2Decoder * self)
637 {
638   GstV4l2Request *request = gst_atomic_queue_pop (self->request_pool);
639   gint ret;
640
641   if (!request) {
642     request = g_new0 (GstV4l2Request, 1);
643
644     ret = ioctl (self->media_fd, MEDIA_IOC_REQUEST_ALLOC, &request->fd);
645     if (ret < 0) {
646       GST_ERROR_OBJECT (self, "MEDIA_IOC_REQUEST_ALLOC failed: %s",
647           g_strerror (errno));
648       return NULL;
649     }
650
651     request->poll = gst_poll_new (FALSE);
652     gst_poll_fd_init (&request->pollfd);
653     request->pollfd.fd = request->fd;
654     gst_poll_add_fd (request->poll, &request->pollfd);
655     gst_poll_fd_ctl_pri (request->poll, &request->pollfd, TRUE);
656   }
657
658   request->decoder = g_object_ref (self);
659   return request;
660 }
661
662 void
663 gst_v4l2_request_free (GstV4l2Request * request)
664 {
665   GstV4l2Decoder *decoder = request->decoder;
666   gint ret;
667
668   if (!decoder) {
669     close (request->fd);
670     gst_poll_free (request->poll);
671     g_free (request);
672     return;
673   }
674
675   g_clear_pointer (&request->bitstream, gst_memory_unref);
676   request->decoder = NULL;
677
678   if (request->pending) {
679     gst_v4l2_request_free (request);
680     g_object_unref (decoder);
681     return;
682   }
683
684   ret = ioctl (request->fd, MEDIA_REQUEST_IOC_REINIT, NULL);
685   if (ret < 0) {
686     GST_ERROR_OBJECT (request->decoder, "MEDIA_REQUEST_IOC_REINIT failed: %s",
687         g_strerror (errno));
688     gst_v4l2_request_free (request);
689     g_object_unref (decoder);
690     return;
691   }
692
693   gst_atomic_queue_push (decoder->request_pool, request);
694   g_object_unref (decoder);
695 }
696
697 gboolean
698 gst_v4l2_request_queue (GstV4l2Request * request)
699 {
700   gint ret;
701
702   ret = ioctl (request->fd, MEDIA_REQUEST_IOC_QUEUE, NULL);
703   if (ret < 0) {
704     GST_ERROR_OBJECT (request->decoder, "MEDIA_REQUEST_IOC_QUEUE, failed: %s",
705         g_strerror (errno));
706     return FALSE;
707   }
708
709   request->pending = TRUE;
710
711   return TRUE;
712 }
713
714 gint
715 gst_v4l2_request_poll (GstV4l2Request * request, GstClockTime timeout)
716 {
717   return gst_poll_wait (request->poll, timeout);
718 }
719
720 void
721 gst_v4l2_request_set_done (GstV4l2Request * request)
722 {
723   if (request->bitstream) {
724     gst_v4l2_decoder_dequeue_sink (request->decoder);
725     g_clear_pointer (&request->bitstream, gst_memory_unref);
726   }
727
728   request->pending = FALSE;
729 }
730
731 gboolean
732 gst_v4l2_request_is_done (GstV4l2Request * request)
733 {
734   return !request->pending;
735 }