[PR] avformat/asfenc: honor audio block alignment (PR #24308)

Forgejo_Fairy via ffmpeg-devel <[email protected]>
Newsgroups gmane.comp.video.ffmpeg.devel
Message-ID <[email protected]>
PR #24308 opened by Forgejo_Fairy
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24308
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24308.patch

Fixes #21362.

The ASF muxer's historical 3,200-byte default packet size can split an audio media object at an offset that is not a multiple of the stream's WAVEFORMATEX Block Alignment. Section 9.1.2 of the Advanced Systems Format Specification requires every audio payload size to be a multiple of that value. Windows Media readers reject such output for WMA blocks larger than the available packet payload.

This change:

- uses an automatic packet-size default starting at 3,200 bytes and enlarges it enough to hold at least one audio block;
- rejects explicitly selected packet sizes that cannot hold one complete audio block;
- aligns fragmented audio payload lengths to the codec block size;
- documents the automatic behavior; and
- adds a FATE remux test using the existing `Californication_cover.wma` sample, whose WMA block alignment is 4,459 bytes.

For the issue sample, the automatic size becomes 4,485 bytes: 4,459 bytes of audio plus 26 bytes of ASF single-payload overhead.

Tested with:

- `make fate-asf-remux-audio-block-align SAMPLES=/opt/fate-suite`
- `make fate-microsoft SAMPLES=/opt/fate-suite`
- `make fate-lavf-asf SAMPLES=/opt/fate-suite`
- `make fate-generic-tags-remux-asf SAMPLES=/opt/fate-suite`
- `make fate-wmav1-encode fate-wmav2-encode SAMPLES=/opt/fate-suite`


>From 71d5b9636b7446bf5080e25d61d7d8e790612e9f Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Fri, 28 Aug 2026 16:56:21 +0000
Subject: [PATCH] avformat/asfenc: honor audio block alignment

Choose a default packet size large enough to hold one audio block and align fragmented audio payloads to the codec block size. This avoids producing invalid ASF when a WMA block exceeds the historical 3200-byte packet default.

Assisted-by: Fairy
---
 doc/muxers.texi                            |  5 ++-
 libavformat/asfenc.c                       | 43 +++++++++++++++++++++-
 tests/fate/microsoft.mak                   |  8 +++-
 tests/ref/fate/asf-remux-audio-block-align | 19 ++++++++++
 4 files changed, 70 insertions(+), 5 deletions(-)
 create mode 100644 tests/ref/fate/asf-remux-audio-block-align

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 99584e2b8d..f110797297 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -841,8 +841,9 @@ muxer too.
 @item packet_size @var{size}
 Set the muxer packet size as a number of bytes. By tuning this setting
 you may reduce data fragmentation or muxer overhead depending on your
-source. Default value is @code{3200}, minimum is @code{100}, maximum
-is @code{64Ki}.
+source. By default, the muxer starts with a size of @code{3200} and
+increases it when necessary to fit at least one audio block. The minimum
+explicit value is @code{100}, and the maximum is @code{64Ki}.
 @end table
 
 @section ass
diff --git a/libavformat/asfenc.c b/libavformat/asfenc.c
index 59638e7b22..ba56998c8e 100644
--- a/libavformat/asfenc.c
+++ b/libavformat/asfenc.c
@@ -188,6 +188,7 @@
 
 #define DATA_HEADER_SIZE 50
 
+#define PACKET_SIZE_DEFAULT 3200
 #define PACKET_SIZE_MAX 65536
 #define PACKET_SIZE_MIN 100
 
@@ -738,8 +739,43 @@ fail:
 static int asf_write_header(AVFormatContext *s)
 {
     ASFContext *asf = s->priv_data;
+    int packet_size = asf->packet_size;
+    const int auto_packet_size = !packet_size;
     int ret;
 
+    if (auto_packet_size) {
+        packet_size = PACKET_SIZE_DEFAULT;
+    } else if (packet_size < PACKET_SIZE_MIN) {
+        av_log(s, AV_LOG_ERROR,
+               "Packet size %d is smaller than the minimum %d\n",
+               packet_size, PACKET_SIZE_MIN);
+        return AVERROR(EINVAL);
+    }
+
+    for (unsigned i = 0; i < s->nb_streams; i++) {
+        const AVCodecParameters *par = s->streams[i]->codecpar;
+
+        if (par->codec_type == AVMEDIA_TYPE_AUDIO && par->block_align) {
+            const int min_packet_size = par->block_align + SINGLE_PAYLOAD_HEADERS;
+
+            if (min_packet_size > PACKET_SIZE_MAX) {
+                av_log(s, AV_LOG_ERROR,
+                       "Block alignment %d is too large for an ASF packet\n",
+                       par->block_align);
+                return AVERROR(EINVAL);
+            }
+            if (auto_packet_size) {
+                packet_size = FFMAX(packet_size, min_packet_size);
+            } else if (packet_size < min_packet_size) {
+                av_log(s, AV_LOG_ERROR,
+                       "Packet size %d is too small for block alignment %d\n",
+                       packet_size, par->block_align);
+                return AVERROR(EINVAL);
+            }
+        }
+    }
+
+    asf->packet_size = packet_size;
     s->packet_size  = asf->packet_size;
     s->max_interleave_delta = 0;
     asf->nb_packets = 0;
@@ -929,6 +965,11 @@ static void put_frame(AVFormatContext *s, ASFStream *stream, AVStream *avst,
             }
         }
         if (frag_len1 > 0) {
+            if (payload_len > frag_len1 &&
+                avst->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
+                avst->codecpar->block_align)
+                frag_len1 -= frag_len1 % avst->codecpar->block_align;
+
             if (payload_len > frag_len1)
                 payload_len = frag_len1;
             else if (payload_len == (frag_len1 - 1))
@@ -1106,7 +1147,7 @@ static void asf_deinit(AVFormatContext *s)
 }
 
 static const AVOption asf_options[] = {
-    { "packet_size", "Packet size", offsetof(ASFContext, packet_size), AV_OPT_TYPE_INT, {.i64 = 3200}, PACKET_SIZE_MIN, PACKET_SIZE_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+    { "packet_size", "Packet size", offsetof(ASFContext, packet_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, PACKET_SIZE_MAX, AV_OPT_FLAG_ENCODING_PARAM },
     { NULL },
 };
 
diff --git a/tests/fate/microsoft.mak b/tests/fate/microsoft.mak
index 8d8e92575a..c4d2927e95 100644
--- a/tests/fate/microsoft.mak
+++ b/tests/fate/microsoft.mak
@@ -80,10 +80,14 @@ fate-vc1-ism: CMD = framecrc -i $(TARGET_SAMPLES)/isom/vc1-wmapro.ism -an
 FATE_MICROSOFT += $(FATE_VC1-yes)
 fate-vc1: $(FATE_VC1-yes)
 
+FATE_ASF_REMUX-$(call REMUX, ASF) += fate-asf-remux-audio-block-align
+fate-asf-remux-audio-block-align: CMD = transcode asf $(TARGET_SAMPLES)/cover_art/Californication_cover.wma asf "-map 0:a -c copy -map_metadata -1 -frames:a 8" "-map 0:a -c copy" "-of compact -select_streams a -show_packets -show_entries packet=pts,size,pos -read_intervals %+\#3"
+
 FATE_MICROSOFT-$(call ALLYES, PIPE_PROTOCOL ASF_DEMUXER FRAMECRC_MUXER) += fate-asf-repldata
 fate-asf-repldata: CMD = framecrc -i $(TARGET_SAMPLES)/asf/bug821-2.asf -c copy
 
 FATE_MICROSOFT += $(FATE_MICROSOFT-yes)
 
-FATE_SAMPLES_FFMPEG += $(FATE_MICROSOFT)
-fate-microsoft: $(FATE_MICROSOFT)
+FATE_SAMPLES_FFMPEG         += $(FATE_MICROSOFT)
+FATE_SAMPLES_FFMPEG_FFPROBE += $(FATE_ASF_REMUX-yes)
+fate-microsoft: $(FATE_MICROSOFT) $(FATE_ASF_REMUX-yes)
diff --git a/tests/ref/fate/asf-remux-audio-block-align b/tests/ref/fate/asf-remux-audio-block-align
new file mode 100644
index 0000000000..1fa6db4a49
--- /dev/null
+++ b/tests/ref/fate/asf-remux-audio-block-align
@@ -0,0 +1,19 @@
+88407d736bfe38ea866d2a867a7869a5 *tests/data/fate/asf-remux-audio-block-align.asf
+36324 tests/data/fate/asf-remux-audio-block-align.asf
+#extradata 0:       10, 0x08a50189
+#tb 0: 1/1000
+#media_type 0: audio
+#codec_id 0: wmav2
+#sample_rate 0: 44100
+#channel_layout_name 0: stereo
+0,          0,          0,      371,     4459, 0x8e6ba76d
+0,        324,        324,      371,     4459, 0x893de414
+0,        696,        696,      371,     4459, 0x69a173aa
+0,        928,        928,      371,     4459, 0xcc9baf3f
+0,       1206,       1206,      371,     4459, 0xc890aa7d
+0,       1439,       1439,      371,     4459, 0x4db6ac94
+0,       1763,       1763,      371,     4459, 0x7d2f71bb
+0,       2043,       2043,      371,     4459, 0xb0be449f
+packet|pts=0|size=4459|pos=444
+packet|pts=324|size=4459|pos=4929
+packet|pts=696|size=4459|pos=9414
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.