diff --git a/sys/v4l2codecs/gstv4l2codech264dec.c b/sys/v4l2codecs/gstv4l2codech264dec.c index 892c8a684f..62fa7f3c74 100644 --- a/sys/v4l2codecs/gstv4l2codech264dec.c +++ b/sys/v4l2codecs/gstv4l2codech264dec.c @@ -26,6 +26,12 @@ #include "gstv4l2codecpool.h" #include "linux/v4l2-controls.h" +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) + +#define V4L2_MIN_KERNEL_VER_MAJOR 5 +#define V4L2_MIN_KERNEL_VER_MINOR 11 +#define V4L2_MIN_KERNEL_VERSION KERNEL_VERSION(V4L2_MIN_KERNEL_VER_MAJOR, V4L2_MIN_KERNEL_VER_MINOR, 0) + GST_DEBUG_CATEGORY_STATIC (v4l2_h264dec_debug); #define GST_CAT_DEFAULT v4l2_h264dec_debug @@ -109,10 +115,62 @@ needs_start_codes (GstV4l2CodecH264Dec * self) } +static gboolean +gst_v4l2_decoder_h264_api_check (GstV4l2CodecH264Dec * self) +{ + guint i, ret_size; + /* *INDENT-OFF* */ + struct + { + unsigned int id; + unsigned int size; + } controls[] = { + { + .id = V4L2_CID_MPEG_VIDEO_H264_SPS, + .size = sizeof(struct v4l2_ctrl_h264_sps), + }, { + .id = V4L2_CID_MPEG_VIDEO_H264_PPS, + .size = sizeof(struct v4l2_ctrl_h264_pps), + }, { + .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + .size = sizeof(struct v4l2_ctrl_h264_scaling_matrix), + }, { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + .size = sizeof(struct v4l2_ctrl_h264_decode_params), + }, { + .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, + .size = sizeof(struct v4l2_ctrl_h264_slice_params), + }, { + .id = V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS, + .size = sizeof(struct v4l2_ctrl_h264_pred_weights), + } + }; + /* *INDENT-ON* */ + + /* + * Compatibility check: make sure the pointer controls are + * the right size. + */ + for (i = 0; i < G_N_ELEMENTS (controls); i++) { + if (gst_v4l2_decoder_query_control_size (self->decoder, controls[i].id, + &ret_size) && ret_size != controls[i].size) { + GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, + ("H264 API mismatch!"), + ("%d control size mismatch: got %d bytes but %d expected.", + controls[i].id, ret_size, controls[i].size)); + return FALSE; + } + } + + return TRUE; +} + static gboolean gst_v4l2_codec_h264_dec_open (GstVideoDecoder * decoder) { GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder); + guint version; + /* *INDENT-OFF* */ struct v4l2_ext_control control[] = { { @@ -131,6 +189,20 @@ gst_v4l2_codec_h264_dec_open (GstVideoDecoder * decoder) return FALSE; } + version = gst_v4l2_decoder_get_version (self->decoder); + if (version < V4L2_MIN_KERNEL_VERSION) + GST_WARNING_OBJECT (self, + "V4L2 API v%u.%u too old, at least v%u.%u required", + (version >> 16) & 0xff, (version >> 8) & 0xff, + V4L2_MIN_KERNEL_VER_MAJOR, V4L2_MIN_KERNEL_VER_MINOR); + + if (!gst_v4l2_decoder_h264_api_check (self)) { + GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, + ("Failed to open H264 decoder"), + ("gst_v4l2_decoder_h264_api_check() failed")); + return FALSE; + } + if (!gst_v4l2_decoder_get_controls (self->decoder, control, G_N_ELEMENTS (control))) { GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE, diff --git a/sys/v4l2codecs/gstv4l2decoder.c b/sys/v4l2codecs/gstv4l2decoder.c index 6df7608845..22937dd5ac 100644 --- a/sys/v4l2codecs/gstv4l2decoder.c +++ b/sys/v4l2codecs/gstv4l2decoder.c @@ -74,6 +74,7 @@ struct _GstV4l2Decoder gint video_fd; GstQueueArray *request_pool; GstQueueArray *pending_requests; + guint version; enum v4l2_buf_type src_buf_type; enum v4l2_buf_type sink_buf_type; @@ -148,6 +149,12 @@ gst_v4l2_decoder_new (GstV4l2CodecDevice * device) return gst_object_ref_sink (decoder); } +guint +gst_v4l2_decoder_get_version (GstV4l2Decoder * self) +{ + return self->version; +} + gboolean gst_v4l2_decoder_open (GstV4l2Decoder * self) { @@ -176,6 +183,8 @@ gst_v4l2_decoder_open (GstV4l2Decoder * self) return FALSE; } + self->version = querycap.version; + if (querycap.capabilities & V4L2_CAP_DEVICE_CAPS) capabilities = querycap.device_caps; else @@ -717,6 +726,29 @@ gst_v4l2_decoder_get_controls (GstV4l2Decoder * self, return TRUE; } +gboolean +gst_v4l2_decoder_query_control_size (GstV4l2Decoder * self, + unsigned int control_id, unsigned int *control_size) +{ + gint ret; + struct v4l2_query_ext_ctrl control = { + .id = control_id, + }; + + *control_size = 0; + + ret = ioctl (self->video_fd, VIDIOC_QUERY_EXT_CTRL, &control); + if (ret < 0) + /* + * It's not an error if a control is not supported by this driver. + * Return false but don't print any error. + */ + return FALSE; + + *control_size = control.elem_size; + return TRUE; +} + void gst_v4l2_decoder_install_properties (GObjectClass * gobject_class, gint prop_offset, GstV4l2CodecDevice * device) diff --git a/sys/v4l2codecs/gstv4l2decoder.h b/sys/v4l2codecs/gstv4l2decoder.h index cfc3f669be..541bab1907 100644 --- a/sys/v4l2codecs/gstv4l2decoder.h +++ b/sys/v4l2codecs/gstv4l2decoder.h @@ -35,6 +35,8 @@ typedef struct _GstV4l2Request GstV4l2Request; GstV4l2Decoder * gst_v4l2_decoder_new (GstV4l2CodecDevice * device); +guint gst_v4l2_decoder_get_version (GstV4l2Decoder * self); + gboolean gst_v4l2_decoder_open (GstV4l2Decoder * decoder); gboolean gst_v4l2_decoder_close (GstV4l2Decoder * decoder); @@ -81,6 +83,10 @@ gboolean gst_v4l2_decoder_get_controls (GstV4l2Decoder * self, struct v4l2_ext_control * control, guint count); +gboolean gst_v4l2_decoder_query_control_size (GstV4l2Decoder * self, + unsigned int control_id, + unsigned int *control_size); + void gst_v4l2_decoder_install_properties (GObjectClass * gobject_class, gint prop_offset, GstV4l2CodecDevice * device);