📄 vorbis.c
字号:
p_dec->fmt_in.i_extra += oggpacket.bytes + 2; block_Release( *pp_block ); p_sys->i_headers++; return NULL; } if( p_sys->i_headers == 3 ) { if( ProcessHeaders( p_dec ) != VLC_SUCCESS ) { p_sys->i_headers = 0; p_dec->fmt_in.i_extra = 0; block_Release( *pp_block ); return NULL; } else p_sys->i_headers++; } return ProcessPacket( p_dec, &oggpacket, pp_block );}/***************************************************************************** * ProcessHeaders: process Vorbis headers. *****************************************************************************/static int ProcessHeaders( decoder_t *p_dec ){ decoder_sys_t *p_sys = p_dec->p_sys; ogg_packet oggpacket; uint8_t *p_extra; int i_extra; if( !p_dec->fmt_in.i_extra ) return VLC_EGENERIC; oggpacket.granulepos = -1; oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */ oggpacket.e_o_s = 0; oggpacket.packetno = 0; p_extra = p_dec->fmt_in.p_extra; i_extra = p_dec->fmt_in.i_extra; /* Take care of the initial Vorbis header */ oggpacket.bytes = *(p_extra++) << 8; oggpacket.bytes |= (*(p_extra++) & 0xFF); oggpacket.packet = p_extra; p_extra += oggpacket.bytes; i_extra -= (oggpacket.bytes + 2); if( i_extra < 0 ) { msg_Err( p_dec, "header data corrupted"); return VLC_EGENERIC; } if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 ) { msg_Err( p_dec, "this bitstream does not contain Vorbis audio data"); return VLC_EGENERIC; } /* Setup the format */ p_dec->fmt_out.audio.i_rate = p_sys->vi.rate; p_dec->fmt_out.audio.i_channels = p_sys->vi.channels; if( p_dec->fmt_out.audio.i_channels < 0 || p_dec->fmt_out.audio.i_channels > 6 ) { msg_Err( p_dec, "invalid number of channels (not between 1 and 6): %i", p_dec->fmt_out.audio.i_channels ); return VLC_EGENERIC; } p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_maps[p_sys->vi.channels]; p_dec->fmt_out.i_bitrate = p_sys->vi.bitrate_nominal; aout_DateInit( &p_sys->end_date, p_sys->vi.rate ); aout_DateSet( &p_sys->end_date, 0 ); msg_Dbg( p_dec, "channels:%d samplerate:%ld bitrate:%ld", p_sys->vi.channels, p_sys->vi.rate, p_sys->vi.bitrate_nominal ); /* The next packet in order is the comments header */ oggpacket.b_o_s = 0; oggpacket.bytes = *(p_extra++) << 8; oggpacket.bytes |= (*(p_extra++) & 0xFF); oggpacket.packet = p_extra; p_extra += oggpacket.bytes; i_extra -= (oggpacket.bytes + 2); if( i_extra < 0 ) { msg_Err( p_dec, "header data corrupted"); return VLC_EGENERIC; } if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 ) { msg_Err( p_dec, "2nd Vorbis header is corrupted" ); return VLC_EGENERIC; } ParseVorbisComments( p_dec ); /* The next packet in order is the codebooks header * We need to watch out that this packet is not missing as a * missing or corrupted header is fatal. */ oggpacket.bytes = *(p_extra++) << 8; oggpacket.bytes |= (*(p_extra++) & 0xFF); oggpacket.packet = p_extra; i_extra -= (oggpacket.bytes + 2); if( i_extra < 0 ) { msg_Err( p_dec, "header data corrupted"); return VLC_EGENERIC; } if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 ) { msg_Err( p_dec, "3rd Vorbis header is corrupted" ); return VLC_EGENERIC; } if( !p_sys->b_packetizer ) { /* Initialize the Vorbis packet->PCM decoder */ vorbis_synthesis_init( &p_sys->vd, &p_sys->vi ); vorbis_block_init( &p_sys->vd, &p_sys->vb ); } else { p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; p_dec->fmt_out.p_extra = realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); memcpy( p_dec->fmt_out.p_extra, p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra ); } ConfigureChannelOrder(p_sys->pi_chan_table, p_sys->vi.channels, p_dec->fmt_out.audio.i_physical_channels, VLC_TRUE); return VLC_SUCCESS;}/***************************************************************************** * ProcessPacket: processes a Vorbis 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 ) { return SendPacket( p_dec, p_oggpacket, p_block ); } else { aout_buffer_t *p_aout_buffer; if( p_sys->i_headers >= 3 ) p_aout_buffer = DecodePacket( p_dec, p_oggpacket ); else p_aout_buffer = NULL; if( p_block ) block_Release( p_block ); return p_aout_buffer; }}/***************************************************************************** * DecodePacket: decodes a Vorbis packet. *****************************************************************************/static aout_buffer_t *DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket ){ decoder_sys_t *p_sys = p_dec->p_sys; int i_samples;#ifdef MODULE_NAME_IS_tremor int32_t **pp_pcm;#else float **pp_pcm;#endif if( p_oggpacket->bytes &&#ifdef MODULE_NAME_IS_tremor vorbis_synthesis( &p_sys->vb, p_oggpacket, 1 ) == 0 )#else vorbis_synthesis( &p_sys->vb, p_oggpacket ) == 0 )#endif vorbis_synthesis_blockin( &p_sys->vd, &p_sys->vb ); /* **pp_pcm is a multichannel float vector. In stereo, for * example, pp_pcm[0] is left, and pp_pcm[1] is right. i_samples is * the size of each channel. Convert the float values * (-1.<=range<=1.) to whatever PCM format and write it out */ if( ( i_samples = vorbis_synthesis_pcmout( &p_sys->vd, &pp_pcm ) ) > 0 ) { aout_buffer_t *p_aout_buffer; p_aout_buffer = p_dec->pf_aout_buffer_new( p_dec, i_samples ); if( p_aout_buffer == NULL ) return NULL; /* Interleave the samples */#ifdef MODULE_NAME_IS_tremor Interleave( (int32_t *)p_aout_buffer->p_buffer, (const int32_t **)pp_pcm, p_sys->vi.channels, i_samples, p_sys->pi_chan_table);#else Interleave( (float *)p_aout_buffer->p_buffer, (const float **)pp_pcm, p_sys->vi.channels, i_samples, p_sys->pi_chan_table);#endif /* Tell libvorbis how many samples we actually consumed */ vorbis_synthesis_read( &p_sys->vd, i_samples ); /* Date management */ p_aout_buffer->start_date = aout_DateGet( &p_sys->end_date ); p_aout_buffer->end_date = aout_DateIncrement( &p_sys->end_date, i_samples ); return p_aout_buffer; } else { return NULL; }}/***************************************************************************** * SendPacket: send an ogg dated packet to the stream output. *****************************************************************************/static block_t *SendPacket( decoder_t *p_dec, ogg_packet *p_oggpacket, block_t *p_block ){ decoder_sys_t *p_sys = p_dec->p_sys; int i_block_size, i_samples; i_block_size = vorbis_packet_blocksize( &p_sys->vi, p_oggpacket ); if( i_block_size < 0 ) i_block_size = 0; /* non audio packet */ i_samples = ( p_sys->i_last_block_size + i_block_size ) >> 2; p_sys->i_last_block_size = i_block_size; /* Date management */ p_block->i_dts = p_block->i_pts = aout_DateGet( &p_sys->end_date ); if( p_sys->i_headers >= 3 ) p_block->i_length = aout_DateIncrement( &p_sys->end_date, i_samples ) - p_block->i_pts; else p_block->i_length = 0; return p_block;}/***************************************************************************** * ParseVorbisComments: FIXME should be done in demuxer *****************************************************************************/static void ParseVorbisComments( decoder_t *p_dec ){ input_thread_t *p_input = (input_thread_t *)p_dec->p_parent; char *psz_name, *psz_value, *psz_comment; int i = 0; if( p_input->i_object_type != VLC_OBJECT_INPUT ) return; while( i < p_dec->p_sys->vc.comments ) { psz_comment = strdup( p_dec->p_sys->vc.user_comments[i] ); if( !psz_comment ) { msg_Warn( p_dec, "out of memory" ); break; } psz_name = psz_comment; psz_value = strchr( psz_comment, '=' ); if( psz_value ) { *psz_value = '\0'; psz_value++; input_Control( p_input, INPUT_ADD_INFO, _("Vorbis comment"), psz_name, psz_value ); if( strcasestr( psz_name, "artist" ) ) { vlc_input_item_AddInfo( p_input->input.p_item, _(VLC_META_INFO_CAT), _(VLC_META_ARTIST), "%s", psz_value ); } else if( strcasestr( psz_name, "title" ) ) { p_input->input.p_item->psz_name = strdup( psz_value ); } } /* FIXME */ var_SetInteger( p_input, "item-change", p_input->input.p_item->i_id ); free( psz_comment ); i++; }}/***************************************************************************** * Interleave: helper function to interleave channels *****************************************************************************/static void ConfigureChannelOrder(int *pi_chan_table, int i_channels, uint32_t i_channel_mask, vlc_bool_t b_decode){ const uint32_t *pi_channels_in; switch( i_channels ) { case 6: case 5:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -