Пример #1
0
static gboolean
sink_setcaps(GstPad *pad,
	     GstCaps *caps)
{
	GstDspVpp *self;
	GstDspBase *base;
	GstCaps *out_caps;
	gboolean ret;

	self = GST_DSP_VPP(GST_PAD_PARENT(pad));
	base = GST_DSP_BASE(self);

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

	base->codec = &td_vpp_codec;

	du_port_alloc_buffers(base->ports[0], 4);
	du_port_alloc_buffers(base->ports[1], 4);

	out_caps = gst_caps_new_empty();
	configure_caps(self, caps, out_caps);
	base->tmp_caps = out_caps;

	ret = gst_pad_set_caps(pad, caps);

	if (!ret)
		return FALSE;

	return TRUE;
}
Пример #2
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_MP4VENC;
	base->codec = &td_mp4venc_codec;
	self->supported_levels = levels;
	self->nr_supported_levels = ARRAY_SIZE(levels);
	base->use_pinned = true;
}
Пример #3
0
static void
instance_init(GTypeInstance *instance,
	      gpointer g_class)
{
	GstDspBase *base;

	base = GST_DSP_BASE(instance);

	base->use_pad_alloc = TRUE;
	base->create_node = create_node;

	gst_pad_set_setcaps_function(base->sinkpad, sink_setcaps);
}
Пример #4
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;
}
Пример #5
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();
}
Пример #6
0
static gboolean
sink_setcaps(GstPad *pad,
	     GstCaps *caps)
{
	GstDspADec *self;
	GstDspBase *base;
	GstStructure *in_struc;
	const char *name;
	GstCaps *out_caps;

	self = GST_DSP_ADEC(GST_PAD_PARENT(pad));
	base = GST_DSP_BASE(self);

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

	in_struc = gst_caps_get_structure(caps, 0);

	name = gst_structure_get_name(in_struc);
	if (strcmp(name, "audio/mpeg") == 0) {
		int version = 1;

		gst_structure_get_int(in_struc, "mpegversion", &version);
		if (version == 2 || version == 4) {
			base->alg = GSTDSP_AACDEC;
			base->codec = &td_aacdec_codec;
		}
	}

	du_port_alloc_buffers(base->ports[0], 4);
	du_port_alloc_buffers(base->ports[1], 4);

	out_caps = gst_caps_new_empty();
	configure_caps(self, caps, out_caps);
	base->tmp_caps = out_caps;

	return TRUE;
}
Пример #7
0
static inline void *
create_node(GstDspVEnc *self)
{
	GstDspBase *base;
	int dsp_handle;
	struct dsp_node *node;
	struct td_codec *codec;

	const struct dsp_uuid usn_uuid = { 0x79A3C8B3, 0x95F2, 0x403F, 0x9A, 0x4B,
		{ 0xCF, 0x80, 0x57, 0x73, 0x05, 0x41 } };

	const struct dsp_uuid conversions_uuid = { 0x722DD0DA, 0xF532, 0x4238, 0xB8, 0x46,
		{ 0xAB, 0xFF, 0x5D, 0xA4, 0xBA, 0x02 } };

	base = GST_DSP_BASE(self);
	dsp_handle = base->dsp_handle;

	if (!gstdsp_register(dsp_handle, &usn_uuid, DSP_DCD_LIBRARYTYPE, "usn.dll64P")) {
		pr_err(self, "failed to register usn node library");
		return NULL;
	}

	codec = base->codec;
	if (!codec) {
		pr_err(self, "unknown algorithm");
		return NULL;
	}

	if (!gstdsp_register(dsp_handle, codec->uuid, DSP_DCD_LIBRARYTYPE, codec->filename)) {
		pr_err(self, "failed to register algo node library");
		return NULL;
	}

	if (!gstdsp_register(dsp_handle, codec->uuid, DSP_DCD_NODETYPE, codec->filename)) {
		pr_err(self, "failed to register algo node");
		return NULL;
	}

	/* only needed for jpegenc */
	if (base->alg == GSTDSP_JPEGENC) {
		/* SN_API == 0 doesn't have it, so don't fail */
		(void) gstdsp_register(dsp_handle, &conversions_uuid, DSP_DCD_LIBRARYTYPE, "conversions.dll64P");
	}

	{
		struct dsp_node_attr_in attrs = {
			.cb = sizeof(attrs),
			.priority = 5,
			.timeout = 1000,
		};
		void *arg_data;

		codec->create_args(base, &attrs.profile_id, &arg_data);

		if (!arg_data)
			return NULL;

		if (!dsp_node_allocate(dsp_handle, base->proc, codec->uuid, arg_data, &attrs, &node)) {
			pr_err(self, "dsp node allocate failed");
			free(arg_data);
			return NULL;
		}
		free(arg_data);
	}

	if (!dsp_node_create(dsp_handle, node)) {
		pr_err(self, "dsp node create failed");
		dsp_node_free(dsp_handle, node);
		return NULL;
	}

	pr_info(self, "dsp node created");

	return node;
}

