flac: Port to the new raw audio caps

This commit is contained in:
Sebastian Dröge 2012-01-06 09:40:22 +01:00
parent 6c800137d8
commit a22a566c0b
5 changed files with 216 additions and 184 deletions

View file

@ -316,7 +316,7 @@ dnl Make sure you have a space before and after all plugins
GST_PLUGINS_NONPORTED="deinterlace interleave flx goom2k1 \
imagefreeze interleave monoscope smpte \
videobox videomixer \
cairo cairo_gobject dv1394 flac gdk_pixbuf libdv libpng \
cairo cairo_gobject dv1394 gdk_pixbuf libdv libpng \
oss oss4 shout2 \
taglib wavpack \
osx_video osx_audio "

View file

@ -45,12 +45,11 @@
#include "gstflacdec.h"
#include <gst/gst-i18n-plugin.h>
#include <gst/audio/multichannel.h>
#include <gst/tag/tag.h>
/* Taken from http://flac.sourceforge.net/format.html#frame_header */
static const GstAudioChannelPosition channel_positions[8][8] = {
{GST_AUDIO_CHANNEL_POSITION_FRONT_MONO},
{GST_AUDIO_CHANNEL_POSITION_MONO},
{GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
@ -68,7 +67,7 @@ static const GstAudioChannelPosition channel_positions[8][8] = {
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
GST_AUDIO_CHANNEL_POSITION_LFE,
GST_AUDIO_CHANNEL_POSITION_LFE1,
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
/* FIXME: 7/8 channel layouts are not defined in the FLAC specs */
@ -78,14 +77,14 @@ static const GstAudioChannelPosition channel_positions[8][8] = {
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
GST_AUDIO_CHANNEL_POSITION_LFE,
GST_AUDIO_CHANNEL_POSITION_LFE1,
GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
GST_AUDIO_CHANNEL_POSITION_LFE,
GST_AUDIO_CHANNEL_POSITION_LFE1,
GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
};
@ -120,12 +119,10 @@ G_DEFINE_TYPE (GstFlacDec, gst_flac_dec, GST_TYPE_AUDIO_DECODER);
#define FORMATS "{ S8BE, S16BE, S32BE } "
#endif
/* FIXME 0.11: Use width=32 for all depths and let audioconvert
* handle the conversions instead of doing it ourself.
*/
#define GST_FLAC_DEC_SRC_CAPS \
"audio/x-raw, " \
"format = (string) " FORMATS ", " \
"layout = (string) interleaved, " \
"rate = (int) [ 1, 655350 ], " \
"channels = (int) [ 1, 8 ]"
@ -193,6 +190,9 @@ gst_flac_dec_start (GstAudioDecoder * audio_dec)
dec->decoder = FLAC__stream_decoder_new ();
gst_audio_info_init (&dec->info);
dec->depth = 0;
/* no point calculating MD5 since it's never checked here */
FLAC__stream_decoder_set_md5_checking (dec->decoder, false);
@ -405,10 +405,10 @@ gst_flac_dec_scan_got_frame (GstFlacDec * flacdec, guint8 * data, guint size,
GST_DEBUG_OBJECT (flacdec, "frame number: %" G_GINT64_FORMAT,
*last_sample_num);
if (flacdec->sample_rate > 0 && *last_sample_num != 0) {
if (flacdec->info.rate > 0 && *last_sample_num != 0) {
GST_DEBUG_OBJECT (flacdec, "last sample %" G_GINT64_FORMAT " = %"
GST_TIME_FORMAT, *last_sample_num,
GST_TIME_ARGS (*last_sample_num * GST_SECOND / flacdec->sample_rate));
GST_TIME_ARGS (*last_sample_num * GST_SECOND / flacdec->info.rate));
}
return TRUE;
@ -425,29 +425,42 @@ gst_flac_dec_metadata_cb (const FLAC__StreamDecoder * decoder,
switch (metadata->type) {
case FLAC__METADATA_TYPE_STREAMINFO:{
gint64 samples;
guint depth;
guint depth, width;
samples = metadata->data.stream_info.total_samples;
flacdec->min_blocksize = metadata->data.stream_info.min_blocksize;
flacdec->max_blocksize = metadata->data.stream_info.max_blocksize;
flacdec->sample_rate = metadata->data.stream_info.sample_rate;
flacdec->depth = depth = metadata->data.stream_info.bits_per_sample;
flacdec->channels = metadata->data.stream_info.channels;
if (depth < 9)
flacdec->width = 8;
width = 8;
else if (depth < 17)
flacdec->width = 16;
width = 16;
else
flacdec->width = 32;
width = 32;
gst_audio_info_set_format (&flacdec->info,
gst_audio_format_build_integer (TRUE, G_BYTE_ORDER, width, width),
metadata->data.stream_info.sample_rate,
metadata->data.stream_info.channels, NULL);
memcpy (flacdec->info.position,
channel_positions[flacdec->info.channels - 1],
sizeof (GstAudioChannelPosition) * flacdec->info.channels);
gst_audio_channel_positions_to_valid_order (flacdec->info.position,
flacdec->info.channels);
/* Note: we create the inverse reordering map here */
gst_audio_get_channel_reorder_map (flacdec->info.channels,
flacdec->info.position, channel_positions[flacdec->info.channels - 1],
flacdec->channel_reorder_map);
GST_DEBUG_OBJECT (flacdec, "blocksize: min=%u, max=%u",
flacdec->min_blocksize, flacdec->max_blocksize);
GST_DEBUG_OBJECT (flacdec, "sample rate: %u, channels: %u",
flacdec->sample_rate, flacdec->channels);
flacdec->info.rate, flacdec->info.channels);
GST_DEBUG_OBJECT (flacdec, "depth: %u, width: %u", flacdec->depth,
flacdec->width);
flacdec->info.finfo->width);
GST_DEBUG_OBJECT (flacdec, "total samples = %" G_GINT64_FORMAT, samples);
break;
@ -524,7 +537,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
guint j, i;
gpointer data;
gsize size;
const gchar *format;
gboolean caps_changed;
GST_LOG_OBJECT (flacdec, "samples in frame header: %d", samples);
@ -537,29 +550,20 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
}
depth = flacdec->depth;
if (depth < 9)
depth = 8;
else if (depth < 17)
depth = 16;
else
depth = 32;
}
switch (depth) {
case 8:
width = 8;
format = GST_AUDIO_NE (S8);
break;
case 12:
case 16:
width = 16;
format = GST_AUDIO_NE (S16);
break;
case 20:
case 24:
case 32:
width = 32;
format = GST_AUDIO_NE (S32);
break;
default:
GST_ERROR_OBJECT (flacdec, "unsupported depth %d", depth);
@ -568,8 +572,8 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
}
if (sample_rate == 0) {
if (flacdec->sample_rate != 0) {
sample_rate = flacdec->sample_rate;
if (flacdec->info.rate != 0) {
sample_rate = flacdec->info.rate;
} else {
GST_ERROR_OBJECT (flacdec, "unknown sample rate");
ret = GST_FLOW_ERROR;
@ -577,27 +581,34 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
}
}
if (!gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (flacdec))) {
caps_changed = (sample_rate != flacdec->info.rate)
|| (width != flacdec->info.finfo->width)
|| (channels != flacdec->info.channels);
if (caps_changed
|| !gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (flacdec))) {
GstCaps *caps;
GST_DEBUG_OBJECT (flacdec, "Negotiating %d Hz @ %d channels",
frame->header.sample_rate, channels);
GST_DEBUG_OBJECT (flacdec, "Negotiating %d Hz @ %d channels", sample_rate,
channels);
caps = gst_caps_new_simple ("audio/x-raw",
"format", G_TYPE_STRING, format,
"rate", G_TYPE_INT, frame->header.sample_rate,
"channels", G_TYPE_INT, channels, NULL);
gst_audio_info_set_format (&flacdec->info,
gst_audio_format_build_integer (TRUE, G_BYTE_ORDER, width, width),
sample_rate, channels, NULL);
if (channels > 2) {
GstStructure *s = gst_caps_get_structure (caps, 0);
memcpy (flacdec->info.position,
channel_positions[flacdec->info.channels - 1],
sizeof (GstAudioChannelPosition) * flacdec->info.channels);
gst_audio_channel_positions_to_valid_order (flacdec->info.position,
flacdec->info.channels);
/* Note: we create the inverse reordering map here */
gst_audio_get_channel_reorder_map (flacdec->info.channels,
flacdec->info.position, channel_positions[flacdec->info.channels - 1],
flacdec->channel_reorder_map);
gst_audio_set_channel_positions (s, channel_positions[channels - 1]);
}
caps = gst_audio_info_to_caps (&flacdec->info);
flacdec->depth = depth;
flacdec->width = width;
flacdec->channels = channels;
flacdec->sample_rate = sample_rate;
gst_audio_decoder_set_outcaps (GST_AUDIO_DECODER (flacdec), caps);
gst_caps_unref (caps);
@ -609,26 +620,55 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
data = gst_buffer_map (outbuf, &size, NULL, GST_MAP_WRITE);
if (width == 8) {
gint8 *outbuffer = (gint8 *) data;
gint *reorder_map = flacdec->channel_reorder_map;
for (i = 0; i < samples; i++) {
for (j = 0; j < channels; j++) {
*outbuffer++ = (gint8) buffer[j][i];
if (width != depth) {
for (i = 0; i < samples; i++) {
for (j = 0; j < channels; j++) {
*outbuffer++ = (gint8) (buffer[reorder_map[j]][i] >> (width - depth));
}
}
} else {
for (i = 0; i < samples; i++) {
for (j = 0; j < channels; j++) {
*outbuffer++ = (gint8) buffer[reorder_map[j]][i];
}
}
}
} else if (width == 16) {
gint16 *outbuffer = (gint16 *) data;
gint *reorder_map = flacdec->channel_reorder_map;
for (i = 0; i < samples; i++) {
for (j = 0; j < channels; j++) {
*outbuffer++ = (gint16) buffer[j][i];
if (width != depth) {
for (i = 0; i < samples; i++) {
for (j = 0; j < channels; j++) {
*outbuffer++ =
(gint16) (buffer[reorder_map[j]][i] >> (width - depth));
}
}
} else {
for (i = 0; i < samples; i++) {
for (j = 0; j < channels; j++) {
*outbuffer++ = (gint16) buffer[reorder_map[j]][i];
}
}
}
} else if (width == 32) {
gint32 *outbuffer = (gint32 *) data;
gint *reorder_map = flacdec->channel_reorder_map;
for (i = 0; i < samples; i++) {
for (j = 0; j < channels; j++) {
*outbuffer++ = (gint32) buffer[j][i];
if (width != depth) {
for (i = 0; i < samples; i++) {
for (j = 0; j < channels; j++) {
*outbuffer++ =
(gint32) (buffer[reorder_map[j]][i] >> (width - depth));
}
}
} else {
for (i = 0; i < samples; i++) {
for (j = 0; j < channels; j++) {
*outbuffer++ = (gint32) buffer[reorder_map[j]][i];
}
}
}
} else {

View file

@ -23,6 +23,7 @@
#define __GST_FLAC_DEC_H__
#include <gst/gst.h>
#include <gst/audio/audio.h>
#include <gst/audio/gstaudiodecoder.h>
#include <FLAC/all.h>
@ -50,10 +51,9 @@ struct _GstFlacDec {
GstFlowReturn last_flow; /* to marshal flow return from finis_frame to
* handle_frame via flac callbacks */
gint channels;
GstAudioInfo info;
gint channel_reorder_map[8];
gint depth;
gint width;
gint sample_rate;
/* from the stream info, needed for scanning */
guint16 min_blocksize;

View file

@ -45,13 +45,12 @@
#include <gstflacenc.h>
#include <gst/audio/audio.h>
#include <gst/audio/multichannel.h>
#include <gst/tag/tag.h>
#include <gst/gsttagsetter.h>
/* Taken from http://flac.sourceforge.net/format.html#frame_header */
static const GstAudioChannelPosition channel_positions[8][8] = {
{GST_AUDIO_CHANNEL_POSITION_FRONT_MONO},
{GST_AUDIO_CHANNEL_POSITION_MONO},
{GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
@ -69,7 +68,7 @@ static const GstAudioChannelPosition channel_positions[8][8] = {
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
GST_AUDIO_CHANNEL_POSITION_LFE,
GST_AUDIO_CHANNEL_POSITION_LFE1,
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
/* FIXME: 7/8 channel layouts are not defined in the FLAC specs */
@ -79,40 +78,30 @@ static const GstAudioChannelPosition channel_positions[8][8] = {
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
GST_AUDIO_CHANNEL_POSITION_LFE,
GST_AUDIO_CHANNEL_POSITION_LFE1,
GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
GST_AUDIO_CHANNEL_POSITION_LFE,
GST_AUDIO_CHANNEL_POSITION_LFE1,
GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
};
#define FLAC_SINK_CAPS \
"audio/x-raw-int, " \
"endianness = (int) BYTE_ORDER, " \
"signed = (boolean) TRUE, " \
"width = (int) 8, " \
"depth = (int) 8, " \
"rate = (int) [ 1, 655350 ], " \
"channels = (int) [ 1, 8 ]; " \
"audio/x-raw-int, " \
"endianness = (int) BYTE_ORDER, " \
"signed = (boolean) TRUE, " \
"width = (int) 16, " \
"depth = (int) { 12, 16 }, " \
"rate = (int) [ 1, 655350 ], " \
"channels = (int) [ 1, 8 ]; " \
"audio/x-raw-int, " \
"endianness = (int) BYTE_ORDER, " \
"signed = (boolean) TRUE, " \
"width = (int) 32, " \
"depth = (int) { 20, 24 }, " \
"rate = (int) [ 1, 655350 ], " \
"channels = (int) [ 1, 8 ]"
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define FORMATS "{ S8LE, S16LE, S24LE, S32LE } "
#else
#define FORMATS "{ S8BE, S16BE, S24BE, S32BE } "
#endif
#define FLAC_SINK_CAPS \
"audio/x-raw, " \
"format = (string) " FORMATS ", " \
"layout = (string) interleaved, " \
"rate = (int) [ 1, 655350 ], " \
"channels = (int) [ 1, 8 ]"
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
@ -424,9 +413,6 @@ gst_flac_enc_start (GstAudioEncoder * enc)
flacenc->got_headers = FALSE;
flacenc->last_flow = GST_FLOW_OK;
flacenc->offset = 0;
flacenc->channels = 0;
flacenc->depth = 0;
flacenc->sample_rate = 0;
flacenc->eos = FALSE;
flacenc->tags = gst_tag_list_new_empty ();
@ -502,6 +488,8 @@ gst_flac_enc_set_metadata (GstFlacEnc * flacenc, guint64 total_samples)
GstTagList *copy;
gint entries = 1;
gint n_images, n_preview_images;
GstAudioInfo *info =
gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc));
g_return_if_fail (flacenc != NULL);
user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (flacenc));
@ -586,7 +574,7 @@ gst_flac_enc_set_metadata (GstFlacEnc * flacenc, guint64 total_samples)
FLAC__metadata_object_seektable_template_append_spaced_points
(flacenc->meta[entries], flacenc->seekpoints, total_samples);
} else {
samples = -flacenc->seekpoints * flacenc->sample_rate;
samples = -flacenc->seekpoints * GST_AUDIO_INFO_RATE (info);
res =
FLAC__metadata_object_seektable_template_append_spaced_points_by_samples
(flacenc->meta[entries], samples, total_samples);
@ -617,49 +605,6 @@ gst_flac_enc_set_metadata (GstFlacEnc * flacenc, guint64 total_samples)
gst_tag_list_free (copy);
}
static void
gst_flac_enc_caps_append_structure_with_widths (GstCaps * caps,
GstStructure * s)
{
GstStructure *tmp;
GValue list = { 0, };
GValue depth = { 0, };
tmp = gst_structure_copy (s);
gst_structure_set (tmp, "width", G_TYPE_INT, 8, "depth", G_TYPE_INT, 8, NULL);
gst_caps_append_structure (caps, tmp);
tmp = gst_structure_copy (s);
g_value_init (&depth, G_TYPE_INT);
g_value_init (&list, GST_TYPE_LIST);
g_value_set_int (&depth, 12);
gst_value_list_append_value (&list, &depth);
g_value_set_int (&depth, 16);
gst_value_list_append_value (&list, &depth);
gst_structure_set (tmp, "width", G_TYPE_INT, 16, NULL);
gst_structure_set_value (tmp, "depth", &list);
gst_caps_append_structure (caps, tmp);
g_value_reset (&list);
tmp = s;
g_value_set_int (&depth, 20);
gst_value_list_append_value (&list, &depth);
g_value_set_int (&depth, 24);
gst_value_list_append_value (&list, &depth);
gst_structure_set (tmp, "width", G_TYPE_INT, 32, NULL);
gst_structure_set_value (tmp, "depth", &list);
gst_caps_append_structure (caps, tmp);
g_value_unset (&list);
g_value_unset (&depth);
}
static GstCaps *
gst_flac_enc_getcaps (GstAudioEncoder * enc, GstCaps * filter)
{
@ -673,41 +618,49 @@ gst_flac_enc_getcaps (GstAudioEncoder * enc, GstCaps * filter)
if (gst_pad_has_current_caps (pad)) {
ret = gst_pad_get_current_caps (pad);
} else {
gint i, c;
gint i;
GValue v_arr = { 0, };
GValue v = { 0, };
GstStructure *s, *s2;
g_value_init (&v_arr, GST_TYPE_ARRAY);
g_value_init (&v, G_TYPE_STRING);
g_value_set_string (&v, GST_AUDIO_NE (S8));
gst_value_array_append_value (&v_arr, &v);
g_value_set_string (&v, GST_AUDIO_NE (S16));
gst_value_array_append_value (&v_arr, &v);
g_value_set_string (&v, GST_AUDIO_NE (S24));
gst_value_array_append_value (&v_arr, &v);
g_value_set_string (&v, GST_AUDIO_NE (S32));
gst_value_array_append_value (&v_arr, &v);
g_value_unset (&v);
s = gst_structure_new_empty ("audio/x-raw");
gst_structure_set_value (s, "format", &v_arr);
g_value_unset (&v_arr);
gst_structure_set (s, "layout", G_TYPE_STRING, "interleaved",
"rate", GST_TYPE_INT_RANGE, 1, 655350, NULL);
ret = gst_caps_new_empty ();
for (i = 1; i <= 8; i++) {
s2 = gst_structure_copy (s);
gst_flac_enc_caps_append_structure_with_widths (ret,
gst_structure_new ("audio/x-raw-int",
"endianness", G_TYPE_INT, G_BYTE_ORDER,
"signed", G_TYPE_BOOLEAN, TRUE,
"rate", GST_TYPE_INT_RANGE, 1, 655350,
"channels", GST_TYPE_INT_RANGE, 1, 2, NULL));
if (i == 1) {
gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
} else {
guint64 channel_mask;
for (i = 3; i <= 8; i++) {
GValue positions = { 0, };
GValue pos = { 0, };
GstStructure *s;
g_value_init (&positions, GST_TYPE_ARRAY);
g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION);
for (c = 0; c < i; c++) {
g_value_set_enum (&pos, channel_positions[i - 1][c]);
gst_value_array_append_value (&positions, &pos);
gst_audio_channel_positions_to_mask (channel_positions[i - 1], i,
&channel_mask);
gst_structure_set (s, "channels", G_TYPE_INT, 1, "channel-mask",
GST_TYPE_BITMASK, channel_mask, NULL);
}
g_value_unset (&pos);
s = gst_structure_new ("audio/x-raw-int",
"endianness", G_TYPE_INT, G_BYTE_ORDER,
"signed", G_TYPE_BOOLEAN, TRUE,
"rate", GST_TYPE_INT_RANGE, 1, 655350,
"channels", G_TYPE_INT, i, NULL);
gst_structure_set_value (s, "channel-positions", &positions);
g_value_unset (&positions);
gst_flac_enc_caps_append_structure_with_widths (ret, s);
gst_caps_append_structure (ret, s2);
}
gst_structure_free (s);
}
GST_OBJECT_UNLOCK (pad);
@ -724,6 +677,8 @@ static guint64
gst_flac_enc_peer_query_total_samples (GstFlacEnc * flacenc, GstPad * pad)
{
gint64 duration;
GstAudioInfo *info =
gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc));
GST_DEBUG_OBJECT (flacenc, "querying peer for DEFAULT format duration");
if (gst_pad_peer_query_duration (pad, GST_FORMAT_DEFAULT, &duration)
@ -736,7 +691,7 @@ gst_flac_enc_peer_query_total_samples (GstFlacEnc * flacenc, GstPad * pad)
&& duration != GST_CLOCK_TIME_NONE) {
GST_DEBUG_OBJECT (flacenc, "peer reported duration %" GST_TIME_FORMAT,
GST_TIME_ARGS (duration));
duration = GST_CLOCK_TIME_TO_FRAMES (duration, flacenc->sample_rate);
duration = GST_CLOCK_TIME_TO_FRAMES (duration, GST_AUDIO_INFO_RATE (info));
goto done;
}
@ -766,26 +721,28 @@ gst_flac_enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
FLAC__STREAM_ENCODER_UNINITIALIZED)
goto encoder_already_initialized;
flacenc->channels = GST_AUDIO_INFO_CHANNELS (info);
flacenc->width = GST_AUDIO_INFO_WIDTH (info);
flacenc->depth = GST_AUDIO_INFO_DEPTH (info);
flacenc->sample_rate = GST_AUDIO_INFO_RATE (info);
caps = gst_caps_new_simple ("audio/x-flac",
"channels", G_TYPE_INT, flacenc->channels,
"rate", G_TYPE_INT, flacenc->sample_rate, NULL);
"channels", G_TYPE_INT, GST_AUDIO_INFO_CHANNELS (info),
"rate", G_TYPE_INT, GST_AUDIO_INFO_RATE (info), NULL);
if (!gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps))
goto setting_src_caps_failed;
gst_caps_unref (caps);
gst_audio_get_channel_reorder_map (GST_AUDIO_INFO_CHANNELS (info),
channel_positions[GST_AUDIO_INFO_CHANNELS (info) - 1], info->position,
flacenc->channel_reorder_map);
total_samples = gst_flac_enc_peer_query_total_samples (flacenc,
GST_AUDIO_ENCODER_SINK_PAD (enc));
FLAC__stream_encoder_set_bits_per_sample (flacenc->encoder, flacenc->depth);
FLAC__stream_encoder_set_sample_rate (flacenc->encoder, flacenc->sample_rate);
FLAC__stream_encoder_set_channels (flacenc->encoder, flacenc->channels);
FLAC__stream_encoder_set_bits_per_sample (flacenc->encoder,
GST_AUDIO_INFO_WIDTH (info));
FLAC__stream_encoder_set_sample_rate (flacenc->encoder,
GST_AUDIO_INFO_RATE (info));
FLAC__stream_encoder_set_channels (flacenc->encoder,
GST_AUDIO_INFO_CHANNELS (info));
if (total_samples != GST_CLOCK_TIME_NONE)
FLAC__stream_encoder_set_total_samples_estimate (flacenc->encoder,
@ -833,6 +790,9 @@ failed_to_initialize:
static gboolean
gst_flac_enc_update_quality (GstFlacEnc * flacenc, gint quality)
{
GstAudioInfo *info =
gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc));
flacenc->quality = quality;
#define DO_UPDATE(name, val, str) \
@ -847,7 +807,8 @@ gst_flac_enc_update_quality (GstFlacEnc * flacenc, gint quality)
g_object_freeze_notify (G_OBJECT (flacenc));
if (flacenc->channels == 2 || flacenc->channels == 0) {
if (GST_AUDIO_INFO_CHANNELS (info) == 2
|| GST_AUDIO_INFO_CHANNELS (info) == 0) {
DO_UPDATE (do_mid_side_stereo, mid_side, "mid_side_stereo");
DO_UPDATE (loose_mid_side_stereo, loose_mid_side, "loose_mid_side");
}
@ -945,10 +906,12 @@ gst_flac_enc_process_stream_headers (GstFlacEnc * enc)
GstCaps *caps;
GList *l;
GstFlowReturn ret = GST_FLOW_OK;
GstAudioInfo *info =
gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (enc));
caps = gst_caps_new_simple ("audio/x-flac",
"channels", G_TYPE_INT, enc->channels,
"rate", G_TYPE_INT, enc->sample_rate, NULL);
"channels", G_TYPE_INT, GST_AUDIO_INFO_CHANNELS (info),
"rate", G_TYPE_INT, GST_AUDIO_INFO_RATE (info), NULL);
for (l = enc->headers; l != NULL; l = l->next) {
GstBuffer *buf;
@ -1193,23 +1156,36 @@ gst_flac_enc_sink_event (GstAudioEncoder * enc, GstEvent * event)
return ret;
}
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define READ_INT24 GST_READ_UINT24_LE
#else
#define READ_INT24 GST_READ_UINT24_BE
#endif
static GstFlowReturn
gst_flac_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
{
GstFlacEnc *flacenc;
FLAC__int32 *data;
gsize bsize;
gint samples, width;
gint samples, width, channels;
gulong i;
gint j;
FLAC__bool res;
gpointer bdata;
GstAudioInfo *info =
gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (enc));
gint *reorder_map;
flacenc = GST_FLAC_ENC (enc);
/* base class ensures configuration */
g_return_val_if_fail (flacenc->depth != 0, GST_FLOW_NOT_NEGOTIATED);
g_return_val_if_fail (GST_AUDIO_INFO_WIDTH (info) != 0,
GST_FLOW_NOT_NEGOTIATED);
width = flacenc->width;
width = GST_AUDIO_INFO_WIDTH (info);
channels = GST_AUDIO_INFO_CHANNELS (info);
reorder_map = flacenc->channel_reorder_map;
if (G_UNLIKELY (!buffer)) {
if (flacenc->eos) {
@ -1229,28 +1205,46 @@ gst_flac_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
data = g_malloc (samples * sizeof (FLAC__int32));
samples /= channels;
if (width == 8) {
gint8 *indata = (gint8 *) bdata;
for (i = 0; i < samples; i++)
data[i] = (FLAC__int32) indata[i];
for (j = 0; j < channels; j++)
data[i * channels + reorder_map[j]] =
(FLAC__int32) indata[i * channels + j];
} else if (width == 16) {
gint16 *indata = (gint16 *) bdata;
for (i = 0; i < samples; i++)
data[i] = (FLAC__int32) indata[i];
for (j = 0; j < channels; j++)
data[i * channels + reorder_map[j]] =
(FLAC__int32) indata[i * channels + j];
} else if (width == 24) {
guint8 *indata = (guint8 *) bdata;
guint32 val;
for (i = 0; i < samples; i++)
for (j = 0; j < channels; j++) {
val = READ_INT24 (&indata[3 * (i * channels + j)]);
if (val & 0x00800000)
val |= 0xff000000;
data[i * channels + reorder_map[j]] = (FLAC__int32) val;
}
} else if (width == 32) {
gint32 *indata = (gint32 *) bdata;
for (i = 0; i < samples; i++)
data[i] = (FLAC__int32) indata[i];
for (j = 0; j < channels; j++)
data[i * channels + reorder_map[j]] =
(FLAC__int32) indata[i * channels + j];
} else {
g_assert_not_reached ();
}
gst_buffer_unmap (buffer, bdata, bsize);
res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
(const FLAC__int32 *) data, samples / flacenc->channels);
(const FLAC__int32 *) data, samples / channels);
g_free (data);

View file

@ -47,10 +47,6 @@ struct _GstFlacEnc {
* fails for some reason */
guint64 offset;
gint channels;
gint width;
gint depth;
gint sample_rate;
gint quality;
gboolean stopped;
guint padding;
@ -66,6 +62,8 @@ struct _GstFlacEnc {
/* queue headers until we have them all so we can add streamheaders to caps */
gboolean got_headers;
GList *headers;
gint channel_reorder_map[8];
};
struct _GstFlacEncClass {