diff mbox series

[FFmpeg-devel] MSN Siren decoder

Message ID 7670b3b92cbc0d76bb37f4b11281b6baa9e92735.1630740208.git.pross@xvid.org
State New
Headers show
Series [FFmpeg-devel] MSN Siren decoder
Related show

Checks

Context Check Description
andriy/commit_msg_x86 warning The first line of the commit message must start with a context terminated by a colon and a space, for example "lavu/opt: " or "doc: ".
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished
andriy/commit_msg_ppc warning The first line of the commit message must start with a context terminated by a colon and a space, for example "lavu/opt: " or "doc: ".
andriy/make_ppc success Make finished
andriy/make_fate_ppc success Make fate finished

Commit Message

Peter Ross Sept. 4, 2021, 7:30 a.m. UTC
---
Sample: http://samples.ffmpeg.org/A-codecs/msnsiren/msnsiren.wav

 Changelog               |  1 +
 libavcodec/Makefile     |  1 +
 libavcodec/allcodecs.c  |  1 +
 libavcodec/codec_desc.c |  7 +++++
 libavcodec/codec_id.h   |  1 +
 libavcodec/siren.c      | 60 +++++++++++++++++++++++++++++++++++++++--
 libavformat/riff.c      |  1 +
 7 files changed, 70 insertions(+), 2 deletions(-)

Comments

Paul B Mahol Sept. 4, 2021, 8:16 a.m. UTC | #1
LGTM
diff mbox series

Patch

diff --git a/Changelog b/Changelog
index 5b58401183..0044462bf4 100644
--- a/Changelog
+++ b/Changelog
@@ -16,6 +16,7 @@  version <next>:
 - atilt audio filter
 - grayworld video filter
 - AV1 Low overhead bitstream format muxer
+- MSN Siren decoder
 
 
 version 4.4:
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 68d808de42..11873eecae 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -508,6 +508,7 @@  OBJS-$(CONFIG_MSMPEG4V2_DECODER)       += msmpeg4dec.o msmpeg4.o msmpeg4data.o
 OBJS-$(CONFIG_MSMPEG4V2_ENCODER)       += msmpeg4enc.o msmpeg4.o msmpeg4data.o
 OBJS-$(CONFIG_MSMPEG4V3_DECODER)       += msmpeg4dec.o msmpeg4.o msmpeg4data.o
 OBJS-$(CONFIG_MSMPEG4V3_ENCODER)       += msmpeg4enc.o msmpeg4.o msmpeg4data.o
+OBJS-$(CONFIG_MSNSIREN_DECODER)        += siren.o
 OBJS-$(CONFIG_MSP2_DECODER)            += msp2dec.o
 OBJS-$(CONFIG_MSRLE_DECODER)           += msrle.o msrledec.o
 OBJS-$(CONFIG_MSS1_DECODER)            += mss1.o mss12.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index c087b91148..c42aba140d 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -479,6 +479,7 @@  extern const AVCodec ff_mp3on4float_decoder;
 extern const AVCodec ff_mp3on4_decoder;
 extern const AVCodec ff_mpc7_decoder;
 extern const AVCodec ff_mpc8_decoder;
+extern const AVCodec ff_msnsiren_decoder;
 extern const AVCodec ff_nellymoser_encoder;
 extern const AVCodec ff_nellymoser_decoder;
 extern const AVCodec ff_on2avc_decoder;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 674f4bf8c3..a06992fce8 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -3222,6 +3222,13 @@  static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("MobiClip FastAudio"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
     },
