mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-06 07:28:53 +00:00
wavpackdec: adjust to audio format limitations
... which does not allow expressing arbitrary depth in a GstAudioFormat. Also adjust unit test to modified behaviour.
This commit is contained in:
parent
0723928e8b
commit
a5144cbba0
3 changed files with 67 additions and 21 deletions
|
@ -71,11 +71,20 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("audio/x-raw-int, "
|
GST_STATIC_CAPS ("audio/x-raw-int, "
|
||||||
"width = (int) 32, "
|
"width = (int) 8, depth = (int) 8, "
|
||||||
"depth = (int) [ 1, 32 ], "
|
|
||||||
"channels = (int) [ 1, 8 ], "
|
"channels = (int) [ 1, 8 ], "
|
||||||
"rate = (int) [ 6000, 192000 ], "
|
"rate = (int) [ 6000, 192000 ], "
|
||||||
"endianness = (int) BYTE_ORDER, " "signed = (boolean) true")
|
"endianness = (int) BYTE_ORDER, " "signed = (boolean) true; "
|
||||||
|
"audio/x-raw-int, "
|
||||||
|
"width = (int) 16, depth = (int) 16, "
|
||||||
|
"channels = (int) [ 1, 8 ], "
|
||||||
|
"rate = (int) [ 6000, 192000 ], "
|
||||||
|
"endianness = (int) BYTE_ORDER, " "signed = (boolean) true; "
|
||||||
|
"audio/x-raw-int, "
|
||||||
|
"width = (int) 32, depth = (int) 32, "
|
||||||
|
"channels = (int) [ 1, 8 ], "
|
||||||
|
"rate = (int) [ 6000, 192000 ], "
|
||||||
|
"endianness = (int) BYTE_ORDER, " "signed = (boolean) true; ")
|
||||||
);
|
);
|
||||||
|
|
||||||
static gboolean gst_wavpack_dec_start (GstAudioDecoder * dec);
|
static gboolean gst_wavpack_dec_start (GstAudioDecoder * dec);
|
||||||
|
@ -186,11 +195,17 @@ gst_wavpack_dec_negotiate (GstWavpackDec * dec)
|
||||||
{
|
{
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
|
|
||||||
|
/* arrange for 1, 2 or 4-byte width == depth output */
|
||||||
|
if (dec->depth == 24)
|
||||||
|
dec->width = 32;
|
||||||
|
else
|
||||||
|
dec->width = dec->depth;
|
||||||
|
|
||||||
caps = gst_caps_new_simple ("audio/x-raw-int",
|
caps = gst_caps_new_simple ("audio/x-raw-int",
|
||||||
"rate", G_TYPE_INT, dec->sample_rate,
|
"rate", G_TYPE_INT, dec->sample_rate,
|
||||||
"channels", G_TYPE_INT, dec->channels,
|
"channels", G_TYPE_INT, dec->channels,
|
||||||
"depth", G_TYPE_INT, dec->depth,
|
"depth", G_TYPE_INT, dec->width,
|
||||||
"width", G_TYPE_INT, 32,
|
"width", G_TYPE_INT, dec->width,
|
||||||
"endianness", G_TYPE_INT, G_BYTE_ORDER,
|
"endianness", G_TYPE_INT, G_BYTE_ORDER,
|
||||||
"signed", G_TYPE_BOOLEAN, TRUE, NULL);
|
"signed", G_TYPE_BOOLEAN, TRUE, NULL);
|
||||||
|
|
||||||
|
@ -279,6 +294,9 @@ gst_wavpack_dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf)
|
||||||
WavpackHeader wph;
|
WavpackHeader wph;
|
||||||
int32_t decoded, unpacked_size;
|
int32_t decoded, unpacked_size;
|
||||||
gboolean format_changed;
|
gboolean format_changed;
|
||||||
|
gint width, depth, i, max;
|
||||||
|
gint32 *dec_data = NULL;
|
||||||
|
guint8 *out_data;
|
||||||
|
|
||||||
dec = GST_WAVPACK_DEC (bdec);
|
dec = GST_WAVPACK_DEC (bdec);
|
||||||
|
|
||||||
|
@ -354,7 +372,7 @@ gst_wavpack_dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* alloc output buffer */
|
/* alloc output buffer */
|
||||||
unpacked_size = 4 * wph.block_samples * dec->channels;
|
unpacked_size = (dec->width / 8) * wph.block_samples * dec->channels;
|
||||||
ret = gst_pad_alloc_buffer (GST_AUDIO_DECODER_SRC_PAD (dec),
|
ret = gst_pad_alloc_buffer (GST_AUDIO_DECODER_SRC_PAD (dec),
|
||||||
GST_BUFFER_OFFSET (buf), unpacked_size,
|
GST_BUFFER_OFFSET (buf), unpacked_size,
|
||||||
GST_PAD_CAPS (GST_AUDIO_DECODER_SRC_PAD (dec)), &outbuf);
|
GST_PAD_CAPS (GST_AUDIO_DECODER_SRC_PAD (dec)), &outbuf);
|
||||||
|
@ -362,12 +380,47 @@ gst_wavpack_dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf)
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
dec_data = g_malloc (4 * wph.block_samples * dec->channels);
|
||||||
|
out_data = GST_BUFFER_DATA (outbuf);
|
||||||
|
|
||||||
/* decode */
|
/* decode */
|
||||||
decoded = WavpackUnpackSamples (dec->context,
|
decoded = WavpackUnpackSamples (dec->context, dec_data, wph.block_samples);
|
||||||
(int32_t *) GST_BUFFER_DATA (outbuf), wph.block_samples);
|
|
||||||
if (decoded != wph.block_samples)
|
if (decoded != wph.block_samples)
|
||||||
goto decode_error;
|
goto decode_error;
|
||||||
|
|
||||||
|
width = dec->width;
|
||||||
|
depth = dec->depth;
|
||||||
|
max = dec->channels * wph.block_samples;
|
||||||
|
if (width == 8) {
|
||||||
|
gint8 *outbuffer = (gint8 *) out_data;
|
||||||
|
|
||||||
|
for (i = 0; i < max; i--) {
|
||||||
|
*outbuffer++ = (gint8) (dec_data[i]);
|
||||||
|
}
|
||||||
|
} else if (width == 16) {
|
||||||
|
gint16 *outbuffer = (gint16 *) out_data;
|
||||||
|
|
||||||
|
for (i = 0; i < max; i++) {
|
||||||
|
*outbuffer++ = (gint8) (dec_data[i]);
|
||||||
|
}
|
||||||
|
} else if (dec->width == 32) {
|
||||||
|
gint32 *outbuffer = (gint32 *) out_data;
|
||||||
|
|
||||||
|
if (width != depth) {
|
||||||
|
for (i = 0; i < max; i++) {
|
||||||
|
*outbuffer++ = (gint32) (dec_data[i] << (width - depth));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < max; i++) {
|
||||||
|
*outbuffer++ = (gint32) dec_data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (dec_data);
|
||||||
|
|
||||||
ret = gst_audio_decoder_finish_frame (bdec, outbuf, 1);
|
ret = gst_audio_decoder_finish_frame (bdec, outbuf, 1);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -410,6 +463,7 @@ decode_error:
|
||||||
}
|
}
|
||||||
GST_AUDIO_DECODER_ERROR (bdec, 1, STREAM, DECODE, (NULL),
|
GST_AUDIO_DECODER_ERROR (bdec, 1, STREAM, DECODE, (NULL),
|
||||||
("decoding error: %s", reason), ret);
|
("decoding error: %s", reason), ret);
|
||||||
|
g_free (dec_data);
|
||||||
if (outbuf)
|
if (outbuf)
|
||||||
gst_buffer_unref (outbuf);
|
gst_buffer_unref (outbuf);
|
||||||
if (ret == GST_FLOW_OK)
|
if (ret == GST_FLOW_OK)
|
||||||
|
|
|
@ -57,6 +57,7 @@ struct _GstWavpackDec
|
||||||
|
|
||||||
gint sample_rate;
|
gint sample_rate;
|
||||||
gint depth;
|
gint depth;
|
||||||
|
gint width;
|
||||||
gint channels;
|
gint channels;
|
||||||
gint channel_mask;
|
gint channel_mask;
|
||||||
};
|
};
|
||||||
|
|
|
@ -52,7 +52,7 @@ static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS ("audio/x-raw-int, "
|
GST_STATIC_CAPS ("audio/x-raw-int, "
|
||||||
"width = (int) 32, "
|
"width = (int) 16, "
|
||||||
"depth = (int) 16, "
|
"depth = (int) 16, "
|
||||||
"channels = (int) 1, "
|
"channels = (int) 1, "
|
||||||
"rate = (int) 44100, "
|
"rate = (int) 44100, "
|
||||||
|
@ -112,23 +112,20 @@ GST_START_TEST (test_decode_frame)
|
||||||
memcpy (GST_BUFFER_DATA (inbuffer), test_frame, sizeof (test_frame));
|
memcpy (GST_BUFFER_DATA (inbuffer), test_frame, sizeof (test_frame));
|
||||||
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
|
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
|
||||||
GST_BUFFER_TIMESTAMP (inbuffer) = 0;
|
GST_BUFFER_TIMESTAMP (inbuffer) = 0;
|
||||||
gst_buffer_ref (inbuffer);
|
|
||||||
|
|
||||||
gst_element_set_bus (wavpackdec, bus);
|
gst_element_set_bus (wavpackdec, bus);
|
||||||
|
|
||||||
/* should decode the buffer without problems */
|
/* should decode the buffer without problems */
|
||||||
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
|
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
|
||||||
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
|
|
||||||
gst_buffer_unref (inbuffer);
|
|
||||||
|
|
||||||
outbuffer = GST_BUFFER (buffers->data);
|
outbuffer = GST_BUFFER (buffers->data);
|
||||||
|
|
||||||
fail_if (outbuffer == NULL);
|
fail_if (outbuffer == NULL);
|
||||||
/* uncompressed data should be 102400 bytes */
|
/* uncompressed data should be 102400 bytes */
|
||||||
fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), 102400);
|
fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), 51200);
|
||||||
|
|
||||||
/* and all 102400 bytes must be 0, i.e. silence */
|
/* and all bytes must be 0, i.e. silence */
|
||||||
for (i = 0; i < 102400; i++)
|
for (i = 0; i < 51200; i++)
|
||||||
fail_unless_equals_int (GST_BUFFER_DATA (outbuffer)[i], 0);
|
fail_unless_equals_int (GST_BUFFER_DATA (outbuffer)[i], 0);
|
||||||
|
|
||||||
ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
|
ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
|
||||||
|
@ -166,14 +163,11 @@ GST_START_TEST (test_decode_frame_with_broken_header)
|
||||||
GST_BUFFER_DATA (inbuffer)[2] = 'e';
|
GST_BUFFER_DATA (inbuffer)[2] = 'e';
|
||||||
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
|
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
|
||||||
GST_BUFFER_TIMESTAMP (inbuffer) = 0;
|
GST_BUFFER_TIMESTAMP (inbuffer) = 0;
|
||||||
gst_buffer_ref (inbuffer);
|
|
||||||
|
|
||||||
gst_element_set_bus (wavpackdec, bus);
|
gst_element_set_bus (wavpackdec, bus);
|
||||||
|
|
||||||
/* should fail gracefully */
|
/* should fail gracefully */
|
||||||
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_ERROR);
|
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_ERROR);
|
||||||
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
|
|
||||||
gst_buffer_unref (inbuffer);
|
|
||||||
|
|
||||||
fail_if ((message = gst_bus_pop (bus)) == NULL);
|
fail_if ((message = gst_bus_pop (bus)) == NULL);
|
||||||
fail_unless_message_error (message, STREAM, DECODE);
|
fail_unless_message_error (message, STREAM, DECODE);
|
||||||
|
@ -204,14 +198,11 @@ GST_START_TEST (test_decode_frame_with_incomplete_frame)
|
||||||
memcpy (GST_BUFFER_DATA (inbuffer), test_frame, sizeof (test_frame) - 2);
|
memcpy (GST_BUFFER_DATA (inbuffer), test_frame, sizeof (test_frame) - 2);
|
||||||
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
|
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
|
||||||
GST_BUFFER_TIMESTAMP (inbuffer) = 0;
|
GST_BUFFER_TIMESTAMP (inbuffer) = 0;
|
||||||
gst_buffer_ref (inbuffer);
|
|
||||||
|
|
||||||
gst_element_set_bus (wavpackdec, bus);
|
gst_element_set_bus (wavpackdec, bus);
|
||||||
|
|
||||||
/* should fail gracefully */
|
/* should fail gracefully */
|
||||||
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_ERROR);
|
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_ERROR);
|
||||||
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
|
|
||||||
gst_buffer_unref (inbuffer);
|
|
||||||
|
|
||||||
fail_if ((message = gst_bus_pop (bus)) == NULL);
|
fail_if ((message = gst_bus_pop (bus)) == NULL);
|
||||||
fail_unless_message_error (message, STREAM, DECODE);
|
fail_unless_message_error (message, STREAM, DECODE);
|
||||||
|
|
Loading…
Reference in a new issue