mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
ext/wavpack/: Add support for encoding, parsing and decoding multichannel files with up to 8 channels. This also impr...
Original commit message from CVS: * ext/wavpack/gstwavpackcommon.c: (gst_wavpack_get_default_channel_mask), (gst_wavpack_set_channel_layout), (gst_wavpack_get_default_channel_positions), (gst_wavpack_get_channel_mask_from_positions), (gst_wavpack_set_channel_mapping): * ext/wavpack/gstwavpackcommon.h: * ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_reset), (gst_wavpack_dec_sink_set_caps), (gst_wavpack_dec_chain): * ext/wavpack/gstwavpackdec.h: * ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_reset), (gst_wavpack_enc_init), (gst_wavpack_enc_sink_set_caps), (gst_wavpack_enc_set_wp_config), (gst_wavpack_enc_push_block), (gst_wavpack_enc_fix_channel_order), (gst_wavpack_enc_chain), (gst_wavpack_enc_rewrite_first_block), (gst_wavpack_enc_sink_event): * ext/wavpack/gstwavpackenc.h: * ext/wavpack/gstwavpackparse.c: (gst_wavpack_parse_index_append_entry), (gst_wavpack_parse_reset), (gst_wavpack_parse_scan_to_find_sample), (gst_wavpack_parse_sink_event), (gst_wavpack_parse_create_src_pad), (gst_wavpack_parse_push_buffer), (gst_wavpack_parse_loop): * ext/wavpack/gstwavpackparse.h: Add support for encoding, parsing and decoding multichannel files with up to 8 channels. This also improves the robustness of parsing quite a bit. * ext/wavpack/gstwavpackstreamreader.c: (gst_wavpack_stream_reader_read_bytes), (gst_wavpack_stream_reader_get_pos), (gst_wavpack_stream_reader_set_pos_abs), (gst_wavpack_stream_reader_set_pos_rel), (gst_wavpack_stream_reader_push_back_byte), (gst_wavpack_stream_reader_get_length), (gst_wavpack_stream_reader_can_seek), (gst_wavpack_stream_reader_write_bytes): Improve debugging.
This commit is contained in:
parent
dfdc0fa8c9
commit
ded2cc6e39
10 changed files with 471 additions and 48 deletions
40
ChangeLog
40
ChangeLog
|
@ -1,3 +1,43 @@
|
|||
2007-11-20 Sebastian Dröge <slomo@circular-chaos.org>
|
||||
|
||||
* ext/wavpack/gstwavpackcommon.c:
|
||||
(gst_wavpack_get_default_channel_mask),
|
||||
(gst_wavpack_set_channel_layout),
|
||||
(gst_wavpack_get_default_channel_positions),
|
||||
(gst_wavpack_get_channel_mask_from_positions),
|
||||
(gst_wavpack_set_channel_mapping):
|
||||
* ext/wavpack/gstwavpackcommon.h:
|
||||
* ext/wavpack/gstwavpackdec.c: (gst_wavpack_dec_reset),
|
||||
(gst_wavpack_dec_sink_set_caps), (gst_wavpack_dec_chain):
|
||||
* ext/wavpack/gstwavpackdec.h:
|
||||
* ext/wavpack/gstwavpackenc.c: (gst_wavpack_enc_reset),
|
||||
(gst_wavpack_enc_init), (gst_wavpack_enc_sink_set_caps),
|
||||
(gst_wavpack_enc_set_wp_config), (gst_wavpack_enc_push_block),
|
||||
(gst_wavpack_enc_fix_channel_order), (gst_wavpack_enc_chain),
|
||||
(gst_wavpack_enc_rewrite_first_block),
|
||||
(gst_wavpack_enc_sink_event):
|
||||
* ext/wavpack/gstwavpackenc.h:
|
||||
* ext/wavpack/gstwavpackparse.c:
|
||||
(gst_wavpack_parse_index_append_entry), (gst_wavpack_parse_reset),
|
||||
(gst_wavpack_parse_scan_to_find_sample),
|
||||
(gst_wavpack_parse_sink_event), (gst_wavpack_parse_create_src_pad),
|
||||
(gst_wavpack_parse_push_buffer), (gst_wavpack_parse_loop):
|
||||
* ext/wavpack/gstwavpackparse.h:
|
||||
Add support for encoding, parsing and decoding multichannel
|
||||
files with up to 8 channels. This also improves the robustness
|
||||
of parsing quite a bit.
|
||||
|
||||
* ext/wavpack/gstwavpackstreamreader.c:
|
||||
(gst_wavpack_stream_reader_read_bytes),
|
||||
(gst_wavpack_stream_reader_get_pos),
|
||||
(gst_wavpack_stream_reader_set_pos_abs),
|
||||
(gst_wavpack_stream_reader_set_pos_rel),
|
||||
(gst_wavpack_stream_reader_push_back_byte),
|
||||
(gst_wavpack_stream_reader_get_length),
|
||||
(gst_wavpack_stream_reader_can_seek),
|
||||
(gst_wavpack_stream_reader_write_bytes):
|
||||
Improve debugging.
|
||||
|
||||
2007-11-20 Stefan Kost <ensonic@users.sf.net>
|
||||
|
||||
* ext/libpng/gstpngdec.c:
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
#include "gstwavpackcommon.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/audio/multichannel.h>
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (wavpack_debug);
|
||||
#define GST_CAT_DEFAULT wavpack_debug
|
||||
|
||||
|
@ -96,3 +99,183 @@ gst_wavpack_read_metadata (GstWavpackMetadata * wpmd, guint8 * header_data,
|
|||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gint
|
||||
gst_wavpack_get_default_channel_mask (gint nchannels)
|
||||
{
|
||||
gint channel_mask = 0;
|
||||
|
||||
/* Set the default channel mask for the given number of channels.
|
||||
* It's the same as for WAVE_FORMAT_EXTENDED:
|
||||
* http://www.microsoft.com/whdc/device/audio/multichaud.mspx
|
||||
*/
|
||||
switch (nchannels) {
|
||||
case 11:
|
||||
channel_mask |= 0x00400;
|
||||
channel_mask |= 0x00200;
|
||||
case 9:
|
||||
channel_mask |= 0x00100;
|
||||
case 8:
|
||||
channel_mask |= 0x00080;
|
||||
channel_mask |= 0x00040;
|
||||
case 6:
|
||||
channel_mask |= 0x00020;
|
||||
channel_mask |= 0x00010;
|
||||
case 4:
|
||||
channel_mask |= 0x00008;
|
||||
case 3:
|
||||
channel_mask |= 0x00004;
|
||||
case 2:
|
||||
channel_mask |= 0x00002;
|
||||
channel_mask |= 0x00001;
|
||||
break;
|
||||
case 1:
|
||||
/* For mono use front center */
|
||||
channel_mask |= 0x00004;
|
||||
break;
|
||||
}
|
||||
|
||||
return channel_mask;
|
||||
}
|
||||
|
||||
static const struct
|
||||
{
|
||||
const guint32 ms_mask;
|
||||
const GstAudioChannelPosition gst_pos;
|
||||
} layout_mapping[] = {
|
||||
{
|
||||
0x00001, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT}, {
|
||||
0x00002, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
|
||||
0x00004, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, {
|
||||
0x00008, GST_AUDIO_CHANNEL_POSITION_LFE}, {
|
||||
0x00010, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT}, {
|
||||
0x00020, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
|
||||
0x00040, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER}, {
|
||||
0x00080, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, {
|
||||
0x00100, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
|
||||
0x00200, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT}, {
|
||||
0x00400, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, {
|
||||
0x00800, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_CENTER */
|
||||
{
|
||||
0x01000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_FRONT_LEFT */
|
||||
{
|
||||
0x02000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_FRONT_CENTER */
|
||||
{
|
||||
0x04000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_FRONT_RIGHT */
|
||||
{
|
||||
0x08000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_BACK_LEFT */
|
||||
{
|
||||
0x10000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_BACK_CENTER */
|
||||
{
|
||||
0x20000, GST_AUDIO_CHANNEL_POSITION_INVALID} /* TOP_BACK_RIGHT */
|
||||
};
|
||||
|
||||
#define MAX_CHANNEL_POSITIONS G_N_ELEMENTS (layout_mapping)
|
||||
|
||||
gboolean
|
||||
gst_wavpack_set_channel_layout (GstCaps * caps, gint layout)
|
||||
{
|
||||
GstAudioChannelPosition pos[MAX_CHANNEL_POSITIONS];
|
||||
GstStructure *s;
|
||||
gint num_channels, i, p;
|
||||
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
if (!gst_structure_get_int (s, "channels", &num_channels))
|
||||
g_return_val_if_reached (FALSE);
|
||||
|
||||
if (num_channels == 1 && layout == 0x00004) {
|
||||
pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_MONO;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
p = 0;
|
||||
for (i = 0; i < MAX_CHANNEL_POSITIONS; ++i) {
|
||||
if ((layout & layout_mapping[i].ms_mask) != 0) {
|
||||
if (p >= num_channels) {
|
||||
GST_WARNING ("More bits set in the channel layout map than there "
|
||||
"are channels! Broken file");
|
||||
return FALSE;
|
||||
}
|
||||
if (layout_mapping[i].gst_pos == GST_AUDIO_CHANNEL_POSITION_INVALID) {
|
||||
GST_WARNING ("Unsupported channel position (mask 0x%08x) in channel "
|
||||
"layout map - ignoring those channels", layout_mapping[i].ms_mask);
|
||||
/* what to do? just ignore it and let downstream deal with a channel
|
||||
* layout that has INVALID positions in it for now ... */
|
||||
}
|
||||
pos[p] = layout_mapping[i].gst_pos;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
if (p != num_channels) {
|
||||
GST_WARNING ("Only %d bits set in the channel layout map, but there are "
|
||||
"supposed to be %d channels! Broken file", p, num_channels);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gst_audio_set_channel_positions (s, pos);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GstAudioChannelPosition *
|
||||
gst_wavpack_get_default_channel_positions (gint nchannels)
|
||||
{
|
||||
GstAudioChannelPosition *pos = g_new (GstAudioChannelPosition, nchannels);
|
||||
gint i;
|
||||
|
||||
if (nchannels == 1) {
|
||||
pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
|
||||
return pos;
|
||||
}
|
||||
|
||||
for (i = 0; i < nchannels; i++)
|
||||
pos[i] = layout_mapping[i].gst_pos;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
gint
|
||||
gst_wavpack_get_channel_mask_from_positions (GstAudioChannelPosition * pos,
|
||||
gint nchannels)
|
||||
{
|
||||
gint channel_mask = 0;
|
||||
gint i, j;
|
||||
|
||||
if (nchannels == 1 && pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) {
|
||||
channel_mask = 0x00000004;
|
||||
return channel_mask;
|
||||
}
|
||||
|
||||
/* FIXME: not exactly efficient but otherwise we need an inverse
|
||||
* mapping table too */
|
||||
for (i = 0; i < nchannels; i++) {
|
||||
for (j = 0; j < MAX_CHANNEL_POSITIONS; j++) {
|
||||
if (pos[i] == layout_mapping[j].gst_pos) {
|
||||
channel_mask |= layout_mapping[j].ms_mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return channel_mask;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_wavpack_set_channel_mapping (GstAudioChannelPosition * pos, gint nchannels,
|
||||
gint8 * channel_mapping)
|
||||
{
|
||||
gint i, j;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
for (i = 0; i < nchannels; i++) {
|
||||
for (j = 0; j < MAX_CHANNEL_POSITIONS; j++) {
|
||||
if (pos[i] == layout_mapping[j].gst_pos) {
|
||||
channel_mapping[i] = j;
|
||||
ret &= (i == j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !ret;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#define __GST_WAVPACK_COMMON_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/audio/multichannel.h>
|
||||
#include <wavpack/wavpack.h>
|
||||
|
||||
typedef struct
|
||||
|
@ -65,5 +66,10 @@ typedef struct
|
|||
gboolean gst_wavpack_read_header (WavpackHeader * header, guint8 * buf);
|
||||
gboolean gst_wavpack_read_metadata (GstWavpackMetadata * meta,
|
||||
guint8 * header_data, guint8 ** p_data);
|
||||
gint gst_wavpack_get_default_channel_mask (gint nchannels);
|
||||
gboolean gst_wavpack_set_channel_layout (GstCaps * caps, gint layout);
|
||||
GstAudioChannelPosition *gst_wavpack_get_default_channel_positions (gint nchannels);
|
||||
gint gst_wavpack_get_channel_mask_from_positions (GstAudioChannelPosition *pos, gint nchannels);
|
||||
gboolean gst_wavpack_set_channel_mapping (GstAudioChannelPosition *pos, gint nchannels, gint8 *channel_mapping);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/audio/audio.h>
|
||||
#include <gst/audio/multichannel.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
@ -62,7 +63,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
|
|||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("audio/x-wavpack, "
|
||||
"width = (int) [ 1, 32 ], "
|
||||
"channels = (int) [ 1, 2 ], "
|
||||
"channels = (int) [ 1, 8 ], "
|
||||
"rate = (int) [ 6000, 192000 ], " "framed = (boolean) true")
|
||||
);
|
||||
|
||||
|
@ -72,7 +73,7 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
|||
GST_STATIC_CAPS ("audio/x-raw-int, "
|
||||
"width = (int) 32, "
|
||||
"depth = (int) [ 1, 32 ], "
|
||||
"channels = (int) [ 1, 2 ], "
|
||||
"channels = (int) [ 1, 8 ], "
|
||||
"rate = (int) [ 6000, 192000 ], "
|
||||
"endianness = (int) BYTE_ORDER, " "signed = (boolean) true")
|
||||
);
|
||||
|
@ -126,6 +127,7 @@ gst_wavpack_dec_reset (GstWavpackDec * dec)
|
|||
dec->error_count = 0;
|
||||
|
||||
dec->channels = 0;
|
||||
dec->channel_mask = 0;
|
||||
dec->sample_rate = 0;
|
||||
dec->depth = 0;
|
||||
|
||||
|
@ -177,6 +179,7 @@ gst_wavpack_dec_sink_set_caps (GstPad * pad, GstCaps * caps)
|
|||
gst_structure_get_int (structure, "rate", &dec->sample_rate) &&
|
||||
gst_structure_get_int (structure, "width", &dec->depth)) {
|
||||
GstCaps *caps;
|
||||
GstAudioChannelPosition *pos;
|
||||
|
||||
caps = gst_caps_new_simple ("audio/x-raw-int",
|
||||
"rate", G_TYPE_INT, dec->sample_rate,
|
||||
|
@ -186,6 +189,22 @@ gst_wavpack_dec_sink_set_caps (GstPad * pad, GstCaps * caps)
|
|||
"endianness", G_TYPE_INT, G_BYTE_ORDER,
|
||||
"signed", G_TYPE_BOOLEAN, TRUE, NULL);
|
||||
|
||||
/* If we already have the channel layout set from upstream
|
||||
* take this */
|
||||
if (gst_structure_has_field (structure, "channel-positions")) {
|
||||
pos = gst_audio_get_channel_positions (structure);
|
||||
if (pos != NULL && dec->channels > 2) {
|
||||
GstStructure *new_str = gst_caps_get_structure (caps, 0);
|
||||
|
||||
gst_audio_set_channel_positions (new_str, pos);
|
||||
dec->channel_mask =
|
||||
gst_wavpack_get_channel_mask_from_positions (pos, dec->channels);
|
||||
}
|
||||
|
||||
if (pos != NULL)
|
||||
g_free (pos);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps);
|
||||
|
||||
/* should always succeed */
|
||||
|
@ -248,7 +267,10 @@ gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf)
|
|||
if (!gst_wavpack_read_header (&wph, GST_BUFFER_DATA (buf)))
|
||||
goto invalid_header;
|
||||
|
||||
if (GST_BUFFER_SIZE (buf) != wph.ckSize + 4 * 1 + 4)
|
||||
if (GST_BUFFER_SIZE (buf) < wph.ckSize + 4 * 1 + 4)
|
||||
goto input_not_framed;
|
||||
|
||||
if (!(wph.flags & INITIAL_BLOCK))
|
||||
goto input_not_framed;
|
||||
|
||||
dec->wv_id.buffer = GST_BUFFER_DATA (buf);
|
||||
|
@ -282,10 +304,12 @@ gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf)
|
|||
format_changed =
|
||||
(dec->sample_rate != WavpackGetSampleRate (dec->context)) ||
|
||||
(dec->channels != WavpackGetNumChannels (dec->context)) ||
|
||||
(dec->depth != WavpackGetBitsPerSample (dec->context));
|
||||
(dec->depth != WavpackGetBitsPerSample (dec->context)) ||
|
||||
(dec->channel_mask != WavpackGetChannelMask (dec->context));
|
||||
|
||||
if (!GST_PAD_CAPS (dec->srcpad) || format_changed) {
|
||||
GstCaps *caps;
|
||||
gint channel_mask;
|
||||
|
||||
dec->sample_rate = WavpackGetSampleRate (dec->context);
|
||||
dec->channels = WavpackGetNumChannels (dec->context);
|
||||
|
@ -299,6 +323,18 @@ gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf)
|
|||
"endianness", G_TYPE_INT, G_BYTE_ORDER,
|
||||
"signed", G_TYPE_BOOLEAN, TRUE, NULL);
|
||||
|
||||
channel_mask = WavpackGetChannelMask (dec->context);
|
||||
if (channel_mask == 0)
|
||||
channel_mask = gst_wavpack_get_default_channel_mask (dec->channels);
|
||||
|
||||
dec->channel_mask = channel_mask;
|
||||
|
||||
/* Only set the channel layout for more than two channels
|
||||
* otherwise things break unfortunately */
|
||||
if (channel_mask != 0 && dec->channels > 2)
|
||||
if (!gst_wavpack_set_channel_layout (caps, channel_mask))
|
||||
GST_WARNING_OBJECT (dec, "Failed to set channel layout");
|
||||
|
||||
GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps);
|
||||
|
||||
/* should always succeed */
|
||||
|
@ -367,7 +403,9 @@ invalid_header:
|
|||
decode_error:
|
||||
{
|
||||
GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
|
||||
("Failed to decode wavpack stream"));
|
||||
("Failed to decode wavpack stream: %s",
|
||||
(dec->context) ? WavpackGetErrorMessage (dec->
|
||||
context) : "couldn't create decoder context"));
|
||||
gst_buffer_unref (outbuf);
|
||||
gst_buffer_unref (buf);
|
||||
return GST_FLOW_ERROR;
|
||||
|
|
|
@ -62,6 +62,7 @@ struct _GstWavpackDec
|
|||
gint sample_rate;
|
||||
gint depth;
|
||||
gint channels;
|
||||
gint channel_mask;
|
||||
|
||||
gint error_count;
|
||||
};
|
||||
|
|
|
@ -52,21 +52,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* TODO: - add multichannel handling. channel_mask is:
|
||||
* front left
|
||||
* front right
|
||||
* center
|
||||
* LFE
|
||||
* back left
|
||||
* back right
|
||||
* front left center
|
||||
* front right center
|
||||
* back left
|
||||
* back center
|
||||
* side left
|
||||
* side right
|
||||
* ...
|
||||
* - add 32 bit float mode. CONFIG_FLOAT_DATA
|
||||
* TODO: - add 32 bit float mode. CONFIG_FLOAT_DATA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
@ -111,7 +97,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
|
|||
"width = (int) 32, "
|
||||
"depth = (int) [ 1, 32], "
|
||||
"endianness = (int) BYTE_ORDER, "
|
||||
"channels = (int) [ 1, 2 ], "
|
||||
"channels = (int) [ 1, 8 ], "
|
||||
"rate = (int) [ 6000, 192000 ]," "signed = (boolean) TRUE")
|
||||
);
|
||||
|
||||
|
@ -320,6 +306,12 @@ gst_wavpack_enc_reset (GstWavpackEnc * enc)
|
|||
enc->md5_context = NULL;
|
||||
}
|
||||
|
||||
if (enc->pending_buffer) {
|
||||
gst_buffer_unref (enc->pending_buffer);
|
||||
enc->pending_buffer = NULL;
|
||||
enc->pending_offset = 0;
|
||||
}
|
||||
|
||||
/* reset the last returns to GST_FLOW_OK. This is only set to something else
|
||||
* while WavpackPackSamples() or more specific gst_wavpack_enc_push_block()
|
||||
* so not valid anymore */
|
||||
|
@ -329,6 +321,8 @@ gst_wavpack_enc_reset (GstWavpackEnc * enc)
|
|||
enc->samplerate = 0;
|
||||
enc->depth = 0;
|
||||
enc->channels = 0;
|
||||
enc->channel_mask = 0;
|
||||
enc->need_channel_remap = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -356,8 +350,10 @@ gst_wavpack_enc_init (GstWavpackEnc * enc, GstWavpackEncClass * gclass)
|
|||
|
||||
enc->wv_id.correction = FALSE;
|
||||
enc->wv_id.wavpack_enc = enc;
|
||||
enc->wv_id.passthrough = FALSE;
|
||||
enc->wvc_id.correction = TRUE;
|
||||
enc->wvc_id.wavpack_enc = enc;
|
||||
enc->wvc_id.passthrough = FALSE;
|
||||
|
||||
/* set default values of params */
|
||||
enc->mode = GST_WAVPACK_ENC_MODE_DEFAULT;
|
||||
|
@ -374,6 +370,7 @@ gst_wavpack_enc_sink_set_caps (GstPad * pad, GstCaps * caps)
|
|||
{
|
||||
GstWavpackEnc *enc = GST_WAVPACK_ENC (gst_pad_get_parent (pad));
|
||||
GstStructure *structure = gst_caps_get_structure (caps, 0);
|
||||
GstAudioChannelPosition *pos;
|
||||
|
||||
if (!gst_structure_get_int (structure, "channels", &enc->channels) ||
|
||||
!gst_structure_get_int (structure, "rate", &enc->samplerate) ||
|
||||
|
@ -384,12 +381,37 @@ gst_wavpack_enc_sink_set_caps (GstPad * pad, GstCaps * caps)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
pos = gst_audio_get_channel_positions (structure);
|
||||
/* If one channel is NONE they'll be all undefined */
|
||||
if (pos != NULL && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) {
|
||||
g_free (pos);
|
||||
pos = NULL;
|
||||
}
|
||||
|
||||
if (pos == NULL) {
|
||||
GST_ELEMENT_ERROR (enc, STREAM, FORMAT, (NULL),
|
||||
("input has no valid channel layout"));
|
||||
|
||||
gst_object_unref (enc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
enc->channel_mask =
|
||||
gst_wavpack_get_channel_mask_from_positions (pos, enc->channels);
|
||||
enc->need_channel_remap =
|
||||
gst_wavpack_set_channel_mapping (pos, enc->channels,
|
||||
enc->channel_mapping);
|
||||
g_free (pos);
|
||||
|
||||
/* set fixed src pad caps now that we know what we will get */
|
||||
caps = gst_caps_new_simple ("audio/x-wavpack",
|
||||
"channels", G_TYPE_INT, enc->channels,
|
||||
"rate", G_TYPE_INT, enc->samplerate,
|
||||
"width", G_TYPE_INT, enc->depth, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
|
||||
|
||||
if (!gst_wavpack_set_channel_layout (caps, enc->channel_mask))
|
||||
GST_WARNING_OBJECT (enc, "setting channel layout failed");
|
||||
|
||||
if (!gst_pad_set_caps (enc->srcpad, caps)) {
|
||||
GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL),
|
||||
("setting caps failed: %" GST_PTR_FORMAT, caps));
|
||||
|
@ -412,13 +434,7 @@ gst_wavpack_enc_set_wp_config (GstWavpackEnc * enc)
|
|||
enc->wp_config->bytes_per_sample = GST_ROUND_UP_8 (enc->depth) / 8;
|
||||
enc->wp_config->bits_per_sample = enc->depth;
|
||||
enc->wp_config->num_channels = enc->channels;
|
||||
|
||||
/* TODO: handle more than 2 channels correctly! */
|
||||
if (enc->channels == 1) {
|
||||
enc->wp_config->channel_mask = 0x4;
|
||||
} else if (enc->channels == 2) {
|
||||
enc->wp_config->channel_mask = 0x2 | 0x1;
|
||||
}
|
||||
enc->wp_config->channel_mask = enc->channel_mask;
|
||||
enc->wp_config->sample_rate = enc->samplerate;
|
||||
|
||||
/*
|
||||
|
@ -556,17 +572,43 @@ gst_wavpack_enc_push_block (void *id, void *data, int32_t count)
|
|||
|
||||
gst_wavpack_read_header (&wph, block);
|
||||
|
||||
/* if it's the first wavpack block, send a NEW_SEGMENT event */
|
||||
if (wph.block_index == 0) {
|
||||
gst_pad_push_event (pad,
|
||||
gst_event_new_new_segment (FALSE,
|
||||
1.0, GST_FORMAT_TIME, 0, GST_BUFFER_OFFSET_NONE, 0));
|
||||
/* Only set when pushing the first buffer again, in that case
|
||||
* we don't want to delay the buffer or push newsegment events
|
||||
*/
|
||||
if (!wid->passthrough) {
|
||||
/* Only push complete blocks */
|
||||
if (enc->pending_buffer == NULL) {
|
||||
enc->pending_buffer = buffer;
|
||||
enc->pending_offset = wph.block_index;
|
||||
} else if (enc->pending_offset == wph.block_index) {
|
||||
enc->pending_buffer = gst_buffer_join (enc->pending_buffer, buffer);
|
||||
} else {
|
||||
GST_ERROR ("Got incomplete block, dropping");
|
||||
gst_buffer_unref (enc->pending_buffer);
|
||||
enc->pending_buffer = buffer;
|
||||
enc->pending_offset = wph.block_index;
|
||||
}
|
||||
|
||||
/* save header for later reference, so we can re-send it later on
|
||||
* EOS with fixed up values for total sample count etc. */
|
||||
if (enc->first_block == NULL && !wid->correction) {
|
||||
enc->first_block = g_memdup (block, count);
|
||||
enc->first_block_size = count;
|
||||
if (!(wph.flags & FINAL_BLOCK))
|
||||
return TRUE;
|
||||
|
||||
buffer = enc->pending_buffer;
|
||||
enc->pending_buffer = NULL;
|
||||
enc->pending_offset = 0;
|
||||
|
||||
/* if it's the first wavpack block, send a NEW_SEGMENT event */
|
||||
if (wph.block_index == 0) {
|
||||
gst_pad_push_event (pad,
|
||||
gst_event_new_new_segment (FALSE,
|
||||
1.0, GST_FORMAT_TIME, 0, GST_BUFFER_OFFSET_NONE, 0));
|
||||
|
||||
/* save header for later reference, so we can re-send it later on
|
||||
* EOS with fixed up values for total sample count etc. */
|
||||
if (enc->first_block == NULL && !wid->correction) {
|
||||
enc->first_block =
|
||||
g_memdup (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
|
||||
enc->first_block_size = GST_BUFFER_SIZE (buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -589,6 +631,8 @@ gst_wavpack_enc_push_block (void *id, void *data, int32_t count)
|
|||
}
|
||||
|
||||
/* push the buffer and forward errors */
|
||||
GST_DEBUG_OBJECT (enc, "pushing buffer with %d bytes",
|
||||
GST_BUFFER_SIZE (buffer));
|
||||
*flow = gst_pad_push (pad, buffer);
|
||||
|
||||
if (*flow != GST_FLOW_OK) {
|
||||
|
@ -600,6 +644,24 @@ gst_wavpack_enc_push_block (void *id, void *data, int32_t count)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_wavpack_enc_fix_channel_order (GstWavpackEnc * enc, gint32 * data,
|
||||
gint nsamples)
|
||||
{
|
||||
gint i, j;
|
||||
gint32 tmp[8];
|
||||
|
||||
for (i = 0; i < nsamples / enc->channels; i++) {
|
||||
for (j = 0; j < enc->channels; j++) {
|
||||
tmp[enc->channel_mapping[j]] = data[j];
|
||||
}
|
||||
for (j = 0; j < enc->channels; j++) {
|
||||
data[j] = tmp[j];
|
||||
}
|
||||
data += enc->channels;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_wavpack_enc_chain (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
|
@ -646,6 +708,12 @@ gst_wavpack_enc_chain (GstPad * pad, GstBuffer * buf)
|
|||
GST_DEBUG ("setup of encoding context successfull");
|
||||
}
|
||||
|
||||
if (enc->need_channel_remap) {
|
||||
buf = gst_buffer_make_writable (buf);
|
||||
gst_wavpack_enc_fix_channel_order (enc, (gint32 *) GST_BUFFER_DATA (buf),
|
||||
sample_count);
|
||||
}
|
||||
|
||||
/* if we want to append the MD5 sum to the stream update it here
|
||||
* with the current raw samples */
|
||||
if (enc->md5) {
|
||||
|
@ -700,8 +768,10 @@ gst_wavpack_enc_rewrite_first_block (GstWavpackEnc * enc)
|
|||
if (ret) {
|
||||
/* try to rewrite the first block */
|
||||
GST_DEBUG_OBJECT (enc, "rewriting first block ...");
|
||||
enc->wv_id.passthrough = TRUE;
|
||||
ret = gst_wavpack_enc_push_block (&enc->wv_id,
|
||||
enc->first_block, enc->first_block_size);
|
||||
enc->wv_id.passthrough = FALSE;
|
||||
} else {
|
||||
GST_WARNING_OBJECT (enc, "rewriting of first block failed. "
|
||||
"Seeking to first block failed!");
|
||||
|
@ -721,6 +791,14 @@ gst_wavpack_enc_sink_event (GstPad * pad, GstEvent * event)
|
|||
/* Encode all remaining samples and flush them to the src pads */
|
||||
WavpackFlushSamples (enc->wp_context);
|
||||
|
||||
/* Drop all remaining data, this is no complete block otherwise
|
||||
* it would've been pushed already */
|
||||
if (enc->pending_buffer) {
|
||||
gst_object_unref (enc->pending_buffer);
|
||||
enc->pending_buffer = NULL;
|
||||
enc->pending_offset = 0;
|
||||
}
|
||||
|
||||
/* write the MD5 sum if we have to write one */
|
||||
if ((enc->md5) && (enc->md5_context)) {
|
||||
guchar md5_digest[16];
|
||||
|
|
|
@ -45,6 +45,7 @@ typedef struct
|
|||
{
|
||||
gboolean correction;
|
||||
GstWavpackEnc *wavpack_enc;
|
||||
gboolean passthrough;
|
||||
} GstWavpackEncWriteID;
|
||||
|
||||
|
||||
|
@ -64,6 +65,9 @@ struct _GstWavpackEnc
|
|||
|
||||
gint samplerate;
|
||||
gint channels;
|
||||
gint channel_mask;
|
||||
gint8 channel_mapping[8];
|
||||
gboolean need_channel_remap;
|
||||
gint depth;
|
||||
|
||||
GstWavpackEncWriteID wv_id;
|
||||
|
@ -80,6 +84,9 @@ struct _GstWavpackEnc
|
|||
|
||||
void *first_block;
|
||||
int32_t first_block_size;
|
||||
|
||||
GstBuffer *pending_buffer;
|
||||
gint32 pending_offset;
|
||||
};
|
||||
|
||||
struct _GstWavpackEncClass
|
||||
|
|
|
@ -70,7 +70,7 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
|||
GST_PAD_SOMETIMES,
|
||||
GST_STATIC_CAPS ("audio/x-wavpack, "
|
||||
"width = (int) [ 1, 32 ], "
|
||||
"channels = (int) [ 1, 2 ], "
|
||||
"channels = (int) [ 1, 8 ], "
|
||||
"rate = (int) [ 6000, 192000 ], " "framed = (boolean) true")
|
||||
);
|
||||
|
||||
|
@ -189,7 +189,8 @@ gst_wavpack_parse_index_append_entry (GstWavpackParse * wvparse,
|
|||
/* do we have this one already? */
|
||||
if (wvparse->entries) {
|
||||
entry = gst_wavpack_parse_index_get_last_entry (wvparse);
|
||||
if (entry->byte_offset >= byte_offset)
|
||||
if (entry->byte_offset >= byte_offset
|
||||
|| entry->sample_offset >= sample_offset)
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -245,6 +246,11 @@ gst_wavpack_parse_reset (GstWavpackParse * parse)
|
|||
g_list_foreach (parse->queued_events, (GFunc) gst_mini_object_unref, NULL);
|
||||
g_list_free (parse->queued_events);
|
||||
parse->queued_events = NULL;
|
||||
|
||||
if (parse->pending_buffer)
|
||||
gst_buffer_unref (parse->pending_buffer);
|
||||
|
||||
parse->pending_buffer = NULL;
|
||||
}
|
||||
|
||||
static const GstQueryType *
|
||||
|
@ -422,8 +428,11 @@ gst_wavpack_parse_scan_to_find_sample (GstWavpackParse * parse,
|
|||
gst_wavpack_read_header (&header, GST_BUFFER_DATA (buf));
|
||||
gst_buffer_unref (buf);
|
||||
|
||||
gst_wavpack_parse_index_append_entry (parse, off, header.block_index,
|
||||
header.block_samples);
|
||||
if (header.flags & INITIAL_BLOCK)
|
||||
gst_wavpack_parse_index_append_entry (parse, off, header.block_index,
|
||||
header.block_samples);
|
||||
else
|
||||
continue;
|
||||
|
||||
if (header.block_index <= sample &&
|
||||
sample < (header.block_index + header.block_samples)) {
|
||||
|
@ -631,6 +640,11 @@ gst_wavpack_parse_sink_event (GstPad * pad, GstEvent * event)
|
|||
if (parse->adapter) {
|
||||
gst_adapter_clear (parse->adapter);
|
||||
}
|
||||
if (parse->pending_buffer) {
|
||||
gst_buffer_unref (parse->pending_buffer);
|
||||
parse->pending_buffer = NULL;
|
||||
parse->pending_offset = 0;
|
||||
}
|
||||
ret = gst_pad_push_event (parse->srcpad, event);
|
||||
break;
|
||||
}
|
||||
|
@ -646,6 +660,11 @@ gst_wavpack_parse_sink_event (GstPad * pad, GstEvent * event)
|
|||
* be a complete Wavpack block and we can't do anything with them */
|
||||
gst_adapter_clear (parse->adapter);
|
||||
}
|
||||
if (parse->pending_buffer) {
|
||||
gst_buffer_unref (parse->pending_buffer);
|
||||
parse->pending_buffer = NULL;
|
||||
parse->pending_offset = 0;
|
||||
}
|
||||
ret = gst_pad_push_event (parse->srcpad, event);
|
||||
break;
|
||||
}
|
||||
|
@ -794,6 +813,7 @@ gst_wavpack_parse_create_src_pad (GstWavpackParse * wvparse, GstBuffer * buf,
|
|||
WavpackContext *wpc;
|
||||
gchar error_msg[80];
|
||||
read_id rid;
|
||||
gint channel_mask;
|
||||
|
||||
rid.buffer = GST_BUFFER_DATA (buf);
|
||||
rid.length = GST_BUFFER_SIZE (buf);
|
||||
|
@ -816,6 +836,23 @@ gst_wavpack_parse_create_src_pad (GstWavpackParse * wvparse, GstBuffer * buf,
|
|||
"channels", G_TYPE_INT, wvparse->channels,
|
||||
"rate", G_TYPE_INT, wvparse->samplerate,
|
||||
"framed", G_TYPE_BOOLEAN, TRUE, NULL);
|
||||
|
||||
channel_mask = WavpackGetChannelMask (wpc);
|
||||
if (channel_mask == 0)
|
||||
channel_mask =
|
||||
gst_wavpack_get_default_channel_mask (wvparse->channels);
|
||||
|
||||
if (channel_mask != 0) {
|
||||
if (!gst_wavpack_set_channel_layout (caps, channel_mask)) {
|
||||
GST_WARNING_OBJECT (wvparse, "Failed to set channel layout");
|
||||
gst_caps_unref (caps);
|
||||
caps = NULL;
|
||||
WavpackCloseFile (wpc);
|
||||
g_free (stream_reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wvparse->srcpad =
|
||||
gst_pad_new_from_template (gst_element_class_get_pad_template
|
||||
(GST_ELEMENT_GET_CLASS (wvparse), "src"), "src");
|
||||
|
@ -880,6 +917,24 @@ gst_wavpack_parse_push_buffer (GstWavpackParse * wvparse, GstBuffer * buf,
|
|||
wvparse->queued_events = NULL;
|
||||
}
|
||||
|
||||
if (wvparse->pending_buffer == NULL) {
|
||||
wvparse->pending_buffer = buf;
|
||||
wvparse->pending_offset = header->block_index;
|
||||
} else if (wvparse->pending_offset == header->block_index) {
|
||||
wvparse->pending_buffer = gst_buffer_join (wvparse->pending_buffer, buf);
|
||||
} else {
|
||||
GST_ERROR ("Got incomplete block, dropping");
|
||||
gst_buffer_unref (wvparse->pending_buffer);
|
||||
wvparse->pending_buffer = buf;
|
||||
wvparse->pending_offset = header->block_index;
|
||||
}
|
||||
|
||||
if (!(header->flags & FINAL_BLOCK))
|
||||
return GST_FLOW_OK;
|
||||
|
||||
buf = wvparse->pending_buffer;
|
||||
wvparse->pending_buffer = NULL;
|
||||
|
||||
GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (header->block_index,
|
||||
GST_SECOND, wvparse->samplerate);
|
||||
GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int (header->block_samples,
|
||||
|
@ -1014,9 +1069,9 @@ gst_wavpack_parse_loop (GstElement * element)
|
|||
goto pause;
|
||||
}
|
||||
}
|
||||
|
||||
gst_wavpack_parse_index_append_entry (parse, parse->current_offset,
|
||||
header.block_index, header.block_samples);
|
||||
if (header.flags & INITIAL_BLOCK)
|
||||
gst_wavpack_parse_index_append_entry (parse, parse->current_offset,
|
||||
header.block_index, header.block_samples);
|
||||
|
||||
flow_ret = gst_wavpack_parse_push_buffer (parse, buf, &header);
|
||||
if (flow_ret != GST_FLOW_OK)
|
||||
|
|
|
@ -67,6 +67,9 @@ struct _GstWavpackParse
|
|||
|
||||
GstSegment segment; /* the currently configured segment, in
|
||||
* samples/audio frames (DEFAULT format) */
|
||||
|
||||
GstBuffer *pending_buffer;
|
||||
gint32 pending_offset;
|
||||
guint32 next_block_index;
|
||||
|
||||
GstAdapter *adapter; /* when operating chain-based, otherwise NULL */
|
||||
|
|
|
@ -35,11 +35,15 @@ gst_wavpack_stream_reader_read_bytes (void *id, void *data, int32_t bcount)
|
|||
uint32_t left = rid->length - rid->position;
|
||||
uint32_t to_read = MIN (left, bcount);
|
||||
|
||||
GST_DEBUG ("Trying to read %d of %d bytes from position %d", bcount,
|
||||
rid->length, rid->position);
|
||||
|
||||
if (to_read > 0) {
|
||||
g_memmove (data, rid->buffer + rid->position, to_read);
|
||||
rid->position += to_read;
|
||||
return to_read;
|
||||
} else {
|
||||
GST_WARNING ("Couldn't read %d bytes");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -47,20 +51,23 @@ gst_wavpack_stream_reader_read_bytes (void *id, void *data, int32_t bcount)
|
|||
static uint32_t
|
||||
gst_wavpack_stream_reader_get_pos (void *id)
|
||||
{
|
||||
GST_DEBUG ("Returning position %d", ((read_id *) id)->position);
|
||||
return ((read_id *) id)->position;
|
||||
}
|
||||
|
||||
static int
|
||||
gst_wavpack_stream_reader_set_pos_abs (void *id, uint32_t pos)
|
||||
{
|
||||
GST_DEBUG ("should not be called");
|
||||
GST_WARNING ("Should not be called: tried to set absolute position to %d",
|
||||
pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
gst_wavpack_stream_reader_set_pos_rel (void *id, int32_t delta, int mode)
|
||||
{
|
||||
GST_DEBUG ("should not be called");
|
||||
GST_WARNING ("Should not be called: tried to set relative position to %d"
|
||||
" with mode %d", delta, mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -69,6 +76,8 @@ gst_wavpack_stream_reader_push_back_byte (void *id, int c)
|
|||
{
|
||||
read_id *rid = (read_id *) id;
|
||||
|
||||
GST_DEBUG ("Pushing back one byte: 0x%x", c);
|
||||
|
||||
rid->position -= 1;
|
||||
if (rid->position < 0)
|
||||
rid->position = 0;
|
||||
|
@ -78,19 +87,22 @@ gst_wavpack_stream_reader_push_back_byte (void *id, int c)
|
|||
static uint32_t
|
||||
gst_wavpack_stream_reader_get_length (void *id)
|
||||
{
|
||||
GST_DEBUG ("Returning length %d", ((read_id *) id)->length);
|
||||
|
||||
return ((read_id *) id)->length;
|
||||
}
|
||||
|
||||
static int
|
||||
gst_wavpack_stream_reader_can_seek (void *id)
|
||||
{
|
||||
GST_DEBUG ("Can't seek");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
gst_wavpack_stream_reader_write_bytes (void *id, void *data, int32_t bcount)
|
||||
{
|
||||
GST_DEBUG ("should not be called");
|
||||
GST_WARNING ("Should not be called, tried to write %d bytes", bcount);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue