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; }
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; }
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); }
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; }
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(); }
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; }
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); }
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; }
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); }
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); }