2020-06-08 03:29:51 +03:00
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 (
2021-08-17 13:06:32 +03:00
"github.com/wader/fq/format"
"github.com/wader/fq/format/registry"
"github.com/wader/fq/pkg/decode"
2020-06-08 03:29:51 +03:00
)
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 } ,
} ,
} )
}
2021-11-05 17:04:26 +03:00
var protectionAbsentNames = decode . BoolToScalar {
true : { Description : "No CRC" } ,
false : { Description : "Has CRC" } ,
}
2020-06-08 03:29:51 +03:00
func adtsFrameDecoder ( d * decode . D , in interface { } ) interface { } {
2021-11-16 19:11:26 +03:00
2020-06-08 03:29:51 +03:00
/ *
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
2021-11-05 17:04:26 +03:00
d . FieldU12 ( "syncword" , d . AssertU ( 0b1111_1111_1111 ) , d . Bin )
2021-11-17 18:13:10 +03:00
d . FieldU1 ( "mpeg_version" , d . MapUToStrSym ( decode . UToStr { 0 : "MPEG-4" , 1 : "MPEG2- AAC" } ) )
2021-11-05 17:04:26 +03:00
d . FieldU2 ( "layer" , d . AssertU ( 0 ) )
protectionAbsent := d . FieldBool ( "protection_absent" , d . MapBoolToScalar ( protectionAbsentNames ) )
2021-11-16 19:11:26 +03:00
2021-11-05 17:04:26 +03:00
// TODO: better sym names
2021-11-17 18:13:10 +03:00
objectType := d . FieldUFn ( "profile" , func ( d * decode . D ) uint64 { return d . U2 ( ) + 1 } , d . MapUToStrSym ( format . MPEGAudioObjectTypeNames ) )
2021-11-05 17:04:26 +03:00
d . FieldUScalarFn ( "sampling_frequency" , func ( d * decode . D ) decode . Scalar {
2020-06-08 03:29:51 +03:00
v := d . U4 ( )
if v == 15 {
2021-11-05 17:04:26 +03:00
return decode . Scalar { Actual : d . U24 ( ) }
2020-06-08 03:29:51 +03:00
}
if f , ok := frequencyIndexHz [ v ] ; ok {
2021-11-05 17:04:26 +03:00
return decode . Scalar { Actual : v , Sym : f }
2020-06-08 03:29:51 +03:00
}
2021-11-05 17:04:26 +03:00
return decode . Scalar { Description : "invalid" }
2020-06-08 03:29:51 +03:00
} )
d . FieldU1 ( "private_bit" )
2021-11-17 18:13:10 +03:00
d . FieldU3 ( "channel_configuration" , d . MapUToStrSym ( channelConfigurationNames ) )
2020-06-08 03:29:51 +03:00
d . FieldU1 ( "originality" )
d . FieldU1 ( "home" )
d . FieldU1 ( "copyrighted" )
d . FieldU1 ( "copyright" )
frameLength := d . FieldU13 ( "frame_length" )
2021-11-16 19:11:26 +03:00
dataLength := int64 ( frameLength - 7 )
2020-06-08 03:29:51 +03:00
if ! protectionAbsent {
// TODO: multuple RDBs CRCs
dataLength -= 2
}
2021-11-16 19:11:26 +03:00
2020-06-08 03:29:51 +03:00
d . FieldU11 ( "buffer_fullness" )
2021-11-05 17:04:26 +03:00
numberOfRDBs := d . FieldUFn ( "number_of_rdbs" , func ( d * decode . D ) uint64 { return d . U2 ( ) + 1 } )
2020-06-08 03:29:51 +03:00
if ! protectionAbsent {
d . FieldU16 ( "crc" )
}
2021-11-16 19:11:26 +03:00
if dataLength < 0 {
d . Fatal ( "dataLength < 0" )
}
2021-11-05 17:04:26 +03:00
d . FieldArray ( "raw_data_blocks" , func ( d * decode . D ) {
2020-06-08 03:29:51 +03:00
for i := uint64 ( 0 ) ; i < numberOfRDBs ; i ++ {
2021-11-16 19:11:26 +03:00
d . FieldFormatLen ( "raw_data_block" , dataLength * 8 , aacFrameFormat , format . AACFrameIn { ObjectType : int ( objectType ) } )
2020-06-08 03:29:51 +03:00
}
} )
return nil
}