Last active
July 20, 2021 16:56
-
-
Save mateon1/dd2ba3c8e3e5476fdfabe505b7fcf1bc to your computer and use it in GitHub Desktop.
Kaitai MP3 parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
meta: | |
id: mp3 | |
file-extension: mp3 | |
seq: | |
- id: frame0 | |
type: frame | |
- id: frames | |
type: frame | |
repeat: expr | |
repeat-expr: 50 | |
# TODO: just testing - can't EOS because the file is truncated and the last frame errors | |
types: | |
frame: | |
instances: | |
channels: | |
value: "header.is_mono ? 1 : 2" | |
hz: | |
value: header.sample_rate_hz | |
layer: | |
value: 4 - header.layer | |
bitrate_kbps: | |
value: header.bitrate_kbps | |
seq: | |
- id: header | |
type: header | |
valid: | |
expr: " | |
_.mpeg1 == _parent.frame0.header.mpeg1 and | |
_.layer == _parent.frame0.header.layer and | |
_.sample_rate == _parent.frame0.header.sample_rate and | |
_.free_format == _parent.frame0.header.free_format | |
" | |
- id: data | |
type: mp3_data(header) | |
size: header.frame_bytes+header.padding_bytes-4 | |
mp3_data: | |
params: | |
- id: header | |
type: header | |
seq: | |
- id: crc | |
type: b16 | |
if: not header.crc_absent | |
- id: side_info | |
type: mp3_side_info(header) | |
- type: b0 # force alignment | |
- id: main_data | |
size-eos: true | |
mp3_side_info: | |
params: | |
- id: header | |
type: header | |
instances: | |
sr_idx: | |
value: "header.my_sample_rate == 0 ? 0 : header.my_sample_rate - 1" | |
gr_cnt: | |
value: "(header.is_mono ? 1 : 2) * (header.mpeg1 ? 2 : 1)" | |
main_data_begin: | |
value: "header.mpeg1 ? hack.main_data_begin_raw9 : (gr_cnt == 1 ? hack.main_data_begin_raw9 >> 1 : hack.main_data_begin_raw10 >> 2)" | |
part_23_sum: | |
value: " | |
gr[0].part_23_len + | |
(gr.size > 1 ? gr[1].part_23_len : 0) + | |
(gr.size > 2 ? gr[2].part_23_len : 0) + | |
(gr.size > 3 ? gr[3].part_23_len : 0) | |
" | |
seq: | |
- id: hack | |
type: side_info_bitalign_hack(header.mpeg1, gr_cnt) | |
- id: gr | |
type: gr_info(header) | |
repeat: expr | |
repeat-expr: gr_cnt | |
side_info_bitalign_hack: | |
params: | |
- id: mpeg1 | |
type: b1 | |
- id: gr_cnt | |
type: u4 | |
seq: | |
- id: main_data_begin_raw9 | |
type: b9 | |
if: mpeg1 or gr_cnt == 1 | |
- id: main_data_begin_raw10 | |
type: b10 | |
if: not mpeg1 and gr_cnt == 2 | |
- id: scfsi_raw9 | |
type: b9 | |
if: mpeg1 and gr_cnt == 2 | |
- id: scfsi_raw11 | |
type: b11 | |
if: mpeg1 and gr_cnt == 4 | |
gr_info: | |
params: | |
- id: header | |
type: header | |
seq: | |
- id: part_23_len | |
type: b12 | |
- id: big_values | |
type: b9 | |
valid: | |
max: 288 | |
- id: global_gain | |
type: b8 | |
- id: scalefac_compress_raw4 | |
type: b4 | |
if: header.mpeg1 | |
- id: scalefac_compress_raw9 | |
type: b9 | |
if: not header.mpeg1 | |
- id: block_bit | |
type: b1 | |
- id: tables0 | |
type: b15 | |
if: not block_bit | |
- id: region_cnt0_raw0 | |
type: b4 | |
if: not block_bit | |
- id: region_cnt1_raw0 | |
type: b3 | |
if: not block_bit | |
- id: block_type_raw1 | |
type: b2 | |
valid: | |
expr: _ != 0 | |
if: block_bit | |
- id: mixed_block_flag_raw1 | |
type: b1 | |
if: block_bit | |
- id: tables1 | |
type: b10 | |
if: block_bit | |
- id: subblock_gain_raw1 | |
type: b3 | |
repeat: expr | |
repeat-expr: 3 | |
if: block_bit | |
- id: preflag_raw | |
type: b1 | |
if: header.mpeg1 | |
- id: scalefac_scale | |
type: b1 | |
- id: count1_table | |
type: b1 | |
header: | |
instances: | |
is_layer_1: | |
value: layer == 3 | |
is_frame_576: | |
value: not mpeg1 and layer == 0b01 | |
my_sample_rate: | |
value: "sample_rate + ((mpeg1 ? 1 : 0) + (not_mpeg25 ? 1 : 0)) * 3" | |
sample_rate_hz: | |
value: "(sample_rate == 0 ? 44100 : sample_rate == 1 ? 48000 : 32000) >> (mpeg1 ? 0 : 1) >> (not_mpeg25 ? 0 : 1)" | |
frame_samples: | |
value: "is_layer_1 ? 384 : (is_frame_576 ? 576 : 1152)" | |
bitrate_helper: | |
value: "layer == 2 ? bitrate + 1 : bitrate" | |
bitrate_kbps: | |
doc: | | |
Lookup table: halfrate[mpeg1][layer-1][bitrate] | |
{ { 0, 4, 8,12,16,20,24, 28, 32, 40, 48, 56, 64, 72, 80 }, | |
{ 0, 4, 8,12,16,20,24, 28, 32, 40, 48, 56, 64, 72, 80 }, | |
{ 0,16,24,28,32,40,48, 56, 64, 72, 80, 88, 96,112,128 } }, | |
{ { 0,16,20,24,28,32,40, 48, 56, 64, 80, 96,112,128,160 }, | |
{ 0,16,24,28,32,40,48, 56, 64, 80, 96,112,128,160,192 }, | |
{ 0,16,32,48,64,80,96,112,128,144,160,176,192,208,224 } }, | |
Deltas: | |
{ { -, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8 }, | |
{ -, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8 }, | |
{ -,16, 8, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16 } }, | |
{ { -,16, 4, 4, 4, 4, 8, 8, 8, 8, 16, 16, 16, 16, 32 }, | |
{ -,16, 8, 4, 4, 8, 8, 8, 8, 16, 16, 16, 16, 32, 32 }, | |
{ -,16,16,16,16,16,16, 16, 16, 16, 16, 16, 16, 16, 16 } }, | |
value: "2 * | |
(mpeg1 ? | |
(layer == 3 or bitrate <= 1 ? | |
16 * bitrate : | |
(bitrate_helper <= 5 ? | |
12 + bitrate_helper * 4: | |
(bitrate_helper <= 9 ? | |
-8 + bitrate_helper * 8 : | |
(bitrate_helper <= 13 ? | |
-80 + bitrate_helper * 16 : | |
-288 + bitrate_helper * 32))) ) : | |
(layer == 3 ? | |
(bitrate <= 1 ? | |
16 * bitrate : | |
(bitrate <= 4 ? | |
24 + 4 * (bitrate - 2) : | |
(bitrate <= 12 ? | |
32 + 8 * (bitrate - 4) : | |
(bitrate == 13 ? 160 : 192)))) : | |
bitrate <= 8 ? 4 * bitrate : 32 + 8 * (bitrate - 8))) | |
" | |
frame_bytes: | |
value: "(frame_samples * bitrate_kbps*125/sample_rate_hz) & (is_layer_1 ? ~3 : ~0)" | |
free_format: | |
value: bitrate == 0 | |
padding_bytes: | |
value: "has_padding ? (is_layer_1 ? 4 : 1) : 0" | |
is_mono: | |
value: "stereo_mode == 3" | |
is_ms_stereo: | |
value: "stereo_mode == 1 and stereo_mode_ext & 2 == 2" | |
test_ms_stereo: | |
value: "stereo_mode_ext & 2 == 2" | |
test_i_stereo: | |
value: "stereo_mode_ext & 1 == 1" | |
seq: | |
- id: sync | |
type: b11 | |
valid: 0x7ff | |
- id: not_mpeg25 | |
type: b1 | |
- id: mpeg1 | |
type: b1 | |
- id: layer | |
type: b2 | |
valid: | |
expr: _ != 0 | |
- id: crc_absent | |
type: b1 | |
# check 0xFFE2/0xFFE3 header validity here | |
valid: "not_mpeg25 or is_frame_576" | |
# byte 2 | |
- id: bitrate | |
type: b4 | |
valid: | |
expr: _ != 15 | |
- id: sample_rate | |
type: b2 | |
valid: | |
expr: _ != 3 | |
- id: has_padding | |
type: b1 | |
- id: unk1 | |
type: b1 | |
# byte 3 | |
- id: stereo_mode | |
type: b2 | |
- id: stereo_mode_ext | |
type: b2 | |
- id: unk2 | |
type: b4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment