From ae7cda6629c7180430a25d834ea83ab5d9f47d77 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Mon, 2 Jun 2014 17:32:05 +0200 Subject: [PATCH] dvdplayer audio: feed planar formats into ae --- xbmc/cores/dvdplayer/DVDAudio.cpp | 128 ++--------------- xbmc/cores/dvdplayer/DVDAudio.h | 4 - .../dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h | 21 +-- .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 132 +++--------------- .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.h | 6 +- xbmc/cores/dvdplayer/DVDPlayerAudio.cpp | 14 +- 6 files changed, 56 insertions(+), 249 deletions(-) diff --git a/xbmc/cores/dvdplayer/DVDAudio.cpp b/xbmc/cores/dvdplayer/DVDAudio.cpp index 5166b9e5ce9d0..46e9509b6bf4a 100644 --- a/xbmc/cores/dvdplayer/DVDAudio.cpp +++ b/xbmc/cores/dvdplayer/DVDAudio.cpp @@ -91,33 +91,11 @@ double CPTSOutputQueue::Current(double timestamp) return m_current.pts + min(m_current.duration, (timestamp - m_current.timestamp)); } -/** \brief Reallocs the memory block pointed to by src by the size len. -* \param[in] src Pointer to a memory block. -* \param[in] len New size of the memory block. -* \exception realloc failed -* \return A pointer to the reallocated memory block. -*/ -static void* realloc_or_free(void* src, int len) throw(exception) -{ - void* new_pBuffer = realloc(src, len); - if (new_pBuffer) - return new_pBuffer; - else - { - CLog::Log(LOGERROR, "DVDAUDIO - %s : could not realloc the buffer", __FUNCTION__); - free(src); - throw exception(); - } -} - CDVDAudio::CDVDAudio(volatile bool &bStop) : m_bStop(bStop) { m_pAudioStream = NULL; m_pAudioCallback = NULL; - m_iBufferSize = 0; - m_dwPacketSize = 0; - m_pBuffer = NULL; m_bPassthrough = false; m_iBitsPerSample = 0; m_iBitrate = 0; @@ -130,8 +108,6 @@ CDVDAudio::~CDVDAudio() CSingleLock lock (m_critSection); if (m_pAudioStream) CAEFactory::FreeStream(m_pAudioStream); - - free(m_pBuffer); } bool CDVDAudio::Create(const DVDAudioFrame &audioframe, AVCodecID codec, bool needresampler) @@ -162,14 +138,12 @@ bool CDVDAudio::Create(const DVDAudioFrame &audioframe, AVCodecID codec, bool ne m_iBitsPerSample = audioframe.bits_per_sample; m_bPassthrough = audioframe.passthrough; m_channelLayout = audioframe.channel_layout; - m_dwPacketSize = m_pAudioStream->GetFrameSize(); if(m_channelLayout.Count() && m_iBitrate && m_iBitsPerSample) m_SecondsPerByte = 1.0 / (m_channelLayout.Count() * m_iBitrate * (m_iBitsPerSample>>3)); else m_SecondsPerByte = 0.0; - m_iBufferSize = 0; SetDynamicRangeCompression((long)(CMediaSettings::Get().GetCurrentVideoSettings().m_VolumeAmplification * 100)); if (m_pAudioCallback) @@ -185,11 +159,7 @@ void CDVDAudio::Destroy() if (m_pAudioStream) CAEFactory::FreeStream(m_pAudioStream); - free(m_pBuffer); - m_pBuffer = NULL; - m_dwPacketSize = 0; m_pAudioStream = NULL; - m_iBufferSize = 0; m_iBitrate = 0; m_iBitsPerSample = 0; m_bPassthrough = false; @@ -197,24 +167,28 @@ void CDVDAudio::Destroy() m_time.Flush(); } -unsigned int CDVDAudio::AddPacketsRenderer(unsigned char* data, unsigned int len, CSingleLock &lock) +unsigned int CDVDAudio::AddPackets(const DVDAudioFrame &audioframe) { + CSingleLock lock (m_critSection); + if(!m_pAudioStream) return 0; //Calculate a timeout when this definitely should be done double timeout; - timeout = DVD_SEC_TO_TIME(m_pAudioStream->GetDelay() + len * m_SecondsPerByte); + timeout = DVD_SEC_TO_TIME(m_pAudioStream->GetDelay() + audioframe.nb_frames*audioframe.framesize * m_SecondsPerByte); timeout += DVD_SEC_TO_TIME(1.0); timeout += CDVDClock::GetAbsoluteClock(); - unsigned int total = len; + unsigned int total = audioframe.nb_frames; + unsigned int frames = audioframe.nb_frames; + unsigned int offset = 0; do { - unsigned int copied = m_pAudioStream->AddData(data, len); - data += copied; - len -= copied; - if (len < m_dwPacketSize) + unsigned int copied = m_pAudioStream->AddData(audioframe.data, offset, frames); + offset += copied; + frames -= copied; + if (frames <= 0) break; if (copied == 0 && timeout < CDVDClock::GetAbsoluteClock()) @@ -228,64 +202,12 @@ unsigned int CDVDAudio::AddPacketsRenderer(unsigned char* data, unsigned int len lock.Enter(); } while (!m_bStop); - return total - len; -} - -unsigned int CDVDAudio::AddPackets(const DVDAudioFrame &audioframe) -{ - CSingleLock lock (m_critSection); - - unsigned char* data = audioframe.data; - unsigned int len = audioframe.size; - - unsigned int total = len; - unsigned int copied; - - if (m_iBufferSize > 0) // See if there are carryover bytes from the last call. need to add them 1st. - { - copied = std::min(m_dwPacketSize - m_iBufferSize % m_dwPacketSize, len); // Smaller of either the data provided or the leftover data - if(copied) - { - m_pBuffer = (uint8_t*)realloc_or_free(m_pBuffer, m_iBufferSize + copied); - memcpy(m_pBuffer + m_iBufferSize, data, copied); // Tack the caller's data onto the end of the buffer - data += copied; // Move forward in caller's data - len -= copied; // Decrease amount of data available from caller - m_iBufferSize += copied; // Increase amount of data available in buffer - } - - if(m_iBufferSize < m_dwPacketSize) // If we don't have enough data to give to the renderer, wait until next time - return copied; - - if(AddPacketsRenderer(m_pBuffer, m_iBufferSize, lock) != m_iBufferSize) - { - m_iBufferSize = 0; - CLog::Log(LOGERROR, "%s - failed to add leftover bytes to render", __FUNCTION__); - return copied; - } - - m_iBufferSize = 0; - if (!len) - return copied; // We used up all the caller's data - } - - copied = AddPacketsRenderer(data, len, lock); - data += copied; - len -= copied; - - // if we have more data left, save it for the next call to this funtion - if (len > 0 && !m_bStop) - { - m_pBuffer = (uint8_t*)realloc_or_free(m_pBuffer, len); - m_iBufferSize = len; - memcpy(m_pBuffer, data, len); - } - - double time_added = DVD_SEC_TO_TIME(m_SecondsPerByte * (data - audioframe.data)); - double delay = GetDelay(); - double timestamp = CDVDClock::GetAbsoluteClock(); + double time_added = DVD_SEC_TO_TIME(m_SecondsPerByte * audioframe.nb_frames * audioframe.framesize); + double delay = GetDelay(); + double timestamp = CDVDClock::GetAbsoluteClock(); m_time.Add(audioframe.pts, delay - time_added, audioframe.duration, timestamp); - return total; + return total - frames; } void CDVDAudio::Finish() @@ -293,21 +215,6 @@ void CDVDAudio::Finish() CSingleLock lock (m_critSection); if (!m_pAudioStream) return; - - unsigned int silence = m_dwPacketSize - m_iBufferSize % m_dwPacketSize; - - if(silence > 0 && m_iBufferSize > 0) - { - CLog::Log(LOGDEBUG, "CDVDAudio::Drain - adding %d bytes of silence, buffer size: %d, chunk size: %d", silence, m_iBufferSize, m_dwPacketSize); - m_pBuffer = (uint8_t*)realloc_or_free(m_pBuffer, m_iBufferSize + silence); - memset(m_pBuffer+m_iBufferSize, 0, silence); - m_iBufferSize += silence; - } - - if(AddPacketsRenderer(m_pBuffer, m_iBufferSize, lock) != m_iBufferSize) - CLog::Log(LOGERROR, "CDVDAudio::Drain - failed to play the final %d bytes", m_iBufferSize); - - m_iBufferSize = 0; } void CDVDAudio::Drain() @@ -377,8 +284,6 @@ double CDVDAudio::GetDelay() if(m_pAudioStream) delay = m_pAudioStream->GetDelay(); - delay += m_SecondsPerByte * m_iBufferSize; - return delay * DVD_TIME_BASE; } @@ -390,7 +295,6 @@ void CDVDAudio::Flush() { m_pAudioStream->Flush(); } - m_iBufferSize = 0; m_time.Flush(); } @@ -428,8 +332,6 @@ double CDVDAudio::GetCacheTime() if(m_pAudioStream) delay = m_pAudioStream->GetCacheTime(); - delay += m_SecondsPerByte * m_iBufferSize; - return delay; } diff --git a/xbmc/cores/dvdplayer/DVDAudio.h b/xbmc/cores/dvdplayer/DVDAudio.h index 4e223838f7107..54c34e5d938a2 100644 --- a/xbmc/cores/dvdplayer/DVDAudio.h +++ b/xbmc/cores/dvdplayer/DVDAudio.h @@ -87,10 +87,6 @@ class CDVDAudio IAEStream *m_pAudioStream; protected: CPTSOutputQueue m_time; - unsigned int AddPacketsRenderer(unsigned char* data, unsigned int len, CSingleLock &lock); - uint8_t* m_pBuffer; // should be [m_dwPacketSize] - unsigned int m_iBufferSize; - unsigned int m_dwPacketSize; CCriticalSection m_critSection; int m_iBitrate; diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h index 7ebf84aaf74b8..a935db7fd9822 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h +++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h @@ -43,10 +43,12 @@ class CDVDCodecOptions; typedef struct stDVDAudioFrame { - uint8_t* data; + uint8_t* data[16]; double pts; double duration; - unsigned int size; + unsigned int nb_frames; + unsigned int framesize; + unsigned int planes; int channel_count; int encoded_channel_count; @@ -92,22 +94,25 @@ class CDVDAudioCodec */ virtual void GetData(DVDAudioFrame &frame) { - frame.size = GetData(&frame.data); - if(frame.size == 0u) + frame.nb_frames = 0; + frame.data_format = GetDataFormat(); + frame.channel_count = GetChannels(); + frame.framesize = (CAEUtil::DataFormatToBits(frame.data_format) >> 3) * frame.channel_count; + if(frame.framesize == 0) return; + frame.nb_frames = GetData(frame.data)/frame.framesize; frame.channel_layout = GetChannelMap(); frame.channel_count = GetChannels(); + frame.planes = AE_IS_PLANAR(frame.data_format) ? frame.channel_count : 1; frame.encoded_channel_count = GetEncodedChannels(); - frame.data_format = GetDataFormat(); frame.bits_per_sample = CAEUtil::DataFormatToBits(frame.data_format); frame.sample_rate = GetSampleRate(); frame.encoded_sample_rate = GetEncodedSampleRate(); frame.passthrough = NeedPassthrough(); frame.pts = DVD_NOPTS_VALUE; // compute duration. - int n = (frame.channel_count * frame.bits_per_sample * frame.sample_rate)>>3; - if (n) - frame.duration = ((double)frame.size * DVD_TIME_BASE) / n; + if (frame.sample_rate) + frame.duration = ((double)frame.nb_frames * DVD_TIME_BASE) / frame.sample_rate; else frame.duration = 0.0; } diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp index 6749c2eba7789..5ba1e1b90f293 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp @@ -32,14 +32,8 @@ CDVDAudioCodecFFmpeg::CDVDAudioCodecFFmpeg() : CDVDAudioCodec() { - m_iBufferSize1 = 0; - m_iBufferSize2 = 0; - m_iBufferTotalSize2 = 0; - m_pBuffer2 = NULL; - m_iBuffered = 0; m_pCodecContext = NULL; - m_pConvert = NULL; m_bOpenedCodec = false; m_channels = 0; @@ -47,6 +41,7 @@ CDVDAudioCodecFFmpeg::CDVDAudioCodecFFmpeg() : CDVDAudioCodec() m_pFrame1 = NULL; m_iSampleFormat = AV_SAMPLE_FMT_NONE; + m_gotFrame = 0; } CDVDAudioCodecFFmpeg::~CDVDAudioCodecFFmpeg() @@ -113,12 +108,6 @@ void CDVDAudioCodecFFmpeg::Dispose() if (m_pFrame1) av_free(m_pFrame1); m_pFrame1 = NULL; - if (m_pConvert) - swr_free(&m_pConvert); - - if (m_pBuffer2) - av_freep(&m_pBuffer2); - if (m_pCodecContext) { if (m_bOpenedCodec) avcodec_close(m_pCodecContext); @@ -127,33 +116,26 @@ void CDVDAudioCodecFFmpeg::Dispose() m_pCodecContext = NULL; } - m_iBufferSize1 = 0; - m_iBufferSize2 = 0; - m_iBufferTotalSize2 = 0; m_iBuffered = 0; } int CDVDAudioCodecFFmpeg::Decode(uint8_t* pData, int iSize) { - int iBytesUsed, got_frame; + int iBytesUsed; if (!m_pCodecContext) return -1; - m_iBufferSize2 = 0; - AVPacket avpkt; av_init_packet(&avpkt); avpkt.data = pData; avpkt.size = iSize; iBytesUsed = avcodec_decode_audio4( m_pCodecContext , m_pFrame1 - , &got_frame + , &m_gotFrame , &avpkt); - if (iBytesUsed < 0 || !got_frame) + if (iBytesUsed < 0 || !m_gotFrame) { - m_iBufferSize1 = 0; return iBytesUsed; } - m_iBufferSize1 = m_pFrame1->nb_samples * m_pCodecContext->channels * av_get_bytes_per_sample(m_pCodecContext->sample_fmt); /* some codecs will attempt to consume more data than what we gave */ if (iBytesUsed > iSize) @@ -162,104 +144,23 @@ int CDVDAudioCodecFFmpeg::Decode(uint8_t* pData, int iSize) iBytesUsed = iSize; } - if(m_iBufferSize1 == 0 && iBytesUsed >= 0) + if(iBytesUsed >= 0) m_iBuffered += iBytesUsed; else m_iBuffered = 0; - bool convert = false; - switch(m_pCodecContext->sample_fmt) - { - case AV_SAMPLE_FMT_U8: - case AV_SAMPLE_FMT_S16: - case AV_SAMPLE_FMT_S32: - case AV_SAMPLE_FMT_FLT: - case AV_SAMPLE_FMT_DBL: - break; - case AV_SAMPLE_FMT_NONE: - CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - invalid data format"); - return -1; - default: - convert = true; - } - if(convert) - ConvertToFloat(); - return iBytesUsed; } -void CDVDAudioCodecFFmpeg::ConvertToFloat() -{ - if(m_pCodecContext->sample_fmt != AV_SAMPLE_FMT_FLT && m_iBufferSize1 > 0) - { - if(m_pConvert && (m_pCodecContext->sample_fmt != m_iSampleFormat || m_channels != m_pCodecContext->channels)) - swr_free(&m_pConvert); - - if(!m_pConvert) - { - m_iSampleFormat = m_pCodecContext->sample_fmt; - m_pConvert = swr_alloc_set_opts(NULL, - av_get_default_channel_layout(m_pCodecContext->channels), AV_SAMPLE_FMT_FLT, m_pCodecContext->sample_rate, - av_get_default_channel_layout(m_pCodecContext->channels), m_pCodecContext->sample_fmt, m_pCodecContext->sample_rate, - 0, NULL); - - if(!m_pConvert || swr_init(m_pConvert) < 0) - { - CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to convert %d to AV_SAMPLE_FMT_FLT", m_pCodecContext->sample_fmt); - m_iBufferSize1 = 0; - m_iBufferSize2 = 0; - return; - } - } - - int needed_buf_size = av_samples_get_buffer_size(NULL, m_pCodecContext->channels, m_pFrame1->nb_samples, AV_SAMPLE_FMT_FLT, 0); - if(m_iBufferTotalSize2 < needed_buf_size) - { - m_pBuffer2 = (uint8_t*)av_realloc(m_pBuffer2, needed_buf_size); - if(!m_pBuffer2) - { - CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to allocate a %i bytes buffer for resampling", needed_buf_size); - m_iBufferSize1 = 0; - m_iBufferSize2 = 0; - m_iBufferTotalSize2 = 0; - return; - } - m_iBufferTotalSize2 = needed_buf_size; - } - - int outsamples; - outsamples = swr_convert(m_pConvert, &m_pBuffer2, m_iBufferTotalSize2, (const uint8_t**)m_pFrame1->extended_data, m_pFrame1->nb_samples); - - if(outsamples < 0) - { - CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to convert %d to AV_SAMPLE_FMT_FLT", (int)m_pCodecContext->sample_fmt); - m_iBufferSize1 = 0; - m_iBufferSize2 = 0; - return; - } - - if(outsamples < m_pFrame1->nb_samples) - { - CLog::Log(LOGWARNING, "CDVDAudioCodecFFmpeg::Decode - Resampler produced less samples than what it was given"); - } - - m_iBufferSize1 = 0; - m_iBufferSize2 = m_pFrame1->nb_samples * m_pCodecContext->channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT); - } -} - int CDVDAudioCodecFFmpeg::GetData(uint8_t** dst) { - if(m_iBufferSize1) - { - *dst = m_pFrame1->data[0]; - return m_iBufferSize1; - } - - if(m_iBufferSize2) + if(m_gotFrame) { - *dst = m_pBuffer2; - return m_iBufferSize2; + int planes = av_sample_fmt_is_planar(m_pCodecContext->sample_fmt) ? m_pFrame1->channels : 1; + for (int i=0; iextended_data[i]; + m_gotFrame = 0; + return m_pFrame1->nb_samples * m_pFrame1->channels * av_get_bytes_per_sample(m_pCodecContext->sample_fmt); } return 0; @@ -268,9 +169,8 @@ int CDVDAudioCodecFFmpeg::GetData(uint8_t** dst) void CDVDAudioCodecFFmpeg::Reset() { if (m_pCodecContext) avcodec_flush_buffers(m_pCodecContext); - m_iBufferSize1 = 0; - m_iBufferSize2 = 0; m_iBuffered = 0; + m_gotFrame = 0; } int CDVDAudioCodecFFmpeg::GetChannels() @@ -290,15 +190,19 @@ enum AEDataFormat CDVDAudioCodecFFmpeg::GetDataFormat() switch(m_pCodecContext->sample_fmt) { case AV_SAMPLE_FMT_U8 : return AE_FMT_U8; + case AV_SAMPLE_FMT_U8P : return AE_FMT_U8P; case AV_SAMPLE_FMT_S16: return AE_FMT_S16NE; + case AV_SAMPLE_FMT_S16P: return AE_FMT_S16NEP; case AV_SAMPLE_FMT_S32: return AE_FMT_S32NE; + case AV_SAMPLE_FMT_S32P: return AE_FMT_S32NEP; case AV_SAMPLE_FMT_FLT: return AE_FMT_FLOAT; + case AV_SAMPLE_FMT_FLTP: return AE_FMT_FLOATP; case AV_SAMPLE_FMT_DBL: return AE_FMT_DOUBLE; + case AV_SAMPLE_FMT_DBLP: return AE_FMT_DOUBLEP; case AV_SAMPLE_FMT_NONE: + default: CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::GetDataFormat - invalid data format"); return AE_FMT_INVALID; - default: - return AE_FMT_FLOAT; } } diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h index 3946e011e5ea2..9d00c3f9ed3e4 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h +++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h @@ -49,15 +49,11 @@ class CDVDAudioCodecFFmpeg : public CDVDAudioCodec protected: AVCodecContext* m_pCodecContext; - SwrContext* m_pConvert; enum AVSampleFormat m_iSampleFormat; CAEChannelInfo m_channelLayout; AVFrame* m_pFrame1; - int m_iBufferSize1; - uint8_t* m_pBuffer2; - int m_iBufferSize2; - int m_iBufferTotalSize2; + int m_gotFrame; bool m_bOpenedCodec; int m_iBuffered; diff --git a/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp b/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp index cd684bcce122c..3141a9b2696c8 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp @@ -246,7 +246,7 @@ int CDVDPlayerAudio::DecodeFrame(DVDAudioFrame &audioframe) int result = 0; // make sure the sent frame is clean - memset(&audioframe, 0, sizeof(DVDAudioFrame)); + audioframe.nb_frames = 0; while (!m_bStop) { @@ -280,7 +280,7 @@ int CDVDPlayerAudio::DecodeFrame(DVDAudioFrame &audioframe) // get decoded data and the size of it m_pAudioCodec->GetData(audioframe); - if (audioframe.size == 0) + if (audioframe.nb_frames == 0) continue; if (audioframe.pts == DVD_NOPTS_VALUE) @@ -532,7 +532,7 @@ void CDVDPlayerAudio::Process() break; } - if( audioframe.size == 0 ) + if( audioframe.nb_frames == 0 ) continue; packetadded = true; @@ -556,12 +556,16 @@ void CDVDPlayerAudio::Process() // Zero out the frame data if we are supposed to silence the audio if (m_silence) - memset(audioframe.data, 0, audioframe.size); + { + int size = audioframe.nb_frames * audioframe.framesize * audioframe.channel_count / audioframe.planes; + for (int i=0; i