mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-20 00:31:13 +00:00
v4l2slh264dec: Add output format negotiation
This allow negotiating the output format through caps. Some drivers can pipeline the decoder buffer through an image processor. This only support colorspace conversion for now.
This commit is contained in:
parent
6494d7b056
commit
390cbe1f00
4 changed files with 124 additions and 10 deletions
|
@ -138,6 +138,16 @@ gst_v4l2_codec_h264_dec_negotiate (GstVideoDecoder * decoder)
|
||||||
{
|
{
|
||||||
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder);
|
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder);
|
||||||
GstH264Decoder *h264dec = GST_H264_DECODER (decoder);
|
GstH264Decoder *h264dec = GST_H264_DECODER (decoder);
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
struct v4l2_ext_control control[] = {
|
||||||
|
{
|
||||||
|
.id = V4L2_CID_MPEG_VIDEO_H264_SPS,
|
||||||
|
.ptr = &self->sps,
|
||||||
|
.size = sizeof (self->sps),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
GstCaps *filter, *caps;
|
||||||
|
|
||||||
/* Ignore downstream renegotiation request. */
|
/* Ignore downstream renegotiation request. */
|
||||||
if (!self->need_negotiation)
|
if (!self->need_negotiation)
|
||||||
|
@ -164,18 +174,29 @@ gst_v4l2_codec_h264_dec_negotiate (GstVideoDecoder * decoder)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO set sequence parameter control, this is needed to negotiate a
|
if (!gst_v4l2_decoder_set_controls (self->decoder, NULL, control,
|
||||||
* format with the help of the driver */
|
G_N_ELEMENTS (control))) {
|
||||||
|
GST_ELEMENT_ERROR (decoder, RESOURCE, WRITE,
|
||||||
|
("Driver does not support the selected stream."), (NULL));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!gst_v4l2_decoder_select_src_format (self->decoder, &self->vinfo)) {
|
filter = gst_v4l2_decoder_enum_src_formats (self->decoder);
|
||||||
|
GST_DEBUG_OBJECT (self, "Supported output formats: %" GST_PTR_FORMAT, filter);
|
||||||
|
|
||||||
|
caps = gst_pad_peer_query_caps (decoder->srcpad, filter);
|
||||||
|
gst_caps_unref (filter);
|
||||||
|
GST_DEBUG_OBJECT (self, "Peer supported formats: %" GST_PTR_FORMAT, caps);
|
||||||
|
|
||||||
|
if (!gst_v4l2_decoder_select_src_format (self->decoder, caps, &self->vinfo)) {
|
||||||
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
|
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
|
||||||
("Unsupported bitdepth/chroma format"),
|
("Unsupported bitdepth/chroma format"),
|
||||||
("No support for %ux%u %ubit chroma IDC %i", self->coded_width,
|
("No support for %ux%u %ubit chroma IDC %i", self->coded_width,
|
||||||
self->coded_height, self->bitdepth, self->chroma_format_idc));
|
self->coded_height, self->bitdepth, self->chroma_format_idc));
|
||||||
|
gst_caps_unref (caps);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
gst_caps_unref (caps);
|
||||||
/* TODO some decoders supports color convertion and scaling */
|
|
||||||
|
|
||||||
if (self->output_state)
|
if (self->output_state)
|
||||||
gst_video_codec_state_unref (self->output_state);
|
gst_video_codec_state_unref (self->output_state);
|
||||||
|
|
|
@ -254,19 +254,108 @@ gst_v4l2_decoder_set_sink_fmt (GstV4l2Decoder * self, guint32 pix_fmt,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
GstCaps *
|
||||||
gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstVideoInfo * info)
|
gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self)
|
||||||
{
|
{
|
||||||
gint ret;
|
gint ret;
|
||||||
struct v4l2_format fmt = {
|
struct v4l2_format fmt = {
|
||||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
|
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
|
||||||
};
|
};
|
||||||
|
GstVideoFormat format;
|
||||||
|
GstCaps *caps;
|
||||||
|
GValue list = G_VALUE_INIT;
|
||||||
|
GValue value = G_VALUE_INIT;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
g_return_val_if_fail (self->opened, FALSE);
|
||||||
|
|
||||||
ret = ioctl (self->video_fd, VIDIOC_G_FMT, &fmt);
|
ret = ioctl (self->video_fd, VIDIOC_G_FMT, &fmt);
|
||||||
|
if (ret < 0) {
|
||||||
|
GST_ERROR_OBJECT (self, "VIDIOC_G_FMT failed: %s", g_strerror (errno));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We first place a structure with the default pixel format */
|
||||||
|
if (gst_v4l2_format_to_video_format (fmt.fmt.pix_mp.pixelformat, &format))
|
||||||
|
caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING,
|
||||||
|
gst_video_format_to_string (format), NULL);
|
||||||
|
else
|
||||||
|
caps = gst_caps_new_empty ();
|
||||||
|
|
||||||
|
/* And then enumerate other possible formats and place that as a second
|
||||||
|
* structure in the caps */
|
||||||
|
g_value_init (&list, GST_TYPE_LIST);
|
||||||
|
g_value_init (&value, G_TYPE_STRING);
|
||||||
|
|
||||||
|
for (i = 0; ret >= 0; i++) {
|
||||||
|
struct v4l2_fmtdesc fmtdesc = { i, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, };
|
||||||
|
|
||||||
|
ret = ioctl (self->video_fd, VIDIOC_ENUM_FMT, &fmtdesc);
|
||||||
|
if (ret < 0) {
|
||||||
|
if (errno != EINVAL)
|
||||||
|
GST_ERROR_OBJECT (self, "VIDIOC_ENUM_FMT failed: %s",
|
||||||
|
g_strerror (errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gst_v4l2_format_to_video_format (fmtdesc.pixelformat, &format)) {
|
||||||
|
g_value_set_static_string (&value, gst_video_format_to_string (format));
|
||||||
|
gst_value_list_append_value (&list, &value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_value_reset (&value);
|
||||||
|
|
||||||
|
if (gst_value_list_get_size (&list) > 0) {
|
||||||
|
GstStructure *str = gst_structure_new_empty ("video/x-raw");
|
||||||
|
gst_structure_take_value (str, "format", &list);
|
||||||
|
gst_caps_append_structure (caps, str);
|
||||||
|
} else {
|
||||||
|
g_value_reset (&list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps,
|
||||||
|
GstVideoInfo * info)
|
||||||
|
{
|
||||||
|
gint ret;
|
||||||
|
struct v4l2_format fmt = {
|
||||||
|
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
|
||||||
|
};
|
||||||
|
GstStructure *str;
|
||||||
|
const gchar *format_str;
|
||||||
|
GstVideoFormat format;
|
||||||
|
guint32 pix_fmt;
|
||||||
|
|
||||||
|
if (gst_caps_is_empty (caps))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ret = ioctl (self->video_fd, VIDIOC_G_FMT, &fmt);
|
||||||
|
if (ret < 0) {
|
||||||
|
GST_ERROR_OBJECT (self, "VIDIOC_G_FMT failed: %s", g_strerror (errno));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
caps = gst_caps_make_writable (caps);
|
||||||
|
str = gst_caps_get_structure (caps, 0);
|
||||||
|
gst_structure_fixate_field (str, "format");
|
||||||
|
|
||||||
|
format_str = gst_structure_get_string (str, "format");
|
||||||
|
format = gst_video_format_from_string (format_str);
|
||||||
|
|
||||||
|
if (gst_v4l2_format_from_video_format (format, &pix_fmt) &&
|
||||||
|
pix_fmt != fmt.fmt.pix_mp.pixelformat) {
|
||||||
|
GST_DEBUG_OBJECT (self, "Trying to use peer format: %s ", format_str);
|
||||||
|
fmt.fmt.pix_mp.pixelformat = pix_fmt;
|
||||||
|
|
||||||
|
ret = ioctl (self->video_fd, VIDIOC_S_FMT, &fmt);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
GST_ERROR_OBJECT (self, "VIDIOC_S_FMT failed: %s", g_strerror (errno));
|
GST_ERROR_OBJECT (self, "VIDIOC_S_FMT failed: %s", g_strerror (errno));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!gst_v4l2_format_to_video_info (&fmt, info)) {
|
if (!gst_v4l2_format_to_video_info (&fmt, info)) {
|
||||||
GST_ERROR_OBJECT (self, "Unsupported V4L2 pixelformat %" GST_FOURCC_FORMAT,
|
GST_ERROR_OBJECT (self, "Unsupported V4L2 pixelformat %" GST_FOURCC_FORMAT,
|
||||||
|
@ -466,8 +555,8 @@ gst_v4l2_decoder_set_controls (GstV4l2Decoder * self, GstV4l2Request * request,
|
||||||
struct v4l2_ext_controls controls = {
|
struct v4l2_ext_controls controls = {
|
||||||
.controls = control,
|
.controls = control,
|
||||||
.count = count,
|
.count = count,
|
||||||
.request_fd = request->fd,
|
.request_fd = request ? request->fd : 0,
|
||||||
.which = V4L2_CTRL_WHICH_REQUEST_VAL,
|
.which = request ? V4L2_CTRL_WHICH_REQUEST_VAL : 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
ret = ioctl (self->video_fd, VIDIOC_S_EXT_CTRLS, &controls);
|
ret = ioctl (self->video_fd, VIDIOC_S_EXT_CTRLS, &controls);
|
||||||
|
|
|
@ -51,7 +51,10 @@ gboolean gst_v4l2_decoder_enum_sink_fmt (GstV4l2Decoder * self,
|
||||||
gboolean gst_v4l2_decoder_set_sink_fmt (GstV4l2Decoder * self, guint32 fmt,
|
gboolean gst_v4l2_decoder_set_sink_fmt (GstV4l2Decoder * self, guint32 fmt,
|
||||||
gint width, gint height);
|
gint width, gint height);
|
||||||
|
|
||||||
|
GstCaps * gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self);
|
||||||
|
|
||||||
gboolean gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self,
|
gboolean gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self,
|
||||||
|
GstCaps * caps,
|
||||||
GstVideoInfo * info);
|
GstVideoInfo * info);
|
||||||
|
|
||||||
gint gst_v4l2_decoder_request_buffers (GstV4l2Decoder * self,
|
gint gst_v4l2_decoder_request_buffers (GstV4l2Decoder * self,
|
||||||
|
|
|
@ -33,6 +33,7 @@ struct FormatEntry
|
||||||
|
|
||||||
static struct FormatEntry format_map[] = {
|
static struct FormatEntry format_map[] = {
|
||||||
{V4L2_PIX_FMT_NV12, 1, GST_VIDEO_FORMAT_NV12, 8, 420},
|
{V4L2_PIX_FMT_NV12, 1, GST_VIDEO_FORMAT_NV12, 8, 420},
|
||||||
|
{V4L2_PIX_FMT_YUYV, 1, GST_VIDEO_FORMAT_YUY2, 8, 422},
|
||||||
{0,}
|
{0,}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue