mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-30 12:49:40 +00:00
audioconvert: implement support for converting between interleaved and non-interleaved layouts
https://bugzilla.gnome.org/show_bug.cgi?id=705986
This commit is contained in:
parent
060ecd16cd
commit
0eda002cfd
1 changed files with 67 additions and 44 deletions
|
@ -138,6 +138,8 @@ static gboolean gst_audio_convert_transform_meta (GstBaseTransform * trans,
|
|||
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,
|
||||
|
@ -169,7 +171,7 @@ G_DEFINE_TYPE_WITH_CODE (GstAudioConvert, gst_audio_convert,
|
|||
|
||||
#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",
|
||||
|
@ -243,6 +245,8 @@ gst_audio_convert_class_init (GstAudioConvertClass * klass)
|
|||
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;
|
||||
|
@ -307,6 +311,14 @@ remove_format_from_structure (GstCapsFeatures * features,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -352,6 +364,7 @@ gst_audio_convert_transform_caps (GstBaseTransform * btrans,
|
|||
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
|
||||
|
@ -792,47 +805,28 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
|
|||
{
|
||||
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;
|
||||
|
@ -840,36 +834,28 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
|
|||
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,
|
||||
|
@ -888,7 +874,7 @@ outmap_error:
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
@ -935,6 +921,43 @@ gst_audio_convert_submit_input_buffer (GstBaseTransform * base,
|
|||
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)
|
||||
|
|
Loading…
Reference in a new issue