[PR] libavformat/mpeg.c: Fix AAC audio misidentification as MP2 in MPEG-PS VOB files (PR #23878)
zhangtingan via ffmpeg-devel <[email protected]> Thu, 23 Jul 2026 06:01:11 -0000
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <178478647193.59.8758727605473192954@29965ddac10e> |
PR #23878 opened by zhangtingan
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23878
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23878.patch
## Problem
Certain VOB files use stream_id 0xC0 for AAC audio in an MPEG-PS
container, with the Program Stream Map (PSM) appearing after the
first audio PES packet. FFmpeg's MPEG-PS demuxer misidentifies the
audio as MP2 in this case.
## Root Cause
Two-fold:
1. When audio PES packets arrive before the PSM, the stream is
created with codec_id=MP2 (the default for stream_id 0xC0-0xDF).
When the PSM is later parsed, mpegps_psm_parse() updates the
psm_es_type[] array but does not retroactively update the
already-created stream's codec_id.
2. Audio streams (0xC0-0xDF) are created with request_probe=0,
unlike video streams which get request_probe=1. This means
there is no fallback auto-detection to correct the misidentified
codec when the PSM is absent or late.
## Fix
- Patch 1: Add a loop after mpegps_psm_parse() to update codec_id
of existing streams based on PSM data.
- Patch 2: Set request_probe=25 for the general audio case, enabling
auto-detection as a fallback.
## Reproduction
Demo file: `demo-aac.vob` (19KB, attached) — audio-only MPEG-PS
with PSM arriving after the first audio PES packet.
$ ffprobe demo-aac.vob
Before:
Stream #0:0: Audio: mp2, 0 channels, s16p
(with "[mp2] Header missing" warnings)
After:
Stream #0:0: Audio: aac, LC, 48000 Hz, mono, fltp
Both patches tested against current master, compile cleanly with
minimal configuration (--disable-everything --enable-demuxer=mpegps
--enable-decoder=aac --enable-decoder=h264 --enable-parser=aac
--enable-parser=h264 --enable-protocol=file).
From bd75721a70b3ffbd3e9ffd6e6a0d3397152493d8 Mon Sep 17 00:00:00 2001
From: ZhangTingan <[email protected]>
Date: Wed, 22 Jul 2026 13:47:24 +0800
Subject: [PATCH 1/2] avformat/mpeg: update stream codec_id when PSM arrives
after stream creation
When audio/video PES packets are encountered before the Program Stream Map
(PSM), streams are created with default codec_id values (e.g., MP2 for
audio stream_id 0xC0-0xDF). The PSM parse path only updates the
psm_es_type[] array but does not retroactively update already-created
streams, causing AAC audio to be misidentified as MP2.
Add a loop after mpegps_psm_parse() to update codec_id of existing
streams based on the newly-parsed PSM data.
Signed-off-by: ZhangTingan <[email protected]>
---
libavformat/mpeg.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c
index 29abe329b9..a457800185 100644
--- a/libavformat/mpeg.c
+++ b/libavformat/mpeg.c
@@ -346,6 +346,42 @@ redo:
}
if (startcode == PROGRAM_STREAM_MAP) {
mpegps_psm_parse(m, s->pb);
+ /* Update codec_id of streams created before the PSM was parsed.
+ * When audio/video PES packets arrive before the PSM, streams are
+ * created with default codec_id values (e.g., MP2 for audio
+ * stream_id 0xC0-0xDF). Retroactively update them based on the
+ * stream types declared in the PSM. */
+ for (int i = 0; i < s->nb_streams; i++) {
+ AVStream *st2 = s->streams[i];
+ unsigned char es_type = m->psm_es_type[st2->id & 0xff];
+ if (es_type == 0)
+ continue;
+
+ if (es_type == STREAM_TYPE_AUDIO_AAC &&
+ st2->codecpar->codec_id == AV_CODEC_ID_MP2) {
+ st2->codecpar->codec_id = AV_CODEC_ID_AAC;
+ } else if (es_type == STREAM_TYPE_VIDEO_H264 &&
+ st2->codecpar->codec_id != AV_CODEC_ID_H264) {
+ st2->codecpar->codec_id = AV_CODEC_ID_H264;
+ st2->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+ } else if (es_type == STREAM_TYPE_VIDEO_HEVC &&
+ st2->codecpar->codec_id != AV_CODEC_ID_HEVC) {
+ st2->codecpar->codec_id = AV_CODEC_ID_HEVC;
+ st2->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+ } else if (es_type == STREAM_TYPE_VIDEO_VVC &&
+ st2->codecpar->codec_id != AV_CODEC_ID_VVC) {
+ st2->codecpar->codec_id = AV_CODEC_ID_VVC;
+ st2->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+ } else if (es_type == STREAM_TYPE_VIDEO_MPEG4 &&
+ st2->codecpar->codec_id != AV_CODEC_ID_MPEG4) {
+ st2->codecpar->codec_id = AV_CODEC_ID_MPEG4;
+ st2->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+ } else if ((es_type == STREAM_TYPE_AUDIO_MPEG1 ||
+ es_type == STREAM_TYPE_AUDIO_MPEG2) &&
+ st2->codecpar->codec_id == AV_CODEC_ID_MP2) {
+ st2->codecpar->codec_id = AV_CODEC_ID_MP3;
+ }
+ }
goto redo;
}
--
2.52.0
From 513152c567f30cb38e9aa784aebd7820beddf127 Mon Sep 17 00:00:00 2001
From: ZhangTingan <[email protected]>
Date: Wed, 22 Jul 2026 13:48:30 +0800
Subject: [PATCH 2/2] avformat/mpeg: enable probing for audio streams with
default MP2 codec_id
Audio streams (stream_id 0xC0-0xDF) are created with codec_id=MP2 and
request_probe=0 by default, unlike video streams which get
request_probe=1. This means that when the PSM is absent or arrives
after the first audio PES packet, there is no fallback mechanism to
auto-detect the actual audio codec.
Set request_probe=25 for the general audio case to allow auto-detection
(e.g., distinguishing AAC ADTS from MP2) as a fallback when PSM data is
not available.
Signed-off-by: ZhangTingan <[email protected]>
---
libavformat/mpeg.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c
index a457800185..020c3079f4 100644
--- a/libavformat/mpeg.c
+++ b/libavformat/mpeg.c
@@ -625,6 +625,10 @@ redo:
request_probe = 50;
} else {
codec_id = AV_CODEC_ID_MP2;
+ /* Enable probing for audio streams to auto-detect the
+ * actual codec (e.g., AAC ADTS) when the PSM is absent
+ * or arrives after the first audio PES packet. */
+ request_probe = 25;
if (m->imkh_cctv)
request_probe = 25;
}
--
2.52.0
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]