[FFmpeg-devel] [PATCH] avcodec/wmaprodec: skip foreign XMA packets

Joel Linn jl at conductive.de
Tue Aug 31 23:45:47 EEST 2021


Support decoding only a selection of the encoded XMA streams.
Previously, the decoder assumed it was decoding all available streams.
---
 libavcodec/wmaprodec.c | 64 ++++++++++++++++++++++++------------------
 1 file changed, 37 insertions(+), 27 deletions(-)

diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c
index 66271c4037..95e039c14e 100644
--- a/libavcodec/wmaprodec.c
+++ b/libavcodec/wmaprodec.c
@@ -1814,7 +1814,43 @@ static int xma_decode_packet(AVCodecContext *avctx, void *data,
     XMADecodeCtx *s = avctx->priv_data;
     int got_stream_frame_ptr = 0;
     AVFrame *frame = data;
-    int i, ret, offset = INT_MAX;
+    int i, ret, offset, skip_current_packet = INT_MAX;
+
+    /* find the owner stream of the new XMA packet that belongs to on of our streams
+     * XMA streams find their packets following packet_skips
+     * there may be other packets in between if we are not responsible for all streams
+     * (at start there is one packet per stream, then interleave non-linearly). */
+    if (s->xma[s->current_stream].packet_done ||
+        s->xma[s->current_stream].packet_loss) {
+        /* select stream with lowest skip_packets (= uses next packet) */
+        if (s->xma[s->current_stream].skip_packets != 0) {
+            int min[2];
+
+            min[0] = s->xma[0].skip_packets;
+            min[1] = i = 0;
+
+            for (i = 1; i < s->num_streams; i++) {
+                if (s->xma[i].skip_packets < min[0]) {
+                    min[0] = s->xma[i].skip_packets;
+                    min[1] = i;
+                }
+            }
+
+            s->current_stream = min[1];
+        }
+
+        skip_current_packet = !!s->xma[s->current_stream].skip_packets;
+
+        /* advance all stream packet skip counts */
+        for (i = 0; i < s->num_streams; i++) {
+            s->xma[i].skip_packets = FFMAX(0, s->xma[i].skip_packets - 1);
+        }
+
+        /* if we are not responsible for every stream, make sure we ignore
+         * XMA packets not belonging to one of our streams */
+        if (skip_current_packet)
+            return avctx->block_align;
+    }
 
     if (!s->frames[s->current_stream]->data[0]) {
         s->frames[s->current_stream]->nb_samples = 512;
@@ -1846,34 +1882,8 @@ static int xma_decode_packet(AVCodecContext *avctx, void *data,
         return ret;
     }
 
-    /* find next XMA packet's owner stream, and update.
-     * XMA streams find their packets following packet_skips
-     * (at start there is one packet per stream, then interleave non-linearly). */
     if (s->xma[s->current_stream].packet_done ||
         s->xma[s->current_stream].packet_loss) {
-
-        /* select stream with 0 skip_packets (= uses next packet) */
-        if (s->xma[s->current_stream].skip_packets != 0) {
-            int min[2];
-
-            min[0] = s->xma[0].skip_packets;
-            min[1] = i = 0;
-
-            for (i = 1; i < s->num_streams; i++) {
-                if (s->xma[i].skip_packets < min[0]) {
-                    min[0] = s->xma[i].skip_packets;
-                    min[1] = i;
-                }
-            }
-
-            s->current_stream = min[1];
-        }
-
-        /* all other streams skip next packet */
-        for (i = 0; i < s->num_streams; i++) {
-            s->xma[i].skip_packets = FFMAX(0, s->xma[i].skip_packets - 1);
-        }
-
         /* copy samples from buffer to output if possible */
         for (i = 0; i < s->num_streams; i++) {
             offset = FFMIN(offset, s->offset[i]);
-- 
2.30.2



More information about the ffmpeg-devel mailing list