2 * Copyright (C) 2005-2013 Team XBMC
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)
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.
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/>.
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"
30 //These values are forced to allow spdif out
31 #define OUT_SAMPLESIZE 16
32 #define OUT_CHANNELS 2
33 #define OUT_SAMPLERATE 48000
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};
39 static const uint16_t DTSFSCod [] = {0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0, 12000, 24000, 48000, 0, 0};
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;
49 CDVDAudioCodecPassthroughFFmpeg::CDVDAudioCodecPassthroughFFmpeg(void)
61 /* make enough room for at-least two audio frames */
63 m_DecodeBuffer = NULL;
64 m_bSupportsAC3Out = false;
65 m_bSupportsDTSOut = false;
66 m_bSupportsAACOut = false;
71 CDVDAudioCodecPassthroughFFmpeg::~CDVDAudioCodecPassthroughFFmpeg(void)
76 /*===================== MUXER FUNCTIONS ========================*/
77 bool CDVDAudioCodecPassthroughFFmpeg::SetupMuxer(CDVDStreamInfo &hints, CStdString muxerName, Muxer &muxer)
79 CLog::Log(LOGINFO, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - Trying to setup %s muxer", muxerName.c_str());
82 AVOutputFormat *fOut = NULL;
84 fOut = m_dllAvFormat.av_guess_format(muxerName.c_str(), NULL, NULL);
87 CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - Failed to get the FFmpeg %s muxer", muxerName.c_str());
92 /* allocate a the format context */
93 muxer.m_pFormat = m_dllAvFormat.avformat_alloc_context();
96 CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - Failed to allocate AVFormat context");
101 muxer.m_pFormat->oformat = fOut;
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)
107 CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - Failed to allocate ByteIOContext");
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;
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";
124 const char *spdifFlags = "-be";
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)
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");
137 /* add a stream to it */
138 muxer.m_pStream = m_dllAvFormat.avformat_new_stream(muxer.m_pFormat, NULL);
139 if (!muxer.m_pStream)
141 CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - Failed to allocate AVStream context");
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;
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);
163 muxer.m_WroteHeader = m_dllAvFormat.avformat_write_header(muxer.m_pFormat, NULL) == 0;
164 if (!muxer.m_WroteHeader)
166 CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - Failed to write the frame header");
170 CLog::Log(LOGINFO, "CDVDAudioCodecPassthroughFFmpeg::SetupMuxer - %s muxer ready", muxerName.c_str());
174 int CDVDAudioCodecPassthroughFFmpeg::MuxerReadPacket(void *opaque, uint8_t *buf, int buf_size)
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);
182 Muxer *muxer = (Muxer*)opaque;
183 muxer->m_OutputBuffer.push_back(packet);
184 muxer->m_OutputSize += buf_size;
186 /* return how much we wrote to our buffer */
190 void CDVDAudioCodecPassthroughFFmpeg::WriteFrame(Muxer &muxer, uint8_t *pData, int iSize)
193 m_dllAvCodec.av_init_packet(&pkt);
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");
202 int CDVDAudioCodecPassthroughFFmpeg::GetMuxerData(Muxer &muxer, uint8_t** dst)
205 if(muxer.m_OutputSize)
207 /* check if the buffer is allocated */
210 /* only re-allocate the buffer it is too small */
211 if (muxer.m_BufferSize < muxer.m_OutputSize)
213 delete[] muxer.m_Buffer;
214 muxer.m_Buffer = new uint8_t[muxer.m_OutputSize];
215 muxer.m_BufferSize = muxer.m_OutputSize;
220 /* allocate the buffer */
221 muxer.m_Buffer = new uint8_t[muxer.m_OutputSize];
222 muxer.m_BufferSize = muxer.m_OutputSize;
225 /* fill the buffer with the output data */
227 offset = muxer.m_Buffer;
228 while(!muxer.m_OutputBuffer.empty())
230 DataPacket* packet = muxer.m_OutputBuffer.front();
231 muxer.m_OutputBuffer.pop_front();
233 memcpy(offset, packet->data, packet->size);
234 offset += packet->size;
236 delete[] packet->data;
240 *dst = muxer.m_Buffer;
241 size = muxer.m_OutputSize;
242 muxer.m_OutputSize = 0;
243 muxer.m_Consumed = 0;
250 void CDVDAudioCodecPassthroughFFmpeg::ResetMuxer(Muxer &muxer)
252 muxer.m_OutputSize = 0;
253 muxer.m_Consumed = 0;
254 while(!muxer.m_OutputBuffer.empty())
256 DataPacket* packet = muxer.m_OutputBuffer.front();
257 muxer.m_OutputBuffer.pop_front();
258 delete[] packet->data;
263 void CDVDAudioCodecPassthroughFFmpeg::DisposeMuxer(Muxer &muxer)
266 delete[] muxer.m_Buffer;
267 muxer.m_Buffer = NULL;
268 muxer.m_BufferSize = 0;
271 if (muxer.m_WroteHeader)
272 m_dllAvFormat.av_write_trailer(muxer.m_pFormat);
273 muxer.m_WroteHeader = false;
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);
281 /*===================== END MUXER FUNCTIONS ========================*/
283 bool CDVDAudioCodecPassthroughFFmpeg::SupportsFormat(CDVDStreamInfo &hints)
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;
295 bool CDVDAudioCodecPassthroughFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
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);
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))
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 )
312 CLog::Log(LOGINFO, "CDVDAudioCodecPassthroughFFmpeg::Open - disabled passthrough due to video OTAS");
316 // TODO - some soundcards do support other sample rates, but they are quite uncommon
317 if( hints.samplerate > 0 && hints.samplerate != 48000 )
319 CLog::Log(LOGINFO, "CDVDAudioCodecPassthroughFFmpeg::Open - disabled passthrough due to sample rate not being 48000");
323 if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load())
326 m_dllAvFormat.av_register_all();
328 /* see if the muxer supports our codec (see spdif.c for supported formats) */
329 if (!SupportsFormat(hints))
331 CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - FFmpeg SPDIF muxer does not support this codec");
337 /* aac needs to be wrapped into ADTS frames */
338 if (hints.codec == AV_CODEC_ID_AAC)
339 if (!SetupMuxer(hints, "adts", m_ADTS))
341 CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - Unable to setup ADTS muxer");
349 if (!SetupMuxer(hints, "spdif", m_SPDIF))
354 /* we will check the first packet's crc */
357 m_codec = hints.codec;
362 void CDVDAudioCodecPassthroughFFmpeg::Dispose()
366 DisposeMuxer(m_SPDIF);
367 DisposeMuxer(m_ADTS );
371 _aligned_free(m_DecodeBuffer);
372 m_DecodeBuffer = NULL;
379 int CDVDAudioCodecPassthroughFFmpeg::Decode(uint8_t* pData, int iSize)
381 unsigned int used, fSize;
384 /* if we are muxing into ADTS (AAC) */
386 if (m_ADTS.m_pFormat)
389 WriteFrame(m_ADTS, pData, iSize);
390 iSize = GetMuxerData(m_ADTS, &pData);
396 /* skip data until we can sync and know how much we need */
399 /* if we have a sync function for this codec */
402 int skip = (this->*m_pSyncFrame)(pData, iSize, &m_Needed);
405 /* we lost sync, so invalidate our buffer */
414 if(m_SPDIF.m_pStream->codec->sample_rate != m_SampleRate)
416 CLog::Log(LOGDEBUG, "CDVDAudioCodecPassthroughFFmpeg::Decode - stream changed sample rate from %d to %d"
417 , m_SPDIF.m_pStream->codec->sample_rate
419 m_SPDIF.m_pStream->codec->sample_rate = m_SampleRate;
422 /* check for bad parsing */
423 assert(m_Needed > 0);
425 /* append one block or less of data */
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);
433 m_NeededUsed += copy;
438 /* if we have enough data in the buffer, write it out */
439 if (m_NeededUsed == m_Needed)
441 WriteFrame(m_SPDIF, m_NeededBuffer, m_Needed);
447 /* return how much data we copied */
448 if (m_ADTS.m_pFormat)
454 int CDVDAudioCodecPassthroughFFmpeg::GetData(uint8_t** dst)
456 return GetMuxerData(m_SPDIF, dst);
459 void CDVDAudioCodecPassthroughFFmpeg::Reset()
470 int CDVDAudioCodecPassthroughFFmpeg::GetChannels()
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
477 int CDVDAudioCodecPassthroughFFmpeg::GetSampleRate()
479 return m_SPDIF.m_pStream->codec->sample_rate;
482 int CDVDAudioCodecPassthroughFFmpeg::GetEncodedSampleRate()
484 return m_SPDIF.m_pStream->codec->sample_rate;
487 enum AEDataFormat CDVDAudioCodecPassthroughFFmpeg::GetDataFormat()
491 case AV_CODEC_ID_AC3: return AE_FMT_AC3;
492 case AV_CODEC_ID_DTS: return AE_FMT_DTS;
494 return AE_FMT_INVALID; //Unknown stream type
499 int CDVDAudioCodecPassthroughFFmpeg::GetBitsPerSample()
501 return OUT_SAMPLESIZE;
504 int CDVDAudioCodecPassthroughFFmpeg::GetBufferSize()
507 return m_Codec->GetBufferSize();
509 return m_SPDIF.m_Consumed + m_ADTS.m_Consumed + m_NeededUsed;
512 /* ========================== SYNC FUNCTIONS ========================== */
513 unsigned int CDVDAudioCodecPassthroughFFmpeg::SyncAC3(uint8_t* pData, unsigned int iSize, unsigned int *fSize)
515 unsigned int skip = 0;
516 for(skip = 0; iSize - skip > 6; ++skip, ++pData)
518 /* search for an ac3 sync word */
519 if(pData[0] != 0x0b || pData[1] != 0x77)
522 uint8_t fscod = pData[4] >> 6;
523 uint8_t frmsizecod = pData[4] & 0x3F;
524 uint8_t bsid = pData[5] >> 3;
526 /* sanity checks on the header */
533 /* get the details we need to check crc1 and framesize */
534 uint16_t bitrate = AC3Bitrates[frmsizecod >> 1];
535 unsigned int framesize = 0;
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;
543 *fSize = framesize * 2;
544 m_SampleRate = AC3FSCod[fscod];
546 /* dont do extensive testing if we have not lost sync */
547 if (!m_LostSync && skip == 0)
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;
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))
560 /* if we get here, we can sync */
565 /* if we get here, the entire packet is invalid and we have lost sync */
570 unsigned int CDVDAudioCodecPassthroughFFmpeg::SyncDTS(uint8_t* pData, unsigned int iSize, unsigned int *fSize)
576 for(skip = 0; iSize - skip > 8; ++skip, ++pData)
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
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)
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;
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)
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;
605 /* make sure the framesize is sane */
606 if (*fSize < 96 || *fSize > 16384)
609 m_SampleRate = DTSFSCod[srCode];
618 unsigned int CDVDAudioCodecPassthroughFFmpeg::SyncAAC(uint8_t* pData, unsigned int iSize, unsigned int *fSize)
621 for(skip = 0; iSize - skip > 5; ++skip, ++pData)
623 if (pData[0] != 0xFF || (pData[1] & 0xF0) != 0xF0)
626 *fSize = (pData[3] & 0x03) << 11 | pData[4] << 3 | (pData[5] & 0xE0) >> 5;
637 /* ========================== END SYNC FUNCTIONS ========================== */
640 CAEChannelInfo CDVDAudioCodecPassthroughFFmpeg::GetChannelMap()
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}