From fb2ee6c08f9c083506fa919ea5b7f0d6b9c13602 Mon Sep 17 00:00:00 2001 From: Michael Giacomelli Date: Mon, 5 Oct 2026 20:24:39 -0400 Subject: [PATCH] wma: decode every codec packet in an ASF payload A payload normally holds one codec packet of blockalign bytes, but some files put several in each. Only the first was decoded, so such a file played one packet in every 8 or 15, as a few seconds of broken sound, and then ended. Step through the payload in blockalign sized packets. Checked with perfsim (Sansa e200v1 build) against ffmpeg's decode: doors-test.wma (WMA v2, 11 kHz mono), 15 packets a payload: 80896 of 1205760 samples before, all of them after, 86 dB SNR test.wma (WMA v1, 44.1 kHz stereo), 8 packets a payload: 1294336 of 10346496 samples before, all after, 114 dB SNR The output of 26 other WMA files is byte-identical before and after. Co-Authored-By: Claude Opus 5.5 --- lib/rbcodec/codecs/wma.c | 49 +++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/lib/rbcodec/codecs/wma.c b/lib/rbcodec/codecs/wma.c index 92022f8b90..a8b09ced6b 100644 --- a/lib/rbcodec/codecs/wma.c +++ b/lib/rbcodec/codecs/wma.c @@ -178,29 +178,42 @@ new_packet: goto new_packet; } } else if (res > 0) { - wma_decode_superframe_init(&wmadec, audiobuf, audiobufsize); + /* A payload usually holds one codec packet (a superframe) of + * blockalign bytes, but it can hold several. */ + int packetsize = audiobufsize; + int offset; - for (i=0; i < wmadec.nb_frames; i++) + if (wfx.blockalign > 0 && audiobufsize % wfx.blockalign == 0) + packetsize = wfx.blockalign; + + for (offset = 0; offset < audiobufsize; offset += packetsize) { - wmares = wma_decode_superframe_frame(&wmadec, - audiobuf, audiobufsize); + const uint8_t *packet = audiobuf + offset; - ci->yield (); + wma_decode_superframe_init(&wmadec, packet, packetsize); - if (wmares < 0) { - /* Do the above, but for errors in decode. */ - errcount++; - DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount); - if (errcount > 5) { - return CODEC_ERROR; - } else { - ci->advance_buffer(packetlength); - goto new_packet; + for (i=0; i < wmadec.nb_frames; i++) + { + wmares = wma_decode_superframe_frame(&wmadec, + packet, packetsize); + + ci->yield (); + + if (wmares < 0) { + /* Do the above, but for errors in decode. */ + errcount++; + DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount); + if (errcount > 5) { + return CODEC_ERROR; + } else { + ci->advance_buffer(packetlength); + goto new_packet; + } + } else if (wmares > 0) { + ci->pcmbuf_insert((*wmadec.frame_out)[0], (*wmadec.frame_out)[1], wmares); + elapsedtime += (wmares*10)/(wfx.rate/100); + ci->set_elapsed(elapsedtime); } - } else if (wmares > 0) { - ci->pcmbuf_insert((*wmadec.frame_out)[0], (*wmadec.frame_out)[1], wmares); - elapsedtime += (wmares*10)/(wfx.rate/100); - ci->set_elapsed(elapsedtime); } } }