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; }
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; }
/***************************************************************************** * 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; }
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; }
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; }
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; }
/***************************************************************************** * 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; }
/***************************************************************************** * 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; }