1
1
mirror of https://github.com/wader/fq.git synced 2024-12-23 13:22:58 +03:00
fq/format/mpeg/aac_frame.go
Mattias Wadman 8e0dde03d0 decode: Support multiple format args and some rename and refactor
This will allow passing both cli options and format options to sub decoder.
Ex: pass keylog option to a tls decoder when decoding a pcap.
Ex: pass decode options to a format inside a http body inside a pcap.

Add ArgAs method to lookup argument based on type. This also makes the format
decode function have same signature as sub decoders in the decode API.

This change decode.Format a bit:
DecodeFn is now just func(d *D) any
DecodeInArg renamed to DefaultInArg
2023-02-18 21:38:51 +01:00

327 lines
8.1 KiB
Go

package mpeg
// one AAC frame or "raw data block"
// ISO/IEC 13818-7 Part 7: Advanced Audio Coding (AAC)
// ISO/IEC 14496-3
// TODO: currently only does very basic main, lc, ssr and ltp
import (
"github.com/wader/fq/format"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/interp"
"github.com/wader/fq/pkg/scalar"
)
func init() {
interp.RegisterFormat(decode.Format{
Name: format.AAC_FRAME,
Description: "Advanced Audio Coding frame",
DecodeFn: aacDecode,
DefaultInArg: format.AACFrameIn{
ObjectType: format.MPEGAudioObjectTypeMain,
},
RootArray: true,
RootName: "elements",
})
}
const (
SCE = 0b000
CPE = 0b001
CCE = 0b010
LFE = 0b011
DSE = 0b100
PCE = 0b101
FIL = 0b110
TERM = 0b111
)
var syntaxElementNames = scalar.UintMapSymStr{
SCE: "SCE",
CPE: "CPE",
CCE: "CCE",
LFE: "LFE",
DSE: "DSE",
PCE: "PCE",
FIL: "FIL",
TERM: "TERM",
}
//nolint:revive
const (
EXT_FILL = 0x0
EXT_FILL_DATA = 0x1
EXT_DATA_ELEMENT = 0x2
EXT_DYNAMIC_RANGE = 0xb
EXT_SBR_DATA = 0xd
EXT_SBR_DATA_CRC = 0xe
)
var extensionPayloadIDNames = scalar.UintMapSymStr{
EXT_FILL: "EXT_FILL",
EXT_FILL_DATA: "EXT_FILL_DATA",
EXT_DATA_ELEMENT: "EXT_DATA_ELEMENT",
EXT_DYNAMIC_RANGE: "EXT_DYNAMIC_RANGE",
EXT_SBR_DATA: "EXT_SBR_DATA",
EXT_SBR_DATA_CRC: "EXT_SBR_DATA_CRC",
}
//nolint:revive
const (
ONLY_LONG_SEQUENCE = 0x0
LONG_START_SEQUENCE = 0x1
EIGHT_SHORT_SEQUENCE = 0x2
LONG_STOP_SEQUENCE = 0x3
)
var windowSequenceNames = scalar.UintMapSymStr{
ONLY_LONG_SEQUENCE: "ONLY_LONG_SEQUENCE",
LONG_START_SEQUENCE: "LONG_START_SEQUENCE",
EIGHT_SHORT_SEQUENCE: "EIGHT_SHORT_SEQUENCE",
LONG_STOP_SEQUENCE: "LONG_STOP_SEQUENCE",
}
var windowSequenceNumWindows = map[int]int{
ONLY_LONG_SEQUENCE: 1,
LONG_START_SEQUENCE: 1,
EIGHT_SHORT_SEQUENCE: 8,
LONG_STOP_SEQUENCE: 1,
}
func aacLTPData(d *decode.D, objectType int, windowSequence int) {
switch objectType {
case format.MPEGAudioObjectTypeER_AAC_LD:
// TODO:
default:
d.FieldU11("ltp_lag")
d.FieldU3("ltp_coef")
_ = windowSequenceNumWindows[windowSequence]
}
}
func aacICSInfo(d *decode.D, objectType int) {
d.FieldU1("ics_reserved_bit")
windowSequence := d.FieldU2("window_sequence", windowSequenceNames)
d.FieldU1("window_shape")
switch windowSequence {
case EIGHT_SHORT_SEQUENCE:
d.FieldU4("max_sfb")
d.FieldU7("scale_factor_grouping")
default:
maxSFB := d.FieldU6("max_sfb")
predictorDataPresent := d.FieldBool("predictor_data_present")
if predictorDataPresent {
switch objectType {
case format.MPEGAudioObjectTypeMain: // 1
predictorReset := d.FieldBool("predictor_reset")
if predictorReset {
d.FieldU5("predictor_reset_group_number")
}
d.FieldU5("predictor_reset_group_number")
// TODO: min(max_sfb, PRED_SFB_MAX)
// TODO: array?
d.FieldRawLen("prediction_used", int64(maxSFB))
default:
ltpDataPresent := d.FieldBool("ltp_data_present")
if ltpDataPresent {
aacLTPData(d, objectType, int(windowSequence))
}
}
}
}
// ;
// if (window_sequence == EIGHT_SHORT_SEQUENCE) {
// max_sfb; scale_factor_grouping;
// } }
// else {
// ltp_data_present;
// if (ltp_data_present) {
// ltp_data(); }
// if (common_window) {
// ltp_data_present;
// LICENSED TO MECON Limited. - RANCHI/BANGALORE,
// FOR INTERNAL USE AT THIS LOCATION ONLY, SUPPLIED BY BOOK SUPPLY BUREAU.
// if (ltp_data_present) {
// ltp_data(); }
// } }
// } }
// }
}
func aacIndividualChannelStream(d *decode.D, objectType int, commonWindow bool, scaleFlag bool) {
d.FieldU8("global_gain")
if !commonWindow && !scaleFlag {
d.FieldStruct("ics_info", func(d *decode.D) {
aacICSInfo(d, objectType)
})
}
}
func aacSingleChannelElement(d *decode.D, objectType int) {
d.FieldU4("element_instance_tag")
aacIndividualChannelStream(d, objectType, false, false)
}
func aacProgramConfigElement(d *decode.D, ascStartPos int64) {
d.FieldU4("element_instance_tag")
d.FieldU2("object_type")
d.FieldU4("sampling_frequency_index")
numFrontChannelElements := d.FieldU4("num_front_channel_elements")
numSideChannelElements := d.FieldU4("num_side_channel_elements")
numBackChannelElements := d.FieldU4("num_back_channel_elements")
numLfeChannelElements := d.FieldU2("num_lfe_channel_elements")
numAssocDataElements := d.FieldU3("num_assoc_data_elements")
numValidCcElements := d.FieldU4("num_valid_cc_elements")
monoMixdownPresent := d.FieldBool("mono_mixdown_present")
if monoMixdownPresent {
d.FieldU4("mono_mixdown_element_number")
}
stereoMixdownPresent := d.FieldBool("stereo_mixdown_present")
if stereoMixdownPresent {
d.FieldU4("stereo_mixdown_element_number")
}
matrixMixdownIdxPresent := d.FieldBool("matrix_mixdown_idx_present")
if matrixMixdownIdxPresent {
d.FieldU2("matrix_mixdown_idx")
d.FieldBool("pseudo_surround_enable")
}
d.FieldArray("front_channel_elements", func(d *decode.D) {
for i := uint64(0); i < numFrontChannelElements; i++ {
d.FieldStruct("front_channel_element", func(d *decode.D) {
d.FieldBool("is_cpe")
d.FieldU4("tag_select")
})
}
})
d.FieldArray("side_channel_elements", func(d *decode.D) {
for i := uint64(0); i < numSideChannelElements; i++ {
d.FieldStruct("side_channel_element", func(d *decode.D) {
d.FieldBool("is_cpe")
d.FieldU4("tag_select")
})
}
})
d.FieldArray("back_channel_elements", func(d *decode.D) {
for i := uint64(0); i < numBackChannelElements; i++ {
d.FieldStruct("back_channel_element", func(d *decode.D) {
d.FieldBool("is_cpe")
d.FieldU4("tag_select")
})
}
})
d.FieldArray("lfe_channel_elements", func(d *decode.D) {
for i := uint64(0); i < numLfeChannelElements; i++ {
d.FieldStruct("lfe_channel_element", func(d *decode.D) {
d.FieldU4("tag_select")
})
}
})
d.FieldArray("assoc_data_elements", func(d *decode.D) {
for i := uint64(0); i < numAssocDataElements; i++ {
d.FieldStruct("assoc_data_element", func(d *decode.D) {
d.FieldU4("tag_select")
})
}
})
d.FieldArray("valid_cc_elements", func(d *decode.D) {
for i := uint64(0); i < numValidCcElements; i++ {
d.FieldStruct("valid_cc_element", func(d *decode.D) {
d.FieldU1("cc_element_is_ind_sw")
d.FieldU4("valid_cc_element_tag_select")
})
}
})
byteAlignBits := (8 - ((d.Pos() + ascStartPos) & 0x7)) & 0x7
d.FieldRawLen("byte_alignment", byteAlignBits)
commentFieldBytes := d.FieldU8("comment_field_bytes")
d.FieldUTF8("comment_field", int(commentFieldBytes))
}
func aacFillElement(d *decode.D) {
var cnt uint64
d.FieldStruct("cnt", func(d *decode.D) {
count := d.FieldU4("count")
cnt = count
if cnt == 15 {
escCount := d.FieldU8("esc_count")
cnt += escCount - 1
}
})
d.FieldValueUint("payload_length", cnt)
d.FieldStruct("extension_payload", func(d *decode.D) {
d.FramedFn(int64(cnt)*8, func(d *decode.D) {
extensionType := d.FieldU4("extension_type", extensionPayloadIDNames)
// d.FieldU("align4", 2)
switch extensionType {
case EXT_FILL:
d.FieldU4("fill_nibble")
d.FieldRawLen("fill_byte", 8*(int64(cnt)-1))
}
})
})
}
func aacDecode(d *decode.D) any {
var ai format.AACFrameIn
d.ArgAs(&ai)
// TODO: seems tricky to know length of blocks
// TODO: currently break when length is unknown
switch ai.ObjectType {
case format.MPEGAudioObjectTypeMain,
format.MPEGAudioObjectTypeLC,
format.MPEGAudioObjectTypeSSR,
format.MPEGAudioObjectTypeLTP,
format.MPEGAudioObjectTypeSBR,
format.MPEGAudioObjectTypeER_AAC_LD,
format.MPEGAudioObjectTypePS:
seenTerm := false
for !seenTerm {
d.FieldStruct("element", func(d *decode.D) {
se := d.FieldU3("syntax_element", syntaxElementNames)
switch se {
case FIL:
aacFillElement(d)
case SCE:
aacSingleChannelElement(d, ai.ObjectType)
seenTerm = true
case PCE:
aacProgramConfigElement(d, 0)
seenTerm = true
default:
fallthrough
case TERM:
seenTerm = true
}
})
}
if d.ByteAlignBits() > 0 {
d.FieldRawLen("byte_align", int64(d.ByteAlignBits()))
}
d.FieldRawLen("data", d.BitsLeft())
default:
// not supported
d.FieldRawLen("data", d.BitsLeft())
}
return nil
}