• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  *
4  * Copyright (C) 2012 Cisco Systems, Inc.
5  *   Author: Youness Alaoui <youness.alaoui@collabora.co.uk>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 
24 /**
25  * SECTION:element-uvch264src
26  * @title: uvch264src
27  *
28  * A camera bin src element that wraps v4l2src and implements UVC H264
29  * Extension Units (XU) to control the H264 encoder in the camera
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35 
36 #include "gstuvch264_src.h"
37 
38 enum
39 {
40   PROP_0,
41   /* uvch264_src properties */
42   PROP_COLORSPACE_NAME,
43   PROP_JPEG_DECODER_NAME,
44   PROP_NUM_CLOCK_SAMPLES,
45   /* v4l2src properties */
46   PROP_NUM_BUFFERS,
47   PROP_DEVICE,
48   PROP_DEVICE_NAME,
49   /* Static controls */
50   PROP_INITIAL_BITRATE,
51   PROP_SLICE_UNITS,
52   PROP_SLICE_MODE,
53   PROP_IFRAME_PERIOD,
54   PROP_USAGE_TYPE,
55   PROP_ENTROPY,
56   PROP_ENABLE_SEI,
57   PROP_NUM_REORDER_FRAMES,
58   PROP_PREVIEW_FLIPPED,
59   PROP_LEAKY_BUCKET_SIZE,
60   /* Dynamic controls */
61   PROP_RATE_CONTROL,
62   PROP_FIXED_FRAMERATE,
63   PROP_MAX_MBPS,                /* read-only */
64   PROP_LEVEL_IDC,
65   PROP_PEAK_BITRATE,
66   PROP_AVERAGE_BITRATE,
67   PROP_MIN_IFRAME_QP,
68   PROP_MAX_IFRAME_QP,
69   PROP_MIN_PFRAME_QP,
70   PROP_MAX_PFRAME_QP,
71   PROP_MIN_BFRAME_QP,
72   PROP_MAX_BFRAME_QP,
73   PROP_LTR_BUFFER_SIZE,
74   PROP_LTR_ENCODER_CONTROL,
75 };
76 /* In caps : frame interval (fps), width, height, profile, mux */
77 /* Ignored: temporal, spatial, SNR, MVC views, version, reset */
78 /* Events: LTR, generate IDR */
79 
80 enum
81 {
82   /* action signals */
83   SIGNAL_GET_ENUM_SETTING,
84   SIGNAL_GET_BOOLEAN_SETTING,
85   SIGNAL_GET_INT_SETTING,
86   LAST_SIGNAL
87 };
88 
89 static guint _signals[LAST_SIGNAL];
90 
91 /* Default values */
92 #define DEFAULT_COLORSPACE_NAME "videoconvert"
93 #define DEFAULT_JPEG_DECODER_NAME "jpegdec"
94 #define DEFAULT_NUM_CLOCK_SAMPLES 0
95 #define DEFAULT_NUM_BUFFERS -1
96 #define DEFAULT_DEVICE "/dev/video0"
97 #define DEFAULT_DEVICE_NAME NULL
98 #define DEFAULT_INITIAL_BITRATE 3000000
99 #define DEFAULT_SLICE_UNITS 4
100 #define DEFAULT_SLICE_MODE UVC_H264_SLICEMODE_SLICEPERFRAME
101 #define DEFAULT_IFRAME_PERIOD 10000
102 #define DEFAULT_USAGE_TYPE UVC_H264_USAGETYPE_REALTIME
103 #define DEFAULT_ENTROPY UVC_H264_ENTROPY_CAVLC
104 #define DEFAULT_ENABLE_SEI FALSE
105 #define DEFAULT_NUM_REORDER_FRAMES 0
106 #define DEFAULT_PREVIEW_FLIPPED FALSE
107 #define DEFAULT_LEAKY_BUCKET_SIZE 1000
108 #define DEFAULT_RATE_CONTROL UVC_H264_RATECONTROL_CBR
109 #define DEFAULT_FIXED_FRAMERATE FALSE
110 #define DEFAULT_LEVEL_IDC 40
111 #define DEFAULT_PEAK_BITRATE DEFAULT_INITIAL_BITRATE
112 #define DEFAULT_AVERAGE_BITRATE DEFAULT_INITIAL_BITRATE
113 #define DEFAULT_MIN_QP 10
114 #define DEFAULT_MAX_QP 46
115 #define DEFAULT_LTR_BUFFER_SIZE 0
116 #define DEFAULT_LTR_ENCODER_CONTROL 0
117 
118 #define NSEC_PER_SEC (G_USEC_PER_SEC * 1000)
119 
120 
121 GST_DEBUG_CATEGORY (uvc_h264_src_debug);
122 #define GST_CAT_DEFAULT uvc_h264_src_debug
123 
124 #define gst_uvc_h264_src_parent_class parent_class
125 G_DEFINE_TYPE (GstUvcH264Src, gst_uvc_h264_src, GST_TYPE_BASE_CAMERA_SRC);
126 GST_ELEMENT_REGISTER_DEFINE (uvch264src, "uvch264src", GST_RANK_NONE,
127     GST_TYPE_UVC_H264_SRC);
128 
129 #define GST_UVC_H264_SRC_VF_CAPS_STR \
130   GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ";" \
131   "image/jpeg,"                                   \
132   "width = " GST_VIDEO_SIZE_RANGE ","             \
133   "height = " GST_VIDEO_SIZE_RANGE ","            \
134   "framerate = " GST_VIDEO_FPS_RANGE
135 
136 #define GST_UVC_H264_SRC_VID_CAPS_STR                                   \
137   GST_UVC_H264_SRC_VF_CAPS_STR ";"                                      \
138   "video/x-h264, "                                                      \
139   "width = " GST_VIDEO_SIZE_RANGE ", "                                  \
140   "height = " GST_VIDEO_SIZE_RANGE ", "                                 \
141   "framerate = " GST_VIDEO_FPS_RANGE ", "                               \
142   "stream-format = (string) { byte-stream, avc }, "                     \
143   "alignment = (string) au, "                                           \
144   "profile = (string) { high, main, baseline, constrained-baseline }"
145 
146 /**
147  * GstUvcH264Src!vfsrc:
148  *
149  * The video src pad template
150  */
151 static GstStaticPadTemplate vfsrc_template =
152 GST_STATIC_PAD_TEMPLATE (GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME,
153     GST_PAD_SRC,
154     GST_PAD_ALWAYS,
155     GST_STATIC_CAPS (GST_UVC_H264_SRC_VF_CAPS_STR));
156 
157 static GstStaticPadTemplate imgsrc_template =
158 GST_STATIC_PAD_TEMPLATE (GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME,
159     GST_PAD_SRC,
160     GST_PAD_ALWAYS,
161     GST_STATIC_CAPS_NONE);
162 
163 static GstStaticPadTemplate vidsrc_template =
164 GST_STATIC_PAD_TEMPLATE (GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME,
165     GST_PAD_SRC,
166     GST_PAD_ALWAYS,
167     GST_STATIC_CAPS (GST_UVC_H264_SRC_VID_CAPS_STR));
168 
169 
170 static void gst_uvc_h264_src_dispose (GObject * object);
171 static void gst_uvc_h264_src_set_property (GObject * object,
172     guint prop_id, const GValue * value, GParamSpec * pspec);
173 static void gst_uvc_h264_src_get_property (GObject * object,
174     guint prop_id, GValue * value, GParamSpec * pspec);
175 static gboolean gst_uvc_h264_src_event (GstPad * pad, GstObject * parent,
176     GstEvent * event);
177 static gboolean gst_uvc_h264_src_send_event (GstElement * element,
178     GstEvent * event);
179 static gboolean gst_uvc_h264_src_construct_pipeline (GstBaseCameraSrc *
180     bcamsrc);
181 static gboolean gst_uvc_h264_src_set_mode (GstBaseCameraSrc * bcamsrc,
182     GstCameraBinMode mode);
183 static gboolean gst_uvc_h264_src_start_capture (GstBaseCameraSrc * camerasrc);
184 static void gst_uvc_h264_src_stop_capture (GstBaseCameraSrc * camerasrc);
185 static GstStateChangeReturn gst_uvc_h264_src_change_state (GstElement * element,
186     GstStateChange trans);
187 static GstPadProbeReturn gst_uvc_h264_src_buffer_probe (GstPad * pad,
188     GstPadProbeInfo * info, gpointer user_data);
189 static GstPadProbeReturn gst_uvc_h264_src_event_probe (GstPad * pad,
190     GstPadProbeInfo * info, gpointer user_data);
191 static void gst_uvc_h264_src_pad_linking_cb (GstPad * pad,
192     GstPad * peer, gpointer user_data);
193 static gboolean gst_uvc_h264_src_query (GstPad * pad, GstObject * parent,
194     GstQuery * query);
195 
196 
197 static void v4l2src_prepare_format (GstElement * v4l2src, gint fd,
198     GstCaps * caps, gpointer user_data);
199 static void fill_probe_commit (GstUvcH264Src * self,
200     uvcx_video_config_probe_commit_t * probe, guint32 frame_interval,
201     guint32 width, guint32 height, guint32 profile,
202     UvcH264StreamFormat stream_format);
203 static gboolean xu_query (GstUvcH264Src * self, guint selector, guint query,
204     guchar * data);
205 
206 static void set_rate_control (GstUvcH264Src * self);
207 static void set_level_idc (GstUvcH264Src * self);
208 static void set_bitrate (GstUvcH264Src * self);
209 static void set_qp (GstUvcH264Src * self, gint type);
210 static void set_ltr (GstUvcH264Src * self);
211 static void update_rate_control (GstUvcH264Src * self);
212 static guint32 update_level_idc_and_get_max_mbps (GstUvcH264Src * self);
213 static void update_bitrate (GstUvcH264Src * self);
214 static gboolean update_qp (GstUvcH264Src * self, gint type);
215 static void update_ltr (GstUvcH264Src * self);
216 
217 static gboolean gst_uvc_h264_src_get_enum_setting (GstUvcH264Src * self,
218     gchar * property, gint * mask, gint * default_value);
219 static gboolean gst_uvc_h264_src_get_boolean_setting (GstUvcH264Src * self,
220     gchar * property, gboolean * changeable, gboolean * def);
221 static gboolean gst_uvc_h264_src_get_int_setting (GstUvcH264Src * self,
222     gchar * property, gint * min, gint * def, gint * max);
223 
224 static void
gst_uvc_h264_src_class_init(GstUvcH264SrcClass * klass)225 gst_uvc_h264_src_class_init (GstUvcH264SrcClass * klass)
226 {
227   GObjectClass *gobject_class;
228   GstElementClass *gstelement_class;
229   GstBaseCameraSrcClass *gstbasecamerasrc_class;
230 
231   parent_class = g_type_class_peek_parent (klass);
232 
233   gobject_class = G_OBJECT_CLASS (klass);
234   gstelement_class = GST_ELEMENT_CLASS (klass);
235   gstbasecamerasrc_class = GST_BASE_CAMERA_SRC_CLASS (klass);
236 
237   gobject_class->dispose = gst_uvc_h264_src_dispose;
238   gobject_class->set_property = gst_uvc_h264_src_set_property;
239   gobject_class->get_property = gst_uvc_h264_src_get_property;
240 
241   gstelement_class->change_state = gst_uvc_h264_src_change_state;
242   gstelement_class->send_event = gst_uvc_h264_src_send_event;
243 
244   gstbasecamerasrc_class->construct_pipeline =
245       gst_uvc_h264_src_construct_pipeline;
246   gstbasecamerasrc_class->set_mode = gst_uvc_h264_src_set_mode;
247   gstbasecamerasrc_class->start_capture = gst_uvc_h264_src_start_capture;
248   gstbasecamerasrc_class->stop_capture = gst_uvc_h264_src_stop_capture;
249 
250   GST_DEBUG_CATEGORY_INIT (uvc_h264_src_debug, "uvch264src",
251       0, "UVC H264 Compliant camera bin source");
252 
253   gst_element_class_set_static_metadata (gstelement_class,
254       "UVC H264 Source",
255       "Source/Video",
256       "UVC H264 Encoding camera source",
257       "Youness Alaoui <youness.alaoui@collabora.co.uk>");
258 
259   gst_element_class_add_static_pad_template (gstelement_class,
260       &vidsrc_template);
261   gst_element_class_add_static_pad_template (gstelement_class,
262       &imgsrc_template);
263   gst_element_class_add_static_pad_template (gstelement_class, &vfsrc_template);
264 
265   /* Properties */
266   g_object_class_install_property (gobject_class, PROP_COLORSPACE_NAME,
267       g_param_spec_string ("colorspace-name", "colorspace element name",
268           "The name of the colorspace element",
269           DEFAULT_COLORSPACE_NAME, G_PARAM_CONSTRUCT | G_PARAM_READWRITE |
270           GST_PARAM_MUTABLE_READY | G_PARAM_STATIC_STRINGS));
271   g_object_class_install_property (gobject_class, PROP_JPEG_DECODER_NAME,
272       g_param_spec_string ("jpeg-decoder-name", "jpeg decoder element name",
273           "The name of the jpeg decoder element",
274           DEFAULT_JPEG_DECODER_NAME, G_PARAM_CONSTRUCT | G_PARAM_READWRITE |
275           GST_PARAM_MUTABLE_READY | G_PARAM_STATIC_STRINGS));
276 
277   g_object_class_install_property (gobject_class, PROP_NUM_CLOCK_SAMPLES,
278       g_param_spec_int ("num-clock-samples", "num-clock-samples",
279           "Number of clock samples to gather for the PTS synchronization"
280           " (-1 = unlimited)",
281           0, G_MAXINT, DEFAULT_NUM_CLOCK_SAMPLES,
282           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | GST_PARAM_MUTABLE_PLAYING |
283           G_PARAM_STATIC_STRINGS));
284 
285   /* v4l2src proxied properties */
286   g_object_class_install_property (gobject_class, PROP_NUM_BUFFERS,
287       g_param_spec_int ("num-buffers", "num-buffers",
288           "Number of buffers to output before sending EOS (-1 = unlimited)",
289           -1, G_MAXINT, DEFAULT_NUM_BUFFERS,
290           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
291   g_object_class_install_property (gobject_class, PROP_DEVICE,
292       g_param_spec_string ("device", "device",
293           "Device location",
294           DEFAULT_DEVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
295   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
296       g_param_spec_string ("device-name", "Device name",
297           "Name of the device", DEFAULT_DEVICE_NAME,
298           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
299 
300   /* Static controls */
301   g_object_class_install_property (gobject_class, PROP_INITIAL_BITRATE,
302       g_param_spec_uint ("initial-bitrate", "Initial bitrate",
303           "Initial bitrate in bits/second (static control)",
304           0, G_MAXUINT, DEFAULT_INITIAL_BITRATE,
305           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
306           GST_PARAM_MUTABLE_READY));
307   g_object_class_install_property (gobject_class, PROP_SLICE_UNITS,
308       g_param_spec_uint ("slice-units", "Slice units",
309           "Slice units (static control)",
310           0, G_MAXUINT16, DEFAULT_SLICE_UNITS,
311           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
312           GST_PARAM_MUTABLE_READY));
313   g_object_class_install_property (gobject_class, PROP_SLICE_MODE,
314       g_param_spec_enum ("slice-mode", "Slice mode",
315           "Defines the unit of the slice-units property (static control)",
316           UVC_H264_SLICEMODE_TYPE,
317           DEFAULT_SLICE_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
318           GST_PARAM_MUTABLE_READY));
319   g_object_class_install_property (gobject_class, PROP_IFRAME_PERIOD,
320       g_param_spec_uint ("iframe-period", "I Frame Period",
321           "Time between IDR frames in milliseconds (static control)",
322           0, G_MAXUINT16, DEFAULT_IFRAME_PERIOD,
323           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
324           GST_PARAM_MUTABLE_READY));
325   g_object_class_install_property (gobject_class, PROP_USAGE_TYPE,
326       g_param_spec_enum ("usage-type", "Usage type",
327           "The usage type (static control)",
328           UVC_H264_USAGETYPE_TYPE, DEFAULT_USAGE_TYPE,
329           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
330           GST_PARAM_MUTABLE_READY));
331   g_object_class_install_property (gobject_class, PROP_ENTROPY,
332       g_param_spec_enum ("entropy", "Entropy",
333           "Entropy (static control)",
334           UVC_H264_ENTROPY_TYPE, DEFAULT_ENTROPY,
335           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
336           GST_PARAM_MUTABLE_READY));
337   g_object_class_install_property (gobject_class, PROP_ENABLE_SEI,
338       g_param_spec_boolean ("enable-sei", "Enable SEI",
339           "Enable SEI picture timing (static control)",
340           DEFAULT_ENABLE_SEI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
341           GST_PARAM_MUTABLE_READY));
342   g_object_class_install_property (gobject_class, PROP_NUM_REORDER_FRAMES,
343       g_param_spec_uint ("num-reorder-frames", "Number of Reorder frames",
344           "Number of B frames between the references frames (static control)",
345           0, G_MAXUINT8, DEFAULT_NUM_REORDER_FRAMES,
346           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
347           GST_PARAM_MUTABLE_READY));
348   g_object_class_install_property (gobject_class, PROP_PREVIEW_FLIPPED,
349       g_param_spec_boolean ("preview-flipped", "Flip preview",
350           "Horizontal flipped image for non H.264 streams (static control)",
351           DEFAULT_PREVIEW_FLIPPED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
352           GST_PARAM_MUTABLE_READY));
353   g_object_class_install_property (gobject_class, PROP_LEAKY_BUCKET_SIZE,
354       g_param_spec_uint ("leaky-bucket-size", "Size of the leaky bucket size",
355           "Size of the leaky bucket size in milliseconds (static control)",
356           0, G_MAXUINT16, DEFAULT_LEAKY_BUCKET_SIZE,
357           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
358           GST_PARAM_MUTABLE_READY));
359 
360   /* Dynamic controls */
361   g_object_class_install_property (gobject_class, PROP_RATE_CONTROL,
362       g_param_spec_enum ("rate-control", "Rate control",
363           "Rate control mode (static & dynamic control)",
364           UVC_H264_RATECONTROL_TYPE, DEFAULT_RATE_CONTROL,
365           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
366           GST_PARAM_MUTABLE_PLAYING));
367   g_object_class_install_property (gobject_class, PROP_FIXED_FRAMERATE,
368       g_param_spec_boolean ("fixed-framerate", "Fixed framerate",
369           "Fixed framerate (static & dynamic control)",
370           DEFAULT_FIXED_FRAMERATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
371           GST_PARAM_MUTABLE_PLAYING));
372   g_object_class_install_property (gobject_class, PROP_MAX_MBPS,
373       g_param_spec_uint ("max-mbps", "Max macroblocks/second",
374           "The number of macroblocks per second for the maximum processing rate",
375           0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
376   g_object_class_install_property (gobject_class, PROP_LEVEL_IDC,
377       g_param_spec_uint ("level-idc", "Level IDC",
378           "Level IDC (dynamic control)",
379           0, G_MAXUINT8, DEFAULT_LEVEL_IDC,
380           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
381           GST_PARAM_MUTABLE_PLAYING));
382   g_object_class_install_property (gobject_class, PROP_PEAK_BITRATE,
383       g_param_spec_uint ("peak-bitrate", "Peak bitrate",
384           "The peak bitrate in bits/second (dynamic control)",
385           0, G_MAXUINT, DEFAULT_PEAK_BITRATE,
386           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
387           GST_PARAM_MUTABLE_PLAYING));
388   g_object_class_install_property (gobject_class, PROP_AVERAGE_BITRATE,
389       g_param_spec_uint ("average-bitrate", "Average bitrate",
390           "The average bitrate in bits/second (dynamic control)",
391           0, G_MAXUINT, DEFAULT_AVERAGE_BITRATE,
392           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
393           GST_PARAM_MUTABLE_PLAYING));
394   g_object_class_install_property (gobject_class, PROP_MIN_IFRAME_QP,
395       g_param_spec_int ("min-iframe-qp", "Minimum I frame QP",
396           "The minimum Quantization step size for I frames (dynamic control)",
397           -G_MAXINT8, G_MAXINT8, DEFAULT_MIN_QP,
398           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
399           GST_PARAM_MUTABLE_PLAYING));
400   g_object_class_install_property (gobject_class, PROP_MAX_IFRAME_QP,
401       g_param_spec_int ("max-iframe-qp", "Minimum I frame QP",
402           "The minimum Quantization step size for I frames (dynamic control)",
403           -G_MAXINT8, G_MAXINT8, DEFAULT_MAX_QP,
404           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
405           GST_PARAM_MUTABLE_PLAYING));
406   g_object_class_install_property (gobject_class, PROP_MIN_PFRAME_QP,
407       g_param_spec_int ("min-pframe-qp", "Minimum P frame QP",
408           "The minimum Quantization step size for P frames (dynamic control)",
409           -G_MAXINT8, G_MAXINT8, DEFAULT_MIN_QP,
410           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
411           GST_PARAM_MUTABLE_PLAYING));
412   g_object_class_install_property (gobject_class, PROP_MAX_PFRAME_QP,
413       g_param_spec_int ("max-pframe-qp", "Minimum P frame QP",
414           "The minimum Quantization step size for P frames (dynamic control)",
415           -G_MAXINT8, G_MAXINT8, DEFAULT_MAX_QP,
416           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
417           GST_PARAM_MUTABLE_PLAYING));
418   g_object_class_install_property (gobject_class, PROP_MIN_BFRAME_QP,
419       g_param_spec_int ("min-bframe-qp", "Minimum B frame QP",
420           "The minimum Quantization step size for B frames (dynamic control)",
421           -G_MAXINT8, G_MAXINT8, DEFAULT_MIN_QP,
422           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
423           GST_PARAM_MUTABLE_PLAYING));
424   g_object_class_install_property (gobject_class, PROP_MAX_BFRAME_QP,
425       g_param_spec_int ("max-bframe-qp", "Minimum B frame QP",
426           "The minimum Quantization step size for B frames (dynamic control)",
427           -G_MAXINT8, G_MAXINT8, DEFAULT_MAX_QP,
428           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
429           GST_PARAM_MUTABLE_PLAYING));
430   g_object_class_install_property (gobject_class, PROP_LTR_BUFFER_SIZE,
431       g_param_spec_int ("ltr-buffer-size", "LTR Buffer size",
432           "Total number of Long-Term Reference frames (dynamic control)",
433           0, G_MAXUINT8, DEFAULT_LTR_BUFFER_SIZE,
434           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
435           GST_PARAM_MUTABLE_PLAYING));
436   g_object_class_install_property (gobject_class, PROP_LTR_ENCODER_CONTROL,
437       g_param_spec_int ("ltr-encoder-control",
438           "LTR frames controlled by device",
439           "Number of LTR frames the device can control (dynamic control)", 0,
440           G_MAXUINT8, DEFAULT_LTR_ENCODER_CONTROL,
441           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
442           GST_PARAM_MUTABLE_PLAYING));
443 
444   _signals[SIGNAL_GET_ENUM_SETTING] =
445       g_signal_new_class_handler ("get-enum-setting",
446       G_TYPE_FROM_CLASS (klass),
447       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
448       G_CALLBACK (gst_uvc_h264_src_get_enum_setting),
449       NULL, NULL, NULL,
450       G_TYPE_BOOLEAN, 3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, 0);
451   _signals[SIGNAL_GET_BOOLEAN_SETTING] =
452       g_signal_new_class_handler ("get-boolean-setting",
453       G_TYPE_FROM_CLASS (klass),
454       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
455       G_CALLBACK (gst_uvc_h264_src_get_boolean_setting), NULL, NULL, NULL,
456       G_TYPE_BOOLEAN, 3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, 0);
457   _signals[SIGNAL_GET_INT_SETTING] =
458       g_signal_new_class_handler ("get-int-setting",
459       G_TYPE_FROM_CLASS (klass),
460       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
461       G_CALLBACK (gst_uvc_h264_src_get_int_setting), NULL, NULL, NULL,
462       G_TYPE_BOOLEAN, 4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER,
463       G_TYPE_POINTER, 0);
464 
465   gst_type_mark_as_plugin_api (UVC_H264_ENTROPY_TYPE, 0);
466   gst_type_mark_as_plugin_api (UVC_H264_RATECONTROL_TYPE, 0);
467   gst_type_mark_as_plugin_api (UVC_H264_SLICEMODE_TYPE, 0);
468   gst_type_mark_as_plugin_api (UVC_H264_USAGETYPE_TYPE, 0);
469 }
470 
471 static void
gst_uvc_h264_src_init(GstUvcH264Src * self)472 gst_uvc_h264_src_init (GstUvcH264Src * self)
473 {
474   self->vfsrc =
475       gst_ghost_pad_new_no_target (GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME,
476       GST_PAD_SRC);
477   gst_pad_set_query_function (self->vfsrc,
478       GST_DEBUG_FUNCPTR (gst_uvc_h264_src_query));
479   gst_element_add_pad (GST_ELEMENT (self), self->vfsrc);
480 
481   self->imgsrc =
482       gst_ghost_pad_new_no_target (GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME,
483       GST_PAD_SRC);
484   gst_element_add_pad (GST_ELEMENT (self), self->imgsrc);
485 
486   self->vidsrc =
487       gst_ghost_pad_new_no_target (GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME,
488       GST_PAD_SRC);
489   gst_pad_set_query_function (self->vidsrc,
490       GST_DEBUG_FUNCPTR (gst_uvc_h264_src_query));
491   gst_element_add_pad (GST_ELEMENT (self), self->vidsrc);
492   gst_pad_add_probe (self->vidsrc, GST_PAD_PROBE_TYPE_BUFFER,
493       gst_uvc_h264_src_buffer_probe, self, NULL);
494   gst_pad_add_probe (self->vfsrc, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM,
495       gst_uvc_h264_src_event_probe, self, NULL);
496   gst_pad_add_probe (self->vidsrc,
497       GST_PAD_PROBE_TYPE_EVENT_UPSTREAM | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
498       gst_uvc_h264_src_event_probe, self, NULL);
499 
500   self->srcpad_event_func = GST_PAD_EVENTFUNC (self->vfsrc);
501 
502   gst_pad_set_event_function (self->imgsrc, gst_uvc_h264_src_event);
503   gst_pad_set_event_function (self->vidsrc, gst_uvc_h264_src_event);
504   gst_pad_set_event_function (self->vfsrc, gst_uvc_h264_src_event);
505 
506   g_signal_connect (self->vidsrc, "linked",
507       (GCallback) gst_uvc_h264_src_pad_linking_cb, self);
508   g_signal_connect (self->vidsrc, "unlinked",
509       (GCallback) gst_uvc_h264_src_pad_linking_cb, self);
510   g_signal_connect (self->vfsrc, "linked",
511       (GCallback) gst_uvc_h264_src_pad_linking_cb, self);
512   g_signal_connect (self->vfsrc, "unlinked",
513       (GCallback) gst_uvc_h264_src_pad_linking_cb, self);
514 
515   self->v4l2_fd = -1;
516   gst_base_camera_src_set_mode (GST_BASE_CAMERA_SRC (self), MODE_VIDEO);
517 
518   self->main_format = UVC_H264_SRC_FORMAT_NONE;
519   self->main_width = 0;
520   self->main_height = 0;
521   self->main_frame_interval = 0;
522   self->main_stream_format = UVC_H264_STREAMFORMAT_ANNEXB;
523   self->main_profile = UVC_H264_PROFILE_CONSTRAINED_BASELINE;
524   self->secondary_format = UVC_H264_SRC_FORMAT_NONE;
525   self->secondary_width = 0;
526   self->secondary_height = 0;
527   self->secondary_frame_interval = 0;
528 
529   /* v4l2src properties */
530   self->num_buffers = DEFAULT_NUM_BUFFERS;
531   self->device = g_strdup (DEFAULT_DEVICE);
532 
533   /* Static controls */
534   self->initial_bitrate = DEFAULT_INITIAL_BITRATE;
535   self->slice_units = DEFAULT_SLICE_UNITS;
536   self->slice_mode = DEFAULT_SLICE_MODE;
537   self->iframe_period = DEFAULT_IFRAME_PERIOD;
538   self->usage_type = DEFAULT_USAGE_TYPE;
539   self->entropy = DEFAULT_ENTROPY;
540   self->enable_sei = DEFAULT_ENABLE_SEI;
541   self->num_reorder_frames = DEFAULT_NUM_REORDER_FRAMES;
542   self->preview_flipped = DEFAULT_PREVIEW_FLIPPED;
543   self->leaky_bucket_size = DEFAULT_LEAKY_BUCKET_SIZE;
544 
545   /* Dynamic controls */
546   self->rate_control = DEFAULT_RATE_CONTROL;
547   self->fixed_framerate = DEFAULT_FIXED_FRAMERATE;
548   self->level_idc = DEFAULT_LEVEL_IDC;
549   self->peak_bitrate = DEFAULT_PEAK_BITRATE;
550   self->average_bitrate = DEFAULT_AVERAGE_BITRATE;
551   self->min_qp[QP_I_FRAME] = DEFAULT_MIN_QP;
552   self->max_qp[QP_I_FRAME] = DEFAULT_MAX_QP;
553   self->min_qp[QP_P_FRAME] = DEFAULT_MIN_QP;
554   self->max_qp[QP_P_FRAME] = DEFAULT_MAX_QP;
555   self->min_qp[QP_B_FRAME] = DEFAULT_MIN_QP;
556   self->max_qp[QP_B_FRAME] = DEFAULT_MAX_QP;
557   self->ltr_buffer_size = DEFAULT_LTR_BUFFER_SIZE;
558   self->ltr_encoder_control = DEFAULT_LTR_ENCODER_CONTROL;
559 }
560 
561 static void
gst_uvc_h264_src_dispose(GObject * object)562 gst_uvc_h264_src_dispose (GObject * object)
563 {
564   GstUvcH264Src *self = GST_UVC_H264_SRC (object);
565 
566   if (self->usb_ctx)
567     libusb_exit (self->usb_ctx);
568   self->usb_ctx = NULL;
569   g_free (self->jpeg_decoder_name);
570   self->jpeg_decoder_name = NULL;
571   g_free (self->colorspace_name);
572   self->colorspace_name = NULL;
573   g_free (self->device);
574   self->device = NULL;
575 
576   G_OBJECT_CLASS (parent_class)->dispose (object);
577 }
578 
579 static void
gst_uvc_h264_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)580 gst_uvc_h264_src_set_property (GObject * object,
581     guint prop_id, const GValue * value, GParamSpec * pspec)
582 {
583   GstUvcH264Src *self = GST_UVC_H264_SRC (object);
584 
585   switch (prop_id) {
586     case PROP_COLORSPACE_NAME:
587       g_free (self->colorspace_name);
588       self->colorspace_name = g_value_dup_string (value);
589       break;
590     case PROP_JPEG_DECODER_NAME:
591       g_free (self->jpeg_decoder_name);
592       self->jpeg_decoder_name = g_value_dup_string (value);
593       break;
594     case PROP_NUM_CLOCK_SAMPLES:
595       self->num_clock_samples = g_value_get_int (value);
596       if (self->mjpg_demux)
597         g_object_set (self->mjpg_demux,
598             "num-clock-samples", self->num_clock_samples, NULL);
599       break;
600       /* v4l2 properties */
601     case PROP_NUM_BUFFERS:
602       self->num_buffers = g_value_get_int (value);
603       if (self->v4l2_src)
604         g_object_set_property (G_OBJECT (self->v4l2_src), "num-buffers", value);
605       break;
606     case PROP_DEVICE:
607       g_free (self->device);
608       self->device = g_value_dup_string (value);
609       if (self->v4l2_src)
610         g_object_set_property (G_OBJECT (self->v4l2_src), "device", value);
611       break;
612       /* Static controls */
613     case PROP_INITIAL_BITRATE:
614       self->initial_bitrate = g_value_get_uint (value);
615       break;
616     case PROP_SLICE_UNITS:
617       self->slice_units = g_value_get_uint (value);
618       break;
619     case PROP_SLICE_MODE:
620       self->slice_mode = g_value_get_enum (value);
621       break;
622     case PROP_IFRAME_PERIOD:
623       self->iframe_period = g_value_get_uint (value);
624       break;
625     case PROP_USAGE_TYPE:
626       self->usage_type = g_value_get_enum (value);
627       break;
628     case PROP_ENTROPY:
629       self->entropy = g_value_get_enum (value);
630       break;
631     case PROP_ENABLE_SEI:
632       self->enable_sei = g_value_get_boolean (value);
633       break;
634     case PROP_NUM_REORDER_FRAMES:
635       self->num_reorder_frames = g_value_get_uint (value);
636       break;
637     case PROP_PREVIEW_FLIPPED:
638       self->preview_flipped = g_value_get_boolean (value);
639       break;
640     case PROP_LEAKY_BUCKET_SIZE:
641       self->leaky_bucket_size = g_value_get_uint (value);
642       break;
643 
644 
645       /* Dynamic controls */
646     case PROP_RATE_CONTROL:
647       self->rate_control = g_value_get_enum (value);
648       set_rate_control (self);
649       update_rate_control (self);
650       break;
651     case PROP_FIXED_FRAMERATE:
652       self->fixed_framerate = g_value_get_boolean (value);
653       set_rate_control (self);
654       update_rate_control (self);
655       break;
656     case PROP_LEVEL_IDC:
657       self->level_idc = g_value_get_uint (value);
658       set_level_idc (self);
659       update_level_idc_and_get_max_mbps (self);
660       break;
661     case PROP_PEAK_BITRATE:
662       self->peak_bitrate = g_value_get_uint (value);
663       set_bitrate (self);
664       update_bitrate (self);
665       break;
666     case PROP_AVERAGE_BITRATE:
667       self->average_bitrate = g_value_get_uint (value);
668       set_bitrate (self);
669       update_bitrate (self);
670       break;
671     case PROP_MIN_IFRAME_QP:
672       self->min_qp[QP_I_FRAME] = g_value_get_int (value);
673       set_qp (self, QP_I_FRAME);
674       update_qp (self, QP_I_FRAME);
675       break;
676     case PROP_MAX_IFRAME_QP:
677       self->max_qp[QP_I_FRAME] = g_value_get_int (value);
678       set_qp (self, QP_I_FRAME);
679       update_qp (self, QP_I_FRAME);
680       break;
681     case PROP_MIN_PFRAME_QP:
682       self->min_qp[QP_P_FRAME] = g_value_get_int (value);
683       set_qp (self, QP_P_FRAME);
684       update_qp (self, QP_P_FRAME);
685       break;
686     case PROP_MAX_PFRAME_QP:
687       self->max_qp[QP_P_FRAME] = g_value_get_int (value);
688       set_qp (self, QP_P_FRAME);
689       update_qp (self, QP_P_FRAME);
690       break;
691     case PROP_MIN_BFRAME_QP:
692       self->min_qp[QP_B_FRAME] = g_value_get_int (value);
693       set_qp (self, QP_B_FRAME);
694       update_qp (self, QP_B_FRAME);
695       break;
696     case PROP_MAX_BFRAME_QP:
697       self->max_qp[QP_B_FRAME] = g_value_get_int (value);
698       set_qp (self, QP_B_FRAME);
699       update_qp (self, QP_B_FRAME);
700       break;
701     case PROP_LTR_BUFFER_SIZE:
702       self->ltr_buffer_size = g_value_get_int (value);
703       set_ltr (self);
704       update_ltr (self);
705       break;
706     case PROP_LTR_ENCODER_CONTROL:
707       self->ltr_encoder_control = g_value_get_int (value);
708       set_ltr (self);
709       update_ltr (self);
710       break;
711     default:
712       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
713       break;
714   }
715 }
716 
717 static void
gst_uvc_h264_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)718 gst_uvc_h264_src_get_property (GObject * object,
719     guint prop_id, GValue * value, GParamSpec * pspec)
720 {
721   GstUvcH264Src *self = GST_UVC_H264_SRC (object);
722   uvcx_video_config_probe_commit_t probe;
723 
724   switch (prop_id) {
725     case PROP_INITIAL_BITRATE:
726     case PROP_SLICE_UNITS:
727     case PROP_SLICE_MODE:
728     case PROP_IFRAME_PERIOD:
729     case PROP_USAGE_TYPE:
730     case PROP_ENTROPY:
731     case PROP_ENABLE_SEI:
732     case PROP_NUM_REORDER_FRAMES:
733     case PROP_PREVIEW_FLIPPED:
734     case PROP_LEAKY_BUCKET_SIZE:
735       fill_probe_commit (self, &probe, 0, 0, 0, 0, 0);
736       if (GST_STATE (self) >= GST_STATE_PAUSED) {
737         if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_GET_CUR,
738                 (guchar *) & probe))
739           GST_WARNING_OBJECT (self, "probe_setting GET_CUR error");
740       }
741       break;
742     default:
743       break;
744   }
745 
746   switch (prop_id) {
747     case PROP_COLORSPACE_NAME:
748       g_value_set_string (value, self->colorspace_name);
749       break;
750     case PROP_JPEG_DECODER_NAME:
751       g_value_set_string (value, self->jpeg_decoder_name);
752       break;
753     case PROP_NUM_CLOCK_SAMPLES:
754       g_value_set_int (value, self->num_clock_samples);
755       break;
756       /* v4l2src properties */
757     case PROP_NUM_BUFFERS:
758       g_value_set_int (value, self->num_buffers);
759       break;
760     case PROP_DEVICE:
761       g_value_set_string (value, self->device);
762       break;
763     case PROP_DEVICE_NAME:
764       if (self->v4l2_src)
765         g_object_get_property (G_OBJECT (self->v4l2_src), "device-name", value);
766       else
767         g_value_set_static_string (value, "");
768       break;
769       /* Static controls */
770     case PROP_INITIAL_BITRATE:
771       g_value_set_uint (value, probe.dwBitRate);
772       break;
773     case PROP_SLICE_UNITS:
774       g_value_set_uint (value, probe.wSliceUnits);
775       break;
776     case PROP_SLICE_MODE:
777       g_value_set_enum (value, probe.wSliceMode);
778       break;
779     case PROP_IFRAME_PERIOD:
780       g_value_set_uint (value, probe.wIFramePeriod);
781       break;
782     case PROP_USAGE_TYPE:
783       g_value_set_enum (value, probe.bUsageType);
784       break;
785     case PROP_ENTROPY:
786       g_value_set_enum (value, probe.bEntropyCABAC);
787       break;
788     case PROP_ENABLE_SEI:
789       g_value_set_boolean (value,
790           (probe.bTimestamp == UVC_H264_TIMESTAMP_SEI_ENABLE));
791       break;
792     case PROP_NUM_REORDER_FRAMES:
793       g_value_set_uint (value, probe.bNumOfReorderFrames);
794       break;
795     case PROP_PREVIEW_FLIPPED:
796       g_value_set_boolean (value,
797           (probe.bPreviewFlipped == UVC_H264_PREFLIPPED_HORIZONTAL));
798       break;
799     case PROP_LEAKY_BUCKET_SIZE:
800       g_value_set_uint (value, probe.wLeakyBucketSize);
801       break;
802 
803       /* Dynamic controls */
804     case PROP_RATE_CONTROL:
805       update_rate_control (self);
806       g_value_set_enum (value, self->rate_control);
807       break;
808     case PROP_FIXED_FRAMERATE:
809       update_rate_control (self);
810       g_value_set_boolean (value, self->fixed_framerate);
811       break;
812     case PROP_MAX_MBPS:
813       g_value_set_uint (value, update_level_idc_and_get_max_mbps (self));
814       break;
815     case PROP_LEVEL_IDC:
816       update_level_idc_and_get_max_mbps (self);
817       g_value_set_uint (value, self->level_idc);
818       break;
819     case PROP_PEAK_BITRATE:
820       update_bitrate (self);
821       g_value_set_uint (value, self->peak_bitrate);
822       break;
823     case PROP_AVERAGE_BITRATE:
824       update_bitrate (self);
825       g_value_set_uint (value, self->average_bitrate);
826       break;
827     case PROP_MIN_IFRAME_QP:
828       update_qp (self, QP_I_FRAME);
829       g_value_set_int (value, self->min_qp[QP_I_FRAME]);
830       break;
831     case PROP_MAX_IFRAME_QP:
832       update_qp (self, QP_I_FRAME);
833       g_value_set_int (value, self->max_qp[QP_I_FRAME]);
834       break;
835     case PROP_MIN_PFRAME_QP:
836       update_qp (self, QP_P_FRAME);
837       g_value_set_int (value, self->min_qp[QP_P_FRAME]);
838       break;
839     case PROP_MAX_PFRAME_QP:
840       update_qp (self, QP_P_FRAME);
841       g_value_set_int (value, self->max_qp[QP_P_FRAME]);
842       break;
843     case PROP_MIN_BFRAME_QP:
844       update_qp (self, QP_B_FRAME);
845       g_value_set_int (value, self->min_qp[QP_B_FRAME]);
846       break;
847     case PROP_MAX_BFRAME_QP:
848       update_qp (self, QP_B_FRAME);
849       g_value_set_int (value, self->max_qp[QP_B_FRAME]);
850       break;
851     case PROP_LTR_BUFFER_SIZE:
852       update_ltr (self);
853       g_value_set_int (value, self->ltr_buffer_size);
854       break;
855     case PROP_LTR_ENCODER_CONTROL:
856       update_ltr (self);
857       g_value_set_int (value, self->ltr_encoder_control);
858       break;
859     default:
860       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
861       break;
862   }
863 }
864 
865 /* Set dynamic controls */
866 static void
set_rate_control(GstUvcH264Src * self)867 set_rate_control (GstUvcH264Src * self)
868 {
869   uvcx_rate_control_mode_t req;
870 
871   if (!xu_query (self, UVCX_RATE_CONTROL_MODE, UVC_GET_CUR, (guchar *) & req)) {
872     GST_WARNING_OBJECT (self, " RATE_CONTROL GET_CUR error");
873     return;
874   }
875 
876   req.bRateControlMode = self->rate_control;
877   if (self->fixed_framerate)
878     req.bRateControlMode |= UVC_H264_RATECONTROL_FIXED_FRM_FLG;
879 
880   if (!xu_query (self, UVCX_RATE_CONTROL_MODE, UVC_SET_CUR, (guchar *) & req)) {
881     GST_WARNING_OBJECT (self, " RATE_CONTROL SET_CUR error");
882     return;
883   }
884 }
885 
886 static void
set_level_idc(GstUvcH264Src * self)887 set_level_idc (GstUvcH264Src * self)
888 {
889   uvcx_video_advance_config_t req;
890 
891   if (!xu_query (self, UVCX_VIDEO_ADVANCE_CONFIG, UVC_GET_CUR,
892           (guchar *) & req)) {
893     GST_WARNING_OBJECT (self, " VIDEO_ADVANCE_CONFIG GET_CUR error");
894     return;
895   }
896 
897   req.blevel_idc = self->level_idc;
898   if (!xu_query (self, UVCX_VIDEO_ADVANCE_CONFIG, UVC_SET_CUR,
899           (guchar *) & req)) {
900     GST_WARNING_OBJECT (self, " VIDEO_ADVANCE_CONFIG SET_CUR error");
901     return;
902   }
903 }
904 
905 static void
set_bitrate(GstUvcH264Src * self)906 set_bitrate (GstUvcH264Src * self)
907 {
908   uvcx_bitrate_layers_t req;
909 
910   if (!xu_query (self, UVCX_BITRATE_LAYERS, UVC_GET_CUR, (guchar *) & req)) {
911     GST_WARNING_OBJECT (self, " BITRATE_LAYERS GET_CUR error");
912     return;
913   }
914 
915   req.dwPeakBitrate = self->peak_bitrate;
916   req.dwAverageBitrate = self->average_bitrate;
917   if (!xu_query (self, UVCX_BITRATE_LAYERS, UVC_SET_CUR, (guchar *) & req)) {
918     GST_WARNING_OBJECT (self, " BITRATE_LAYERS SET_CUR error");
919     return;
920   }
921 }
922 
923 static void
set_qp(GstUvcH264Src * self,gint type)924 set_qp (GstUvcH264Src * self, gint type)
925 {
926   uvcx_qp_steps_layers_t req;
927 
928   req.wLayerID = 0;
929   switch (type) {
930     case QP_I_FRAME:
931       req.bFrameType = UVC_H264_QP_STEPS_I_FRAME_TYPE;
932       break;
933     case QP_P_FRAME:
934       req.bFrameType = UVC_H264_QP_STEPS_P_FRAME_TYPE;
935       break;
936     case QP_B_FRAME:
937       req.bFrameType = UVC_H264_QP_STEPS_B_FRAME_TYPE;
938       break;
939     default:
940       return;
941   }
942   req.bMinQp = 0;
943   req.bMaxQp = 0;
944   if (!xu_query (self, UVCX_QP_STEPS_LAYERS, UVC_SET_CUR, (guchar *) & req)) {
945     GST_WARNING_OBJECT (self, " QP_STEPS_LAYERS SET_CUR error");
946     return;
947   }
948 
949   if (!xu_query (self, UVCX_QP_STEPS_LAYERS, UVC_GET_CUR, (guchar *) & req)) {
950     GST_WARNING_OBJECT (self, " QP_STEPS_LAYERS GET_CUR error");
951     return;
952   }
953 
954   req.bMinQp = self->min_qp[type];
955   req.bMaxQp = self->max_qp[type];
956   if (!xu_query (self, UVCX_QP_STEPS_LAYERS, UVC_SET_CUR, (guchar *) & req)) {
957     GST_WARNING_OBJECT (self, " QP_STEPS_LAYERS SET_CUR error");
958     return;
959   }
960 }
961 
962 static void
set_ltr(GstUvcH264Src * self)963 set_ltr (GstUvcH264Src * self)
964 {
965   uvcx_ltr_buffer_size_control_t req;
966 
967   if (!xu_query (self, UVCX_LTR_BUFFER_SIZE_CONTROL, UVC_GET_CUR,
968           (guchar *) & req)) {
969     GST_WARNING_OBJECT (self, " LTR_BUFFER_SIZE GET_CUR error");
970     return;
971   }
972 
973   req.bLTRBufferSize = self->ltr_buffer_size;
974   req.bLTREncoderControl = self->ltr_encoder_control;
975   if (!xu_query (self, UVCX_LTR_BUFFER_SIZE_CONTROL, UVC_SET_CUR,
976           (guchar *) & req)) {
977     GST_WARNING_OBJECT (self, "LTR_BUFFER_SIZE  SET_CUR error");
978     return;
979   }
980 }
981 
982 /* Get Dynamic controls */
983 
984 static void
update_rate_control(GstUvcH264Src * self)985 update_rate_control (GstUvcH264Src * self)
986 {
987   uvcx_rate_control_mode_t req;
988 
989   if (!xu_query (self, UVCX_RATE_CONTROL_MODE, UVC_GET_CUR, (guchar *) & req)) {
990     GST_WARNING_OBJECT (self, " RATE_CONTROL GET_CUR error");
991     return;
992   }
993 
994   if (self->rate_control != (req.bRateControlMode &
995           ~UVC_H264_RATECONTROL_FIXED_FRM_FLG)) {
996     self->rate_control = (req.bRateControlMode &
997         ~UVC_H264_RATECONTROL_FIXED_FRM_FLG);
998     g_object_notify (G_OBJECT (self), "rate-control");
999   }
1000   if (self->fixed_framerate != ((req.bRateControlMode &
1001               UVC_H264_RATECONTROL_FIXED_FRM_FLG) != 0)) {
1002     self->fixed_framerate = ((req.bRateControlMode &
1003             UVC_H264_RATECONTROL_FIXED_FRM_FLG) != 0);
1004     g_object_notify (G_OBJECT (self), "fixed-framerate");
1005   }
1006 }
1007 
1008 
1009 static guint32
update_level_idc_and_get_max_mbps(GstUvcH264Src * self)1010 update_level_idc_and_get_max_mbps (GstUvcH264Src * self)
1011 {
1012   uvcx_video_advance_config_t req;
1013 
1014   if (!xu_query (self, UVCX_VIDEO_ADVANCE_CONFIG, UVC_GET_CUR,
1015           (guchar *) & req)) {
1016     GST_WARNING_OBJECT (self, " VIDEO_ADVANCE_CONFIG GET_CUR error");
1017     return 0;
1018   }
1019 
1020   if (self->level_idc != req.blevel_idc) {
1021     self->level_idc = req.blevel_idc;
1022     g_object_notify (G_OBJECT (self), "level-idc");
1023   }
1024   return req.dwMb_max;
1025 }
1026 
1027 static void
update_bitrate(GstUvcH264Src * self)1028 update_bitrate (GstUvcH264Src * self)
1029 {
1030   uvcx_bitrate_layers_t req;
1031 
1032   if (!xu_query (self, UVCX_BITRATE_LAYERS, UVC_GET_CUR, (guchar *) & req)) {
1033     GST_WARNING_OBJECT (self, " BITRATE_LAYERS GET_CUR error");
1034     return;
1035   }
1036   if (self->peak_bitrate != req.dwPeakBitrate) {
1037     self->peak_bitrate = req.dwPeakBitrate;
1038     g_object_notify (G_OBJECT (self), "peak-bitrate");
1039   }
1040   if (self->average_bitrate != req.dwAverageBitrate) {
1041     self->average_bitrate = req.dwAverageBitrate;
1042     g_object_notify (G_OBJECT (self), "average-bitrate");
1043   }
1044 }
1045 
1046 static gboolean
update_qp(GstUvcH264Src * self,gint type)1047 update_qp (GstUvcH264Src * self, gint type)
1048 {
1049   uvcx_qp_steps_layers_t req;
1050   guint8 frame_type;
1051 
1052   req.wLayerID = 0;
1053   switch (type) {
1054     case QP_I_FRAME:
1055       frame_type = UVC_H264_QP_STEPS_I_FRAME_TYPE;
1056       break;
1057     case QP_P_FRAME:
1058       frame_type = UVC_H264_QP_STEPS_P_FRAME_TYPE;
1059       break;
1060     case QP_B_FRAME:
1061       frame_type = UVC_H264_QP_STEPS_B_FRAME_TYPE;
1062       break;
1063     default:
1064       return FALSE;
1065   }
1066   req.bFrameType = frame_type;
1067   req.bMinQp = 0;
1068   req.bMaxQp = 0;
1069   if (!xu_query (self, UVCX_QP_STEPS_LAYERS, UVC_SET_CUR, (guchar *) & req)) {
1070     GST_WARNING_OBJECT (self, " QP_STEPS_LAYERS SET_CUR error");
1071     return FALSE;
1072   }
1073 
1074   if (!xu_query (self, UVCX_QP_STEPS_LAYERS, UVC_GET_CUR, (guchar *) & req)) {
1075     GST_WARNING_OBJECT (self, " QP_STEPS_LAYERS GET_CUR error");
1076     return FALSE;
1077   }
1078 
1079   if (req.bFrameType == frame_type) {
1080     if (self->min_qp[type] != req.bMinQp) {
1081       self->min_qp[type] = req.bMinQp;
1082       switch (type) {
1083         case QP_I_FRAME:
1084           g_object_notify (G_OBJECT (self), "min-iframe-qp");
1085           break;
1086         case QP_P_FRAME:
1087           g_object_notify (G_OBJECT (self), "min-pframe-qp");
1088           break;
1089         case QP_B_FRAME:
1090           g_object_notify (G_OBJECT (self), "min-bframe-qp");
1091           break;
1092         default:
1093           break;
1094       }
1095     }
1096     if (self->max_qp[type] != req.bMaxQp) {
1097       self->max_qp[type] = req.bMaxQp;
1098       switch (type) {
1099         case QP_I_FRAME:
1100           g_object_notify (G_OBJECT (self), "max-iframe-qp");
1101           break;
1102         case QP_P_FRAME:
1103           g_object_notify (G_OBJECT (self), "max-pframe-qp");
1104           break;
1105         case QP_B_FRAME:
1106           g_object_notify (G_OBJECT (self), "max-bframe-qp");
1107           break;
1108         default:
1109           break;
1110       }
1111     }
1112     return TRUE;
1113   } else {
1114     self->min_qp[type] = 0xFF;
1115     self->max_qp[type] = 0xFF;
1116     return FALSE;
1117   }
1118 }
1119 
1120 static void
update_ltr(GstUvcH264Src * self)1121 update_ltr (GstUvcH264Src * self)
1122 {
1123   uvcx_ltr_buffer_size_control_t req;
1124 
1125   if (!xu_query (self, UVCX_LTR_BUFFER_SIZE_CONTROL, UVC_GET_CUR,
1126           (guchar *) & req)) {
1127     GST_WARNING_OBJECT (self, " LTR_BUFFER_SIZE GET_CUR error");
1128     return;
1129   }
1130 
1131   if (self->ltr_buffer_size != req.bLTRBufferSize) {
1132     self->ltr_buffer_size = req.bLTRBufferSize;
1133     g_object_notify (G_OBJECT (self), "ltr-buffer-size");
1134   }
1135   if (self->ltr_encoder_control != req.bLTREncoderControl) {
1136     self->ltr_encoder_control = req.bLTREncoderControl;
1137     g_object_notify (G_OBJECT (self), "ltr-encoder-control");
1138   }
1139 }
1140 
1141 #define STORE_MIN_DEF_MAX(type)                         \
1142   *(type *)min = *((type *) (min_p + offset));          \
1143   *(type *)def = *((type *) (def_p + offset));          \
1144   *(type *)max = *((type *) (max_p + offset));
1145 
1146 static gboolean
probe_setting(GstUvcH264Src * self,uvcx_control_selector_t selector,guint offset,gint size,gpointer min,gpointer def,gpointer max)1147 probe_setting (GstUvcH264Src * self, uvcx_control_selector_t selector,
1148     guint offset, gint size, gpointer min, gpointer def, gpointer max)
1149 {
1150   guchar *min_p, *def_p, *max_p;
1151   gboolean ret = FALSE;
1152   __u16 len;
1153 
1154   if (!xu_query (self, selector, UVC_GET_LEN, (guchar *) & len)) {
1155     GST_WARNING_OBJECT (self, "probe_setting GET_LEN error");
1156     return FALSE;
1157   }
1158   min_p = g_malloc0 (len);
1159   def_p = g_malloc0 (len);
1160   max_p = g_malloc0 (len);
1161 
1162   if (!xu_query (self, selector, UVC_GET_MIN, min_p)) {
1163     GST_WARNING_OBJECT (self, "probe_setting GET_MIN error");
1164     goto end;
1165   }
1166   if (!xu_query (self, selector, UVC_GET_DEF, def_p)) {
1167     GST_WARNING_OBJECT (self, "probe_setting GET_DEF error");
1168     goto end;
1169   }
1170   if (!xu_query (self, selector, UVC_GET_MAX, max_p)) {
1171     GST_WARNING_OBJECT (self, "probe_setting GET_MAX error");
1172     goto end;
1173   }
1174 
1175   switch (size) {
1176     case -1:
1177       STORE_MIN_DEF_MAX (gint8);
1178       ret = TRUE;
1179       break;
1180     case 1:
1181       STORE_MIN_DEF_MAX (guint8);
1182       ret = TRUE;
1183       break;
1184     case -2:
1185       STORE_MIN_DEF_MAX (gint16);
1186       ret = TRUE;
1187       break;
1188     case 2:
1189       STORE_MIN_DEF_MAX (guint16);
1190       ret = TRUE;
1191       break;
1192     case -4:
1193       STORE_MIN_DEF_MAX (gint32);
1194       ret = TRUE;
1195       break;
1196     case 4:
1197       STORE_MIN_DEF_MAX (guint32);
1198       ret = TRUE;
1199       break;
1200     default:
1201       break;
1202   }
1203 
1204 end:
1205   g_free (min_p);
1206   g_free (def_p);
1207   g_free (max_p);
1208 
1209   return ret;
1210 }
1211 
1212 static gboolean
test_enum_setting(GstUvcH264Src * self,guint offset,guint size,guint16 value)1213 test_enum_setting (GstUvcH264Src * self, guint offset, guint size,
1214     guint16 value)
1215 {
1216   uvcx_video_config_probe_commit_t cur;
1217   uvcx_video_config_probe_commit_t req;
1218   guchar *req_p = (guchar *) & req;
1219 
1220   if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_GET_CUR, (guchar *) & cur)) {
1221     GST_WARNING_OBJECT (self, " GET_CUR error");
1222     return FALSE;
1223   }
1224 
1225   req = cur;
1226 
1227   if (size == 1)
1228     *((guint8 *) (req_p + offset)) = (guint8) value;
1229   else
1230     *((guint16 *) (req_p + offset)) = value;
1231 
1232   if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_SET_CUR, req_p)) {
1233     GST_WARNING_OBJECT (self, " SET_CUR error");
1234     return FALSE;
1235   }
1236 
1237   if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_GET_CUR, req_p)) {
1238     GST_WARNING_OBJECT (self, " GET_CUR error");
1239     return FALSE;
1240   }
1241 
1242   if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_SET_CUR, (guchar *) & cur)) {
1243     GST_WARNING_OBJECT (self, " SET_CUR error");
1244     return FALSE;
1245   }
1246 
1247   if (size == 1)
1248     return *((guint8 *) (req_p + offset)) == (guint8) value;
1249   else
1250     return *((guint16 *) (req_p + offset)) == value;
1251 }
1252 
1253 static gboolean
gst_uvc_h264_src_get_enum_setting(GstUvcH264Src * self,gchar * property,gint * mask,gint * default_value)1254 gst_uvc_h264_src_get_enum_setting (GstUvcH264Src * self, gchar * property,
1255     gint * mask, gint * default_value)
1256 {
1257   guint8 min, def, max;
1258   guint8 en;
1259   gboolean ret = FALSE;
1260 
1261   if (g_strcmp0 (property, "slice-mode") == 0) {
1262     guint16 min16, def16, max16;
1263     guint16 en16;
1264 
1265     ret = probe_setting (self, UVCX_VIDEO_CONFIG_PROBE,
1266         offsetof (uvcx_video_config_probe_commit_t, wSliceMode), 2,
1267         &min16, &def16, &max16);
1268     if (ret) {
1269       *default_value = def16;
1270       *mask = 0;
1271       for (en16 = min16; en16 <= max16; en16++) {
1272         if (test_enum_setting (self, offsetof (uvcx_video_config_probe_commit_t,
1273                     wSliceMode), 2, en16))
1274           *mask |= (1 << en16);
1275       }
1276     }
1277   } else if (g_strcmp0 (property, "usage-type") == 0) {
1278     ret = probe_setting (self, UVCX_VIDEO_CONFIG_PROBE,
1279         offsetof (uvcx_video_config_probe_commit_t, bUsageType), 1,
1280         &min, &def, &max);
1281     if (ret) {
1282       *default_value = def;
1283       *mask = 0;
1284       for (en = min; en <= max; en++) {
1285         if (test_enum_setting (self, offsetof (uvcx_video_config_probe_commit_t,
1286                     bUsageType), 1, en))
1287           *mask |= (1 << en);
1288       }
1289     }
1290   } else if (g_strcmp0 (property, "entropy") == 0) {
1291     ret = probe_setting (self, UVCX_VIDEO_CONFIG_PROBE,
1292         offsetof (uvcx_video_config_probe_commit_t, bEntropyCABAC), 1,
1293         &min, &def, &max);
1294     if (ret) {
1295       *mask = (1 << min) | (1 << max);
1296       *default_value = def;
1297     }
1298   } else if (g_strcmp0 (property, "rate-control") == 0) {
1299     ret = probe_setting (self, UVCX_VIDEO_CONFIG_PROBE,
1300         offsetof (uvcx_video_config_probe_commit_t, bRateControlMode), 1,
1301         &min, &def, &max);
1302     if (ret) {
1303       uvcx_rate_control_mode_t cur;
1304 
1305       *default_value = def;
1306       *mask = 0;
1307 
1308       if (!xu_query (self, UVCX_RATE_CONTROL_MODE, UVC_GET_CUR,
1309               (guchar *) & cur)) {
1310         GST_WARNING_OBJECT (self, " CONTROL_MODE GET_CUR error");
1311         return FALSE;
1312       }
1313 
1314       for (en = min; en <= max; en++) {
1315         uvcx_rate_control_mode_t req = { 0, en };
1316 
1317         if (xu_query (self, UVCX_RATE_CONTROL_MODE, UVC_SET_CUR,
1318                 (guchar *) & req) &&
1319             xu_query (self, UVCX_RATE_CONTROL_MODE, UVC_GET_CUR,
1320                 (guchar *) & req) && req.bRateControlMode == en)
1321           *mask |= (1 << en);
1322       }
1323       if (!xu_query (self, UVCX_RATE_CONTROL_MODE, UVC_SET_CUR,
1324               (guchar *) & cur)) {
1325         GST_WARNING_OBJECT (self, " CONTROL_MODE SET_CUR error");
1326         return FALSE;
1327       }
1328     }
1329   }
1330 
1331   return ret;
1332 }
1333 
1334 static gboolean
gst_uvc_h264_src_get_boolean_setting(GstUvcH264Src * self,gchar * property,gboolean * changeable,gboolean * default_value)1335 gst_uvc_h264_src_get_boolean_setting (GstUvcH264Src * self, gchar * property,
1336     gboolean * changeable, gboolean * default_value)
1337 {
1338   guint8 min, def, max;
1339   gboolean ret = FALSE;
1340 
1341   if (g_strcmp0 (property, "enable-sei") == 0) {
1342     if ((ret = probe_setting (self, UVCX_VIDEO_CONFIG_PROBE,
1343                 offsetof (uvcx_video_config_probe_commit_t, bTimestamp), 1,
1344                 &min, &def, &max))) {
1345       *changeable = (min != max);
1346       *default_value = (def != 0);
1347     }
1348   } else if (g_strcmp0 (property, "preview-flipped") == 0) {
1349     if ((ret = probe_setting (self, UVCX_VIDEO_CONFIG_PROBE,
1350                 offsetof (uvcx_video_config_probe_commit_t, bPreviewFlipped), 1,
1351                 &min, &def, &max))) {
1352       *changeable = (min != max);
1353       *default_value = (def != 0);
1354     }
1355   } else if (g_strcmp0 (property, "fixed-framerate") == 0) {
1356     if ((ret = probe_setting (self, UVCX_VIDEO_CONFIG_PROBE,
1357                 offsetof (uvcx_video_config_probe_commit_t, bRateControlMode),
1358                 1, &min, &def, &max))) {
1359       *changeable = ((max & UVC_H264_RATECONTROL_FIXED_FRM_FLG) != 0);
1360       *default_value = ((def & UVC_H264_RATECONTROL_FIXED_FRM_FLG) != 0);
1361     }
1362   }
1363 
1364   return ret;
1365 }
1366 
1367 static gboolean
gst_uvc_h264_src_get_int_setting(GstUvcH264Src * self,gchar * property,gint * min,gint * def,gint * max)1368 gst_uvc_h264_src_get_int_setting (GstUvcH264Src * self, gchar * property,
1369     gint * min, gint * def, gint * max)
1370 {
1371   guint32 min32, def32, max32;
1372   guint16 min16, def16, max16;
1373   guint8 min8, def8, max8;
1374   gint8 smin8, sdef8, smax8;
1375   gboolean ret = FALSE;
1376 
1377   GST_DEBUG_OBJECT (self, "Probing int property %s", property);
1378   if (g_strcmp0 (property, "initial-bitrate") == 0) {
1379     ret = probe_setting (self, UVCX_VIDEO_CONFIG_PROBE,
1380         offsetof (uvcx_video_config_probe_commit_t, dwBitRate), 4,
1381         &min32, &def32, &max32);
1382     if (ret) {
1383       *min = min32;
1384       *def = def32;
1385       *max = max32;
1386     }
1387   } else if (g_strcmp0 (property, "slice-units") == 0) {
1388     ret = probe_setting (self, UVCX_VIDEO_CONFIG_PROBE,
1389         offsetof (uvcx_video_config_probe_commit_t, wSliceUnits), 2,
1390         &min16, &def16, &max16);
1391     if (ret) {
1392       *min = min16;
1393       *def = def16;
1394       *max = max16;
1395     }
1396   } else if (g_strcmp0 (property, "iframe-period") == 0) {
1397     ret = probe_setting (self, UVCX_VIDEO_CONFIG_PROBE,
1398         offsetof (uvcx_video_config_probe_commit_t, wIFramePeriod), 2,
1399         &min16, &def16, &max16);
1400     if (ret) {
1401       *min = min16;
1402       *def = def16;
1403       *max = max16;
1404     }
1405   } else if (g_strcmp0 (property, "num-reorder-frames") == 0) {
1406     ret = probe_setting (self, UVCX_VIDEO_CONFIG_PROBE,
1407         offsetof (uvcx_video_config_probe_commit_t, bNumOfReorderFrames), 1,
1408         &min8, &def8, &max8);
1409     if (ret) {
1410       *min = min8;
1411       *def = def8;
1412       *max = max8;
1413     }
1414   } else if (g_strcmp0 (property, "leaky-bucket-size") == 0) {
1415     ret = probe_setting (self, UVCX_VIDEO_CONFIG_PROBE,
1416         offsetof (uvcx_video_config_probe_commit_t, wLeakyBucketSize), 2,
1417         &min16, &def16, &max16);
1418     if (ret) {
1419       *min = min16;
1420       *def = def16;
1421       *max = max16;
1422     }
1423   } else if (g_strcmp0 (property, "level-idc") == 0) {
1424     ret = probe_setting (self, UVCX_VIDEO_ADVANCE_CONFIG,
1425         offsetof (uvcx_video_advance_config_t, blevel_idc), 1,
1426         &min8, &def8, &max8);
1427     if (ret) {
1428       *min = min8;
1429       *def = def8;
1430       *max = max8;
1431     }
1432   } else if (g_strcmp0 (property, "max-mbps") == 0) {
1433     ret = probe_setting (self, UVCX_VIDEO_ADVANCE_CONFIG,
1434         offsetof (uvcx_video_advance_config_t, dwMb_max), 4,
1435         &min32, &def32, &max32);
1436     if (ret) {
1437       *min = min32;
1438       *def = def32;
1439       *max = max32;
1440     }
1441   } else if (g_strcmp0 (property, "peak-bitrate") == 0) {
1442     ret = probe_setting (self, UVCX_BITRATE_LAYERS,
1443         offsetof (uvcx_bitrate_layers_t, dwPeakBitrate), 4,
1444         &min32, &def32, &max32);
1445     if (ret) {
1446       *min = min32;
1447       *def = def32;
1448       *max = max32;
1449     }
1450   } else if (g_strcmp0 (property, "average-bitrate") == 0) {
1451     ret = probe_setting (self, UVCX_BITRATE_LAYERS,
1452         offsetof (uvcx_bitrate_layers_t, dwAverageBitrate), 4,
1453         &min32, &def32, &max32);
1454     if (ret) {
1455       *min = min32;
1456       *def = def32;
1457       *max = max32;
1458     }
1459   } else if (g_strcmp0 (property, "min-iframe-qp") == 0) {
1460     if (update_qp (self, QP_I_FRAME))
1461       ret = probe_setting (self, UVCX_QP_STEPS_LAYERS,
1462           offsetof (uvcx_qp_steps_layers_t, bMinQp), 1, &smin8, &sdef8, &smax8);
1463     if (ret) {
1464       *min = smin8;
1465       *def = sdef8;
1466       *max = smax8;
1467     }
1468   } else if (g_strcmp0 (property, "max-iframe-qp") == 0) {
1469     if (update_qp (self, QP_I_FRAME))
1470       ret = probe_setting (self, UVCX_QP_STEPS_LAYERS,
1471           offsetof (uvcx_qp_steps_layers_t, bMaxQp), 1, &smin8, &sdef8, &smax8);
1472     if (ret) {
1473       *min = smin8;
1474       *def = sdef8;
1475       *max = smax8;
1476     }
1477   } else if (g_strcmp0 (property, "min-pframe-qp") == 0) {
1478     if (update_qp (self, QP_P_FRAME))
1479       ret = probe_setting (self, UVCX_QP_STEPS_LAYERS,
1480           offsetof (uvcx_qp_steps_layers_t, bMinQp), 1, &smin8, &sdef8, &smax8);
1481     if (ret) {
1482       *min = smin8;
1483       *def = sdef8;
1484       *max = smax8;
1485     }
1486   } else if (g_strcmp0 (property, "max-pframe-qp") == 0) {
1487     if (update_qp (self, QP_P_FRAME))
1488       ret = probe_setting (self, UVCX_QP_STEPS_LAYERS,
1489           offsetof (uvcx_qp_steps_layers_t, bMaxQp), 1, &smin8, &sdef8, &smax8);
1490     if (ret) {
1491       *min = smin8;
1492       *def = sdef8;
1493       *max = smax8;
1494     }
1495   } else if (g_strcmp0 (property, "min-bframe-qp") == 0) {
1496     if (update_qp (self, QP_B_FRAME))
1497       ret = probe_setting (self, UVCX_QP_STEPS_LAYERS,
1498           offsetof (uvcx_qp_steps_layers_t, bMinQp), 1, &smin8, &sdef8, &smax8);
1499     if (ret) {
1500       *min = smin8;
1501       *def = sdef8;
1502       *max = smax8;
1503     }
1504   } else if (g_strcmp0 (property, "max-bframe-qp") == 0) {
1505     if (update_qp (self, QP_B_FRAME))
1506       ret = probe_setting (self, UVCX_QP_STEPS_LAYERS,
1507           offsetof (uvcx_qp_steps_layers_t, bMaxQp), 1, &smin8, &sdef8, &smax8);
1508     if (ret) {
1509       *min = smin8;
1510       *def = sdef8;
1511       *max = smax8;
1512     }
1513   } else if (g_strcmp0 (property, "ltr-buffer-size") == 0) {
1514     ret = probe_setting (self, UVCX_LTR_BUFFER_SIZE_CONTROL,
1515         offsetof (uvcx_ltr_buffer_size_control_t, bLTRBufferSize), 1,
1516         &min8, &def8, &max8);
1517     if (ret) {
1518       *min = min8;
1519       *def = def8;
1520       *max = max8;
1521     }
1522   } else if (g_strcmp0 (property, "ltr-encoder-control") == 0) {
1523     ret = probe_setting (self, UVCX_LTR_BUFFER_SIZE_CONTROL,
1524         offsetof (uvcx_ltr_buffer_size_control_t, bLTREncoderControl), 1,
1525         &min8, &def8, &max8);
1526     if (ret) {
1527       *min = min8;
1528       *def = def8;
1529       *max = max8;
1530     }
1531   } else {
1532     g_return_val_if_reached (FALSE);
1533   }
1534 
1535   return ret;
1536 }
1537 
1538 static GstPadProbeReturn
gst_uvc_h264_src_event_probe(GstPad * pad,GstPadProbeInfo * info,gpointer user_data)1539 gst_uvc_h264_src_event_probe (GstPad * pad, GstPadProbeInfo * info,
1540     gpointer user_data)
1541 {
1542   GstUvcH264Src *self = GST_UVC_H264_SRC (user_data);
1543   GstPadProbeReturn ret = GST_PAD_PROBE_OK;
1544   GstEvent *event = info->data;
1545 
1546   switch (GST_EVENT_TYPE (event)) {
1547     case GST_EVENT_SEGMENT:
1548       if (pad == self->vidsrc) {
1549         const GstSegment *s;
1550 
1551         gst_event_parse_segment (event, &s);
1552         gst_segment_copy_into (s, &self->segment);
1553       }
1554       break;
1555     case GST_EVENT_EOS:
1556       ret = self->reconfiguring ? GST_PAD_PROBE_DROP : GST_PAD_PROBE_OK;
1557       break;
1558     default:
1559       break;
1560   }
1561 
1562   return ret;
1563 }
1564 
1565 static GstPadProbeReturn
gst_uvc_h264_src_buffer_probe(GstPad * pad,GstPadProbeInfo * info,gpointer user_data)1566 gst_uvc_h264_src_buffer_probe (GstPad * pad, GstPadProbeInfo * info,
1567     gpointer user_data)
1568 {
1569   GstUvcH264Src *self = GST_UVC_H264_SRC (user_data);
1570   GstBuffer *buffer = info->data;
1571 
1572   /* TODO: Check the NALU type and make sure it is a keyframe */
1573   if (self->key_unit_event) {
1574     GstClockTime ts, running_time, stream_time;
1575     gboolean all_headers;
1576     guint count;
1577     GstEvent *downstream;
1578 
1579     if (gst_video_event_parse_upstream_force_key_unit (self->key_unit_event,
1580             &ts, &all_headers, &count)) {
1581       if (!GST_CLOCK_TIME_IS_VALID (ts)) {
1582         ts = GST_BUFFER_TIMESTAMP (buffer);
1583       }
1584       running_time = gst_segment_to_running_time (&self->segment,
1585           GST_FORMAT_TIME, ts);
1586 
1587       stream_time = gst_segment_to_stream_time (&self->segment,
1588           GST_FORMAT_TIME, ts);
1589 
1590       GST_DEBUG_OBJECT (self, "Sending downstream force-key-unit : %d - %d ts=%"
1591           GST_TIME_FORMAT " running time =%" GST_TIME_FORMAT " stream=%"
1592           GST_TIME_FORMAT, all_headers, count, GST_TIME_ARGS (ts),
1593           GST_TIME_ARGS (running_time), GST_TIME_ARGS (stream_time));
1594       downstream = gst_video_event_new_downstream_force_key_unit (ts,
1595           stream_time, running_time, all_headers, count);
1596       gst_pad_push_event (self->vidsrc, downstream);
1597       gst_event_replace (&self->key_unit_event, NULL);
1598     }
1599   }
1600   return TRUE;
1601 }
1602 
1603 static gboolean
gst_uvc_h264_src_parse_event(GstUvcH264Src * self,GstPad * pad,GstEvent * event)1604 gst_uvc_h264_src_parse_event (GstUvcH264Src * self, GstPad * pad,
1605     GstEvent * event)
1606 {
1607   const GstStructure *s = gst_event_get_structure (event);
1608 
1609   switch (GST_EVENT_TYPE (event)) {
1610     case GST_EVENT_CUSTOM_UPSTREAM:
1611       if (pad == self->vidsrc && self->main_format == UVC_H264_SRC_FORMAT_H264) {
1612         if (gst_video_event_is_force_key_unit (event)) {
1613           uvcx_picture_type_control_t req = { 0, 0 };
1614           GstClockTime ts;
1615           gboolean all_headers;
1616 
1617           if (gst_video_event_parse_upstream_force_key_unit (event,
1618                   &ts, &all_headers, NULL)) {
1619             GST_INFO_OBJECT (self, "Received upstream force-key-unit : %d %"
1620                 GST_TIME_FORMAT, all_headers, GST_TIME_ARGS (ts));
1621             /* TODO: wait until 'ts' time is reached */
1622             if (all_headers)
1623               req.wPicType = UVC_H264_PICTYPE_IDR_WITH_PPS_SPS;
1624             else
1625               req.wPicType = UVC_H264_PICTYPE_IDR;
1626 
1627             if (!xu_query (self, UVCX_PICTURE_TYPE_CONTROL, UVC_SET_CUR,
1628                     (guchar *) & req)) {
1629               GST_WARNING_OBJECT (self, " PICTURE_TYPE_CONTROL SET_CUR error");
1630             } else {
1631               gst_event_replace (&self->key_unit_event, event);
1632               gst_event_unref (event);
1633 
1634               return TRUE;
1635             }
1636           }
1637         } else if (s &&
1638             gst_structure_has_name (s, "uvc-h264-ltr-picture-control")) {
1639           guint put_at, encode_using;
1640 
1641           if (gst_structure_get_uint (s, "put-at", &put_at) &&
1642               gst_structure_get_uint (s, "encode-using", &encode_using)) {
1643             uvcx_ltr_picture_control req = { 0, put_at, encode_using };
1644 
1645             if (!xu_query (self, UVCX_LTR_PICTURE_CONTROL, UVC_SET_CUR,
1646                     (guchar *) & req)) {
1647               GST_WARNING_OBJECT (self, " LTR PICTURE_CONTROL SET_CUR error");
1648             } else {
1649               gst_event_unref (event);
1650 
1651               return TRUE;
1652             }
1653           }
1654           return TRUE;
1655         } else if (s && gst_structure_has_name (s, "uvc-h264-bitrate-control")) {
1656           guint average, peak;
1657 
1658           if (gst_structure_get_uint (s, "average-bitrate", &average) &&
1659               gst_structure_get_uint (s, "peak-bitrate", &peak)) {
1660             self->average_bitrate = average;
1661             self->peak_bitrate = peak;
1662             set_bitrate (self);
1663             update_bitrate (self);
1664 
1665             gst_event_unref (event);
1666 
1667             return TRUE;
1668           }
1669         } else if (s && gst_structure_has_name (s, "uvc-h264-qp-control")) {
1670           gint min_qp, max_qp;
1671           gboolean valid_event = FALSE;
1672 
1673           if (gst_structure_get_int (s, "min-iframe-qp", &min_qp) &&
1674               gst_structure_get_int (s, "max-iframe-qp", &max_qp)) {
1675             self->min_qp[QP_I_FRAME] = min_qp;
1676             self->max_qp[QP_I_FRAME] = max_qp;
1677             set_qp (self, QP_I_FRAME);
1678             update_qp (self, QP_I_FRAME);
1679             valid_event = TRUE;
1680           }
1681           if (gst_structure_get_int (s, "min-pframe-qp", &min_qp) &&
1682               gst_structure_get_int (s, "max-pframe-qp", &max_qp)) {
1683             self->min_qp[QP_P_FRAME] = min_qp;
1684             self->max_qp[QP_P_FRAME] = max_qp;
1685             set_qp (self, QP_P_FRAME);
1686             update_qp (self, QP_P_FRAME);
1687             valid_event = TRUE;
1688           }
1689           if (gst_structure_get_int (s, "min-bframe-qp", &min_qp) &&
1690               gst_structure_get_int (s, "max-bframe-qp", &max_qp)) {
1691             self->min_qp[QP_B_FRAME] = min_qp;
1692             self->max_qp[QP_B_FRAME] = max_qp;
1693             set_qp (self, QP_B_FRAME);
1694             update_qp (self, QP_B_FRAME);
1695             valid_event = TRUE;
1696           }
1697 
1698           if (valid_event) {
1699             gst_event_unref (event);
1700 
1701             return TRUE;
1702           }
1703         } else if (s && gst_structure_has_name (s, "uvc-h264-rate-control")) {
1704           UvcH264RateControl rate;
1705           gboolean fixed_framerate;
1706 
1707           if (gst_structure_get_enum (s, "rate-control",
1708                   UVC_H264_RATECONTROL_TYPE, (gint *) & rate) &&
1709               gst_structure_get_boolean (s, "fixed-framerate",
1710                   &fixed_framerate)) {
1711             self->rate_control = rate;
1712             self->fixed_framerate = fixed_framerate;
1713             set_rate_control (self);
1714             update_rate_control (self);
1715 
1716             gst_event_unref (event);
1717 
1718             return TRUE;
1719           }
1720         } else if (s && gst_structure_has_name (s, "uvc-h264-level-idc")) {
1721           guint level_idc;
1722 
1723           if (gst_structure_get_uint (s, "level-idc", &level_idc)) {
1724             self->level_idc = level_idc;
1725             set_level_idc (self);
1726             update_level_idc_and_get_max_mbps (self);
1727 
1728             gst_event_unref (event);
1729           }
1730         }
1731       }
1732       break;
1733     default:
1734       break;
1735   }
1736 
1737   return FALSE;
1738 }
1739 
1740 static gboolean
gst_uvc_h264_src_send_event(GstElement * element,GstEvent * event)1741 gst_uvc_h264_src_send_event (GstElement * element, GstEvent * event)
1742 {
1743   GstUvcH264Src *self = GST_UVC_H264_SRC (element);
1744 
1745   if (gst_uvc_h264_src_parse_event (self, self->vidsrc, event))
1746     return TRUE;
1747 
1748   return GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
1749 }
1750 
1751 static gboolean
gst_uvc_h264_src_event(GstPad * pad,GstObject * parent,GstEvent * event)1752 gst_uvc_h264_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
1753 {
1754   GstUvcH264Src *self = GST_UVC_H264_SRC (GST_PAD_PARENT (pad));
1755 
1756   switch (GST_EVENT_TYPE (event)) {
1757     case GST_EVENT_SEGMENT:
1758       if (pad == self->vidsrc) {
1759         const GstSegment *s;
1760 
1761         gst_event_parse_segment (event, &s);
1762         gst_segment_copy_into (s, &self->segment);
1763       }
1764       break;
1765     case GST_EVENT_FLUSH_STOP:
1766       if (pad == self->vidsrc)
1767         gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1768       break;
1769     default:
1770       if (gst_uvc_h264_src_parse_event (self, pad, event))
1771         return TRUE;
1772       break;
1773   }
1774   return self->srcpad_event_func (pad, parent, event);
1775 }
1776 
1777 static gboolean
xu_query(GstUvcH264Src * self,guint selector,guint query,guchar * data)1778 xu_query (GstUvcH264Src * self, guint selector, guint query, guchar * data)
1779 {
1780   struct uvc_xu_control_query xu;
1781   __u16 len;
1782 
1783   if (self->v4l2_fd == -1) {
1784     GST_WARNING_OBJECT (self, "Can't query XU with fd = -1");
1785     return FALSE;
1786   }
1787 
1788   xu.unit = self->h264_unit_id;
1789   xu.selector = selector;
1790 
1791   xu.query = UVC_GET_LEN;
1792   xu.size = sizeof (len);
1793   xu.data = (unsigned char *) &len;
1794   if (-1 == ioctl (self->v4l2_fd, UVCIOC_CTRL_QUERY, &xu)) {
1795     GST_WARNING_OBJECT (self, "PROBE GET_LEN error");
1796     return FALSE;
1797   }
1798 
1799   if (query == UVC_GET_LEN) {
1800     *((__u16 *) data) = len;
1801   } else {
1802     xu.query = query;
1803     xu.size = len;
1804     xu.data = data;
1805     if (-1 == ioctl (self->v4l2_fd, UVCIOC_CTRL_QUERY, &xu)) {
1806       return FALSE;
1807     }
1808   }
1809 
1810   return TRUE;
1811 }
1812 
1813 static void
fill_probe_commit(GstUvcH264Src * self,uvcx_video_config_probe_commit_t * probe,guint32 frame_interval,guint32 width,guint32 height,guint32 profile,UvcH264StreamFormat stream_format)1814 fill_probe_commit (GstUvcH264Src * self,
1815     uvcx_video_config_probe_commit_t * probe, guint32 frame_interval,
1816     guint32 width, guint32 height, guint32 profile,
1817     UvcH264StreamFormat stream_format)
1818 {
1819   probe->dwFrameInterval = frame_interval;
1820   probe->dwBitRate = self->initial_bitrate;
1821   probe->wWidth = width;
1822   probe->wHeight = height;
1823   probe->wSliceUnits = self->slice_units;
1824   probe->wSliceMode = self->slice_mode;
1825   probe->wProfile = profile;
1826   probe->wIFramePeriod = self->iframe_period;
1827   probe->bUsageType = self->usage_type;
1828   probe->bRateControlMode = self->rate_control;
1829   if (self->fixed_framerate)
1830     probe->bRateControlMode |= UVC_H264_RATECONTROL_FIXED_FRM_FLG;
1831   probe->bStreamFormat = stream_format;
1832   probe->bEntropyCABAC = self->entropy;
1833   probe->bTimestamp = self->enable_sei ?
1834       UVC_H264_TIMESTAMP_SEI_ENABLE : UVC_H264_TIMESTAMP_SEI_DISABLE;
1835   probe->bNumOfReorderFrames = self->num_reorder_frames;
1836   probe->bPreviewFlipped = self->preview_flipped ?
1837       UVC_H264_PREFLIPPED_HORIZONTAL : UVC_H264_PREFLIPPED_DISABLE;
1838   probe->wLeakyBucketSize = self->leaky_bucket_size;
1839 }
1840 
1841 static void
print_probe_commit(GstUvcH264Src * self,uvcx_video_config_probe_commit_t * probe)1842 print_probe_commit (GstUvcH264Src * self,
1843     uvcx_video_config_probe_commit_t * probe)
1844 {
1845   GST_DEBUG_OBJECT (self, "  Frame interval : %d *100ns",
1846       probe->dwFrameInterval);
1847   GST_DEBUG_OBJECT (self, "  Bit rate : %d", probe->dwBitRate);
1848   GST_DEBUG_OBJECT (self, "  Hints : %X", probe->bmHints);
1849   GST_DEBUG_OBJECT (self, "  Configuration index : %d",
1850       probe->wConfigurationIndex);
1851   GST_DEBUG_OBJECT (self, "  Width : %d", probe->wWidth);
1852   GST_DEBUG_OBJECT (self, "  Height : %d", probe->wHeight);
1853   GST_DEBUG_OBJECT (self, "  Slice units : %d", probe->wSliceUnits);
1854   GST_DEBUG_OBJECT (self, "  Slice mode : %X", probe->wSliceMode);
1855   GST_DEBUG_OBJECT (self, "  Profile : %X", probe->wProfile);
1856   GST_DEBUG_OBJECT (self, "  IFrame Period : %d ms", probe->wIFramePeriod);
1857   GST_DEBUG_OBJECT (self, "  Estimated video delay : %d ms",
1858       probe->wEstimatedVideoDelay);
1859   GST_DEBUG_OBJECT (self, "  Estimated max config delay : %d ms",
1860       probe->wEstimatedMaxConfigDelay);
1861   GST_DEBUG_OBJECT (self, "  Usage type : %X", probe->bUsageType);
1862   GST_DEBUG_OBJECT (self, "  Rate control mode : %X", probe->bRateControlMode);
1863   GST_DEBUG_OBJECT (self, "  Temporal scale mode : %X",
1864       probe->bTemporalScaleMode);
1865   GST_DEBUG_OBJECT (self, "  Spatial scale mode : %X",
1866       probe->bSpatialScaleMode);
1867   GST_DEBUG_OBJECT (self, "  SNR scale mode : %X", probe->bSNRScaleMode);
1868   GST_DEBUG_OBJECT (self, "  Stream mux option : %X", probe->bStreamMuxOption);
1869   GST_DEBUG_OBJECT (self, "  Stream Format : %X", probe->bStreamFormat);
1870   GST_DEBUG_OBJECT (self, "  Entropy CABAC : %X", probe->bEntropyCABAC);
1871   GST_DEBUG_OBJECT (self, "  Timestamp : %X", probe->bTimestamp);
1872   GST_DEBUG_OBJECT (self, "  Num of reorder frames : %d",
1873       probe->bNumOfReorderFrames);
1874   GST_DEBUG_OBJECT (self, "  Preview flipped : %X", probe->bPreviewFlipped);
1875   GST_DEBUG_OBJECT (self, "  View : %d", probe->bView);
1876   GST_DEBUG_OBJECT (self, "  Stream ID : %X", probe->bStreamID);
1877   GST_DEBUG_OBJECT (self, "  Spatial layer ratio : %f",
1878       ((probe->bSpatialLayerRatio & 0xF0) >> 4) +
1879       ((float) (probe->bSpatialLayerRatio & 0x0F)) / 16);
1880   GST_DEBUG_OBJECT (self, "  Leaky bucket size : %d ms",
1881       probe->wLeakyBucketSize);
1882 }
1883 
1884 static void
configure_h264(GstUvcH264Src * self,gint fd)1885 configure_h264 (GstUvcH264Src * self, gint fd)
1886 {
1887   uvcx_video_config_probe_commit_t probe;
1888 
1889   /* Set the secondary format first, so the last SET_CUR will be for the
1890    * H264 format. This way, we can still get the static control values with
1891    * a GET_CUR. Otherwise all static properties will return 0 because that's
1892    * what the GET_CUR of the raw format returns.
1893    */
1894   if (self->secondary_format == UVC_H264_SRC_FORMAT_RAW) {
1895     memset (&probe, 0, sizeof (probe));
1896     probe.dwFrameInterval = self->secondary_frame_interval;
1897     probe.wWidth = self->secondary_width;
1898     probe.wHeight = self->secondary_height;
1899     probe.bStreamMuxOption = 5;
1900 
1901     GST_DEBUG_OBJECT (self, "RAW PROBE SET_CUR : ");
1902     print_probe_commit (self, &probe);
1903 
1904     if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_SET_CUR,
1905             (guchar *) & probe)) {
1906       GST_WARNING_OBJECT (self, "PROBE SET_CUR error");
1907       return;
1908     }
1909 
1910     if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_GET_CUR,
1911             (guchar *) & probe)) {
1912       GST_WARNING_OBJECT (self, "PROBE GET_CUR error");
1913       return;
1914     }
1915     GST_DEBUG_OBJECT (self, "RAW PROBE GET_CUR : ");
1916     print_probe_commit (self, &probe);
1917 
1918     if (!xu_query (self, UVCX_VIDEO_CONFIG_COMMIT, UVC_SET_CUR,
1919             (guchar *) & probe)) {
1920       GST_WARNING_OBJECT (self, "COMMIT SET_CUR error");
1921       return;
1922     }
1923   }
1924   /* Print MIN/MAX/DEF probe values for debugging purposes */
1925   if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_GET_MIN,
1926           (guchar *) & probe)) {
1927     GST_WARNING_OBJECT (self, "PROBE GET_CUR error");
1928     return;
1929   }
1930   GST_DEBUG_OBJECT (self, "PROBE GET_MIN : ");
1931   print_probe_commit (self, &probe);
1932 
1933   if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_GET_MAX,
1934           (guchar *) & probe)) {
1935     GST_WARNING_OBJECT (self, "PROBE GET_CUR error");
1936     return;
1937   }
1938   GST_DEBUG_OBJECT (self, "PROBE GET_MAX : ");
1939   print_probe_commit (self, &probe);
1940 
1941   if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_GET_DEF,
1942           (guchar *) & probe)) {
1943     GST_WARNING_OBJECT (self, "PROBE GET_CUR error");
1944     return;
1945   }
1946   GST_DEBUG_OBJECT (self, "PROBE GET_DEF : ");
1947   print_probe_commit (self, &probe);
1948 
1949   fill_probe_commit (self, &probe, self->main_frame_interval,
1950       self->main_width, self->main_height, self->main_profile,
1951       self->main_stream_format);
1952   if (self->secondary_format != UVC_H264_SRC_FORMAT_NONE)
1953     probe.bStreamMuxOption = 3;
1954   else
1955     probe.bStreamMuxOption = 0;
1956   probe.bmHints = UVC_H264_BMHINTS_RESOLUTION | UVC_H264_BMHINTS_PROFILE |
1957       UVC_H264_BMHINTS_FRAME_INTERVAL;
1958 
1959   GST_DEBUG_OBJECT (self, "PROBE SET_CUR : ");
1960   print_probe_commit (self, &probe);
1961 
1962   if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_SET_CUR,
1963           (guchar *) & probe)) {
1964     GST_WARNING_OBJECT (self, "PROBE SET_CUR error");
1965     return;
1966   }
1967 
1968   if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_GET_CUR,
1969           (guchar *) & probe)) {
1970     GST_WARNING_OBJECT (self, "PROBE GET_CUR error");
1971     return;
1972   }
1973   GST_DEBUG_OBJECT (self, "PROBE GET_CUR : ");
1974   print_probe_commit (self, &probe);
1975 
1976   /* Must validate the settings accepted by the encoder */
1977   if (!xu_query (self, UVCX_VIDEO_CONFIG_COMMIT, UVC_SET_CUR,
1978           (guchar *) & probe)) {
1979     GST_WARNING_OBJECT (self, "COMMIT SET_CUR error");
1980     return;
1981   }
1982 }
1983 
1984 static void
v4l2src_prepare_format(GstElement * v4l2src,gint fd,GstCaps * caps,gpointer user_data)1985 v4l2src_prepare_format (GstElement * v4l2src, gint fd, GstCaps * caps,
1986     gpointer user_data)
1987 {
1988   GstUvcH264Src *self = GST_UVC_H264_SRC (user_data);
1989 
1990   if (self->main_format == UVC_H264_SRC_FORMAT_H264) {
1991     /* TODO: update static controls and g_object_notify those that changed */
1992     configure_h264 (self, fd);
1993 
1994     /* TODO: update dynamic controls on READY state */
1995     /* Configure dynamic controls */
1996     set_rate_control (self);
1997     update_rate_control (self);
1998     set_level_idc (self);
1999     update_level_idc_and_get_max_mbps (self);
2000     set_bitrate (self);
2001     update_bitrate (self);
2002     set_qp (self, QP_I_FRAME);
2003     update_qp (self, QP_I_FRAME);
2004     set_qp (self, QP_P_FRAME);
2005     update_qp (self, QP_P_FRAME);
2006     set_qp (self, QP_B_FRAME);
2007     update_qp (self, QP_B_FRAME);
2008     set_ltr (self);
2009     update_ltr (self);
2010   }
2011 }
2012 
2013 static gboolean
_extract_caps_info(GstStructure * structure,guint16 * width,guint16 * height,guint32 * frame_interval)2014 _extract_caps_info (GstStructure * structure, guint16 * width, guint16 * height,
2015     guint32 * frame_interval)
2016 {
2017   gint w, h, fps_n, fps_d;
2018   gboolean ret = TRUE;
2019 
2020   ret &= gst_structure_get_int (structure, "width", &w);
2021   ret &= gst_structure_get_int (structure, "height", &h);
2022   ret &= gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d);
2023 
2024   if (ret) {
2025     *width = w;
2026     *height = h;
2027     /* Interval is in 100ns */
2028     *frame_interval = GST_TIME_AS_NSECONDS ((fps_d * GST_SECOND) / fps_n) / 100;
2029   }
2030 
2031   return ret;
2032 }
2033 
2034 static guint16
_extract_profile(GstStructure * structure)2035 _extract_profile (GstStructure * structure)
2036 {
2037   const gchar *profile_str;
2038   guint16 profile;
2039 
2040   profile = UVC_H264_PROFILE_HIGH;
2041   profile_str = gst_structure_get_string (structure, "profile");
2042   if (profile_str) {
2043     if (!strcmp (profile_str, "constrained-baseline")) {
2044       profile = UVC_H264_PROFILE_CONSTRAINED_BASELINE;
2045     } else if (!strcmp (profile_str, "baseline")) {
2046       profile = UVC_H264_PROFILE_BASELINE;
2047     } else if (!strcmp (profile_str, "main")) {
2048       profile = UVC_H264_PROFILE_MAIN;
2049     } else if (!strcmp (profile_str, "high")) {
2050       profile = UVC_H264_PROFILE_HIGH;
2051     }
2052   }
2053   return profile;
2054 }
2055 
2056 static UvcH264StreamFormat
_extract_stream_format(GstStructure * structure)2057 _extract_stream_format (GstStructure * structure)
2058 {
2059   const gchar *stream_format;
2060 
2061   stream_format = gst_structure_get_string (structure, "stream-format");
2062   if (stream_format) {
2063     if (!strcmp (stream_format, "avc"))
2064       return UVC_H264_STREAMFORMAT_NAL;
2065     else if (!strcmp (stream_format, "byte-stream"))
2066       return UVC_H264_STREAMFORMAT_ANNEXB;
2067   }
2068   return UVC_H264_STREAMFORMAT_ANNEXB;
2069 }
2070 
2071 static GstCaps *
_transform_caps(GstUvcH264Src * self,GstCaps * caps,const gchar * name)2072 _transform_caps (GstUvcH264Src * self, GstCaps * caps, const gchar * name)
2073 {
2074   GstElement *el = gst_element_factory_make (name, NULL);
2075   GstElement *cf = gst_element_factory_make ("capsfilter", NULL);
2076   GstElement *fs = gst_element_factory_make ("fakesink", NULL);
2077   GstPad *sink;
2078   GstCaps *out_caps = NULL;
2079 
2080   if (!el || !cf || !fs) {
2081     if (el)
2082       gst_object_unref (el);
2083     if (cf)
2084       gst_object_unref (cf);
2085     if (fs)
2086       gst_object_unref (fs);
2087     goto done;
2088   }
2089 
2090   gst_element_set_locked_state (el, TRUE);
2091   gst_element_set_locked_state (cf, TRUE);
2092   gst_element_set_locked_state (fs, TRUE);
2093 
2094   if (!gst_bin_add (GST_BIN (self), el)) {
2095     gst_object_unref (el);
2096     gst_object_unref (cf);
2097     gst_object_unref (fs);
2098     goto done;
2099   }
2100   if (!gst_bin_add (GST_BIN (self), cf)) {
2101     gst_object_unref (cf);
2102     gst_object_unref (fs);
2103     gst_bin_remove (GST_BIN (self), el);
2104     goto done;
2105   }
2106   if (!gst_bin_add (GST_BIN (self), fs)) {
2107     gst_object_unref (fs);
2108     gst_bin_remove (GST_BIN (self), el);
2109     gst_bin_remove (GST_BIN (self), cf);
2110     goto done;
2111   }
2112 
2113   g_object_set (cf, "caps", caps, NULL);
2114 
2115   if (!gst_element_link (cf, fs))
2116     goto error_remove;
2117   if (!gst_element_link (el, cf))
2118     goto error_remove;
2119 
2120   sink = gst_element_get_static_pad (el, "sink");
2121   if (!sink)
2122     goto error_remove;
2123   GST_DEBUG_OBJECT (self, "Transforming: %" GST_PTR_FORMAT, caps);
2124 
2125   caps = gst_pad_query_caps (sink, NULL);
2126   gst_object_unref (sink);
2127 
2128   GST_DEBUG_OBJECT (self, "Result: %" GST_PTR_FORMAT, out_caps);
2129 
2130 error_remove:
2131   gst_bin_remove (GST_BIN (self), cf);
2132   gst_bin_remove (GST_BIN (self), el);
2133   gst_bin_remove (GST_BIN (self), fs);
2134 
2135 done:
2136   if (out_caps == NULL)
2137     out_caps = gst_caps_copy (caps);
2138 
2139   return out_caps;
2140 }
2141 
2142 static GstCaps *
gst_uvc_h264_src_transform_caps(GstUvcH264Src * self,GstCaps * caps)2143 gst_uvc_h264_src_transform_caps (GstUvcH264Src * self, GstCaps * caps)
2144 {
2145   GstCaps *h264 = gst_caps_new_empty_simple ("video/x-h264");
2146   GstCaps *jpg = gst_caps_new_empty_simple ("image/jpeg");
2147   GstCaps *h264_caps = gst_caps_intersect (h264, caps);
2148   GstCaps *jpg_caps = gst_caps_intersect (jpg, caps);
2149 
2150   /* TODO: Keep caps order after transformation */
2151   caps = _transform_caps (self, caps, self->colorspace_name);
2152   caps = gst_caps_make_writable (caps);
2153 
2154   if (!gst_caps_is_empty (h264_caps)) {
2155     gst_caps_append (caps, h264_caps);
2156   } else {
2157     gst_caps_unref (h264_caps);
2158   }
2159 
2160   if (!gst_caps_is_empty (jpg_caps)) {
2161     gst_caps_append (caps, jpg_caps);
2162   } else {
2163     gst_caps_unref (jpg_caps);
2164   }
2165 
2166   gst_caps_unref (h264);
2167   gst_caps_unref (jpg);
2168 
2169   return caps;
2170 }
2171 
2172 static GstCaps *
gst_uvc_h264_src_fixate_caps(GstUvcH264Src * self,GstPad * v4l_pad,GstCaps * v4l_caps,GstCaps * peer_caps,gboolean primary)2173 gst_uvc_h264_src_fixate_caps (GstUvcH264Src * self, GstPad * v4l_pad,
2174     GstCaps * v4l_caps, GstCaps * peer_caps, gboolean primary)
2175 {
2176   GstCaps *caps = NULL;
2177   GstCaps *icaps = NULL;
2178   GstCaps *tcaps = NULL;
2179   int i;
2180 
2181   if (v4l_caps == NULL || gst_caps_is_any (v4l_caps)) {
2182     GST_DEBUG_OBJECT (self, "v4l caps are invalid. not fixating");
2183     return NULL;
2184   }
2185 
2186   tcaps = gst_caps_intersect_full (peer_caps, v4l_caps,
2187       GST_CAPS_INTERSECT_FIRST);
2188   GST_DEBUG_OBJECT (self, "intersect: %" GST_PTR_FORMAT, tcaps);
2189   icaps = gst_caps_normalize (tcaps);
2190 
2191   /* Prefer the first caps we are compatible with that the peer proposed */
2192   for (i = 0; i < gst_caps_get_size (icaps); i++) {
2193     /* get intersection */
2194     GstCaps *ipcaps = gst_caps_copy_nth (icaps, i);
2195     GstStructure *s = gst_caps_get_structure (ipcaps, 0);
2196 
2197     GST_DEBUG_OBJECT (self, "Testing %s: %" GST_PTR_FORMAT,
2198         primary ? "primary" : "secondary", ipcaps);
2199     if (primary && gst_structure_has_name (s, "video/x-h264")) {
2200       uvcx_video_config_probe_commit_t probe;
2201       guint16 width;
2202       guint16 height;
2203       guint32 interval;
2204       guint16 profile;
2205       UvcH264StreamFormat stream_format;
2206 
2207       if (_extract_caps_info (s, &width, &height, &interval)) {
2208         profile = _extract_profile (s);
2209         stream_format = _extract_stream_format (s);
2210         fill_probe_commit (self, &probe, interval, width, height,
2211             profile, stream_format);
2212         probe.bmHints = UVC_H264_BMHINTS_RESOLUTION |
2213             UVC_H264_BMHINTS_PROFILE | UVC_H264_BMHINTS_FRAME_INTERVAL;
2214 
2215         if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_SET_CUR,
2216                 (guchar *) & probe)) {
2217           GST_WARNING_OBJECT (self, "PROBE SET_CUR error");
2218           return NULL;
2219         }
2220 
2221         if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_GET_CUR,
2222                 (guchar *) & probe)) {
2223           GST_WARNING_OBJECT (self, "PROBE GET_CUR error");
2224           return NULL;
2225         }
2226         GST_DEBUG_OBJECT (self, "Probe gives us %d==%d, %d==%d, %d==%d",
2227             probe.wWidth, width, probe.wHeight, height,
2228             probe.bStreamFormat, stream_format);
2229         if (probe.wWidth == width && probe.wHeight == height &&
2230             probe.bStreamFormat == stream_format) {
2231           caps = ipcaps;
2232           break;
2233         }
2234       }
2235     } else if (!primary && self->main_format == UVC_H264_SRC_FORMAT_H264) {
2236       uvcx_video_config_probe_commit_t probe;
2237       guint16 width;
2238       guint16 height;
2239       guint32 interval;
2240 
2241       if (_extract_caps_info (s, &width, &height, &interval)) {
2242         if (gst_structure_has_name (s, "video/x-raw")) {
2243           guint8 mux = 0;
2244           const gchar *format = gst_structure_get_string (s, "format");
2245 
2246           if ((format = gst_structure_get_string (s, "format"))) {
2247             if (g_strcmp0 (format, "YUY2") == 0)
2248               mux = 4;
2249             else if (g_strcmp0 (format, "NV12") == 0)
2250               mux = 8;
2251           }
2252           if (mux != 0) {
2253             memset (&probe, 0, sizeof (probe));
2254             probe.dwFrameInterval = interval;
2255             probe.wWidth = width;
2256             probe.wHeight = height;
2257             probe.bStreamMuxOption = mux | 1;
2258             probe.bmHints = UVC_H264_BMHINTS_RESOLUTION |
2259                 UVC_H264_BMHINTS_PROFILE | UVC_H264_BMHINTS_FRAME_INTERVAL;
2260 
2261             if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_SET_CUR,
2262                     (guchar *) & probe)) {
2263               GST_WARNING_OBJECT (self, "PROBE SET_CUR error");
2264               return NULL;
2265             }
2266 
2267             if (!xu_query (self, UVCX_VIDEO_CONFIG_PROBE, UVC_GET_CUR,
2268                     (guchar *) & probe)) {
2269               GST_WARNING_OBJECT (self, "PROBE GET_CUR error");
2270               return NULL;
2271             }
2272             GST_DEBUG_OBJECT (self, "Probe gives us %d==%d, %d==%d, %d~=%d",
2273                 probe.wWidth, width, probe.wHeight, height,
2274                 probe.bStreamMuxOption, mux);
2275             if (probe.wWidth == width && probe.wHeight == height &&
2276                 (probe.bStreamMuxOption & mux) != 0) {
2277               caps = ipcaps;
2278               break;
2279             }
2280           }
2281         } else if (gst_structure_has_name (s, "image/jpeg")) {
2282           /* HACK ALERT:  No way of figuring this one out but it seems the
2283            * camera doesn't allow for h264 muxing and jpeg resolution higher
2284            * than 640x480 so we shouldn't allow it */
2285           if (width <= 640 && height <= 480) {
2286             caps = ipcaps;
2287             break;
2288           }
2289         }
2290       }
2291     } else {
2292       caps = ipcaps;
2293       break;
2294     }
2295     gst_caps_unref (ipcaps);
2296   }
2297 
2298   if (caps) {
2299     caps = gst_caps_make_writable (caps);
2300 
2301     /* now fixate */
2302     if (!gst_caps_is_empty (caps)) {
2303       caps = gst_caps_fixate (caps);
2304       GST_DEBUG_OBJECT (self, "fixated to: %" GST_PTR_FORMAT, caps);
2305     }
2306 
2307     if (gst_caps_is_empty (caps) || gst_caps_is_any (caps)) {
2308       gst_caps_unref (caps);
2309       caps = NULL;
2310     }
2311   }
2312 
2313   return caps;
2314 }
2315 
2316 static void
gst_uvc_h264_src_destroy_pipeline(GstUvcH264Src * self,gboolean v4l2src)2317 gst_uvc_h264_src_destroy_pipeline (GstUvcH264Src * self, gboolean v4l2src)
2318 {
2319   GstIterator *iter = NULL;
2320   gboolean done;
2321 
2322   if (v4l2src && self->v4l2_src) {
2323     gst_bin_remove (GST_BIN (self), self->v4l2_src);
2324     gst_element_set_state (self->v4l2_src, GST_STATE_NULL);
2325     gst_object_unref (self->v4l2_src);
2326     self->v4l2_src = NULL;
2327     self->v4l2_fd = -1;
2328     self->h264_unit_id = 0;
2329   }
2330   if (self->mjpg_demux) {
2331     gst_bin_remove (GST_BIN (self), self->mjpg_demux);
2332     gst_element_set_state (self->mjpg_demux, GST_STATE_NULL);
2333     gst_object_unref (self->mjpg_demux);
2334     self->mjpg_demux = NULL;
2335   }
2336   if (self->jpeg_dec) {
2337     gst_bin_remove (GST_BIN (self), self->jpeg_dec);
2338     gst_element_set_state (self->jpeg_dec, GST_STATE_NULL);
2339     gst_object_unref (self->jpeg_dec);
2340     self->jpeg_dec = NULL;
2341   }
2342   if (self->vid_colorspace) {
2343     gst_bin_remove (GST_BIN (self), self->vid_colorspace);
2344     gst_element_set_state (self->vid_colorspace, GST_STATE_NULL);
2345     gst_object_unref (self->vid_colorspace);
2346     self->vid_colorspace = NULL;
2347   }
2348   if (self->vf_colorspace) {
2349     gst_bin_remove (GST_BIN (self), self->vf_colorspace);
2350     gst_element_set_state (self->vf_colorspace, GST_STATE_NULL);
2351     gst_object_unref (self->vf_colorspace);
2352     self->vf_colorspace = NULL;
2353   }
2354   iter = gst_bin_iterate_elements (GST_BIN (self));
2355   done = FALSE;
2356   while (!done) {
2357     GValue data = { 0, };
2358 
2359     switch (gst_iterator_next (iter, &data)) {
2360       case GST_ITERATOR_OK:
2361       {
2362         GstElement *child = g_value_get_object (&data);
2363         if (child != self->v4l2_src) {
2364           gst_bin_remove (GST_BIN (self), child);
2365           gst_element_set_state (child, GST_STATE_NULL);
2366         }
2367         g_value_reset (&data);
2368         break;
2369       }
2370       case GST_ITERATOR_RESYNC:
2371         gst_iterator_resync (iter);
2372         break;
2373       case GST_ITERATOR_ERROR:
2374         done = TRUE;
2375         break;
2376       case GST_ITERATOR_DONE:
2377         done = TRUE;
2378         break;
2379     }
2380   }
2381   gst_iterator_free (iter);
2382 }
2383 
2384 static gboolean
ensure_v4l2src(GstUvcH264Src * self)2385 ensure_v4l2src (GstUvcH264Src * self)
2386 {
2387   gchar *device = NULL;
2388   GstClock *v4l2_clock = NULL;
2389 
2390   if (self->v4l2_src == NULL) {
2391     /* Create v4l2 source and set it up */
2392     self->v4l2_src = gst_element_factory_make ("v4l2src", NULL);
2393     if (!self->v4l2_src || !gst_bin_add (GST_BIN (self), self->v4l2_src))
2394       goto error;
2395     gst_object_ref (self->v4l2_src);
2396     g_signal_connect (self->v4l2_src, "prepare-format",
2397         (GCallback) v4l2src_prepare_format, self);
2398   }
2399 
2400   g_object_get (self->v4l2_src, "device", &device, NULL);
2401   g_object_set (self->v4l2_src,
2402       "device", self->device, "num-buffers", self->num_buffers, NULL);
2403 
2404   v4l2_clock = gst_element_get_clock (self->v4l2_src);
2405 
2406   /* Set to NULL if the device changed */
2407   if (g_strcmp0 (device, self->device))
2408     gst_element_set_state (self->v4l2_src, GST_STATE_NULL);
2409   g_free (device);
2410 
2411   if (gst_element_set_state (self->v4l2_src, GST_STATE_READY) !=
2412       GST_STATE_CHANGE_SUCCESS) {
2413     GST_DEBUG_OBJECT (self, "Unable to set v4l2src to READY state");
2414     goto error_remove;
2415   }
2416 
2417   /* Set/Update the fd and unit id after we go to READY */
2418   g_object_get (self->v4l2_src, "device-fd", &self->v4l2_fd, NULL);
2419   self->h264_unit_id =
2420       xu_get_id (GST_OBJECT (self), self->device, &self->usb_ctx);
2421 
2422   if (self->h264_unit_id == 0) {
2423     GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
2424         ("Device is not a valid UVC H264 camera"), (NULL));
2425     goto error_remove;
2426   }
2427 
2428   /* going to state READY makes v4l2src lose its reference to the clock */
2429   if (v4l2_clock) {
2430     gst_element_set_clock (self->v4l2_src, v4l2_clock);
2431     gst_element_set_base_time (self->v4l2_src,
2432         gst_element_get_base_time (GST_ELEMENT (self)));
2433     gst_object_unref (v4l2_clock);
2434   }
2435 
2436   return TRUE;
2437 
2438 error_remove:
2439   gst_element_set_state (self->v4l2_src, GST_STATE_NULL);
2440   gst_bin_remove (GST_BIN (self), self->v4l2_src);
2441 
2442 error:
2443   if (v4l2_clock)
2444     gst_object_unref (v4l2_clock);
2445   if (self->v4l2_src)
2446     gst_object_unref (self->v4l2_src);
2447   self->v4l2_src = NULL;
2448   self->v4l2_fd = -1;
2449   self->h264_unit_id = 0;
2450 
2451   return FALSE;
2452 }
2453 
2454 static gboolean
gst_uvc_h264_src_construct_pipeline(GstBaseCameraSrc * bcamsrc)2455 gst_uvc_h264_src_construct_pipeline (GstBaseCameraSrc * bcamsrc)
2456 {
2457   GstUvcH264Src *self = GST_UVC_H264_SRC (bcamsrc);
2458   GstIterator *iter = NULL;
2459   gboolean iter_done = FALSE;
2460   GstPad *vf_pad = NULL;
2461   GstCaps *vf_caps = NULL;
2462   GstStructure *vf_struct = NULL;
2463   GstPad *vid_pad = NULL;
2464   GstCaps *vid_caps = NULL;
2465   GstStructure *vid_struct = NULL;
2466   GstCaps *src_caps = NULL;
2467   GstPad *v4l_pad = NULL;
2468   GstCaps *v4l_caps = NULL;
2469   gboolean jpg2raw = FALSE;
2470 
2471   enum
2472   {
2473     RAW_NONE, ENCODED_NONE, NONE_RAW, NONE_ENCODED,
2474     H264_JPG, H264_RAW, H264_JPG2RAW, NONE_NONE,
2475     RAW_RAW, ENCODED_ENCODED,
2476   } type;
2477 
2478   GST_DEBUG_OBJECT (self, "Construct pipeline");
2479   self->reconfiguring = TRUE;
2480 
2481   if (self->v4l2_src) {
2482     uvcx_encoder_reset req = { 0 };
2483 
2484     if (!xu_query (self, UVCX_ENCODER_RESET, UVC_SET_CUR, (guchar *) & req))
2485       GST_WARNING_OBJECT (self, " UVCX_ENCODER_RESET SET_CUR error");
2486   }
2487 
2488   if (!ensure_v4l2src (self))
2489     goto error;
2490 
2491   gst_uvc_h264_src_destroy_pipeline (self, FALSE);
2492 
2493   /* Potentially unlink v4l2src to the ghost pads */
2494   gst_ghost_pad_set_target (GST_GHOST_PAD (self->vidsrc), NULL);
2495   gst_ghost_pad_set_target (GST_GHOST_PAD (self->vfsrc), NULL);
2496 
2497   if (gst_pad_is_linked (self->vfsrc))
2498     vf_caps = gst_pad_peer_query_caps (self->vfsrc, NULL);
2499   if (gst_pad_is_linked (self->vidsrc))
2500     vid_caps = gst_pad_peer_query_caps (self->vidsrc, NULL);
2501 
2502   GST_DEBUG_OBJECT (self, "vfsrc caps : %" GST_PTR_FORMAT, vf_caps);
2503   GST_DEBUG_OBJECT (self, "vidsrc caps : %" GST_PTR_FORMAT, vid_caps);
2504   if (!self->started) {
2505     GST_DEBUG_OBJECT (self, "video not started. Ignoring vidsrc caps");
2506     if (vid_caps)
2507       gst_caps_unref (vid_caps);
2508     vid_caps = NULL;
2509   }
2510 
2511   v4l_pad = gst_element_get_static_pad (self->v4l2_src, "src");
2512   v4l_caps = gst_pad_query_caps (v4l_pad, NULL);
2513   GST_DEBUG_OBJECT (self, "v4l2src caps : %" GST_PTR_FORMAT, v4l_caps);
2514   if (vid_caps) {
2515     GstCaps *trans_caps = gst_uvc_h264_src_transform_caps (self, vid_caps);
2516 
2517     gst_caps_unref (vid_caps);
2518     vid_caps = gst_uvc_h264_src_fixate_caps (self, v4l_pad, v4l_caps,
2519         trans_caps, TRUE);
2520     gst_caps_unref (trans_caps);
2521 
2522     if (vid_caps) {
2523       vid_struct = gst_caps_get_structure (vid_caps, 0);
2524     } else {
2525       GST_WARNING_OBJECT (self, "Could not negotiate vidsrc caps format");
2526       gst_object_unref (v4l_pad);
2527       gst_caps_unref (v4l_caps);
2528       goto error_remove;
2529     }
2530   }
2531   GST_DEBUG_OBJECT (self, "Fixated vidsrc caps : %" GST_PTR_FORMAT, vid_caps);
2532 
2533   if (vid_caps && gst_structure_has_name (vid_struct, "video/x-h264")) {
2534     self->main_format = UVC_H264_SRC_FORMAT_H264;
2535     if (!_extract_caps_info (vid_struct, &self->main_width,
2536             &self->main_height, &self->main_frame_interval)) {
2537       gst_object_unref (v4l_pad);
2538       gst_caps_unref (v4l_caps);
2539       goto error_remove;
2540     }
2541 
2542     self->main_stream_format = _extract_stream_format (vid_struct);
2543     self->main_profile = _extract_profile (vid_struct);
2544   } else {
2545     self->main_format = UVC_H264_SRC_FORMAT_NONE;
2546   }
2547 
2548   if (vf_caps) {
2549     GstCaps *trans_caps = gst_uvc_h264_src_transform_caps (self, vf_caps);
2550 
2551     gst_caps_unref (vf_caps);
2552     vf_caps = gst_uvc_h264_src_fixate_caps (self, v4l_pad, v4l_caps,
2553         trans_caps, FALSE);
2554 
2555     /* If we couldn't find a suitable vf cap, try the jpeg2raw pipeline */
2556     if (!vf_caps && self->main_format == UVC_H264_SRC_FORMAT_H264) {
2557       GstCaps *jpg_caps;
2558 
2559       jpg2raw = TRUE;
2560       jpg_caps = _transform_caps (self, trans_caps, self->jpeg_decoder_name);
2561 
2562       vf_caps = gst_uvc_h264_src_fixate_caps (self, v4l_pad, v4l_caps,
2563           jpg_caps, FALSE);
2564       gst_caps_unref (jpg_caps);
2565     }
2566     gst_caps_unref (trans_caps);
2567     if (vf_caps) {
2568       vf_struct = gst_caps_get_structure (vf_caps, 0);
2569     } else {
2570       GST_WARNING_OBJECT (self, "Could not negotiate vfsrc caps format");
2571       gst_object_unref (v4l_pad);
2572       gst_caps_unref (v4l_caps);
2573       goto error_remove;
2574     }
2575   }
2576   GST_DEBUG_OBJECT (self, "Fixated vfsrc caps : %" GST_PTR_FORMAT, vf_caps);
2577   gst_object_unref (v4l_pad);
2578   gst_caps_unref (v4l_caps);
2579 
2580   if (vf_caps && vid_caps &&
2581       !gst_structure_has_name (vid_struct, "video/x-h264")) {
2582     /* Allow for vfsrc+vidsrc to both be raw or jpeg */
2583     if (gst_structure_has_name (vid_struct, "image/jpeg") &&
2584         gst_structure_has_name (vf_struct, "image/jpeg")) {
2585       self->main_format = UVC_H264_SRC_FORMAT_JPG;
2586       self->secondary_format = UVC_H264_SRC_FORMAT_JPG;
2587       type = ENCODED_ENCODED;
2588     } else if (!gst_structure_has_name (vid_struct, "image/jpeg") &&
2589         !gst_structure_has_name (vf_struct, "image/jpeg")) {
2590       self->main_format = UVC_H264_SRC_FORMAT_RAW;
2591       self->secondary_format = UVC_H264_SRC_FORMAT_RAW;
2592       type = RAW_RAW;
2593     } else {
2594       goto error_remove;
2595     }
2596   } else if (vf_caps && vid_caps) {
2597     guint32 smallest_frame_interval;
2598 
2599     if (!_extract_caps_info (vf_struct, &self->secondary_width,
2600             &self->secondary_height, &self->secondary_frame_interval))
2601       goto error_remove;
2602 
2603     if (jpg2raw == FALSE && gst_structure_has_name (vf_struct, "image/jpeg")) {
2604       type = H264_JPG;
2605       self->secondary_format = UVC_H264_SRC_FORMAT_JPG;
2606     } else {
2607       if (jpg2raw) {
2608         type = H264_JPG2RAW;
2609         self->secondary_format = UVC_H264_SRC_FORMAT_JPG;
2610       } else {
2611         type = H264_RAW;
2612         self->secondary_format = UVC_H264_SRC_FORMAT_RAW;
2613       }
2614     }
2615     smallest_frame_interval = MIN (self->main_frame_interval,
2616         self->secondary_frame_interval);
2617     /* Just to avoid a potential division by zero, set interval to 30 fps */
2618     if (smallest_frame_interval == 0)
2619       smallest_frame_interval = 333333;
2620 
2621     /* Frame interval is in 100ns units */
2622     src_caps = gst_caps_new_simple ("image/jpeg",
2623         "width", G_TYPE_INT, self->secondary_width,
2624         "height", G_TYPE_INT, self->secondary_height,
2625         "framerate", GST_TYPE_FRACTION,
2626         NSEC_PER_SEC / smallest_frame_interval, 100, NULL);
2627   } else if (vf_caps || vid_caps) {
2628     self->secondary_format = UVC_H264_SRC_FORMAT_NONE;
2629     if (vid_struct && gst_structure_has_name (vid_struct, "video/x-h264")) {
2630       type = ENCODED_NONE;
2631     } else if (vid_struct && gst_structure_has_name (vid_struct, "image/jpeg")) {
2632       type = ENCODED_NONE;
2633       self->main_format = UVC_H264_SRC_FORMAT_JPG;
2634     } else if (vf_struct && gst_structure_has_name (vf_struct, "image/jpeg")) {
2635       type = NONE_ENCODED;
2636       self->secondary_format = UVC_H264_SRC_FORMAT_JPG;
2637     } else if (vid_struct) {
2638       type = RAW_NONE;
2639       self->main_format = UVC_H264_SRC_FORMAT_RAW;
2640     } else if (vf_struct) {
2641       type = NONE_RAW;
2642       self->secondary_format = UVC_H264_SRC_FORMAT_RAW;
2643     } else {
2644       g_assert_not_reached ();
2645       type = NONE_NONE;
2646       self->main_format = UVC_H264_SRC_FORMAT_NONE;
2647     }
2648   } else {
2649     type = NONE_NONE;
2650     self->main_format = UVC_H264_SRC_FORMAT_NONE;
2651     self->secondary_format = UVC_H264_SRC_FORMAT_NONE;
2652   }
2653 
2654   switch (type) {
2655     case NONE_NONE:
2656       GST_DEBUG_OBJECT (self, "None+None");
2657       vf_pad = gst_element_get_static_pad (self->v4l2_src, "src");
2658       break;
2659     case RAW_NONE:
2660       GST_DEBUG_OBJECT (self, "Raw+None");
2661       self->vid_colorspace = gst_element_factory_make (self->colorspace_name,
2662           NULL);
2663       if (!self->vid_colorspace ||
2664           !gst_bin_add (GST_BIN (self), self->vid_colorspace))
2665         goto error_remove;
2666       gst_object_ref (self->vid_colorspace);
2667       if (!gst_element_link (self->v4l2_src, self->vid_colorspace))
2668         goto error_remove_all;
2669       vid_pad = gst_element_get_static_pad (self->vid_colorspace, "src");
2670       break;
2671     case NONE_RAW:
2672       GST_DEBUG_OBJECT (self, "None+Raw");
2673       self->vf_colorspace = gst_element_factory_make (self->colorspace_name,
2674           NULL);
2675       if (!self->vf_colorspace ||
2676           !gst_bin_add (GST_BIN (self), self->vf_colorspace))
2677         goto error_remove;
2678       gst_object_ref (self->vf_colorspace);
2679       if (!gst_element_link (self->v4l2_src, self->vf_colorspace))
2680         goto error_remove_all;
2681       vf_pad = gst_element_get_static_pad (self->vf_colorspace, "src");
2682       break;
2683     case ENCODED_NONE:
2684       GST_DEBUG_OBJECT (self, "Encoded+None");
2685       vid_pad = gst_element_get_static_pad (self->v4l2_src, "src");
2686       break;
2687     case NONE_ENCODED:
2688       GST_DEBUG_OBJECT (self, "None+Encoded");
2689       vf_pad = gst_element_get_static_pad (self->v4l2_src, "src");
2690       break;
2691     case H264_JPG:
2692       GST_DEBUG_OBJECT (self, "H264+JPG");
2693       self->mjpg_demux = gst_element_factory_make ("uvch264mjpgdemux", NULL);
2694       if (!self->mjpg_demux || !gst_bin_add (GST_BIN (self), self->mjpg_demux))
2695         goto error_remove;
2696       gst_object_ref (self->mjpg_demux);
2697       g_object_set (self->mjpg_demux, "device-fd", self->v4l2_fd,
2698           "num-clock-samples", self->num_clock_samples, NULL);
2699       if (!gst_element_link_filtered (self->v4l2_src, self->mjpg_demux,
2700               src_caps))
2701         goto error_remove_all;
2702       vid_pad = gst_element_get_static_pad (self->mjpg_demux, "h264");
2703       vf_pad = gst_element_get_static_pad (self->mjpg_demux, "jpeg");
2704       break;
2705     case H264_RAW:
2706       GST_DEBUG_OBJECT (self, "H264+Raw");
2707       self->mjpg_demux = gst_element_factory_make ("uvch264mjpgdemux", NULL);
2708       self->vf_colorspace = gst_element_factory_make (self->colorspace_name,
2709           NULL);
2710       if (!self->mjpg_demux || !self->vf_colorspace)
2711         goto error_remove;
2712       if (!gst_bin_add (GST_BIN (self), self->mjpg_demux))
2713         goto error_remove;
2714       gst_object_ref (self->mjpg_demux);
2715       g_object_set (self->mjpg_demux, "device-fd", self->v4l2_fd,
2716           "num-clock-samples", self->num_clock_samples, NULL);
2717       if (!gst_bin_add (GST_BIN (self), self->vf_colorspace)) {
2718         gst_object_unref (self->vf_colorspace);
2719         self->vf_colorspace = NULL;
2720         goto error_remove_all;
2721       }
2722       gst_object_ref (self->vf_colorspace);
2723       if (!gst_element_link_filtered (self->v4l2_src, self->mjpg_demux,
2724               src_caps))
2725         goto error_remove_all;
2726       if (!gst_element_link_pads (self->mjpg_demux, "yuy2",
2727               self->vf_colorspace, "sink"))
2728         goto error_remove_all;
2729       vid_pad = gst_element_get_static_pad (self->mjpg_demux, "h264");
2730       vf_pad = gst_element_get_static_pad (self->vf_colorspace, "src");
2731       break;
2732     case H264_JPG2RAW:
2733       GST_DEBUG_OBJECT (self, "H264+Raw(jpegdec)");
2734       self->mjpg_demux = gst_element_factory_make ("uvch264mjpgdemux", NULL);
2735       self->jpeg_dec = gst_element_factory_make (self->jpeg_decoder_name, NULL);
2736       self->vf_colorspace = gst_element_factory_make (self->colorspace_name,
2737           NULL);
2738       if (!self->mjpg_demux || !self->jpeg_dec || !self->vf_colorspace)
2739         goto error_remove;
2740       if (!gst_bin_add (GST_BIN (self), self->mjpg_demux))
2741         goto error_remove;
2742       gst_object_ref (self->mjpg_demux);
2743       g_object_set (self->mjpg_demux, "device-fd", self->v4l2_fd,
2744           "num-clock-samples", self->num_clock_samples, NULL);
2745       if (!gst_bin_add (GST_BIN (self), self->jpeg_dec)) {
2746         gst_object_unref (self->jpeg_dec);
2747         self->jpeg_dec = NULL;
2748         gst_object_unref (self->vf_colorspace);
2749         self->vf_colorspace = NULL;
2750         goto error_remove_all;
2751       }
2752       gst_object_ref (self->jpeg_dec);
2753       if (!gst_bin_add (GST_BIN (self), self->vf_colorspace)) {
2754         gst_object_unref (self->vf_colorspace);
2755         self->vf_colorspace = NULL;
2756         goto error_remove_all;
2757       }
2758       gst_object_ref (self->vf_colorspace);
2759       if (!gst_element_link_filtered (self->v4l2_src, self->mjpg_demux,
2760               src_caps))
2761         goto error_remove_all;
2762       if (!gst_element_link_pads (self->mjpg_demux, "jpeg", self->jpeg_dec,
2763               "sink"))
2764         goto error_remove_all;
2765       if (!gst_element_link (self->jpeg_dec, self->vf_colorspace))
2766         goto error_remove_all;
2767       vid_pad = gst_element_get_static_pad (self->mjpg_demux, "h264");
2768       vf_pad = gst_element_get_static_pad (self->vf_colorspace, "src");
2769       break;
2770     case RAW_RAW:
2771     {
2772       GstElement *tee = NULL;
2773 
2774       GST_DEBUG_OBJECT (self, "Raw+Raw");
2775       tee = gst_element_factory_make ("tee", NULL);
2776       if (!tee || !gst_bin_add (GST_BIN (self), tee)) {
2777         if (tee)
2778           gst_object_unref (tee);
2779         goto error_remove;
2780       }
2781       self->vf_colorspace = gst_element_factory_make (self->colorspace_name,
2782           NULL);
2783       self->vid_colorspace = gst_element_factory_make (self->colorspace_name,
2784           NULL);
2785       if (!self->vf_colorspace || !self->vid_colorspace)
2786         goto error_remove;
2787       if (!gst_bin_add (GST_BIN (self), self->vf_colorspace))
2788         goto error_remove;
2789       gst_object_ref (self->vf_colorspace);
2790       if (!gst_bin_add (GST_BIN (self), self->vid_colorspace)) {
2791         gst_object_unref (self->vid_colorspace);
2792         self->vid_colorspace = NULL;
2793         goto error_remove_all;
2794       }
2795       gst_object_ref (self->vid_colorspace);
2796       if (!gst_element_link (self->v4l2_src, tee))
2797         goto error_remove_all;
2798       if (!gst_element_link (tee, self->vf_colorspace))
2799         goto error_remove_all;
2800       if (!gst_element_link (tee, self->vid_colorspace))
2801         goto error_remove_all;
2802       vf_pad = gst_element_get_static_pad (self->vf_colorspace, "src");
2803       vid_pad = gst_element_get_static_pad (self->vid_colorspace, "src");
2804     }
2805       break;
2806     case ENCODED_ENCODED:
2807     {
2808       GstElement *tee = NULL;
2809 
2810       GST_DEBUG_OBJECT (self, "Encoded+Encoded");
2811       tee = gst_element_factory_make ("tee", NULL);
2812       if (!tee || !gst_bin_add (GST_BIN (self), tee)) {
2813         if (tee)
2814           gst_object_unref (tee);
2815         goto error_remove;
2816       }
2817       if (!gst_element_link (self->v4l2_src, tee))
2818         goto error_remove_all;
2819       vf_pad = gst_element_request_pad_simple (tee, "src_%u");
2820       vid_pad = gst_element_request_pad_simple (tee, "src_%u");
2821     }
2822       break;
2823   }
2824 
2825   if (!gst_ghost_pad_set_target (GST_GHOST_PAD (self->vidsrc), vid_pad) ||
2826       !gst_ghost_pad_set_target (GST_GHOST_PAD (self->vfsrc), vf_pad))
2827     goto error_remove_all;
2828   if (vid_pad)
2829     gst_object_unref (vid_pad);
2830   if (vf_pad)
2831     gst_object_unref (vf_pad);
2832   vid_pad = vf_pad = NULL;
2833 
2834   if (vf_caps)
2835     gst_caps_unref (vf_caps);
2836   if (vid_caps)
2837     gst_caps_unref (vid_caps);
2838   if (src_caps)
2839     gst_caps_unref (src_caps);
2840   vf_caps = vid_caps = src_caps = NULL;
2841 
2842   /* Sync children states, in sink to source order */
2843   if (self->vid_colorspace &&
2844       !gst_element_sync_state_with_parent (self->vid_colorspace))
2845     goto error_remove_all;
2846   if (self->vf_colorspace &&
2847       !gst_element_sync_state_with_parent (self->vf_colorspace))
2848     goto error_remove_all;
2849   if (self->jpeg_dec && !gst_element_sync_state_with_parent (self->jpeg_dec))
2850     goto error_remove_all;
2851   if (self->mjpg_demux &&
2852       !gst_element_sync_state_with_parent (self->mjpg_demux))
2853     goto error_remove_all;
2854   if (self->v4l2_src && !gst_element_sync_state_with_parent (self->v4l2_src))
2855     goto error_remove_all;
2856 
2857   /* Sync any remaining children states with bin's state */
2858   iter = gst_bin_iterate_elements (GST_BIN (self));
2859   iter_done = FALSE;
2860   while (!iter_done) {
2861     GstElement *child = NULL;
2862     GValue data = { 0, };
2863 
2864     switch (gst_iterator_next (iter, &data)) {
2865       case GST_ITERATOR_OK:
2866         child = g_value_get_object (&data);
2867         if (!gst_element_sync_state_with_parent (child)) {
2868           g_value_reset (&data);
2869           gst_iterator_free (iter);
2870           goto error_remove_all;
2871         }
2872         g_value_reset (&data);
2873         break;
2874       case GST_ITERATOR_RESYNC:
2875         gst_iterator_resync (iter);
2876         break;
2877       case GST_ITERATOR_ERROR:
2878         iter_done = TRUE;
2879         break;
2880       case GST_ITERATOR_DONE:
2881         iter_done = TRUE;
2882         break;
2883     }
2884   }
2885   gst_iterator_free (iter);
2886 
2887   self->reconfiguring = FALSE;
2888   return TRUE;
2889 
2890 error_remove_all:
2891   gst_uvc_h264_src_destroy_pipeline (self, FALSE);
2892 error_remove:
2893   gst_element_set_state (self->v4l2_src, GST_STATE_NULL);
2894   gst_bin_remove (GST_BIN (self), self->v4l2_src);
2895 
2896 error:
2897   if (self->v4l2_src)
2898     gst_object_unref (self->v4l2_src);
2899   self->v4l2_src = NULL;
2900   self->v4l2_fd = -1;
2901   self->h264_unit_id = 0;
2902 
2903   if (self->mjpg_demux)
2904     gst_object_unref (self->mjpg_demux);
2905   self->mjpg_demux = NULL;
2906   if (self->jpeg_dec)
2907     gst_object_unref (self->jpeg_dec);
2908   self->jpeg_dec = NULL;
2909   if (self->vid_colorspace)
2910     gst_object_unref (self->vid_colorspace);
2911   self->vid_colorspace = NULL;
2912   if (self->vf_colorspace)
2913     gst_object_unref (self->vf_colorspace);
2914   self->vf_colorspace = NULL;
2915 
2916   if (src_caps)
2917     gst_caps_unref (src_caps);
2918 
2919   if (vf_caps)
2920     gst_caps_unref (vf_caps);
2921   if (vid_caps)
2922     gst_caps_unref (vid_caps);
2923 
2924   if (vid_pad)
2925     gst_object_unref (vid_pad);
2926   if (vf_pad)
2927     gst_object_unref (vf_pad);
2928 
2929   self->reconfiguring = FALSE;
2930   return FALSE;
2931 }
2932 
2933 static GstCaps *
gst_uvc_h264_src_getcaps(GstPad * pad,GstObject * parent,GstQuery * query)2934 gst_uvc_h264_src_getcaps (GstPad * pad, GstObject * parent, GstQuery * query)
2935 {
2936   GstUvcH264Src *self = GST_UVC_H264_SRC (parent);
2937   GstCaps *template = NULL;
2938   GstCaps *result = NULL;
2939 
2940   if (pad == self->vfsrc)
2941     template = gst_static_pad_template_get_caps (&vfsrc_template);
2942   else if (pad == self->vidsrc)
2943     template = gst_static_pad_template_get_caps (&vidsrc_template);
2944   else
2945     template = gst_caps_new_empty ();
2946 
2947   if (self->v4l2_src) {
2948     GstCaps *filter;
2949     GstPad *v4l_pad = gst_element_get_static_pad (self->v4l2_src, "src");
2950     GstCaps *v4l_caps = NULL;
2951     GstCaps *new_caps = NULL;
2952 
2953     gst_query_parse_caps (query, &filter);
2954     v4l_caps = gst_pad_query_caps (v4l_pad, filter);
2955     new_caps = gst_uvc_h264_src_transform_caps (self, v4l_caps);
2956 
2957     result = gst_caps_intersect (new_caps, template);
2958     gst_object_unref (v4l_pad);
2959     gst_caps_unref (v4l_caps);
2960     gst_caps_unref (new_caps);
2961     gst_caps_unref (template);
2962   } else {
2963     result = template;
2964   }
2965 
2966   return result;
2967 }
2968 
2969 static gboolean
gst_uvc_h264_src_query(GstPad * pad,GstObject * parent,GstQuery * query)2970 gst_uvc_h264_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
2971 {
2972   gboolean ret;
2973 
2974   switch (GST_QUERY_TYPE (query)) {
2975     case GST_QUERY_CAPS:{
2976       GstCaps *caps;
2977 
2978       caps = gst_uvc_h264_src_getcaps (pad, parent, query);
2979       gst_query_set_caps_result (query, caps);
2980       gst_caps_unref (caps);
2981       ret = TRUE;
2982       break;
2983     }
2984     default:
2985       ret = gst_pad_query_default (pad, parent, query);
2986       break;
2987   }
2988   return ret;
2989 }
2990 
2991 
2992 static gboolean
gst_uvc_h264_src_set_mode(GstBaseCameraSrc * bcamsrc,GstCameraBinMode mode)2993 gst_uvc_h264_src_set_mode (GstBaseCameraSrc * bcamsrc, GstCameraBinMode mode)
2994 {
2995   GstUvcH264Src *self = GST_UVC_H264_SRC (bcamsrc);
2996 
2997   GST_DEBUG_OBJECT (self, "set mode to %d", mode);
2998 
2999   return (mode == MODE_VIDEO);
3000 }
3001 
3002 static gboolean
gst_uvc_h264_src_start_capture(GstBaseCameraSrc * camerasrc)3003 gst_uvc_h264_src_start_capture (GstBaseCameraSrc * camerasrc)
3004 {
3005   GstUvcH264Src *self = GST_UVC_H264_SRC (camerasrc);
3006   gboolean ret = TRUE;
3007 
3008   GST_DEBUG_OBJECT (self, "start capture");
3009 
3010   if (!self->started) {
3011     self->started = TRUE;
3012     if (GST_STATE (self) >= GST_STATE_READY) {
3013       ret = gst_uvc_h264_src_construct_pipeline (GST_BASE_CAMERA_SRC (self));
3014       if (!ret) {
3015         GST_DEBUG_OBJECT (self, "Could not start capture");
3016         self->started = FALSE;
3017         gst_uvc_h264_src_construct_pipeline (GST_BASE_CAMERA_SRC (self));
3018       }
3019     }
3020   }
3021 
3022   return ret;
3023 }
3024 
3025 static void
gst_uvc_h264_src_stop_capture(GstBaseCameraSrc * camerasrc)3026 gst_uvc_h264_src_stop_capture (GstBaseCameraSrc * camerasrc)
3027 {
3028   GstUvcH264Src *self = GST_UVC_H264_SRC (camerasrc);
3029 
3030   GST_DEBUG_OBJECT (self, "stop capture");
3031 
3032   if (self->started) {
3033     self->started = FALSE;
3034     if (GST_STATE (self) >= GST_STATE_READY)
3035       gst_uvc_h264_src_construct_pipeline (GST_BASE_CAMERA_SRC (self));
3036     gst_base_camera_src_finish_capture (camerasrc);
3037   }
3038 }
3039 
3040 static void
gst_uvc_h264_src_pad_linking_cb(GstPad * pad,GstPad * peer,gpointer user_data)3041 gst_uvc_h264_src_pad_linking_cb (GstPad * pad,
3042     GstPad * peer, gpointer user_data)
3043 {
3044   GstUvcH264Src *self = GST_UVC_H264_SRC (user_data);
3045   gchar *pad_name = gst_pad_get_name (pad);
3046 
3047   GST_DEBUG_OBJECT (self, "Pad %s was (un)linked. Renegotiating", pad_name);
3048   g_free (pad_name);
3049   if (GST_STATE (self) >= GST_STATE_READY)
3050     gst_uvc_h264_src_construct_pipeline (GST_BASE_CAMERA_SRC (self));
3051 }
3052 
3053 
3054 static GstStateChangeReturn
gst_uvc_h264_src_change_state(GstElement * element,GstStateChange trans)3055 gst_uvc_h264_src_change_state (GstElement * element, GstStateChange trans)
3056 {
3057   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3058   GstUvcH264Src *self = GST_UVC_H264_SRC (element);
3059 
3060   switch (trans) {
3061     case GST_STATE_CHANGE_NULL_TO_READY:
3062       if (!ensure_v4l2src (self)) {
3063         ret = GST_STATE_CHANGE_FAILURE;
3064         goto end;
3065       }
3066       gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
3067       break;
3068     case GST_STATE_CHANGE_READY_TO_PAUSED:
3069     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
3070       if (!self->v4l2_src)
3071         gst_uvc_h264_src_construct_pipeline (GST_BASE_CAMERA_SRC (self));
3072       break;
3073     default:
3074       break;
3075   }
3076 
3077   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, trans);
3078 
3079   if (ret == GST_STATE_CHANGE_FAILURE)
3080     goto end;
3081 
3082   switch (trans) {
3083     case GST_STATE_CHANGE_READY_TO_NULL:
3084       gst_uvc_h264_src_destroy_pipeline (self, TRUE);
3085       break;
3086     default:
3087       break;
3088   }
3089 
3090 
3091 end:
3092   return ret;
3093 }
3094