mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
v4l2codecs: Implement H264 format negotiation
This commit is contained in:
parent
020a019fd6
commit
7ae57631d4
3 changed files with 178 additions and 10 deletions
|
@ -22,6 +22,7 @@
|
|||
#endif
|
||||
|
||||
#include "gstv4l2codech264dec.h"
|
||||
#include "linux/h264-ctrls.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (v4l2_h264dec_debug);
|
||||
#define GST_CAT_DEFAULT v4l2_h264dec_debug
|
||||
|
@ -49,9 +50,13 @@ struct _GstV4l2CodecH264Dec
|
|||
GstH264Decoder parent;
|
||||
GstV4l2Decoder *decoder;
|
||||
GstVideoCodecState *output_state;
|
||||
GstVideoFormat out_format;
|
||||
gint width;
|
||||
gint height;
|
||||
GstVideoInfo vinfo;
|
||||
gint display_width;
|
||||
gint display_height;
|
||||
gint coded_width;
|
||||
gint coded_height;
|
||||
guint bitdepth;
|
||||
guint chroma_format_idc;
|
||||
};
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstV4l2CodecH264Dec,
|
||||
|
@ -63,12 +68,23 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstV4l2CodecH264Dec,
|
|||
static gboolean
|
||||
gst_v4l2_codec_h264_dec_open (GstVideoDecoder * decoder)
|
||||
{
|
||||
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder);
|
||||
|
||||
if (!gst_v4l2_decoder_open (self->decoder)) {
|
||||
GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE,
|
||||
("Failed to open H264 decoder"),
|
||||
("gst_v4l2_decoder_open() failed: %s", g_strerror (errno)));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4l2_codec_h264_dec_close (GstVideoDecoder * decoder)
|
||||
{
|
||||
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder);
|
||||
gst_v4l2_decoder_close (self->decoder);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -90,14 +106,39 @@ gst_v4l2_codec_h264_dec_negotiate (GstVideoDecoder * decoder)
|
|||
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder);
|
||||
GstH264Decoder *h264dec = GST_H264_DECODER (decoder);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "negotiate");
|
||||
GST_DEBUG_OBJECT (self, "Negotiate");
|
||||
|
||||
/* TODO drain / reset */
|
||||
|
||||
if (!gst_v4l2_decoder_set_sink_fmt (self->decoder, V4L2_PIX_FMT_H264_SLICE,
|
||||
self->coded_width, self->coded_height)) {
|
||||
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
|
||||
("Failed to configure H264 decoder"),
|
||||
("gst_v4l2_decoder_set_sink_fmt() failed: %s", g_strerror (errno)));
|
||||
gst_v4l2_decoder_close (self->decoder);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* TODO set sequence parameter control, this is needed to negotiate a
|
||||
* format with the help of the driver */
|
||||
|
||||
if (!gst_v4l2_decoder_select_src_format (self->decoder, &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));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* TODO some decoders supports color convertion and scaling */
|
||||
|
||||
if (self->output_state)
|
||||
gst_video_codec_state_unref (self->output_state);
|
||||
|
||||
self->output_state =
|
||||
gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
|
||||
self->out_format, self->width, self->height, h264dec->input_state);
|
||||
self->vinfo.finfo->format, self->display_width,
|
||||
self->display_height, h264dec->input_state);
|
||||
|
||||
self->output_state->caps = gst_video_info_to_caps (&self->output_state->info);
|
||||
|
||||
|
@ -116,7 +157,51 @@ static gboolean
|
|||
gst_v4l2_codec_h264_dec_new_sequence (GstH264Decoder * decoder,
|
||||
const GstH264SPS * sps, gint max_dpb_size)
|
||||
{
|
||||
/* TODO check if we need to setup a new format */
|
||||
GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder);
|
||||
gint crop_width = sps->width;
|
||||
gint crop_height = sps->height;
|
||||
gboolean negotiation_needed = FALSE;
|
||||
|
||||
if (self->vinfo.finfo->format == GST_VIDEO_FORMAT_UNKNOWN)
|
||||
negotiation_needed = TRUE;
|
||||
|
||||
if (sps->frame_cropping_flag) {
|
||||
crop_width = sps->crop_rect_width;
|
||||
crop_height = sps->crop_rect_height;
|
||||
}
|
||||
|
||||
if (self->display_width != crop_width || self->display_height != crop_height
|
||||
|| self->coded_width != sps->width || self->coded_height != sps->height) {
|
||||
self->display_width = crop_width;
|
||||
self->display_height = crop_height;
|
||||
self->coded_width = sps->width;
|
||||
self->coded_height = sps->height;
|
||||
negotiation_needed = TRUE;
|
||||
GST_INFO_OBJECT (self, "Resolution changed to %dx%d (%ix%i)",
|
||||
self->display_width, self->display_height,
|
||||
self->coded_width, self->coded_height);
|
||||
}
|
||||
|
||||
if (self->bitdepth != sps->bit_depth_luma_minus8 + 8) {
|
||||
self->bitdepth = sps->bit_depth_luma_minus8 + 8;
|
||||
negotiation_needed = TRUE;
|
||||
GST_INFO_OBJECT (self, "Bitdepth changed to %u", self->bitdepth);
|
||||
}
|
||||
|
||||
if (self->chroma_format_idc != sps->chroma_format_idc) {
|
||||
self->chroma_format_idc = sps->chroma_format_idc;
|
||||
negotiation_needed = TRUE;
|
||||
GST_INFO_OBJECT (self, "Chroma format changed to %i",
|
||||
self->chroma_format_idc);
|
||||
}
|
||||
|
||||
if (negotiation_needed) {
|
||||
if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
|
||||
GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -124,6 +209,7 @@ static gboolean
|
|||
gst_v4l2_codec_h264_dec_start_picture (GstH264Decoder * decoder,
|
||||
GstH264Picture * picture, GstH264Slice * slice, GstH264Dpb * dpb)
|
||||
{
|
||||
/* Fill v4l2_ctrl_h264_decode_params */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -131,6 +217,7 @@ static GstFlowReturn
|
|||
gst_v4l2_codec_h264_dec_output_picture (GstH264Decoder * decoder,
|
||||
GstH264Picture * picture)
|
||||
{
|
||||
/* Fill vl2_ctrl_h264_slice_params */
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
|
@ -186,6 +273,7 @@ gst_v4l2_codec_h264_dec_subinit (GstV4l2CodecH264Dec * self,
|
|||
GstV4l2CodecH264DecClass * klass)
|
||||
{
|
||||
self->decoder = gst_v4l2_decoder_new (klass->device);
|
||||
gst_video_info_init (&self->vinfo);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#endif
|
||||
|
||||
#include "gstv4l2decoder.h"
|
||||
#include "gstv4l2format.h"
|
||||
#include "linux/media.h"
|
||||
#include "linux/videodev2.h"
|
||||
|
||||
|
@ -62,10 +63,7 @@ gst_v4l2_decoder_finalize (GObject * obj)
|
|||
{
|
||||
GstV4l2Decoder *self = GST_V4L2_DECODER (obj);
|
||||
|
||||
if (self->media_fd)
|
||||
close (self->media_fd);
|
||||
if (self->video_fd)
|
||||
close (self->media_fd);
|
||||
gst_v4l2_decoder_close (self);
|
||||
|
||||
g_free (self->media_device);
|
||||
g_free (self->video_device);
|
||||
|
@ -127,6 +125,21 @@ gst_v4l2_decoder_open (GstV4l2Decoder * self)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_v4l2_decoder_close (GstV4l2Decoder * self)
|
||||
{
|
||||
if (self->media_fd)
|
||||
close (self->media_fd);
|
||||
if (self->video_fd)
|
||||
close (self->media_fd);
|
||||
|
||||
self->media_fd = 0;
|
||||
self->video_fd = 0;
|
||||
self->opened = FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_v4l2_decoder_enum_sink_fmt (GstV4l2Decoder * self, gint i,
|
||||
guint32 * out_fmt)
|
||||
|
@ -150,6 +163,65 @@ gst_v4l2_decoder_enum_sink_fmt (GstV4l2Decoder * self, gint i,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_v4l2_decoder_set_sink_fmt (GstV4l2Decoder * self, guint32 pix_fmt,
|
||||
gint width, gint height)
|
||||
{
|
||||
struct v4l2_format format = (struct v4l2_format) {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
|
||||
.fmt.pix_mp = (struct v4l2_pix_format_mplane) {
|
||||
.pixelformat = pix_fmt,
|
||||
.width = width,
|
||||
.height = height,
|
||||
},
|
||||
};
|
||||
gint ret;
|
||||
|
||||
ret = ioctl (self->video_fd, VIDIOC_S_FMT, &format);
|
||||
if (ret < 0) {
|
||||
GST_ERROR_OBJECT (self, "VIDIOC_S_FMT failed: %s", g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (format.fmt.pix_mp.pixelformat != pix_fmt
|
||||
|| format.fmt.pix_mp.width != width
|
||||
|| format.fmt.pix_mp.height != height) {
|
||||
GST_WARNING_OBJECT (self, "Failed to set sink format to %"
|
||||
GST_FOURCC_FORMAT " %ix%i", GST_FOURCC_ARGS (pix_fmt), width, height);
|
||||
errno = EINVAL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstVideoInfo * info)
|
||||
{
|
||||
gint ret;
|
||||
struct v4l2_format fmt = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
|
||||
};
|
||||
|
||||
ret = ioctl (self->video_fd, VIDIOC_G_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));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_INFO_OBJECT (self, "Selected format %s %ix%i",
|
||||
gst_video_format_to_string (info->finfo->format),
|
||||
info->width, info->height);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gst_v4l2_decoder_install_properties (GObjectClass * gobject_class,
|
||||
gint prop_offset, GstV4l2CodecDevice * device)
|
||||
|
|
|
@ -34,9 +34,17 @@ GstV4l2Decoder * gst_v4l2_decoder_new (GstV4l2CodecDevice * device);
|
|||
|
||||
gboolean gst_v4l2_decoder_open (GstV4l2Decoder * decoder);
|
||||
|
||||
gboolean gst_v4l2_decoder_close (GstV4l2Decoder * decoder);
|
||||
|
||||
gboolean gst_v4l2_decoder_enum_sink_fmt (GstV4l2Decoder * self,
|
||||
gint i, guint32 * out_fmt);
|
||||
|
||||
gboolean gst_v4l2_decoder_set_sink_fmt (GstV4l2Decoder * self, guint32 fmt,
|
||||
gint width, gint height);
|
||||
|
||||
gboolean gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self,
|
||||
GstVideoInfo * info);
|
||||
|
||||
void gst_v4l2_decoder_install_properties (GObjectClass * gobject_class,
|
||||
gint prop_offset,
|
||||
GstV4l2CodecDevice * device);
|
||||
|
|
Loading…
Reference in a new issue