@ -40,6 +40,8 @@ struct dshow_ctx {
int list_options ;
int list_devices ;
int audio_buffer_size ;
char * video_pin_name ;
char * audio_pin_name ;
IBaseFilter * device_filter [ 2 ] ;
IPin * device_pin [ 2 ] ;
@ -269,8 +271,31 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
while ( ! device_filter & & IEnumMoniker_Next ( classenum , 1 , & m , NULL ) = = S_OK ) {
IPropertyBag * bag = NULL ;
char * buf = NULL ;
char * friendly_name = NULL ;
char * unique_name = NULL ;
VARIANT var ;
IBindCtx * bind_ctx = NULL ;
LPOLESTR olestr = NULL ;
LPMALLOC co_malloc = NULL ;
int i ;
r = CoGetMalloc ( 1 , & co_malloc ) ;
if ( r = S_OK )
goto fail1 ;
r = CreateBindCtx ( 0 , & bind_ctx ) ;
if ( r ! = S_OK )
goto fail1 ;
/* GetDisplayname works for both video and audio, DevicePath doesn't */
r = IMoniker_GetDisplayName ( m , bind_ctx , NULL , & olestr ) ;
if ( r ! = S_OK )
goto fail1 ;
unique_name = dup_wchar_to_utf8 ( olestr ) ;
/* replace ':' with '_' since we use : to delineate between sources */
for ( i = 0 ; i < strlen ( unique_name ) ; i + + ) {
if ( unique_name [ i ] = = ' : ' )
unique_name [ i ] = ' _ ' ;
}
r = IMoniker_BindToStorage ( m , 0 , 0 , & IID_IPropertyBag , ( void * ) & bag ) ;
if ( r ! = S_OK )
@ -281,23 +306,35 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
if ( r ! = S_OK )
goto fail1 ;
bu f = dup_wchar_to_utf8 ( var . bstrVal ) ;
friendly_name = dup_wchar_to_utf8 ( var . bstrVal ) ;
if ( pfilter ) {
if ( strcmp ( device_name , bu f) )
if ( pfilter ) {
if ( strcmp ( device_name , friendly_name ) & & strcmp ( device_name , unique_name ) )
goto fail1 ;
if ( ! skip - - )
IMoniker_BindToObject ( m , 0 , 0 , & IID_IBaseFilter , ( void * ) & device_filter ) ;
if ( ! skip - - ) {
r = IMoniker_BindToObject ( m , 0 , 0 , & IID_IBaseFilter , ( void * ) & device_filter ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Unable to BindToObject for %s \n " , device_name ) ;
goto fail1 ;
}
}
} else {
av_log ( avctx , AV_LOG_INFO , " \" %s \" \n " , buf ) ;
av_log ( avctx , AV_LOG_INFO , " \" %s \" \n " , friendly_name ) ;
av_log ( avctx , AV_LOG_INFO , " Alternative name \" %s \" \n " , unique_name ) ;
}
fail1 :
av_free ( buf ) ;
if ( olestr & & co_malloc )
IMalloc_Free ( co_malloc , olestr ) ;
if ( bind_ctx )
IBindCtx_Release ( bind_ctx ) ;
av_free ( friendly_name ) ;
av_free ( unique_name ) ;
if ( bag )
IPropertyBag_Release ( bag ) ;
IMoniker_Release ( m ) ;
}
IEnumMoniker_Release ( classenum ) ;
@ -550,6 +587,10 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
AM_MEDIA_TYPE * type ;
GUID category ;
DWORD r2 ;
char * name_buf = NULL ;
wchar_t * pin_id = NULL ;
char * pin_buf = NULL ;
char * desired_pin_name = devtype = = VideoDevice ? ctx - > video_pin_name : ctx - > audio_pin_name ;
IPin_QueryPinInfo ( pin , & info ) ;
IBaseFilter_Release ( info . pFilter ) ;
@ -563,14 +604,29 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
goto next ;
if ( ! IsEqualGUID ( & category , & PIN_CATEGORY_CAPTURE ) )
goto next ;
name_buf = dup_wchar_to_utf8 ( info . achName ) ;
r = IPin_QueryId ( pin , & pin_id ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not query pin id \n " ) ;
return AVERROR ( EIO ) ;
}
pin_buf = dup_wchar_to_utf8 ( pin_id ) ;
if ( ! ppin ) {
char * buf = dup_wchar_to_utf8 ( info . achName ) ;
av_log ( avctx , AV_LOG_INFO , " Pin \" %s \" \n " , buf ) ;
av_free ( buf ) ;
av_log ( avctx , AV_LOG_INFO , " Pin \" %s \" (alternative pin name \" %s \" ) \n " , name_buf , pin_buf ) ;
dshow_cycle_formats ( avctx , devtype , pin , NULL ) ;
goto next ;
}
if ( desired_pin_name ) {
if ( strcmp ( name_buf , desired_pin_name ) & & strcmp ( pin_buf , desired_pin_name ) ) {
av_log ( avctx , AV_LOG_DEBUG , " skipping pin \" %s \" ( \" %s \" ) != requested \" %s \" \n " ,
name_buf , pin_buf , desired_pin_name ) ;
goto next ;
}
}
if ( set_format ) {
dshow_cycle_formats ( avctx , devtype , pin , & format_set ) ;
if ( ! format_set ) {
@ -590,6 +646,7 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
while ( ! device_pin & & IEnumMediaTypes_Next ( types , 1 , & type , NULL ) = = S_OK ) {
if ( IsEqualGUID ( & type - > majortype , mediatype [ devtype ] ) ) {
device_pin = pin ;
av_log ( avctx , AV_LOG_DEBUG , " Selecting pin %s on %s \n " , name_buf , devtypename ) ;
goto next ;
}
CoTaskMemFree ( type ) ;
@ -602,6 +659,11 @@ next:
IKsPropertySet_Release ( p ) ;
if ( device_pin ! = pin )
IPin_Release ( pin ) ;
av_free ( name_buf ) ;
av_free ( pin_buf ) ;
if ( pin_id )
CoTaskMemFree ( pin_id ) ;
}
IEnumPins_Release ( pins ) ;
@ -1066,6 +1128,7 @@ static const AVOption options[] = {
{ " sample_rate " , " set audio sample rate " , OFFSET ( sample_rate ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , INT_MAX , DEC } ,
{ " sample_size " , " set audio sample size " , OFFSET ( sample_size ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , 16 , DEC } ,
{ " channels " , " set number of audio channels, such as 1 or 2 " , OFFSET ( channels ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , INT_MAX , DEC } ,
{ " audio_buffer_size " , " set audio device buffer latency size in milliseconds (default is the device's default) " , OFFSET ( audio_buffer_size ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , INT_MAX , DEC } ,
{ " list_devices " , " list available devices " , OFFSET ( list_devices ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , 1 , DEC , " list_devices " } ,
{ " true " , " " , 0 , AV_OPT_TYPE_CONST , { . i64 = 1 } , 0 , 0 , DEC , " list_devices " } ,
{ " false " , " " , 0 , AV_OPT_TYPE_CONST , { . i64 = 0 } , 0 , 0 , DEC , " list_devices " } ,
@ -1074,7 +1137,8 @@ static const AVOption options[] = {
{ " false " , " " , 0 , AV_OPT_TYPE_CONST , { . i64 = 0 } , 0 , 0 , DEC , " list_options " } ,
{ " video_device_number " , " set video device number for devices with same name (starts at 0) " , OFFSET ( video_device_number ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , INT_MAX , DEC } ,
{ " audio_device_number " , " set audio device number for devices with same name (starts at 0) " , OFFSET ( audio_device_number ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , INT_MAX , DEC } ,
{ " audio_buffer_size " , " set audio device buffer latency size in milliseconds (default is the device's default) " , OFFSET ( audio_buffer_size ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , INT_MAX , DEC } ,
{ " video_pin_name " , " select video capture pin by name " , OFFSET ( video_pin_name ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , 0 , AV_OPT_FLAG_ENCODING_PARAM } ,
{ " audio_pin_name " , " select audio capture pin by name " , OFFSET ( audio_pin_name ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , 0 , AV_OPT_FLAG_ENCODING_PARAM } ,
{ NULL } ,
} ;