mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-07 03:02:17 +00:00
flac: Port to the new raw audio caps
This commit is contained in:
parent
6c800137d8
commit
a22a566c0b
5 changed files with 216 additions and 184 deletions
|
@ -316,7 +316,7 @@ dnl Make sure you have a space before and after all plugins
|
||||||
GST_PLUGINS_NONPORTED="deinterlace interleave flx goom2k1 \
|
GST_PLUGINS_NONPORTED="deinterlace interleave flx goom2k1 \
|
||||||
imagefreeze interleave monoscope smpte \
|
imagefreeze interleave monoscope smpte \
|
||||||
videobox videomixer \
|
videobox videomixer \
|
||||||
cairo cairo_gobject dv1394 flac gdk_pixbuf libdv libpng \
|
cairo cairo_gobject dv1394 gdk_pixbuf libdv libpng \
|
||||||
oss oss4 shout2 \
|
oss oss4 shout2 \
|
||||||
taglib wavpack \
|
taglib wavpack \
|
||||||
osx_video osx_audio "
|
osx_video osx_audio "
|
||||||
|
|
|
@ -45,12 +45,11 @@
|
||||||
|
|
||||||
#include "gstflacdec.h"
|
#include "gstflacdec.h"
|
||||||
#include <gst/gst-i18n-plugin.h>
|
#include <gst/gst-i18n-plugin.h>
|
||||||
#include <gst/audio/multichannel.h>
|
|
||||||
#include <gst/tag/tag.h>
|
#include <gst/tag/tag.h>
|
||||||
|
|
||||||
/* Taken from http://flac.sourceforge.net/format.html#frame_header */
|
/* Taken from http://flac.sourceforge.net/format.html#frame_header */
|
||||||
static const GstAudioChannelPosition channel_positions[8][8] = {
|
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_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
|
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
|
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_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
|
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
|
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_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
|
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
|
||||||
/* FIXME: 7/8 channel layouts are not defined in the FLAC specs */
|
/* 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_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
|
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
|
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_REAR_CENTER}, {
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
|
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
|
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
|
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
|
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
|
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_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
|
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 } "
|
#define FORMATS "{ S8BE, S16BE, S32BE } "
|
||||||
#endif
|
#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 \
|
#define GST_FLAC_DEC_SRC_CAPS \
|
||||||
"audio/x-raw, " \
|
"audio/x-raw, " \
|
||||||
"format = (string) " FORMATS ", " \
|
"format = (string) " FORMATS ", " \
|
||||||
|
"layout = (string) interleaved, " \
|
||||||
"rate = (int) [ 1, 655350 ], " \
|
"rate = (int) [ 1, 655350 ], " \
|
||||||
"channels = (int) [ 1, 8 ]"
|
"channels = (int) [ 1, 8 ]"
|
||||||
|
|
||||||
|
@ -193,6 +190,9 @@ gst_flac_dec_start (GstAudioDecoder * audio_dec)
|
||||||
|
|
||||||
dec->decoder = FLAC__stream_decoder_new ();
|
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 */
|
/* no point calculating MD5 since it's never checked here */
|
||||||
FLAC__stream_decoder_set_md5_checking (dec->decoder, false);
|
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,
|
GST_DEBUG_OBJECT (flacdec, "frame number: %" G_GINT64_FORMAT,
|
||||||
*last_sample_num);
|
*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_DEBUG_OBJECT (flacdec, "last sample %" G_GINT64_FORMAT " = %"
|
||||||
GST_TIME_FORMAT, *last_sample_num,
|
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;
|
return TRUE;
|
||||||
|
@ -425,29 +425,42 @@ gst_flac_dec_metadata_cb (const FLAC__StreamDecoder * decoder,
|
||||||
switch (metadata->type) {
|
switch (metadata->type) {
|
||||||
case FLAC__METADATA_TYPE_STREAMINFO:{
|
case FLAC__METADATA_TYPE_STREAMINFO:{
|
||||||
gint64 samples;
|
gint64 samples;
|
||||||
guint depth;
|
guint depth, width;
|
||||||
|
|
||||||
samples = metadata->data.stream_info.total_samples;
|
samples = metadata->data.stream_info.total_samples;
|
||||||
|
|
||||||
flacdec->min_blocksize = metadata->data.stream_info.min_blocksize;
|
flacdec->min_blocksize = metadata->data.stream_info.min_blocksize;
|
||||||
flacdec->max_blocksize = metadata->data.stream_info.max_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->depth = depth = metadata->data.stream_info.bits_per_sample;
|
||||||
flacdec->channels = metadata->data.stream_info.channels;
|
|
||||||
|
|
||||||
if (depth < 9)
|
if (depth < 9)
|
||||||
flacdec->width = 8;
|
width = 8;
|
||||||
else if (depth < 17)
|
else if (depth < 17)
|
||||||
flacdec->width = 16;
|
width = 16;
|
||||||
else
|
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",
|
GST_DEBUG_OBJECT (flacdec, "blocksize: min=%u, max=%u",
|
||||||
flacdec->min_blocksize, flacdec->max_blocksize);
|
flacdec->min_blocksize, flacdec->max_blocksize);
|
||||||
GST_DEBUG_OBJECT (flacdec, "sample rate: %u, channels: %u",
|
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,
|
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);
|
GST_DEBUG_OBJECT (flacdec, "total samples = %" G_GINT64_FORMAT, samples);
|
||||||
break;
|
break;
|
||||||
|
@ -524,7 +537,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
|
||||||
guint j, i;
|
guint j, i;
|
||||||
gpointer data;
|
gpointer data;
|
||||||
gsize size;
|
gsize size;
|
||||||
const gchar *format;
|
gboolean caps_changed;
|
||||||
|
|
||||||
GST_LOG_OBJECT (flacdec, "samples in frame header: %d", samples);
|
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;
|
depth = flacdec->depth;
|
||||||
if (depth < 9)
|
|
||||||
depth = 8;
|
|
||||||
else if (depth < 17)
|
|
||||||
depth = 16;
|
|
||||||
else
|
|
||||||
depth = 32;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (depth) {
|
switch (depth) {
|
||||||
case 8:
|
case 8:
|
||||||
width = 8;
|
width = 8;
|
||||||
format = GST_AUDIO_NE (S8);
|
|
||||||
break;
|
break;
|
||||||
case 12:
|
case 12:
|
||||||
case 16:
|
case 16:
|
||||||
width = 16;
|
width = 16;
|
||||||
format = GST_AUDIO_NE (S16);
|
|
||||||
break;
|
break;
|
||||||
case 20:
|
case 20:
|
||||||
case 24:
|
case 24:
|
||||||
case 32:
|
case 32:
|
||||||
width = 32;
|
width = 32;
|
||||||
format = GST_AUDIO_NE (S32);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
GST_ERROR_OBJECT (flacdec, "unsupported depth %d", depth);
|
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 (sample_rate == 0) {
|
||||||
if (flacdec->sample_rate != 0) {
|
if (flacdec->info.rate != 0) {
|
||||||
sample_rate = flacdec->sample_rate;
|
sample_rate = flacdec->info.rate;
|
||||||
} else {
|
} else {
|
||||||
GST_ERROR_OBJECT (flacdec, "unknown sample rate");
|
GST_ERROR_OBJECT (flacdec, "unknown sample rate");
|
||||||
ret = GST_FLOW_ERROR;
|
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;
|
GstCaps *caps;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (flacdec, "Negotiating %d Hz @ %d channels",
|
GST_DEBUG_OBJECT (flacdec, "Negotiating %d Hz @ %d channels", sample_rate,
|
||||||
frame->header.sample_rate, channels);
|
channels);
|
||||||
|
|
||||||
caps = gst_caps_new_simple ("audio/x-raw",
|
gst_audio_info_set_format (&flacdec->info,
|
||||||
"format", G_TYPE_STRING, format,
|
gst_audio_format_build_integer (TRUE, G_BYTE_ORDER, width, width),
|
||||||
"rate", G_TYPE_INT, frame->header.sample_rate,
|
sample_rate, channels, NULL);
|
||||||
"channels", G_TYPE_INT, channels, NULL);
|
|
||||||
|
|
||||||
if (channels > 2) {
|
memcpy (flacdec->info.position,
|
||||||
GstStructure *s = gst_caps_get_structure (caps, 0);
|
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->depth = depth;
|
||||||
flacdec->width = width;
|
|
||||||
flacdec->channels = channels;
|
|
||||||
flacdec->sample_rate = sample_rate;
|
|
||||||
|
|
||||||
gst_audio_decoder_set_outcaps (GST_AUDIO_DECODER (flacdec), caps);
|
gst_audio_decoder_set_outcaps (GST_AUDIO_DECODER (flacdec), caps);
|
||||||
gst_caps_unref (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);
|
data = gst_buffer_map (outbuf, &size, NULL, GST_MAP_WRITE);
|
||||||
if (width == 8) {
|
if (width == 8) {
|
||||||
gint8 *outbuffer = (gint8 *) data;
|
gint8 *outbuffer = (gint8 *) data;
|
||||||
|
gint *reorder_map = flacdec->channel_reorder_map;
|
||||||
|
|
||||||
for (i = 0; i < samples; i++) {
|
if (width != depth) {
|
||||||
for (j = 0; j < channels; j++) {
|
for (i = 0; i < samples; i++) {
|
||||||
*outbuffer++ = (gint8) buffer[j][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) {
|
} else if (width == 16) {
|
||||||
gint16 *outbuffer = (gint16 *) data;
|
gint16 *outbuffer = (gint16 *) data;
|
||||||
|
gint *reorder_map = flacdec->channel_reorder_map;
|
||||||
|
|
||||||
for (i = 0; i < samples; i++) {
|
if (width != depth) {
|
||||||
for (j = 0; j < channels; j++) {
|
for (i = 0; i < samples; i++) {
|
||||||
*outbuffer++ = (gint16) buffer[j][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) {
|
} else if (width == 32) {
|
||||||
gint32 *outbuffer = (gint32 *) data;
|
gint32 *outbuffer = (gint32 *) data;
|
||||||
|
gint *reorder_map = flacdec->channel_reorder_map;
|
||||||
|
|
||||||
for (i = 0; i < samples; i++) {
|
if (width != depth) {
|
||||||
for (j = 0; j < channels; j++) {
|
for (i = 0; i < samples; i++) {
|
||||||
*outbuffer++ = (gint32) buffer[j][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 {
|
} else {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#define __GST_FLAC_DEC_H__
|
#define __GST_FLAC_DEC_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/audio/audio.h>
|
||||||
#include <gst/audio/gstaudiodecoder.h>
|
#include <gst/audio/gstaudiodecoder.h>
|
||||||
|
|
||||||
#include <FLAC/all.h>
|
#include <FLAC/all.h>
|
||||||
|
@ -50,10 +51,9 @@ struct _GstFlacDec {
|
||||||
GstFlowReturn last_flow; /* to marshal flow return from finis_frame to
|
GstFlowReturn last_flow; /* to marshal flow return from finis_frame to
|
||||||
* handle_frame via flac callbacks */
|
* handle_frame via flac callbacks */
|
||||||
|
|
||||||
gint channels;
|
GstAudioInfo info;
|
||||||
|
gint channel_reorder_map[8];
|
||||||
gint depth;
|
gint depth;
|
||||||
gint width;
|
|
||||||
gint sample_rate;
|
|
||||||
|
|
||||||
/* from the stream info, needed for scanning */
|
/* from the stream info, needed for scanning */
|
||||||
guint16 min_blocksize;
|
guint16 min_blocksize;
|
||||||
|
|
|
@ -45,13 +45,12 @@
|
||||||
|
|
||||||
#include <gstflacenc.h>
|
#include <gstflacenc.h>
|
||||||
#include <gst/audio/audio.h>
|
#include <gst/audio/audio.h>
|
||||||
#include <gst/audio/multichannel.h>
|
|
||||||
#include <gst/tag/tag.h>
|
#include <gst/tag/tag.h>
|
||||||
#include <gst/gsttagsetter.h>
|
#include <gst/gsttagsetter.h>
|
||||||
|
|
||||||
/* Taken from http://flac.sourceforge.net/format.html#frame_header */
|
/* Taken from http://flac.sourceforge.net/format.html#frame_header */
|
||||||
static const GstAudioChannelPosition channel_positions[8][8] = {
|
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_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
|
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
|
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_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
|
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
|
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_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
|
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
|
||||||
/* FIXME: 7/8 channel layouts are not defined in the FLAC specs */
|
/* 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_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
|
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
|
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_REAR_CENTER}, {
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
|
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
|
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
|
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
|
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
|
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_LEFT,
|
||||||
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
|
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FLAC_SINK_CAPS \
|
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||||
"audio/x-raw-int, " \
|
#define FORMATS "{ S8LE, S16LE, S24LE, S32LE } "
|
||||||
"endianness = (int) BYTE_ORDER, " \
|
#else
|
||||||
"signed = (boolean) TRUE, " \
|
#define FORMATS "{ S8BE, S16BE, S24BE, S32BE } "
|
||||||
"width = (int) 8, " \
|
#endif
|
||||||
"depth = (int) 8, " \
|
|
||||||
"rate = (int) [ 1, 655350 ], " \
|
#define FLAC_SINK_CAPS \
|
||||||
"channels = (int) [ 1, 8 ]; " \
|
"audio/x-raw, " \
|
||||||
"audio/x-raw-int, " \
|
"format = (string) " FORMATS ", " \
|
||||||
"endianness = (int) BYTE_ORDER, " \
|
"layout = (string) interleaved, " \
|
||||||
"signed = (boolean) TRUE, " \
|
"rate = (int) [ 1, 655350 ], " \
|
||||||
"width = (int) 16, " \
|
"channels = (int) [ 1, 8 ]"
|
||||||
"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 ]"
|
|
||||||
|
|
||||||
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
|
@ -424,9 +413,6 @@ gst_flac_enc_start (GstAudioEncoder * enc)
|
||||||
flacenc->got_headers = FALSE;
|
flacenc->got_headers = FALSE;
|
||||||
flacenc->last_flow = GST_FLOW_OK;
|
flacenc->last_flow = GST_FLOW_OK;
|
||||||
flacenc->offset = 0;
|
flacenc->offset = 0;
|
||||||
flacenc->channels = 0;
|
|
||||||
flacenc->depth = 0;
|
|
||||||
flacenc->sample_rate = 0;
|
|
||||||
flacenc->eos = FALSE;
|
flacenc->eos = FALSE;
|
||||||
flacenc->tags = gst_tag_list_new_empty ();
|
flacenc->tags = gst_tag_list_new_empty ();
|
||||||
|
|
||||||
|
@ -502,6 +488,8 @@ gst_flac_enc_set_metadata (GstFlacEnc * flacenc, guint64 total_samples)
|
||||||
GstTagList *copy;
|
GstTagList *copy;
|
||||||
gint entries = 1;
|
gint entries = 1;
|
||||||
gint n_images, n_preview_images;
|
gint n_images, n_preview_images;
|
||||||
|
GstAudioInfo *info =
|
||||||
|
gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc));
|
||||||
|
|
||||||
g_return_if_fail (flacenc != NULL);
|
g_return_if_fail (flacenc != NULL);
|
||||||
user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (flacenc));
|
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
|
FLAC__metadata_object_seektable_template_append_spaced_points
|
||||||
(flacenc->meta[entries], flacenc->seekpoints, total_samples);
|
(flacenc->meta[entries], flacenc->seekpoints, total_samples);
|
||||||
} else {
|
} else {
|
||||||
samples = -flacenc->seekpoints * flacenc->sample_rate;
|
samples = -flacenc->seekpoints * GST_AUDIO_INFO_RATE (info);
|
||||||
res =
|
res =
|
||||||
FLAC__metadata_object_seektable_template_append_spaced_points_by_samples
|
FLAC__metadata_object_seektable_template_append_spaced_points_by_samples
|
||||||
(flacenc->meta[entries], samples, total_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);
|
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 *
|
static GstCaps *
|
||||||
gst_flac_enc_getcaps (GstAudioEncoder * enc, GstCaps * filter)
|
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)) {
|
if (gst_pad_has_current_caps (pad)) {
|
||||||
ret = gst_pad_get_current_caps (pad);
|
ret = gst_pad_get_current_caps (pad);
|
||||||
} else {
|
} 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 ();
|
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,
|
if (i == 1) {
|
||||||
gst_structure_new ("audio/x-raw-int",
|
gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
|
||||||
"endianness", G_TYPE_INT, G_BYTE_ORDER,
|
} else {
|
||||||
"signed", G_TYPE_BOOLEAN, TRUE,
|
guint64 channel_mask;
|
||||||
"rate", GST_TYPE_INT_RANGE, 1, 655350,
|
|
||||||
"channels", GST_TYPE_INT_RANGE, 1, 2, NULL));
|
|
||||||
|
|
||||||
for (i = 3; i <= 8; i++) {
|
gst_audio_channel_positions_to_mask (channel_positions[i - 1], i,
|
||||||
GValue positions = { 0, };
|
&channel_mask);
|
||||||
GValue pos = { 0, };
|
gst_structure_set (s, "channels", G_TYPE_INT, 1, "channel-mask",
|
||||||
GstStructure *s;
|
GST_TYPE_BITMASK, channel_mask, NULL);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
g_value_unset (&pos);
|
|
||||||
|
|
||||||
s = gst_structure_new ("audio/x-raw-int",
|
gst_caps_append_structure (ret, s2);
|
||||||
"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_structure_free (s);
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_OBJECT_UNLOCK (pad);
|
GST_OBJECT_UNLOCK (pad);
|
||||||
|
@ -724,6 +677,8 @@ static guint64
|
||||||
gst_flac_enc_peer_query_total_samples (GstFlacEnc * flacenc, GstPad * pad)
|
gst_flac_enc_peer_query_total_samples (GstFlacEnc * flacenc, GstPad * pad)
|
||||||
{
|
{
|
||||||
gint64 duration;
|
gint64 duration;
|
||||||
|
GstAudioInfo *info =
|
||||||
|
gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc));
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (flacenc, "querying peer for DEFAULT format duration");
|
GST_DEBUG_OBJECT (flacenc, "querying peer for DEFAULT format duration");
|
||||||
if (gst_pad_peer_query_duration (pad, GST_FORMAT_DEFAULT, &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) {
|
&& duration != GST_CLOCK_TIME_NONE) {
|
||||||
GST_DEBUG_OBJECT (flacenc, "peer reported duration %" GST_TIME_FORMAT,
|
GST_DEBUG_OBJECT (flacenc, "peer reported duration %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (duration));
|
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;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -766,26 +721,28 @@ gst_flac_enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
|
||||||
FLAC__STREAM_ENCODER_UNINITIALIZED)
|
FLAC__STREAM_ENCODER_UNINITIALIZED)
|
||||||
goto encoder_already_initialized;
|
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",
|
caps = gst_caps_new_simple ("audio/x-flac",
|
||||||
"channels", G_TYPE_INT, flacenc->channels,
|
"channels", G_TYPE_INT, GST_AUDIO_INFO_CHANNELS (info),
|
||||||
"rate", G_TYPE_INT, flacenc->sample_rate, NULL);
|
"rate", G_TYPE_INT, GST_AUDIO_INFO_RATE (info), NULL);
|
||||||
|
|
||||||
if (!gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps))
|
if (!gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps))
|
||||||
goto setting_src_caps_failed;
|
goto setting_src_caps_failed;
|
||||||
|
|
||||||
gst_caps_unref (caps);
|
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,
|
total_samples = gst_flac_enc_peer_query_total_samples (flacenc,
|
||||||
GST_AUDIO_ENCODER_SINK_PAD (enc));
|
GST_AUDIO_ENCODER_SINK_PAD (enc));
|
||||||
|
|
||||||
FLAC__stream_encoder_set_bits_per_sample (flacenc->encoder, flacenc->depth);
|
FLAC__stream_encoder_set_bits_per_sample (flacenc->encoder,
|
||||||
FLAC__stream_encoder_set_sample_rate (flacenc->encoder, flacenc->sample_rate);
|
GST_AUDIO_INFO_WIDTH (info));
|
||||||
FLAC__stream_encoder_set_channels (flacenc->encoder, flacenc->channels);
|
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)
|
if (total_samples != GST_CLOCK_TIME_NONE)
|
||||||
FLAC__stream_encoder_set_total_samples_estimate (flacenc->encoder,
|
FLAC__stream_encoder_set_total_samples_estimate (flacenc->encoder,
|
||||||
|
@ -833,6 +790,9 @@ failed_to_initialize:
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_flac_enc_update_quality (GstFlacEnc * flacenc, gint quality)
|
gst_flac_enc_update_quality (GstFlacEnc * flacenc, gint quality)
|
||||||
{
|
{
|
||||||
|
GstAudioInfo *info =
|
||||||
|
gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc));
|
||||||
|
|
||||||
flacenc->quality = quality;
|
flacenc->quality = quality;
|
||||||
|
|
||||||
#define DO_UPDATE(name, val, str) \
|
#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));
|
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 (do_mid_side_stereo, mid_side, "mid_side_stereo");
|
||||||
DO_UPDATE (loose_mid_side_stereo, loose_mid_side, "loose_mid_side");
|
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;
|
GstCaps *caps;
|
||||||
GList *l;
|
GList *l;
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
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",
|
caps = gst_caps_new_simple ("audio/x-flac",
|
||||||
"channels", G_TYPE_INT, enc->channels,
|
"channels", G_TYPE_INT, GST_AUDIO_INFO_CHANNELS (info),
|
||||||
"rate", G_TYPE_INT, enc->sample_rate, NULL);
|
"rate", G_TYPE_INT, GST_AUDIO_INFO_RATE (info), NULL);
|
||||||
|
|
||||||
for (l = enc->headers; l != NULL; l = l->next) {
|
for (l = enc->headers; l != NULL; l = l->next) {
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
|
@ -1193,23 +1156,36 @@ gst_flac_enc_sink_event (GstAudioEncoder * enc, GstEvent * event)
|
||||||
return ret;
|
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
|
static GstFlowReturn
|
||||||
gst_flac_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
|
gst_flac_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstFlacEnc *flacenc;
|
GstFlacEnc *flacenc;
|
||||||
FLAC__int32 *data;
|
FLAC__int32 *data;
|
||||||
gsize bsize;
|
gsize bsize;
|
||||||
gint samples, width;
|
gint samples, width, channels;
|
||||||
gulong i;
|
gulong i;
|
||||||
|
gint j;
|
||||||
FLAC__bool res;
|
FLAC__bool res;
|
||||||
gpointer bdata;
|
gpointer bdata;
|
||||||
|
GstAudioInfo *info =
|
||||||
|
gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (enc));
|
||||||
|
gint *reorder_map;
|
||||||
|
|
||||||
flacenc = GST_FLAC_ENC (enc);
|
flacenc = GST_FLAC_ENC (enc);
|
||||||
|
|
||||||
/* base class ensures configuration */
|
/* 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 (G_UNLIKELY (!buffer)) {
|
||||||
if (flacenc->eos) {
|
if (flacenc->eos) {
|
||||||
|
@ -1229,28 +1205,46 @@ gst_flac_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
|
||||||
|
|
||||||
data = g_malloc (samples * sizeof (FLAC__int32));
|
data = g_malloc (samples * sizeof (FLAC__int32));
|
||||||
|
|
||||||
|
samples /= channels;
|
||||||
if (width == 8) {
|
if (width == 8) {
|
||||||
gint8 *indata = (gint8 *) bdata;
|
gint8 *indata = (gint8 *) bdata;
|
||||||
|
|
||||||
for (i = 0; i < samples; i++)
|
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) {
|
} else if (width == 16) {
|
||||||
gint16 *indata = (gint16 *) bdata;
|
gint16 *indata = (gint16 *) bdata;
|
||||||
|
|
||||||
for (i = 0; i < samples; i++)
|
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) {
|
} else if (width == 32) {
|
||||||
gint32 *indata = (gint32 *) bdata;
|
gint32 *indata = (gint32 *) bdata;
|
||||||
|
|
||||||
for (i = 0; i < samples; i++)
|
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 {
|
} else {
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
gst_buffer_unmap (buffer, bdata, bsize);
|
gst_buffer_unmap (buffer, bdata, bsize);
|
||||||
|
|
||||||
res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
|
res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
|
||||||
(const FLAC__int32 *) data, samples / flacenc->channels);
|
(const FLAC__int32 *) data, samples / channels);
|
||||||
|
|
||||||
g_free (data);
|
g_free (data);
|
||||||
|
|
||||||
|
|
|
@ -47,10 +47,6 @@ struct _GstFlacEnc {
|
||||||
* fails for some reason */
|
* fails for some reason */
|
||||||
|
|
||||||
guint64 offset;
|
guint64 offset;
|
||||||
gint channels;
|
|
||||||
gint width;
|
|
||||||
gint depth;
|
|
||||||
gint sample_rate;
|
|
||||||
gint quality;
|
gint quality;
|
||||||
gboolean stopped;
|
gboolean stopped;
|
||||||
guint padding;
|
guint padding;
|
||||||
|
@ -66,6 +62,8 @@ struct _GstFlacEnc {
|
||||||
/* queue headers until we have them all so we can add streamheaders to caps */
|
/* queue headers until we have them all so we can add streamheaders to caps */
|
||||||
gboolean got_headers;
|
gboolean got_headers;
|
||||||
GList *headers;
|
GList *headers;
|
||||||
|
|
||||||
|
gint channel_reorder_map[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstFlacEncClass {
|
struct _GstFlacEncClass {
|
||||||
|
|
Loading…
Reference in a new issue