Esempio n. 1
0
bool OMXPlayerAudio::Open(COMXStreamInfo& hints, OMXClock *av_clock, OMXReader *omx_reader,
                          std::string device, bool passthrough, bool hw_decode,
                          bool boost_on_downmix, bool use_thread)
{
	if(ThreadHandle())
	{
		Close();
	}

	if (!av_clock)
	{
		return false;
	}


	m_hints       = hints;
	m_av_clock    = av_clock;
	m_omx_reader  = omx_reader;
	m_device      = device;
	m_passthrough = COMXAudio::ENCODED_NONE;
	m_hw_decode   = false;
	m_use_passthrough = passthrough;
	m_use_hw_decode   = hw_decode;
	m_boost_on_downmix = boost_on_downmix;
	m_iCurrentPts = DVD_NOPTS_VALUE;
	m_bAbort      = false;
	m_use_thread  = use_thread;
	m_flush       = false;
	m_cached_size = 0;
	m_pAudioCodec = NULL;
	m_pChannelMap = NULL;
	m_speed       = DVD_PLAYSPEED_NORMAL;

// m_av_clock->SetMasterClock(false);

	m_player_error = OpenAudioCodec();
	if(!m_player_error)
	{
		Close();
		return false;
	}

	m_player_error = OpenDecoder();
	if(!m_player_error)
	{
		Close();
		return false;
	}

	if(m_use_thread)
	{
		Create();
	}

	m_open        = true;

	return true;
}
Esempio n. 2
0
bool OMXPlayerAudio::Open(COMXStreamInfo &hints, OMXClock *av_clock, OMXReader *omx_reader,
                          std::string device, bool passthrough, bool hw_decode,
                          bool boost_on_downmix, bool use_thread, bool is_live, enum PCMLayout layout, float queue_size, float fifo_size)
{
  if(ThreadHandle())
    Close();

  if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load() || !av_clock)
    return false;
  
  m_dllAvFormat.av_register_all();

  m_hints       = hints;
  m_av_clock    = av_clock;
  m_omx_reader  = omx_reader;
  m_device      = device;
  m_passthrough = false;
  m_hw_decode   = false;
  m_use_passthrough = passthrough;
  m_use_hw_decode   = hw_decode;
  m_boost_on_downmix = boost_on_downmix;
  m_iCurrentPts = DVD_NOPTS_VALUE;
  m_bAbort      = false;
  m_use_thread  = use_thread;
  m_flush       = false;
  m_flush_requested = false;
  m_live        = is_live;
  m_layout      = layout;
  m_cached_size = 0;
  m_pAudioCodec = NULL;
  if (queue_size != 0.0)
    m_max_data_size = queue_size * 1024 * 1024;
  if (fifo_size != 0.0)
    m_fifo_size = fifo_size;

  m_player_error = OpenAudioCodec();
  if(!m_player_error)
  {
    Close();
    return false;
  }

  m_player_error = OpenDecoder();
  if(!m_player_error)
  {
    Close();
    return false;
  }

  if(m_use_thread)
    Create();

  m_open        = true;

  return true;
}
Esempio n. 3
0
/*****************************************************************************
 * InitAudioDec: initialize audio decoder
 *****************************************************************************
 * The avcodec codec will be opened, some memory allocated.
 *****************************************************************************/
