Beispiel #1
0
static void
set_property(GObject *obj,
	     guint prop_id,
	     const GValue *value,
	     GParamSpec *pspec)
{
	GstDspVEnc *self = GST_DSP_VENC(obj);

	switch (prop_id) {
	case ARG_QUALITY: {
		if (GST_STATE(self) == GST_STATE_NULL) {
			guint quality;
			quality = g_value_get_uint(value);
			g_atomic_int_set(&self->quality, quality);
		} else {
			GST_WARNING_OBJECT(self,
					"encoding quality property can be set only in NULL state");
		}
		break;
	}
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
		break;
	}
}
Beispiel #2
0
static void
get_property(GObject *obj,
	     guint prop_id,
	     GValue *value,
	     GParamSpec *pspec)
{
	GstDspVEnc *self = GST_DSP_VENC(obj);

	switch (prop_id) {
	case ARG_BITRATE:
		g_value_set_uint(value, g_atomic_int_get(&self->bitrate));
		break;
	case ARG_MODE:
		g_value_set_enum(value, self->mode);
		break;
	case ARG_KEYFRAME_INTERVAL:
		g_value_set_int(value, g_atomic_int_get(&self->keyframe_interval));
		break;
	case ARG_MAX_BITRATE: {
		guint bitrate;

		bitrate = self->user_max_bitrate;
		if (!bitrate)
			bitrate = self->max_bitrate;
		g_value_set_uint(value, bitrate);
		break;
	}
	case ARG_INTRA_REFRESH:
		g_value_set_boolean(value, self->intra_refresh);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
		break;
	}
}
Beispiel #3
0
static gboolean
src_event(GstDspBase *base,
	  GstEvent *event)
{
	GstDspVEnc *self = GST_DSP_VENC(base);

	switch (GST_EVENT_TYPE(event)) {
	case GST_EVENT_CUSTOM_UPSTREAM:
		{
			const GstStructure *s;
			s = gst_event_get_structure(event);

			if (gst_structure_has_name(s, "GstForceKeyUnit")) {
				g_mutex_lock(self->keyframe_mutex);
				/* make it downstream */
				GST_EVENT_TYPE(event) = GST_EVENT_CUSTOM_DOWNSTREAM;
				if (self->keyframe_event)
					gst_event_unref(self->keyframe_event);
				self->keyframe_event = event;
				g_mutex_unlock(self->keyframe_mutex);
				return TRUE;
			}
			break;
		}
	default:
		break;
	}

	if (parent_class->src_event)
		return parent_class->src_event(base, event);

	return gst_pad_push_event(base->sinkpad, event);
}
Beispiel #4
0
static void
finalize(GObject *obj)
{
	GstDspVEnc *self = GST_DSP_VENC(obj);
	g_mutex_free(self->keyframe_mutex);
	if (self->keyframe_event)
		gst_event_unref(self->keyframe_event);
	G_OBJECT_CLASS(parent_class)->finalize(obj);
}
static void
instance_init(GTypeInstance *instance,
	      gpointer g_class)
{
	GstDspBase *base = GST_DSP_BASE(instance);
	GstDspVEnc *self = GST_DSP_VENC(instance);

	base->alg = GSTDSP_MP4VENC;
	base->codec = &td_mp4venc_codec;
	self->supported_levels = levels;
	self->nr_supported_levels = ARRAY_SIZE(levels);
	base->use_pinned = true;
}
Beispiel #6
0
static void
instance_init(GTypeInstance *instance,
	      gpointer g_class)
{
	GstDspBase *base = GST_DSP_BASE(instance);
	GstDspVEnc *self = GST_DSP_VENC(instance);

	base->alg = GSTDSP_JPEGENC;
	base->codec = &td_jpegenc_codec;
	base->eos_timeout = 0;
	base->use_pinned = true;

	self->quality = DEFAULT_ENCODING_QUALITY;
}
Beispiel #7
0
static void
get_property(GObject *obj,
	     guint prop_id,
	     GValue *value,
	     GParamSpec *pspec)
{
	GstDspVEnc *self = GST_DSP_VENC(obj);

	switch (prop_id) {
	case ARG_QUALITY:
		g_value_set_uint(value, g_atomic_int_get(&self->quality));
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
		break;
	}
}
Beispiel #8
0
static void
instance_init(GTypeInstance *instance,
	      gpointer g_class)
{
	GstDspBase *base = GST_DSP_BASE(instance);
	GstDspVEnc *self = GST_DSP_VENC(instance);

	gst_pad_set_setcaps_function(base->sinkpad, sink_setcaps);
	base->reset = reset;

	self->bitrate = DEFAULT_BITRATE;
	self->mode = DEFAULT_MODE;
	self->keyframe_interval = DEFAULT_KEYFRAME_INTERVAL;
	self->intra_refresh = DEFAULT_INTRA_REFRESH;

	self->keyframe_mutex = g_mutex_new();
}
Beispiel #9
0
static void
reset(GstDspBase *base)
{
	GstDspVEnc *self = GST_DSP_VENC(base);

	pr_debug(self, "venc reset");

	/* some cleanup */
	if (base->alg == GSTDSP_H264ENC) {
		self->priv.h264.codec_data_done = FALSE;
		self->priv.h264.sps_received = FALSE;
		self->priv.h264.pps_received = FALSE;
		gst_buffer_replace(&self->priv.h264.sps, NULL);
		gst_buffer_replace(&self->priv.h264.pps, NULL);
		gst_buffer_replace(&self->priv.h264.codec_data, NULL);
	} else
		self->priv.mpeg4.codec_data_done = FALSE;
}
Beispiel #10
0
static void
set_property(GObject *obj,
	     guint prop_id,
	     const GValue *value,
	     GParamSpec *pspec)
{
	GstDspVEnc *self = GST_DSP_VENC(obj);

	switch (prop_id) {
	case ARG_BITRATE: {
		guint bitrate;
		bitrate = g_value_get_uint(value);
		if (self->max_bitrate && bitrate > (unsigned) self->max_bitrate)
			bitrate = self->max_bitrate;
		g_atomic_int_set(&self->bitrate, bitrate);
		break;
	}
	case ARG_MODE:
		self->mode = g_value_get_enum(value);
		/* guess intra-refresh, if not manually set */
		if (self->intra_refresh_set)
			break;
		self->intra_refresh = (self->mode == 1);
		break;
	case ARG_KEYFRAME_INTERVAL:
		g_atomic_int_set(&self->keyframe_interval, g_value_get_int(value));
		break;
	case ARG_MAX_BITRATE:
		self->user_max_bitrate = g_value_get_uint(value);
		break;
	case ARG_INTRA_REFRESH:
		self->intra_refresh = g_value_get_boolean(value);
		self->intra_refresh_set = true;
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
		break;
	}
}
Beispiel #11
0
static gboolean
sink_setcaps(GstPad *pad,
	     GstCaps *caps)
{
	GstDspVEnc *self;
	GstDspBase *base;
	GstStructure *in_struc;
	GstCaps *out_caps;
	GstStructure *out_struc;
	gint width = 0, height = 0;
	GstCaps *allowed_caps;
	gint tgt_level = -1;
	struct td_codec *codec;

	self = GST_DSP_VENC(GST_PAD_PARENT(pad));
	base = GST_DSP_BASE(self);
	codec = base->codec;

	if (!codec)
		return FALSE;

#ifdef DEBUG
	{
		gchar *str = gst_caps_to_string(caps);
		pr_info(self, "sink caps: %s", str);
		g_free(str);
	}
#endif

	in_struc = gst_caps_get_structure(caps, 0);

	out_caps = gst_caps_new_empty();

	switch (base->alg) {
	case GSTDSP_JPEGENC:
		out_struc = gst_structure_new("image/jpeg",
					      NULL);
		break;
	case GSTDSP_H263ENC:
		out_struc = gst_structure_new("video/x-h263",
					      "variant", G_TYPE_STRING, "itu",
					      NULL);
		break;
	case GSTDSP_MP4VENC:
		out_struc = gst_structure_new("video/mpeg",
					      "mpegversion", G_TYPE_INT, 4,
					      "systemstream", G_TYPE_BOOLEAN, FALSE,
					      NULL);
		break;
	case GSTDSP_H264ENC:
		out_struc = gst_structure_new("video/x-h264",
					      "alignment", G_TYPE_STRING, "au",
					      NULL);
		break;
	default:
		return FALSE;
	}

	if (gst_structure_get_int(in_struc, "width", &width))
		gst_structure_set(out_struc, "width", G_TYPE_INT, width, NULL);
	if (gst_structure_get_int(in_struc, "height", &height))
		gst_structure_set(out_struc, "height", G_TYPE_INT, height, NULL);
	gst_structure_get_fourcc(in_struc, "format", &self->color_format);

	switch (base->alg) {
	case GSTDSP_H263ENC:
	case GSTDSP_MP4VENC:
	case GSTDSP_H264ENC:
		base->output_buffer_size = width * height / 2;
		break;
	case GSTDSP_JPEGENC:
		if (width % 2 || height % 2)
			return FALSE;
		if (self->color_format == GST_MAKE_FOURCC('I', '4', '2', '0'))
			base->input_buffer_size = ROUND_UP(width, 16) * ROUND_UP(height, 16) * 3 / 2;
		else
			base->input_buffer_size = ROUND_UP(width, 16) * ROUND_UP(height, 16) * 2;
		base->output_buffer_size = width * height;
		if (self->quality < 10)
			base->output_buffer_size /= 10;
		else if (self->quality < 100)
			base->output_buffer_size /= (100 / self->quality);
		break;
	default:
		break;
	}

	if (base->node)
		goto skip_setup;

	switch (base->alg) {
	case GSTDSP_JPEGENC:
		du_port_alloc_buffers(base->ports[0], 1);
#if SN_API > 1
		du_port_alloc_buffers(base->ports[1], 2);
#else
		/* old versions of the sn can't handle 2 buffers */
		/*
		 * Some constrained pipelines might starve because of this. You
		 * might want to try enable-last-buffer=false on some sinks.
		 * TODO Is there any way around this?
		 */
		du_port_alloc_buffers(base->ports[1], 1);
#endif
		break;
	default:
		du_port_alloc_buffers(base->ports[0], 2);
		du_port_alloc_buffers(base->ports[1], 4);
		break;
	}

skip_setup:
	self->width = width;
	self->height = height;

	{
		const GValue *framerate = NULL;
		framerate = gst_structure_get_value(in_struc, "framerate");
		if (framerate) {
			gst_structure_set_value(out_struc, "framerate", framerate);
			/* calculate nearest integer */
			self->framerate = (gst_value_get_fraction_numerator(framerate) * 2 /
					   gst_value_get_fraction_denominator(framerate) + 1) / 2;
		}
	}

	/* see if downstream caps express something */
	allowed_caps = gst_pad_get_allowed_caps(base->srcpad);
	if (allowed_caps) {
		if (gst_caps_get_size(allowed_caps) > 0) {
			GstStructure *s;
			s = gst_caps_get_structure(allowed_caps, 0);
			gst_structure_get_int(s, "level", &tgt_level);
			if (base->alg == GSTDSP_H264ENC) {
				const char *stream_format;
				stream_format = gst_structure_get_string(s, "stream-format");
				if (stream_format && !strcmp(stream_format, "avc"))
					self->priv.h264.bytestream = false;
				else
					stream_format = "byte-stream";
				gst_structure_set(out_struc, "stream-format", G_TYPE_STRING, stream_format, NULL);
			}
		}
		gst_caps_unref(allowed_caps);
	}

	check_supported_levels(self, tgt_level);

	if (self->bitrate == 0)
		self->bitrate = self->max_bitrate;
	else if (self->bitrate > self->max_bitrate)
		self->bitrate = self->max_bitrate;

	gst_caps_append_structure(out_caps, out_struc);

#ifdef DEBUG
	{
		gchar *str = gst_caps_to_string(out_caps);
		pr_info(self, "src caps: %s", str);
		g_free(str);
	}
#endif

	if (!gst_pad_take_caps(base->srcpad, out_caps))
		return FALSE;

	if (base->node)
		return TRUE;

	base->node = create_node(self);
	if (!base->node) {
		pr_err(self, "dsp node creation failed");
		return FALSE;
	}

	if (codec->setup_params)
		codec->setup_params(base);

	if (!gstdsp_start(base)) {
		pr_err(self, "dsp start failed");
		return FALSE;
	}

	if (codec->send_params)
		codec->send_params(base, base->node);

	return TRUE;
}