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 }