Mercurial > foo_out_sdl
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foosdk/sdk/foobar2000/helpers/packet_decoder_aac_common.cpp Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,312 @@ +#include "StdAfx.h" + +#include "packet_decoder_aac_common.h" + +#include "../SDK/filesystem_helper.h" +#include "bitreader_helper.h" + +size_t packet_decoder_aac_common::skipADTSHeader( const uint8_t * data,size_t size ) { + if ( size < 7 ) throw exception_io_data(); + PFC_ASSERT( bitreader_helper::extract_int(data, 0, 12) == 0xFFF); + if (bitreader_helper::extract_bit(data, 12+1+2)) { + return 7; // ABSENT flag + } + if (size < 9) throw exception_io_data(); + return 9; +} + +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) { + + if ( p_owner == owner_ADTS ) { + pfc::array_t<uint8_t> ret; + ret.resize( 2 ); + ret[0] = 0; ret[1] = 0; + // ret: + // 5 bits AOT + // 4 bits freqindex + // 4 bits channelconfig + + // source: + // 12 bits 0xFFF + // 4 bits disregard + // 2 bits AOT-1 @ 16 + // 4 bits freqindex @ 18 + // 1 bit disregard + // 3 bits channelconfig @ 23 + // 26 bits total, 4 bytes minimum + + + if ( p_param2size < 4 ) throw exception_io_data(); + const uint8_t * source = (const uint8_t*) p_param2; + if ( bitreader_helper::extract_int(source, 0, 12) != 0xFFF ) throw exception_io_data(); + size_t aot = bitreader_helper::extract_int(source, 16, 2) + 1; + if ( aot >= 31 ) throw exception_io_data(); + size_t freqindex = bitreader_helper::extract_int(source, 18, 4); + if ( freqindex > 12 ) throw exception_io_data(); + size_t channelconfig = bitreader_helper::extract_bits( source, 23, 3); + + bitreader_helper::write_int(ret.get_ptr(), 0, 5, aot); + bitreader_helper::write_int(ret.get_ptr(), 5, 4, freqindex); + bitreader_helper::write_int(ret.get_ptr(), 9, 4, channelconfig); + return ret; + } else if ( p_owner == owner_ADIF ) { + // bah + } else if ( p_owner == owner_MP4 ) + { + if ( p_param1 == 0x40 || p_param1 == 0x66 || p_param1 == 0x67 || p_param1 == 0x68 ) { + pfc::array_t<uint8_t> ret; + ret.set_data_fromptr( (const uint8_t*) p_param2, p_param2size); + return ret; + } + } + else if ( p_owner == owner_matroska ) + { + const matroska_setup * setup = ( const matroska_setup * ) p_param2; + if ( p_param2size == sizeof(*setup) ) + { + if ( !strcmp(setup->codec_id, "A_AAC") || !strncmp(setup->codec_id, "A_AAC/", 6) ) { + pfc::array_t<uint8_t> ret; + ret.set_data_fromptr( (const uint8_t*) setup->codec_private, setup->codec_private_size ); + return ret; + } + } + } + throw exception_io_data(); +} + +#if 0 +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) { + outCodecPrivate = NULL; + outCodecPrivateSize = 0; + + if ( p_owner == owner_ADTS ) { return true; } + else if ( p_owner == owner_ADIF ) { return true; } + else if ( p_owner == owner_MP4 ) + { + if ( p_param1 == 0x40 || p_param1 == 0x66 || p_param1 == 0x67 || p_param1 == 0x68 ) { + outCodecPrivate = p_param2; outCodecPrivateSize = p_param2size; + return true; + } + } + else if ( p_owner == owner_matroska ) + { + const matroska_setup * setup = ( const matroska_setup * ) p_param2; + if ( p_param2size == sizeof(*setup) ) + { + if ( !strcmp(setup->codec_id, "A_AAC") || !strncmp(setup->codec_id, "A_AAC/", 6) ) { + outCodecPrivate = (const uint8_t *) setup->codec_private; + outCodecPrivateSize = setup->codec_private_size; + return true; + } + } + } + return false; + +} +#endif + +bool packet_decoder_aac_common::testDecoderSetup( const GUID & p_owner, t_size p_param1, const void * p_param2, t_size p_param2size ) { + if ( p_owner == owner_ADTS ) { return true; } + else if ( p_owner == owner_ADIF ) { return true; } + else if ( p_owner == owner_MP4 ) + { + if ( p_param1 == 0x40 || p_param1 == 0x66 || p_param1 == 0x67 || p_param1 == 0x68 ) { + return true; + } + } + else if ( p_owner == owner_matroska ) + { + const matroska_setup * setup = ( const matroska_setup * ) p_param2; + if ( p_param2size == sizeof(*setup) ) + { + if ( !strcmp(setup->codec_id, "A_AAC") || !strncmp(setup->codec_id, "A_AAC/", 6) ) { + return true; + } + } + } + return false; +} + + +namespace { + class esds_maker : public stream_writer_buffer_simple { + public: + void write_esds_obj( uint8_t code, const void * data, size_t size, abort_callback & aborter ) { + if ( size >= ( 1 << 28 ) ) throw pfc::exception_overflow(); + write_byte(code, aborter); + for ( int i = 3; i >= 0; -- i ) { + uint8_t c = (uint8_t)( 0x7F & ( size >> 7 * i ) ); + if ( i > 0 ) c |= 0x80; + write_byte(c, aborter); + } + write( data, size, aborter ); + } + void write_esds_obj( uint8_t code, esds_maker const & other, abort_callback & aborter ) { + write_esds_obj( code, other.m_buffer.get_ptr(), other.m_buffer.get_size(), aborter ); + } + void write_byte( uint8_t byte , abort_callback & aborter ) { + write( &byte, 1, aborter ); + } + }; +} + +void packet_decoder_aac_common::make_ESDS( pfc::array_t<uint8_t> & outESDS, const void * inCodecPrivate, size_t inCodecPrivateSize ) { + if (inCodecPrivateSize > 1024*1024) throw exception_io_data(); // sanity + auto & p_abort = fb2k::noAbort; + + esds_maker esds4; + + const uint8_t crap[] = {0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x05, 0x34, 0x08, 0x00, 0x02, 0x3D, 0x55}; + esds4.write( crap, sizeof(crap), p_abort ); + + { + esds_maker esds5; + esds5.write( inCodecPrivate, inCodecPrivateSize, p_abort ); + esds4.write_esds_obj(5, esds5, p_abort); + } + + + esds_maker esds3; + + esds3.write_byte( 0, p_abort ); + esds3.write_byte( 1, p_abort ); + esds3.write_byte( 0, p_abort ); + esds3.write_esds_obj(4, esds4, p_abort); + + // esds6 after esds4, but doesn't seem that important + + esds_maker final; + final.write_esds_obj(3, esds3, p_abort); + outESDS.set_data_fromptr( final.m_buffer.get_ptr(), final.m_buffer.get_size() ); + + /* + static const uint8_t esdsTemplate[] = { + 0x03, 0x80, 0x80, 0x80, 0x25, 0x00, 0x01, 0x00, 0x04, 0x80, 0x80, 0x80, 0x17, 0x40, 0x15, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x34, 0x08, 0x00, 0x02, 0x3D, 0x55, 0x05, 0x80, 0x80, 0x80, 0x05, 0x12, + 0x30, 0x56, 0xE5, 0x00, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02 + }; + */ + + // 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 + // For: 12 30 56 E5 00 + +} + +const uint32_t aac_sample_rates[] = { + 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350 +}; + +static unsigned readSamplingFreq(bitreader_helper::bitreader_limited& r) { + unsigned samplingRateIndex = (unsigned)r.read(4); + if (samplingRateIndex == 15) { + return (unsigned)r.read(24); + } else { + if (samplingRateIndex >= PFC_TABSIZE(aac_sample_rates)) throw exception_io_data(); + return aac_sample_rates[samplingRateIndex]; + } +} + +packet_decoder_aac_common::audioSpecificConfig_t packet_decoder_aac_common::parseASC(const void * p_, size_t s) { + // Source: https://wiki.multimedia.cx/index.php?title=MPEG-4_Audio + bitreader_helper::bitreader_limited r((const uint8_t*)p_, 0, s * 8); + + audioSpecificConfig_t cfg = {}; + cfg.m_objectType = (unsigned) r.read(5); + if (cfg.m_objectType == 31) { + cfg.m_objectType = 32 + (unsigned) r.read(6); + } + + cfg.m_sampleRate = readSamplingFreq(r); + + cfg.m_channels = (unsigned) r.read( 4 ); + + if (cfg.m_objectType == 5 || cfg.m_objectType == 29) { + cfg.m_explicitSBR = true; + cfg.m_explicitPS = (cfg.m_objectType == 29); + cfg.m_sbrRate = readSamplingFreq(r); + cfg.m_objectType = (unsigned)r.read(5); + } + + switch (cfg.m_objectType) { + case 1: case 2: case 3: case 4: case 17: case 23: + cfg.m_shortWindow = (r.read(1) != 0); + break; + } + + return cfg; +} + +unsigned packet_decoder_aac_common::get_ASC_object_type(const void * p_, size_t s) { + // Source: https://wiki.multimedia.cx/index.php?title=MPEG-4_Audio + bitreader_helper::bitreader_limited r((const uint8_t*)p_, 0, s * 8); + unsigned objectType = (unsigned) r.read(5); + if (objectType == 31) { + objectType = 32 + (unsigned) r.read(6); + } + return objectType; +} + +const char * packet_decoder_aac_common::objectTypeStr( unsigned ot ) { + switch(ot) { + case 1: return "Main"; + case 2: return "LC"; + case 3: return "SSR"; + case 4: return "LTP"; + case 5: return "SBR"; + case 23: return "LD"; + case 39: return "ELD"; + case 42: + case 45: + return "USAC"; + default: + return nullptr; // unknown + } + +} + +const char * packet_decoder_aac_common::audioSpecificConfig_t::objectTypeStr() const { + return packet_decoder_aac_common::objectTypeStr( this->m_objectType ); +} + +pfc::array_t<uint8_t> packet_decoder_aac_common::buildASC(audioSpecificConfig_t const& arg) { + pfc::array_t<uint8_t> ret; ret.resize(5); memset(ret.get_ptr(), 0, ret.get_size()); + unsigned pos = 0; + auto write = [&](unsigned v, unsigned bits) { + bitreader_helper::write_int(ret.get_ptr(), pos, bits, v); + pos += bits; + }; + + if (arg.m_objectType < 32) { + write(arg.m_objectType, 5); + } else { + write(31, 5); + write(arg.m_objectType - 32, 6); + } + + { + bool stdRate = false; + for (unsigned i = 0; i < std::size(aac_sample_rates); ++i) { + if (arg.m_sampleRate == aac_sample_rates[i]) { + write(i, 4); + stdRate = true; break; + } + } + if (!stdRate) { + write(arg.m_sampleRate, 24); + } + + write(arg.m_channels, 4); + } + + ret.set_size((pos + 7) / 8); + return ret; +} + +pfc::array_t<uint8_t> packet_decoder_aac_common::buildSafeASC(unsigned rate) { + if (rate == 0) rate = 44100; + audioSpecificConfig_t info = {}; + info.m_sampleRate = rate; + info.m_objectType = 1; // 1 = main, 2 = LC + info.m_channels = 2; // stereo + return buildASC(info); +} \ No newline at end of file
