diff --git a/patterns/adts.hexpat b/patterns/adts.hexpat new file mode 100644 index 0000000..3d0da81 --- /dev/null +++ b/patterns/adts.hexpat @@ -0,0 +1,198 @@ +#pragma authors: zhoubo +#pragma version: 0.4 +#pragma description: Parse AAC's ADTS(Audio Data Transport Stream) audio files. +#pragma category: Audio +#pragma filemask: *.aac +#pragma IDBytes: FF F //ADTS Syncword +#pragma history: +#pragma 0.4 2024-02-12 zhoubo: Porting from 010 Editor Templates. +#pragma 0.3 2024-02-09 zhoubo: use BitfieldDisablePadding(Unpadded Bitfields) for odd header bytes(7,9 bytes) color, and remove FSeek. +#pragma 0.2 2024-02-05 zhoubo: fix some comment & color. +#pragma 0.1 2022-06-13 zhoubo: Init release. only ADTS, not support ADIF,LATM. + +// More information available at: +// 1. https://wiki.multimedia.cx/index.php?title=ADTS +// 2. https://en.wikipedia.org/wiki/Advanced_Audio_Coding +// 3. https://en.wikipedia.org/wiki/AAC +// 4. https://juejin.cn/post/7032170229732442148 + +#pragma endian big + +#include +#include + +fn GetMPEGVersionComment(auto MPEG_Version) +{ + str comment = ""; + match (MPEG_Version) + { + (0): comment = "MPEG-4"; + (1): comment = "MPEG-2"; + } + return comment; +}; + +fn GetProtectionAbsentComment(auto Protection_absence) +{ + str comment = ""; + match (Protection_absence) + { + (0): comment = "ADTS has 9 bytes with CRC"; + (1): comment = "ADTS has 7 bytes without CRC"; + } + return comment; +}; + +fn GetProfileComment(auto Profile) +{ + str comment = ""; + match (Profile) + { + (0x00): comment = "AAC Main"; + (0x01): comment = "AAC LC (Low Complexity)"; + (0x10): comment = "AAC SSR (Scalable Sample Rate)"; + (0x11): comment = "AAC LTP (Long Term Prediction)"; + } + return comment; +}; + +fn GetSamplingFrequencyIndexComment(auto Sampling_frequency_index) +{ + str comment = ""; + match (Sampling_frequency_index) + { + (0x0): comment = "96000Hz"; + (0x1): comment = "88200Hz"; + (0x2): comment = "64000Hz"; + (0x3): comment = "48000Hz"; + (0x4): comment = "44100Hz"; + (0x5): comment = "32000Hz"; + (0x6): comment = "24000Hz"; + (0x7): comment = "22050Hz"; + (0x8): comment = "16000Hz"; + (0x9): comment = "12000Hz"; + (0xa): comment = "11025Hz"; + (0xb): comment = "8000Hz"; + (0xc): comment = "7350Hz"; + (0xd): comment = "Reserved"; + (0xe): comment = "Reserved"; + (0xf): comment = "FORBIDDEN (malformed)"; + } + return comment; +}; + +fn GetChannelConfigurationComment(auto Channel_configuration) +{ + str comment = ""; + match (Channel_configuration) + { + (0): comment = "Defined in AOT Specifc Config"; + (1): comment = "1 channel: front-center"; + (2): comment = "2 channels: front-left, front-right"; + (3): comment = "3 channels: front-center, front-left, front-right"; + (4): comment = "4 channels: front-center, front-left, front-right, back-center"; + (5): comment = "5 channels: front-center, front-left, front-right, back-left, back-right"; + (6): comment = "6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel"; + (7): comment = "8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel"; + } + return comment; +}; + +fn GetBufferFullnessComment(auto ADTS_buffer_fullness) +{ + str comment = ""; + match (ADTS_buffer_fullness) + { + (0x7FF): comment = "VBR (most software ignore this field)"; + (_): comment = "rate..?? (most software ignore this field)"; + } + return comment; +}; + +fn GetRawDataBlockComment(auto Number_of_AAC_frames_minus_1) +{ + str comment = ""; + match (Number_of_AAC_frames_minus_1) + { + (0x0): comment = "has 1 AAC data block"; + (_): comment = "data block number + 1"; + } + return comment; +}; + + +//----------------------------------- +// Define structures used in AAC files +// +// [1.adts_fixed_header information] +// Syncword: 12bits, sync header, always 0xFFF。 +// MPEG_Version: 1bit, 0 means MPGE-4, 1 means MPGE-2 +// Layer: 2bits, alwayas ”00” +// Protection_absence: 1bit, 0 means ADTS Header 9 bytes; 1 means ADTS Header 7 bytes +// Profile: 2bit, AAC level : Main,LC,SSR,LTP +// Sampling_frequency_index: 4bits, Sampling Frequencies +// Private_bit: 1bit +// Channel_configuration: 3bits, channel number... +// Originality: 1bit +// Home: 1bit +// +// [2.adts_variable_header information] +// Copyright_id_bit: 1bit +// Copyright_id_start: 1bit +// AAC_frame_length: 13bits, AAC frame length : ADTS Header(7 or 9 bytes) + sizeof(AAC Frame) +// ADTS_buffer_fullness: 11bits, 0x7FF means VBR +// Number_of_AAC_frames_minus_1: 2bits, ADTS Frame numbers : Number_of_AAC_frames_minus_1 + 1 +// +// [3.CRC information] +// CRC16: 16bits, when Protection_absence=0 + +bitfield ADTS_HEADER +{ + // ADTS_FIXED_HEADER + Syncword : 12 [[color("00FF00"), comment("always 0xFFF")]]; + MPEG_Version : 1 [[color("00FF00"), comment(GetMPEGVersionComment(this))]]; + Layer : 2 [[color("00FF00"), comment("always 0")]]; + Protection_absence : 1 [[color("00FF00"), comment(GetProtectionAbsentComment(this))]]; + + Profile : 2 [[color("0000FF"), comment(GetProfileComment(this))]]; + Sampling_frequency_index : 4 [[color("0000FF"), comment(GetSamplingFrequencyIndexComment(this))]]; + Private_bit : 1 [[color("0000FF")]]; + Channel_configuration : 3 [[color("0000FF"), comment(GetChannelConfigurationComment(this))]]; + Originality : 1 [[color("0000FF")]]; + Home : 1 [[color("0000FF")]]; + + // ADTS_VARIABLE_HEADER + Copyright_id_bit : 1 [[color("0000FF")]]; + Copyright_id_start : 1 [[color("0000FF")]]; + AAC_frame_length : 13 [[color("0000FF")]]; + ADTS_buffer_fullness : 11 [[color("0000FF"), comment(GetBufferFullnessComment(this))]]; + Number_of_AAC_frames_minus_1 : 2 [[color("0000FF"), comment(GetRawDataBlockComment(this))]]; + + // ADTS_CRC_HEADER + if (0 == Protection_absence) // Header with CRC + { + u16 CRC16 [[color("FFFF00")]]; + } + else // Header without CRC + { + } +}; + + +struct ADTS_FRAME +{ + ADTS_HEADER Header; + + if (0 == Header.Protection_absence) // Header with CRC 2 bytes + { + u8 Data[Header.AAC_frame_length - 9] [[color("000000")]]; + } + else // Header without CRC + { + u8 Data[Header.AAC_frame_length - 7] [[color("000000")]]; + } +}; + +//--------------------------------------------- + +ADTS_FRAME adtsFrame[while(!std::mem::eof())] @ 0x00; diff --git a/tests/patterns/test_data/16b-2ch-44100hz.aac b/tests/patterns/test_data/16b-2ch-44100hz.aac new file mode 100644 index 0000000..22871a8 Binary files /dev/null and b/tests/patterns/test_data/16b-2ch-44100hz.aac differ