mirror of
https://github.com/wader/fq.git
synced 2024-12-27 07:24:48 +03:00
1b32b42f93
Generate more code More generic and comfortable API Improve and Update format decoder to new API Add some more format tests
108 lines
4.0 KiB
Go
108 lines
4.0 KiB
Go
package mpeg
|
|
|
|
// https://github.com/mstorsjo/fdk-aac/blob/f285813ec15e7c6f8e4839c9eb4f6b0cd2da1990/libMpegTPEnc/src/tpenc_asc.cpp
|
|
// https://www.iis.fraunhofer.de/content/dam/iis/de/doc/ame/wp/FraunhoferIIS_Application-Bulletin_AAC-Transport-Formats.pdf
|
|
// https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/aac_adtstoasc_bsf.c
|
|
|
|
import (
|
|
"github.com/wader/fq/format"
|
|
"github.com/wader/fq/format/registry"
|
|
"github.com/wader/fq/pkg/decode"
|
|
)
|
|
|
|
var aacFrameFormat []*decode.Format
|
|
|
|
func init() {
|
|
registry.MustRegister(&decode.Format{
|
|
Name: format.ADTS_FRAME,
|
|
Description: "Audio Data Transport Stream frame",
|
|
DecodeFn: adtsFrameDecoder,
|
|
Dependencies: []decode.Dependency{
|
|
{Names: []string{format.AAC_FRAME}, Formats: &aacFrameFormat},
|
|
},
|
|
})
|
|
}
|
|
|
|
var protectionAbsentNames = decode.BoolToScalar{
|
|
true: {Description: "No CRC"},
|
|
false: {Description: "Has CRC"},
|
|
}
|
|
|
|
func adtsFrameDecoder(d *decode.D, in interface{}) interface{} {
|
|
/*
|
|
adts_frame() {
|
|
adts_fixed_header();
|
|
adts_variable_header();
|
|
if (number_of_raw_data_blocks_in_frame == 0) {
|
|
adts_error_check();
|
|
raw_data_block();
|
|
} else {
|
|
adts_header_error_check();
|
|
for( i = 0; i <= number_of_raw_data_blocks_in_frame; i++ ) {
|
|
raw_data_block();
|
|
adts_raw_data_block_error_check();
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// A 12 syncword 0xFFF, all bits must be 1
|
|
// B 1 MPEG Version: 0 for MPEG-4, 1 for MPEG-2
|
|
// C 2 Layer: always 0
|
|
// D 1 protection absent, Warning, set to 1 if there is no CRC and 0 if there is CRC
|
|
// E 2 profile, the MPEG-4 Audio Object Type minus 1
|
|
// F 4 MPEG-4 Sampling Frequency Index (15 is forbidden)
|
|
// G 1 private bit, guaranteed never to be used by MPEG, set to 0 when encoding, ignore when decoding
|
|
// H 3 MPEG-4 Channel Configuration (in the case of 0, the channel configuration is sent via an inband PCE)
|
|
// I 1 originality, set to 0 when encoding, ignore when decoding
|
|
// J 1 home, set to 0 when encoding, ignore when decoding
|
|
// K 1 copyrighted id bit, the next bit of a centrally registered copyright identifier, set to 0 when encoding, ignore when decoding
|
|
// L 1 copyright id start, signals that this frame's copyright id bit is the first bit of the copyright id, set to 0 when encoding, ignore when decoding
|
|
// M 13 frame length, this value must include 7 or 9 bytes of header length: FrameLength = (ProtectionAbsent == 1 ? 7 : 9) + size(AACFrame)
|
|
// O 11 Buffer fullness
|
|
// P 2 Number of AAC frames (RDBs) in ADTS frame minus 1, for maximum compatibility always use 1 AAC frame per ADTS frame
|
|
// Q 16 CRC if protection absent is 0
|
|
|
|
d.FieldU12("syncword", d.AssertU(0b1111_1111_1111), d.Bin)
|
|
d.FieldU1("mpeg_version", d.MapUToStr(decode.UToStr{0: "MPEG-4", 1: "MPEG2- AAC"}))
|
|
d.FieldU2("layer", d.AssertU(0))
|
|
protectionAbsent := d.FieldBool("protection_absent", d.MapBoolToScalar(protectionAbsentNames))
|
|
// TODO: better sym names
|
|
objectType := d.FieldUFn("profile", func(d *decode.D) uint64 { return d.U2() + 1 }, d.MapUToStr(format.MPEGAudioObjectTypeNames))
|
|
d.FieldUScalarFn("sampling_frequency", func(d *decode.D) decode.Scalar {
|
|
v := d.U4()
|
|
if v == 15 {
|
|
return decode.Scalar{Actual: d.U24()}
|
|
}
|
|
if f, ok := frequencyIndexHz[v]; ok {
|
|
return decode.Scalar{Actual: v, Sym: f}
|
|
}
|
|
return decode.Scalar{Description: "invalid"}
|
|
})
|
|
d.FieldU1("private_bit")
|
|
d.FieldU3("channel_configuration", d.MapUToStr(channelConfigurationNames))
|
|
d.FieldU1("originality")
|
|
d.FieldU1("home")
|
|
d.FieldU1("copyrighted")
|
|
d.FieldU1("copyright")
|
|
frameLength := d.FieldU13("frame_length")
|
|
dataLength := frameLength - 7
|
|
if !protectionAbsent {
|
|
// TODO: multuple RDBs CRCs
|
|
dataLength -= 2
|
|
}
|
|
d.FieldU11("buffer_fullness")
|
|
numberOfRDBs := d.FieldUFn("number_of_rdbs", func(d *decode.D) uint64 { return d.U2() + 1 })
|
|
if !protectionAbsent {
|
|
d.FieldU16("crc")
|
|
}
|
|
|
|
d.FieldArray("raw_data_blocks", func(d *decode.D) {
|
|
for i := uint64(0); i < numberOfRDBs; i++ {
|
|
d.FieldFormatLen("raw_data_block", int64(dataLength)*8, aacFrameFormat, format.AACFrameIn{ObjectType: int(objectType)})
|
|
}
|
|
})
|
|
|
|
return nil
|
|
}
|