Mercurial > foo_out_sdl
comparison foosdk/sdk/foobar2000/helpers/packet_decoder_aac_common.cpp @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:e9bb126753e7 | 1:20d02a178406 |
|---|---|
| 1 #include "StdAfx.h" | |
| 2 | |
| 3 #include "packet_decoder_aac_common.h" | |
| 4 | |
| 5 #include "../SDK/filesystem_helper.h" | |
| 6 #include "bitreader_helper.h" | |
| 7 | |
| 8 size_t packet_decoder_aac_common::skipADTSHeader( const uint8_t * data,size_t size ) { | |
| 9 if ( size < 7 ) throw exception_io_data(); | |
| 10 PFC_ASSERT( bitreader_helper::extract_int(data, 0, 12) == 0xFFF); | |
| 11 if (bitreader_helper::extract_bit(data, 12+1+2)) { | |
| 12 return 7; // ABSENT flag | |
| 13 } | |
| 14 if (size < 9) throw exception_io_data(); | |
| 15 return 9; | |
| 16 } | |
| 17 | |
| 18 pfc::array_t<uint8_t> packet_decoder_aac_common::parseDecoderSetup( const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size) { | |
| 19 | |
| 20 if ( p_owner == owner_ADTS ) { | |
| 21 pfc::array_t<uint8_t> ret; | |
| 22 ret.resize( 2 ); | |
| 23 ret[0] = 0; ret[1] = 0; | |
| 24 // ret: | |
| 25 // 5 bits AOT | |
| 26 // 4 bits freqindex | |
| 27 // 4 bits channelconfig | |
| 28 | |
| 29 // source: | |
| 30 // 12 bits 0xFFF | |
| 31 // 4 bits disregard | |
| 32 // 2 bits AOT-1 @ 16 | |
| 33 // 4 bits freqindex @ 18 | |
| 34 // 1 bit disregard | |
| 35 // 3 bits channelconfig @ 23 | |
| 36 // 26 bits total, 4 bytes minimum | |
| 37 | |
| 38 | |
| 39 if ( p_param2size < 4 ) throw exception_io_data(); | |
| 40 const uint8_t * source = (const uint8_t*) p_param2; | |
| 41 if ( bitreader_helper::extract_int(source, 0, 12) != 0xFFF ) throw exception_io_data(); | |
| 42 size_t aot = bitreader_helper::extract_int(source, 16, 2) + 1; | |
| 43 if ( aot >= 31 ) throw exception_io_data(); | |
| 44 size_t freqindex = bitreader_helper::extract_int(source, 18, 4); | |
| 45 if ( freqindex > 12 ) throw exception_io_data(); | |
| 46 size_t channelconfig = bitreader_helper::extract_bits( source, 23, 3); | |
| 47 | |
| 48 bitreader_helper::write_int(ret.get_ptr(), 0, 5, aot); | |
| 49 bitreader_helper::write_int(ret.get_ptr(), 5, 4, freqindex); | |
| 50 bitreader_helper::write_int(ret.get_ptr(), 9, 4, channelconfig); | |
| 51 return ret; | |
| 52 } else if ( p_owner == owner_ADIF ) { | |
| 53 // bah | |
| 54 } else if ( p_owner == owner_MP4 ) | |
| 55 { | |
| 56 if ( p_param1 == 0x40 || p_param1 == 0x66 || p_param1 == 0x67 || p_param1 == 0x68 ) { | |
| 57 pfc::array_t<uint8_t> ret; | |
| 58 ret.set_data_fromptr( (const uint8_t*) p_param2, p_param2size); | |
| 59 return ret; | |
| 60 } | |
| 61 } | |
| 62 else if ( p_owner == owner_matroska ) | |
| 63 { | |
| 64 const matroska_setup * setup = ( const matroska_setup * ) p_param2; | |
| 65 if ( p_param2size == sizeof(*setup) ) | |
| 66 { | |
| 67 if ( !strcmp(setup->codec_id, "A_AAC") || !strncmp(setup->codec_id, "A_AAC/", 6) ) { | |
| 68 pfc::array_t<uint8_t> ret; | |
| 69 ret.set_data_fromptr( (const uint8_t*) setup->codec_private, setup->codec_private_size ); | |
| 70 return ret; | |
| 71 } | |
| 72 } | |
| 73 } | |
| 74 throw exception_io_data(); | |
| 75 } | |
| 76 | |
| 77 #if 0 | |
| 78 bool packet_decoder_aac_common::parseDecoderSetup(const GUID &p_owner, t_size p_param1, const void *p_param2, t_size p_param2size, const void *&outCodecPrivate, size_t &outCodecPrivateSize) { | |
| 79 outCodecPrivate = NULL; | |
| 80 outCodecPrivateSize = 0; | |
| 81 | |
| 82 if ( p_owner == owner_ADTS ) { return true; } | |
| 83 else if ( p_owner == owner_ADIF ) { return true; } | |
| 84 else if ( p_owner == owner_MP4 ) | |
| 85 { | |
| 86 if ( p_param1 == 0x40 || p_param1 == 0x66 || p_param1 == 0x67 || p_param1 == 0x68 ) { | |
| 87 outCodecPrivate = p_param2; outCodecPrivateSize = p_param2size; | |
| 88 return true; | |
| 89 } | |
| 90 } | |
| 91 else if ( p_owner == owner_matroska ) | |
| 92 { | |
| 93 const matroska_setup * setup = ( const matroska_setup * ) p_param2; | |
| 94 if ( p_param2size == sizeof(*setup) ) | |
| 95 { | |
| 96 if ( !strcmp(setup->codec_id, "A_AAC") || !strncmp(setup->codec_id, "A_AAC/", 6) ) { | |
| 97 outCodecPrivate = (const uint8_t *) setup->codec_private; | |
| 98 outCodecPrivateSize = setup->codec_private_size; | |
| 99 return true; | |
| 100 } | |
| 101 } | |
| 102 } | |
| 103 return false; | |
| 104 | |
| 105 } | |
| 106 #endif | |
| 107 | |
| 108 bool packet_decoder_aac_common::testDecoderSetup( const GUID & p_owner, t_size p_param1, const void * p_param2, t_size p_param2size ) { | |
| 109 if ( p_owner == owner_ADTS ) { return true; } | |
| 110 else if ( p_owner == owner_ADIF ) { return true; } | |
| 111 else if ( p_owner == owner_MP4 ) | |
| 112 { | |
| 113 if ( p_param1 == 0x40 || p_param1 == 0x66 || p_param1 == 0x67 || p_param1 == 0x68 ) { | |
| 114 return true; | |
| 115 } | |
| 116 } | |
| 117 else if ( p_owner == owner_matroska ) | |
| 118 { | |
| 119 const matroska_setup * setup = ( const matroska_setup * ) p_param2; | |
| 120 if ( p_param2size == sizeof(*setup) ) | |
| 121 { | |
| 122 if ( !strcmp(setup->codec_id, "A_AAC") || !strncmp(setup->codec_id, "A_AAC/", 6) ) { | |
| 123 return true; | |
| 124 } | |
| 125 } | |
| 126 } | |
| 127 return false; | |
| 128 } | |
| 129 | |
| 130 | |
| 131 namespace { | |
| 132 class esds_maker : public stream_writer_buffer_simple { | |
| 133 public: | |
| 134 void write_esds_obj( uint8_t code, const void * data, size_t size, abort_callback & aborter ) { | |
| 135 if ( size >= ( 1 << 28 ) ) throw pfc::exception_overflow(); | |
| 136 write_byte(code, aborter); | |
| 137 for ( int i = 3; i >= 0; -- i ) { | |
| 138 uint8_t c = (uint8_t)( 0x7F & ( size >> 7 * i ) ); | |
| 139 if ( i > 0 ) c |= 0x80; | |
| 140 write_byte(c, aborter); | |
| 141 } | |
| 142 write( data, size, aborter ); | |
| 143 } | |
| 144 void write_esds_obj( uint8_t code, esds_maker const & other, abort_callback & aborter ) { | |
| 145 write_esds_obj( code, other.m_buffer.get_ptr(), other.m_buffer.get_size(), aborter ); | |
| 146 } | |
| 147 void write_byte( uint8_t byte , abort_callback & aborter ) { | |
| 148 write( &byte, 1, aborter ); | |
| 149 } | |
| 150 }; | |
| 151 } | |
| 152 | |
| 153 void packet_decoder_aac_common::make_ESDS( pfc::array_t<uint8_t> & outESDS, const void * inCodecPrivate, size_t inCodecPrivateSize ) { | |
| 154 if (inCodecPrivateSize > 1024*1024) throw exception_io_data(); // sanity | |
| 155 auto & p_abort = fb2k::noAbort; | |
| 156 | |
| 157 esds_maker esds4; | |
| 158 | |
| 159 const uint8_t crap[] = {0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x05, 0x34, 0x08, 0x00, 0x02, 0x3D, 0x55}; | |
| 160 esds4.write( crap, sizeof(crap), p_abort ); | |
| 161 | |
| 162 { | |
| 163 esds_maker esds5; | |
| 164 esds5.write( inCodecPrivate, inCodecPrivateSize, p_abort ); | |
| 165 esds4.write_esds_obj(5, esds5, p_abort); | |
| 166 } | |
| 167 | |
| 168 | |
| 169 esds_maker esds3; | |
| 170 | |
| 171 esds3.write_byte( 0, p_abort ); | |
| 172 esds3.write_byte( 1, p_abort ); | |
| 173 esds3.write_byte( 0, p_abort ); | |
| 174 esds3.write_esds_obj(4, esds4, p_abort); | |
| 175 | |
| 176 // esds6 after esds4, but doesn't seem that important | |
| 177 | |
| 178 esds_maker final; | |
| 179 final.write_esds_obj(3, esds3, p_abort); | |
| 180 outESDS.set_data_fromptr( final.m_buffer.get_ptr(), final.m_buffer.get_size() ); | |
| 181 | |
| 182 /* | |
| 183 static const uint8_t esdsTemplate[] = { | |
| 184 0x03, 0x80, 0x80, 0x80, 0x25, 0x00, 0x01, 0x00, 0x04, 0x80, 0x80, 0x80, 0x17, 0x40, 0x15, 0x00, | |
| 185 0x00, 0x00, 0x00, 0x05, 0x34, 0x08, 0x00, 0x02, 0x3D, 0x55, 0x05, 0x80, 0x80, 0x80, 0x05, 0x12, | |
| 186 0x30, 0x56, 0xE5, 0x00, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02 | |
| 187 }; | |
| 188 */ | |
| 189 | |
| 190 // ESDS: 03 80 80 80 25 00 01 00 04 80 80 80 17 40 15 00 00 00 00 05 34 08 00 02 3D 55 05 80 80 80 05 12 30 56 E5 00 06 80 80 80 01 02 | |
| 191 // For: 12 30 56 E5 00 | |
| 192 | |
| 193 } | |
| 194 | |
| 195 const uint32_t aac_sample_rates[] = { | |
| 196 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350 | |
| 197 }; | |
| 198 | |
| 199 static unsigned readSamplingFreq(bitreader_helper::bitreader_limited& r) { | |
| 200 unsigned samplingRateIndex = (unsigned)r.read(4); | |
| 201 if (samplingRateIndex == 15) { | |
| 202 return (unsigned)r.read(24); | |
| 203 } else { | |
| 204 if (samplingRateIndex >= PFC_TABSIZE(aac_sample_rates)) throw exception_io_data(); | |
| 205 return aac_sample_rates[samplingRateIndex]; | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 packet_decoder_aac_common::audioSpecificConfig_t packet_decoder_aac_common::parseASC(const void * p_, size_t s) { | |
| 210 // Source: https://wiki.multimedia.cx/index.php?title=MPEG-4_Audio | |
| 211 bitreader_helper::bitreader_limited r((const uint8_t*)p_, 0, s * 8); | |
| 212 | |
| 213 audioSpecificConfig_t cfg = {}; | |
| 214 cfg.m_objectType = (unsigned) r.read(5); | |
| 215 if (cfg.m_objectType == 31) { | |
| 216 cfg.m_objectType = 32 + (unsigned) r.read(6); | |
| 217 } | |
| 218 | |
| 219 cfg.m_sampleRate = readSamplingFreq(r); | |
| 220 | |
| 221 cfg.m_channels = (unsigned) r.read( 4 ); | |
| 222 | |
| 223 if (cfg.m_objectType == 5 || cfg.m_objectType == 29) { | |
| 224 cfg.m_explicitSBR = true; | |
| 225 cfg.m_explicitPS = (cfg.m_objectType == 29); | |
| 226 cfg.m_sbrRate = readSamplingFreq(r); | |
| 227 cfg.m_objectType = (unsigned)r.read(5); | |
| 228 } | |
| 229 | |
| 230 switch (cfg.m_objectType) { | |
| 231 case 1: case 2: case 3: case 4: case 17: case 23: | |
| 232 cfg.m_shortWindow = (r.read(1) != 0); | |
| 233 break; | |
| 234 } | |
| 235 | |
| 236 return cfg; | |
| 237 } | |
| 238 | |
| 239 unsigned packet_decoder_aac_common::get_ASC_object_type(const void * p_, size_t s) { | |
| 240 // Source: https://wiki.multimedia.cx/index.php?title=MPEG-4_Audio | |
| 241 bitreader_helper::bitreader_limited r((const uint8_t*)p_, 0, s * 8); | |
| 242 unsigned objectType = (unsigned) r.read(5); | |
| 243 if (objectType == 31) { | |
| 244 objectType = 32 + (unsigned) r.read(6); | |
| 245 } | |
| 246 return objectType; | |
| 247 } | |
| 248 | |
| 249 const char * packet_decoder_aac_common::objectTypeStr( unsigned ot ) { | |
| 250 switch(ot) { | |
| 251 case 1: return "Main"; | |
| 252 case 2: return "LC"; | |
| 253 case 3: return "SSR"; | |
| 254 case 4: return "LTP"; | |
| 255 case 5: return "SBR"; | |
| 256 case 23: return "LD"; | |
| 257 case 39: return "ELD"; | |
| 258 case 42: | |
| 259 case 45: | |
| 260 return "USAC"; | |
| 261 default: | |
| 262 return nullptr; // unknown | |
| 263 } | |
| 264 | |
| 265 } | |
| 266 | |
| 267 const char * packet_decoder_aac_common::audioSpecificConfig_t::objectTypeStr() const { | |
| 268 return packet_decoder_aac_common::objectTypeStr( this->m_objectType ); | |
| 269 } | |
| 270 | |
| 271 pfc::array_t<uint8_t> packet_decoder_aac_common::buildASC(audioSpecificConfig_t const& arg) { | |
| 272 pfc::array_t<uint8_t> ret; ret.resize(5); memset(ret.get_ptr(), 0, ret.get_size()); | |
| 273 unsigned pos = 0; | |
| 274 auto write = [&](unsigned v, unsigned bits) { | |
| 275 bitreader_helper::write_int(ret.get_ptr(), pos, bits, v); | |
| 276 pos += bits; | |
| 277 }; | |
| 278 | |
| 279 if (arg.m_objectType < 32) { | |
| 280 write(arg.m_objectType, 5); | |
| 281 } else { | |
| 282 write(31, 5); | |
| 283 write(arg.m_objectType - 32, 6); | |
| 284 } | |
| 285 | |
| 286 { | |
| 287 bool stdRate = false; | |
| 288 for (unsigned i = 0; i < std::size(aac_sample_rates); ++i) { | |
| 289 if (arg.m_sampleRate == aac_sample_rates[i]) { | |
| 290 write(i, 4); | |
| 291 stdRate = true; break; | |
| 292 } | |
| 293 } | |
| 294 if (!stdRate) { | |
| 295 write(arg.m_sampleRate, 24); | |
| 296 } | |
| 297 | |
| 298 write(arg.m_channels, 4); | |
| 299 } | |
| 300 | |
| 301 ret.set_size((pos + 7) / 8); | |
| 302 return ret; | |
| 303 } | |
| 304 | |
| 305 pfc::array_t<uint8_t> packet_decoder_aac_common::buildSafeASC(unsigned rate) { | |
| 306 if (rate == 0) rate = 44100; | |
| 307 audioSpecificConfig_t info = {}; | |
| 308 info.m_sampleRate = rate; | |
| 309 info.m_objectType = 1; // 1 = main, 2 = LC | |
| 310 info.m_channels = 2; // stereo | |
| 311 return buildASC(info); | |
| 312 } |
