GstBuffer * outbuf, GstMeta * meta, GstBuffer * inbuf);
static GstFlowReturn gst_audio_convert_submit_input_buffer (GstBaseTransform *
base, gboolean is_discont, GstBuffer * input);
+static GstFlowReturn gst_audio_convert_prepare_output_buffer (GstBaseTransform *
+ base, GstBuffer * inbuf, GstBuffer ** outbuf);
static void gst_audio_convert_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_audio_convert_get_property (GObject * object, guint prop_id,
#define STATIC_CAPS \
GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL) \
- ", layout = (string) interleaved")
+ ", layout = (string) { interleaved, non-interleaved }")
static GstStaticPadTemplate gst_audio_convert_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_DEBUG_FUNCPTR (gst_audio_convert_transform_meta);
basetransform_class->submit_input_buffer =
GST_DEBUG_FUNCPTR (gst_audio_convert_submit_input_buffer);
+ basetransform_class->prepare_output_buffer =
+ GST_DEBUG_FUNCPTR (gst_audio_convert_prepare_output_buffer);
basetransform_class->passthrough_on_same_caps = TRUE;
basetransform_class->transform_ip_on_passthrough = FALSE;
}
static gboolean
+remove_layout_from_structure (GstCapsFeatures * features,
+ GstStructure * structure, gpointer user_data G_GNUC_UNUSED)
+{
+ gst_structure_remove_field (structure, "layout");
+ return TRUE;
+}
+
+static gboolean
remove_channels_from_structure (GstCapsFeatures * features, GstStructure * s,
gpointer user_data)
{
tmp = gst_caps_copy (caps);
gst_caps_map_in_place (tmp, remove_format_from_structure, NULL);
+ gst_caps_map_in_place (tmp, remove_layout_from_structure, NULL);
gst_caps_map_in_place (tmp, remove_channels_from_structure, btrans);
/* We can infer the required input / output channels based on the
{
GstFlowReturn ret;
GstAudioConvert *this = GST_AUDIO_CONVERT (base);
- GstMapInfo srcmap = { NULL, }, dstmap;
- gint insize, outsize;
+ GstAudioBuffer srcabuf, dstabuf;
gboolean inbuf_writable;
GstAudioConverterFlags flags;
- gsize samples;
-
- /* get amount of samples to convert. */
- samples = gst_buffer_get_size (inbuf) / this->in_info.bpf;
-
- /* get in/output sizes, to see if the buffers we got are of correct
- * sizes */
- insize = samples * this->in_info.bpf;
- outsize = samples * this->out_info.bpf;
- if (insize == 0 || outsize == 0)
+ /* https://bugzilla.gnome.org/show_bug.cgi?id=396835 */
+ if (gst_buffer_get_size (inbuf) == 0)
return GST_FLOW_OK;
- gst_buffer_resize (outbuf, 0, outsize);
-
- /* get src and dst data */
if (inbuf != outbuf) {
inbuf_writable = gst_buffer_is_writable (inbuf)
&& gst_buffer_n_memory (inbuf) == 1
&& gst_memory_is_writable (gst_buffer_peek_memory (inbuf, 0));
- if (!gst_buffer_map (inbuf, &srcmap,
+ if (!gst_audio_buffer_map (&srcabuf, &this->in_info, inbuf,
inbuf_writable ? GST_MAP_READWRITE : GST_MAP_READ))
goto inmap_error;
} else {
inbuf_writable = TRUE;
}
- if (!gst_buffer_map (outbuf, &dstmap, GST_MAP_WRITE))
- goto outmap_error;
- /* check in and outsize */
- if (inbuf != outbuf) {
- if (srcmap.size < insize)
- goto wrong_size;
- }
- if (dstmap.size < outsize)
- goto wrong_size;
+ if (!gst_audio_buffer_map (&dstabuf, &this->out_info, outbuf, GST_MAP_WRITE))
+ goto outmap_error;
/* and convert the samples */
flags = 0;
flags |= GST_AUDIO_CONVERTER_FLAG_IN_WRITABLE;
if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
- gpointer in[1] = { srcmap.data };
- gpointer out[1] = { dstmap.data };
-
if (!gst_audio_converter_samples (this->convert, flags,
- inbuf != outbuf ? in : out, samples, out, samples))
+ inbuf != outbuf ? srcabuf.planes : dstabuf.planes,
+ dstabuf.n_samples, dstabuf.planes, dstabuf.n_samples))
goto convert_error;
} else {
/* Create silence buffer */
- gst_audio_format_fill_silence (this->out_info.finfo, dstmap.data, outsize);
+ gint i;
+ for (i = 0; i < dstabuf.n_planes; i++) {
+ gst_audio_format_fill_silence (this->out_info.finfo, dstabuf.planes[i],
+ GST_AUDIO_BUFFER_PLANE_SIZE (&dstabuf));
+ }
}
ret = GST_FLOW_OK;
done:
- gst_buffer_unmap (outbuf, &dstmap);
+ gst_audio_buffer_unmap (&dstabuf);
if (inbuf != outbuf)
- gst_buffer_unmap (inbuf, &srcmap);
+ gst_audio_buffer_unmap (&srcabuf);
return ret;
/* ERRORS */
-wrong_size:
- {
- GST_ELEMENT_ERROR (this, STREAM, FORMAT,
- (NULL),
- ("input/output buffers are of wrong size in: %" G_GSIZE_FORMAT " < %d"
- " or out: %" G_GSIZE_FORMAT " < %d",
- srcmap.size, insize, dstmap.size, outsize));
- ret = GST_FLOW_ERROR;
- goto done;
- }
convert_error:
{
GST_ELEMENT_ERROR (this, STREAM, FORMAT,
GST_ELEMENT_ERROR (this, STREAM, FORMAT,
(NULL), ("failed to map output buffer"));
if (inbuf != outbuf)
- gst_buffer_unmap (inbuf, &srcmap);
+ gst_audio_buffer_unmap (&srcabuf);
return GST_FLOW_ERROR;
}
}
is_discont, input);
}
+static GstFlowReturn
+gst_audio_convert_prepare_output_buffer (GstBaseTransform * base,
+ GstBuffer * inbuf, GstBuffer ** outbuf)
+{
+ GstAudioConvert *this = GST_AUDIO_CONVERT (base);
+ GstAudioMeta *meta;
+ GstFlowReturn ret;
+
+ ret = GST_BASE_TRANSFORM_CLASS (parent_class)->prepare_output_buffer (base,
+ inbuf, outbuf);
+
+ if (ret != GST_FLOW_OK)
+ return ret;
+
+ meta = gst_buffer_get_audio_meta (inbuf);
+
+ if (inbuf != *outbuf) {
+ gsize samples = meta ?
+ meta->samples : (gst_buffer_get_size (inbuf) / this->in_info.bpf);
+
+ /* ensure that the output buffer is not bigger than what we need */
+ gst_buffer_resize (*outbuf, 0, samples * this->out_info.bpf);
+
+ /* add the audio meta on the output buffer if it's planar */
+ if (this->out_info.layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
+ gst_buffer_add_audio_meta (*outbuf, &this->out_info, samples, NULL);
+ }
+ } else {
+ /* if the input buffer came with a GstAudioMeta,
+ * update it to reflect the properties of the output format */
+ if (meta)
+ meta->info = this->out_info;
+ }
+
+ return ret;
+}
+
static void
gst_audio_convert_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)