static int DecodeAudio( decoder_t *p_dec, block_t *p_block ) { if( p_block == NULL ) /* No Drain */ return VLCDEC_SUCCESS; block_t **pp_block = &p_block, *p_out; while( ( p_out = DecodeBlock( p_dec, pp_block ) ) != NULL ) decoder_QueueAudio( p_dec, p_out ); return VLCDEC_SUCCESS; }
/**************************************************************************** * DecodeBlock: the whole thing **************************************************************************** * This function must be fed with whole samples (see nBlockAlign). ****************************************************************************/ static int DecodeBlock( decoder_t *p_dec, block_t *p_block ) { decoder_sys_t *p_sys = p_dec->p_sys; if( p_block == NULL ) /* No Drain */ return VLCDEC_SUCCESS; if( p_block->i_flags & (BLOCK_FLAG_CORRUPTED|BLOCK_FLAG_DISCONTINUITY) ) { Flush( p_dec ); if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) goto skip; } if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != date_Get( &p_sys->end_date ) ) { date_Set( &p_sys->end_date, p_block->i_pts ); } else if( !date_Get( &p_sys->end_date ) ) /* We've just started the stream, wait for the first PTS. */ goto skip; unsigned samples = (8 * p_block->i_buffer) / p_sys->framebits; if( samples == 0 ) goto skip; if( p_sys->decode != NULL ) { if( decoder_UpdateAudioFormat( p_dec ) ) goto skip; block_t *p_out = decoder_NewAudioBuffer( p_dec, samples ); if( p_out == NULL ) goto skip; p_sys->decode( p_out->p_buffer, p_block->p_buffer, samples * p_dec->fmt_in.audio.i_channels ); block_Release( p_block ); p_block = p_out; } else { decoder_UpdateAudioFormat( p_dec ); p_block->i_nb_samples = samples; p_block->i_buffer = samples * (p_sys->framebits / 8); } p_block->i_pts = date_Get( &p_sys->end_date ); p_block->i_length = date_Increment( &p_sys->end_date, samples ) - p_block->i_pts; decoder_QueueAudio( p_dec, p_block ); return VLCDEC_SUCCESS; skip: block_Release( p_block ); return VLCDEC_SUCCESS; }
static int ProcessOutputStream(decoder_t *p_dec, DWORD stream_id) { decoder_sys_t *p_sys = p_dec->p_sys; HRESULT hr; picture_t *picture = NULL; block_t *aout_buffer = NULL; DWORD output_status = 0; MFT_OUTPUT_DATA_BUFFER output_buffer = { stream_id, p_sys->output_sample, 0, NULL }; hr = IMFTransform_ProcessOutput(p_sys->mft, 0, 1, &output_buffer, &output_status); if (output_buffer.pEvents) IMFCollection_Release(output_buffer.pEvents); /* Use the returned sample since it can be provided by the MFT. */ IMFSample *output_sample = output_buffer.pSample; if (hr == S_OK) { if (!output_sample) return VLC_SUCCESS; LONGLONG sample_time; hr = IMFSample_GetSampleTime(output_sample, &sample_time); if (FAILED(hr)) goto error; /* Convert from 100 nanoseconds unit to microseconds. */ sample_time /= 10; DWORD total_length = 0; hr = IMFSample_GetTotalLength(output_sample, &total_length); if (FAILED(hr)) goto error; if (p_dec->fmt_in.i_cat == VIDEO_ES) { if (decoder_UpdateVideoFormat(p_dec)) return VLC_SUCCESS; picture = decoder_NewPicture(p_dec); if (!picture) return VLC_SUCCESS; UINT32 interlaced = false; hr = IMFSample_GetUINT32(output_sample, &MFSampleExtension_Interlaced, &interlaced); picture->b_progressive = !interlaced; picture->date = sample_time; } else { if (decoder_UpdateAudioFormat(p_dec)) goto error; if (p_dec->fmt_out.audio.i_bitspersample == 0 || p_dec->fmt_out.audio.i_channels == 0) goto error; int samples = total_length / (p_dec->fmt_out.audio.i_bitspersample * p_dec->fmt_out.audio.i_channels / 8); aout_buffer = decoder_NewAudioBuffer(p_dec, samples); if (!aout_buffer) return VLC_SUCCESS; if (aout_buffer->i_buffer < total_length) goto error; aout_buffer->i_pts = sample_time; } IMFMediaBuffer *output_media_buffer = NULL; hr = IMFSample_GetBufferByIndex(output_sample, 0, &output_media_buffer); BYTE *buffer_start; hr = IMFMediaBuffer_Lock(output_media_buffer, &buffer_start, NULL, NULL); if (FAILED(hr)) goto error; if (p_dec->fmt_in.i_cat == VIDEO_ES) CopyPackedBufferToPicture(picture, buffer_start); else memcpy(aout_buffer->p_buffer, buffer_start, total_length); hr = IMFMediaBuffer_Unlock(output_media_buffer); IMFSample_Release(output_media_buffer); if (FAILED(hr)) goto error; if (p_sys->output_sample) { /* Sample is not provided by the MFT: clear its content. */ hr = IMFMediaBuffer_SetCurrentLength(output_media_buffer, 0); if (FAILED(hr)) goto error; } else { /* Sample is provided by the MFT: decrease refcount. */ IMFSample_Release(output_sample); } } else if (hr == MF_E_TRANSFORM_STREAM_CHANGE || hr == MF_E_TRANSFORM_TYPE_NOT_SET) { if (p_sys->output_type) IMFMediaType_Release(p_sys->output_type); if (SetOutputType(p_dec, p_sys->output_stream_id, &p_sys->output_type)) goto error; /* Reallocate output sample. */ if (p_sys->output_sample) IMFSample_Release(p_sys->output_sample); p_sys->output_sample = NULL; if (AllocateOutputSample(p_dec, 0, &p_sys->output_sample)) goto error; return VLC_SUCCESS; } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { return VLC_SUCCESS; } else /* An error not listed above occurred */ { msg_Err(p_dec, "Unexpected error in IMFTransform::ProcessOutput: %#lx", hr); goto error; } if (p_dec->fmt_in.i_cat == VIDEO_ES) decoder_QueueVideo(p_dec, picture); else decoder_QueueAudio(p_dec, aout_buffer); return VLC_SUCCESS; error: msg_Err(p_dec, "Error in ProcessOutputStream()"); if (picture) picture_Release(picture); if (aout_buffer) block_Release(aout_buffer); return VLC_EGENERIC; }
static int Decode( decoder_t *p_dec, block_t *p_in_buf ) { decoder_sys_t *p_sys = p_dec->p_sys; if (p_in_buf == NULL) /* No Drain */ return VLCDEC_SUCCESS; sample_t i_sample_level = 1; int i_flags = p_sys->i_flags; size_t i_bytes_per_block = 256 * p_sys->i_nb_channels * sizeof(float); block_t *p_out_buf = block_Alloc( 6 * i_bytes_per_block ); if( unlikely(p_out_buf == NULL) ) goto out; /* * Do the actual decoding now. */ /* Needs to be called so the decoder knows which type of bitstream it is * dealing with. */ int i_sample_rate, i_bit_rate, i_frame_length; if( !dca_syncinfo( p_sys->p_libdca, p_in_buf->p_buffer, &i_flags, &i_sample_rate, &i_bit_rate, &i_frame_length ) ) { msg_Warn( p_dec, "libdca couldn't sync on frame" ); p_out_buf->i_nb_samples = p_out_buf->i_buffer = 0; goto out; } i_flags = p_sys->i_flags; dca_frame( p_sys->p_libdca, p_in_buf->p_buffer, &i_flags, &i_sample_level, 0 ); if ( (i_flags & DCA_CHANNEL_MASK) != (p_sys->i_flags & DCA_CHANNEL_MASK) && !p_sys->b_dontwarn ) { msg_Warn( p_dec, "libdca couldn't do the requested downmix 0x%x->0x%x", p_sys->i_flags & DCA_CHANNEL_MASK, i_flags & DCA_CHANNEL_MASK ); p_sys->b_dontwarn = 1; } if( 0)//!p_sys->b_dynrng ) { dca_dynrng( p_sys->p_libdca, NULL, NULL ); } for( int i = 0; i < dca_blocks_num(p_sys->p_libdca); i++ ) { sample_t * p_samples; if( dca_block( p_sys->p_libdca ) ) { msg_Warn( p_dec, "dca_block failed for block %d", i ); break; } p_samples = dca_samples( p_sys->p_libdca ); if ( (p_sys->i_flags & DCA_CHANNEL_MASK) == DCA_MONO && (p_dec->fmt_out.audio.i_physical_channels & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) ) { Duplicate( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block), p_samples ); } else if ( p_dec->fmt_out.audio.i_original_channels & AOUT_CHAN_REVERSESTEREO ) { Exchange( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block), p_samples ); } else { /* Interleave the *$£%ù samples. */ Interleave( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block), p_samples, p_sys->i_nb_channels, p_sys->pi_chan_table); } } p_out_buf->i_nb_samples = dca_blocks_num(p_sys->p_libdca) * 256; p_out_buf->i_buffer = p_in_buf->i_nb_samples * sizeof(float) * p_sys->i_nb_channels; p_out_buf->i_dts = p_in_buf->i_dts; p_out_buf->i_pts = p_in_buf->i_pts; p_out_buf->i_length = p_in_buf->i_length; out: if (p_out_buf != NULL) decoder_QueueAudio(p_dec, p_out_buf); block_Release( p_in_buf ); return VLCDEC_SUCCESS; }
/**************************************************************************** * DecodeBlock: the whole thing ****************************************************************************/ static int DecodeBlock( decoder_t *p_dec, block_t *p_block ) { int i_err; decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_out = NULL; if( !p_sys->b_opened ) { if( p_block ) block_Release( p_block ); return VLCDEC_ECRITICAL; } /* Feed input block */ if( p_block != NULL ) { if( !date_Get( &p_sys->end_date ) && p_block->i_pts <= VLC_TS_INVALID ) { /* We've just started the stream, wait for the first PTS. */ msg_Dbg( p_dec, "waiting for PTS" ); goto end; } if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { Flush( p_dec ); if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) goto end; } /* Feed mpg123 with raw data */ i_err = mpg123_feed( p_sys->p_handle, p_block->p_buffer, p_block->i_buffer ); if( i_err != MPG123_OK ) { msg_Err( p_dec, "mpg123_feed failed: %s", mpg123_plain_strerror( i_err ) ); goto end; } } /* Fetch a new output block (if possible) */ if( !p_sys->p_out || p_sys->p_out->i_buffer != mpg123_outblock( p_sys->p_handle ) ) { if( p_sys->p_out ) block_Release( p_sys->p_out ); /* Keep the output buffer for next calls in case it's not used (in case * of MPG123_NEED_MORE status) */ p_sys->p_out = block_Alloc( mpg123_outblock( p_sys->p_handle ) ); if( unlikely( !p_sys->p_out ) ) return VLCDEC_SUCCESS; } /* Do the actual decoding now */ size_t i_bytes = 0; while( true ) { /* Make mpg123 write directly into the VLC output buffer */ i_err = mpg123_replace_buffer( p_sys->p_handle, p_sys->p_out->p_buffer, p_sys->p_out->i_buffer ); if( i_err != MPG123_OK ) { msg_Err( p_dec, "could not replace buffer: %s", mpg123_plain_strerror( i_err ) ); block_Release( p_sys->p_out ); p_sys->p_out = NULL; return VLCDEC_SUCCESS; } i_err = mpg123_decode_frame( p_sys->p_handle, NULL, NULL, &i_bytes ); if( i_err != MPG123_OK ) { if( i_err == MPG123_NEW_FORMAT ) { if( UpdateAudioFormat( p_dec ) != VLC_SUCCESS ) goto end; else continue; } else if( i_err != MPG123_NEED_MORE ) msg_Err( p_dec, "mpg123_decode_frame error: %s", mpg123_plain_strerror( i_err ) ); } else if( p_dec->fmt_out.audio.i_rate == 0 ) { msg_Warn( p_dec, "mpg123_decode_frame returned valid frame without " "updating the format" ); if( UpdateAudioFormat( p_dec ) != VLC_SUCCESS ) goto end; } break; } if( p_block && p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != date_Get( &p_sys->end_date ) ) date_Set( &p_sys->end_date, p_block->i_pts ); if( i_bytes == 0 ) goto end; assert( p_dec->fmt_out.audio.i_rate != 0 ); p_out = p_sys->p_out; p_sys->p_out = NULL; assert( p_out->i_buffer >= i_bytes ); p_out->i_buffer = i_bytes; p_out->i_nb_samples = p_out->i_buffer * p_dec->fmt_out.audio.i_frame_length / p_dec->fmt_out.audio.i_bytes_per_frame; /* Configure the buffer */ p_out->i_dts = p_out->i_pts = date_Get( &p_sys->end_date ); p_out->i_length = date_Increment( &p_sys->end_date, p_out->i_nb_samples ) - p_out->i_pts; end: if( p_block ) block_Release( p_block ); if( p_out != NULL ) decoder_QueueAudio( p_dec, p_out ); return VLCDEC_SUCCESS; }