diff mbox

[FFmpeg-devel] avcodec/wmaprodec: improve XMA missing samples

Message ID 20181026234950.4220-1-bananaman255@gmail.com
State Accepted
Commit 27e114b4511b771ccf2c64ab9f4a3d0391ace4ea
Headers show

Commit Message

bananaman255@gmail.com Oct. 26, 2018, 11:49 p.m. UTC
From: bnnm <bananaman255@gmail.com>

Writes missing (delay) samples after EOF.

Signed-off-by: bnnm <bananaman255@gmail.com>
---
 libavcodec/wmaprodec.c | 35 ++++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

Comments

Paul B Mahol Oct. 27, 2018, 8:32 a.m. UTC | #1
On 10/27/18, bananaman255@gmail.com <bananaman255@gmail.com> wrote:
> From: bnnm <bananaman255@gmail.com>
>
> Writes missing (delay) samples after EOF.
>
> Signed-off-by: bnnm <bananaman255@gmail.com>
> ---
>  libavcodec/wmaprodec.c | 35 ++++++++++++++++++++++++++++++++---
>  1 file changed, 32 insertions(+), 3 deletions(-)
>
> diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c
> index 9439bfa771..d0fa974c80 100644
> --- a/libavcodec/wmaprodec.c
> +++ b/libavcodec/wmaprodec.c
> @@ -210,6 +210,7 @@ typedef struct WMAProDecodeCtx {
>      int              subframe_offset;               ///< subframe offset in
> the bit reservoir
>      uint8_t          packet_loss;                   ///< set in case of
> bitstream error
>      uint8_t          packet_done;                   ///< set when a packet
> is fully decoded
> +    uint8_t          eof_done;                      ///< set when EOF
> reached and extra subframe is written (XMA1/2)
>
>      /* frame decode state */
>      uint32_t         frame_num;                     ///< current frame
> number (not used for decoding)
> @@ -1609,7 +1610,34 @@ static int decode_packet(AVCodecContext *avctx,
> WMAProDecodeCtx *s,
>
>      *got_frame_ptr = 0;
>
> -    if (s->packet_done || s->packet_loss) {
> +    if (!buf_size) {
> +        AVFrame *frame = data;
> +        int i;
> +
> +        /** Must output remaining samples after stream end. WMAPRO 5.1
> created
> +         * by XWMA encoder don't though (maybe only 1/2ch streams need it).
> */
> +        s->packet_done = 0;
> +        if (s->eof_done)
> +            return 0;
> +
> +        /** clean output buffer and copy last IMDCT samples */
> +        for (i = 0; i < s->nb_channels; i++) {
> +            memset(frame->extended_data[i], 0,
> +            s->samples_per_frame * sizeof(*s->channel[i].out));
> +
> +            memcpy(frame->extended_data[i], s->channel[i].out,
> +                   s->samples_per_frame * sizeof(*s->channel[i].out) >> 1);
> +        }
> +
> +        /* TODO: XMA should output 128 samples only (instead of 512) and
> WMAPRO
> +         * maybe 768 (with 2048), XMA needs changes in multi-stream
> handling though. */
> +
> +        s->eof_done = 1;
> +        s->packet_done = 1;
> +        *got_frame_ptr = 1;
> +        return 0;
> +    }
> +    else if (s->packet_done || s->packet_loss) {
>          s->packet_done = 0;
>
>          /** sanity check for the buffer length */
> @@ -1922,6 +1950,7 @@ static void flush(WMAProDecodeCtx *s)
>                 sizeof(*s->channel[i].out));
>      s->packet_loss = 1;
>      s->skip_packets = 0;
> +    s->eof_done = 0;
>  }
>
>
> @@ -1976,7 +2005,7 @@ AVCodec ff_xma1_decoder = {
>      .init           = xma_decode_init,
>      .close          = xma_decode_end,
>      .decode         = xma_decode_packet,
> -    .capabilities   = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1,
> +    .capabilities   = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1 |
> AV_CODEC_CAP_DELAY,
>      .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
>                                                        AV_SAMPLE_FMT_NONE },
>  };
> @@ -1991,7 +2020,7 @@ AVCodec ff_xma2_decoder = {
>      .close          = xma_decode_end,
>      .decode         = xma_decode_packet,
>      .flush          = xma_flush,
> -    .capabilities   = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1,
> +    .capabilities   = AV_CODEC_CAP_SUBFRAMES | 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
>


You can set final number of samples in output frame directly:
frame->nb_samples = X.
bananaman255@gmail.com Oct. 27, 2018, 9:45 a.m. UTC | #2
> You can set final number of samples in output frame directly:
> frame->nb_samples = X.

I was told I shouldn't do that (even though other codecs do it?). I quote:
>> No, this is wrong. Codecs don't need to do this manually, this is done by
>> libavcodec/decode.c, based on the packet's AV_PKT_DATA_SKIP_SAMPLES side
data.

I think it would also have problems with xma_decode_packet since it only
works with 512 nb_samples.

So I hope this can patch accepted as-is and then it can be refined in later
patches.
diff mbox

Patch

diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c
index 9439bfa771..d0fa974c80 100644
--- a/libavcodec/wmaprodec.c
+++ b/libavcodec/wmaprodec.c
@@ -210,6 +210,7 @@  typedef struct WMAProDecodeCtx {
     int              subframe_offset;               ///< subframe offset in the bit reservoir
     uint8_t          packet_loss;                   ///< set in case of bitstream error
     uint8_t          packet_done;                   ///< set when a packet is fully decoded
+    uint8_t          eof_done;                      ///< set when EOF reached and extra subframe is written (XMA1/2)
 
     /* frame decode state */
     uint32_t         frame_num;                     ///< current frame number (not used for decoding)
@@ -1609,7 +1610,34 @@  static int decode_packet(AVCodecContext *avctx, WMAProDecodeCtx *s,
 
     *got_frame_ptr = 0;
 
-    if (s->packet_done || s->packet_loss) {
+    if (!buf_size) {
+        AVFrame *frame = data;
+        int i;
+
+        /** Must output remaining samples after stream end. WMAPRO 5.1 created
+         * by XWMA encoder don't though (maybe only 1/2ch streams need it). */
+        s->packet_done = 0;
+        if (s->eof_done)
+            return 0;
+
+        /** clean output buffer and copy last IMDCT samples */
+        for (i = 0; i < s->nb_channels; i++) {
+            memset(frame->extended_data[i], 0,
+            s->samples_per_frame * sizeof(*s->channel[i].out));
+
+            memcpy(frame->extended_data[i], s->channel[i].out,
+                   s->samples_per_frame * sizeof(*s->channel[i].out) >> 1);
+        }
+
+        /* TODO: XMA should output 128 samples only (instead of 512) and WMAPRO
+         * maybe 768 (with 2048), XMA needs changes in multi-stream handling though. */
+
+        s->eof_done = 1;
+        s->packet_done = 1;
+        *got_frame_ptr = 1;
+        return 0;
+    }
+    else if (s->packet_done || s->packet_loss) {
         s->packet_done = 0;
 
         /** sanity check for the buffer length */
@@ -1922,6 +1950,7 @@  static void flush(WMAProDecodeCtx *s)
                sizeof(*s->channel[i].out));
     s->packet_loss = 1;
     s->skip_packets = 0;
+    s->eof_done = 0;
 }
 
 
@@ -1976,7 +2005,7 @@  AVCodec ff_xma1_decoder = {
     .init           = xma_decode_init,
     .close          = xma_decode_end,
     .decode         = xma_decode_packet,
-    .capabilities   = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1,
+    .capabilities   = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
     .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
                                                       AV_SAMPLE_FMT_NONE },
 };
@@ -1991,7 +2020,7 @@  AVCodec ff_xma2_decoder = {
     .close          = xma_decode_end,
     .decode         = xma_decode_packet,
     .flush          = xma_flush,
-    .capabilities   = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1,
+    .capabilities   = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
     .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
                                                       AV_SAMPLE_FMT_NONE },
 };