dshow.cpp

来自「VLC媒体播放程序」· C++ 代码 · 共 1,570 行 · 第 1/4 页

CPP
1,570
字号
    //p_sys->p_control->Stop(); /* FIXME?: we get stuck here sometimes */    p_sys->p_control->Release();    /* Remove filters from graph */    for( int i = 0; i < p_sys->i_streams; i++ )    {        p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_capture_filter );        p_sys->p_graph->RemoveFilter( p_sys->pp_streams[i]->p_device_filter );        p_sys->pp_streams[i]->p_capture_filter->Release();        p_sys->pp_streams[i]->p_device_filter->Release();    }    p_sys->p_graph->Release();    /* Uninitialize OLE/COM */    CoUninitialize();    free( p_sys->p_header );    for( int i = 0; i < p_sys->i_streams; i++ ) delete p_sys->pp_streams[i];    free( p_sys->pp_streams );    free( p_sys );}/**************************************************************************** * ConnectFilters ****************************************************************************/static bool ConnectFilters( vlc_object_t *p_this, IFilterGraph *p_graph,                            IBaseFilter *p_filter, IPin *p_input_pin ){    IEnumPins *p_enumpins;    IPin *p_pin;    if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return false;    while( S_OK == p_enumpins->Next( 1, &p_pin, NULL ) )    {        PIN_DIRECTION pin_dir;        p_pin->QueryDirection( &pin_dir );        if( pin_dir == PINDIR_OUTPUT &&            S_OK == p_graph->ConnectDirect( p_pin, p_input_pin, 0 ) )        {            p_pin->Release();            p_enumpins->Release();            return true;        }        p_pin->Release();    }    p_enumpins->Release();    return false;}static int OpenDevice( input_thread_t *p_input, string devicename,                       vlc_bool_t b_audio ){    access_sys_t *p_sys = p_input->p_access_data;    list<string> list_devices;    /* Enumerate devices and display their names */    FindCaptureDevice( (vlc_object_t *)p_input, NULL, &list_devices, b_audio );    if( !list_devices.size() )        return VLC_EGENERIC;    list<string>::iterator iter;    for( iter = list_devices.begin(); iter != list_devices.end(); iter++ )        msg_Dbg( p_input, "found device: %s", iter->c_str() );    /* If no device name was specified, pick the 1st one */    if( devicename.size() == 0 )    {        devicename = *list_devices.begin();    }    // Use the system device enumerator and class enumerator to find    // a capture/preview device, such as a desktop USB video camera.    IBaseFilter *p_device_filter =        FindCaptureDevice( (vlc_object_t *)p_input, &devicename,                           NULL, b_audio );    if( p_device_filter )        msg_Dbg( p_input, "using device: %s", devicename.c_str() );    else    {        msg_Err( p_input, "can't use device: %s", devicename.c_str() );        return VLC_EGENERIC;    }    AM_MEDIA_TYPE media_type =        EnumDeviceCaps( (vlc_object_t *)p_input, p_device_filter,                        p_sys->i_chroma, p_sys->i_width, p_sys->i_height,                        0, 0, 0 );    /* Create and add our capture filter */    CaptureFilter *p_capture_filter = new CaptureFilter( p_input, media_type );    p_sys->p_graph->AddFilter( p_capture_filter, 0 );    /* Add the device filter to the graph (seems necessary with VfW before     * accessing pin attributes). */    p_sys->p_graph->AddFilter( p_device_filter, 0 );    /* Attempt to connect one of this device's capture output pins */    msg_Dbg( p_input, "connecting filters" );    if( ConnectFilters( VLC_OBJECT(p_input), p_sys->p_graph, p_device_filter,                        p_capture_filter->CustomGetPin() ) )    {        /* Success */        dshow_stream_t dshow_stream;        dshow_stream.b_invert = VLC_FALSE;        dshow_stream.b_pts = VLC_FALSE;        dshow_stream.mt =            p_capture_filter->CustomGetPin()->CustomGetMediaType();        if( dshow_stream.mt.majortype == MEDIATYPE_Video )        {            msg_Dbg( p_input, "MEDIATYPE_Video");            /* Packed RGB formats */            if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB1 )                dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '1' );            if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB4 )                dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '4' );            if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB8 )                dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '8' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB555 )                dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB565 )                dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB24 )                dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_RGB32 )                dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_ARGB32 )                dshow_stream.i_fourcc = VLC_FOURCC( 'R', 'G', 'B', 'A' );            /* Packed YUV formats */            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YVYU )                dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'V', 'Y', 'U' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YUYV )                dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', 'V' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y411 )                dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y211 )                dshow_stream.i_fourcc = VLC_FOURCC( 'Y', '2', '1', '1' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YUY2 ||                     dshow_stream.mt.subtype == MEDIASUBTYPE_UYVY )                dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );            /* Planar YUV formats */            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_I420 )                dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '2', '0' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_Y41P )                dshow_stream.i_fourcc = VLC_FOURCC( 'I', '4', '1', '1' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YV12 ||                     dshow_stream.mt.subtype == MEDIASUBTYPE_IYUV )                dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_YVU9 )                dshow_stream.i_fourcc = VLC_FOURCC( 'Y', 'V', 'U', '9' );            /* DV formats */            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_dvsl )                dshow_stream.i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'l' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_dvsd )                dshow_stream.i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'd' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_dvhd )                dshow_stream.i_fourcc = VLC_FOURCC( 'd', 'v', 'h', 'd' );            /* MPEG video formats */            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_MPEG2_VIDEO )                dshow_stream.i_fourcc = VLC_FOURCC( 'm', 'p', '2', 'v' );            else goto fail;            dshow_stream.header.video =                *(VIDEOINFOHEADER *)dshow_stream.mt.pbFormat;            int i_height = dshow_stream.header.video.bmiHeader.biHeight;            /* Check if the image is inverted (bottom to top) */            if( dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'G', 'B', '1' ) ||                dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'G', 'B', '4' ) ||                dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'G', 'B', '8' ) ||                dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'V', '1', '5' ) ||                dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'V', '1', '6' ) ||                dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'V', '2', '4' ) ||                dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'V', '3', '2' ) ||                dshow_stream.i_fourcc == VLC_FOURCC( 'R', 'G', 'B', 'A' ) )            {                if( i_height > 0 ) dshow_stream.b_invert = VLC_TRUE;                else i_height = - i_height;            }            /* Check if we are dealing with a DV stream */            if( dshow_stream.i_fourcc == VLC_FOURCC( 'd', 'v', 's', 'l' ) ||                dshow_stream.i_fourcc == VLC_FOURCC( 'd', 'v', 's', 'd' ) ||                dshow_stream.i_fourcc == VLC_FOURCC( 'd', 'v', 'h', 'd' ) )            {                p_input->pf_read = ReadCompressed;                if( !p_input->psz_demux || !*p_input->psz_demux )                {                    p_input->psz_demux = "rawdv";                }                p_sys->b_audio = VLC_FALSE;            }            /* Check if we are dealing with an MPEG video stream */            if( dshow_stream.i_fourcc == VLC_FOURCC( 'm', 'p', '2', 'v' ) )            {                p_input->pf_read = ReadCompressed;                if( !p_input->psz_demux || !*p_input->psz_demux )                {                    p_input->psz_demux = "mpgv";                }                p_sys->b_audio = VLC_FALSE;            }            /* Add video stream to header */            p_sys->i_header_size += 20;            p_sys->p_header = (uint8_t *)realloc( p_sys->p_header,                                                  p_sys->i_header_size );            memcpy(  &p_sys->p_header[p_sys->i_header_pos], "vids", 4 );            memcpy(  &p_sys->p_header[p_sys->i_header_pos + 4],                     &dshow_stream.i_fourcc, 4 );            SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 8],                     dshow_stream.header.video.bmiHeader.biWidth );            SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 12], i_height );            SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 16], 0 );            p_sys->i_header_pos = p_sys->i_header_size;            /* Greatly simplifies the reading routine */            int i_mtu = dshow_stream.header.video.bmiHeader.biWidth *                i_height * 4;            p_input->i_mtu = __MAX( p_input->i_mtu, (unsigned int)i_mtu );        }        else if( dshow_stream.mt.majortype == MEDIATYPE_Audio &&                 dshow_stream.mt.formattype == FORMAT_WaveFormatEx )        {            msg_Dbg( p_input, "MEDIATYPE_Audio");            if( dshow_stream.mt.subtype == MEDIASUBTYPE_PCM )                dshow_stream.i_fourcc = VLC_FOURCC( 'a', 'r', 'a', 'w' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_IEEE_FLOAT )                dshow_stream.i_fourcc = VLC_FOURCC( 'f', 'l', '3', '2' );            else goto fail;            dshow_stream.header.audio =                *(WAVEFORMATEX *)dshow_stream.mt.pbFormat;            /* Add audio stream to header */            p_sys->i_header_size += 20;            p_sys->p_header = (uint8_t *)realloc( p_sys->p_header,                                                  p_sys->i_header_size );            memcpy(  &p_sys->p_header[p_sys->i_header_pos], "auds", 4 );            memcpy(  &p_sys->p_header[p_sys->i_header_pos + 4],                     &dshow_stream.i_fourcc, 4 );            SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 8],                     dshow_stream.header.audio.nChannels );            SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 12],                     dshow_stream.header.audio.nSamplesPerSec );            SetDWBE( &p_sys->p_header[p_sys->i_header_pos + 16],                     dshow_stream.header.audio.wBitsPerSample );            p_sys->i_header_pos = p_sys->i_header_size;            /* Greatly simplifies the reading routine */            IAMBufferNegotiation *p_ambuf;            IPin *p_pin;            int i_mtu;            p_capture_filter->CustomGetPin()->ConnectedTo( &p_pin );            if( SUCCEEDED( p_pin->QueryInterface(                  IID_IAMBufferNegotiation, (void **)&p_ambuf ) ) )            {                ALLOCATOR_PROPERTIES AllocProp;                memset( &AllocProp, 0, sizeof( ALLOCATOR_PROPERTIES ) );                p_ambuf->GetAllocatorProperties( &AllocProp );                p_ambuf->Release();                i_mtu = AllocProp.cbBuffer;            }            else            {                /* Worst case */                i_mtu = dshow_stream.header.audio.nSamplesPerSec *                        dshow_stream.header.audio.nChannels *                        dshow_stream.header.audio.wBitsPerSample / 8;            }            p_pin->Release();            p_input->i_mtu = __MAX( p_input->i_mtu, (unsigned int)i_mtu );        }        else if( dshow_stream.mt.majortype == MEDIATYPE_Stream )        {            msg_Dbg( p_input, "MEDIATYPE_Stream" );            if( dshow_stream.mt.subtype == MEDIASUBTYPE_MPEG2_PROGRAM )                dshow_stream.i_fourcc = VLC_FOURCC( 'm', 'p', '2', 'p' );            else if( dshow_stream.mt.subtype == MEDIASUBTYPE_MPEG2_TRANSPORT )                dshow_stream.i_fourcc = VLC_FOURCC( 'm', 'p', '2', 't' );            msg_Dbg( p_input, "selected stream pin accepts format: %4.4s",                     (char *)&dshow_stream.i_fourcc);            p_sys->b_audio = VLC_FALSE;            p_sys->i_header_size = 0;            p_sys->i_header_pos = 0;            p_input->i_mtu = INPUT_DEFAULT_BUFSIZE;            p_input->pf_read = ReadCompressed;            p_input->pf_set_program = input_SetProgram;        }        else        {            msg_Dbg( p_input, "unknown stream majortype" );            goto fail;        }        /* Show properties */        vlc_value_t val;        var_Create( p_input, "dshow-config",                    VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );        var_Get( p_input, "dshow-config", &val );        if(val.i_int) PropertiesPage( VLC_OBJECT(p_input), p_device_filter );        /* Add directshow elementary stream to our list */        dshow_stream.p_device_filter = p_device_filter;        dshow_stream.p_capture_filter = p_capture_filter;        p_sys->pp_streams =            (dshow_stream_t **)realloc( p_sys->pp_streams,                                        sizeof(dshow_stream_t *)                                        * (p_sys->i_streams + 1) );        p_sys->pp_streams[p_sys->i_streams] = new dshow_stream_t;        *p_sys->pp_streams[p_sys->i_streams++] = dshow_stream;        SetDWBE( &p_sys->p_header[4], (uint32_t)p_sys->i_streams );        return VLC_SUCCESS;    } fail:    /* Remove filters from graph */    p_sys->p_graph->RemoveFilter( p_device_filter );    p_sys->p_graph->RemoveFilter( p_capture_filter );    /* Release objects */    p_device_filter->Release();    p_capture_filter->Release();    return VLC_EGENERIC;}static IBaseFilter *FindCaptureDevice( vlc_object_t *p_this, string *p_devicename,                   list<string> *p_listdevices, vlc_bool_t b_audio ){    IBaseFilter *p_base_filter = NULL;    IMoniker *p_moniker = NULL;    ULONG i_fetched;    HRESULT hr;    /* Create the system device enumerator */    ICreateDevEnum *p_dev_enum = NULL;    hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,                           IID_ICreateDevEnum, (void **)&p_dev_enum );    if( FAILED(hr) )    {        msg_Err( p_this, "failed to create the device enumerator (0x%x)", hr);        return NULL;    }    /* Create an enumerator for the video capture devices */    IEnumMoniker *p_class_enum = NULL;    if( !b_audio )        hr = p_dev_enum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory,                                                &p_class_enum, 0 );    else        hr = p_dev_enum->CreateClassEnumerator( CLSID_AudioInputDeviceCategory,                                                &p_class_enum, 0 );    p_dev_enum->Release();    if( FAILED(hr) )    {        msg_Err( p_this, "failed to create the class enumerator (0x%x)", hr );        return NULL;    }    /* If there are no enumerators for the requested type, then     * CreateClassEnumerator will succeed, but p_class_enum will be NULL */    if( p_class_enum == NULL )    {        msg_Err( p_this, "no capture device was detected" );        return NULL;    }

⌨️ 快捷键说明

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