int InitAudioDec( decoder_t *p_dec, AVCodecContext *p_context,
                  const AVCodec *p_codec )
{
    decoder_sys_t *p_sys;

    /* Allocate the memory needed to store the decoder's structure */
    if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
    {
        return VLC_ENOMEM;
    }

    p_sys->p_decoded = NULL;
    p_sys->pp_decoded_last = &p_sys->p_decoded;

    p_context->refcounted_frames = true;
    p_sys->p_context = p_context;
    p_sys->p_codec = p_codec;
    p_sys->b_delayed_open = true;

    // Initialize decoder extradata
    InitDecoderConfig( p_dec, p_context);

    /* ***** Open the codec ***** */
    if( OpenAudioCodec( p_dec ) < 0 )
    {
        free( p_sys );
        return VLC_EGENERIC;
    }

    p_sys->i_reject_count = 0;
    p_sys->b_extract = false;
    p_sys->i_previous_channels = 0;
    p_sys->i_previous_layout = 0;

    /* */
    p_dec->fmt_out.i_cat = AUDIO_ES;
    /* Try to set as much information as possible but do not trust it */
    SetupOutputFormat( p_dec, false );

    date_Set( &p_sys->end_date, VLC_TS_INVALID );
    if( !p_dec->fmt_out.audio.i_rate )
        p_dec->fmt_out.audio.i_rate = p_dec->fmt_in.audio.i_rate;
    if( p_dec->fmt_out.audio.i_rate )
        date_Init( &p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1 );

    p_dec->pf_decode_audio = DecodeAudio;
    p_dec->pf_flush        = Flush;
    return VLC_SUCCESS;
}
Esempio n. 4
0
bool OMXPlayerAudio::Open(OMXClock *av_clock, const OMXAudioConfig &config, OMXReader *omx_reader)
{
    if(ThreadHandle())
        Close();

    if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load() || !av_clock)
        return false;

    m_dllAvFormat.av_register_all();

    m_config      = config;
    m_av_clock    = av_clock;
    m_omx_reader  = omx_reader;
    m_passthrough = false;
    m_hw_decode   = false;
    m_iCurrentPts = DVD_NOPTS_VALUE;
    m_bAbort      = false;
    m_flush       = false;
    m_flush_requested = false;
    m_cached_size = 0;
    m_pAudioCodec = NULL;

    m_player_error = OpenAudioCodec();
    if(!m_player_error)
    {
        Close();
        return false;
    }

    m_player_error = OpenDecoder();
    if(!m_player_error)
    {
        Close();
        return false;
    }

    if(m_config.use_thread)
        Create();

    m_open        = true;

    return true;
}
Esempio n. 5
0
bool OMXPlayerAudio::Decode(OMXPacket *pkt)
{
  if(!pkt)
    return false;

  /* last decoder reinit went wrong */
  if(!m_decoder || !m_pAudioCodec)
    return true;

  if(!m_omx_reader->IsActive(OMXSTREAM_AUDIO, pkt->stream_index))
    return true; 

  int channels = pkt->hints.channels;

  /* 6 channel have to be mapped to 8 for PCM */
  if(!m_passthrough && !m_hw_decode)
  {
    if(channels == 6)
      channels = 8;
  }
 
  unsigned int old_bitrate = m_hints.bitrate;
  unsigned int new_bitrate = pkt->hints.bitrate;

  /* only check bitrate changes on CODEC_ID_DTS, CODEC_ID_AC3, CODEC_ID_EAC3 */
  if(m_hints.codec != CODEC_ID_DTS && m_hints.codec != CODEC_ID_AC3 && m_hints.codec != CODEC_ID_EAC3)
  {
    new_bitrate = old_bitrate = 0;
  }

  /* audio codec changed. reinit device and decoder */
  if(m_hints.codec         != pkt->hints.codec ||
     m_hints.channels      != channels ||
     m_hints.samplerate    != pkt->hints.samplerate ||
     old_bitrate           != new_bitrate ||
     m_hints.bitspersample != pkt->hints.bitspersample)
  {
    ofLog(OF_LOG_VERBOSE, "C : %d %d %d %d %d\n", m_hints.codec, m_hints.channels, m_hints.samplerate, m_hints.bitrate, m_hints.bitspersample);
     ofLog(OF_LOG_VERBOSE, "N : %d %d %d %d %d\n", pkt->hints.codec, channels, pkt->hints.samplerate, pkt->hints.bitrate, pkt->hints.bitspersample);


    CloseDecoder();
    CloseAudioCodec();

    m_hints = pkt->hints;

    m_player_error = OpenAudioCodec();
    if(!m_player_error)
      return false;

    m_player_error = OpenDecoder();
    if(!m_player_error)
      return false;

    m_av_clock->OMXStateExecute();
    m_av_clock->OMXReset();
    m_av_clock->OMXResume();

  }

  if(!((int)m_decoder->GetSpace() > pkt->size))
    OMXClock::OMXSleep(10);

  if((int)m_decoder->GetSpace() > pkt->size)
  {
	  if(pkt->pts != DVD_NOPTS_VALUE)
		  m_iCurrentPts = pkt->pts;
	  else if(pkt->dts != DVD_NOPTS_VALUE)
		  m_iCurrentPts = pkt->dts;

    const uint8_t *data_dec = pkt->data;
    int            data_len = pkt->size;

    if(!m_passthrough && !m_hw_decode)
    {
      while(data_len > 0)
      {
        int len = m_pAudioCodec->Decode((BYTE *)data_dec, data_len);
        if( (len < 0) || (len >  data_len) )
        {
          m_pAudioCodec->Reset();
          break;
        }

        data_dec+= len;
        data_len -= len;

        uint8_t *decoded;
        int decoded_size = m_pAudioCodec->GetData(&decoded);

        if(decoded_size <=0)
          continue;

        int ret = 0;

        ret = m_decoder->AddPackets(decoded, decoded_size, pkt->dts, pkt->pts);

        if(ret != decoded_size)
        {
          ofLog(OF_LOG_VERBOSE, "error ret %d decoded_size %d\n", ret, decoded_size);
        }
      }
    }
    else
    {
		m_decoder->AddPackets(pkt->data, pkt->size, pkt->dts, pkt->pts);
    }
    return true;
  }
  else
  {
    return false;
  }
}
bool OMXPlayerAudio::Decode(OMXPacket *pkt)
{
  if(!pkt)
    return false;

  /* last decoder reinit went wrong */
  if(!m_decoder || !m_pAudioCodec)
    return true;

  if(!m_omx_reader->IsActive(OMXSTREAM_AUDIO, pkt->stream_index))
    return true; 

  int channels = pkt->hints.channels;

  unsigned int old_bitrate = m_hints.bitrate;
  unsigned int new_bitrate = pkt->hints.bitrate;

  /* only check bitrate changes on CODEC_ID_DTS, CODEC_ID_AC3, CODEC_ID_EAC3 */
  if(m_hints.codec != CODEC_ID_DTS && m_hints.codec != CODEC_ID_AC3 && m_hints.codec != CODEC_ID_EAC3)
  {
    new_bitrate = old_bitrate = 0;
  }

  /* audio codec changed. reinit device and decoder */
  if(m_hints.codec         != pkt->hints.codec ||
     m_hints.channels      != channels ||
     m_hints.samplerate    != pkt->hints.samplerate ||
     old_bitrate           != new_bitrate ||
     m_hints.bitspersample != pkt->hints.bitspersample)
  {
    printf("C : %d %d %d %d %d\n", m_hints.codec, m_hints.channels, m_hints.samplerate, m_hints.bitrate, m_hints.bitspersample);
    printf("N : %d %d %d %d %d\n", pkt->hints.codec, channels, pkt->hints.samplerate, pkt->hints.bitrate, pkt->hints.bitspersample);

    m_av_clock->OMXPause();

    CloseDecoder();
    CloseAudioCodec();

    m_hints = pkt->hints;

    m_player_error = OpenAudioCodec();
    if(!m_player_error)
      return false;

    m_player_error = OpenDecoder();
    if(!m_player_error)
      return false;

    m_av_clock->OMXStateExecute();
    m_av_clock->OMXReset();
    m_av_clock->OMXResume();

  }

  if(!((int)m_decoder->GetSpace() > pkt->size))
    OMXClock::OMXSleep(10);

  if((int)m_decoder->GetSpace() > pkt->size)
  {
    if(pkt->dts != DVD_NOPTS_VALUE)
      m_iCurrentPts = pkt->dts;

    m_av_clock->SetPTS(m_iCurrentPts);

    const uint8_t *data_dec = pkt->data;
    int            data_len = pkt->size;

    if(!m_passthrough && !m_hw_decode)
    {
      while(data_len > 0)
      {
        int len = m_pAudioCodec->Decode((BYTE *)data_dec, data_len);
        if( (len < 0) || (len >  data_len) )
        {
          m_pAudioCodec->Reset();
          break;
        }

        data_dec+= len;
        data_len -= len;

        uint8_t *decoded;
        int decoded_size = m_pAudioCodec->GetData(&decoded);

        if(decoded_size <=0)
          continue;

        int ret = 0;

        if(m_bMpeg)
          ret = m_decoder->AddPackets(decoded, decoded_size, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE);
        else
          ret = m_decoder->AddPackets(decoded, decoded_size, m_iCurrentPts, m_iCurrentPts);

        if(ret != decoded_size)
        {
          printf("error ret %d decoded_size %d\n", ret, decoded_size);
        }

        int n = (m_hints.channels * 32 * m_hints.samplerate)>>3;
        if (n > 0 && m_iCurrentPts != DVD_NOPTS_VALUE)
          m_iCurrentPts += ((double)decoded_size * DVD_TIME_BASE) / n;

        HandleSyncError((((double)decoded_size * DVD_TIME_BASE) / n), m_iCurrentPts);
      }
    }
    else
    {
      if(m_bMpeg)
        m_decoder->AddPackets(pkt->data, pkt->size, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE);
      else
        m_decoder->AddPackets(pkt->data, pkt->size, m_iCurrentPts, m_iCurrentPts);

      HandleSyncError(0, m_iCurrentPts);
    }

    m_av_clock->SetAudioClock(m_iCurrentPts);
    return true;
  }
bool OMXPlayerAudio::Open(COMXStreamInfo &hints, OMXClock *av_clock, OMXReader *omx_reader,
                          std::string device, bool passthrough, long initialVolume, bool hw_decode,
                          bool boost_on_downmix, bool use_thread, float queue_size, float fifo_size)
{
  if(ThreadHandle())
    Close();

  if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load() || !av_clock)
    return false;
  
  m_dllAvFormat.av_register_all();

  m_hints       = hints;
  m_av_clock    = av_clock;
  m_omx_reader  = omx_reader;
  m_device      = device;
  m_passthrough = IAudioRenderer::ENCODED_NONE;
  m_hw_decode   = false;
  m_use_passthrough = passthrough;
  m_use_hw_decode   = hw_decode;
  m_boost_on_downmix = boost_on_downmix;
  m_iCurrentPts = DVD_NOPTS_VALUE;
  m_bAbort      = false;
  m_bMpeg       = m_omx_reader->IsMpegVideo();
  m_use_thread  = use_thread;
  m_flush       = false;
  m_cached_size = 0;
  m_pAudioCodec = NULL;
  m_pChannelMap = NULL;
  m_speed       = DVD_PLAYSPEED_NORMAL;
  m_initialVolume = initialVolume;
  if (queue_size != 0.0)
    m_max_data_size = queue_size * 1024 * 1024;
  if (fifo_size != 0.0)
    m_fifo_size = fifo_size;

  m_error = 0;
  m_errorbuff = 0;
  m_errorcount = 0;
  m_integral = 0;
  m_skipdupcount = 0;
  m_prevskipped = false;
  m_syncclock = true;
  m_errortime = m_av_clock->CurrentHostCounter();

  m_freq = m_av_clock->CurrentHostFrequency();

  m_av_clock->SetMasterClock(false);

  m_player_error = OpenAudioCodec();
  if(!m_player_error)
  {
    Close();
    return false;
  }

  m_player_error = OpenDecoder();
  if(!m_player_error)
  {
    Close();
    return false;
  }

  if(m_use_thread)
    Create();

  m_open        = true;

  return true;
}
Esempio n. 8
0
bool OMXPlayerAudio::Decode(OMXPacket *pkt)
{
  if(!pkt)
    return false;

  /* last decoder reinit went wrong */
  if(!m_decoder || !m_pAudioCodec)
    return true;

  if(!m_omx_reader->IsActive(OMXSTREAM_AUDIO, pkt->stream_index))
    return true; 

  int channels = pkt->hints.channels;

  unsigned int old_bitrate = m_hints.bitrate;
  unsigned int new_bitrate = pkt->hints.bitrate;

  /* only check bitrate changes on CODEC_ID_DTS, CODEC_ID_AC3, CODEC_ID_EAC3 */
  if(m_hints.codec != CODEC_ID_DTS && m_hints.codec != CODEC_ID_AC3 && m_hints.codec != CODEC_ID_EAC3)
  {
    new_bitrate = old_bitrate = 0;
  }

  // for passthrough we only care about the codec and the samplerate
  bool minor_change = channels                 != m_hints.channels ||
                      pkt->hints.bitspersample != m_hints.bitspersample ||
                      old_bitrate              != new_bitrate;

  if(pkt->hints.codec          != m_hints.codec ||
     pkt->hints.samplerate     != m_hints.samplerate ||
     (!m_passthrough && minor_change))
  {
    printf("C : %d %d %d %d %d\n", m_hints.codec, m_hints.channels, m_hints.samplerate, m_hints.bitrate, m_hints.bitspersample);
    printf("N : %d %d %d %d %d\n", pkt->hints.codec, channels, pkt->hints.samplerate, pkt->hints.bitrate, pkt->hints.bitspersample);


    CloseDecoder();
    CloseAudioCodec();

    m_hints = pkt->hints;

    m_player_error = OpenAudioCodec();
    if(!m_player_error)
      return false;

    m_player_error = OpenDecoder();
    if(!m_player_error)
      return false;
  }

  CLog::Log(LOGINFO, "CDVDPlayerAudio::Decode dts:%.0f pts:%.0f size:%d", pkt->dts, pkt->pts, pkt->size);

  if(pkt->pts != DVD_NOPTS_VALUE)
    m_iCurrentPts = pkt->pts;
  else if(pkt->dts != DVD_NOPTS_VALUE)
    m_iCurrentPts = pkt->dts;

  const uint8_t *data_dec = pkt->data;
  int            data_len = pkt->size;

  if(!m_passthrough && !m_hw_decode)
  {
    while(data_len > 0)
    {
      int len = m_pAudioCodec->Decode((BYTE *)data_dec, data_len);
      if( (len < 0) || (len >  data_len) )
      {
        m_pAudioCodec->Reset();
        break;
      }

      data_dec+= len;
      data_len -= len;

      uint8_t *decoded;
      int decoded_size = m_pAudioCodec->GetData(&decoded);

      if(decoded_size <=0)
        continue;

      while((int) m_decoder->GetSpace() < decoded_size)
      {
        OMXClock::OMXSleep(10);
        if(m_flush_requested) return true;
      }

      int ret = 0;

      ret = m_decoder->AddPackets(decoded, decoded_size, pkt->dts, pkt->pts);
      if(ret != decoded_size)
      {
        printf("error ret %d decoded_size %d\n", ret, decoded_size);
      }
    }
  }
  else
  {
    while((int) m_decoder->GetSpace() < pkt->size)
    {
      OMXClock::OMXSleep(10);
      if(m_flush_requested) return true;
    }

    m_decoder->AddPackets(pkt->data, pkt->size, pkt->dts, pkt->pts);
  }

  return true;
}
Esempio n. 9
0
/*****************************************************************************
 * DecodeAudio: Called to decode one frame
 *****************************************************************************/
static block_t *DecodeAudio( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    AVCodecContext *ctx = p_sys->p_context;
    AVFrame *frame = NULL;
    block_t *p_block = NULL;

    if( !ctx->extradata_size && p_dec->fmt_in.i_extra && p_sys->b_delayed_open)
    {
        InitDecoderConfig( p_dec, ctx );
        OpenAudioCodec( p_dec );
    }

    if( p_sys->b_delayed_open )
    {
        if( pp_block )
            p_block = *pp_block;
        goto drop;
    }

    /* Flushing or decoding, we return any block ready from multiple frames output */
    if( p_sys->p_decoded )
        return DequeueOneDecodedFrame( p_sys );

    if( pp_block == NULL ) /* Drain request */
    {
        /* we don't need to care about return val */
        (void) avcodec_send_packet( ctx, NULL );
    }
    else
    {
        p_block = *pp_block;
    }

    if( p_block )
    {
        if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
        {
            Flush( p_dec );
            goto drop;
        }

        if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
        {
            date_Set( &p_sys->end_date, VLC_TS_INVALID );
        }

        /* We've just started the stream, wait for the first PTS. */
        if( !date_Get( &p_sys->end_date ) && p_block->i_pts <= VLC_TS_INVALID )
            goto drop;

        if( p_block->i_buffer <= 0 )
            goto drop;

        if( (p_block->i_flags & BLOCK_FLAG_PRIVATE_REALLOCATED) == 0 )
        {
            p_block = block_Realloc( p_block, 0, p_block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE );
            if( !p_block )
                return NULL;
            *pp_block = p_block;
            p_block->i_buffer -= FF_INPUT_BUFFER_PADDING_SIZE;
            memset( &p_block->p_buffer[p_block->i_buffer], 0, FF_INPUT_BUFFER_PADDING_SIZE );

            p_block->i_flags |= BLOCK_FLAG_PRIVATE_REALLOCATED;
        }
    }

    frame = av_frame_alloc();
    if (unlikely(frame == NULL))
        goto end;

    for( int ret = 0; ret == 0; )
    {
        /* Feed in the loop as buffer could have been full on first iterations */
        if( p_block )
        {
            AVPacket pkt;
            av_init_packet( &pkt );
            pkt.data = p_block->p_buffer;
            pkt.size = p_block->i_buffer;
            ret = avcodec_send_packet( ctx, &pkt );
            if( ret == 0 ) /* Block has been consumed */
            {
                /* Only set new pts from input block if it has been used,
                 * otherwise let it be through interpolation */
                if( p_block->i_pts > date_Get( &p_sys->end_date ) )
                {
                    date_Set( &p_sys->end_date, p_block->i_pts );
                }

                block_Release( p_block );
                *pp_block = p_block = NULL;
            }
            else if ( ret != AVERROR(EAGAIN) ) /* Errors other than buffer full */
            {
                if( ret == AVERROR(ENOMEM) || ret == AVERROR(EINVAL) )
                    goto end;
                else
                    goto drop;
            }
        }

        /* Try to read one or multiple frames */
        ret = avcodec_receive_frame( ctx, frame );
        if( ret == 0 )
        {
            /* checks and init from first decoded frame */
            if( ctx->channels <= 0 || ctx->channels > 8 || ctx->sample_rate <= 0 )
            {
                msg_Warn( p_dec, "invalid audio properties channels count %d, sample rate %d",
                          ctx->channels, ctx->sample_rate );
                goto drop;
            }
            else if( p_dec->fmt_out.audio.i_rate != (unsigned int)ctx->sample_rate )
            {
                date_Init( &p_sys->end_date, ctx->sample_rate, 1 );
            }

            SetupOutputFormat( p_dec, true );
            if( decoder_UpdateAudioFormat( p_dec ) )
                goto drop;

            block_t *p_converted = ConvertAVFrame( p_dec, frame ); /* Consumes frame */
            if( p_converted )
            {
                /* Silent unwanted samples */
                if( p_sys->i_reject_count > 0 )
                {
                    memset( p_converted->p_buffer, 0, p_converted->i_buffer );
                    p_sys->i_reject_count--;
                }
                p_converted->i_buffer = p_converted->i_nb_samples
                                      * p_dec->fmt_out.audio.i_bytes_per_frame;
                p_converted->i_pts = date_Get( &p_sys->end_date );
                p_converted->i_length = date_Increment( &p_sys->end_date,
                                                      p_converted->i_nb_samples ) - p_converted->i_pts;

                block_ChainLastAppend( &p_sys->pp_decoded_last, p_converted );
            }

            /* Prepare new frame */
            frame = av_frame_alloc();
            if (unlikely(frame == NULL))
                break;
        }
        else av_frame_free( &frame );
    };

    return ( p_sys->p_decoded ) ? DequeueOneDecodedFrame( p_sys ) : NULL;

end:
    p_dec->b_error = true;
    if( pp_block )
    {
        assert( *pp_block == p_block );
        *pp_block = NULL;
    }
drop:
    if( p_block != NULL )
        block_Release(p_block);
    if( frame != NULL )
        av_frame_free( &frame );
    return NULL;
}
Esempio n. 10
0
/*****************************************************************************
 * DecodeAudio: Called to decode one frame
 *****************************************************************************/
