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 + -
显示快捷键?