[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]