From: Sebastian Dröge Date: Fri, 6 Jan 2012 08:40:22 +0000 (+0100) Subject: flac: Port to the new raw audio caps X-Git-Tag: 1.19.3~509^2~7428 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a22a566c0bc543e08214a9e40837e76222974464;p=platform%2Fupstream%2Fgstreamer.git flac: Port to the new raw audio caps --- diff --git a/configure.ac b/configure.ac index 62a42c4..f2e608b 100644 --- a/configure.ac +++ b/configure.ac @@ -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 " diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c index 9dc0ca2..94c0402 100644 --- a/ext/flac/gstflacdec.c +++ b/ext/flac/gstflacdec.c @@ -45,12 +45,11 @@ #include "gstflacdec.h" #include -#include #include /* 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; - - for (i = 0; i < samples; i++) { - for (j = 0; j < channels; j++) { - *outbuffer++ = (gint16) buffer[j][i]; + gint *reorder_map = flacdec->channel_reorder_map; + + 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; - - for (i = 0; i < samples; i++) { - for (j = 0; j < channels; j++) { - *outbuffer++ = (gint32) buffer[j][i]; + gint *reorder_map = flacdec->channel_reorder_map; + + 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 { diff --git a/ext/flac/gstflacdec.h b/ext/flac/gstflacdec.h index 8572e8d..2386a12 100644 --- a/ext/flac/gstflacdec.h +++ b/ext/flac/gstflacdec.h @@ -23,6 +23,7 @@ #define __GST_FLAC_DEC_H__ #include +#include #include #include @@ -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; diff --git a/ext/flac/gstflacenc.c b/ext/flac/gstflacenc.c index 1b3dac2..6138455 100644 --- a/ext/flac/gstflacenc.c +++ b/ext/flac/gstflacenc.c @@ -45,13 +45,12 @@ #include #include -#include #include #include /* 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)); - - 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); + if (i == 1) { + gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL); + } else { + guint64 channel_mask; - 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); diff --git a/ext/flac/gstflacenc.h b/ext/flac/gstflacenc.h index 9084892..0a4e2b4 100644 --- a/ext/flac/gstflacenc.h +++ b/ext/flac/gstflacenc.h @@ -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 {