mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
v4l2codecs: h264: Add API checks
Check that the V4L2 H264 controls' sizes match our expectation. If not, then probably there's an API mismatch which will cause errors or decoding corruption. Also, print a warning if the kernel version is too old. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1624>
This commit is contained in:
parent
7d6b06ca1b
commit
010565eb7f
3 changed files with 110 additions and 0 deletions
|
@ -26,6 +26,12 @@
|
||||||
#include "gstv4l2codecpool.h"
|
#include "gstv4l2codecpool.h"
|
||||||
#include "linux/v4l2-controls.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);
|
GST_DEBUG_CATEGORY_STATIC (v4l2_h264dec_debug);
|
||||||
#define GST_CAT_DEFAULT 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
|
static gboolean
|
||||||
gst_v4l2_codec_h264_dec_open (GstVideoDecoder * decoder)
|
gst_v4l2_codec_h264_dec_open (GstVideoDecoder * decoder)
|
||||||
{
|
{
|
||||||
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder);
|
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder);
|
||||||
|
guint version;
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
struct v4l2_ext_control control[] = {
|
struct v4l2_ext_control control[] = {
|
||||||
{
|
{
|
||||||
|
@ -131,6 +189,20 @@ gst_v4l2_codec_h264_dec_open (GstVideoDecoder * decoder)
|
||||||
return FALSE;
|
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,
|
if (!gst_v4l2_decoder_get_controls (self->decoder, control,
|
||||||
G_N_ELEMENTS (control))) {
|
G_N_ELEMENTS (control))) {
|
||||||
GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE,
|
GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE,
|
||||||
|
|
|
@ -74,6 +74,7 @@ struct _GstV4l2Decoder
|
||||||
gint video_fd;
|
gint video_fd;
|
||||||
GstQueueArray *request_pool;
|
GstQueueArray *request_pool;
|
||||||
GstQueueArray *pending_requests;
|
GstQueueArray *pending_requests;
|
||||||
|
guint version;
|
||||||
|
|
||||||
enum v4l2_buf_type src_buf_type;
|
enum v4l2_buf_type src_buf_type;
|
||||||
enum v4l2_buf_type sink_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);
|
return gst_object_ref_sink (decoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guint
|
||||||
|
gst_v4l2_decoder_get_version (GstV4l2Decoder * self)
|
||||||
|
{
|
||||||
|
return self->version;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_v4l2_decoder_open (GstV4l2Decoder * self)
|
gst_v4l2_decoder_open (GstV4l2Decoder * self)
|
||||||
{
|
{
|
||||||
|
@ -176,6 +183,8 @@ gst_v4l2_decoder_open (GstV4l2Decoder * self)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self->version = querycap.version;
|
||||||
|
|
||||||
if (querycap.capabilities & V4L2_CAP_DEVICE_CAPS)
|
if (querycap.capabilities & V4L2_CAP_DEVICE_CAPS)
|
||||||
capabilities = querycap.device_caps;
|
capabilities = querycap.device_caps;
|
||||||
else
|
else
|
||||||
|
@ -717,6 +726,29 @@ gst_v4l2_decoder_get_controls (GstV4l2Decoder * self,
|
||||||
return TRUE;
|
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
|
void
|
||||||
gst_v4l2_decoder_install_properties (GObjectClass * gobject_class,
|
gst_v4l2_decoder_install_properties (GObjectClass * gobject_class,
|
||||||
gint prop_offset, GstV4l2CodecDevice * device)
|
gint prop_offset, GstV4l2CodecDevice * device)
|
||||||
|
|
|
@ -35,6 +35,8 @@ typedef struct _GstV4l2Request GstV4l2Request;
|
||||||
|
|
||||||
GstV4l2Decoder * gst_v4l2_decoder_new (GstV4l2CodecDevice * device);
|
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_open (GstV4l2Decoder * decoder);
|
||||||
|
|
||||||
gboolean gst_v4l2_decoder_close (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,
|
struct v4l2_ext_control * control,
|
||||||
guint count);
|
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,
|
void gst_v4l2_decoder_install_properties (GObjectClass * gobject_class,
|
||||||
gint prop_offset,
|
gint prop_offset,
|
||||||
GstV4l2CodecDevice * device);
|
GstV4l2CodecDevice * device);
|
||||||
|
|
Loading…
Reference in a new issue