static void check_supported_levels(GstDspVEnc *self, gint tgt_level)
{
	guint i;
	gint tgt_mbps, tgt_mbpf, tgt_bitrate;
	struct gstdsp_codec_level *cur, *level;

	if (!self->supported_levels)
		return;

	tgt_bitrate = self->user_max_bitrate;
	tgt_mbpf = ROUND_UP(self->width, 16) / 16 * ROUND_UP(self->height, 16) / 16;
	tgt_mbps = tgt_mbpf * self->framerate;

	if (!tgt_bitrate)
		tgt_bitrate =  self->bitrate;

search:
	level = cur = self->supported_levels;

	for (i = 0; i < self->nr_supported_levels; i++, cur++) {
		bool ok = false;

		/* is this the level we want? */
		if (tgt_level > 0 && tgt_level != cur->id)
			continue;

		/* is the bitrate enough? (and doesn't overshoot) */
		if (tgt_bitrate && cur->bitrate >= tgt_bitrate && level->bitrate < tgt_bitrate)
			ok = true;

		/* are the mbps enough? (and don't overshoot) */
		if (cur->mbps >= tgt_mbps && level->mbps < tgt_mbps)
			ok = true;

		/* at same level of mbps, get the biggest bitrate */
		if (cur->mbps >= tgt_mbps && cur->mbps == level->mbps &&
				!tgt_bitrate && cur->bitrate >= level->bitrate)
			ok = true;

		/* are the mbpf enough? (and don't overshoot) */
		if (cur->mbpf >= tgt_mbpf && level->mbpf < tgt_mbpf)
			ok = true;

		if (!ok)
			continue;

		/* we got a winner */
		level = cur;
	}

	if (tgt_level > 0 && tgt_level != level->id) {
		pr_warning(self, "invalid level: %d; ignoring", tgt_level);
		tgt_level = -1;
		goto search;
	}

	/* went beyond the table looking for a target; pick last one */
	if ((tgt_bitrate && level->bitrate < tgt_bitrate) || (level->mbps < tgt_mbps)) {
		if (tgt_level > 0) {
			pr_warning(self, "invalid level: %d; ignoring", tgt_level);
			tgt_level = -1;
			goto search;
		} else
			level = --cur;
	}

	if (!self->user_max_bitrate || self->user_max_bitrate >= level->bitrate)
		self->max_bitrate = level->bitrate;
	else
		self->max_bitrate = self->user_max_bitrate;

	self->level = level->id;

	pr_info(self, "level bitrate: %d", level->bitrate);
	pr_info(self, "max bitrate: %d", self->max_bitrate);
	pr_info(self, "level: %d", self->level);
}
Пример #8
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;
}
Пример #9
0
static void *
create_node(GstDspBase *base)
{
	GstDspVpp *self;
	struct td_codec *codec;
	int dsp_handle;
	struct dsp_node *node;

	const struct dsp_uuid usn_uuid = { 0x79A3C8B3, 0x95F2, 0x403F, 0x9A, 0x4B,
		{ 0xCF, 0x80, 0x57, 0x73, 0x05, 0x41 } };

	self = GST_DSP_VPP(base);
	dsp_handle = base->dsp_handle;

	if (!gstdsp_register(dsp_handle, &usn_uuid, DSP_DCD_LIBRARYTYPE, "usn.dll64P")) {
		pr_err(self, "failed to register usn node library");
		return NULL;
	}

	codec = base->codec;
	if (!codec) {
		pr_err(self, "unknown algorithm");
		return NULL;
	}

	pr_info(base, "algo=%s", codec->filename);

	if (!gstdsp_register(dsp_handle, codec->uuid, DSP_DCD_LIBRARYTYPE, codec->filename)) {
		pr_err(self, "failed to register algo node library");
		return NULL;
	}

	if (!gstdsp_register(dsp_handle, codec->uuid, DSP_DCD_NODETYPE, codec->filename)) {
		pr_err(self, "failed to register algo node");
		return NULL;
	}

	{
		struct dsp_node_attr_in attrs = {
			.cb = sizeof(attrs),
			.priority = 5,
			.timeout = 1000,
		};
		void *arg_data;

		codec->create_args(base, &attrs.profile_id, &arg_data);

		if (!arg_data)
			return NULL;

		if (!dsp_node_allocate(dsp_handle, base->proc, codec->uuid, arg_data, &attrs, &node)) {
			pr_err(self, "dsp node allocate failed");
			free(arg_data);
			return NULL;
		}
		free(arg_data);
	}

	if (!dsp_node_create(dsp_handle, node)) {
		pr_err(self, "dsp node create failed");
		dsp_node_free(dsp_handle, node);
		return NULL;
	}

	pr_info(self, "dsp node created");

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

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

	return node;
}

static inline bool
destroy_node(GstDspVpp *self,
	     int dsp_handle,
	     struct dsp_node *node)
{
	if (node) {
		if (!dsp_node_free(dsp_handle, node)) {
			pr_err(self, "dsp node free failed");
			return false;
		}

		pr_info(self, "dsp node deleted");
	}

	return true;
}

