[FFmpeg-devel] [PATCH 1/3] adpcm_thp: Use packet side data for coeff table and previous sample
James Almer
jamrial at gmail.com
Thu Apr 18 03:28:01 CEST 2013
There are several containers that support adpcm_thp (Also known as Gamecube DSP)
streams, but only thp files contain the coeff table and previous sample inside
each frame.
Some don't even contain previous sample information at all.
This change will make it allow us to implement demuxers for said containers.
The BRSTM fate test is updated because the contents of each frame are changed
and the test makes a crc check of said frames instead of the decoded samples.
Signed-off-by: James Almer <jamrial at gmail.com>
---
libavcodec/adpcm.c | 40 ++++++++++++++++++++++++++--------------
libavformat/brstm.c | 10 +++++-----
libavformat/thp.c | 15 ++++++++++++---
tests/ref/fate/brstm | 2 +-
4 files changed, 44 insertions(+), 23 deletions(-)
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index f5af5d4..dd60857 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -591,11 +591,7 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
break;
}
case AV_CODEC_ID_ADPCM_THP:
- has_coded_samples = 1;
- bytestream2_skip(gb, 4); // channel size
- *coded_samples = bytestream2_get_be32(gb);
- *coded_samples -= *coded_samples % 14;
- nb_samples = (buf_size - (8 + 36 * ch)) / (8 * ch) * 14;
+ nb_samples = buf_size / (8 * ch) * 14;
break;
case AV_CODEC_ID_ADPCM_AFC:
nb_samples = buf_size / (9 * ch) * 16;
@@ -1318,17 +1314,31 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
}
case AV_CODEC_ID_ADPCM_THP:
{
- int table[6][16];
- int ch;
+ int table[6][16], prev[6][2];
+ int ch, sd_size;
+ uint8_t *sd_data;
+ GetByteContext sd;
+
+ sd_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &sd_size);
+ bytestream2_init(&sd, sd_data, sd_size);
+ if (bytestream2_get_bytes_left(&sd) < 32 * avctx->channels) {
+ av_log(avctx, AV_LOG_ERROR, "Missing coeff table\n");
+ return AVERROR_INVALIDDATA;
+ }
for (i = 0; i < avctx->channels; i++)
for (n = 0; n < 16; n++)
- table[i][n] = sign_extend(bytestream2_get_be16u(&gb), 16);
+ table[i][n] = sign_extend(bytestream2_get_be16u(&sd), 16);
/* Initialize the previous sample. */
for (i = 0; i < avctx->channels; i++) {
- c->status[i].sample1 = sign_extend(bytestream2_get_be16u(&gb), 16);
- c->status[i].sample2 = sign_extend(bytestream2_get_be16u(&gb), 16);
+ if (bytestream2_get_bytes_left(&sd)) {
+ prev[i][0] = sign_extend(bytestream2_get_be16u(&sd), 16);
+ prev[i][1] = sign_extend(bytestream2_get_be16u(&sd), 16);
+ } else {
+ prev[i][0] = c->status[i].sample1;
+ prev[i][1] = c->status[i].sample2;
+ }
}
for (ch = 0; ch < avctx->channels; ch++) {
@@ -1353,13 +1363,15 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
sampledat = sign_extend(byte >> 4, 4);
}
- sampledat = ((c->status[ch].sample1 * factor1
- + c->status[ch].sample2 * factor2) >> 11) + (sampledat << exp);
+ sampledat = ((prev[ch][0] * factor1
+ + prev[ch][1] * factor2) >> 11) + (sampledat << exp);
*samples = av_clip_int16(sampledat);
- c->status[ch].sample2 = c->status[ch].sample1;
- c->status[ch].sample1 = *samples++;
+ prev[ch][1] = prev[ch][0];
+ prev[ch][0] = *samples++;
}
}
+ c->status[ch].sample1 = prev[ch][0];
+ c->status[ch].sample2 = prev[ch][1];
}
break;
}
diff --git a/libavformat/brstm.c b/libavformat/brstm.c
index 7781b3c..fb3a561 100644
--- a/libavformat/brstm.c
+++ b/libavformat/brstm.c
@@ -260,16 +260,16 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt)
if (codec->codec_id == AV_CODEC_ID_ADPCM_THP) {
uint8_t *dst;
- if (av_new_packet(pkt, 8 + (32 + 4) * codec->channels + size) < 0)
+ if ((ret = av_new_packet(pkt, size)) < 0)
+ return ret;
+ if (!av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, (32 + 4) * codec->channels))
return AVERROR(ENOMEM);
- dst = pkt->data;
- bytestream_put_be32(&dst, size);
- bytestream_put_be32(&dst, samples);
+ dst = pkt->side_data[0].data;
bytestream_put_buffer(&dst, b->table, 32 * codec->channels);
bytestream_put_buffer(&dst, b->adpc + 4 * codec->channels *
(b->current_block - 1), 4 * codec->channels);
- ret = avio_read(s->pb, dst, size);
+ ret = avio_read(s->pb, pkt->data, size);
if (ret != size)
av_free_packet(pkt);
pkt->duration = samples;
diff --git a/libavformat/thp.c b/libavformat/thp.c
index 3717b8f..dd7a2a1 100644
--- a/libavformat/thp.c
+++ b/libavformat/thp.c
@@ -179,15 +179,24 @@ static int thp_read_packet(AVFormatContext *s,
pkt->stream_index = thp->video_stream_index;
} else {
- ret = av_get_packet(pb, pkt, thp->audiosize);
- if (ret != thp->audiosize) {
+ int duration, extradata_size = (32 + 4) * s->streams[1]->codec->channels;
+
+ if ((ret = av_new_packet(pkt, thp->audiosize - extradata_size)) < 0)
+ return ret;
+ if (!av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, extradata_size))
+ return AVERROR(ENOMEM);
+
+ avio_skip(pb, 4);
+ duration = avio_rb32(pb);
+ if (avio_read(pb, pkt->side_data[0].data, extradata_size) != extradata_size ||
+ avio_read(pb, pkt->data, thp->audiosize - extradata_size) != thp->audiosize - extradata_size) {
av_free_packet(pkt);
return AVERROR(EIO);
}
pkt->stream_index = thp->audio_stream_index;
if (thp->audiosize >= 8)
- pkt->duration = AV_RB32(&pkt->data[4]);
+ pkt->duration = duration;
thp->audiosize = 0;
thp->frame++;
diff --git a/tests/ref/fate/brstm b/tests/ref/fate/brstm
index d183b3f..5b1a124 100644
--- a/tests/ref/fate/brstm
+++ b/tests/ref/fate/brstm
@@ -1 +1 @@
-CRC=0x1feb92a8
+CRC=0x2990e735
--
1.8.1.msysgit.1
More information about the ffmpeg-devel
mailing list