From: bnnm <bananaman...@gmail.com>

Fixes trac issue #7473.

Removes encoder delay (skip samples) and writes remaining frame samples after 
EOF to get correct sample count.

Output is now accurate vs players that use Microsoft's codecs (Windows Media 
Format Runtime).

Tested vs encode>decode WMAv2 with MS's codecs and most sample rate/bit 
rate/channel/mode combinations in ASF/XWMA. WMAv1 appears to use the same 
delay, from FFmpeg samples.

Signed-off-by: bnnm <bananaman...@gmail.com>
---
 libavcodec/wma.h    |  2 ++
 libavcodec/wmadec.c | 34 ++++++++++++++++++++++++++++++++--
 2 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/libavcodec/wma.h b/libavcodec/wma.h
index 325f03c44b..c80068de80 100644
--- a/libavcodec/wma.h
+++ b/libavcodec/wma.h
@@ -133,6 +133,8 @@ typedef struct WMACodecContext {
     float lsp_pow_m_table2[(1 << LSP_POW_BITS)];
     AVFloatDSPContext *fdsp;
 
+    int eof_done; /* decode flag to output remaining samples after EOF */
+
 #ifdef TRACE
     int frame_count;
 #endif /* TRACE */
diff --git a/libavcodec/wmadec.c b/libavcodec/wmadec.c
index 78b51e5871..d59432d3f1 100644
--- a/libavcodec/wmadec.c
+++ b/libavcodec/wmadec.c
@@ -124,6 +124,11 @@ static av_cold int wma_decode_init(AVCodecContext *avctx)
 
     avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
 
+    /* Skip WMA encoder delay (>=32000: 4096, >=22050: 2048, >=8000: 1024).
+     * The amount doesn't seem specified in the flags or container (ASF/XWMA),
+     * but can be verified compared to Microsoft codecs' output. */
+    avctx->internal->skip_samples = s->frame_len * 2;
+
     return 0;
 }
 
@@ -819,7 +824,29 @@ static int wma_decode_superframe(AVCodecContext *avctx, 
void *data,
     ff_tlog(avctx, "***decode_superframe:\n");
 
     if (buf_size == 0) {
+        /* must output one final frame with remaining samples */
+
+        if (s->eof_done)
+            return 0;
+
+        /* get output buffer */
+        frame->nb_samples = s->frame_len;
+        if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+            return ret;
+        samples = (float **) frame->extended_data;
+
+        /* clean output buffer and copy last IMCDT samples */
+        for (i = 0; i < s->avctx->channels; i++) {
+            memset(frame->extended_data[i], 0,
+                 s->frame_len * sizeof(*s->frame_out[i]));
+
+            memcpy(frame->extended_data[i], &s->frame_out[i][0],
+                 s->frame_len * sizeof(*s->frame_out[i]) >> 1);
+        }
+
         s->last_superframe_len = 0;
+        s->eof_done = 1;
+        *got_frame_ptr = 1;
         return 0;
     }
     if (buf_size < avctx->block_align) {
@@ -965,6 +992,9 @@ static av_cold void flush(AVCodecContext *avctx)
 
     s->last_bitoffset      =
     s->last_superframe_len = 0;
+
+    s->eof_done = 0;
+    avctx->internal->skip_samples = s->frame_len * 2;
 }
 
 #if CONFIG_WMAV1_DECODER
@@ -978,7 +1008,7 @@ AVCodec ff_wmav1_decoder = {
     .close          = ff_wma_end,
     .decode         = wma_decode_superframe,
     .flush          = flush,
-    .capabilities   = AV_CODEC_CAP_DR1,
+    .capabilities   = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
     .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
                                                       AV_SAMPLE_FMT_NONE },
 };
@@ -994,7 +1024,7 @@ AVCodec ff_wmav2_decoder = {
     .close          = ff_wma_end,
     .decode         = wma_decode_superframe,
     .flush          = flush,
-    .capabilities   = AV_CODEC_CAP_DR1,
+    .capabilities   = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
     .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
                                                       AV_SAMPLE_FMT_NONE },
 };
-- 
2.11.0.windows.3

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to