static block_t *Encode( encoder_t *p_enc, aout_buffer_t *p_aout_buf ) { encoder_sys_t *p_sys = p_enc->p_sys; int16_t *p_buffer = (int16_t *)p_aout_buf->p_buffer; int i_nb_samples = p_aout_buf->i_nb_samples; block_t *p_chain = NULL; mtime_t i_computed_pts = p_aout_buf->start_date - (mtime_t)1000000 * (mtime_t)p_sys->i_nb_samples / (mtime_t)p_enc->fmt_in.audio.i_rate; if ( aout_DateGet( &p_sys->pts ) - i_computed_pts > 10000 || aout_DateGet( &p_sys->pts ) - i_computed_pts < -10000 ) { msg_Dbg( p_enc, "resetting audio date" ); aout_DateSet( &p_sys->pts, i_computed_pts ); } while ( p_sys->i_nb_samples + i_nb_samples >= MPEG_FRAME_SIZE ) { int i_used; block_t *p_block; Uninterleave( p_enc, p_buffer, MPEG_FRAME_SIZE - p_sys->i_nb_samples ); i_nb_samples -= MPEG_FRAME_SIZE - p_sys->i_nb_samples; p_buffer += (MPEG_FRAME_SIZE - p_sys->i_nb_samples) * 2; toolame_encode_buffer( p_sys->p_toolame, p_sys->p_left, p_sys->p_right, MPEG_FRAME_SIZE, p_sys->p_out_buffer, MAX_CODED_FRAME_SIZE, &i_used ); p_sys->i_nb_samples = 0; p_block = block_New( p_enc, i_used ); p_enc->p_vlc->pf_memcpy( p_block->p_buffer, p_sys->p_out_buffer, i_used ); p_block->i_length = (mtime_t)1000000 * (mtime_t)MPEG_FRAME_SIZE / (mtime_t)p_enc->fmt_in.audio.i_rate; p_block->i_dts = p_block->i_pts = aout_DateGet( &p_sys->pts ); aout_DateIncrement( &p_sys->pts, MPEG_FRAME_SIZE ); block_ChainAppend( &p_chain, p_block ); } if ( i_nb_samples ) { Uninterleave( p_enc, p_buffer, i_nb_samples ); p_sys->i_nb_samples += i_nb_samples; } return p_chain; }
/***************************************************************************** * aout_FifoPush : push a packet into the FIFO *****************************************************************************/ void aout_FifoPush( aout_instance_t * p_aout, aout_fifo_t * p_fifo, aout_buffer_t * p_buffer ) { *p_fifo->pp_last = p_buffer; p_fifo->pp_last = &p_buffer->p_next; *p_fifo->pp_last = NULL; /* Enforce the continuity of the stream. */ if ( aout_DateGet( &p_fifo->end_date ) ) { p_buffer->start_date = aout_DateGet( &p_fifo->end_date ); p_buffer->end_date = aout_DateIncrement( &p_fifo->end_date, p_buffer->i_nb_samples ); } else { aout_DateSet( &p_fifo->end_date, p_buffer->end_date ); } }
/***************************************************************************** * Fill buffer *****************************************************************************/ static int FillBuffer( int16_t *p_data, int *pi_data, audio_date_t *pi_date, audio_date_t *pi_date_end, goom_thread_t *p_this ) { int i_samples = 0; block_t *p_block; while( *pi_data < 512 ) { if( !p_this->i_blocks ) return VLC_EGENERIC; p_block = p_this->pp_blocks[0]; i_samples = __MIN( 512 - *pi_data, p_block->i_buffer / sizeof(float) / p_this->i_channels ); /* Date management */ if( p_block->i_pts > 0 && p_block->i_pts != aout_DateGet( pi_date_end ) ) { aout_DateSet( pi_date_end, p_block->i_pts ); } p_block->i_pts = 0; aout_DateIncrement( pi_date_end, i_samples ); while( i_samples > 0 ) { float *p_float = (float *)p_block->p_buffer; p_data[*pi_data] = FloatToInt16( p_float[0] ); if( p_this->i_channels > 1 ) p_data[512 + *pi_data] = FloatToInt16( p_float[1] ); (*pi_data)++; p_block->p_buffer += (sizeof(float) * p_this->i_channels); p_block->i_buffer -= (sizeof(float) * p_this->i_channels); i_samples--; } if( !p_block->i_buffer ) { block_Release( p_block ); p_this->i_blocks--; if( p_this->i_blocks ) memmove( p_this->pp_blocks, p_this->pp_blocks + 1, p_this->i_blocks * sizeof(block_t *) ); } } *pi_date = *pi_date_end; *pi_data = 0; return VLC_SUCCESS; }
/***************************************************************************** * SplitBuffer: Needed because aout really doesn't like big audio chunk and * wma produces easily > 30000 samples... *****************************************************************************/ static aout_buffer_t *SplitBuffer( decoder_t *p_dec ) { decoder_sys_t *p_sys = p_dec->p_sys; unsigned int i_samples = __MIN( p_sys->i_samples, 2048 ); aout_buffer_t *p_buffer; if( i_samples == 0 ) return NULL; if( !( p_buffer = p_dec->pf_aout_buffer_new( p_dec, i_samples ) ) ) return NULL; p_buffer->start_date = aout_DateGet( &p_sys->end_date ); p_buffer->end_date = aout_DateIncrement( &p_sys->end_date, i_samples ); memcpy( p_buffer->p_buffer, p_sys->p_samples, p_buffer->i_nb_bytes ); p_sys->p_samples += p_buffer->i_nb_bytes; p_sys->i_samples -= i_samples; return p_buffer; }
/***************************************************************************** * aout_FifoNextStart : return the current end_date *****************************************************************************/ mtime_t aout_FifoNextStart( aout_instance_t * p_aout, aout_fifo_t * p_fifo ) { return aout_DateGet( &p_fifo->end_date ); }
/***************************************************************************** * MixBuffer: try to prepare one output buffer ***************************************************************************** * Please note that you must hold the mixer lock. *****************************************************************************/ static int MixBuffer( aout_instance_t * p_aout ) { int i, i_first_input = 0; aout_buffer_t * p_output_buffer; mtime_t start_date, end_date; audio_date_t exact_start_date; if ( p_aout->mixer.b_error ) { /* Free all incoming buffers. */ vlc_mutex_lock( &p_aout->input_fifos_lock ); for ( i = 0; i < p_aout->i_nb_inputs; i++ ) { aout_input_t * p_input = p_aout->pp_inputs[i]; aout_buffer_t * p_buffer = p_input->fifo.p_first; if ( p_input->b_error ) continue; while ( p_buffer != NULL ) { aout_buffer_t * p_next = p_buffer->p_next; aout_BufferFree( p_buffer ); p_buffer = p_next; } } vlc_mutex_unlock( &p_aout->input_fifos_lock ); return -1; } vlc_mutex_lock( &p_aout->output_fifo_lock ); vlc_mutex_lock( &p_aout->input_fifos_lock ); /* Retrieve the date of the next buffer. */ memcpy( &exact_start_date, &p_aout->output.fifo.end_date, sizeof(audio_date_t) ); start_date = aout_DateGet( &exact_start_date ); if ( start_date != 0 && start_date < mdate() ) { /* The output is _very_ late. This can only happen if the user * pauses the stream (or if the decoder is buggy, which cannot * happen :). */ msg_Warn( p_aout, "output PTS is out of range ("I64Fd"), clearing out", mdate() - start_date ); aout_FifoSet( p_aout, &p_aout->output.fifo, 0 ); aout_DateSet( &exact_start_date, 0 ); start_date = 0; } vlc_mutex_unlock( &p_aout->output_fifo_lock ); /* See if we have enough data to prepare a new buffer for the audio * output. First : start date. */ if ( !start_date ) { /* Find the latest start date available. */ for ( i = 0; i < p_aout->i_nb_inputs; i++ ) { aout_input_t * p_input = p_aout->pp_inputs[i]; aout_fifo_t * p_fifo = &p_input->fifo; aout_buffer_t * p_buffer; if ( p_input->b_error ) continue; p_buffer = p_fifo->p_first; while ( p_buffer != NULL && p_buffer->start_date < mdate() ) { msg_Warn( p_aout, "input PTS is out of range ("I64Fd"), " "trashing", mdate() - p_buffer->start_date ); p_buffer = aout_FifoPop( p_aout, p_fifo ); aout_BufferFree( p_buffer ); p_buffer = p_fifo->p_first; p_input->p_first_byte_to_mix = NULL; } if ( p_buffer == NULL ) { break; } if ( !start_date || start_date < p_buffer->start_date ) { aout_DateSet( &exact_start_date, p_buffer->start_date ); start_date = p_buffer->start_date; } } if ( i < p_aout->i_nb_inputs ) { /* Interrupted before the end... We can't run. */ vlc_mutex_unlock( &p_aout->input_fifos_lock ); return -1; } } aout_DateIncrement( &exact_start_date, p_aout->output.i_nb_samples ); end_date = aout_DateGet( &exact_start_date ); /* Check that start_date and end_date are available for all input * streams. */ for ( i = 0; i < p_aout->i_nb_inputs; i++ ) { aout_input_t * p_input = p_aout->pp_inputs[i]; aout_fifo_t * p_fifo = &p_input->fifo; aout_buffer_t * p_buffer; mtime_t prev_date; vlc_bool_t b_drop_buffers; if ( p_input->b_error ) { if ( i_first_input == i ) i_first_input++; continue; } p_buffer = p_fifo->p_first; if ( p_buffer == NULL ) { break; } /* Check for the continuity of start_date */ while ( p_buffer != NULL && p_buffer->end_date < start_date - 1 ) { /* We authorize a +-1 because rounding errors get compensated * regularly. */ aout_buffer_t * p_next = p_buffer->p_next; msg_Warn( p_aout, "the mixer got a packet in the past ("I64Fd")", start_date - p_buffer->end_date ); aout_BufferFree( p_buffer ); p_fifo->p_first = p_buffer = p_next; p_input->p_first_byte_to_mix = NULL; } if ( p_buffer == NULL ) { p_fifo->pp_last = &p_fifo->p_first; break; } /* Check that we have enough samples. */ for ( ; ; ) { p_buffer = p_fifo->p_first; if ( p_buffer == NULL ) break; if ( p_buffer->end_date >= end_date ) break; /* Check that all buffers are contiguous. */ prev_date = p_fifo->p_first->end_date; p_buffer = p_buffer->p_next; b_drop_buffers = 0; for ( ; p_buffer != NULL; p_buffer = p_buffer->p_next ) { if ( prev_date != p_buffer->start_date ) { msg_Warn( p_aout, "buffer hole, dropping packets ("I64Fd")", p_buffer->start_date - prev_date ); b_drop_buffers = 1; break; } if ( p_buffer->end_date >= end_date ) break; prev_date = p_buffer->end_date; } if ( b_drop_buffers ) { aout_buffer_t * p_deleted = p_fifo->p_first; while ( p_deleted != NULL && p_deleted != p_buffer ) { aout_buffer_t * p_next = p_deleted->p_next; aout_BufferFree( p_deleted ); p_deleted = p_next; } p_fifo->p_first = p_deleted; /* == p_buffer */ } else break; } if ( p_buffer == NULL ) break; p_buffer = p_fifo->p_first; if ( !AOUT_FMT_NON_LINEAR( &p_aout->mixer.mixer ) ) { /* Additionally check that p_first_byte_to_mix is well * located. */ mtime_t i_nb_bytes = (start_date - p_buffer->start_date) * p_aout->mixer.mixer.i_bytes_per_frame * p_aout->mixer.mixer.i_rate / p_aout->mixer.mixer.i_frame_length / 1000000; ptrdiff_t mixer_nb_bytes; if ( p_input->p_first_byte_to_mix == NULL ) { p_input->p_first_byte_to_mix = p_buffer->p_buffer; } mixer_nb_bytes = p_input->p_first_byte_to_mix - p_buffer->p_buffer; if ( !((i_nb_bytes + p_aout->mixer.mixer.i_bytes_per_frame > mixer_nb_bytes) && (i_nb_bytes < p_aout->mixer.mixer.i_bytes_per_frame + mixer_nb_bytes)) ) { msg_Warn( p_aout, "mixer start isn't output start ("I64Fd")", i_nb_bytes - mixer_nb_bytes ); /* Round to the nearest multiple */ i_nb_bytes /= p_aout->mixer.mixer.i_bytes_per_frame; i_nb_bytes *= p_aout->mixer.mixer.i_bytes_per_frame; if( i_nb_bytes < 0 ) { /* Is it really the best way to do it ? */ aout_FifoSet( p_aout, &p_aout->output.fifo, 0 ); aout_DateSet( &exact_start_date, 0 ); break; } p_input->p_first_byte_to_mix = p_buffer->p_buffer + i_nb_bytes; } } } if ( i < p_aout->i_nb_inputs || i_first_input == p_aout->i_nb_inputs ) { /* Interrupted before the end... We can't run. */ vlc_mutex_unlock( &p_aout->input_fifos_lock ); return -1; } /* Run the mixer. */ aout_BufferAlloc( &p_aout->mixer.output_alloc, ((uint64_t)p_aout->output.i_nb_samples * 1000000) / p_aout->output.output.i_rate, /* This is a bit kludgy, but is actually only used * for the S/PDIF dummy mixer : */ p_aout->pp_inputs[i_first_input]->fifo.p_first, p_output_buffer ); if ( p_output_buffer == NULL ) { msg_Err( p_aout, "out of memory" ); vlc_mutex_unlock( &p_aout->input_fifos_lock ); return -1; } /* This is again a bit kludgy - for the S/PDIF mixer. */ if ( p_aout->mixer.output_alloc.i_alloc_type != AOUT_ALLOC_NONE ) { p_output_buffer->i_nb_samples = p_aout->output.i_nb_samples; p_output_buffer->i_nb_bytes = p_aout->output.i_nb_samples * p_aout->mixer.mixer.i_bytes_per_frame / p_aout->mixer.mixer.i_frame_length; } p_output_buffer->start_date = start_date; p_output_buffer->end_date = end_date; p_aout->mixer.pf_do_work( p_aout, p_output_buffer ); vlc_mutex_unlock( &p_aout->input_fifos_lock ); aout_OutputPlay( p_aout, p_output_buffer ); return 0; }
static aout_buffer_t *DecodeBlock (decoder_t *p_dec, block_t **pp_block) { block_t *p_block; decoder_sys_t *p_sys = p_dec->p_sys; aout_buffer_t *p_out = NULL; if (pp_block == NULL) return NULL; p_block = *pp_block; if (p_block == NULL) return NULL; *pp_block = NULL; if (p_block->i_pts && !aout_DateGet (&p_sys->end_date)) aout_DateSet (&p_sys->end_date, p_block->i_pts); else if (p_block->i_pts < aout_DateGet (&p_sys->end_date)) { msg_Warn (p_dec, "MIDI message in the past?"); goto drop; } if (p_block->i_buffer < 1) goto drop; uint8_t channel = p_block->p_buffer[0] & 0xf; uint8_t p1 = (p_block->i_buffer > 1) ? (p_block->p_buffer[1] & 0x7f) : 0; uint8_t p2 = (p_block->i_buffer > 2) ? (p_block->p_buffer[2] & 0x7f) : 0; switch (p_block->p_buffer[0] & 0xf0) { case 0x80: fluid_synth_noteoff (p_sys->synth, channel, p1); break; case 0x90: fluid_synth_noteon (p_sys->synth, channel, p1, p2); break; case 0xB0: fluid_synth_cc (p_sys->synth, channel, p1, p2); break; case 0xC0: fluid_synth_program_change (p_sys->synth, channel, p1); break; case 0xE0: fluid_synth_pitch_bend (p_sys->synth, channel, (p1 << 7) | p2); break; } unsigned samples = (p_block->i_pts - aout_DateGet (&p_sys->end_date)) * 441 / 10000; if (samples == 0) return NULL; p_out = decoder_NewAudioBuffer (p_dec, samples); if (p_out == NULL) goto drop; p_out->start_date = aout_DateGet (&p_sys->end_date ); p_out->end_date = aout_DateIncrement (&p_sys->end_date, samples); fluid_synth_write_float (p_sys->synth, samples, p_out->p_buffer, 0, 2, p_out->p_buffer, 1, 2); drop: block_Release (p_block); return p_out; }
/***************************************************************************** * DecodeAudio: *****************************************************************************/ static aout_buffer_t *DecodeAudio( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; vlc_value_t lockval; block_t *p_block; int i_error; #ifdef LOADER /* We must do open and close in the same thread (unless we do * Setup_LDT_Keeper in the main thread before all others */ if( p_sys == NULL ) { if( OpenAudio( p_dec ) ) { /* Fatal */ p_dec->b_error = VLC_TRUE; return NULL; } p_sys = p_dec->p_sys; } #endif if( pp_block == NULL || *pp_block == NULL ) { return NULL; } p_block = *pp_block; if( p_sys->i_out_frames > 0 && p_sys->i_out >= p_sys->i_out_frames ) { /* Ask new data */ p_sys->i_out = 0; p_sys->i_out_frames = 0; *pp_block = NULL; return NULL; } if( p_sys->i_out_frames <= 0 ) { if( ( p_sys->pts = p_block->i_pts ) < mdate() ) { block_Release( p_block ); *pp_block = NULL; return NULL; } /* Append data */ if( p_sys->i_buffer_size < p_sys->i_buffer + p_block->i_buffer ) { p_sys->i_buffer_size = p_sys->i_buffer + p_block->i_buffer + 1024; p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size ); } memcpy( &p_sys->p_buffer[p_sys->i_buffer], p_block->p_buffer, p_block->i_buffer ); p_sys->i_buffer += p_block->i_buffer; if( p_sys->i_buffer > p_sys->InFrameSize ) { int i_frames = p_sys->i_buffer / p_sys->InFrameSize; unsigned long i_out_frames, i_out_bytes; var_Get( p_dec->p_libvlc, "qt_mutex", &lockval ); vlc_mutex_lock( lockval.p_address ); i_error = p_sys->SoundConverterConvertBuffer( p_sys->myConverter, p_sys->p_buffer, i_frames, p_sys->out_buffer, &i_out_frames, &i_out_bytes ); vlc_mutex_unlock( lockval.p_address ); /* msg_Dbg( p_dec, "decoded %d frames -> %ld frames (error=%d)", i_frames, i_out_frames, i_error ); msg_Dbg( p_dec, "decoded %ld frames = %ld bytes", i_out_frames, i_out_bytes ); */ p_sys->i_buffer -= i_frames * p_sys->InFrameSize; if( p_sys->i_buffer > 0 ) { memmove( &p_sys->p_buffer[0], &p_sys->p_buffer[i_frames * p_sys->InFrameSize], p_sys->i_buffer ); } if( p_sys->pts != 0 && p_sys->pts != aout_DateGet( &p_sys->date ) ) { aout_DateSet( &p_sys->date, p_sys->pts ); } else if( !aout_DateGet( &p_sys->date ) ) { return NULL; } if( !i_error && i_out_frames > 0 ) { /* we have others samples */ p_sys->i_out_frames = i_out_frames; p_sys->i_out = 0; } } } if( p_sys->i_out < p_sys->i_out_frames ) { aout_buffer_t *p_out; int i_frames = __MIN( p_sys->i_out_frames - p_sys->i_out, 1000 ); p_out = p_dec->pf_aout_buffer_new( p_dec, i_frames ); if( p_out ) { p_out->start_date = aout_DateGet( &p_sys->date ); p_out->end_date = aout_DateIncrement( &p_sys->date, i_frames ); memcpy( p_out->p_buffer, &p_sys->out_buffer[2 * p_sys->i_out * p_dec->fmt_out.audio.i_channels], p_out->i_nb_bytes ); p_sys->i_out += i_frames; } return p_out; } return NULL; }
/***************************************************************************** * DecodeBlock: *****************************************************************************/ static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; if( !pp_block || !*pp_block ) return NULL; p_block = *pp_block; if( p_block->i_pts != 0 && p_block->i_pts != aout_DateGet( &p_sys->end_date ) ) { aout_DateSet( &p_sys->end_date, p_block->i_pts ); } else if( !aout_DateGet( &p_sys->end_date ) ) { /* We've just started the stream, wait for the first PTS. */ block_Release( p_block ); return NULL; } /* Don't re-use the same pts twice */ p_block->i_pts = 0; if( p_block->i_buffer >= p_sys->i_block ) { aout_buffer_t *p_out; p_out = p_dec->pf_aout_buffer_new( p_dec, p_sys->i_samplesperblock ); if( p_out == NULL ) { block_Release( p_block ); return NULL; } p_out->start_date = aout_DateGet( &p_sys->end_date ); p_out->end_date = aout_DateIncrement( &p_sys->end_date, p_sys->i_samplesperblock ); switch( p_sys->codec ) { case ADPCM_IMA_QT: DecodeAdpcmImaQT( p_dec, (int16_t*)p_out->p_buffer, p_block->p_buffer ); break; case ADPCM_IMA_WAV: DecodeAdpcmImaWav( p_dec, (int16_t*)p_out->p_buffer, p_block->p_buffer ); break; case ADPCM_MS: DecodeAdpcmMs( p_dec, (int16_t*)p_out->p_buffer, p_block->p_buffer ); break; case ADPCM_DK4: DecodeAdpcmDk4( p_dec, (int16_t*)p_out->p_buffer, p_block->p_buffer ); break; case ADPCM_DK3: DecodeAdpcmDk3( p_dec, (int16_t*)p_out->p_buffer, p_block->p_buffer ); break; case ADPCM_EA: DecodeAdpcmEA( p_dec, (int16_t*)p_out->p_buffer, p_block->p_buffer ); default: break; } p_block->p_buffer += p_sys->i_block; p_block->i_buffer -= p_sys->i_block; return p_out; } block_Release( p_block ); return NULL; }
/***************************************************************************** * DecodeBlock: *****************************************************************************/ static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; if( !pp_block || !*pp_block ) return NULL; p_block = *pp_block; if( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { block_Release( p_block ); return NULL; } /* Remove ADTS header if we have decoder specific config */ if( p_dec->fmt_in.i_extra && p_block->i_buffer > 7 ) { if( p_block->p_buffer[0] == 0xff && ( p_block->p_buffer[1] & 0xf0 ) == 0xf0 ) /* syncword */ { /* ADTS header present */ size_t i_header_size; /* 7 bytes (+ 2 bytes for crc) */ i_header_size = 7 + ( ( p_block->p_buffer[1] & 0x01 ) ? 0 : 2 ); /* FIXME: multiple blocks per frame */ if( p_block->i_buffer > i_header_size ) { vlc_memcpy( p_block->p_buffer, p_block->p_buffer + i_header_size, p_block->i_buffer - i_header_size ); p_block->i_buffer -= i_header_size; } } } /* Append the block to the temporary buffer */ if( p_sys->i_buffer_size < p_sys->i_buffer + p_block->i_buffer ) { p_sys->i_buffer_size = p_sys->i_buffer + p_block->i_buffer; p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size ); } if( p_block->i_buffer > 0 ) { vlc_memcpy( &p_sys->p_buffer[p_sys->i_buffer], p_block->p_buffer, p_block->i_buffer ); p_sys->i_buffer += p_block->i_buffer; p_block->i_buffer = 0; } if( p_dec->fmt_out.audio.i_rate == 0 && p_dec->fmt_in.i_extra > 0 ) { /* We have a decoder config so init the handle */ unsigned long i_rate; unsigned char i_channels; if( faacDecInit2( p_sys->hfaad, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra, &i_rate, &i_channels ) >= 0 ) { p_dec->fmt_out.audio.i_rate = i_rate; p_dec->fmt_out.audio.i_channels = i_channels; p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_guessed[i_channels]; aout_DateInit( &p_sys->date, i_rate ); } } if( p_dec->fmt_out.audio.i_rate == 0 && p_sys->i_buffer ) { unsigned long i_rate; unsigned char i_channels; /* Init faad with the first frame */ if( faacDecInit( p_sys->hfaad, p_sys->p_buffer, p_sys->i_buffer, &i_rate, &i_channels ) < 0 ) { block_Release( p_block ); return NULL; } p_dec->fmt_out.audio.i_rate = i_rate; p_dec->fmt_out.audio.i_channels = i_channels; p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_guessed[i_channels]; aout_DateInit( &p_sys->date, i_rate ); } if( p_block->i_pts != 0 && p_block->i_pts != aout_DateGet( &p_sys->date ) ) { aout_DateSet( &p_sys->date, p_block->i_pts ); } else if( !aout_DateGet( &p_sys->date ) ) { /* We've just started the stream, wait for the first PTS. */ block_Release( p_block ); p_sys->i_buffer = 0; return NULL; } /* Decode all data */ if( p_sys->i_buffer ) { void *samples; faacDecFrameInfo frame; aout_buffer_t *p_out; int i, j; samples = faacDecDecode( p_sys->hfaad, &frame, p_sys->p_buffer, p_sys->i_buffer ); if( frame.error > 0 ) { msg_Warn( p_dec, "%s", faacDecGetErrorMessage( frame.error ) ); /* Flush the buffer */ p_sys->i_buffer = 0; block_Release( p_block ); return NULL; } if( frame.channels <= 0 || frame.channels > 8 || frame.channels == 7 ) { msg_Warn( p_dec, "invalid channels count: %i", frame.channels ); /* Flush the buffer */ p_sys->i_buffer -= frame.bytesconsumed; if( p_sys->i_buffer > 0 ) { memmove( p_sys->p_buffer,&p_sys->p_buffer[frame.bytesconsumed], p_sys->i_buffer ); } block_Release( p_block ); return NULL; } if( frame.samples <= 0 ) { msg_Warn( p_dec, "decoded zero sample" ); /* Flush the buffer */ p_sys->i_buffer -= frame.bytesconsumed; if( p_sys->i_buffer > 0 ) { memmove( p_sys->p_buffer,&p_sys->p_buffer[frame.bytesconsumed], p_sys->i_buffer ); } block_Release( p_block ); return NULL; } /* We decoded a valid frame */ if( p_dec->fmt_out.audio.i_rate != frame.samplerate ) { aout_DateInit( &p_sys->date, frame.samplerate ); aout_DateSet( &p_sys->date, p_block->i_pts ); } p_block->i_pts = 0; /* PTS is valid only once */ p_dec->fmt_out.audio.i_rate = frame.samplerate; p_dec->fmt_out.audio.i_channels = frame.channels; p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_guessed[frame.channels]; /* Adjust stream info when dealing with SBR/PS */ if( p_sys->b_sbr != frame.sbr || p_sys->b_ps != frame.ps ) { const char *psz_ext = (frame.sbr && frame.ps) ? "SBR+PS" : frame.sbr ? "SBR" : "PS"; msg_Dbg( p_dec, "AAC %s (channels: %u, samplerate: %lu)", psz_ext, frame.channels, frame.samplerate ); if( !p_dec->p_description ) p_dec->p_description = vlc_meta_New(); if( p_dec->p_description ) vlc_meta_AddExtra( p_dec->p_description, _("AAC extension"), psz_ext ); p_sys->b_sbr = frame.sbr; p_sys->b_ps = frame.ps; } /* Convert frame.channel_position to our own channel values */ p_dec->fmt_out.audio.i_physical_channels = 0; for( i = 0; i < frame.channels; i++ ) { /* Find the channel code */ for( j = 0; j < MAX_CHANNEL_POSITIONS; j++ ) { if( frame.channel_position[i] == pi_channels_in[j] ) break; } if( j >= MAX_CHANNEL_POSITIONS ) { msg_Warn( p_dec, "unknown channel ordering" ); /* Invent something */ j = i; } /* */ p_sys->pi_channel_positions[i] = pi_channels_out[j]; if( p_dec->fmt_out.audio.i_physical_channels & pi_channels_out[j] ) frame.channels--; /* We loose a duplicated channel */ else p_dec->fmt_out.audio.i_physical_channels |= pi_channels_out[j]; } p_dec->fmt_out.audio.i_original_channels = p_dec->fmt_out.audio.i_physical_channels; p_out = decoder_NewAudioBuffer(p_dec, frame.samples/frame.channels); if( p_out == NULL ) { p_sys->i_buffer = 0; block_Release( p_block ); return NULL; } p_out->start_date = aout_DateGet( &p_sys->date ); p_out->end_date = aout_DateIncrement( &p_sys->date, frame.samples / frame.channels ); DoReordering( (uint32_t *)p_out->p_buffer, samples, frame.samples / frame.channels, frame.channels, p_sys->pi_channel_positions ); p_sys->i_buffer -= frame.bytesconsumed; if( p_sys->i_buffer > 0 ) { memmove( p_sys->p_buffer, &p_sys->p_buffer[frame.bytesconsumed], p_sys->i_buffer ); } return p_out; } block_Release( p_block ); return NULL; }
/***************************************************************************** * DecodeFrame: decodes a wma frame. *****************************************************************************/ static aout_buffer_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; aout_buffer_t *p_aout_buffer = NULL; #ifdef NDEBUG mtime_t start = mdate(); /* for statistics */ #endif if( !pp_block || !*pp_block ) return NULL; p_block = *pp_block; if( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { aout_DateSet( &p_sys->end_date, 0 ); block_Release( p_block ); *pp_block = NULL; return NULL; } if( p_block->i_buffer <= 0 ) { /* we already decoded the samples, just feed a few to aout */ if( p_sys->i_samples ) p_aout_buffer = SplitBuffer( p_dec ); if( !p_sys->i_samples ) { /* we need to decode new samples now */ free( p_sys->p_output ); p_sys->p_output = NULL; block_Release( p_block ); *pp_block = NULL; } return p_aout_buffer; } /* Date management */ if( p_block->i_pts > 0 && p_block->i_pts != aout_DateGet( &p_sys->end_date ) ) { aout_DateSet( &p_sys->end_date, p_block->i_pts ); /* don't reuse the same pts */ p_block->i_pts = 0; } else if( !aout_DateGet( &p_sys->end_date ) ) { /* We've just started the stream, wait for the first PTS. */ block_Release( p_block ); return NULL; } if( wma_decode_superframe_init( &p_sys->wmadec, p_block->p_buffer, p_block->i_buffer ) == 0 ) { msg_Err( p_dec, "failed initializing wmafixed decoder" ); block_Release( p_block ); *pp_block = NULL; return NULL; } if( p_sys->wmadec.nb_frames <= 0 ) { msg_Err( p_dec, "can not decode, invalid ASF packet ?" ); block_Release( p_block ); *pp_block = NULL; return NULL; } /* worst case */ size_t i_buffer = BLOCK_MAX_SIZE * MAX_CHANNELS * p_sys->wmadec.nb_frames; if( p_sys->p_output ) free( p_sys->p_output ); p_sys->p_output = malloc(i_buffer * sizeof(int32_t) ); p_sys->p_samples = (int8_t*)p_sys->p_output; if( !p_sys->p_output ) { /* OOM, will try a bit later if VLC hasn't been killed */ block_Release( p_block ); return NULL; } p_sys->i_samples = 0; for( int i = 0 ; i < p_sys->wmadec.nb_frames; i++ ) { int i_samples = 0; i_samples = wma_decode_superframe_frame( &p_sys->wmadec, p_sys->p_output + p_sys->i_samples * p_sys->wmadec.nb_channels, p_block->p_buffer, p_block->i_buffer ); if( i_samples < 0 ) { msg_Warn( p_dec, "wma_decode_superframe_frame() failed for frame %d", i ); free( p_sys->p_output ); p_sys->p_output = NULL; return NULL; } p_sys->i_samples += i_samples; /* advance in the samples buffer */ } p_block->i_buffer = 0; /* this block has been decoded */ for( size_t s = 0 ; s < i_buffer; s++ ) p_sys->p_output[s] >>= 2; /* Q30 -> Q28 translation */ p_aout_buffer = SplitBuffer( p_dec ); assert( p_aout_buffer ); #ifdef NDEBUG msg_Dbg( p_dec, "%s took %"PRIi64" us",__func__,mdate()-start); #endif return p_aout_buffer; }
/***************************************************************************** * Thread: *****************************************************************************/ static void Thread( vlc_object_t *p_this ) { goom_thread_t *p_thread = (goom_thread_t*)p_this; vlc_value_t width, height, speed; audio_date_t i_pts; int16_t p_data[2][512]; int i_data = 0, i_count = 0; PluginInfo *p_plugin_info; var_Get( p_this, "goom-width", &width ); var_Get( p_this, "goom-height", &height ); var_Create( p_thread, "goom-speed", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT ); var_Get( p_thread, "goom-speed", &speed ); speed.i_int = MAX_SPEED - speed.i_int; if( speed.i_int < 0 ) speed.i_int = 0; p_plugin_info = goom_init( width.i_int, height.i_int ); while( !p_thread->b_die ) { uint32_t *plane; picture_t *p_pic; /* goom_update is damn slow, so just copy data and release the lock */ vlc_mutex_lock( &p_thread->lock ); if( FillBuffer( (int16_t *)p_data, &i_data, &i_pts, &p_thread->date, p_thread ) != VLC_SUCCESS ) vlc_cond_wait( &p_thread->wait, &p_thread->lock ); vlc_mutex_unlock( &p_thread->lock ); /* Speed selection */ if( speed.i_int && (++i_count % (speed.i_int+1)) ) continue; /* Frame dropping if necessary */ if( aout_DateGet( &i_pts ) + GOOM_DELAY <= mdate() ) continue; plane = goom_update( p_plugin_info, p_data, 0, 0.0, p_thread->psz_title, NULL ); if( p_thread->psz_title ) { free( p_thread->psz_title ); p_thread->psz_title = NULL; } while( !( p_pic = vout_CreatePicture( p_thread->p_vout, 0, 0, 0 ) ) && !p_thread->b_die ) { msleep( VOUT_OUTMEM_SLEEP ); } if( p_pic == NULL ) break; memcpy( p_pic->p[0].p_pixels, plane, width.i_int * height.i_int * 4 ); vout_DatePicture( p_thread->p_vout, p_pic, aout_DateGet( &i_pts ) + GOOM_DELAY ); vout_DisplayPicture( p_thread->p_vout, p_pic ); } goom_close( p_plugin_info ); }