static gboolean gst_v4l2_transform_sink_event (GstBaseTransform * trans, GstEvent * event) { GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans); gboolean ret; /* Nothing to flush in passthrough */ if (gst_base_transform_is_passthrough (trans)) return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_START: GST_DEBUG_OBJECT (self, "flush start"); gst_v4l2_object_unlock (self->v4l2output); gst_v4l2_object_unlock (self->v4l2capture); break; default: break; } ret = GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_STOP: /* Buffer should be back now */ GST_DEBUG_OBJECT (self, "flush stop"); gst_v4l2_object_unlock_stop (self->v4l2capture); gst_v4l2_object_unlock_stop (self->v4l2output); break; default: break; } return ret; }
/* GstBaseTransform vmethod implementations */ static GstFlowReturn gst_audio_amplify_transform_ip (GstBaseTransform * base, GstBuffer * buf) { GstAudioAmplify *filter = GST_AUDIO_AMPLIFY (base); guint num_samples; GstClockTime timestamp, stream_time; timestamp = GST_BUFFER_TIMESTAMP (buf); stream_time = gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp); GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); if (GST_CLOCK_TIME_IS_VALID (stream_time)) gst_object_sync_values (G_OBJECT (filter), stream_time); num_samples = GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8); if (gst_base_transform_is_passthrough (base) || G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP))) return GST_FLOW_OK; filter->process (filter, GST_BUFFER_DATA (buf), num_samples); return GST_FLOW_OK; }
static GstFlowReturn gst_iir_equalizer_transform_ip (GstBaseTransform * btrans, GstBuffer * buf) { GstAudioFilter *filter = GST_AUDIO_FILTER (btrans); GstIirEqualizer *equ = GST_IIR_EQUALIZER (btrans); GstClockTime timestamp; if (G_UNLIKELY (filter->format.channels < 1 || equ->process == NULL)) return GST_FLOW_NOT_NEGOTIATED; if (equ->need_new_coefficients) { update_coefficients (equ); set_passthrough (equ); } if (gst_base_transform_is_passthrough (btrans)) return GST_FLOW_OK; timestamp = GST_BUFFER_TIMESTAMP (buf); timestamp = gst_segment_to_stream_time (&btrans->segment, GST_FORMAT_TIME, timestamp); if (GST_CLOCK_TIME_IS_VALID (timestamp)) gst_object_sync_values (G_OBJECT (equ), timestamp); equ->process (equ, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), filter->format.channels); return GST_FLOW_OK; }
static gboolean audioresample_query (GstPad * pad, GstQuery * query) { GstAudioresample *audioresample = GST_AUDIORESAMPLE (gst_pad_get_parent (pad)); GstBaseTransform *trans = GST_BASE_TRANSFORM (audioresample); gboolean res = TRUE; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: { GstClockTime min, max; gboolean live; guint64 latency; GstPad *peer; gint rate = audioresample->i_rate; gint resampler_latency = audioresample->filter_length / 2; if (gst_base_transform_is_passthrough (trans)) resampler_latency = 0; if ((peer = gst_pad_get_peer (trans->sinkpad))) { if ((res = gst_pad_query (peer, query))) { gst_query_parse_latency (query, &live, &min, &max); GST_DEBUG ("Peer latency: min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); /* add our own latency */ if (rate != 0 && resampler_latency != 0) latency = gst_util_uint64_scale (resampler_latency, GST_SECOND, rate); else latency = 0; GST_DEBUG ("Our latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency)); min += latency; if (max != GST_CLOCK_TIME_NONE) max += latency; GST_DEBUG ("Calculated total latency : min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max)); gst_query_set_latency (query, live, min, max); } gst_object_unref (peer); } break; } default: res = gst_pad_query_default (pad, query); break; } gst_object_unref (audioresample); return res; }
static GstFlowReturn transform_ip_assert_writable (GstBaseTransform * trans, GstBuffer * buf) { GST_DEBUG_OBJECT (trans, "transform called"); if (!gst_base_transform_is_passthrough (trans)) fail_unless (gst_buffer_is_writable (buf)); return GST_FLOW_OK; }
static GstFlowReturn gst_video_filter_transform_ip (GstBaseTransform * trans, GstBuffer * buf) { GstFlowReturn res; GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans); GstVideoFilterClass *fclass; if (G_UNLIKELY (!filter->negotiated)) goto unknown_format; fclass = GST_VIDEO_FILTER_GET_CLASS (filter); if (fclass->transform_frame_ip) { GstVideoFrame frame; GstMapFlags flags; flags = GST_MAP_READ; if (!gst_base_transform_is_passthrough (trans)) flags |= GST_MAP_WRITE; if (!gst_video_frame_map (&frame, &filter->in_info, buf, flags)) goto invalid_buffer; /* GstVideoFrame has another reference, so the buffer looks unwriteable, * meaning that we can't attach any metas or anything to it. Other * map() functions like gst_buffer_map() don't get another reference * of the buffer and expect the buffer reference to be kept until * the buffer is unmapped again. */ gst_buffer_unref (buf); res = fclass->transform_frame_ip (filter, &frame); gst_buffer_ref (buf); gst_video_frame_unmap (&frame); } else { GST_DEBUG_OBJECT (trans, "no transform_frame_ip vmethod"); res = GST_FLOW_OK; } return res; /* ERRORS */ unknown_format: { GST_ELEMENT_ERROR (filter, CORE, NOT_IMPLEMENTED, (NULL), ("unknown format")); return GST_FLOW_NOT_NEGOTIATED; } invalid_buffer: { GST_ELEMENT_WARNING (filter, CORE, NOT_IMPLEMENTED, (NULL), ("invalid video buffer received")); return GST_FLOW_OK; } }
static GstFlowReturn gst_msdkvpp_prepare_output_buffer (GstBaseTransform * trans, GstBuffer * inbuf, GstBuffer ** outbuf_ptr) { GstMsdkVPP *thiz = GST_MSDKVPP (trans); if (gst_base_transform_is_passthrough (trans)) { *outbuf_ptr = inbuf; return GST_FLOW_OK; } *outbuf_ptr = create_output_buffer (thiz); return *outbuf_ptr ? GST_FLOW_OK : GST_FLOW_ERROR; }
static GstFlowReturn gst_iir_equalizer_transform_ip (GstBaseTransform * btrans, GstBuffer * buf) { GstAudioFilter *filter = GST_AUDIO_FILTER (btrans); GstIirEqualizer *equ = GST_IIR_EQUALIZER (btrans); GstClockTime timestamp; GstMapInfo map; gint channels = GST_AUDIO_FILTER_CHANNELS (filter); gboolean need_new_coefficients; if (G_UNLIKELY (channels < 1 || equ->process == NULL)) return GST_FLOW_NOT_NEGOTIATED; BANDS_LOCK (equ); need_new_coefficients = equ->need_new_coefficients; BANDS_UNLOCK (equ); if (!need_new_coefficients && gst_base_transform_is_passthrough (btrans)) return GST_FLOW_OK; timestamp = GST_BUFFER_TIMESTAMP (buf); timestamp = gst_segment_to_stream_time (&btrans->segment, GST_FORMAT_TIME, timestamp); if (GST_CLOCK_TIME_IS_VALID (timestamp)) { GstIirEqualizerBand **filters = equ->bands; guint f, nf = equ->freq_band_count; gst_object_sync_values (GST_OBJECT (equ), timestamp); /* sync values for bands too */ /* FIXME: iterating equ->bands is not thread-safe here */ for (f = 0; f < nf; f++) { gst_object_sync_values (GST_OBJECT (filters[f]), timestamp); } } BANDS_LOCK (equ); if (need_new_coefficients) { update_coefficients (equ); set_passthrough (equ); } BANDS_UNLOCK (equ); gst_buffer_map (buf, &map, GST_MAP_READWRITE); equ->process (equ, map.data, map.size, channels); gst_buffer_unmap (buf, &map); return GST_FLOW_OK; }
static GstFlowReturn gst_crossfeed_transform_inplace (GstBaseTransform * base, GstBuffer * outbuf) { GstCrossfeed *crossfeed = GST_CROSSFEED (base); void *data = GST_BUFFER_DATA (outbuf); gint samples = GST_BUFFER_SIZE (outbuf); if(gst_base_transform_is_passthrough (base) || G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_GAP))) return GST_FLOW_OK; crossfeed->func (crossfeed->bs2bdp, data, samples / crossfeed->divider); return GST_FLOW_OK; }
static GstFlowReturn gst_video_filter_transform_ip (GstBaseTransform * trans, GstBuffer * buf) { GstFlowReturn res; GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans); GstVideoFilterClass *fclass; if (G_UNLIKELY (!filter->negotiated)) goto unknown_format; fclass = GST_VIDEO_FILTER_GET_CLASS (filter); if (fclass->transform_frame_ip) { GstVideoFrame frame; GstMapFlags flags; flags = GST_MAP_READ; if (!gst_base_transform_is_passthrough (trans)) flags |= GST_MAP_WRITE; if (!gst_video_frame_map (&frame, &filter->in_info, buf, flags)) goto invalid_buffer; res = fclass->transform_frame_ip (filter, &frame); gst_video_frame_unmap (&frame); } else { GST_DEBUG_OBJECT (trans, "no transform_frame_ip vmethod"); res = GST_FLOW_OK; } return res; /* ERRORS */ unknown_format: { GST_ELEMENT_ERROR (filter, CORE, NOT_IMPLEMENTED, (NULL), ("unknown format")); return GST_FLOW_NOT_NEGOTIATED; } invalid_buffer: { GST_ELEMENT_WARNING (filter, CORE, NOT_IMPLEMENTED, (NULL), ("invalid video buffer received")); return GST_FLOW_OK; } }
/* GstBaseTransform vmethod implementations */ static GstFlowReturn gst_audio_amplify_transform_ip (GstBaseTransform * base, GstBuffer * buf) { GstAudioAmplify *filter = GST_AUDIO_AMPLIFY (base); guint num_samples = GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8); if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (buf)); if (gst_base_transform_is_passthrough (base) || G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP))) return GST_FLOW_OK; filter->process (filter, GST_BUFFER_DATA (buf), num_samples); return GST_FLOW_OK; }
static GstFlowReturn gst_bml_transform_transform_mono_to_stereo (GstBaseTransform * base, GstBuffer * inbuf, GstBuffer * outbuf) { GstMapInfo infoi, infoo; GstBMLTransform *bml_transform = GST_BML_TRANSFORM (base); GstBMLTransformClass *klass = GST_BML_TRANSFORM_GET_CLASS (bml_transform); GstBML *bml = GST_BML (bml_transform); GstBMLClass *bml_class = GST_BML_CLASS (klass); BMLData *datai, *datao, *seg_datai, *seg_datao; gpointer bm = bml->bm; guint todo, seg_size, samples_per_buffer; gboolean has_data; guint mode = 3; /*WM_READWRITE */ bml->running_time = gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (inbuf)); if (GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_DISCONT)) { bml->subtick_count = (!bml->reverse) ? bml->subticks_per_tick : 1; } if (bml->subtick_count >= bml->subticks_per_tick) { bml (gstbml_reset_triggers (bml, bml_class)); bml (gstbml_sync_values (bml, bml_class, GST_BUFFER_TIMESTAMP (outbuf))); bml (tick (bm)); bml->subtick_count = 1; } else { bml->subtick_count++; } /* don't process data in passthrough-mode */ if (gst_base_transform_is_passthrough (base)) { // we would actually need to convert mono to stereo here // but this is not even called GST_WARNING_OBJECT (bml_transform, "m2s in passthrough mode"); //return GST_FLOW_OK; } if (!gst_buffer_map (inbuf, &infoi, GST_MAP_READ)) { GST_WARNING_OBJECT (base, "unable to map input buffer for read"); return GST_FLOW_ERROR; } datai = (BMLData *) infoi.data; samples_per_buffer = infoi.size / sizeof (BMLData); if (!gst_buffer_map (outbuf, &infoo, GST_MAP_READ | GST_MAP_WRITE)) { GST_WARNING_OBJECT (base, "unable to map output buffer for read & write"); return GST_FLOW_ERROR; } datao = (BMLData *) infoo.data; // some buzzmachines expect a cleared buffer //for(i=0;i<samples_per_buffer*2;i++) datao[i]=0.0f; memset (datao, 0, samples_per_buffer * 2 * sizeof (BMLData)); /* if buffer has only silence process with different mode */ if (GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_GAP)) { mode = 2; /* WM_WRITE */ } else { gfloat fc = 32768.0; orc_scalarmultiply_f32_ns (datai, datai, fc, samples_per_buffer); } GST_DEBUG_OBJECT (bml_transform, " calling work_m2s(%d,%d)", samples_per_buffer, mode); todo = samples_per_buffer; seg_datai = datai; seg_datao = datao; has_data = FALSE; while (todo) { // 256 is MachineInterface.h::MAX_BUFFER_LENGTH seg_size = (todo > 256) ? 256 : todo; has_data |= bml (work_m2s (bm, seg_datai, seg_datao, (int) seg_size, mode)); seg_datai = &seg_datai[seg_size]; seg_datao = &seg_datao[seg_size * 2]; todo -= seg_size; } if (gstbml_fix_data ((GstElement *) bml_transform, &infoo, has_data)) { GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP); } else { GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_GAP); } gst_buffer_unmap (inbuf, &infoi); gst_buffer_unmap (outbuf, &infoo); return (GST_FLOW_OK); }
static GstFlowReturn gst_bml_transform_transform_ip_stereo (GstBaseTransform * base, GstBuffer * outbuf) { GstMapInfo info; GstBMLTransform *bml_transform = GST_BML_TRANSFORM (base); GstBMLTransformClass *klass = GST_BML_TRANSFORM_GET_CLASS (bml_transform); GstBML *bml = GST_BML (bml_transform); GstBMLClass *bml_class = GST_BML_CLASS (klass); BMLData *data, *seg_data; gpointer bm = bml->bm; guint todo, seg_size, samples_per_buffer; gboolean has_data; guint mode = 3; /*WM_READWRITE */ bml->running_time = gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (outbuf)); if (GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_DISCONT)) { bml->subtick_count = (!bml->reverse) ? bml->subticks_per_tick : 1; } /* TODO(ensonic): sync on subticks ? */ if (bml->subtick_count >= bml->subticks_per_tick) { bml (gstbml_reset_triggers (bml, bml_class)); bml (gstbml_sync_values (bml, bml_class, GST_BUFFER_TIMESTAMP (outbuf))); bml (tick (bm)); bml->subtick_count = 1; } else { bml->subtick_count++; } /* don't process data in passthrough-mode */ if (gst_base_transform_is_passthrough (base)) return GST_FLOW_OK; if (!gst_buffer_map (outbuf, &info, GST_MAP_READ | GST_MAP_WRITE)) { GST_WARNING_OBJECT (base, "unable to map buffer for read & write"); return GST_FLOW_ERROR; } data = (BMLData *) info.data; samples_per_buffer = info.size / (sizeof (BMLData) * 2); /* if buffer has only silence process with different mode */ if (GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_GAP)) { mode = 2; /* WM_WRITE */ } else { gfloat fc = 32768.0; orc_scalarmultiply_f32_ns (data, data, fc, samples_per_buffer * 2); } GST_DEBUG_OBJECT (bml_transform, " calling work_m2s(%d,%d)", samples_per_buffer, mode); todo = samples_per_buffer; seg_data = data; has_data = FALSE; while (todo) { // 256 is MachineInterface.h::MAX_BUFFER_LENGTH seg_size = (todo > 256) ? 256 : todo; // first seg_data can be NULL, its ignored has_data |= bml (work_m2s (bm, seg_data, seg_data, (int) seg_size, mode)); seg_data = &seg_data[seg_size * 2]; todo -= seg_size; } if (gstbml_fix_data ((GstElement *) bml_transform, &info, has_data)) { GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP); } else { GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_GAP); } gst_buffer_unmap (outbuf, &info); return (GST_FLOW_OK); }
static void gst_gl_alpha_update_properties (GstGLAlpha * glalpha) { GstBaseTransform *base = GST_BASE_TRANSFORM (glalpha); gboolean current_passthrough, passthrough; gfloat kgl; gfloat tmp; gfloat target_r, target_g, target_b; gfloat target_y, target_u, target_v; const float *matrix = cog_rgb_to_ycbcr_matrix_8bit_sdtv; GST_OBJECT_LOCK (glalpha); switch (glalpha->method) { case ALPHA_METHOD_GREEN: target_r = 0.0; target_g = 1.0; target_b = 0.0; break; case ALPHA_METHOD_BLUE: target_r = 0.0; target_g = 0.0; target_b = 1.0; break; default: target_r = (gfloat) glalpha->target_r / 255.0; target_g = (gfloat) glalpha->target_g / 255.0; target_b = (gfloat) glalpha->target_b / 255.0; break; } target_y = matrix[0] * target_r + matrix[1] * target_g + matrix[2] * target_b + matrix[3]; /* Cb,Cr without offset here because the chroma keying * works with them being in range [-128,127] */ target_u = matrix[4] * target_r + matrix[5] * target_g + matrix[6] * target_b; target_v = matrix[8] * target_r + matrix[9] * target_g + matrix[10] * target_b; tmp = target_u * target_u + target_v * target_v; kgl = sqrt (tmp); glalpha->cb = target_u / kgl * 0.5; glalpha->cr = target_v / kgl * 0.5; tmp = 15 * tan (M_PI * glalpha->angle / 180); tmp = MIN (tmp, 255); glalpha->accept_angle_tg = tmp; tmp = 15 / tan (M_PI * glalpha->angle / 180); tmp = MIN (tmp, 255); glalpha->accept_angle_ctg = tmp; glalpha->one_over_kc = wrap (2 / kgl - 255, 0, 256); tmp = 15 * target_y / kgl; tmp = MIN (tmp, 255); glalpha->kfgy_scale = tmp; glalpha->kg = MIN (kgl, 0.5); glalpha->noise_level2 = glalpha->noise_level / 256.0 * glalpha->noise_level / 256.0; GST_INFO_OBJECT (glalpha, "target yuv: %f, %f, %f, " "kgl: %f, cb: %f, cr: %f, accept_angle_tg: %f, accept_angle_ctg: %f, " "one_over_kc: %f, kgfy_scale: %f, kg: %f, noise level: %f", (float) target_y, (float) target_u, (float) target_v, (float) kgl, (float) glalpha->cb, (float) glalpha->cr, (float) glalpha->accept_angle_tg, (float) glalpha->accept_angle_ctg, (float) glalpha->one_over_kc, (float) glalpha->kfgy_scale, (float) glalpha->kg, (float) glalpha->noise_level2); passthrough = gst_gl_alpha_is_passthrough (glalpha); GST_OBJECT_UNLOCK (glalpha); current_passthrough = gst_base_transform_is_passthrough (base); gst_base_transform_set_passthrough (base, passthrough); if (current_passthrough != passthrough) gst_base_transform_reconfigure_src (base); }
static GstFlowReturn gst_v4l2_transform_prepare_output_buffer (GstBaseTransform * trans, GstBuffer * inbuf, GstBuffer ** outbuf) { GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans); GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool); GstFlowReturn ret = GST_FLOW_OK; GstBaseTransformClass *bclass = GST_BASE_TRANSFORM_CLASS (parent_class); if (gst_base_transform_is_passthrough (trans)) { GST_DEBUG_OBJECT (self, "Passthrough, no need to do anything"); *outbuf = inbuf; goto beach; } /* Ensure input internal pool is active */ if (!gst_buffer_pool_is_active (pool)) { GstStructure *config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, self->incaps, self->v4l2output->info.size, 2, 2); /* There is no reason to refuse this config */ if (!gst_buffer_pool_set_config (pool, config)) goto activate_failed; if (!gst_buffer_pool_set_active (pool, TRUE)) goto activate_failed; } GST_DEBUG_OBJECT (self, "Queue input buffer"); ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (pool), &inbuf); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto beach; do { pool = gst_base_transform_get_buffer_pool (trans); if (!gst_buffer_pool_set_active (pool, TRUE)) goto activate_failed; GST_DEBUG_OBJECT (self, "Dequeue output buffer"); ret = gst_buffer_pool_acquire_buffer (pool, outbuf, NULL); g_object_unref (pool); if (ret != GST_FLOW_OK) goto alloc_failed; pool = self->v4l2capture->pool; ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (pool), outbuf); } while (ret == GST_V4L2_FLOW_CORRUPTED_BUFFER); if (ret != GST_FLOW_OK) { gst_buffer_unref (*outbuf); *outbuf = NULL; } if (bclass->copy_metadata) if (!bclass->copy_metadata (trans, inbuf, *outbuf)) { /* something failed, post a warning */ GST_ELEMENT_WARNING (self, STREAM, NOT_IMPLEMENTED, ("could not copy metadata"), (NULL)); } beach: return ret; activate_failed: GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, ("failed to activate bufferpool"), ("failed to activate bufferpool")); g_object_unref (pool); return GST_FLOW_ERROR; alloc_failed: GST_DEBUG_OBJECT (self, "could not allocate buffer from pool"); return ret; }