{
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (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. */
if (!self->need_negotiation)
return FALSE;
}
- /* TODO set sequence parameter control, this is needed to negotiate a
- * format with the help of the driver */
+ if (!gst_v4l2_decoder_set_controls (self->decoder, NULL, control,
+ G_N_ELEMENTS (control))) {
+ GST_ELEMENT_ERROR (decoder, RESOURCE, WRITE,
+ ("Driver does not support the selected stream."), (NULL));
+ return FALSE;
+ }
+
+ filter = gst_v4l2_decoder_enum_src_formats (self->decoder);
+ GST_DEBUG_OBJECT (self, "Supported output formats: %" GST_PTR_FORMAT, filter);
- if (!gst_v4l2_decoder_select_src_format (self->decoder, &self->vinfo)) {
+ 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,
("Unsupported bitdepth/chroma format"),
("No support for %ux%u %ubit chroma IDC %i", self->coded_width,
self->coded_height, self->bitdepth, self->chroma_format_idc));
+ gst_caps_unref (caps);
return FALSE;
}
-
- /* TODO some decoders supports color convertion and scaling */
+ gst_caps_unref (caps);
if (self->output_state)
gst_video_codec_state_unref (self->output_state);
return TRUE;
}
+GstCaps *
+gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self)
+{
+ gint ret;
+ struct v4l2_format fmt = {
+ .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);
+ 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, GstVideoInfo * info)
+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_S_FMT failed: %s", g_strerror (errno));
+ 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) {
+ GST_ERROR_OBJECT (self, "VIDIOC_S_FMT failed: %s", g_strerror (errno));
+ return FALSE;
+ }
+ }
+
if (!gst_v4l2_format_to_video_info (&fmt, info)) {
GST_ERROR_OBJECT (self, "Unsupported V4L2 pixelformat %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (fmt.fmt.pix_mp.pixelformat));
struct v4l2_ext_controls controls = {
.controls = control,
.count = count,
- .request_fd = request->fd,
- .which = V4L2_CTRL_WHICH_REQUEST_VAL,
+ .request_fd = request ? request->fd : 0,
+ .which = request ? V4L2_CTRL_WHICH_REQUEST_VAL : 0,
};
ret = ioctl (self->video_fd, VIDIOC_S_EXT_CTRLS, &controls);