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 <noreply@anthropic.com>
This commit is contained in:
Michael Giacomelli 2026-10-05 20:24:39 -04:00
parent 6ffbee954b
commit fb2ee6c08f

View file

@ -178,29 +178,42 @@ new_packet:
goto new_packet; goto new_packet;
} }
} else if (res > 0) { } 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, const uint8_t *packet = audiobuf + offset;
audiobuf, audiobufsize);
ci->yield (); wma_decode_superframe_init(&wmadec, packet, packetsize);
if (wmares < 0) { for (i=0; i < wmadec.nb_frames; i++)
/* Do the above, but for errors in decode. */ {
errcount++; wmares = wma_decode_superframe_frame(&wmadec,
DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount); packet, packetsize);
if (errcount > 5) {
return CODEC_ERROR; ci->yield ();
} else {
ci->advance_buffer(packetlength); if (wmares < 0) {
goto new_packet; /* 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);
} }
} }
} }