static block_t *DecodeAudio( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    AVCodecContext *ctx = p_sys->p_context;
    AVFrame *frame = NULL;

    if( !pp_block || !*pp_block )
        return NULL;

    block_t *p_block = *pp_block;

    if( !ctx->extradata_size && p_dec->fmt_in.i_extra && p_sys->b_delayed_open)
    {
        InitDecoderConfig( p_dec, ctx );
        OpenAudioCodec( p_dec );
    }

    if( p_sys->b_delayed_open )
        goto end;

    if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
    {
        Flush( p_dec );
        goto end;
    }

    if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
    {
        date_Set( &p_sys->end_date, VLC_TS_INVALID );
    }

    /* We've just started the stream, wait for the first PTS. */
    if( !date_Get( &p_sys->end_date ) && p_block->i_pts <= VLC_TS_INVALID )
        goto end;

    if( p_block->i_buffer <= 0 )
        goto end;

    if( (p_block->i_flags & BLOCK_FLAG_PRIVATE_REALLOCATED) == 0 )
    {
        p_block = block_Realloc( p_block, 0, p_block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE );
        if( !p_block )
            return NULL;
        *pp_block = p_block;
        p_block->i_buffer -= FF_INPUT_BUFFER_PADDING_SIZE;
        memset( &p_block->p_buffer[p_block->i_buffer], 0, FF_INPUT_BUFFER_PADDING_SIZE );

        p_block->i_flags |= BLOCK_FLAG_PRIVATE_REALLOCATED;
    }

    frame = av_frame_alloc();
    if (unlikely(frame == NULL))
        goto end;

    for( int got_frame = 0; !got_frame; )
    {
        if( p_block->i_buffer == 0 )
            goto end;

        AVPacket pkt;
        av_init_packet( &pkt );
        pkt.data = p_block->p_buffer;
        pkt.size = p_block->i_buffer;

        int ret = avcodec_send_packet( ctx, &pkt );
        if( ret != 0 && ret != AVERROR(EAGAIN) )
        {
            msg_Warn( p_dec, "cannot decode one frame (%zu bytes)",
                      p_block->i_buffer );
            goto end;
        }
        int used = ret != AVERROR(EAGAIN) ? pkt.size : 0;

        ret = avcodec_receive_frame( ctx, frame );
        if( ret != 0 && ret != AVERROR(EAGAIN) )
        {
            msg_Warn( p_dec, "cannot decode one frame (%zu bytes)",
                      p_block->i_buffer );
            goto end;
        }
        got_frame = ret == 0;

        p_block->p_buffer += used;
        p_block->i_buffer -= used;
    }

    if( ctx->channels <= 0 || ctx->channels > 8 || ctx->sample_rate <= 0 )
    {
        msg_Warn( p_dec, "invalid audio properties channels count %d, sample rate %d",
                  ctx->channels, ctx->sample_rate );
        goto end;
    }

    if( p_dec->fmt_out.audio.i_rate != (unsigned int)ctx->sample_rate )
        date_Init( &p_sys->end_date, ctx->sample_rate, 1 );

    if( p_block->i_pts > date_Get( &p_sys->end_date ) )
    {
        date_Set( &p_sys->end_date, p_block->i_pts );
    }

    if( p_block->i_buffer == 0 )
    {   /* Done with this buffer */
        block_Release( p_block );
        p_block = NULL;
        *pp_block = NULL;
    }

    /* NOTE WELL: Beyond this point, p_block refers to the DECODED block! */
    SetupOutputFormat( p_dec, true );
    if( decoder_UpdateAudioFormat( p_dec ) )
        goto drop;

    /* Interleave audio if required */
    if( av_sample_fmt_is_planar( ctx->sample_fmt ) )
    {
        p_block = block_Alloc(frame->linesize[0] * ctx->channels);
        if (unlikely(p_block == NULL))
            goto drop;

        const void *planes[ctx->channels];
        for (int i = 0; i < ctx->channels; i++)
            planes[i] = frame->extended_data[i];

        aout_Interleave(p_block->p_buffer, planes, frame->nb_samples,
                        ctx->channels, p_dec->fmt_out.audio.i_format);
        p_block->i_nb_samples = frame->nb_samples;
        av_frame_free(&frame);
    }
    else
    {
        p_block = vlc_av_frame_Wrap(frame);
        if (unlikely(p_block == NULL))
            goto drop;
        frame = NULL;
    }

    if (p_sys->b_extract)
    {   /* TODO: do not drop channels... at least not here */
        block_t *p_buffer = block_Alloc( p_dec->fmt_out.audio.i_bytes_per_frame
                                         * p_block->i_nb_samples );
        if( unlikely(p_buffer == NULL) )
            goto drop;
        aout_ChannelExtract( p_buffer->p_buffer,
                             p_dec->fmt_out.audio.i_channels,
                             p_block->p_buffer, ctx->channels,
                             p_block->i_nb_samples, p_sys->pi_extraction,
                             p_dec->fmt_out.audio.i_bitspersample );
        p_buffer->i_nb_samples = p_block->i_nb_samples;
        block_Release( p_block );
        p_block = p_buffer;
    }

    /* Silent unwanted samples */
    if( p_sys->i_reject_count > 0 )
    {
        memset( p_block->p_buffer, 0, p_block->i_buffer );
        p_sys->i_reject_count--;
    }

    p_block->i_buffer = p_block->i_nb_samples
                        * p_dec->fmt_out.audio.i_bytes_per_frame;
    p_block->i_pts = date_Get( &p_sys->end_date );
    p_block->i_length = date_Increment( &p_sys->end_date,
                                      p_block->i_nb_samples ) - p_block->i_pts;
    return p_block;

end:
    *pp_block = NULL;
drop:
    av_frame_free(&frame);
    if( p_block != NULL )
        block_Release(p_block);
    return NULL;
}