static inline void
configure_caps(GstDspVpp *self,
	       GstCaps *in,
	       GstCaps *out)
{
	GstDspBase *base;
	GstStructure *out_struc, *in_struc;
	const GValue *aspect_ratio;
	const GValue *framerate;
	GstCaps *allowed_caps;

	base = GST_DSP_BASE(self);

	in_struc = gst_caps_get_structure(in, 0);

	out_struc = gst_structure_new("video/x-raw-yuv",
				      "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('I', '4', '2', '0'),
				      NULL);

	if (gst_structure_get_int(in_struc, "width", &self->width))
		self->out_width = self->width;
	if (gst_structure_get_int(in_struc, "height", &self->height))
		self->out_height = self->height;

	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, "width", &self->out_width);
			gst_structure_get_int(s, "height", &self->out_height);
		}
		gst_caps_unref(allowed_caps);
	}

	gst_structure_set(out_struc, "width", G_TYPE_INT, self->out_width, NULL);
	gst_structure_set(out_struc, "height", G_TYPE_INT, self->out_height, NULL);

	aspect_ratio = gst_structure_get_value(in_struc, "pixel-aspect-ratio");
	if (aspect_ratio)
		gst_structure_set_value(out_struc, "pixel-aspect-ratio", aspect_ratio);

	framerate = gst_structure_get_value(in_struc, "framerate");
	if (framerate)
		gst_structure_set_value(out_struc, "framerate", framerate);

	base->output_buffer_size = self->out_width * self->out_height * 1.5;

	gst_caps_append_structure(out, out_struc);
}
Пример #10
0
static void *
create_node(GstDspBase *base)
{
	GstDspADec *self;
	struct td_codec *codec;
	int dsp_handle;
	struct dsp_node *node;

	const struct dsp_uuid usn_uuid = { 0x79A3C8B3, 0x95F2, 0x403F, 0x9A, 0x4B,
		{ 0xCF, 0x80, 0x57, 0x73, 0x05, 0x41 } };

	self = GST_DSP_ADEC(base);
	dsp_handle = base->dsp_handle;

	if (!gstdsp_register(dsp_handle, &usn_uuid, DSP_DCD_LIBRARYTYPE, "usn.dll64P")) {
		pr_err(self, "failed to register usn node library");
		return NULL;
	}

	codec = base->codec;
	if (!codec) {
		pr_err(self, "unknown algorithm");
		return NULL;
	}

	pr_info(base, "algo=%s", codec->filename);

	if (!gstdsp_register(dsp_handle, codec->uuid, DSP_DCD_LIBRARYTYPE, codec->filename)) {
		pr_err(self, "failed to register algo node library");
		return NULL;
	}

	if (!gstdsp_register(dsp_handle, codec->uuid, DSP_DCD_NODETYPE, codec->filename)) {
		pr_err(self, "failed to register algo node");
		return NULL;
	}

	{
		struct dsp_node_attr_in attrs = {
			.cb = sizeof(attrs),
			.priority = 10,
			.timeout = 10000,
		};
		void *arg_data;

		codec->create_args(base, &attrs.profile_id, &arg_data);

		if (!arg_data)
			return NULL;

		if (!dsp_node_allocate(dsp_handle, base->proc, codec->uuid, arg_data, &attrs, &node)) {
			pr_err(self, "dsp node allocate failed");
			free(arg_data);
			return NULL;
		}
		free(arg_data);
	}

	if (!dsp_node_create(dsp_handle, node)) {
		pr_err(self, "dsp node create failed");
		dsp_node_free(dsp_handle, node);
		return NULL;
	}

	pr_info(self, "dsp node created");

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

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

	base->flush_buffer = codec->flush_buffer;

	return node;
}

static inline void
configure_caps(GstDspADec *self,
	       GstCaps *in,
	       GstCaps *out)
{
	GstDspBase *base;
	GstStructure *out_struc, *in_struc;
	int channels;

	base = GST_DSP_BASE(self);

	in_struc = gst_caps_get_structure(in, 0);

	out_struc = gst_structure_new("audio/x-raw-int",
				"endianness", G_TYPE_INT, G_BYTE_ORDER,
				"signed", G_TYPE_BOOLEAN, TRUE,
				"width", G_TYPE_INT, 16,
				"depth", G_TYPE_INT, 16,
				NULL);

	if (gst_structure_get_int(in_struc, "channels", &channels))
		gst_structure_set(out_struc, "channels", G_TYPE_INT, channels, NULL);

	if (gst_structure_get_int(in_struc, "rate", &self->samplerate))
		gst_structure_set(out_struc, "rate", G_TYPE_INT, self->samplerate, NULL);

	if (base->alg == GSTDSP_AACDEC) {
		const char *fmt;
		gboolean tmp;
		gst_structure_get_boolean(in_struc, "framed", &tmp);
		self->packetized = tmp;
		fmt = gst_structure_get_string(in_struc, "stream-format");
		self->raw = strcmp(fmt, "raw") == 0;
	}

	base->output_buffer_size = 4 * 1024;

	gst_caps_append_structure(out, out_struc);
}