static void ConfigureChannelOrder(uint8_t *pi_chan_table, int i_channels, uint32_t i_channel_mask, bool b_decode) { const uint32_t *pi_channels_in; switch( i_channels ) { case 8: pi_channels_in = pi_8channels_in; break; case 7: pi_channels_in = pi_7channels_in; break; case 6: case 5: pi_channels_in = pi_6channels_in; break; case 4: pi_channels_in = pi_4channels_in; break; case 3: pi_channels_in = pi_3channels_in; break; default: { int i; for( i = 0; i< i_channels; ++i ) { pi_chan_table[i] = i; } return; } } if( b_decode ) aout_CheckChannelReorder( pi_channels_in, NULL, i_channel_mask, pi_chan_table ); else aout_CheckChannelReorder( NULL, pi_channels_in, i_channel_mask, pi_chan_table ); }
/***************************************************************************** * ProcessInitialHeader: processes the inital Opus header packet. *****************************************************************************/ static int ProcessInitialHeader( decoder_t *p_dec, ogg_packet *p_oggpacket ) { int err; unsigned char new_stream_map[8]; decoder_sys_t *p_sys = p_dec->p_sys; OpusHeader *p_header = &p_sys->header; if( !opus_header_parse((unsigned char *)p_oggpacket->packet,p_oggpacket->bytes,p_header) ) { msg_Err( p_dec, "cannot read Opus header" ); return VLC_EGENERIC; } msg_Dbg( p_dec, "Opus audio with %d channels", p_header->channels); if((p_header->channels>2 && p_header->channel_mapping==0) || (p_header->channels>8 && p_header->channel_mapping==1) || p_header->channel_mapping>1) { msg_Err( p_dec, "Unsupported channel mapping" ); 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->channels]; p_dec->fmt_out.audio.i_channels = p_header->channels; p_dec->fmt_out.audio.i_rate = 48000; if( p_header->channels>2 && p_header->channels<9 ) { static const uint32_t *pi_ch[6] = { pi_3channels_in, pi_4channels_in, pi_5channels_in, pi_6channels_in, pi_7channels_in, pi_8channels_in }; uint8_t pi_chan_table[AOUT_CHAN_MAX]; aout_CheckChannelReorder( pi_ch[p_header->channels-3], NULL, p_dec->fmt_out.audio.i_physical_channels, pi_chan_table ); for(int i=0;i<p_header->channels;i++) new_stream_map[pi_chan_table[i]]=p_header->stream_map[i]; } /* Opus decoder init */ p_sys->p_st = opus_multistream_decoder_create( 48000, p_header->channels, p_header->nb_streams, p_header->nb_coupled, p_header->channels>2?new_stream_map:p_header->stream_map, &err ); if( !p_sys->p_st || err!=OPUS_OK ) { msg_Err( p_dec, "decoder initialization failed" ); return VLC_EGENERIC; } #ifdef OPUS_SET_GAIN if( opus_multistream_decoder_ctl( p_sys->p_st,OPUS_SET_GAIN(p_header->gain) ) != OPUS_OK ) { msg_Err( p_dec, "OPUS_SET_GAIN failed" ); opus_multistream_decoder_destroy( p_sys->p_st ); return VLC_EGENERIC; } #endif date_Init( &p_sys->end_date, 48000, 1 ); return VLC_SUCCESS; }
/***************************************************************************** * Open: *****************************************************************************/ static int Open( vlc_object_t *p_this, filter_sys_t *p_sys, audio_format_t input, audio_format_t output ) { p_sys->b_dynrng = var_InheritBool( p_this, "a52-dynrng" ); p_sys->b_dontwarn = 0; /* No upmixing: it's not necessary and some other filters may want to do * it themselves. */ if ( aout_FormatNbChannels( &output ) > aout_FormatNbChannels( &input ) ) { if ( ! var_InheritBool( p_this, "a52-upmix" ) ) { return VLC_EGENERIC; } } /* We'll do our own downmixing, thanks. */ p_sys->i_nb_channels = aout_FormatNbChannels( &output ); switch ( (output.i_physical_channels & AOUT_CHAN_PHYSMASK) & ~AOUT_CHAN_LFE ) { case AOUT_CHAN_CENTER: if ( (output.i_original_channels & AOUT_CHAN_CENTER) || (output.i_original_channels & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) ) { p_sys->i_flags = A52_MONO; } else if ( output.i_original_channels & AOUT_CHAN_LEFT ) { p_sys->i_flags = A52_CHANNEL1; } else { p_sys->i_flags = A52_CHANNEL2; } break; case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT: if ( output.i_original_channels & AOUT_CHAN_DOLBYSTEREO ) { p_sys->i_flags = A52_DOLBY; } else if ( input.i_original_channels == AOUT_CHAN_CENTER ) { p_sys->i_flags = A52_MONO; } else if ( input.i_original_channels & AOUT_CHAN_DUALMONO ) { p_sys->i_flags = A52_CHANNEL; } else if ( !(output.i_original_channels & AOUT_CHAN_RIGHT) ) { p_sys->i_flags = A52_CHANNEL1; } else if ( !(output.i_original_channels & AOUT_CHAN_LEFT) ) { p_sys->i_flags = A52_CHANNEL2; } else { p_sys->i_flags = A52_STEREO; } break; case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER: p_sys->i_flags = A52_3F; break; case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARCENTER: p_sys->i_flags = A52_2F1R; break; case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARCENTER: p_sys->i_flags = A52_3F1R; break; case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT: p_sys->i_flags = A52_2F2R; break; case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT: p_sys->i_flags = A52_3F2R; break; default: msg_Warn( p_this, "unknown sample format!" ); free( p_sys ); return VLC_EGENERIC; } if ( output.i_physical_channels & AOUT_CHAN_LFE ) { p_sys->i_flags |= A52_LFE; } p_sys->i_flags |= A52_ADJUST_LEVEL; /* Initialize liba52 */ p_sys->p_liba52 = a52_init( 0 ); if( p_sys->p_liba52 == NULL ) { msg_Err( p_this, "unable to initialize liba52" ); free( p_sys ); return VLC_EGENERIC; } aout_CheckChannelReorder( pi_channels_in, NULL, output.i_physical_channels & AOUT_CHAN_PHYSMASK, p_sys->i_nb_channels, p_sys->pi_chan_table ); return VLC_SUCCESS; }
static int BdHeader( decoder_sys_t *p_sys, unsigned *pi_rate, unsigned *pi_channels, unsigned *pi_channels_padding, unsigned *pi_original_channels, unsigned *pi_bits, const uint8_t *p_header ) { const uint32_t h = GetDWBE( p_header ); const uint32_t *pi_channels_in = NULL; switch( ( h & 0xf000) >> 12 ) { case 1: *pi_channels = 1; *pi_original_channels = AOUT_CHAN_CENTER; break; case 3: *pi_channels = 2; *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; break; case 4: *pi_channels = 3; *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER; pi_channels_in = pi_3channels_in; break; case 5: *pi_channels = 3; *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARCENTER; break; case 6: *pi_channels = 4; *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARCENTER; break; case 7: *pi_channels = 4; *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; pi_channels_in = pi_4channels_in; break; case 8: *pi_channels = 5; *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; pi_channels_in = pi_5channels_in; break; case 9: *pi_channels = 6; *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; pi_channels_in = pi_6channels_in; break; case 10: *pi_channels = 7; *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT; pi_channels_in = pi_7channels_in; break; case 11: *pi_channels = 8; *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE; pi_channels_in = pi_8channels_in; break; default: return -1; } *pi_channels_padding = *pi_channels & 1; switch( (h >> 6) & 0x03 ) { case 1: *pi_bits = 16; break; case 2: /* 20 bits but samples are stored on 24 bits */ case 3: /* 24 bits */ *pi_bits = 24; break; default: return -1; } switch( (h >> 8) & 0x0f ) { case 1: *pi_rate = 48000; break; case 4: *pi_rate = 96000; break; case 5: *pi_rate = 192000; break; default: return -1; } if( pi_channels_in ) { p_sys->i_chans_to_reorder = aout_CheckChannelReorder( pi_channels_in, NULL, *pi_original_channels, p_sys->pi_chan_table ); } return 0; }
/***************************************************************************** * Open: *****************************************************************************/ static int Open( vlc_object_t *p_this, filter_sys_t *p_sys, audio_format_t input, audio_format_t output ) { p_sys->b_dynrng = config_GetInt( p_this, "dts-dynrng" ); p_sys->b_dontwarn = 0; /* We'll do our own downmixing, thanks. */ p_sys->i_nb_channels = aout_FormatNbChannels( &output ); switch ( (output.i_physical_channels & AOUT_CHAN_PHYSMASK) & ~AOUT_CHAN_LFE ) { case AOUT_CHAN_CENTER: if ( (output.i_original_channels & AOUT_CHAN_CENTER) || (output.i_original_channels & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) ) { p_sys->i_flags = DTS_MONO; } break; case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT: if ( output.i_original_channels & AOUT_CHAN_DOLBYSTEREO ) { p_sys->i_flags = DTS_DOLBY; } else if ( input.i_original_channels == AOUT_CHAN_CENTER ) { p_sys->i_flags = DTS_MONO; } else if ( input.i_original_channels & AOUT_CHAN_DUALMONO ) { p_sys->i_flags = DTS_CHANNEL; } else { p_sys->i_flags = DTS_STEREO; } break; case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER: p_sys->i_flags = DTS_3F; break; case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARCENTER: p_sys->i_flags = DTS_2F1R; break; case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARCENTER: p_sys->i_flags = DTS_3F1R; break; case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT: p_sys->i_flags = DTS_2F2R; break; case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT: p_sys->i_flags = DTS_3F2R; break; default: msg_Warn( p_this, "unknown sample format!" ); free( p_sys ); return -1; } if ( output.i_physical_channels & AOUT_CHAN_LFE ) { p_sys->i_flags |= DTS_LFE; } //p_sys->i_flags |= DTS_ADJUST_LEVEL; /* Initialize libdts */ p_sys->p_libdts = dts_init( 0 ); if( p_sys->p_libdts == NULL ) { msg_Err( p_this, "unable to initialize libdts" ); return VLC_EGENERIC; } aout_CheckChannelReorder( pi_channels_in, pi_channels_out, output.i_physical_channels & AOUT_CHAN_PHYSMASK, p_sys->i_nb_channels, p_sys->pi_chan_table ); return VLC_SUCCESS; }
static int Open( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t *)p_this; decoder_sys_t *p_sys; if( p_dec->fmt_in.i_codec != VLC_CODEC_DTS || p_dec->fmt_in.audio.i_rate == 0 || p_dec->fmt_in.audio.i_physical_channels == 0 || p_dec->fmt_in.audio.i_original_channels == 0 || p_dec->fmt_in.audio.i_bytes_per_frame == 0 || p_dec->fmt_in.audio.i_frame_length == 0 ) return VLC_EGENERIC; /* Allocate the memory needed to store the module's structure */ p_sys = p_dec->p_sys = malloc( sizeof(decoder_sys_t) ); if( p_sys == NULL ) return VLC_ENOMEM; p_sys->b_dynrng = var_InheritBool( p_this, "dts-dynrng" ); p_sys->b_dontwarn = 0; /* We'll do our own downmixing, thanks. */ p_sys->i_nb_channels = aout_FormatNbChannels( &p_dec->fmt_in.audio ); if( channels_vlc2dca( &p_dec->fmt_in.audio, &p_sys->i_flags ) != VLC_SUCCESS ) { msg_Warn( p_this, "unknown sample format!" ); free( p_sys ); return VLC_EGENERIC; } //p_sys->i_flags |= DCA_ADJUST_LEVEL; /* Initialize libdca */ p_sys->p_libdca = dca_init( 0 ); if( p_sys->p_libdca == NULL ) { msg_Err( p_this, "unable to initialize libdca" ); free( p_sys ); return VLC_EGENERIC; } /* libdca channel order * libdca currently only decodes 5.1, even if you have a DTS-ES source. */ static const uint32_t pi_channels_in[] = { AOUT_CHAN_CENTER, AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_REARCENTER, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_LFE, 0 }; aout_CheckChannelReorder( pi_channels_in, NULL, p_dec->fmt_in.audio.i_physical_channels, p_sys->pi_chan_table ); p_dec->fmt_out.i_cat = AUDIO_ES; p_dec->fmt_out.audio = p_dec->fmt_in.audio; p_dec->fmt_out.audio.i_format = VLC_CODEC_FL32; p_dec->fmt_out.i_codec = p_dec->fmt_out.audio.i_format; aout_FormatPrepare( &p_dec->fmt_out.audio ); if( decoder_UpdateAudioFormat( p_dec ) ) { es_format_Init( &p_dec->fmt_out, UNKNOWN_ES, 0 ); Close( p_this ); return VLC_EGENERIC; } p_dec->pf_decode = Decode; p_dec->pf_flush = NULL; return VLC_SUCCESS; }
/** * Creates a DirectSound buffer of the required format. * * This function creates the buffer we'll use to play audio. * In DirectSound there are two kinds of buffers: * - the primary buffer: which is the actual buffer that the soundcard plays * - the secondary buffer(s): these buffers are the one actually used by * applications and DirectSound takes care of mixing them into the primary. * * Once you create a secondary buffer, you cannot change its format anymore so * you have to release the current one and create another. */ static HRESULT CreateDSBuffer( vlc_object_t *obj, aout_stream_sys_t *sys, int i_format, int i_channels, int i_nb_channels, int i_rate, bool b_probe ) { WAVEFORMATEXTENSIBLE waveformat; DSBUFFERDESC dsbdesc; HRESULT hr; /* First set the sound buffer format */ waveformat.dwChannelMask = 0; for( unsigned i = 0; pi_vlc_chan_order_wg4[i]; i++ ) if( i_channels & pi_vlc_chan_order_wg4[i] ) waveformat.dwChannelMask |= pi_channels_in[i]; switch( i_format ) { case VLC_CODEC_SPDIFL: i_nb_channels = 2; /* To prevent channel re-ordering */ waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; waveformat.Format.wBitsPerSample = 16; waveformat.Samples.wValidBitsPerSample = waveformat.Format.wBitsPerSample; waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF; break; case VLC_CODEC_FL32: waveformat.Format.wBitsPerSample = sizeof(float) * 8; waveformat.Samples.wValidBitsPerSample = waveformat.Format.wBitsPerSample; waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; break; case VLC_CODEC_S16N: waveformat.Format.wBitsPerSample = 16; waveformat.Samples.wValidBitsPerSample = waveformat.Format.wBitsPerSample; waveformat.Format.wFormatTag = WAVE_FORMAT_PCM; waveformat.SubFormat = _KSDATAFORMAT_SUBTYPE_PCM; break; } waveformat.Format.nChannels = i_nb_channels; waveformat.Format.nSamplesPerSec = i_rate; waveformat.Format.nBlockAlign = waveformat.Format.wBitsPerSample / 8 * i_nb_channels; waveformat.Format.nAvgBytesPerSec = waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign; sys->i_bytes_per_sample = waveformat.Format.nBlockAlign; sys->format = i_format; /* Then fill in the direct sound descriptor */ memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); dsbdesc.dwSize = sizeof(DSBUFFERDESC); dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 /* Better position accuracy */ | DSBCAPS_GLOBALFOCUS /* Allows background playing */ | DSBCAPS_CTRLVOLUME /* Allows volume control */ | DSBCAPS_CTRLPOSITIONNOTIFY; /* Allow position notifications */ /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */ if( i_nb_channels <= 2 ) { waveformat.Format.cbSize = 0; } else { waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; waveformat.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); /* Needed for 5.1 on emu101k */ dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE; } dsbdesc.dwBufferBytes = DS_BUF_SIZE; /* buffer size */ dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&waveformat; /* CreateSoundBuffer doesn't allow volume control for non-PCM buffers */ if ( i_format == VLC_CODEC_SPDIFL ) dsbdesc.dwFlags &= ~DSBCAPS_CTRLVOLUME; hr = IDirectSound_CreateSoundBuffer( sys->p_dsobject, &dsbdesc, &sys->p_dsbuffer, NULL ); if( FAILED(hr) ) { if( !(dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE) ) return hr; /* Try without DSBCAPS_LOCHARDWARE */ dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE; hr = IDirectSound_CreateSoundBuffer( sys->p_dsobject, &dsbdesc, &sys->p_dsbuffer, NULL ); if( FAILED(hr) ) return hr; if( !b_probe ) msg_Dbg( obj, "couldn't use hardware sound buffer" ); } /* Stop here if we were just probing */ if( b_probe ) { IDirectSoundBuffer_Release( sys->p_dsbuffer ); sys->p_dsbuffer = NULL; return DS_OK; } sys->i_rate = i_rate; sys->i_channel_mask = waveformat.dwChannelMask; sys->chans_to_reorder = aout_CheckChannelReorder( pi_channels_in, pi_channels_out, waveformat.dwChannelMask, sys->chan_table ); if( sys->chans_to_reorder ) msg_Dbg( obj, "channel reordering needed" ); hr = IDirectSoundBuffer_QueryInterface( sys->p_dsbuffer, &IID_IDirectSoundNotify, (void **) &sys->p_notify ); if( hr != DS_OK ) { msg_Err( obj, "Couldn't query IDirectSoundNotify" ); sys->p_notify = NULL; } FillBuffer( obj, sys, NULL ); return DS_OK; }
/***************************************************************************** * OpenWaveOut: open the waveout sound device ****************************************************************************/ static int OpenWaveOut( aout_instance_t *p_aout, int i_format, int i_channels, int i_nb_channels, int i_rate, vlc_bool_t b_probe ) { MMRESULT result; unsigned int i; /* Set sound format */ #define waveformat p_aout->output.p_sys->waveformat waveformat.dwChannelMask = 0; for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ ) { if( i_channels & pi_channels_src[i] ) waveformat.dwChannelMask |= pi_channels_in[i]; } switch( i_format ) { case VLC_FOURCC('s','p','d','i'): i_nb_channels = 2; /* To prevent channel re-ordering */ waveformat.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; waveformat.Format.wBitsPerSample = 16; waveformat.Samples.wValidBitsPerSample = waveformat.Format.wBitsPerSample; waveformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF; break; case VLC_FOURCC('f','l','3','2'): waveformat.Format.wBitsPerSample = sizeof(float) * 8; waveformat.Samples.wValidBitsPerSample = waveformat.Format.wBitsPerSample; waveformat.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; break; case VLC_FOURCC('s','1','6','l'): waveformat.Format.wBitsPerSample = 16; waveformat.Samples.wValidBitsPerSample = waveformat.Format.wBitsPerSample; waveformat.Format.wFormatTag = WAVE_FORMAT_PCM; waveformat.SubFormat = __KSDATAFORMAT_SUBTYPE_PCM; break; } waveformat.Format.nChannels = i_nb_channels; waveformat.Format.nSamplesPerSec = i_rate; waveformat.Format.nBlockAlign = waveformat.Format.wBitsPerSample / 8 * i_nb_channels; waveformat.Format.nAvgBytesPerSec = waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign; /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */ if( i_nb_channels <= 2 ) { waveformat.Format.cbSize = 0; } else { waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; waveformat.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); } /* Open the device */ result = waveOutOpen( &p_aout->output.p_sys->h_waveout, WAVE_MAPPER, (WAVEFORMATEX *)&waveformat, (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout, CALLBACK_FUNCTION | (b_probe?WAVE_FORMAT_QUERY:0) ); if( result == WAVERR_BADFORMAT ) { msg_Warn( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" ); return VLC_EGENERIC; } if( result == MMSYSERR_ALLOCATED ) { msg_Warn( p_aout, "waveOutOpen failed WAVERR_ALLOCATED" ); return VLC_EGENERIC; } if( result != MMSYSERR_NOERROR ) { msg_Warn( p_aout, "waveOutOpen failed" ); return VLC_EGENERIC; } p_aout->output.p_sys->b_chan_reorder = aout_CheckChannelReorder( pi_channels_in, pi_channels_out, waveformat.dwChannelMask, i_nb_channels, p_aout->output.p_sys->pi_chan_table ); if( p_aout->output.p_sys->b_chan_reorder ) { msg_Dbg( p_aout, "channel reordering needed" ); } return VLC_SUCCESS; #undef waveformat }
/***************************************************************************** * Open: check file and initializes structures *****************************************************************************/ static int Open( vlc_object_t * p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; const uint8_t *p_peek; unsigned int i_size; unsigned int i_extended; const char *psz_name; WAVEFORMATEXTENSIBLE *p_wf_ext = NULL; WAVEFORMATEX *p_wf = NULL; /* Is it a wav file ? */ if( stream_Peek( p_demux->s, &p_peek, 12 ) < 12 ) return VLC_EGENERIC; if( memcmp( p_peek, "RIFF", 4 ) || memcmp( &p_peek[8], "WAVE", 4 ) ) { return VLC_EGENERIC; } p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys = malloc( sizeof( *p_sys ) ); if( unlikely(!p_sys) ) return VLC_ENOMEM; p_sys->p_es = NULL; p_sys->i_chans_to_reorder = 0; p_sys->i_channel_mask = 0; /* skip riff header */ if( stream_Read( p_demux->s, NULL, 12 ) != 12 ) goto error; /* search fmt chunk */ if( ChunkFind( p_demux, "fmt ", &i_size ) ) { msg_Err( p_demux, "cannot find 'fmt ' chunk" ); goto error; } i_size += 2; if( i_size < sizeof( WAVEFORMATEX ) ) { msg_Err( p_demux, "invalid 'fmt ' chunk" ); goto error; } if( stream_Read( p_demux->s, NULL, 8 ) != 8 ) goto error; /* load waveformatex */ p_wf_ext = malloc( i_size ); if( unlikely( !p_wf_ext ) ) goto error; p_wf = &p_wf_ext->Format; p_wf->cbSize = 0; i_size -= 2; if( stream_Read( p_demux->s, p_wf, i_size ) != (int)i_size || ( ( i_size & 1 ) && stream_Read( p_demux->s, NULL, 1 ) != 1 ) ) { msg_Err( p_demux, "cannot load 'fmt ' chunk" ); goto error; } es_format_Init( &p_sys->fmt, AUDIO_ES, 0 ); wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &p_sys->fmt.i_codec, &psz_name ); p_sys->fmt.audio.i_channels = GetWLE ( &p_wf->nChannels ); p_sys->fmt.audio.i_rate = GetDWLE( &p_wf->nSamplesPerSec ); p_sys->fmt.audio.i_blockalign = GetWLE( &p_wf->nBlockAlign ); p_sys->fmt.i_bitrate = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8; p_sys->fmt.audio.i_bitspersample = GetWLE( &p_wf->wBitsPerSample ); if( i_size >= sizeof(WAVEFORMATEX) ) p_sys->fmt.i_extra = __MIN( GetWLE( &p_wf->cbSize ), i_size - sizeof(WAVEFORMATEX) ); i_extended = 0; /* Handle new WAVE_FORMAT_EXTENSIBLE wav files */ /* see the following link for more information: * http://www.microsoft.com/whdc/device/audio/multichaud.mspx#EFAA */ if( GetWLE( &p_wf->wFormatTag ) == WAVE_FORMAT_EXTENSIBLE && i_size >= sizeof( WAVEFORMATEXTENSIBLE ) && ( p_sys->fmt.i_extra + sizeof( WAVEFORMATEX ) >= sizeof( WAVEFORMATEXTENSIBLE ) ) ) { unsigned i_channel_mask; GUID guid_subformat; guid_subformat = p_wf_ext->SubFormat; guid_subformat.Data1 = GetDWLE( &p_wf_ext->SubFormat.Data1 ); guid_subformat.Data2 = GetWLE( &p_wf_ext->SubFormat.Data2 ); guid_subformat.Data3 = GetWLE( &p_wf_ext->SubFormat.Data3 ); sf_tag_to_fourcc( &guid_subformat, &p_sys->fmt.i_codec, &psz_name ); i_extended = sizeof( WAVEFORMATEXTENSIBLE ) - sizeof( WAVEFORMATEX ); p_sys->fmt.i_extra -= i_extended; i_channel_mask = GetDWLE( &p_wf_ext->dwChannelMask ); if( i_channel_mask ) { int i_match = 0; for( unsigned i = 0; i < sizeof(pi_channels_src)/sizeof(*pi_channels_src); i++ ) { if( i_channel_mask & pi_channels_src[i] ) { if( !( p_sys->i_channel_mask & pi_channels_in[i] ) ) i_match++; i_channel_mask &= ~pi_channels_src[i]; p_sys->i_channel_mask |= pi_channels_in[i]; if( i_match >= p_sys->fmt.audio.i_channels ) break; } } if( i_channel_mask ) msg_Warn( p_demux, "Some channels are unrecognized or uselessly specified (0x%x)", i_channel_mask ); if( i_match < p_sys->fmt.audio.i_channels ) { int i_missing = p_sys->fmt.audio.i_channels - i_match; msg_Warn( p_demux, "Trying to fill up unspecified position for %d channels", p_sys->fmt.audio.i_channels - i_match ); static const uint32_t pi_pair[] = { AOUT_CHAN_REARLEFT|AOUT_CHAN_REARRIGHT, AOUT_CHAN_MIDDLELEFT|AOUT_CHAN_MIDDLERIGHT, AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT }; /* FIXME: Unused yet static const uint32_t pi_center[] = { AOUT_CHAN_REARCENTER, 0, AOUT_CHAN_CENTER }; */ /* Try to complete with pair */ for( unsigned i = 0; i < sizeof(pi_pair)/sizeof(*pi_pair); i++ ) { if( i_missing >= 2 && !(p_sys->i_channel_mask & pi_pair[i] ) ) { i_missing -= 2; p_sys->i_channel_mask |= pi_pair[i]; } } /* Well fill up with what we can */ for( unsigned i = 0; i < sizeof(pi_channels_in)/sizeof(*pi_channels_in) && i_missing > 0; i++ ) { if( !( p_sys->i_channel_mask & pi_channels_in[i] ) ) { p_sys->i_channel_mask |= pi_channels_in[i]; i_missing--; if( i_missing <= 0 ) break; } } i_match = p_sys->fmt.audio.i_channels - i_missing; } if( i_match < p_sys->fmt.audio.i_channels ) { msg_Err( p_demux, "Invalid/unsupported channel mask" ); p_sys->i_channel_mask = 0; } } } else if( GetWLE( &p_wf->wFormatTag ) == WAVE_FORMAT_PCM && p_sys->fmt.audio.i_channels > 2 && p_sys->fmt.audio.i_channels <= 9 ) { for( int i = 0; i < p_sys->fmt.audio.i_channels; i++ ) p_sys->i_channel_mask |= pi_channels_in[i]; } if( p_sys->i_channel_mask ) { if( p_sys->fmt.i_codec == VLC_FOURCC('a','r','a','w') || p_sys->fmt.i_codec == VLC_FOURCC('p','c','m',' ') || p_sys->fmt.i_codec == VLC_FOURCC('a','f','l','t') ) p_sys->i_chans_to_reorder = aout_CheckChannelReorder( pi_channels_in, NULL, p_sys->i_channel_mask, p_sys->pi_chan_table ); msg_Dbg( p_demux, "channel mask: %x, reordering: %u", p_sys->i_channel_mask, p_sys->i_chans_to_reorder ); } p_sys->fmt.audio.i_physical_channels = p_sys->fmt.audio.i_original_channels = p_sys->i_channel_mask; if( p_sys->fmt.i_extra > 0 ) { p_sys->fmt.p_extra = malloc( p_sys->fmt.i_extra ); if( unlikely(!p_sys->fmt.p_extra) ) { p_sys->fmt.i_extra = 0; goto error; } memcpy( p_sys->fmt.p_extra, (uint8_t *)p_wf + sizeof( WAVEFORMATEX ) + i_extended, p_sys->fmt.i_extra ); } msg_Dbg( p_demux, "format: 0x%4.4x, fourcc: %4.4s, channels: %d, " "freq: %u Hz, bitrate: %uKo/s, blockalign: %d, bits/samples: %d, " "extra size: %d", GetWLE( &p_wf->wFormatTag ), (char *)&p_sys->fmt.i_codec, p_sys->fmt.audio.i_channels, p_sys->fmt.audio.i_rate, p_sys->fmt.i_bitrate / 8 / 1024, p_sys->fmt.audio.i_blockalign, p_sys->fmt.audio.i_bitspersample, p_sys->fmt.i_extra ); free( p_wf ); p_wf = NULL; switch( p_sys->fmt.i_codec ) { case VLC_FOURCC( 'a', 'r', 'a', 'w' ): case VLC_FOURCC( 'a', 'f', 'l', 't' ): case VLC_FOURCC( 'u', 'l', 'a', 'w' ): case VLC_CODEC_ALAW: case VLC_CODEC_MULAW: case VLC_FOURCC( 'p', 'c', 'm', ' ' ): if( FrameInfo_PCM( &p_sys->i_frame_size, &p_sys->i_frame_samples, &p_sys->fmt ) ) goto error; break; case VLC_CODEC_ADPCM_MS: if( FrameInfo_MS_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples, &p_sys->fmt ) ) goto error; break; case VLC_CODEC_ADPCM_IMA_WAV: if( FrameInfo_IMA_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples, &p_sys->fmt ) ) goto error; break; case VLC_FOURCC( 'm', 's', 0x00, 0x61 ): case VLC_FOURCC( 'm', 's', 0x00, 0x62 ): /* FIXME not sure at all FIXME */ if( FrameInfo_MS_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples, &p_sys->fmt ) ) goto error; break; case VLC_CODEC_MPGA: case VLC_CODEC_A52: /* FIXME set end of area FIXME */ goto error; case VLC_CODEC_GSM_MS: case VLC_CODEC_ADPCM_G726: case VLC_CODEC_TRUESPEECH: case VLC_CODEC_ATRAC3: case VLC_CODEC_G723_1: if( FrameInfo_MSGSM( &p_sys->i_frame_size, &p_sys->i_frame_samples, &p_sys->fmt ) ) goto error; break; default: msg_Err( p_demux, "unsupported codec (%4.4s)", (char*)&p_sys->fmt.i_codec ); goto error; } if( p_sys->i_frame_size <= 0 || p_sys->i_frame_samples <= 0 ) { msg_Dbg( p_demux, "invalid frame size: %i %i", p_sys->i_frame_size, p_sys->i_frame_samples ); goto error; } if( p_sys->fmt.audio.i_rate <= 0 ) { msg_Dbg( p_demux, "invalid sample rate: %i", p_sys->fmt.audio.i_rate ); goto error; } msg_Dbg( p_demux, "found %s audio format", psz_name ); if( ChunkFind( p_demux, "data", &p_sys->i_data_size ) ) { msg_Err( p_demux, "cannot find 'data' chunk" ); goto error; } if( stream_Read( p_demux->s, NULL, 8 ) != 8 ) goto error; p_sys->i_data_pos = stream_Tell( p_demux->s ); if( p_sys->fmt.i_bitrate <= 0 ) { p_sys->fmt.i_bitrate = (int64_t)p_sys->i_frame_size * p_sys->fmt.audio.i_rate * 8 / p_sys->i_frame_samples; } p_sys->p_es = es_out_Add( p_demux->out, &p_sys->fmt ); date_Init( &p_sys->pts, p_sys->fmt.audio.i_rate, 1 ); date_Set( &p_sys->pts, 1 ); return VLC_SUCCESS; error: msg_Err( p_demux, "An error occurred during wav demuxing" ); free( p_wf ); free( p_sys ); return VLC_EGENERIC; }
static int PAOpenStream( audio_output_t *p_aout ) { aout_sys_t *p_sys = p_aout->sys; const PaHostErrorInfo* paLastHostErrorInfo = Pa_GetLastHostErrorInfo(); PaStreamParameters paStreamParameters; vlc_value_t val; int i_channels, i_err; uint32_t i_channel_mask; if( var_Get( p_aout, "audio-device", &val ) < 0 ) { return VLC_EGENERIC; } if( val.i_int == AOUT_VAR_5_1 ) { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; } else if( val.i_int == AOUT_VAR_3F2R ) { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if( val.i_int == AOUT_VAR_2F2R ) { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if( val.i_int == AOUT_VAR_MONO ) { p_aout->format.i_physical_channels = AOUT_CHAN_CENTER; } else { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } i_channels = aout_FormatNbChannels( &p_aout->format ); msg_Dbg( p_aout, "nb_channels requested = %d", i_channels ); i_channel_mask = p_aout->format.i_physical_channels; /* Calculate the frame size in bytes */ p_sys->i_sample_size = 4 * i_channels; aout_FormatPrepare( &p_aout->format ); aout_PacketInit( p_aout, &p_sys->packet, FRAME_SIZE ); aout_VolumeSoftInit( p_aout ); /* Check for channel reordering */ p_aout->sys->i_channel_mask = i_channel_mask; p_aout->sys->i_bits_per_sample = 32; /* forced to paFloat32 */ p_aout->sys->i_channels = i_channels; p_aout->sys->b_chan_reorder = aout_CheckChannelReorder( NULL, pi_channels_out, i_channel_mask, i_channels, p_aout->sys->pi_chan_table ); if( p_aout->sys->b_chan_reorder ) { msg_Dbg( p_aout, "channel reordering needed" ); } paStreamParameters.device = p_sys->i_device_id; paStreamParameters.channelCount = i_channels; paStreamParameters.sampleFormat = paFloat32; paStreamParameters.suggestedLatency = p_sys->deviceInfo->defaultLowOutputLatency; paStreamParameters.hostApiSpecificStreamInfo = NULL; i_err = Pa_OpenStream( &p_sys->p_stream, NULL /* no input */, &paStreamParameters, (double)p_aout->format.i_rate, FRAME_SIZE, paClipOff, paCallback, p_sys ); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_OpenStream returns %d : %s", i_err, Pa_GetErrorText( i_err ) ); if( i_err == paUnanticipatedHostError ) { msg_Err( p_aout, "type %d code %ld : %s", paLastHostErrorInfo->hostApiType, paLastHostErrorInfo->errorCode, paLastHostErrorInfo->errorText ); } p_sys->p_stream = 0; aout_PacketDestroy( p_aout ); return VLC_EGENERIC; } i_err = Pa_StartStream( p_sys->p_stream ); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_StartStream() failed" ); Pa_CloseStream( p_sys->p_stream ); aout_PacketDestroy( p_aout ); return VLC_EGENERIC; } return VLC_SUCCESS; }