From 786c0fe7bfa8fa18c8c5efddd962329d445fbd58 Mon Sep 17 00:00:00 2001
From: UniqProject <3046095+UniqProject@users.noreply.github.com>
Date: Sun, 22 Jan 2023 02:22:48 +0100
Subject: [PATCH] Add support for AAC audio streams
implements #25
---
BDInfo/BDInfo.csproj | 1 +
BDInfo/BDROM/TSCodecAAC.cs | 121 +++++++++++++++++++++++++++++++
BDInfo/BDROM/TSPlaylistFile.cs | 14 +++-
BDInfo/BDROM/TSStream.cs | 14 ++++
BDInfo/BDROM/TSStreamClipFile.cs | 4 +-
BDInfo/BDROM/TSStreamFile.cs | 8 ++
6 files changed, 157 insertions(+), 5 deletions(-)
create mode 100644 BDInfo/BDROM/TSCodecAAC.cs
diff --git a/BDInfo/BDInfo.csproj b/BDInfo/BDInfo.csproj
index 2686c62661..8e5c96f0e4 100644
--- a/BDInfo/BDInfo.csproj
+++ b/BDInfo/BDInfo.csproj
@@ -76,6 +76,7 @@
+
diff --git a/BDInfo/BDROM/TSCodecAAC.cs b/BDInfo/BDROM/TSCodecAAC.cs
new file mode 100644
index 0000000000..5d6581c84c
--- /dev/null
+++ b/BDInfo/BDROM/TSCodecAAC.cs
@@ -0,0 +1,121 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+#undef DEBUG
+
+namespace BDInfo
+{
+ public abstract class TSCodecAAC
+ {
+ private static readonly string[] AACID =
+ {
+ "MPEG-4",
+ "MPEG-2",
+ };
+
+ private static string GetAACProfile(int profileType)
+ {
+ switch (profileType)
+ {
+ case 0: return "AAC Main";
+ case 1: return "AAC LC";
+ case 2: return "AAC SSR";
+ case 3: return "AAC LTP";
+ case 16: return "ER AAC LC";
+ case 18: return "ER AAC LTP";
+ case 36: return "SLS";
+ default: return "";
+ }
+ }
+
+ public static int[] AACSampleRates =
+ {
+ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+ 16000, 12000, 11025, 8000, 7350, 0, 0, 57600,
+ 51200, 40000, 38400, 34150, 28800, 25600, 20000, 19200,
+ 17075, 14400, 12800, 9600, 0, 0, 0
+ };
+
+ private const int AACChannelsSize = 8;
+
+ public static int[] AACChannels = { 0, 1, 2, 3, 4, 5, 6, 8 };
+
+ private static readonly byte[] AACChannelModes =
+ {
+ (byte)TSAudioMode.Unknown,
+ (byte)TSAudioMode.Mono,
+ (byte)TSAudioMode.Stereo,
+ (byte)TSAudioMode.Extended,
+ (byte)TSAudioMode.Surround,
+ (byte)TSAudioMode.Surround,
+ (byte)TSAudioMode.Surround,
+ (byte)TSAudioMode.Surround,
+ };
+
+ public static void Scan(TSAudioStream stream, TSStreamBuffer buffer, ref string tag)
+ {
+ if (stream.IsInitialized) return;
+
+ int syncWord = buffer.ReadBits2(12);
+ if (syncWord != 0b1111_1111_1111) return;
+
+ // fixed header
+ int audioVersionID = buffer.ReadBits2(1);
+ int layerIndex = buffer.ReadBits2(2);
+ bool protectionAbsent = buffer.ReadBool();
+ int profileObjectType = buffer.ReadBits2(2);
+ int samplingRateIndex = buffer.ReadBits2(4);
+ bool privateBit = buffer.ReadBool();
+ int channelMode = buffer.ReadBits2(3);
+ bool originalBit = buffer.ReadBool();
+ bool home = buffer.ReadBool();
+
+
+ if (samplingRateIndex <= 13)
+ stream.SampleRate = AACSampleRates[samplingRateIndex];
+ else
+ stream.SampleRate = 0;
+
+
+ if (channelMode <= AACChannelsSize)
+ {
+ stream.AudioMode = (TSAudioMode)AACChannelModes[channelMode];
+ stream.ChannelCount = AACChannels[channelMode];
+ }
+ else
+ {
+ stream.ChannelCount = 0;
+ stream.AudioMode = TSAudioMode.Unknown;
+ }
+
+ if (channelMode >=7 && channelMode <= 8)
+ {
+ stream.ChannelCount--;
+ stream.LFE = 1;
+ }
+ else
+ stream.LFE = 0;
+
+ stream.ExtendedData = $"{AACID[audioVersionID]} {GetAACProfile(profileObjectType)}";
+
+ stream.IsVBR = true;
+ stream.IsInitialized = true;
+ }
+ }
+}
diff --git a/BDInfo/BDROM/TSPlaylistFile.cs b/BDInfo/BDROM/TSPlaylistFile.cs
index 5ea87b8c90..b0d1c70089 100644
--- a/BDInfo/BDROM/TSPlaylistFile.cs
+++ b/BDInfo/BDROM/TSPlaylistFile.cs
@@ -694,6 +694,8 @@ protected TSStream CreatePlaylistStream(byte[] data, ref int pos)
case TSStreamType.LPCM_AUDIO:
case TSStreamType.MPEG1_AUDIO:
case TSStreamType.MPEG2_AUDIO:
+ case TSStreamType.MPEG2_AAC_AUDIO:
+ case TSStreamType.MPEG4_AAC_AUDIO:
int audioFormat = ReadByte(data, ref pos);
@@ -1313,14 +1315,18 @@ private static int GetStreamTypeSortIndex(TSStreamType streamType)
return 6;
case TSStreamType.AC3_PLUS_AUDIO:
return 7;
- case TSStreamType.DTS_HD_AUDIO:
+ case TSStreamType.MPEG2_AAC_AUDIO:
return 8;
- case TSStreamType.AC3_TRUE_HD_AUDIO:
+ case TSStreamType.MPEG4_AAC_AUDIO:
return 9;
- case TSStreamType.DTS_HD_MASTER_AUDIO:
+ case TSStreamType.DTS_HD_AUDIO:
return 10;
- case TSStreamType.LPCM_AUDIO:
+ case TSStreamType.AC3_TRUE_HD_AUDIO:
return 11;
+ case TSStreamType.DTS_HD_MASTER_AUDIO:
+ return 12;
+ case TSStreamType.LPCM_AUDIO:
+ return 13;
case TSStreamType.SUBTITLE:
return 1;
diff --git a/BDInfo/BDROM/TSStream.cs b/BDInfo/BDROM/TSStream.cs
index a8d8d88262..4ee6696cd7 100644
--- a/BDInfo/BDROM/TSStream.cs
+++ b/BDInfo/BDROM/TSStream.cs
@@ -34,6 +34,8 @@ public enum TSStreamType : byte
VC1_VIDEO = 0xea,
MPEG1_AUDIO = 0x03,
MPEG2_AUDIO = 0x04,
+ MPEG2_AAC_AUDIO = 0x0F,
+ MPEG4_AAC_AUDIO = 0x11,
LPCM_AUDIO = 0x80,
AC3_AUDIO = 0x81,
AC3_PLUS_AUDIO = 0x84,
@@ -191,6 +193,8 @@ public bool IsAudioStream
{
case TSStreamType.MPEG1_AUDIO:
case TSStreamType.MPEG2_AUDIO:
+ case TSStreamType.MPEG2_AAC_AUDIO:
+ case TSStreamType.MPEG4_AAC_AUDIO:
case TSStreamType.LPCM_AUDIO:
case TSStreamType.AC3_AUDIO:
case TSStreamType.AC3_PLUS_AUDIO:
@@ -259,6 +263,8 @@ public string CodecName
return "VC-1 Video";
case TSStreamType.MPEG1_AUDIO:
case TSStreamType.MPEG2_AUDIO:
+ case TSStreamType.MPEG2_AAC_AUDIO:
+ case TSStreamType.MPEG4_AAC_AUDIO:
return (string)((TSAudioStream)this).ExtendedData;
case TSStreamType.LPCM_AUDIO:
return "LPCM Audio";
@@ -330,6 +336,10 @@ public string CodecAltName
return "MP1";
case TSStreamType.MPEG2_AUDIO:
return "MP2";
+ case TSStreamType.MPEG2_AAC_AUDIO:
+ return "MPEG-2 AAC";
+ case TSStreamType.MPEG4_AAC_AUDIO:
+ return "MPEG-4 AAC";
case TSStreamType.LPCM_AUDIO:
return "LPCM";
case TSStreamType.AC3_AUDIO:
@@ -390,6 +400,10 @@ public string CodecShortName
return "MP1";
case TSStreamType.MPEG2_AUDIO:
return "MP2";
+ case TSStreamType.MPEG2_AAC_AUDIO:
+ return "MPEG-2 AAC";
+ case TSStreamType.MPEG4_AAC_AUDIO:
+ return "MPEG-4 AAC";
case TSStreamType.LPCM_AUDIO:
return "LPCM";
case TSStreamType.AC3_AUDIO:
diff --git a/BDInfo/BDROM/TSStreamClipFile.cs b/BDInfo/BDROM/TSStreamClipFile.cs
index b4f13c4f34..f26c587e2f 100644
--- a/BDInfo/BDROM/TSStreamClipFile.cs
+++ b/BDInfo/BDROM/TSStreamClipFile.cs
@@ -186,7 +186,9 @@ public void Scan()
case TSStreamType.LPCM_AUDIO:
case TSStreamType.MPEG1_AUDIO:
case TSStreamType.MPEG2_AUDIO:
- {
+ case TSStreamType.MPEG2_AAC_AUDIO:
+ case TSStreamType.MPEG4_AAC_AUDIO:
+ {
byte[] languageBytes = new byte[3];
Array.Copy(clipData, streamOffset + 3,
languageBytes, 0, languageBytes.Length);
diff --git a/BDInfo/BDROM/TSStreamFile.cs b/BDInfo/BDROM/TSStreamFile.cs
index 144e60122f..cec120ed55 100644
--- a/BDInfo/BDROM/TSStreamFile.cs
+++ b/BDInfo/BDROM/TSStreamFile.cs
@@ -275,6 +275,12 @@ private bool ScanStream(
(TSAudioStream)stream, buffer, ref streamState.StreamTag);
break;
+ case TSStreamType.MPEG2_AAC_AUDIO:
+ case TSStreamType.MPEG4_AAC_AUDIO:
+ TSCodecAAC.Scan(
+ (TSAudioStream)stream, buffer, ref streamState.StreamTag);
+ break;
+
case TSStreamType.AC3_AUDIO:
TSCodecAC3.Scan(
(TSAudioStream)stream, buffer, ref streamState.StreamTag);
@@ -1562,6 +1568,8 @@ private TSStream CreateStream(
case TSStreamType.LPCM_AUDIO:
case TSStreamType.MPEG1_AUDIO:
case TSStreamType.MPEG2_AUDIO:
+ case TSStreamType.MPEG2_AAC_AUDIO:
+ case TSStreamType.MPEG4_AAC_AUDIO:
{
stream = new TSAudioStream();
}