+    {
+        .id        = AV_CODEC_ID_MSNSIREN,
+        .type      = AVMEDIA_TYPE_AUDIO,
+        .name      = "msnsiren",
+        .long_name = NULL_IF_CONFIG_SMALL("MSN Siren"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+    },
 
     /* subtitle codecs */
     {
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index d49f9af36c..446bb2c2fb 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -514,6 +514,7 @@  enum AVCodecID {
     AV_CODEC_ID_SIREN,
     AV_CODEC_ID_HCA,
     AV_CODEC_ID_FASTAUDIO,
+    AV_CODEC_ID_MSNSIREN,
 
     /* subtitle codecs */
     AV_CODEC_ID_FIRST_SUBTITLE = 0x17000,          ///< A dummy ID pointing at the start of subtitle codecs.
diff --git a/libavcodec/siren.c b/libavcodec/siren.c
index 87464808a4..df45054a36 100644
--- a/libavcodec/siren.c
+++ b/libavcodec/siren.c
@@ -359,11 +359,13 @@  static const float noise_category6[21] = {
 typedef struct SirenContext {
     GetBitContext gb;
 
+    int microsoft;
     int rate_control_possibilities;
     int esf_adjustment;
     int number_of_regions;
     int scale_factor;
     int sample_rate_bits;
+    int checksum_bits;
 
     unsigned dw1, dw2, dw3, dw4;
 
@@ -421,6 +423,15 @@  static av_cold int siren_init(AVCodecContext *avctx)
     if (!s->fdsp)
         return AVERROR(ENOMEM);
 
+    s->microsoft = avctx->codec->id == AV_CODEC_ID_MSNSIREN;
+    if (s->microsoft) {
+        s->esf_adjustment = -2;
+        s->number_of_regions = 14;
+        s->scale_factor = 1;
+        s->sample_rate_bits = 2;
+        s->checksum_bits = 4;
+    }
+
     return av_tx_init(&s->tx_ctx, &s->tx_fn, AV_TX_FLOAT_MDCT, 1, FRAME_SIZE, &scale, 0);
 }
 
@@ -626,6 +637,20 @@  static int decode_vector(SirenContext *s, int number_of_regions,
 
         coefs_ptr = coefs + (region * REGION_SIZE);
 
+        if (category == 5 && s->microsoft) {
+            i = 0;
+            for (j = 0; j < REGION_SIZE; j++) {
+                if (*coefs_ptr != 0) {
+                    i++;
+                    if (fabs(*coefs_ptr) > 2.0 * decoder_standard_deviation[region]) {
+                        i += 3;
+                    }
+                }
+                coefs_ptr++;
+            }
+
+            noise = decoder_standard_deviation[region] * noise_category5[i];
+        } else
         if (category == 5 || category == 6) {
             i = 0;
             for (j = 0; j < REGION_SIZE; j++) {
@@ -675,10 +700,23 @@  static int siren_decode(AVCodecContext *avctx, void *data,
     AVFrame *frame = data;
     int ret, number_of_valid_coefs = 20 * s->number_of_regions;
     int frame_error = 0, rate_control = 0;
+    int bits_per_frame;
+
+    if (s->microsoft) {
+        bits_per_frame  = avctx->sample_rate / 50;
 
+        if (avpkt->size < bits_per_frame / 8)
+            return AVERROR_INVALIDDATA;
+
+        if ((ret = init_get_bits(gb, avpkt->data, bits_per_frame - s->checksum_bits)) < 0)
+            return ret;
+
+    } else
     if ((ret = init_get_bits8(gb, avpkt->data, avpkt->size)) < 0)
         return ret;
 
+    skip_bits(gb, s->sample_rate_bits);
+
     decode_envelope(s, gb, s->number_of_regions,
                     s->decoder_standard_deviation,
                     s->absolute_region_power_index, s->esf_adjustment);
@@ -697,7 +735,7 @@  static int siren_decode(AVCodecContext *avctx, void *data,
     ret = decode_vector(s, s->number_of_regions, get_bits_left(gb),
                         s->decoder_standard_deviation, s->power_categories,
                         s->imdct_in, s->scale_factor);
-    if (ret < 0)
+    if (ret < 0 && !s->microsoft)
         return ret;
 
     if (get_bits_left(gb) > 0) {
@@ -715,6 +753,8 @@  static int siren_decode(AVCodecContext *avctx, void *data,
             frame_error = 1;
     }
 
+    skip_bits(gb, s->checksum_bits);
+
     if (frame_error) {
         memcpy(s->imdct_in, s->backup_frame, number_of_valid_coefs * sizeof(float));
         memset(s->backup_frame, 0, number_of_valid_coefs * sizeof(float));
@@ -738,7 +778,7 @@  static int siren_decode(AVCodecContext *avctx, void *data,
 
     *got_frame = 1;
 
-    return avpkt->size;
+    return s->microsoft ? bits_per_frame / 8 : avpkt->size;
 }
 
 static av_cold void siren_flush(AVCodecContext *avctx)
@@ -775,3 +815,19 @@  const AVCodec ff_siren_decoder = {
     .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
                       FF_CODEC_CAP_INIT_CLEANUP,
 };
+
+const AVCodec ff_msnsiren_decoder = {
+    .name           = "msnsiren",
+    .long_name      = NULL_IF_CONFIG_SMALL("MSN Siren"),
+    .priv_data_size = sizeof(SirenContext),
+    .type           = AVMEDIA_TYPE_AUDIO,
+    .id             = AV_CODEC_ID_MSNSIREN,
+    .init           = siren_init,
+    .close          = siren_close,
+    .decode         = siren_decode,
+    .flush          = siren_flush,
+    .capabilities   = AV_CODEC_CAP_CHANNEL_CONF |
+                      AV_CODEC_CAP_DR1,
+    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
+                      FF_CODEC_CAP_INIT_CLEANUP,
+};
diff --git a/libavformat/riff.c b/libavformat/riff.c
index 423926e3bd..27a9706510 100644
--- a/libavformat/riff.c
+++ b/libavformat/riff.c
@@ -560,6 +560,7 @@  const AVCodecTag ff_codec_wav_tags[] = {
     { AV_CODEC_ID_DVAUDIO,         0x0215 },
     { AV_CODEC_ID_DVAUDIO,         0x0216 },
     { AV_CODEC_ID_ATRAC3,          0x0270 },
+    { AV_CODEC_ID_MSNSIREN,        0x028E },
     { AV_CODEC_ID_ADPCM_G722,      0x028F },
     { AV_CODEC_ID_IMC,             0x0401 },
     { AV_CODEC_ID_IAC,             0x0402 },