]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/rsd.c
Merge commit 'e02dcdf6bb6835ef4b49986b85a67efcb3495a7f'
[ffmpeg] / libavformat / rsd.c
index 1eff5de7e657b4ce328afe8c838969d71fff6339..98e793e9ef5e2a5aafb5aad7bc4a324b326808f1 100644 (file)
 #include "internal.h"
 
 static const AVCodecTag rsd_tags[] = {
+    { AV_CODEC_ID_ADPCM_PSX,       MKTAG('V','A','G',' ') },
     { AV_CODEC_ID_ADPCM_THP,       MKTAG('G','A','D','P') },
+    { AV_CODEC_ID_ADPCM_THP,       MKTAG('W','A','D','P') },
     { AV_CODEC_ID_ADPCM_IMA_RAD,   MKTAG('R','A','D','P') },
+    { AV_CODEC_ID_ADPCM_IMA_WAV,   MKTAG('X','A','D','P') },
     { AV_CODEC_ID_PCM_S16BE,       MKTAG('P','C','M','B') },
     { AV_CODEC_ID_PCM_S16LE,       MKTAG('P','C','M',' ') },
     { AV_CODEC_ID_NONE, 0 },
@@ -35,9 +38,6 @@ static const AVCodecTag rsd_tags[] = {
 
 static const uint32_t rsd_unsupported_tags[] = {
     MKTAG('O','G','G',' '),
-    MKTAG('V','A','G',' '),
-    MKTAG('W','A','D','P'),
-    MKTAG('X','A','D','P'),
     MKTAG('X','M','A',' '),
 };
 
@@ -55,7 +55,7 @@ static int rsd_probe(AVProbeData *p)
 static int rsd_read_header(AVFormatContext *s)
 {
     AVIOContext *pb = s->pb;
-    int i, version, start = 0x800;
+    int i, ret, version, start = 0x800;
     AVCodecContext *codec;
     AVStream *st = avformat_new_stream(s, NULL);
 
@@ -95,25 +95,52 @@ static int rsd_read_header(AVFormatContext *s)
     avio_skip(pb, 4); // Unknown
 
     switch (codec->codec_id) {
+    case AV_CODEC_ID_ADPCM_PSX:
+        codec->block_align = 16 * codec->channels;
+        if (pb->seekable)
+            st->duration = av_get_audio_frame_duration(codec, avio_size(pb) - start);
+        break;
     case AV_CODEC_ID_ADPCM_IMA_RAD:
         codec->block_align = 20 * codec->channels;
         if (pb->seekable)
             st->duration = av_get_audio_frame_duration(codec, avio_size(pb) - start);
         break;
+    case AV_CODEC_ID_ADPCM_IMA_WAV:
+        if (version == 2)
+            start = avio_rl32(pb);
+
+        codec->bits_per_coded_sample = 4;
+        codec->block_align = 36 * codec->channels;
+        if (pb->seekable)
+            st->duration = av_get_audio_frame_duration(codec, avio_size(pb) - start);
+        break;
     case AV_CODEC_ID_ADPCM_THP:
-        /* RSD3GADP is mono, so only alloc enough memory
-           to store the coeff table for a single channel. */
+        if (st->codec->codec_tag == MKTAG('G','A','D','P')) {
+            /* RSD3GADP is mono, so only alloc enough memory
+               to store the coeff table for a single channel. */
 
-        start = avio_rl32(pb);
+            start = avio_rl32(pb);
 
-        if (ff_get_extradata(codec, s->pb, 32) < 0)
-            return AVERROR(ENOMEM);
+            if ((ret = ff_get_extradata(codec, s->pb, 32)) < 0)
+                return ret;
 
-        for (i = 0; i < 16; i++)
-            AV_WB16(codec->extradata + i * 2, AV_RL16(codec->extradata + i * 2));
+            for (i = 0; i < 16; i++)
+                AV_WB16(codec->extradata + i * 2, AV_RL16(codec->extradata + i * 2));
 
+        } else {
+            codec->block_align = 8 * codec->channels;
+            avio_skip(s->pb, 0x1A4 - avio_tell(s->pb));
+
+            if ((ret = ff_alloc_extradata(st->codec, 32 * st->codec->channels)) < 0)
+                return ret;
+
+            for (i = 0; i < st->codec->channels; i++) {
+                avio_read(s->pb, st->codec->extradata + 32 * i, 32);
+                avio_skip(s->pb, 8);
+            }
+        }
         if (pb->seekable)
-            st->duration = (avio_size(pb) - start) / 8 * 14;
+            st->duration = (avio_size(pb) - start) / (8 * st->codec->channels) * 14;
         break;
     case AV_CODEC_ID_PCM_S16LE:
     case AV_CODEC_ID_PCM_S16BE:
@@ -140,18 +167,28 @@ static int rsd_read_packet(AVFormatContext *s, AVPacket *pkt)
     if (avio_feof(s->pb))
         return AVERROR_EOF;
 
-    if (codec->codec_id == AV_CODEC_ID_ADPCM_IMA_RAD)
+    if (codec->codec_id == AV_CODEC_ID_ADPCM_IMA_RAD ||
+        codec->codec_id == AV_CODEC_ID_ADPCM_PSX     ||
+        codec->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
         ret = av_get_packet(s->pb, pkt, codec->block_align);
-    else
-        ret = av_get_packet(s->pb, pkt, size);
+    } else if (codec->codec_tag == MKTAG('W','A','D','P') &&
+               codec->channels > 1) {
+        int i, ch;
 
-    if (ret != size) {
-        if (ret < 0) {
-            av_free_packet(pkt);
+        ret = av_new_packet(pkt, codec->block_align);
+        if (ret < 0)
             return ret;
+        for (i = 0; i < 4; i++) {
+            for (ch = 0; ch < codec->channels; ch++) {
+                pkt->data[ch * 8 + i * 2 + 0] = avio_r8(s->pb);
+                pkt->data[ch * 8 + i * 2 + 1] = avio_r8(s->pb);
+            }
         }
-        av_shrink_packet(pkt, ret);
+        ret = 0;
+    } else {
+        ret = av_get_packet(s->pb, pkt, size);
     }
+
     pkt->stream_index = 0;
 
     return ret;