📄 speex.c
字号:
void *p_state; SpeexHeader *p_header; const SpeexMode *p_mode; SpeexCallback callback; p_sys->p_header = p_header = speex_packet_to_header( (char *)p_oggpacket->packet, p_oggpacket->bytes ); if( !p_header ) { msg_Err( p_dec, "cannot read Speex header" ); return VLC_EGENERIC; } if( p_header->mode >= SPEEX_NB_MODES || p_header->mode < 0 ) { msg_Err( p_dec, "mode number %d does not (yet/any longer) exist in " "this version of libspeex.", p_header->mode ); return VLC_EGENERIC; } p_mode = speex_mode_list[p_header->mode]; if( p_mode == NULL ) return VLC_EGENERIC; if( p_header->speex_version_id > 1 ) { msg_Err( p_dec, "this file was encoded with Speex bit-stream " "version %d which is not supported by this decoder.", p_header->speex_version_id ); return VLC_EGENERIC; } if( p_mode->bitstream_version < p_header->mode_bitstream_version ) { msg_Err( p_dec, "file encoded with a newer version of Speex." ); return VLC_EGENERIC; } if( p_mode->bitstream_version > p_header->mode_bitstream_version ) { msg_Err( p_dec, "file encoded with an older version of Speex." ); return VLC_EGENERIC; } msg_Dbg( p_dec, "Speex %d Hz audio using %s mode %s%s", p_header->rate, p_mode->modeName, ( p_header->nb_channels == 1 ) ? " (mono" : " (stereo", p_header->vbr ? ", VBR)" : ")" ); /* Take care of speex decoder init */ speex_bits_init( &p_sys->bits ); p_sys->p_state = p_state = speex_decoder_init( p_mode ); if( !p_state ) { msg_Err( p_dec, "decoder initialization failed" ); return VLC_EGENERIC; } if( p_header->nb_channels == 2 ) { SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT; p_sys->stereo = stereo; callback.callback_id = SPEEX_INBAND_STEREO; callback.func = speex_std_stereo_request_handler; callback.data = &p_sys->stereo; speex_decoder_ctl( p_state, SPEEX_SET_HANDLER, &callback ); } if( p_header->nb_channels <= 0 || p_header->nb_channels > 5 ) { msg_Err( p_dec, "invalid number of channels (not between 1 and 5): %i", p_header->nb_channels ); return VLC_EGENERIC; } /* Setup the format */ p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_maps[p_header->nb_channels]; p_dec->fmt_out.audio.i_channels = p_header->nb_channels; p_dec->fmt_out.audio.i_rate = p_header->rate; aout_DateInit( &p_sys->end_date, p_header->rate ); return VLC_SUCCESS;}/***************************************************************************** * ProcessPacket: processes a Speex packet. *****************************************************************************/static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket, block_t **pp_block ){ decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block = *pp_block; /* Date management */ if( p_block && 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 ); } if( !aout_DateGet( &p_sys->end_date ) ) { /* We've just started the stream, wait for the first PTS. */ if( p_block ) block_Release( p_block ); return NULL; } *pp_block = NULL; /* To avoid being fed the same packet again */ if( p_sys->b_packetizer ) { if ( p_sys->p_header->frames_per_packet > 1 ) { short *p_frame_holder = NULL; int i_bits_before = 0, i_bits_after = 0, i_bytes_in_speex_frame = 0, i_pcm_output_size = 0, i_bits_in_speex_frame = 0; block_t *p_new_block = NULL; i_pcm_output_size = p_sys->p_header->frame_size; p_frame_holder = (short*)malloc( sizeof(short)*i_pcm_output_size ); speex_bits_read_from( &p_sys->bits, (char*)p_oggpacket->packet, p_oggpacket->bytes); i_bits_before = speex_bits_remaining( &p_sys->bits ); speex_decode_int(p_sys->p_state, &p_sys->bits, p_frame_holder); i_bits_after = speex_bits_remaining( &p_sys->bits ); i_bits_in_speex_frame = i_bits_before - i_bits_after; i_bytes_in_speex_frame = ( i_bits_in_speex_frame + (8 - (i_bits_in_speex_frame % 8)) ) / 8; p_new_block = block_New( p_dec, i_bytes_in_speex_frame ); memset( p_new_block->p_buffer, 0xff, i_bytes_in_speex_frame ); /* * Copy the first frame in this packet to a new packet. */ speex_bits_rewind( &p_sys->bits ); speex_bits_write( &p_sys->bits, (char*)p_new_block->p_buffer, (int)i_bytes_in_speex_frame ); /* * Move the remaining part of the original packet (subsequent * frames, if there are any) into the beginning * of the original packet so * they are preserved following the realloc. * Note: Any bits that * remain in the initial packet * are "filler" if they do not constitute * an entire byte. */ if ( i_bits_after > 7 ) { /* round-down since we rounded-up earlier (to include * the speex terminator code. */ i_bytes_in_speex_frame--; speex_bits_write( &p_sys->bits, (char*)p_block->p_buffer, p_block->i_buffer - i_bytes_in_speex_frame ); p_block = block_Realloc( p_block, 0, p_block->i_buffer-i_bytes_in_speex_frame ); *pp_block = p_block; } else { speex_bits_reset( &p_sys->bits ); } free( p_frame_holder ); return SendPacket( p_dec, p_new_block); } else { return SendPacket( p_dec, p_block ); } } else { aout_buffer_t *p_aout_buffer; if( p_sys->i_headers >= p_sys->p_header->extra_headers + 2 ) p_aout_buffer = DecodePacket( p_dec, p_oggpacket ); else p_aout_buffer = NULL; /* Skip headers */ if( p_block ) block_Release( p_block ); return p_aout_buffer; }}static aout_buffer_t *DecodeRtpSpeexPacket( decoder_t *p_dec, block_t **pp_block ){ block_t *p_speex_bit_block = *pp_block; decoder_sys_t *p_sys = p_dec->p_sys; aout_buffer_t *p_aout_buffer; int i_decode_ret; unsigned int i_speex_frame_size; if ( !p_speex_bit_block || p_speex_bit_block->i_pts == 0 ) return NULL; /* If the SpeexBits buffer size is 0 (a default value), we know that a proper initialization has not yet been done. */ if ( p_sys->bits.buf_size==0 ) { p_sys->p_header = (SpeexHeader *)malloc(sizeof(SpeexHeader)); if ( !p_sys->p_header ) { msg_Err( p_dec, "Could not allocate a Speex header."); return NULL; } speex_init_header( p_sys->p_header,p_sys->rtp_rate,1,&speex_nb_mode ); speex_bits_init( &p_sys->bits ); p_sys->p_state = speex_decoder_init( &speex_nb_mode ); if ( !p_sys->p_state ) { msg_Err( p_dec, "Could not allocate a Speex decoder." ); free( p_sys->p_header ); return NULL; } /* Assume that variable bit rate is enabled. Also assume that there is only one frame per packet. */ p_sys->p_header->vbr = 1; p_sys->p_header->frames_per_packet = 1; p_dec->fmt_out.audio.i_channels = p_sys->p_header->nb_channels; p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_maps[p_sys->p_header->nb_channels]; p_dec->fmt_out.audio.i_rate = p_sys->p_header->rate; if ( speex_mode_query( &speex_nb_mode, SPEEX_MODE_FRAME_SIZE, &i_speex_frame_size ) ) { msg_Err( p_dec, "Could not determine the frame size." ); speex_decoder_destroy( p_sys->p_state ); free( p_sys->p_header ); return NULL; } p_dec->fmt_out.audio.i_bytes_per_frame = i_speex_frame_size; aout_DateInit(&p_sys->end_date, p_sys->p_header->rate); } /* If the SpeexBits are initialized but there is still no header, an error must be thrown. */ if ( !p_sys->p_header ) { msg_Err( p_dec, "There is no valid Speex header found." ); return NULL; } *pp_block = NULL; if ( !aout_DateGet( &p_sys->end_date ) ) aout_DateSet( &p_sys->end_date, p_speex_bit_block->i_dts ); /* Ask for a new audio output buffer and make sure we get one. */ p_aout_buffer = p_dec->pf_aout_buffer_new( p_dec, p_sys->p_header->frame_size ); if ( !p_aout_buffer || p_aout_buffer->i_nb_bytes == 0 ) { msg_Err(p_dec, "Oops: No new buffer was returned!"); return NULL; } /* Read the Speex payload into the SpeexBits buffer. */ speex_bits_read_from( &p_sys->bits, (char*)p_speex_bit_block->p_buffer, p_speex_bit_block->i_buffer ); /* Decode the input and ensure that no errors were encountered. */ i_decode_ret = speex_decode_int( p_sys->p_state, &p_sys->bits, (int16_t*)p_aout_buffer->p_buffer ); if ( i_decode_ret < 0 ) { msg_Err( p_dec, "Decoding failed. Perhaps we have a bad stream?" ); return NULL; } /* Handle date management on the audio output buffer. */ p_aout_buffer->start_date = aout_DateGet( &p_sys->end_date ); p_aout_buffer->end_date = aout_DateIncrement( &p_sys->end_date, p_sys->p_header->frame_size ); p_sys->i_frame_in_packet++; block_Release( p_speex_bit_block ); return p_aout_buffer;}/***************************************************************************** * DecodePacket: decodes a Speex packet. *****************************************************************************/static aout_buffer_t *DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket ){ decoder_sys_t *p_sys = p_dec->p_sys; if( p_oggpacket->bytes ) { /* Copy Ogg packet to Speex bitstream */ speex_bits_read_from( &p_sys->bits, (char *)p_oggpacket->packet, p_oggpacket->bytes ); p_sys->i_frame_in_packet = 0; } /* Decode one frame at a time */ if( p_sys->i_frame_in_packet < p_sys->p_header->frames_per_packet ) { aout_buffer_t *p_aout_buffer; if( p_sys->p_header->frame_size == 0 ) return NULL; p_aout_buffer = p_dec->pf_aout_buffer_new( p_dec, p_sys->p_header->frame_size ); if( !p_aout_buffer ) { return NULL; } switch( speex_decode_int( p_sys->p_state, &p_sys->bits,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -