mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
adpcmdec: decode adpcm without explicit length, as found in qt.
This commit is contained in:
parent
181786f8bf
commit
dde31f09bd
1 changed files with 69 additions and 52 deletions
|
@ -161,7 +161,8 @@ adpcmdec_sink_setcaps (GstPad * pad, GstCaps * caps)
|
|||
return FALSE;
|
||||
|
||||
if (!gst_structure_get_int (structure, "block_align", &dec->blocksize))
|
||||
return FALSE;
|
||||
dec->blocksize = -1; /* Not provided */
|
||||
|
||||
if (!gst_structure_get_int (structure, "rate", &dec->rate))
|
||||
return FALSE;
|
||||
if (!gst_structure_get_int (structure, "channels", &dec->channels))
|
||||
|
@ -381,17 +382,65 @@ adpcmdec_decode_ima_block (ADPCMDec * dec, int n_samples, guint8 * data,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
adpcmdec_decode_block (ADPCMDec * dec, guint8 * data, int blocksize)
|
||||
{
|
||||
gboolean res;
|
||||
GstBuffer *outbuf = NULL;
|
||||
int outsize;
|
||||
int samples;
|
||||
|
||||
if (dec->layout == LAYOUT_ADPCM_MICROSOFT) {
|
||||
/* Each block has a 3 byte header per channel, plus 4 bytes per channel to
|
||||
give two initial sample values per channel. Then the remainder gives
|
||||
two samples per byte */
|
||||
if (blocksize < 7 * dec->channels)
|
||||
return GST_FLOW_ERROR;
|
||||
samples = (blocksize - 7 * dec->channels) * 2 + 2 * dec->channels;
|
||||
outsize = 2 * samples;
|
||||
outbuf = gst_buffer_new_and_alloc (outsize);
|
||||
|
||||
res = adpcmdec_decode_ms_block (dec, samples, data,
|
||||
(gint16 *) (GST_BUFFER_DATA (outbuf)));
|
||||
} else if (dec->layout == LAYOUT_ADPCM_DVI) {
|
||||
/* Each block has a 4 byte header per channel, include an initial sample.
|
||||
Then the remainder gives two samples per byte */
|
||||
if (blocksize < 4 * dec->channels)
|
||||
return GST_FLOW_ERROR;
|
||||
samples = (blocksize - 4 * dec->channels) * 2 + dec->channels;
|
||||
outsize = 2 * samples;
|
||||
outbuf = gst_buffer_new_and_alloc (outsize);
|
||||
|
||||
res = adpcmdec_decode_ima_block (dec, samples, data,
|
||||
(gint16 *) (GST_BUFFER_DATA (outbuf)));
|
||||
} else {
|
||||
GST_WARNING_OBJECT (dec, "Unknown layout");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
gst_buffer_unref (outbuf);
|
||||
GST_WARNING_OBJECT (dec, "Decode of block failed");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
gst_buffer_set_caps (outbuf, dec->output_caps);
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = dec->timestamp;
|
||||
dec->out_samples += samples / dec->channels;
|
||||
dec->timestamp = dec->base_timestamp +
|
||||
gst_util_uint64_scale_int (dec->out_samples, GST_SECOND, dec->rate);
|
||||
GST_BUFFER_DURATION (outbuf) = dec->timestamp - GST_BUFFER_TIMESTAMP (outbuf);
|
||||
|
||||
return gst_pad_push (dec->srcpad, outbuf);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
adpcmdec_chain (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
ADPCMDec *dec = (ADPCMDec *) gst_pad_get_parent (pad);
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
guint8 *data;
|
||||
GstBuffer *outbuf = NULL;
|
||||
GstBuffer *databuf = NULL;
|
||||
int outsize;
|
||||
int samples;
|
||||
gboolean res;
|
||||
|
||||
if (!dec->is_setup)
|
||||
adpcmdec_setup (dec);
|
||||
|
@ -403,59 +452,27 @@ adpcmdec_chain (GstPad * pad, GstBuffer * buf)
|
|||
dec->timestamp = dec->base_timestamp;
|
||||
}
|
||||
|
||||
if (dec->blocksize > 0) {
|
||||
gst_adapter_push (dec->adapter, buf);
|
||||
|
||||
while (gst_adapter_available (dec->adapter) >= dec->blocksize) {
|
||||
databuf = gst_adapter_take_buffer (dec->adapter, dec->blocksize);
|
||||
data = GST_BUFFER_DATA (databuf);
|
||||
|
||||
if (dec->layout == LAYOUT_ADPCM_MICROSOFT) {
|
||||
/* Each block has a 3 byte header per channel, plus 4 bytes per channel to
|
||||
give two initial sample values per channel. Then the remainder gives
|
||||
two samples per byte */
|
||||
samples = (dec->blocksize - 7 * dec->channels) * 2 + 2 * dec->channels;
|
||||
outsize = 2 * samples;
|
||||
outbuf = gst_buffer_new_and_alloc (outsize);
|
||||
|
||||
res = adpcmdec_decode_ms_block (dec, samples, data,
|
||||
(gint16 *) (GST_BUFFER_DATA (outbuf)));
|
||||
} else if (dec->layout == LAYOUT_ADPCM_DVI) {
|
||||
/* Each block has a 4 byte header per channel, include an initial sample.
|
||||
Then the remainder gives two samples per byte */
|
||||
samples = (dec->blocksize - 4 * dec->channels) * 2 + dec->channels;
|
||||
outsize = 2 * samples;
|
||||
outbuf = gst_buffer_new_and_alloc (outsize);
|
||||
|
||||
res = adpcmdec_decode_ima_block (dec, samples, data,
|
||||
(gint16 *) (GST_BUFFER_DATA (outbuf)));
|
||||
} else {
|
||||
GST_WARNING_OBJECT (dec, "Unknown layout");
|
||||
ret = GST_FLOW_ERROR;
|
||||
goto done;
|
||||
}
|
||||
ret = adpcmdec_decode_block (dec, data, dec->blocksize);
|
||||
|
||||
/* Done with input data, free it */
|
||||
gst_buffer_unref (databuf);
|
||||
|
||||
if (!res) {
|
||||
gst_buffer_unref (outbuf);
|
||||
GST_WARNING_OBJECT (dec, "Decode of block failed");
|
||||
ret = GST_FLOW_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
gst_buffer_set_caps (outbuf, dec->output_caps);
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = dec->timestamp;
|
||||
dec->out_samples += samples / dec->channels;
|
||||
dec->timestamp = dec->base_timestamp +
|
||||
gst_util_uint64_scale_int (dec->out_samples, GST_SECOND, dec->rate);
|
||||
GST_BUFFER_DURATION (outbuf) =
|
||||
dec->timestamp - GST_BUFFER_TIMESTAMP (outbuf);
|
||||
|
||||
ret = gst_pad_push (dec->srcpad, outbuf);
|
||||
if (ret != GST_FLOW_OK)
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
/* No explicit blocksize; we just process one input buffer at a time */
|
||||
ret = adpcmdec_decode_block (dec, GST_BUFFER_DATA (buf),
|
||||
GST_BUFFER_SIZE (buf));
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
|
||||
done:
|
||||
gst_object_unref (dec);
|
||||
|
|
Loading…
Reference in a new issue