dvdplayer audio: feed planar formats into ae
authorRainer Hochecker <fernetmenta@online.de>
Mon, 2 Jun 2014 15:32:05 +0000 (17:32 +0200)
committerRainer Hochecker <fernetmenta@online.de>
Sun, 8 Jun 2014 12:05:06 +0000 (14:05 +0200)
xbmc/cores/dvdplayer/DVDAudio.cpp
xbmc/cores/dvdplayer/DVDAudio.h
xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h
xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h
xbmc/cores/dvdplayer/DVDPlayerAudio.cpp

index 5166b9e..46e9509 100644 (file)
@@ -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;
 }
 
index 4e22383..54c34e5 100644 (file)
@@ -87,10 +87,6 @@ public:
   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;
index 7ebf84a..a935db7 100644 (file)
@@ -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 @@ public:
    */
   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;
   }
index 6749c2e..5ba1e1b 100644 (file)
 
 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; i<planes; i++)
+      dst[i] = m_pFrame1->extended_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;
   }
 }
 
index 3946e01..9d00c3f 100644 (file)
@@ -49,15 +49,11 @@ public:
 
 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;
index cd684bc..3141a9b 100644 (file)
@@ -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<audioframe.planes; i++)
+        memset(audioframe.data[i], 0, size);
+    }
 
     if(result & DECODE_FLAG_DROP)
     {
       // keep output times in sync
-     m_dvdAudio.SetPlayingPts(m_audioClock);
+      m_dvdAudio.SetPlayingPts(m_audioClock);
     }
     else
     {