[release] version bump to 13.0 beta1
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Audio / DVDAudioCodecPassthroughFFmpeg.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "DVDAudioCodecPassthroughFFmpeg.h"
22 #include "DVDCodecs/DVDCodecs.h"
23 #include "DVDStreamInfo.h"
24 #include "cores/AudioEngine/Utils/AEUtil.h"
25 #include "settings/MediaSettings.h"
26 #include "settings/Settings.h"
27 #include "utils/log.h"
28 #include "cores/AudioEngine/AEFactory.h"
29
30 //These values are forced to allow spdif out
31 #define OUT_SAMPLESIZE 16
32 #define OUT_CHANNELS   2
33 #define OUT_SAMPLERATE 48000
34
35 /* Lookup tables */
36 static const uint16_t AC3Bitrates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640};
37 static const uint16_t AC3FSCod   [] = {48000, 44100, 32000, 0};
38
39 static const uint16_t DTSFSCod   [] = {0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0, 12000, 24000, 48000, 0, 0};
40
41 #define NULL_MUXER(muxer) \
42   muxer.m_pFormat    = NULL; \
43   muxer.m_pStream    = NULL; \
44   muxer.m_OutputSize = 0; \
45   muxer.m_Consumed   = 0; \
46   muxer.m_Buffer     = NULL; \
47   muxer.m_BufferSize = 0;
48
49 CDVDAudioCodecPassthroughFFmpeg::CDVDAudioCodecPassthroughFFmpeg(void)
50 {
51   NULL_MUXER(m_SPDIF);
52   NULL_MUXER(m_ADTS );
53
54   m_pSyncFrame   = NULL;
55   m_Needed       = 0;
56   m_NeededUsed   = 0;
57   m_SampleRate   = 0;
58
59   m_Codec        = NULL;
60
61   /* make enough room for at-least two audio frames */
62   m_DecodeSize   = 0;
63   m_DecodeBuffer = NULL;
64   m_bSupportsAC3Out = false;
65   m_bSupportsDTSOut = false;
66   m_bSupportsAACOut = false;
67   m_LostSync = false;
68   
69 }
70
71 CDVDAudioCodecPassthroughFFmpeg::~CDVDAudioCodecPassthroughFFmpeg(void)
72 {
73   Dispose();
74 }
75
76 /*===================== MUXER FUNCTIONS ========================*/
77 bool CDVDAudioCodecPassthroughFFmpeg::SetupMuxer(CDVDStreamInfo &hints, CStdString muxerName, Muxer &muxer)
78 {
79   CLog::Log(LOGINFO, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - Trying to setup %s muxer", muxerName.c_str());
80
81   /* get the muxer */
82   AVOutputFormat *fOut = NULL;
83
84   fOut = m_dllAvFormat.av_guess_format(muxerName.c_str(), NULL, NULL);
85   if (!fOut)
86   {
87     CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - Failed to get the FFmpeg %s muxer", muxerName.c_str());
88     Dispose();
89     return false;
90   }
91
92   /* allocate a the format context */
93   muxer.m_pFormat = m_dllAvFormat.avformat_alloc_context();
94   if (!muxer.m_pFormat)
95   {
96     CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - Failed to allocate AVFormat context");
97     Dispose();
98     return false;
99   }
100
101   muxer.m_pFormat->oformat = fOut;
102
103   /* allocate a put_byte struct so we can grab the output */
104   muxer.m_pFormat->pb = m_dllAvFormat.avio_alloc_context(muxer.m_BCBuffer, sizeof(muxer.m_BCBuffer), AVIO_FLAG_READ, &muxer,  NULL, MuxerReadPacket, NULL);
105   if (!muxer.m_pFormat->pb)
106   {
107     CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - Failed to allocate ByteIOContext");
108     Dispose();
109     return false;
110   }
111
112   /* this is streamed, no file, and ignore the index */
113   muxer.m_pFormat->pb->seekable      = 0;
114   muxer.m_pFormat->flags            |= AVFMT_NOFILE | AVFMT_FLAG_IGNIDX;
115   muxer.m_pFormat->bit_rate          = hints.bitrate;
116
117   /* While this is strictly only needed on big-endian systems, we do it on
118    * both to avoid as much dead code as possible.
119    * CoreAudio (at least on the cases we've seen) wants IEC 61937 in
120    * little-endian format even on big-endian systems. */
121 #if defined(WORDS_BIGENDIAN) && !defined(TARGET_DARWIN)
122   const char *spdifFlags = "+be";
123 #else
124   const char *spdifFlags = "-be";
125 #endif
126
127   /* request output of wanted endianness */
128   if (!fOut->priv_class || m_dllAvUtil.av_opt_set(muxer.m_pFormat->priv_data, "spdif_flags", spdifFlags, 0) != 0)
129   {
130 #if defined(WORDS_BIGENDIAN) && !defined(TARGET_DARWIN)
131     CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - Unable to set big-endian stream mode (FFmpeg too old?), disabling passthrough");
132     Dispose();
133     return false;
134 #endif
135   }
136
137   /* add a stream to it */
138   muxer.m_pStream = m_dllAvFormat.avformat_new_stream(muxer.m_pFormat, NULL);
139   if (!muxer.m_pStream)
140   {
141     CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - Failed to allocate AVStream context");
142     Dispose();
143     return false;
144   }
145
146
147   /* set the stream's parameters */
148   m_SampleRate = hints.samplerate;
149   if(!m_SampleRate && hints.codec == AV_CODEC_ID_AC3)
150     m_SampleRate = 48000;
151
152   AVCodecContext *codec = muxer.m_pStream->codec;
153   codec->codec_type     = AVMEDIA_TYPE_AUDIO;
154   codec->codec_id       = hints.codec;
155   codec->sample_rate    = m_SampleRate;
156   codec->sample_fmt     = AV_SAMPLE_FMT_S16;
157   codec->channels       = hints.channels;
158   codec->bit_rate       = hints.bitrate;
159   codec->extradata      = new uint8_t[hints.extrasize];
160   codec->extradata_size = hints.extrasize;
161   memcpy(codec->extradata, hints.extradata, hints.extrasize);
162
163   muxer.m_WroteHeader = m_dllAvFormat.avformat_write_header(muxer.m_pFormat, NULL) == 0;
164   if (!muxer.m_WroteHeader)
165   {
166     CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - Failed to write the frame header");
167     return false;
168   }
169
170   CLog::Log(LOGINFO, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - %s muxer ready", muxerName.c_str());
171   return true;
172 }
173
174 int CDVDAudioCodecPassthroughFFmpeg::MuxerReadPacket(void *opaque, uint8_t *buf, int buf_size)
175 {
176   /* create a new packet and push it into our output buffer */
177   DataPacket *packet = new DataPacket();
178   packet->size       = buf_size;
179   packet->data       = new uint8_t[buf_size];
180   memcpy(packet->data, buf, buf_size);
181
182   Muxer *muxer = (Muxer*)opaque;
183   muxer->m_OutputBuffer.push_back(packet);
184   muxer->m_OutputSize += buf_size;
185
186   /* return how much we wrote to our buffer */
187   return buf_size;
188 }
189
190 void CDVDAudioCodecPassthroughFFmpeg::WriteFrame(Muxer &muxer, uint8_t *pData, int iSize)
191 {
192   AVPacket pkt;
193   m_dllAvCodec.av_init_packet(&pkt);
194   pkt.data = pData;
195   pkt.size = iSize;
196
197   muxer.m_Consumed += iSize;
198   if (m_dllAvFormat.av_write_frame(muxer.m_pFormat, &pkt) < 0)
199     CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::WriteFrame - Failed to write the frame data");
200 }
201
202 int CDVDAudioCodecPassthroughFFmpeg::GetMuxerData(Muxer &muxer, uint8_t** dst)
203 {
204   int size;
205   if(muxer.m_OutputSize)
206   {
207     /* check if the buffer is allocated */
208     if (muxer.m_Buffer)
209     {
210       /* only re-allocate the buffer it is too small */
211       if (muxer.m_BufferSize < muxer.m_OutputSize)
212       {
213         delete[] muxer.m_Buffer;
214         muxer.m_Buffer = new uint8_t[muxer.m_OutputSize];
215         muxer.m_BufferSize = muxer.m_OutputSize;
216       }
217     }
218     else
219     {
220       /* allocate the buffer */
221       muxer.m_Buffer     = new uint8_t[muxer.m_OutputSize];
222       muxer.m_BufferSize = muxer.m_OutputSize;
223     }
224
225     /* fill the buffer with the output data */
226     uint8_t *offset;
227     offset = muxer.m_Buffer;
228     while(!muxer.m_OutputBuffer.empty())
229     {
230       DataPacket* packet = muxer.m_OutputBuffer.front();
231       muxer.m_OutputBuffer.pop_front();
232
233       memcpy(offset, packet->data, packet->size);
234       offset += packet->size;
235
236       delete[] packet->data;
237       delete   packet;
238     }
239
240     *dst = muxer.m_Buffer;
241     size = muxer.m_OutputSize;
242     muxer.m_OutputSize = 0;
243     muxer.m_Consumed = 0;
244     return size;
245   }
246   else
247     return 0;
248 }
249
250 void CDVDAudioCodecPassthroughFFmpeg::ResetMuxer(Muxer &muxer)
251 {
252   muxer.m_OutputSize = 0;
253   muxer.m_Consumed   = 0;
254   while(!muxer.m_OutputBuffer.empty())
255   {
256     DataPacket* packet = muxer.m_OutputBuffer.front();
257     muxer.m_OutputBuffer.pop_front();
258     delete[] packet->data;
259     delete   packet;
260   }
261 }
262
263 void CDVDAudioCodecPassthroughFFmpeg::DisposeMuxer(Muxer &muxer)
264 {
265   ResetMuxer(muxer);
266   delete[] muxer.m_Buffer;
267   muxer.m_Buffer     = NULL;
268   muxer.m_BufferSize = 0;
269   if (muxer.m_pFormat)
270   {
271     if (muxer.m_WroteHeader)
272       m_dllAvFormat.av_write_trailer(muxer.m_pFormat);
273     muxer.m_WroteHeader = false;
274     if (muxer.m_pStream)
275       delete[] muxer.m_pStream->codec->extradata;
276     m_dllAvUtil.av_freep(&muxer.m_pFormat->pb);
277     m_dllAvUtil.av_freep(&muxer.m_pFormat);
278     m_dllAvUtil.av_freep(&muxer.m_pStream);
279   }
280 }
281 /*===================== END MUXER FUNCTIONS ========================*/
282
283 bool CDVDAudioCodecPassthroughFFmpeg::SupportsFormat(CDVDStreamInfo &hints)
284 {
285   m_pSyncFrame = NULL;
286
287        if (m_bSupportsAC3Out && hints.codec == AV_CODEC_ID_AC3) m_pSyncFrame = &CDVDAudioCodecPassthroughFFmpeg::SyncAC3;
288   else if (m_bSupportsDTSOut && hints.codec == AV_CODEC_ID_DTS) m_pSyncFrame = &CDVDAudioCodecPassthroughFFmpeg::SyncDTS;
289   else if (m_bSupportsAACOut && hints.codec == AV_CODEC_ID_AAC) m_pSyncFrame = &CDVDAudioCodecPassthroughFFmpeg::SyncAAC;
290   else return false;
291
292   return true;
293 }
294
295 bool CDVDAudioCodecPassthroughFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
296 {
297   // TODO - move this stuff somewhere else
298   bool m_bSupportsAC3Out    = CAEFactory::SupportsRaw(AE_FMT_AC3);
299   bool m_bSupportsEAC3Out   = CAEFactory::SupportsRaw(AE_FMT_EAC3);
300   bool m_bSupportsDTSOut    = CAEFactory::SupportsRaw(AE_FMT_DTS);
301
302   if ((hints.codec == AV_CODEC_ID_AC3 && !m_bSupportsAC3Out) ||
303       (hints.codec == AV_CODEC_ID_EAC3 && !m_bSupportsEAC3Out) ||
304       (hints.codec == AV_CODEC_ID_DTS && !m_bSupportsDTSOut))
305   {
306     return false;
307   }
308
309   // TODO - this is only valid for video files, and should be moved somewhere else
310   if( hints.channels == 2 && CMediaSettings::Get().GetCurrentVideoSettings().m_OutputToAllSpeakers )
311   {
312     CLog::Log(LOGINFO, "CDVDAudioCodecPassthroughFFmpeg::Open - disabled passthrough due to video OTAS");
313     return false;
314   }
315
316   // TODO - some soundcards do support other sample rates, but they are quite uncommon
317   if( hints.samplerate > 0 && hints.samplerate != 48000 )
318   {
319     CLog::Log(LOGINFO, "CDVDAudioCodecPassthroughFFmpeg::Open - disabled passthrough due to sample rate not being 48000");
320     return false;
321   }
322
323   if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load())
324     return false;
325
326   m_dllAvFormat.av_register_all();
327
328   /* see if the muxer supports our codec (see spdif.c for supported formats) */
329   if (!SupportsFormat(hints))
330   {
331     CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - FFmpeg SPDIF muxer does not support this codec");
332     Dispose();
333     return false;
334   }
335   else
336   {
337     /* aac needs to be wrapped into ADTS frames */
338     if (hints.codec == AV_CODEC_ID_AAC)
339       if (!SetupMuxer(hints, "adts", m_ADTS))
340       {
341         CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - Unable to setup ADTS muxer");
342         Dispose();
343         return false;
344       }
345
346     m_Codec   = NULL;
347   }
348
349   if (!SetupMuxer(hints, "spdif", m_SPDIF))
350     return false;
351
352   Reset();
353
354   /* we will check the first packet's crc */
355   m_LostSync = true;
356
357   m_codec = hints.codec;
358
359   return true;
360 }
361
362 void CDVDAudioCodecPassthroughFFmpeg::Dispose()
363 {
364   Reset();
365
366   DisposeMuxer(m_SPDIF);
367   DisposeMuxer(m_ADTS );
368
369   if (m_DecodeBuffer)
370   {
371     _aligned_free(m_DecodeBuffer);
372     m_DecodeBuffer = NULL;
373   }
374
375   delete m_Codec;
376   m_Codec   = NULL;
377 }
378
379 int CDVDAudioCodecPassthroughFFmpeg::Decode(uint8_t* pData, int iSize)
380 {
381   unsigned int used, fSize;
382   fSize = iSize;
383
384   /* if we are muxing into ADTS (AAC) */
385   int adts_used = 0;
386   if (m_ADTS.m_pFormat)
387   {
388     adts_used = iSize;
389     WriteFrame(m_ADTS, pData, iSize);
390     iSize = GetMuxerData(m_ADTS, &pData);
391   }
392
393   used = 0;
394   while(iSize > 0)
395   {
396     /* skip data until we can sync and know how much we need */
397     if (m_Needed == 0)
398     {
399       /* if we have a sync function for this codec */
400       if (m_pSyncFrame)
401       {
402         int skip = (this->*m_pSyncFrame)(pData, iSize, &m_Needed);
403         if (skip > 0)
404         {
405           /* we lost sync, so invalidate our buffer */
406           m_NeededUsed = 0;
407           return used + skip;
408         }
409       }
410       else
411         m_Needed = iSize;
412     }
413
414     if(m_SPDIF.m_pStream->codec->sample_rate != m_SampleRate)
415     {
416      CLog::Log(LOGDEBUG, "CDVDAudioCodecPassthroughFFmpeg::Decode - stream changed sample rate from %d to %d"
417                        , m_SPDIF.m_pStream->codec->sample_rate
418                        , m_SampleRate);
419      m_SPDIF.m_pStream->codec->sample_rate = m_SampleRate;
420     }
421
422     /* check for bad parsing */
423     assert(m_Needed > 0);
424
425     /* append one block or less of data */
426     int copy;
427     int room = sizeof(m_NeededBuffer) - m_NeededUsed;
428     int need = m_Needed - m_NeededUsed;
429     copy = room  > need ? need : room;
430     copy = iSize > copy ? copy : iSize;
431     memcpy(m_NeededBuffer + m_NeededUsed, pData, copy);
432
433     m_NeededUsed += copy;
434     used         += copy;
435     iSize        -= copy;
436     pData        += copy;
437
438     /* if we have enough data in the buffer, write it out */
439     if (m_NeededUsed == m_Needed)
440     {
441       WriteFrame(m_SPDIF, m_NeededBuffer, m_Needed);
442       m_NeededUsed = 0;
443       m_Needed     = 0;
444     }
445   }
446
447   /* return how much data we copied */
448   if (m_ADTS.m_pFormat)
449     return adts_used;
450   else
451     return used;
452 }
453
454 int CDVDAudioCodecPassthroughFFmpeg::GetData(uint8_t** dst)
455 {
456   return GetMuxerData(m_SPDIF, dst);
457 }
458
459 void CDVDAudioCodecPassthroughFFmpeg::Reset()
460 {
461   m_DecodeSize = 0;
462   m_LostSync   = true;
463   m_Needed     = 0;
464   m_NeededUsed = 0;
465
466   ResetMuxer(m_SPDIF);
467   ResetMuxer(m_ADTS );
468 }
469
470 int CDVDAudioCodecPassthroughFFmpeg::GetChannels()
471 {
472   //Can't return correct channels here as this is used to keep sync.
473   //should probably have some other way to find out this
474   return 2;
475 }
476
477 int CDVDAudioCodecPassthroughFFmpeg::GetSampleRate()
478 {
479   return m_SPDIF.m_pStream->codec->sample_rate;
480 }
481
482 int CDVDAudioCodecPassthroughFFmpeg::GetEncodedSampleRate()
483 {
484   return m_SPDIF.m_pStream->codec->sample_rate;
485 }
486
487 enum AEDataFormat CDVDAudioCodecPassthroughFFmpeg::GetDataFormat()
488 {
489   switch(m_codec)
490   {
491     case AV_CODEC_ID_AC3:      return AE_FMT_AC3;
492     case AV_CODEC_ID_DTS:      return AE_FMT_DTS;
493     default:
494       return AE_FMT_INVALID; //Unknown stream type
495   }
496 }
497
498
499 int CDVDAudioCodecPassthroughFFmpeg::GetBitsPerSample()
500 {
501   return OUT_SAMPLESIZE;
502 }
503
504 int CDVDAudioCodecPassthroughFFmpeg::GetBufferSize()
505 {
506   if (m_Codec)
507     return m_Codec->GetBufferSize();
508   else
509     return m_SPDIF.m_Consumed + m_ADTS.m_Consumed + m_NeededUsed;
510 }
511
512 /* ========================== SYNC FUNCTIONS ========================== */
513 unsigned int CDVDAudioCodecPassthroughFFmpeg::SyncAC3(uint8_t* pData, unsigned int iSize, unsigned int *fSize)
514 {
515   unsigned int skip = 0;
516   for(skip = 0; iSize - skip > 6; ++skip, ++pData)
517   {
518     /* search for an ac3 sync word */
519     if(pData[0] != 0x0b || pData[1] != 0x77)
520       continue;
521  
522     uint8_t fscod      = pData[4] >> 6;
523     uint8_t frmsizecod = pData[4] & 0x3F;
524     uint8_t bsid       = pData[5] >> 3;
525
526     /* sanity checks on the header */
527     if (
528         fscod      ==   3 ||
529         frmsizecod >   37 ||
530         bsid       > 0x11
531     ) continue;
532
533     /* get the details we need to check crc1 and framesize */
534     uint16_t     bitrate   = AC3Bitrates[frmsizecod >> 1];
535     unsigned int framesize = 0;
536     switch(fscod)
537     {
538       case 0: framesize = bitrate * 2; break;
539       case 1: framesize = (320 * bitrate / 147 + (frmsizecod & 1 ? 1 : 0)); break;
540       case 2: framesize = bitrate * 4; break;
541     }
542
543     *fSize = framesize * 2;
544     m_SampleRate = AC3FSCod[fscod];
545
546     /* dont do extensive testing if we have not lost sync */
547     if (!m_LostSync && skip == 0)
548       return 0;
549
550     unsigned int crc_size;
551     /* if we have enough data, validate the entire packet, else try to validate crc2 (5/8 of the packet) */
552     if (framesize <= iSize - skip)
553          crc_size = framesize - 1;
554     else crc_size = (framesize >> 1) + (framesize >> 3) - 1;
555
556     if (crc_size <= iSize - skip)
557       if(m_dllAvUtil.av_crc(m_dllAvUtil.av_crc_get_table(AV_CRC_16_ANSI), 0, &pData[2], crc_size * 2))
558         continue;
559
560     /* if we get here, we can sync */
561     m_LostSync = false;
562     return skip;
563   }
564
565   /* if we get here, the entire packet is invalid and we have lost sync */
566   m_LostSync = true;
567   return iSize;
568 }
569
570 unsigned int CDVDAudioCodecPassthroughFFmpeg::SyncDTS(uint8_t* pData, unsigned int iSize, unsigned int *fSize)
571 {
572   unsigned int skip;
573   unsigned int srCode;
574   bool littleEndian;
575
576   for(skip = 0; iSize - skip > 8; ++skip, ++pData)
577   {
578     /* 16bit le */ if (pData[0] == 0x7F && pData[1] == 0xFE && pData[2] == 0x80 && pData[3] == 0x01                                                 ) littleEndian = true ; else
579     /* 14bit le */ if (pData[0] == 0x1F && pData[1] == 0xFF && pData[2] == 0xE8 && pData[3] == 0x00 && pData[4] == 0x07 && (pData[5] & 0xF0) == 0xF0) littleEndian = true ; else
580     /* 16bit be */ if (pData[1] == 0x7F && pData[0] == 0xFE && pData[3] == 0x80 && pData[2] == 0x01                                                 ) littleEndian = false; else
581     /* 14bit be */ if (pData[1] == 0x1F && pData[0] == 0xFF && pData[3] == 0xE8 && pData[2] == 0x00 && pData[5] == 0x07 && (pData[4] & 0xF0) == 0xF0) littleEndian = false; else
582       continue;
583
584     if (littleEndian)
585     {
586       /* if it is not a termination frame, check the next 6 bits are set */
587       if ((pData[4] & 0x80) == 0x80 && (pData[4] & 0x7C) != 0x7C)
588         continue;
589
590       /* get the frame size */
591       *fSize = ((((pData[5] & 0x3) << 8 | pData[6]) << 4) | ((pData[7] & 0xF0) >> 4)) + 1;
592       srCode = (pData[8] & 0x3C) >> 2;
593    }
594    else
595    {
596       /* if it is not a termination frame, check the next 6 bits are set */
597       if ((pData[5] & 0x80) == 0x80 && (pData[5] & 0x7C) != 0x7C)
598         continue;
599
600       /* get the frame size */
601       *fSize = ((((pData[4] & 0x3) << 8 | pData[7]) << 4) | ((pData[6] & 0xF0) >> 4)) + 1;
602       srCode = (pData[9] & 0x3C) >> 2;
603    }
604
605     /* make sure the framesize is sane */
606     if (*fSize < 96 || *fSize > 16384)
607       continue;
608
609     m_SampleRate = DTSFSCod[srCode];
610     m_LostSync = false;
611     return skip;
612   }
613
614   m_LostSync = true;
615   return iSize;
616 }
617
618 unsigned int CDVDAudioCodecPassthroughFFmpeg::SyncAAC(uint8_t* pData, unsigned int iSize, unsigned int *fSize)
619 {
620   unsigned int skip;
621   for(skip = 0; iSize - skip > 5; ++skip, ++pData)
622   {
623     if (pData[0] != 0xFF || (pData[1] & 0xF0) != 0xF0)
624       continue;
625
626     *fSize = (pData[3] & 0x03) << 11 | pData[4] << 3 | (pData[5] & 0xE0) >> 5;
627     if (*fSize < 7)
628       continue;
629
630     m_LostSync = false;
631     return skip;
632   }
633
634   m_LostSync = true;
635   return iSize;
636 }
637 /* ========================== END SYNC FUNCTIONS ========================== */
638
639
640 CAEChannelInfo CDVDAudioCodecPassthroughFFmpeg::GetChannelMap()
641 {
642   static enum AEChannel map[2][9] = {
643     {AE_CH_RAW, AE_CH_RAW, AE_CH_NULL},
644     {AE_CH_RAW, AE_CH_RAW, AE_CH_RAW, AE_CH_RAW, AE_CH_RAW, AE_CH_RAW, AE_CH_RAW, AE_CH_RAW, AE_CH_NULL}
645   };
646
647   return map[0];
648 }