1 /*******************************************************************************
2 *                         Goggles Audio Player Library                         *
3 ********************************************************************************
4 *           Copyright (C) 2010-2021 by Sander Jansen. All Rights Reserved      *
5 *                               ---                                            *
6 * This program is free software: you can redistribute it and/or modify         *
7 * it under the terms of the GNU General Public License as published by         *
8 * the Free Software Foundation, either version 3 of the License, or            *
9 * (at your option) any later version.                                          *
10 *                                                                              *
11 * This program is distributed in the hope that it will be useful,              *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of               *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                *
14 * GNU General Public License for more details.                                 *
15 *                                                                              *
16 * You should have received a copy of the GNU General Public License            *
17 * along with this program.  If not, see http://www.gnu.org/licenses.           *
18 ********************************************************************************/
19 #include "ap_defs.h"
20 #include "ap_packet.h"
21 #include "ap_event_private.h"
22 #include "ap_reader_plugin.h"
23 #include "ap_input_plugin.h"
24 #include "ap_decoder_plugin.h"
25 
26 #include "neaacdec.h"
27 
28 namespace ap {
29 
30 #ifdef HAVE_FAAD
31 
32 class BitReader {
33 public:
34   class OverflowException {};
35 private:
36   const FXuchar* buffer;
37   FXuint length;
38   FXuint position=0;
39 public:
BitReader(const FXuchar * data,FXuint len)40   BitReader(const FXuchar * data,FXuint len) : buffer(data), length(len) {}
41 
remaining()42   FXuint remaining() {
43     return (length*8) - position;
44     }
45 
read(FXuint nbits)46   FXuint read(FXuint nbits) {
47     FXuint value  = 0;
48     while(nbits) {
49       FXuint offset = position / 8;
50       FXuint shift  = position % 8;
51       FXuchar     r = FXMIN(nbits,8-shift);
52       if (__unlikely(offset>=length)) throw OverflowException();
53       value<<=r;
54       value|=((unsigned char)(buffer[offset]<<shift))>>(8-r);
55       nbits-=r;
56       position+=r;
57       }
58     return value;
59     }
60   };
61 
62 
63 static const FXuint mp4_channel_map[]={
64   Channel::FrontCenter, // maybe mono?
65 
66   AP_CHANNELMAP_STEREO,
67 
68   AP_CMAP3(Channel::FrontCenter,
69            Channel::FrontLeft,
70            Channel::FrontRight),
71 
72   AP_CMAP4(Channel::FrontCenter,
73            Channel::FrontLeft,
74            Channel::FrontRight,
75            Channel::BackCenter),
76 
77   AP_CMAP5(Channel::FrontCenter,
78            Channel::FrontLeft,
79            Channel::FrontRight,
80            Channel::BackLeft,
81            Channel::BackRight),
82 
83   AP_CMAP6(Channel::FrontCenter,
84            Channel::FrontLeft,
85            Channel::FrontRight,
86            Channel::BackLeft,
87            Channel::BackRight,
88            Channel::LFE),
89 
90   AP_CMAP8(Channel::FrontCenter,
91            Channel::FrontLeft,
92            Channel::FrontRight,
93            Channel::SideLeft,
94            Channel::SideRight,
95            Channel::BackLeft,
96            Channel::BackRight,
97            Channel::LFE)
98   };
99 
100 
ap_parse_aac_specific_config(const FXuchar * data,FXuint length,FXushort & samples_per_frame,FXbool & upsampled,AudioFormat & af)101 FXbool ap_parse_aac_specific_config(const FXuchar * data, FXuint length,
102                                     FXushort & samples_per_frame,
103                                     FXbool & upsampled,
104                                     AudioFormat & af) {
105 
106   static const FXuint rates[] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 };
107   BitReader bit(data,length);
108   try {
109 
110     FXuint index;
111     FXuint samplerate;
112     FXuint ext_samplerate = 0;
113     FXuint ext_objtype = 0;
114     FXint  has_sbr = -1;
115 
116     enum {
117       AAC_MAIN   = 1,
118       AAC_LC     = 2,
119       AAC_SSR    = 3,
120       AAC_LTP    = 4,
121       AAC_SBR    = 5,
122       ER_AAC_LC  = 17,
123       ER_AAC_LTP = 19,
124       ER_AAC_LD  = 23
125       };
126 
127     // object type
128     FXuint objtype = bit.read(5);
129     if (objtype==31)
130       objtype = 32 + bit.read(6);
131 
132     GM_DEBUG_PRINT("[asc] object type %u\n",objtype);
133 
134     // samplerate
135     index = bit.read(4);
136     if (index < 12)
137       samplerate = rates[index];
138     else if (index == 15)
139       samplerate = bit.read(24);
140     else
141       samplerate = 0;
142 
143     GM_DEBUG_PRINT("[asc] samplerate %u\n",samplerate);
144 
145     // channel layout
146     FXuint channelconfig = bit.read(4);
147     if (channelconfig>0 && channelconfig<8) {
148       // faad will upmatrix to 2 channels
149       if (channelconfig==1) {
150         GM_DEBUG_PRINT("[asc] found 1 channel config. assuming faad will upmatrix to 2 channels\n");
151         channelconfig = 2;
152         af.channels   = 2;
153         }
154       af.channelmap = mp4_channel_map[channelconfig-1];
155       }
156 
157     if (objtype == AAC_SBR) {
158       ext_objtype = AAC_SBR;
159       has_sbr = 1;
160 
161       // samplerate
162       index = bit.read(4);
163       if (index < 12)
164         ext_samplerate = rates[index];
165       else if (index == 15)
166         ext_samplerate = bit.read(24);
167       else
168         ext_samplerate = 0;
169 
170       GM_DEBUG_PRINT("[asc] ext. samplerate %u\n",ext_samplerate);
171 
172       objtype = bit.read(5);
173       if(objtype==31)
174         objtype = 32 + bit.read(6);
175 
176       GM_DEBUG_PRINT("[asc] sbr object type %u\n",objtype);
177       FXASSERT(objtype!=22);
178       }
179 
180     FXbool small_frame_length = false;
181     if (objtype == AAC_MAIN ||
182         objtype == AAC_LC ||
183         objtype == AAC_SSR ||
184         objtype == AAC_LTP ||
185         objtype == ER_AAC_LC ||
186         objtype == ER_AAC_LTP ||
187         objtype == ER_AAC_LD) {
188 
189       // ga specific info
190       small_frame_length = (bit.read(1)!=0);
191 
192       FXbool core_order = bit.read(1);
193       if (core_order)
194         bit.read(14);
195 
196       FXbool extension = bit.read(1);
197       if (channelconfig==0) {
198         FXASSERT(0);
199         GM_DEBUG_PRINT("[asc] program element not supported\n");
200         }
201 
202       if (extension) {
203         if (objtype>=17) bit.read(3);
204         bit.read(1);
205         }
206       }
207     else {
208       FXASSERT(0);
209       GM_DEBUG_PRINT("[asc] unsupported object type %u\n",objtype);
210       return false;
211       }
212 
213     if (ext_objtype!=AAC_SBR && bit.remaining() >= 16) {
214       GM_DEBUG_PRINT("[asc] extension bit present\n");
215       if (bit.read(11)==0x2b7) {
216         FXuint x = bit.read(5);
217         if (x==AAC_SBR) {
218           has_sbr = bit.read(1);
219           if (has_sbr == 1) {
220             objtype = x;
221             GM_DEBUG_PRINT("[asc] object type %u\n",objtype);
222             index = bit.read(4);
223             if (index < 12)
224               ext_samplerate = rates[index];
225             else if (index == 15)
226               ext_samplerate = bit.read(24);
227             else
228               ext_samplerate = 0;
229 
230             GM_DEBUG_PRINT("[asc] ext. samplerate %u\n",ext_samplerate);
231             }
232           }
233         }
234       }
235 
236     samples_per_frame = 1024;
237     if (small_frame_length)
238       samples_per_frame = 960;
239 
240     if (objtype == ER_AAC_LD)
241       samples_per_frame >>= 1;
242 
243     // implicit sbr
244     if (has_sbr == -1 && samplerate <= 24000) {
245       GM_DEBUG_PRINT("[asc] implicit sbr %u -> %u\n", samplerate, samplerate<<1);
246       samplerate <<= 1;
247       samples_per_frame <<= 1;
248       upsampled = true;
249       }
250 
251     // explicit sbr
252     if (has_sbr == 1) {
253       if (ext_samplerate != samplerate) {
254         FXASSERT(ext_samplerate==(samplerate<<1));
255         GM_DEBUG_PRINT("[asc] explicit sbr %u -> %u\n", samplerate, ext_samplerate);
256         samplerate=ext_samplerate;
257         samples_per_frame <<= 1;
258         upsampled = true;
259         }
260       }
261 
262     af.rate = samplerate;
263     GM_DEBUG_PRINT("[asc] using samplerate %u\n",samplerate);
264     GM_DEBUG_PRINT("[asc] using samples_per_frame %u\n",samples_per_frame);
265     }
266   catch(BitReader::OverflowException &) {
267     return false;
268     }
269   return true;
270   }
271 
272 
273 class AACReader : public ReaderPlugin {
274 public:
AACReader(InputContext * ctx)275   AACReader(InputContext * ctx) : ReaderPlugin(ctx) {}
init(InputPlugin * plugin)276   FXbool init(InputPlugin*plugin) override { ReaderPlugin::init(plugin); flags=0; return true; }
format() const277   FXuchar format() const override { return Format::AAC; }
278 
279   ReadStatus process(Packet*p) override;
280 
~AACReader()281   ~AACReader() {}
282   };
283 
ap_aac_reader(InputContext * ctx)284 ReaderPlugin * ap_aac_reader(InputContext * ctx) {
285   return new AACReader(ctx);
286   }
287 
process(Packet * packet)288 ReadStatus AACReader::process(Packet*packet) {
289   if (!(flags&FLAG_PARSED)) {
290     GM_DEBUG_PRINT("[aac] finding sync\n");
291     FXuchar buffer[2];
292     if (input->read(buffer,2)!=2)
293       return ReadError;
294     do {
295       if ((buffer[0]==0xFF) && (buffer[1]&0xf0)==0xf0) {
296         GM_DEBUG_PRINT("[aac] found sync\n");
297         context->post_configuration(new ConfigureEvent(af,Codec::AAC));
298         flags|=FLAG_PARSED;
299         packet->append(buffer,2);
300         break;
301         }
302       buffer[0]=buffer[1];
303       if (input->read(&buffer[1],1)!=1)
304         return ReadError;
305       }
306     while(1);
307     }
308   return ReaderPlugin::process(packet);
309   }
310 
311 
312 
313 
314 
315 
316 
317 
318 
319 
320 
321 class AacDecoder : public DecoderPlugin {
322 protected:
323   NeAACDecHandle handle;
324   MemoryBuffer   buffer;
325   FXlong         stream_position = -1;
326   FXushort       stream_offset_start;
327   FXbool         rawmode=false;
328   FXbool         use_internal_buffer=false;
329 protected:
330   Packet *       out = nullptr;
331 protected:
332   FXbool getNextFrame(Packet *& packet,FXuchar *& ptr,FXuint & framesize);
333   FXbool process_frames(Packet*);
334   FXbool process_raw(Packet*);
335   FXbool create();
336   FXint  process_output(FXuint streamid,FXlong stream_length,void * outsamples,FXint nsamples);
337 public:
338   AacDecoder(DecoderContext*);
codec() const339   FXuchar codec() const override { return Codec::AAC; }
340   FXbool flush(FXlong offset=0) override;
341   FXbool init(ConfigureEvent*) override ;
342   FXbool process(Packet*) override;
343   ~AacDecoder();
344   };
345 
346 
347 
AacDecoder(DecoderContext * e)348 AacDecoder::AacDecoder(DecoderContext * e) : DecoderPlugin(e),
349   handle(nullptr),
350   buffer(0) {
351   }
352 
~AacDecoder()353 AacDecoder::~AacDecoder() {
354   flush();
355   if (handle) {
356     NeAACDecClose(handle);
357     handle=nullptr;
358     }
359   }
360 
361 
create()362 FXbool AacDecoder::create() {
363   static const FXbool is_fixed_point_decoder = NeAACDecGetCapabilities()&FIXED_POINT_CAP;
364 
365   handle = NeAACDecOpen();
366   if (handle==nullptr) return false;
367 
368   NeAACDecConfiguration * config = NeAACDecGetCurrentConfiguration(handle);
369   if (__unlikely(is_fixed_point_decoder)) {
370     config->outputFormat = FAAD_FMT_16BIT;
371     af.format = AP_FORMAT_S16;
372     }
373   else {
374     config->outputFormat = FAAD_FMT_FLOAT;
375     af.format = AP_FORMAT_FLOAT;
376     }
377   NeAACDecSetConfiguration(handle, config);
378   return true;
379   }
380 
init(ConfigureEvent * event)381 FXbool AacDecoder::init(ConfigureEvent*event) {
382   DecoderPlugin::init(event);
383   buffer.clear();
384   af=event->af;
385   if (handle) {
386     NeAACDecClose(handle);
387     handle=nullptr;
388     }
389   use_internal_buffer=false;
390 
391   DecoderSpecificConfig * ac = dynamic_cast<DecoderSpecificConfig*>(event->dc);
392   if (ac) {
393     long unsigned int samplerate;
394     FXuchar           channels;
395     if (create() && NeAACDecInit2(handle,ac->config,ac->config_bytes,&samplerate,&channels)<0){
396       NeAACDecClose(handle);
397       handle=nullptr;
398       return false;
399       }
400     event->af=af; // Pass decoder output format back to OutputThread.
401     rawmode=false;
402     }
403   else {
404     rawmode=true;
405     }
406   stream_position=-1;
407   stream_offset_start=event->stream_offset_start;
408   return true;
409   }
410 
flush(FXlong offset)411 FXbool AacDecoder::flush(FXlong offset) {
412   DecoderPlugin::flush(offset);
413   buffer.clear();
414   if (out) {
415     out->unref();
416     out=nullptr;
417     }
418   stream_position=-1;
419   if (handle) NeAACDecPostSeekReset(handle,0); // always drop the first frame
420   return true;
421   }
422 
423 
getNextFrame(Packet * & packet,FXuchar * & ptr,FXuint & framesize)424 FXbool AacDecoder::getNextFrame(Packet *& packet,FXuchar *& ptr,FXuint & framesize) {
425   framesize=0;
426 
427   // data in local cache
428   if (buffer.size()) {
429 
430     // read next framesize
431     memcpy(&framesize,buffer.data(),4);
432 
433     // get frame from buffer
434     if (framesize+4<=buffer.size()){
435       buffer.readBytes(4);
436       ptr=buffer.data();
437       buffer.readBytes(framesize);
438       return true;
439       }
440 
441     // see if packet contains additional data
442     if (packet) {
443 
444       // get missing data from packet
445       FXuint missing = framesize - (buffer.size()-4);
446       if (packet->size()>=missing) {
447         buffer.append(packet->data(),missing);
448         packet->readBytes(missing);
449         buffer.readBytes(4);
450         ptr=buffer.data();
451         buffer.readBytes(framesize);
452         if (packet->size()==0) {
453           packet->unref();
454           packet=nullptr;
455           }
456         return true;
457         }
458 
459       // incomplete data in packet
460       buffer.append(packet->data(),packet->size());
461       packet->unref();
462       packet=nullptr;
463       }
464     return false;
465     }
466 
467   if (packet) {
468 
469     if (packet->size()>=4) {
470 
471       // read next framesize
472       memcpy(&framesize,packet->data(),4);
473 
474       // get frame from packet
475       if (framesize+4<=packet->size()){
476         packet->readBytes(4);
477         ptr=packet->data();
478         packet->readBytes(framesize);
479         return true;
480         }
481       }
482 
483     // incomplete data in packet
484     if (packet->size())
485       buffer.append(packet->data(),packet->size());
486 
487     packet->unref();
488     packet=nullptr;
489     return false;
490     }
491   return false;
492   }
493 
494 
process_output(FXuint stream_id,FXlong stream_length,void * outsamples,FXint nsamples)495 FXint AacDecoder::process_output(FXuint stream_id,FXlong stream_length,void * outsamples,FXint nsamples) {
496   const FXlong stream_begin = FXMAX(stream_offset_start,stream_decode_offset);
497 
498   FXint nframes = nsamples / af.channels;
499   //GM_DEBUG_PRINT("process_output %d\n",nframes);
500 
501   // trim all samples
502   if ((stream_position+nframes)<stream_begin) {
503     stream_position+=nframes;
504     return 0;
505     }
506 
507   // trim end of stream
508   if (stream_length>0 && stream_position+nframes > stream_length) {
509     nframes = FXMIN(nframes,stream_length-stream_position);
510     }
511 
512   if (use_internal_buffer) {
513     FXuchar * in = reinterpret_cast<FXuchar*>(outsamples);
514     if (stream_position<stream_begin) {
515       FXint skip_frames = FXMIN(nframes,(stream_begin-stream_position));
516       FXint nbytes = (skip_frames*af.framesize());
517       in+=nbytes;
518       nframes-=skip_frames;
519       stream_position += skip_frames;
520       }
521     while(nframes) {
522       if (out==nullptr){
523         out = context->get_output_packet();
524         if (out==nullptr) return 1;
525         out->af              = af;
526         out->stream          = stream_id;
527         out->stream_position = stream_position - stream_offset_start;
528         out->stream_length   = stream_length - stream_offset_start;
529         }
530       stream_position += out->copyFrames(in,nframes);
531       if (out->availableFrames()==0)
532         context->post_output_packet(out);
533       }
534     }
535   else {
536     stream_position+=nframes;
537     out->wroteFrames(nframes);
538     if (stream_position<stream_begin) {
539       FXint skip_frames = FXMIN(nframes,(stream_begin-stream_position));
540       out->trimBegin(af.framesize()*skip_frames);
541       }
542     if (out->availableFrames() < (nsamples / af.channels))
543       context->post_output_packet(out);
544     }
545   return 0;
546   }
547 
548 
process_raw(Packet * packet)549 FXbool AacDecoder::process_raw(Packet*packet) {
550   const FXbool eos           = packet->flags&FLAG_EOS;
551   const FXlong stream_length = packet->stream_length;
552   const FXuint stream_id     = packet->stream;
553 
554   if (stream_position==-1 && buffer.size()==0) {
555     GM_DEBUG_PRINT("[aac] stream_position %lld\n",stream_position);
556     stream_position = packet->stream_position;
557     }
558 
559   // buffer data
560   buffer.append(packet->data(),packet->size());
561   packet->unref();
562   packet=nullptr;
563 
564   // initialize the decoder
565   if (handle==nullptr) {
566 
567     long unsigned int samplerate;
568     FXuchar channels;
569 
570     // Create Decoder Instance
571     if (!create())
572       return false;
573 
574     // Init Decoder
575     long n = NeAACDecInit(handle,buffer.data(),buffer.size(),&samplerate,&channels);
576     if (n<0) {
577       buffer.clear();
578       return false;
579       }
580     else if (n>0) {
581       buffer.readBytes(n);
582       }
583 
584     af.rate = samplerate;
585     af.setChannels(channels);
586     context->post_configuration(new ConfigureEvent(af,Codec::AAC));
587     stream_position=0;
588     }
589 
590   const FXuint bytes_needed  = FAAD_MIN_STREAMSIZE*af.channels;
591   NeAACDecFrameInfo frame;
592 
593   // decode data
594   do {
595 
596     void * outsamples = nullptr;
597 
598     // done for now
599     if (buffer.size() < bytes_needed && eos == false)
600       return true;
601 
602     // get output buffer
603     if (use_internal_buffer==false && out==nullptr){
604       out = context->get_output_packet();
605       if (out==nullptr) return true;
606       out->af              = af;
607       out->stream          = stream_id;
608       out->stream_position = stream_position;
609       out->stream_length   = stream_length - stream_offset_start;
610       }
611 
612     // Looks like the decoder already takes care of stripping any encoder delay. So first call will return 0 samples.
613     if (use_internal_buffer) {
614       outsamples = NeAACDecDecode(handle,&frame,buffer.data(),buffer.size());
615       }
616     else {
617       void * outbuffer = out->ptr();
618       NeAACDecDecode2(handle,&frame,buffer.data(),buffer.size(),&outbuffer,out->availableFrames()*out->af.framesize());
619       if (frame.error == 27) {
620         GM_DEBUG_PRINT("[aac] using faad internal buffer (%d)\n",out->availableFrames()*out->af.framesize());
621         use_internal_buffer=true;
622         outsamples = NeAACDecDecode(handle,&frame,buffer.data(),buffer.size());
623         }
624       }
625 
626     if (frame.error > 0) {
627       GM_DEBUG_PRINT("[aac] error %hhu (%lu) buffer size %ld: %s\n",frame.error,frame.bytesconsumed,buffer.size(),faacDecGetErrorMessage(frame.error));
628       return false;
629       }
630 
631 
632     if (frame.bytesconsumed > 0) {
633       buffer.readBytes(frame.bytesconsumed);
634       }
635 
636     if (frame.samples==0)
637       continue;
638 
639     if (process_output(stream_id, stream_length, outsamples, frame.samples))
640       return true;
641     }
642   while( buffer.size() && frame.bytesconsumed );
643 
644 
645   if (eos) {
646     FXASSERT(stream_position==stream_length);
647     GM_DEBUG_PRINT("stream_position %ld == stream_length %ld\n",stream_position-stream_offset_start,stream_length-stream_offset_start);
648     context->post_output_packet(out,true);
649     }
650   return true;
651   }
652 
653 
process_frames(Packet * packet)654 FXbool AacDecoder::process_frames(Packet*packet) {
655   const FXbool eos           = packet->flags&FLAG_EOS;
656   const FXlong stream_length = packet->stream_length;
657   const FXuint stream_id     = packet->stream;
658   FXuchar *    framedata     = nullptr;
659   FXuint       framesize     = 0;
660   void * outsamples = nullptr;
661 
662   if (stream_position==-1) {
663     GM_DEBUG_PRINT("[aac] stream_position %ld\n",stream_position);
664     stream_position = packet->stream_position;
665     }
666 
667   while(getNextFrame(packet,framedata,framesize)) {
668 
669     NeAACDecFrameInfo frame;
670 
671     // get output buffer
672     if (use_internal_buffer==false && out==nullptr){
673       out = context->get_output_packet();
674       if (out==nullptr) {
675         if (packet) packet->unref();
676         return true;
677         }
678       out->af              = af;
679       out->stream          = stream_id;
680       out->stream_position = stream_position;
681       out->stream_length   = stream_length - stream_offset_start;
682       }
683 
684     // Looks like the decoder already takes care of stripping any encoder delay. So first call will return 0 samples.
685     if (use_internal_buffer) {
686       outsamples = NeAACDecDecode(handle,&frame,framedata,framesize);
687       }
688     else {
689       void * outbuffer = out->ptr();
690       NeAACDecDecode2(handle,&frame,framedata,framesize,&outbuffer,out->availableFrames()*out->af.framesize());
691       if (frame.error == 27) {
692         GM_DEBUG_PRINT("[aac] using faad internal buffer (%d)\n",out->availableFrames()*out->af.framesize());
693         use_internal_buffer=true;
694         outsamples = NeAACDecDecode(handle,&frame,framedata,framesize);
695         }
696       }
697 
698     if (stream_position == 0)
699       GM_DEBUG_PRINT("[aac] nframes %u\n",frame.samples/af.channels);
700 
701     if (frame.error > 0) {
702       GM_DEBUG_PRINT("[aac] fatal decoder error %hhu: %s\n",frame.error,faacDecGetErrorMessage(frame.error));
703       if (packet) packet->unref();
704       return false;
705       }
706 
707     if (frame.samplerate!=af.rate) {
708       GM_DEBUG_PRINT("[aac] mismatch samplerate\n");
709       af.rate = frame.samplerate;
710       if (out) out->af = af;
711       context->post_configuration(new ConfigureEvent(af,Codec::AAC));
712       }
713 
714     if (frame.samples==0)
715       continue;
716 
717     if (process_output(stream_id, stream_length, outsamples, frame.samples)){
718       if (packet) packet->unref();
719       return true;
720       }
721     }
722   FXASSERT(packet==nullptr);
723   if (eos) {
724     FXASSERT(stream_position==stream_length);
725     GM_DEBUG_PRINT("stream_position %ld == stream_length %ld\n",stream_position-stream_offset_start,stream_length-stream_offset_start);
726     context->post_output_packet(out,true);
727     }
728   return true;
729   }
730 
process(Packet * packet)731 FXbool AacDecoder::process(Packet*packet){
732   if (__unlikely(rawmode==true))
733     return process_raw(packet);
734   else
735     return process_frames(packet);
736   }
737 
ap_aac_decoder(DecoderContext * ctx)738 DecoderPlugin * ap_aac_decoder(DecoderContext * ctx) {
739   return new AacDecoder(ctx);
740   }
741 
742 #endif
743 }
744 
745 
746