...
 
......@@ -304,3 +304,176 @@ gst_audio_clipping_meta_get_info (void)
}
return audio_clipping_meta_info;
}
static gboolean
gst_audio_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
{
GstAudioMeta *ameta = (GstAudioMeta *) meta;
ameta->format = GST_AUDIO_FORMAT_UNKNOWN;
ameta->layout = GST_AUDIO_LAYOUT_INTERLEAVED;
ameta->channels = ameta->samples = 0;
ameta->offsets = NULL;
ameta->map = NULL;
ameta->unmap = NULL;
return TRUE;
}
static void
gst_audio_meta_free (GstMeta * meta, GstBuffer * buffer)
{
GstAudioMeta *ameta = (GstAudioMeta *) meta;
if (ameta->offsets)
g_slice_free1 (ameta->channels * sizeof (gsize), ameta->offsets);
}
static gboolean
gst_audio_meta_transform (GstBuffer * dest, GstMeta * meta,
GstBuffer * buffer, GQuark type, gpointer data)
{
GstAudioMeta *smeta, *dmeta;
smeta = (GstAudioMeta *) meta;
if (GST_META_TRANSFORM_IS_COPY (type)) {
dmeta = gst_buffer_add_audio_meta (dest, smeta->format, smeta->layout,
smeta->channels, smeta->samples, smeta->offsets);
if (!dmeta)
return FALSE;
} else {
/* return FALSE, if transform type is not supported */
return FALSE;
}
return TRUE;
}
GstAudioMeta *
gst_buffer_add_audio_meta (GstBuffer * buffer, GstAudioFormat format,
GstAudioLayout layout, gint channels, gint samples, gsize offsets[])
{
GstAudioMeta *meta;
gint i;
g_return_val_if_fail (format != GST_AUDIO_FORMAT_UNKNOWN, NULL);
meta =
(GstAudioMeta *) gst_buffer_add_meta (buffer, GST_AUDIO_META_INFO, NULL);
meta->format = format;
meta->layout = layout;
meta->channels = channels;
meta->samples = samples;
if (layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
meta->offsets = g_slice_alloc (channels * sizeof (gsize));
if (offsets) {
for (i = 0; i < channels; i++)
meta->offsets[i] = offsets[i];
} else {
/* default offsets assume channels are laid out sequentially in memory */
const GstAudioFormatInfo *finfo =
gst_audio_format_get_info (meta->format);
for (i = 0; i < channels; i++)
meta->offsets[i] = i * samples * finfo->width / 8;
}
}
return meta;
}
gboolean
gst_audio_buffer_map (GstBuffer * buffer, GstAudioMapInfo * info,
GstMapFlags flags)
{
GstAudioMeta *meta = NULL;
gboolean ret = TRUE;
gint i;
meta = gst_buffer_get_audio_meta (buffer);
if (meta && meta->map) {
ret = meta->map (meta, buffer, info, flags);
} else if (!meta || meta->layout == GST_AUDIO_LAYOUT_INTERLEAVED) {
/* interleaved */
if (!gst_buffer_map (buffer, &info->map_info, flags))
return FALSE;
info->n_planes = 1;
info->plane_size = info->map_info.size;
info->planes = g_slice_alloc (info->n_planes * sizeof (gpointer));
info->planes[0] = info->map_info.data;
} else {
/* non-interleaved */
const GstAudioFormatInfo *finfo = gst_audio_format_get_info (meta->format);
if (!gst_buffer_map (buffer, &info->map_info, flags))
return FALSE;
info->n_planes = meta->channels;
info->plane_size = meta->samples * finfo->width / 8;
if (info->n_planes * info->plane_size > info->map_info.size) {
GST_ERROR ("Invalid buffer size according to its attached GstAudioMeta");
gst_buffer_unmap (buffer, &info->map_info);
return FALSE;
}
info->planes = g_slice_alloc (info->n_planes * sizeof (gpointer));
for (i = 0; i < meta->channels; i++)
info->planes[i] = info->map_info.data + meta->offsets[i];
}
return ret;
}
void
gst_audio_buffer_unmap (GstBuffer * buffer, GstAudioMapInfo * info)
{
GstAudioMeta *meta = NULL;
meta = gst_buffer_get_audio_meta (buffer);
if (meta && meta->unmap) {
meta->unmap (meta, buffer, info);
} else {
gst_buffer_unmap (buffer, &info->map_info);
g_slice_free1 (info->n_planes * sizeof (gpointer), info->planes);
memset (info, 0, sizeof (GstAudioMapInfo));
}
}
GType
gst_audio_meta_api_get_type (void)
{
static volatile GType type;
static const gchar *tags[] = {
GST_META_TAG_AUDIO_STR, GST_META_TAG_AUDIO_CHANNELS_STR,
GST_META_TAG_AUDIO_RATE_STR, NULL
};
if (g_once_init_enter (&type)) {
GType _type = gst_meta_api_type_register ("GstAudioMetaAPI", tags);
g_once_init_leave (&type, _type);
}
return type;
}
const GstMetaInfo *
gst_audio_meta_get_info (void)
{
static const GstMetaInfo *audio_meta_info = NULL;
if (g_once_init_enter ((GstMetaInfo **) & audio_meta_info)) {
const GstMetaInfo *meta = gst_meta_register (GST_AUDIO_META_API_TYPE,
"GstAudioMeta", sizeof (GstAudioMeta),
gst_audio_meta_init,
gst_audio_meta_free,
gst_audio_meta_transform);
g_once_init_leave ((GstMetaInfo **) & audio_meta_info,
(GstMetaInfo *) meta);
}
return audio_meta_info;
}
......@@ -125,6 +125,65 @@ GstAudioClippingMeta * gst_buffer_add_audio_clipping_meta (GstBuffer *buffer,
guint64 start,
guint64 end);
#define GST_AUDIO_META_API_TYPE (gst_audio_meta_api_get_type())
#define GST_AUDIO_META_INFO (gst_audio_meta_get_info())
typedef struct _GstAudioMeta GstAudioMeta;
typedef struct {
gint n_planes;
gsize plane_size;
gpointer *planes;
GstMapInfo map_info;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
} GstAudioMapInfo;
struct _GstAudioMeta {
GstMeta meta;
GstAudioFormat format;
GstAudioLayout layout;
gint channels;
gint samples;
gsize *offsets;
gboolean (*map) (GstAudioMeta * meta, GstBuffer * buffer,
GstAudioMapInfo * info, GstMapFlags flags);
void (*unmap) (GstAudioMeta * meta, GstBuffer *buffer,
GstAudioMapInfo *info);
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
GST_EXPORT
GType gst_audio_meta_api_get_type (void);
GST_EXPORT
const GstMetaInfo * gst_audio_meta_get_info (void);
#define gst_buffer_get_audio_meta(b) \
((GstAudioMeta*)gst_buffer_get_meta((b), GST_AUDIO_META_API_TYPE))
GST_EXPORT
GstAudioMeta * gst_buffer_add_audio_meta (GstBuffer *buffer,
GstAudioFormat format,
GstAudioLayout layout,
gint channels, gint samples,
gsize offsets[]);
GST_EXPORT
gboolean gst_audio_buffer_map (GstBuffer *buffer, GstAudioMapInfo *info,
GstMapFlags flags);
GST_EXPORT
void gst_audio_buffer_unmap (GstBuffer *buffer, GstAudioMapInfo *info);
G_END_DECLS
#endif /* __GST_AUDIO_META_H__ */
......@@ -267,8 +267,6 @@ gst_audio_convert_dispose (GObject * obj)
gst_audio_converter_free (this->convert);
this->convert = NULL;
}
g_clear_pointer (&this->in, g_free);
g_clear_pointer (&this->out, g_free);
g_value_unset (&this->mix_matrix);
......@@ -776,19 +774,6 @@ gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
this->in_info = in_info;
this->out_info = out_info;
/* allocate arrays to hold channel pointers */
g_free (this->in);
if (in_info.layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED)
this->in = g_malloc0 (in_info.channels * sizeof (gpointer));
else
this->in = g_malloc0 (sizeof (gpointer));
g_free (this->out);
if (out_info.layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED)
this->out = g_malloc0 (out_info.channels * sizeof (gpointer));
else
this->out = g_malloc0 (sizeof (gpointer));
return TRUE;
/* ERRORS */
......@@ -816,14 +801,17 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
{
GstFlowReturn ret;
GstAudioConvert *this = GST_AUDIO_CONVERT (base);
GstMapInfo srcmap = { NULL, }, dstmap;
GstAudioMeta *meta;
GstAudioMapInfo srcmap, dstmap;
gint insize, outsize;
gboolean inbuf_writable;
GstAudioConverterFlags flags;
gsize samples;
/* get amount of samples to convert. */
samples = gst_buffer_get_size (inbuf) / this->in_info.bpf;
meta = gst_buffer_get_audio_meta (inbuf);
samples =
meta ? meta->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 */
......@@ -835,27 +823,33 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
gst_buffer_resize (outbuf, 0, outsize);
if (inbuf != outbuf &&
this->out_info.layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
gst_buffer_add_audio_meta (outbuf, this->out_info.finfo->format,
this->out_info.layout, this->out_info.channels, samples, NULL);
}
/* 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 (inbuf, &srcmap,
inbuf_writable ? GST_MAP_READWRITE : GST_MAP_READ))
goto inmap_error;
} else {
inbuf_writable = TRUE;
}
if (!gst_buffer_map (outbuf, &dstmap, GST_MAP_WRITE))
if (!gst_audio_buffer_map (outbuf, &dstmap, GST_MAP_WRITE))
goto outmap_error;
/* check in and outsize */
if (inbuf != outbuf) {
if (srcmap.size < insize)
if (srcmap.n_planes * srcmap.plane_size < insize)
goto wrong_size;
}
if (dstmap.size < outsize)
if (dstmap.n_planes * dstmap.plane_size < outsize)
goto wrong_size;
/* and convert the samples */
......@@ -864,41 +858,24 @@ 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)) {
gint i;
/* TODO use GstAudioMeta */
if (inbuf != outbuf) {
this->in[0] = srcmap.data;
if (this->in_info.layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
for (i = 1; i < this->in_info.channels; i++) {
this->in[i] =
srcmap.data + i * samples * this->in_info.finfo->width / 8;
}
}
}
this->out[0] = dstmap.data;
if (this->out_info.layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
for (i = 1; i < this->out_info.channels; i++) {
this->out[i] =
dstmap.data + i * samples * this->out_info.finfo->width / 8;
}
}
if (!gst_audio_converter_samples (this->convert, flags,
inbuf != outbuf ? this->in : this->out, samples,
this->out, samples))
inbuf != outbuf ? srcmap.planes : dstmap.planes, samples,
dstmap.planes, 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 < dstmap.n_planes; i++) {
gst_audio_format_fill_silence (this->out_info.finfo, dstmap.planes[i],
dstmap.plane_size);
}
}
ret = GST_FLOW_OK;
done:
gst_buffer_unmap (outbuf, &dstmap);
gst_audio_buffer_unmap (outbuf, &dstmap);
if (inbuf != outbuf)
gst_buffer_unmap (inbuf, &srcmap);
gst_audio_buffer_unmap (inbuf, &srcmap);
return ret;
......@@ -909,7 +886,8 @@ wrong_size:
(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));
srcmap.n_planes * srcmap.plane_size, insize,
dstmap.n_planes * dstmap.plane_size, outsize));
ret = GST_FLOW_ERROR;
goto done;
}
......@@ -931,7 +909,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 (inbuf, &srcmap);
return GST_FLOW_ERROR;
}
}
......
......@@ -53,7 +53,6 @@ struct _GstAudioConvert
GstAudioInfo in_info;
GstAudioInfo out_info;
GstAudioConverter *convert;
gpointer *in, *out;
};
struct _GstAudioConvertClass
......
......@@ -1437,6 +1437,12 @@ gst_audio_test_src_fill (GstBaseSrc * basesrc, guint64 offset,
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_GAP);
}
if (src->info.layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
gst_buffer_add_audio_meta (buffer, src->info.finfo->format,
src->info.layout, src->info.channels, src->generate_samples_per_buffer,
NULL);
}
return GST_FLOW_OK;
}
......