settings_changed (GstFFMpegAudDec * ffmpegdec, AVFrame * frame)
{
GstAudioFormat format;
+ GstAudioLayout layout;
gint channels = av_get_channel_layout_nb_channels (frame->channel_layout);
- format = gst_ffmpeg_smpfmt_to_audioformat (frame->format);
+ format = gst_ffmpeg_smpfmt_to_audioformat (frame->format, &layout);
if (format == GST_AUDIO_FORMAT_UNKNOWN)
return TRUE;
- return !(ffmpegdec->info.rate ==
- frame->sample_rate &&
+ return !(ffmpegdec->info.rate == frame->sample_rate &&
ffmpegdec->info.channels == channels &&
- ffmpegdec->info.finfo->format == format);
+ ffmpegdec->info.finfo->format == format &&
+ ffmpegdec->info.layout == layout);
}
static gboolean
{
GstFFMpegAudDecClass *oclass;
GstAudioFormat format;
+ GstAudioLayout layout;
gint channels;
GstAudioChannelPosition pos[64] = { 0, };
oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
- format = gst_ffmpeg_smpfmt_to_audioformat (frame->format);
+ format = gst_ffmpeg_smpfmt_to_audioformat (frame->format, &layout);
if (format == GST_AUDIO_FORMAT_UNKNOWN)
goto no_caps;
channels = av_get_channel_layout_nb_channels (frame->channel_layout);
return TRUE;
GST_DEBUG_OBJECT (ffmpegdec,
- "Renegotiating audio from %dHz@%dchannels (%d) to %dHz@%dchannels (%d)",
+ "Renegotiating audio from %dHz@%dchannels (%d, interleaved=%d) "
+ "to %dHz@%dchannels (%d, interleaved=%d)",
ffmpegdec->info.rate, ffmpegdec->info.channels,
- ffmpegdec->info.finfo->format, frame->sample_rate, channels, format);
+ ffmpegdec->info.finfo->format,
+ ffmpegdec->info.layout == GST_AUDIO_LAYOUT_INTERLEAVED,
+ frame->sample_rate, channels, format,
+ layout == GST_AUDIO_LAYOUT_INTERLEAVED);
gst_ffmpeg_channel_layout_to_gst (frame->channel_layout, channels, pos);
memcpy (ffmpegdec->ffmpeg_layout, pos,
memcmp (pos, ffmpegdec->ffmpeg_layout, sizeof (pos[0]) * channels) != 0;
gst_audio_info_set_format (&ffmpegdec->info, format,
frame->sample_rate, channels, pos);
+ ffmpegdec->info.layout = layout;
if (!gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (ffmpegdec),
&ffmpegdec->info))
if (res >= 0) {
gint nsamples, channels, byte_per_sample;
gsize output_size;
+ gboolean planar;
if (!gst_ffmpegauddec_negotiate (ffmpegdec, ffmpegdec->context,
ffmpegdec->frame, FALSE)) {
channels = ffmpegdec->info.channels;
nsamples = ffmpegdec->frame->nb_samples;
byte_per_sample = ffmpegdec->info.finfo->width / 8;
+ planar = av_sample_fmt_is_planar (ffmpegdec->context->sample_fmt);
+
+ g_return_val_if_fail (ffmpegdec->info.layout == (planar ?
+ GST_AUDIO_LAYOUT_NON_INTERLEAVED : GST_AUDIO_LAYOUT_INTERLEAVED),
+ GST_FLOW_NOT_NEGOTIATED);
+
+ GST_DEBUG_OBJECT (ffmpegdec, "Creating output buffer");
/* ffmpegdec->frame->linesize[0] might contain padding, allocate only what's needed */
output_size = nsamples * byte_per_sample * channels;
- GST_DEBUG_OBJECT (ffmpegdec, "Creating output buffer");
- if (av_sample_fmt_is_planar (ffmpegdec->context->sample_fmt)
- && channels > 1) {
- gint i, j;
- GstMapInfo minfo;
-
- /* note: linesize[0] might contain padding, allocate only what's needed */
- *outbuf =
- gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER
- (ffmpegdec), output_size);
-
- gst_buffer_map (*outbuf, &minfo, GST_MAP_WRITE);
-
- switch (ffmpegdec->info.finfo->width) {
- case 8:{
- guint8 *odata = minfo.data;
-
- for (i = 0; i < nsamples; i++) {
- for (j = 0; j < channels; j++) {
- odata[j] =
- ((const guint8 *) ffmpegdec->frame->extended_data[j])[i];
- }
- odata += channels;
- }
- break;
- }
- case 16:{
- guint16 *odata = (guint16 *) minfo.data;
-
- for (i = 0; i < nsamples; i++) {
- for (j = 0; j < channels; j++) {
- odata[j] =
- ((const guint16 *) ffmpegdec->frame->extended_data[j])[i];
- }
- odata += channels;
- }
- break;
- }
- case 32:{
- guint32 *odata = (guint32 *) minfo.data;
-
- for (i = 0; i < nsamples; i++) {
- for (j = 0; j < channels; j++) {
- odata[j] =
- ((const guint32 *) ffmpegdec->frame->extended_data[j])[i];
- }
- odata += channels;
- }
- break;
- }
- case 64:{
- guint64 *odata = (guint64 *) minfo.data;
-
- for (i = 0; i < nsamples; i++) {
- for (j = 0; j < channels; j++) {
- odata[j] =
- ((const guint64 *) ffmpegdec->frame->extended_data[j])[i];
- }
- odata += channels;
- }
- break;
- }
- default:
- g_assert_not_reached ();
- break;
+ *outbuf =
+ gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER
+ (ffmpegdec), output_size);
+
+ if (planar) {
+ gint i;
+ GstAudioMeta *meta;
+
+ meta = gst_buffer_add_audio_meta (*outbuf, &ffmpegdec->info, nsamples,
+ NULL);
+
+ for (i = 0; i < channels; i++) {
+ gst_buffer_fill (*outbuf, meta->offsets[i],
+ ffmpegdec->frame->extended_data[i], nsamples * byte_per_sample);
}
- gst_buffer_unmap (*outbuf, &minfo);
} else {
- *outbuf =
- gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER
- (ffmpegdec), output_size);
gst_buffer_fill (*outbuf, 0, ffmpegdec->frame->data[0], output_size);
}
static void
gst_ffmpeg_audio_set_sample_fmts (GstCaps * caps,
- const enum AVSampleFormat *fmts)
+ const enum AVSampleFormat *fmts, gboolean always_interleaved)
{
GValue va = { 0, };
+ GValue vap = { 0, };
GValue v = { 0, };
GstAudioFormat format;
+ GstAudioLayout layout;
+ GstCaps *caps_copy = NULL;
if (!fmts || fmts[0] == -1) {
gint i;
g_value_init (&va, GST_TYPE_LIST);
g_value_init (&v, G_TYPE_STRING);
for (i = 0; i <= AV_SAMPLE_FMT_DBL; i++) {
- format = gst_ffmpeg_smpfmt_to_audioformat (i);
+ format = gst_ffmpeg_smpfmt_to_audioformat (i, NULL);
if (format == GST_AUDIO_FORMAT_UNKNOWN)
continue;
g_value_set_string (&v, gst_audio_format_to_string (format));
gst_value_list_append_value (&va, &v);
}
gst_caps_set_value (caps, "format", &va);
+ if (!always_interleaved) {
+ g_value_init (&vap, GST_TYPE_LIST);
+ g_value_set_string (&v, "interleaved");
+ gst_value_list_append_value (&vap, &v);
+ g_value_set_string (&v, "non-interleaved");
+ gst_value_list_append_value (&vap, &v);
+ gst_caps_set_value (caps, "layout", &vap);
+ g_value_unset (&vap);
+ } else {
+ gst_caps_set_simple (caps, "layout", G_TYPE_STRING, "interleaved", NULL);
+ }
g_value_unset (&v);
g_value_unset (&va);
return;
}
g_value_init (&va, GST_TYPE_LIST);
+ g_value_init (&vap, GST_TYPE_LIST);
g_value_init (&v, G_TYPE_STRING);
while (*fmts != -1) {
- format = gst_ffmpeg_smpfmt_to_audioformat (*fmts);
+ format = gst_ffmpeg_smpfmt_to_audioformat (*fmts, &layout);
if (format != GST_AUDIO_FORMAT_UNKNOWN) {
g_value_set_string (&v, gst_audio_format_to_string (format));
/* Only append values we don't have yet */
- if (!_gst_value_list_contains (&va, &v))
- gst_value_list_append_value (&va, &v);
+ if (layout == GST_AUDIO_LAYOUT_INTERLEAVED || always_interleaved) {
+ if (!_gst_value_list_contains (&va, &v))
+ gst_value_list_append_value (&va, &v);
+ } else {
+ if (!_gst_value_list_contains (&vap, &v))
+ gst_value_list_append_value (&vap, &v);
+ }
}
fmts++;
}
+ if (gst_value_list_get_size (&va) >= 1 && gst_value_list_get_size (&vap) >= 1) {
+ caps_copy = gst_caps_copy (caps);
+ }
if (gst_value_list_get_size (&va) == 1) {
- /* The single value is still in v */
- gst_caps_set_value (caps, "format", &v);
+ gst_caps_set_value (caps, "format", gst_value_list_get_value (&va, 0));
+ gst_caps_set_simple (caps, "layout", G_TYPE_STRING, "interleaved", NULL);
} else if (gst_value_list_get_size (&va) > 1) {
gst_caps_set_value (caps, "format", &va);
+ gst_caps_set_simple (caps, "layout", G_TYPE_STRING, "interleaved", NULL);
+ }
+ if (gst_value_list_get_size (&vap) == 1) {
+ gst_caps_set_value (caps_copy ? caps_copy : caps, "format",
+ gst_value_list_get_value (&vap, 0));
+ gst_caps_set_simple (caps_copy ? caps_copy : caps, "layout", G_TYPE_STRING,
+ "non-interleaved", NULL);
+ } else if (gst_value_list_get_size (&vap) > 1) {
+ gst_caps_set_value (caps_copy ? caps_copy : caps, "format", &vap);
+ gst_caps_set_simple (caps_copy ? caps_copy : caps, "layout", G_TYPE_STRING,
+ "non-interleaved", NULL);
+ }
+ if (caps_copy) {
+ gst_caps_append (caps, caps_copy);
}
g_value_unset (&v);
g_value_unset (&va);
+ g_value_unset (&vap);
}
/* same for audio - now with channels/sample rate
}
GstAudioFormat
-gst_ffmpeg_smpfmt_to_audioformat (enum AVSampleFormat sample_fmt)
+gst_ffmpeg_smpfmt_to_audioformat (enum AVSampleFormat sample_fmt,
+ GstAudioLayout * layout)
{
+ if (layout)
+ *layout = GST_AUDIO_LAYOUT_NON_INTERLEAVED;
+
switch (sample_fmt) {
case AV_SAMPLE_FMT_U8:
+ if (layout)
+ *layout = GST_AUDIO_LAYOUT_INTERLEAVED;
case AV_SAMPLE_FMT_U8P:
return GST_AUDIO_FORMAT_U8;
break;
+
case AV_SAMPLE_FMT_S16:
+ if (layout)
+ *layout = GST_AUDIO_LAYOUT_INTERLEAVED;
case AV_SAMPLE_FMT_S16P:
return GST_AUDIO_FORMAT_S16;
break;
+
case AV_SAMPLE_FMT_S32:
+ if (layout)
+ *layout = GST_AUDIO_LAYOUT_INTERLEAVED;
case AV_SAMPLE_FMT_S32P:
return GST_AUDIO_FORMAT_S32;
break;
case AV_SAMPLE_FMT_FLT:
+ if (layout)
+ *layout = GST_AUDIO_LAYOUT_INTERLEAVED;
case AV_SAMPLE_FMT_FLTP:
return GST_AUDIO_FORMAT_F32;
break;
+
case AV_SAMPLE_FMT_DBL:
+ if (layout)
+ *layout = GST_AUDIO_LAYOUT_INTERLEAVED;
case AV_SAMPLE_FMT_DBLP:
return GST_AUDIO_FORMAT_F64;
break;
+
default:
/* .. */
return GST_AUDIO_FORMAT_UNKNOWN;
{
GstCaps *caps = NULL;
GstAudioFormat format;
+ GstAudioLayout layout;
- format = gst_ffmpeg_smpfmt_to_audioformat (sample_fmt);
+ format = gst_ffmpeg_smpfmt_to_audioformat (sample_fmt, &layout);
if (format != GST_AUDIO_FORMAT_UNKNOWN) {
caps = gst_ff_aud_caps_new (context, codec, codec_id, TRUE, "audio/x-raw",
"format", G_TYPE_STRING, gst_audio_format_to_string (format),
- "layout", G_TYPE_STRING, "interleaved", NULL);
+ "layout", G_TYPE_STRING,
+ (layout == GST_AUDIO_LAYOUT_INTERLEAVED) ?
+ "interleaved" : "non-interleaved", NULL);
GST_LOG ("caps for sample_fmt=%d: %" GST_PTR_FORMAT, sample_fmt, caps);
} else {
GST_LOG ("No caps found for sample_fmt=%d", sample_fmt);
codec_id);
} else {
caps = gst_ff_aud_caps_new (context, codec, codec_id, encode, "audio/x-raw",
- "layout", G_TYPE_STRING, "interleaved", NULL);
+ NULL);
if (!caps_has_field (caps, "format"))
gst_ffmpeg_audio_set_sample_fmts (caps,
- codec ? codec->sample_fmts : NULL);
+ codec ? codec->sample_fmts : NULL, encode);
}
return caps;
const gchar *fmt;
GstAudioFormat format = GST_AUDIO_FORMAT_UNKNOWN;
gint bitrate;
+ const gchar *layout;
+ gboolean interleaved;
g_return_if_fail (gst_caps_get_size (caps) == 1);
}
}
+ layout = gst_structure_get_string (structure, "layout");
+ interleaved = ! !g_strcmp0 (layout, "non-interleaved");
+
switch (format) {
case GST_AUDIO_FORMAT_F32:
- context->sample_fmt = AV_SAMPLE_FMT_FLT;
+ context->sample_fmt =
+ interleaved ? AV_SAMPLE_FMT_FLT : AV_SAMPLE_FMT_FLTP;
break;
case GST_AUDIO_FORMAT_F64:
- context->sample_fmt = AV_SAMPLE_FMT_DBL;
+ context->sample_fmt =
+ interleaved ? AV_SAMPLE_FMT_DBL : AV_SAMPLE_FMT_DBLP;
break;
case GST_AUDIO_FORMAT_S32:
- context->sample_fmt = AV_SAMPLE_FMT_S32;
+ context->sample_fmt =
+ interleaved ? AV_SAMPLE_FMT_S32 : AV_SAMPLE_FMT_S32P;
break;
case GST_AUDIO_FORMAT_S16:
- context->sample_fmt = AV_SAMPLE_FMT_S16;
+ context->sample_fmt =
+ interleaved ? AV_SAMPLE_FMT_S16 : AV_SAMPLE_FMT_S16P;
break;
default:
break;