Exemplo n.º 1
0
unsigned int CAESinkPi::AddPackets(uint8_t **data, unsigned int frames, unsigned int offset)
{
  if (!m_Initialized || !m_omx_output || !frames)
  {
    Sleep(10);
    return frames;
  }
  OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
  OMX_BUFFERHEADERTYPE *omx_buffer = NULL;

  unsigned int channels    = m_format.m_channelLayout.Count();
  unsigned int sample_size = CAEUtil::DataFormatToBits(m_format.m_dataFormat) >> 3;
  const int planes = AE_IS_PLANAR(m_format.m_dataFormat) ? channels : 1;
  const int chans  = AE_IS_PLANAR(m_format.m_dataFormat) ? 1 : channels;
  const int pitch  = chans * sample_size;

  AEDelayStatus status;
  GetDelay(status);
  double delay = status.GetDelay();
  if (delay <= 0.0 && m_submitted)
    CLog::Log(LOGNOTICE, "%s:%s Underrun (delay:%.2f frames:%d)", CLASSNAME, __func__, delay, frames);

  omx_buffer = m_omx_output->GetInputBuffer(1000);
  if (omx_buffer == NULL)
  {
    CLog::Log(LOGERROR, "CAESinkPi::AddPackets timeout");
    return 0;
  }

  omx_buffer->nFilledLen = frames * m_format.m_frameSize;
  // must be true
  assert(omx_buffer->nFilledLen <= omx_buffer->nAllocLen);
  omx_buffer->nTimeStamp = ToOMXTime(0);
  omx_buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;

  if (omx_buffer->nFilledLen)
  {
    int planesize = omx_buffer->nFilledLen / planes;
    for (int i=0; i < planes; i++)
      memcpy((uint8_t *)omx_buffer->pBuffer + i * planesize, data[i] + offset * pitch, planesize);
  }
  omx_err = m_omx_output->EmptyThisBuffer(omx_buffer);
  if (omx_err != OMX_ErrorNone)
  {
    CLog::Log(LOGERROR, "%s:%s frames=%d err=%x", CLASSNAME, __func__, frames, omx_err);
    m_omx_output->DecoderEmptyBufferDone(m_omx_output->GetComponent(), omx_buffer);
  }
  m_submitted++;
  GetDelay(status);
  delay = status.GetDelay();
  if (delay > m_latency)
    Sleep((int)(1000.0f * (delay - m_latency)));
  return frames;
}
Exemplo n.º 2
0
AVSampleFormat CAEUtil::GetAVSampleFormat(AEDataFormat format)
{
  switch (format)
  {
    case AEDataFormat::AE_FMT_U8:
      return AV_SAMPLE_FMT_U8;
    case AEDataFormat::AE_FMT_S16NE:
      return AV_SAMPLE_FMT_S16;
    case AEDataFormat::AE_FMT_S32NE:
      return AV_SAMPLE_FMT_S32;
    case AEDataFormat::AE_FMT_S24NE4:
      return AV_SAMPLE_FMT_S32;
    case AEDataFormat::AE_FMT_S24NE4MSB:
      return AV_SAMPLE_FMT_S32;
    case AEDataFormat::AE_FMT_S24NE3:
      return AV_SAMPLE_FMT_S32;
    case AEDataFormat::AE_FMT_FLOAT:
      return AV_SAMPLE_FMT_FLT;
    case AEDataFormat::AE_FMT_DOUBLE:
      return AV_SAMPLE_FMT_DBL;
    case AEDataFormat::AE_FMT_U8P:
      return AV_SAMPLE_FMT_U8P;
    case AEDataFormat::AE_FMT_S16NEP:
      return AV_SAMPLE_FMT_S16P;
    case AEDataFormat::AE_FMT_S32NEP:
      return AV_SAMPLE_FMT_S32P;
    case AEDataFormat::AE_FMT_S24NE4P:
      return AV_SAMPLE_FMT_S32P;
    case AEDataFormat::AE_FMT_S24NE4MSBP:
      return AV_SAMPLE_FMT_S32P;
    case AEDataFormat::AE_FMT_S24NE3P:
      return AV_SAMPLE_FMT_S32P;
    case AEDataFormat::AE_FMT_FLOATP:
      return AV_SAMPLE_FMT_FLTP;
    case AEDataFormat::AE_FMT_DOUBLEP:
      return AV_SAMPLE_FMT_DBLP;
    case AEDataFormat::AE_FMT_RAW:
      return AV_SAMPLE_FMT_U8;
    default:
    {
      if (AE_IS_PLANAR(format))
        return AV_SAMPLE_FMT_FLTP;
      else
        return AV_SAMPLE_FMT_FLT;
    }
  }
}
Exemplo n.º 3
0
bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device)
{
  // This may be called before Application calls g_RBP.Initialise, so call it here too
  g_RBP.Initialize();

  /* if we are raw need to let gpu know */
  m_passthrough = format.m_dataFormat == AE_FMT_RAW;

  m_initDevice = device;
  m_initFormat = format;

  m_latency = CServiceBroker::GetSettings().GetInt("audiooutput.latency") * 1e-3;
  m_latency = std::max(m_latency, 50e-3);

  if (m_passthrough || CServiceBroker::GetSettings().GetString(CSettings::SETTING_AUDIOOUTPUT_AUDIODEVICE) == "PI:HDMI")
    m_output = AESINKPI_HDMI;
  else if (CServiceBroker::GetSettings().GetString(CSettings::SETTING_AUDIOOUTPUT_AUDIODEVICE) == "PI:Analogue")
    m_output = AESINKPI_ANALOGUE;
  else if (CServiceBroker::GetSettings().GetString(CSettings::SETTING_AUDIOOUTPUT_AUDIODEVICE) == "PI:Both")
    m_output = AESINKPI_BOTH;
  else assert(0);

  // analogue only supports stereo
  if (m_output == AESINKPI_ANALOGUE || m_output == AESINKPI_BOTH)
    format.m_channelLayout = AE_CH_LAYOUT_2_0;

  // setup for a 50ms sink feed from SoftAE
  if (format.m_dataFormat != AE_FMT_FLOATP && format.m_dataFormat != AE_FMT_FLOAT &&
      format.m_dataFormat != AE_FMT_S32NE && format.m_dataFormat != AE_FMT_S32NEP && format.m_dataFormat != AE_FMT_S32LE &&
      format.m_dataFormat != AE_FMT_S16NE && format.m_dataFormat != AE_FMT_S16NEP && format.m_dataFormat != AE_FMT_S16LE)
    format.m_dataFormat = AE_FMT_S16LE;
  unsigned int channels    = format.m_channelLayout.Count();
  unsigned int sample_size = CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3;
  format.m_frameSize     = sample_size * channels;
  format.m_sampleRate    = std::max(8000U, std::min(192000U, format.m_sampleRate));
  format.m_frames        = format.m_sampleRate * m_latency / NUM_OMX_BUFFERS;

  m_format = format;
  m_sinkbuffer_sec_per_byte = 1.0 / (double)(m_format.m_frameSize * m_format.m_sampleRate);

  CLog::Log(LOGDEBUG, "%s:%s Format:%d Channels:%d Samplerate:%d framesize:%d bufsize:%d bytes/s=%.2f dest=%s", CLASSNAME, __func__,
                m_format.m_dataFormat, channels, m_format.m_sampleRate, m_format.m_frameSize, m_format.m_frameSize * m_format.m_frames, 1.0/m_sinkbuffer_sec_per_byte,
                CServiceBroker::GetSettings().GetString(CSettings::SETTING_AUDIOOUTPUT_AUDIODEVICE).c_str());

  // magic value used when omxplayer is playing - want sink to be disabled
  if (m_passthrough && m_format.m_streamInfo.m_sampleRate == 16000)
    return true;

  SetAudioProps(m_passthrough, GetChannelMap(m_format.m_channelLayout, m_passthrough));

  OMX_ERRORTYPE omx_err   = OMX_ErrorNone;

  if (!m_omx_render.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
    CLog::Log(LOGERROR, "%s::%s - m_omx_render.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err);

  if (m_output == AESINKPI_BOTH)
  {
    if (!m_omx_splitter.Initialize("OMX.broadcom.audio_splitter", OMX_IndexParamAudioInit))
      CLog::Log(LOGERROR, "%s::%s - m_omx_splitter.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
    if (!m_omx_render_slave.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
      CLog::Log(LOGERROR, "%s::%s - m_omx_render.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
    m_omx_output = &m_omx_splitter;
  }
  else
    m_omx_output = &m_omx_render;

  SetAudioDest();

  OMX_INIT_STRUCTURE(m_pcm_input);
  m_pcm_input.eNumData              = OMX_NumericalDataSigned;
  m_pcm_input.eEndian               = OMX_EndianLittle;
  m_pcm_input.bInterleaved          = OMX_TRUE;
  m_pcm_input.nBitPerSample         = sample_size * 8;
  // 0x8000 = float, 0x10000 = planar
  uint32_t flags = 0;
  if (m_format.m_dataFormat == AE_FMT_FLOAT || m_format.m_dataFormat == AE_FMT_FLOATP)
   flags |= 0x8000;
  if (AE_IS_PLANAR(m_format.m_dataFormat))
   flags |= 0x10000;
  m_pcm_input.ePCMMode              = flags == 0 ? OMX_AUDIO_PCMModeLinear : (OMX_AUDIO_PCMMODETYPE)flags;
  m_pcm_input.nChannels             = channels;
  m_pcm_input.nSamplingRate         = m_format.m_sampleRate;

  if ( m_omx_splitter.IsInitialized() )
  {
    m_pcm_input.nPortIndex = m_omx_splitter.GetInputPort();
    omx_err = m_omx_splitter.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
    if (omx_err != OMX_ErrorNone)
      CLog::Log(LOGERROR, "%s::%s - error m_omx_splitter SetParameter in omx_err(0x%08x)", CLASSNAME, __func__, omx_err);

    m_pcm_input.nPortIndex = m_omx_splitter.GetOutputPort();
    omx_err = m_omx_splitter.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
    if(omx_err != OMX_ErrorNone)
      CLog::Log(LOGERROR, "%s::%s - error m_omx_splitter SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);

    m_pcm_input.nPortIndex = m_omx_splitter.GetOutputPort() + 1;
    omx_err = m_omx_splitter.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
    if(omx_err != OMX_ErrorNone)
      CLog::Log(LOGERROR, "%s::%s - error m_omx_splitter SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
  }

  if ( m_omx_render_slave.IsInitialized() )
  {
    m_pcm_input.nPortIndex = m_omx_render_slave.GetInputPort();
    omx_err = m_omx_render_slave.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
    if (omx_err != OMX_ErrorNone)
      CLog::Log(LOGERROR, "%s::%s - error m_omx_render_slave SetParameter in omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
  }

  if ( m_omx_render.IsInitialized() )
  {
    m_pcm_input.nPortIndex = m_omx_render.GetInputPort();
    omx_err = m_omx_render.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
    if (omx_err != OMX_ErrorNone)
      CLog::Log(LOGERROR, "%s::%s - error m_omx_render SetParameter in omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
  }

  if ( m_omx_output->IsInitialized() )
  {
    // set up the number/size of buffers for decoder input
    OMX_PARAM_PORTDEFINITIONTYPE port_param;
    OMX_INIT_STRUCTURE(port_param);
    port_param.nPortIndex = m_omx_output->GetInputPort();

    omx_err = m_omx_output->GetParameter(OMX_IndexParamPortDefinition, &port_param);
    if (omx_err != OMX_ErrorNone)
      CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);

    port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)NUM_OMX_BUFFERS);
    port_param.nBufferSize = ALIGN_UP(m_format.m_frameSize * m_format.m_frames, port_param.nBufferAlignment);

    omx_err = m_omx_output->SetParameter(OMX_IndexParamPortDefinition, &port_param);
    if (omx_err != OMX_ErrorNone)
      CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);

    omx_err = m_omx_output->AllocInputBuffers();
    if (omx_err != OMX_ErrorNone)
      CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err);
  }

  if ( m_omx_splitter.IsInitialized() )
  {
    m_omx_tunnel_splitter.Initialize(&m_omx_splitter, m_omx_splitter.GetOutputPort(), &m_omx_render, m_omx_render.GetInputPort());
    omx_err = m_omx_tunnel_splitter.Establish();
    if (omx_err != OMX_ErrorNone)
    {
      CLog::Log(LOGERROR, "COMXAudio::Initialize - Error m_omx_tunnel_splitter.Establish 0x%08x", omx_err);
      return false;
    }

    m_omx_tunnel_splitter_slave.Initialize(&m_omx_splitter, m_omx_splitter.GetOutputPort() + 1, &m_omx_render_slave, m_omx_render_slave.GetInputPort());
    omx_err = m_omx_tunnel_splitter_slave.Establish();
    if (omx_err != OMX_ErrorNone)
    {
      CLog::Log(LOGERROR, "COMXAudio::Initialize - Error m_omx_tunnel_splitter_slave.Establish 0x%08x", omx_err);
      return false;
    }
  }

  if ( m_omx_splitter.IsInitialized() )
  {
    omx_err = m_omx_splitter.SetStateForComponent(OMX_StateExecuting);
    if (omx_err != OMX_ErrorNone)
      CLog::Log(LOGERROR, "%s:%s - m_omx_splitter OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
  }
  if ( m_omx_render.IsInitialized() )
  {
    omx_err = m_omx_render.SetStateForComponent(OMX_StateExecuting);
    if (omx_err != OMX_ErrorNone)
      CLog::Log(LOGERROR, "%s:%s - m_omx_render OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
  }
  if ( m_omx_render_slave.IsInitialized() )
  {
    omx_err = m_omx_render_slave.SetStateForComponent(OMX_StateExecuting);
    if (omx_err != OMX_ErrorNone)
      CLog::Log(LOGERROR, "%s:%s - m_omx_render_slave OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
  }

  m_Initialized = true;
  return true;
}