⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 directx.c

📁 VLC Player Source Code
💻 C
📖 第 1 页 / 共 3 页
字号:
    {        FreeLibrary( p_aout->output.p_sys->hdsound_dll );        p_aout->output.p_sys->hdsound_dll = NULL;    }    return VLC_EGENERIC;}/***************************************************************************** * CreateDSBuffer: Creates a direct sound 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 int CreateDSBuffer( aout_instance_t *p_aout, int i_format,                           int i_channels, int i_nb_channels, int i_rate,                           int i_bytes_per_frame, bool b_probe ){    WAVEFORMATEXTENSIBLE waveformat;    DSBUFFERDESC         dsbdesc;    unsigned int         i;    /* First set the sound buffer format */    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;    p_aout->output.p_sys->i_bits_per_sample = waveformat.Format.wBitsPerSample;    p_aout->output.p_sys->i_channels = i_nb_channels;    /* 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 */    /* 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 = FRAMES_NUM * i_bytes_per_frame;   /* buffer size */    dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&waveformat;    if FAILED( IDirectSound_CreateSoundBuffer(                   p_aout->output.p_sys->p_dsobject, &dsbdesc,                   &p_aout->output.p_sys->p_dsbuffer, NULL) )    {        if( dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE )        {            /* Try without DSBCAPS_LOCHARDWARE */            dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE;            if FAILED( IDirectSound_CreateSoundBuffer(                   p_aout->output.p_sys->p_dsobject, &dsbdesc,                   &p_aout->output.p_sys->p_dsbuffer, NULL) )            {                return VLC_EGENERIC;            }            if( !b_probe )                msg_Dbg( p_aout, "couldn't use hardware sound buffer" );        }        else        {            return VLC_EGENERIC;        }    }    /* Stop here if we were just probing */    if( b_probe )    {        IDirectSoundBuffer_Release( p_aout->output.p_sys->p_dsbuffer );        p_aout->output.p_sys->p_dsbuffer = NULL;        return VLC_SUCCESS;    }    p_aout->output.p_sys->i_frame_size = i_bytes_per_frame;    p_aout->output.p_sys->i_channel_mask = waveformat.dwChannelMask;    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;}/***************************************************************************** * CreateDSBufferPCM: creates a PCM direct sound buffer. ***************************************************************************** * We first try to create a WAVE_FORMAT_IEEE_FLOAT buffer if supported by * the hardware, otherwise we create a WAVE_FORMAT_PCM buffer. ****************************************************************************/static int CreateDSBufferPCM( aout_instance_t *p_aout, int *i_format,                              int i_channels, int i_nb_channels, int i_rate,                              bool b_probe ){    vlc_value_t val;    var_Get( p_aout, "directx-audio-float32", &val );    /* Float32 audio samples are not supported for 5.1 output on the emu101k */    if( !val.b_bool || i_nb_channels > 2 ||        CreateDSBuffer( p_aout, VLC_FOURCC('f','l','3','2'),                        i_channels, i_nb_channels, i_rate,                        FRAME_SIZE * 4 * i_nb_channels, b_probe )        != VLC_SUCCESS )    {        if ( CreateDSBuffer( p_aout, VLC_FOURCC('s','1','6','l'),                             i_channels, i_nb_channels, i_rate,                             FRAME_SIZE * 2 * i_nb_channels, b_probe )             != VLC_SUCCESS )        {            return VLC_EGENERIC;        }        else        {            *i_format = VLC_FOURCC('s','1','6','l');            return VLC_SUCCESS;        }    }    else    {        *i_format = VLC_FOURCC('f','l','3','2');        return VLC_SUCCESS;    }}/***************************************************************************** * DestroyDSBuffer ***************************************************************************** * This function destroys the secondary buffer. *****************************************************************************/static void DestroyDSBuffer( aout_instance_t *p_aout ){    if( p_aout->output.p_sys->p_dsbuffer )    {        IDirectSoundBuffer_Release( p_aout->output.p_sys->p_dsbuffer );        p_aout->output.p_sys->p_dsbuffer = NULL;    }}/***************************************************************************** * FillBuffer: Fill in one of the direct sound frame buffers. ***************************************************************************** * Returns VLC_SUCCESS on success. *****************************************************************************/static int FillBuffer( aout_instance_t *p_aout, int i_frame,                       aout_buffer_t *p_buffer ){    notification_thread_t *p_notif = p_aout->output.p_sys->p_notif;    aout_sys_t *p_sys = p_aout->output.p_sys;    void *p_write_position, *p_wrap_around;    long l_bytes1, l_bytes2;    HRESULT dsresult;    /* Before copying anything, we have to lock the buffer */    dsresult = IDirectSoundBuffer_Lock(                p_sys->p_dsbuffer,                              /* DS buffer */                i_frame * p_notif->i_frame_size,             /* Start offset */                p_notif->i_frame_size,                    /* Number of bytes */                &p_write_position,                  /* Address of lock start */                &l_bytes1,       /* Count of bytes locked before wrap around */                &p_wrap_around,            /* Buffer adress (if wrap around) */                &l_bytes2,               /* Count of bytes after wrap around */                0 );                                                /* Flags */    if( dsresult == DSERR_BUFFERLOST )    {        IDirectSoundBuffer_Restore( p_sys->p_dsbuffer );        dsresult = IDirectSoundBuffer_Lock(                               p_sys->p_dsbuffer,                               i_frame * p_notif->i_frame_size,                               p_notif->i_frame_size,                               &p_write_position,                               &l_bytes1,                               &p_wrap_around,                               &l_bytes2,                               0 );    }    if( dsresult != DS_OK )    {        msg_Warn( p_notif, "cannot lock buffer" );        if( p_buffer ) aout_BufferFree( p_buffer );        return VLC_EGENERIC;    }    if( p_buffer == NULL )    {        memset( p_write_position, 0, l_bytes1 );    }    else    {        if( p_sys->b_chan_reorder )        {            /* Do the channel reordering here */            aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_nb_bytes,                                 p_sys->i_channels, p_sys->pi_chan_table,                                 p_sys->i_bits_per_sample );        }        vlc_memcpy( p_write_position, p_buffer->p_buffer, l_bytes1 );        aout_BufferFree( p_buffer );    }    /* Now the data has been copied, unlock the buffer */    IDirectSoundBuffer_Unlock( p_sys->p_dsbuffer, p_write_position, l_bytes1,                               p_wrap_around, l_bytes2 );    p_notif->i_write_slot = (i_frame + 1) % FRAMES_NUM;    return VLC_SUCCESS;}/***************************************************************************** * DirectSoundThread: this thread will capture play notification events. ***************************************************************************** * We use this thread to emulate a callback mechanism. The thread probes for * event notification and fills up the DS secondary buffer when needed. *****************************************************************************/static void* DirectSoundThread( vlc_object_t *p_this ){    notification_thread_t *p_notif = (notification_thread_t*)p_this;    aout_instance_t *p_aout = p_notif->p_aout;    bool b_sleek;    mtime_t last_time;    HRESULT dsresult;    long l_queued = 0;    /* We don't want any resampling when using S/PDIF output */    b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i');    /* Tell the main thread that we are ready */    vlc_thread_ready( p_notif );    msg_Dbg( p_notif, "DirectSoundThread ready" );    /* Wait here until Play() is called */    WaitForSingleObject( p_notif->event, INFINITE );    if( vlc_object_alive (p_notif) )    {        mwait( p_notif->start_date - AOUT_PTS_TOLERANCE / 2 );        /* start playing the buffer */        dsresult = IDirectSoundBuffer_Play( p_aout->output.p_sys->p_dsbuffer,                                        0,                         /* Unused */                                        0,                         /* Unused */                                        DSBPLAY_LOOPING );          /* Flags */        if( dsresult == DSERR_BUFFERLOST )        {            IDirectSoundBuffer_Restore( p_aout->output.p_sys->p_dsbuffer );            dsresult = IDirectSoundBuffer_Play(                                            p_aout->output.p_sys->p_dsbuffer,                                            0,                     /* Unused */                                            0,                     /* Unused */                                            DSBPLAY_LOOPING );      /* Flags */        }        if( dsresult != DS_OK )        {            msg_Err( p_aout, "cannot start playing buffer" );        }    }    last_time = mdate();    while( vlc_object_alive (p_notif) )    {        long l_read, l_free_slots;        mtime_t mtime = mdate();        int i;        /*         * Fill in as much audio data as we can in our circular buffer         */        /* Find out current play position */        if FAILED( IDirectSoundBuffer_GetCurrentPosition(                   p_aout->output.p_sys->p_dsbuffer, &l_read, NULL ) )        {            msg_Err( p_aout, "GetCurrentPosition() failed!" );            l_read = 0;        }        /* Detect underruns */        if( l_queued && mtime - last_time >            INT64_C(1000000) * l_queued / p_aout->output.output.i_rate )        {            msg_Dbg( p_aout, "detected underrun!" );        }        last_time = mtime;        /* Try to fill in as many frame buffers as possible */        l_read /= p_aout->output.output.i_bytes_per_frame;        l_queued = p_notif->i_write_slot * FRAME_SIZE - l_read;        if( l_queued < 0 ) l_queued += (FRAME_SIZE * FRAMES_NUM);        l_free_slots = (FRAMES_NUM * FRAME_SIZE - l_queued) / FRAME_SIZE;        for( i = 0; i < l_free_slots; i++ )        {            aout_buffer_t *p_buffer = aout_OutputNextBuffer( p_aout,                mtime + INT64_C(1000000) * (i * FRAME_SIZE + l_queued) /                p_aout->output.output.i_rate, b_sleek );            /* If there is no audio data available and we have some buffered             * already, then just wait for the next time */            if( !p_buffer && (i || l_queued / FRAME_SIZE) ) break;            if( FillBuffer( p_aout, p_notif->i_write_slot % FRAMES_NUM,                            p_buffer ) != VLC_SUCCESS ) break;        }        /* Sleep a reasonable amount of time */        l_queued += (i * FRAME_SIZE);        msleep( INT64_C(1000000) * l_queued / p_aout->output.output.i_rate / 2 );    }    /* make sure the buffer isn't playing */    IDirectSoundBuffer_Stop( p_aout->output.p_sys->p_dsbuffer );    /* free the event */    CloseHandle( p_notif->event );    msg_Dbg( p_notif, "DirectSoundThread exiting" );    return NULL;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -