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