[FFmpeg-devel] [PATCH 1/3] adpcm_thp: Use packet side data for coeff table and previous sample

James Almer jamrial at gmail.com
Mon Apr 22 11:25:44 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 easier to implement demuxers for said containers
without having to create a new decoder.

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   | 32 +++++++++++++++++++-------------
 libavformat/brstm.c  | 10 +++++-----
 libavformat/thp.c    | 15 ++++++++++++---
 tests/ref/fate/brstm |  2 +-
 4 files changed, 37 insertions(+), 22 deletions(-)

diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index f5af5d4..a036c09 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;
@@ -1319,19 +1315,29 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
     case AV_CODEC_ID_ADPCM_THP:
     {
         int table[6][16];
-        int ch;
-
-        for (i = 0; i < avctx->channels; i++)
-            for (n = 0; n < 16; n++)
-                table[i][n] = sign_extend(bytestream2_get_be16u(&gb), 16);
+        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;
+        }
 
-        /* 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);
+            for (n = 0; n < 16; n++)
+                table[i][n] = sign_extend(bytestream2_get_be16u(&sd), 16);
         }
 
         for (ch = 0; ch < avctx->channels; ch++) {
+            /* Initialize the previous sample.  */
+            if (bytestream2_get_bytes_left(&sd)) {
+                c->status[ch].sample1 = sign_extend(bytestream2_get_be16u(&sd), 16);
+                c->status[ch].sample2 = sign_extend(bytestream2_get_be16u(&sd), 16);
+            }
+
             samples = samples_p[ch];
 
             /* Read in every sample for this channel.  */
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