2011-05-21 12:24:50 +00:00
/*
* Directshow capture interface
* Copyright ( c ) 2010 Ramiro Polla
*
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* FFmpeg is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2014-11-25 02:49:09 +00:00
# include "dshow_capture.h"
2011-09-09 03:12:42 +00:00
# include "libavutil/parseutils.h"
2012-09-06 23:41:19 +00:00
# include "libavutil/pixdesc.h"
2011-09-09 03:09:23 +00:00
# include "libavutil/opt.h"
2024-04-25 09:18:18 +00:00
# include "libavutil/mem.h"
2011-12-02 23:45:46 +00:00
# include "libavformat/internal.h"
2013-01-15 22:01:43 +00:00
# include "libavformat/riff.h"
2011-05-26 17:11:25 +00:00
# include "avdevice.h"
2013-01-16 00:07:54 +00:00
# include "libavcodec/raw.h"
2015-04-22 16:38:38 +00:00
# include "objidl.h"
# include "shlwapi.h"
2024-04-25 09:18:18 +00:00
// NB: technically, we should include dxva.h and use
// DXVA_ExtendedFormat, but that type is not defined in
// the MinGW headers. The DXVA2_ExtendedFormat and the
// contents of its fields is identical to
// DXVA_ExtendedFormat (see https://docs.microsoft.com/en-us/windows/win32/medfound/extended-color-information#color-space-in-media-types)
// and is provided by MinGW as well, so we use that
// instead. NB also that per the Microsoft docs, the
// lowest 8 bits of the structure, i.e. the SampleFormat
// field, contain AMCONTROL_xxx flags instead of sample
// format information, and should thus not be used.
// NB further that various values in the structure's
// fields (e.g. BT.2020 color space) are not provided
// for either of the DXVA structs, but are provided in
// the flags of the corresponding fields of Media Foundation.
// These may be provided by DirectShow devices (e.g. LAVFilters
// does so). So we use those values here too (the equivalence is
// indicated by Microsoft example code: https://docs.microsoft.com/en-us/windows/win32/api/dxva2api/ns-dxva2api-dxva2_videodesc)
# include "d3d9types.h"
# include "dxva2api.h"
# ifndef AMCONTROL_COLORINFO_PRESENT
// not defined in some versions of MinGW's dvdmedia.h
# define AMCONTROL_COLORINFO_PRESENT 0x00000080 // if set, indicates DXVA color info is present in the upper (24) bits of the dwControlFlags
# endif
2011-05-21 12:24:50 +00:00
2012-10-08 18:54:00 +00:00
static enum AVPixelFormat dshow_pixfmt ( DWORD biCompression , WORD biBitCount )
2011-05-21 12:24:50 +00:00
{
switch ( biCompression ) {
2011-10-08 18:00:00 +00:00
case BI_BITFIELDS :
2011-05-21 12:24:50 +00:00
case BI_RGB :
switch ( biBitCount ) { /* 1-8 are untested */
case 1 :
2012-10-08 18:54:00 +00:00
return AV_PIX_FMT_MONOWHITE ;
2011-05-21 12:24:50 +00:00
case 4 :
2012-10-08 18:54:00 +00:00
return AV_PIX_FMT_RGB4 ;
2011-05-21 12:24:50 +00:00
case 8 :
2012-10-08 18:54:00 +00:00
return AV_PIX_FMT_RGB8 ;
2011-05-21 12:24:50 +00:00
case 16 :
2012-10-08 18:54:00 +00:00
return AV_PIX_FMT_RGB555 ;
2011-05-21 12:24:50 +00:00
case 24 :
2012-10-08 18:54:00 +00:00
return AV_PIX_FMT_BGR24 ;
2011-05-21 12:24:50 +00:00
case 32 :
2014-03-08 12:46:05 +00:00
return AV_PIX_FMT_0RGB32 ;
2011-05-21 12:24:50 +00:00
}
}
2024-04-25 09:18:18 +00:00
return avpriv_pix_fmt_find ( PIX_FMT_LIST_RAW , biCompression ) ; // all others
}
static enum AVColorRange dshow_color_range ( DXVA2_ExtendedFormat * fmt_info )
{
switch ( fmt_info - > NominalRange )
{
case DXVA2_NominalRange_Unknown :
return AVCOL_RANGE_UNSPECIFIED ;
case DXVA2_NominalRange_Normal : // equal to DXVA2_NominalRange_0_255
return AVCOL_RANGE_JPEG ;
case DXVA2_NominalRange_Wide : // equal to DXVA2_NominalRange_16_235
return AVCOL_RANGE_MPEG ;
case DXVA2_NominalRange_48_208 :
// not an ffmpeg color range
return AVCOL_RANGE_UNSPECIFIED ;
// values from MediaFoundation SDK (mfobjects.h)
case 4 : // MFNominalRange_64_127
// not an ffmpeg color range
return AVCOL_RANGE_UNSPECIFIED ;
default :
return AVCOL_RANGE_UNSPECIFIED ;
}
}
static enum AVColorSpace dshow_color_space ( DXVA2_ExtendedFormat * fmt_info )
{
switch ( fmt_info - > VideoTransferMatrix )
{
case DXVA2_VideoTransferMatrix_BT709 :
return AVCOL_SPC_BT709 ;
case DXVA2_VideoTransferMatrix_BT601 :
return AVCOL_SPC_BT470BG ;
case DXVA2_VideoTransferMatrix_SMPTE240M :
return AVCOL_SPC_SMPTE240M ;
// values from MediaFoundation SDK (mfobjects.h)
case 4 : // MFVideoTransferMatrix_BT2020_10
case 5 : // MFVideoTransferMatrix_BT2020_12
if ( fmt_info - > VideoTransferFunction = = 12 ) // MFVideoTransFunc_2020_const
return AVCOL_SPC_BT2020_CL ;
else
return AVCOL_SPC_BT2020_NCL ;
default :
return AVCOL_SPC_UNSPECIFIED ;
}
}
static enum AVColorPrimaries dshow_color_primaries ( DXVA2_ExtendedFormat * fmt_info )
{
switch ( fmt_info - > VideoPrimaries )
{
case DXVA2_VideoPrimaries_Unknown :
return AVCOL_PRI_UNSPECIFIED ;
case DXVA2_VideoPrimaries_reserved :
return AVCOL_PRI_RESERVED ;
case DXVA2_VideoPrimaries_BT709 :
return AVCOL_PRI_BT709 ;
case DXVA2_VideoPrimaries_BT470_2_SysM :
return AVCOL_PRI_BT470M ;
case DXVA2_VideoPrimaries_BT470_2_SysBG :
case DXVA2_VideoPrimaries_EBU3213 : // this is PAL
return AVCOL_PRI_BT470BG ;
case DXVA2_VideoPrimaries_SMPTE170M :
case DXVA2_VideoPrimaries_SMPTE_C :
return AVCOL_PRI_SMPTE170M ;
case DXVA2_VideoPrimaries_SMPTE240M :
return AVCOL_PRI_SMPTE240M ;
// values from MediaFoundation SDK (mfobjects.h)
case 9 : // MFVideoPrimaries_BT2020
return AVCOL_PRI_BT2020 ;
case 10 : // MFVideoPrimaries_XYZ
return AVCOL_PRI_SMPTE428 ;
case 11 : // MFVideoPrimaries_DCI_P3
return AVCOL_PRI_SMPTE431 ;
case 12 : // MFVideoPrimaries_ACES (Academy Color Encoding System)
// not an FFmpeg color primary
return AVCOL_PRI_UNSPECIFIED ;
default :
return AVCOL_PRI_UNSPECIFIED ;
}
}
static enum AVColorTransferCharacteristic dshow_color_trc ( DXVA2_ExtendedFormat * fmt_info )
{
switch ( fmt_info - > VideoTransferFunction )
{
case DXVA2_VideoTransFunc_Unknown :
return AVCOL_TRC_UNSPECIFIED ;
case DXVA2_VideoTransFunc_10 :
return AVCOL_TRC_LINEAR ;
case DXVA2_VideoTransFunc_18 :
// not an FFmpeg transfer characteristic
return AVCOL_TRC_UNSPECIFIED ;
case DXVA2_VideoTransFunc_20 :
// not an FFmpeg transfer characteristic
return AVCOL_TRC_UNSPECIFIED ;
case DXVA2_VideoTransFunc_22 :
return AVCOL_TRC_GAMMA22 ;
case DXVA2_VideoTransFunc_709 :
return AVCOL_TRC_BT709 ;
case DXVA2_VideoTransFunc_240M :
return AVCOL_TRC_SMPTE240M ;
case DXVA2_VideoTransFunc_sRGB :
return AVCOL_TRC_IEC61966_2_1 ;
case DXVA2_VideoTransFunc_28 :
return AVCOL_TRC_GAMMA28 ;
// values from MediaFoundation SDK (mfobjects.h)
case 9 : // MFVideoTransFunc_Log_100
return AVCOL_TRC_LOG ;
case 10 : // MFVideoTransFunc_Log_316
return AVCOL_TRC_LOG_SQRT ;
case 11 : // MFVideoTransFunc_709_sym
// not an FFmpeg transfer characteristic
return AVCOL_TRC_UNSPECIFIED ;
case 12 : // MFVideoTransFunc_2020_const
case 13 : // MFVideoTransFunc_2020
if ( fmt_info - > VideoTransferMatrix = = 5 ) // MFVideoTransferMatrix_BT2020_12
return AVCOL_TRC_BT2020_12 ;
else
return AVCOL_TRC_BT2020_10 ;
case 14 : // MFVideoTransFunc_26
// not an FFmpeg transfer characteristic
return AVCOL_TRC_UNSPECIFIED ;
case 15 : // MFVideoTransFunc_2084
return AVCOL_TRC_SMPTEST2084 ;
case 16 : // MFVideoTransFunc_HLG
return AVCOL_TRC_ARIB_STD_B67 ;
case 17 : // MFVideoTransFunc_10_rel
// not an FFmpeg transfer characteristic? Undocumented also by MS
return AVCOL_TRC_UNSPECIFIED ;
default :
return AVCOL_TRC_UNSPECIFIED ;
}
}
static enum AVChromaLocation dshow_chroma_loc ( DXVA2_ExtendedFormat * fmt_info )
{
if ( fmt_info - > VideoChromaSubsampling = = DXVA2_VideoChromaSubsampling_Cosited ) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
return AVCHROMA_LOC_TOPLEFT ;
else if ( fmt_info - > VideoChromaSubsampling = = DXVA2_VideoChromaSubsampling_MPEG1 ) // that is: DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes
return AVCHROMA_LOC_CENTER ;
else if ( fmt_info - > VideoChromaSubsampling = = DXVA2_VideoChromaSubsampling_MPEG2 ) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
return AVCHROMA_LOC_LEFT ;
else if ( fmt_info - > VideoChromaSubsampling = = DXVA2_VideoChromaSubsampling_DV_PAL ) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited)
return AVCHROMA_LOC_TOPLEFT ;
else
// unknown
return AVCHROMA_LOC_UNSPECIFIED ;
2011-05-21 12:24:50 +00:00
}
static int
dshow_read_close ( AVFormatContext * s )
{
struct dshow_ctx * ctx = s - > priv_data ;
2024-04-25 09:18:18 +00:00
PacketListEntry * pktl ;
2011-05-21 12:24:50 +00:00
if ( ctx - > control ) {
IMediaControl_Stop ( ctx - > control ) ;
IMediaControl_Release ( ctx - > control ) ;
}
2012-12-17 05:44:12 +00:00
if ( ctx - > media_event )
IMediaEvent_Release ( ctx - > media_event ) ;
2011-09-13 17:56:28 +00:00
if ( ctx - > graph ) {
IEnumFilters * fenum ;
int r ;
r = IGraphBuilder_EnumFilters ( ctx - > graph , & fenum ) ;
if ( r = = S_OK ) {
IBaseFilter * f ;
IEnumFilters_Reset ( fenum ) ;
2011-09-30 20:49:43 +00:00
while ( IEnumFilters_Next ( fenum , 1 , & f , NULL ) = = S_OK ) {
2011-09-13 17:56:28 +00:00
if ( IGraphBuilder_RemoveFilter ( ctx - > graph , f ) = = S_OK )
IEnumFilters_Reset ( fenum ) ; /* When a filter is removed,
* the list must be reset . */
2011-09-30 20:49:43 +00:00
IBaseFilter_Release ( f ) ;
}
2011-09-13 17:56:28 +00:00
IEnumFilters_Release ( fenum ) ;
}
IGraphBuilder_Release ( ctx - > graph ) ;
}
2011-05-21 12:24:50 +00:00
if ( ctx - > capture_pin [ VideoDevice ] )
2022-05-23 03:23:35 +00:00
ff_dshow_pin_Release ( ctx - > capture_pin [ VideoDevice ] ) ;
2011-05-21 12:24:50 +00:00
if ( ctx - > capture_pin [ AudioDevice ] )
2022-05-23 03:23:35 +00:00
ff_dshow_pin_Release ( ctx - > capture_pin [ AudioDevice ] ) ;
2011-05-21 12:24:50 +00:00
if ( ctx - > capture_filter [ VideoDevice ] )
2022-05-23 03:23:35 +00:00
ff_dshow_filter_Release ( ctx - > capture_filter [ VideoDevice ] ) ;
2011-05-21 12:24:50 +00:00
if ( ctx - > capture_filter [ AudioDevice ] )
2022-05-23 03:23:35 +00:00
ff_dshow_filter_Release ( ctx - > capture_filter [ AudioDevice ] ) ;
2011-05-21 12:24:50 +00:00
if ( ctx - > device_pin [ VideoDevice ] )
IPin_Release ( ctx - > device_pin [ VideoDevice ] ) ;
if ( ctx - > device_pin [ AudioDevice ] )
IPin_Release ( ctx - > device_pin [ AudioDevice ] ) ;
if ( ctx - > device_filter [ VideoDevice ] )
IBaseFilter_Release ( ctx - > device_filter [ VideoDevice ] ) ;
if ( ctx - > device_filter [ AudioDevice ] )
IBaseFilter_Release ( ctx - > device_filter [ AudioDevice ] ) ;
2016-06-17 20:04:34 +00:00
av_freep ( & ctx - > device_name [ 0 ] ) ;
av_freep ( & ctx - > device_name [ 1 ] ) ;
av_freep ( & ctx - > device_unique_name [ 0 ] ) ;
av_freep ( & ctx - > device_unique_name [ 1 ] ) ;
2011-05-21 12:24:50 +00:00
if ( ctx - > mutex )
CloseHandle ( ctx - > mutex ) ;
2012-12-17 05:44:12 +00:00
if ( ctx - > event [ 0 ] )
CloseHandle ( ctx - > event [ 0 ] ) ;
if ( ctx - > event [ 1 ] )
CloseHandle ( ctx - > event [ 1 ] ) ;
2011-05-21 12:24:50 +00:00
pktl = ctx - > pktl ;
while ( pktl ) {
2024-04-25 09:18:18 +00:00
PacketListEntry * next = pktl - > next ;
2015-10-27 13:35:30 +00:00
av_packet_unref ( & pktl - > pkt ) ;
2011-05-21 12:24:50 +00:00
av_free ( pktl ) ;
pktl = next ;
}
2012-12-17 05:44:51 +00:00
CoUninitialize ( ) ;
2011-05-21 12:24:50 +00:00
return 0 ;
}
static char * dup_wchar_to_utf8 ( wchar_t * w )
{
char * s = NULL ;
int l = WideCharToMultiByte ( CP_UTF8 , 0 , w , - 1 , 0 , 0 , 0 , 0 ) ;
s = av_malloc ( l ) ;
if ( s )
WideCharToMultiByte ( CP_UTF8 , 0 , w , - 1 , s , l , 0 , 0 ) ;
return s ;
}
2014-03-27 19:44:20 +00:00
static int shall_we_drop ( AVFormatContext * s , int index , enum dshowDeviceType devtype )
2011-05-21 12:24:50 +00:00
{
struct dshow_ctx * ctx = s - > priv_data ;
2013-08-03 20:24:11 +00:00
static const uint8_t dropscore [ ] = { 62 , 75 , 87 , 100 } ;
2011-05-21 12:24:50 +00:00
const int ndropscores = FF_ARRAY_ELEMS ( dropscore ) ;
2014-03-21 22:27:01 +00:00
unsigned int buffer_fullness = ( ctx - > curbufsize [ index ] * 100 ) / s - > max_picture_buffer ;
2015-01-23 13:01:32 +00:00
const char * devtypename = ( devtype = = VideoDevice ) ? " video " : " audio " ;
2011-05-21 12:24:50 +00:00
if ( dropscore [ + + ctx - > video_frame_num % ndropscores ] < = buffer_fullness ) {
av_log ( s , AV_LOG_ERROR ,
2015-01-23 13:01:32 +00:00
" real-time buffer [%s] [%s input] too full or near too full (%d%% of size: %d [rtbufsize parameter])! frame dropped! \n " ,
ctx - > device_name [ devtype ] , devtypename , buffer_fullness , s - > max_picture_buffer ) ;
2011-05-21 12:24:50 +00:00
return 1 ;
}
return 0 ;
}
static void
2014-03-27 19:44:20 +00:00
callback ( void * priv_data , int index , uint8_t * buf , int buf_size , int64_t time , enum dshowDeviceType devtype )
2011-05-21 12:24:50 +00:00
{
AVFormatContext * s = priv_data ;
struct dshow_ctx * ctx = s - > priv_data ;
2024-04-25 09:18:18 +00:00
PacketListEntry * * ppktl , * pktl_next ;
2011-05-21 12:24:50 +00:00
// dump_videohdr(s, vdhdr);
WaitForSingleObject ( ctx - > mutex , INFINITE ) ;
2014-03-27 19:44:20 +00:00
if ( shall_we_drop ( s , index , devtype ) )
2012-08-19 14:10:07 +00:00
goto fail ;
2024-04-25 09:18:18 +00:00
pktl_next = av_mallocz ( sizeof ( * pktl_next ) ) ;
2011-05-21 12:24:50 +00:00
if ( ! pktl_next )
goto fail ;
if ( av_new_packet ( & pktl_next - > pkt , buf_size ) < 0 ) {
av_free ( pktl_next ) ;
goto fail ;
}
pktl_next - > pkt . stream_index = index ;
pktl_next - > pkt . pts = time ;
memcpy ( pktl_next - > pkt . data , buf , buf_size ) ;
for ( ppktl = & ctx - > pktl ; * ppktl ; ppktl = & ( * ppktl ) - > next ) ;
* ppktl = pktl_next ;
2014-03-21 22:27:01 +00:00
ctx - > curbufsize [ index ] + = buf_size ;
2011-05-21 12:24:50 +00:00
2012-12-17 05:44:12 +00:00
SetEvent ( ctx - > event [ 1 ] ) ;
2011-05-21 12:24:50 +00:00
ReleaseMutex ( ctx - > mutex ) ;
return ;
fail :
ReleaseMutex ( ctx - > mutex ) ;
return ;
}
2024-04-25 09:18:18 +00:00
static void
dshow_get_device_media_types ( AVFormatContext * avctx , enum dshowDeviceType devtype ,
enum dshowSourceFilterType sourcetype , IBaseFilter * device_filter ,
enum AVMediaType * * media_types , int * nb_media_types )
{
IEnumPins * pins = 0 ;
IPin * pin ;
int has_audio = 0 , has_video = 0 ;
if ( IBaseFilter_EnumPins ( device_filter , & pins ) ! = S_OK )
return ;
while ( IEnumPins_Next ( pins , 1 , & pin , NULL ) = = S_OK ) {
IKsPropertySet * p = NULL ;
PIN_INFO info = { 0 } ;
GUID category ;
DWORD r2 ;
IEnumMediaTypes * types = NULL ;
AM_MEDIA_TYPE * type ;
if ( IPin_QueryPinInfo ( pin , & info ) ! = S_OK )
goto next ;
IBaseFilter_Release ( info . pFilter ) ;
if ( info . dir ! = PINDIR_OUTPUT )
goto next ;
if ( IPin_QueryInterface ( pin , & IID_IKsPropertySet , ( void * * ) & p ) ! = S_OK )
goto next ;
if ( IKsPropertySet_Get ( p , & AMPROPSETID_Pin , AMPROPERTY_PIN_CATEGORY ,
NULL , 0 , & category , sizeof ( GUID ) , & r2 ) ! = S_OK )
goto next ;
if ( ! IsEqualGUID ( & category , & PIN_CATEGORY_CAPTURE ) )
goto next ;
if ( IPin_EnumMediaTypes ( pin , & types ) ! = S_OK )
goto next ;
// enumerate media types exposed by pin
// NB: don't know if a pin can expose both audio and video, check 'm all to be safe
IEnumMediaTypes_Reset ( types ) ;
while ( IEnumMediaTypes_Next ( types , 1 , & type , NULL ) = = S_OK ) {
if ( IsEqualGUID ( & type - > majortype , & MEDIATYPE_Video ) ) {
has_video = 1 ;
} else if ( IsEqualGUID ( & type - > majortype , & MEDIATYPE_Audio ) ) {
has_audio = 1 ;
}
CoTaskMemFree ( type ) ;
}
next :
if ( types )
IEnumMediaTypes_Release ( types ) ;
if ( p )
IKsPropertySet_Release ( p ) ;
if ( pin )
IPin_Release ( pin ) ;
}
IEnumPins_Release ( pins ) ;
if ( has_audio | | has_video ) {
int nb_types = has_audio + has_video ;
* media_types = av_malloc_array ( nb_types , sizeof ( enum AVMediaType ) ) ;
if ( * media_types ) {
if ( has_audio )
( * media_types ) [ 0 ] = AVMEDIA_TYPE_AUDIO ;
if ( has_video )
( * media_types ) [ 0 + has_audio ] = AVMEDIA_TYPE_VIDEO ;
* nb_media_types = nb_types ;
}
}
}
2011-09-09 03:08:43 +00:00
/**
* Cycle through available devices using the device enumerator devenum ,
* retrieve the device with type specified by devtype and return the
* pointer to the object found in * pfilter .
2011-09-09 03:09:23 +00:00
* If pfilter is NULL , list all device names .
2024-04-25 09:18:18 +00:00
* If device_list is not NULL , populate it with found devices instead of
* outputting device names to log
2011-09-09 03:08:43 +00:00
*/
2011-05-21 12:24:50 +00:00
static int
2011-09-09 03:08:43 +00:00
dshow_cycle_devices ( AVFormatContext * avctx , ICreateDevEnum * devenum ,
2016-06-15 08:17:11 +00:00
enum dshowDeviceType devtype , enum dshowSourceFilterType sourcetype ,
2024-04-25 09:18:18 +00:00
IBaseFilter * * pfilter , char * * device_unique_name ,
AVDeviceInfoList * * device_list )
2011-05-21 12:24:50 +00:00
{
struct dshow_ctx * ctx = avctx - > priv_data ;
IBaseFilter * device_filter = NULL ;
IEnumMoniker * classenum = NULL ;
IMoniker * m = NULL ;
const char * device_name = ctx - > device_name [ devtype ] ;
2011-09-30 20:49:09 +00:00
int skip = ( devtype = = VideoDevice ) ? ctx - > video_device_number
: ctx - > audio_device_number ;
2011-09-02 04:33:24 +00:00
int r ;
2011-05-21 12:24:50 +00:00
const GUID * device_guid [ 2 ] = { & CLSID_VideoInputDeviceCategory ,
& CLSID_AudioInputDeviceCategory } ;
2015-01-23 13:54:44 +00:00
const char * devtypename = ( devtype = = VideoDevice ) ? " video " : " audio only " ;
const char * sourcetypename = ( sourcetype = = VideoSourceDevice ) ? " video " : " audio " ;
2011-05-21 12:24:50 +00:00
2015-01-23 13:54:44 +00:00
r = ICreateDevEnum_CreateClassEnumerator ( devenum , device_guid [ sourcetype ] ,
2011-05-21 12:24:50 +00:00
( IEnumMoniker * * ) & classenum , 0 ) ;
if ( r ! = S_OK ) {
2015-01-23 13:54:44 +00:00
av_log ( avctx , AV_LOG_ERROR , " Could not enumerate %s devices (or none found). \n " ,
2011-05-21 12:24:50 +00:00
devtypename ) ;
2011-09-09 03:08:43 +00:00
return AVERROR ( EIO ) ;
2011-05-21 12:24:50 +00:00
}
2011-09-09 03:16:17 +00:00
while ( ! device_filter & & IEnumMoniker_Next ( classenum , 1 , & m , NULL ) = = S_OK ) {
2011-05-21 12:24:50 +00:00
IPropertyBag * bag = NULL ;
2015-01-23 12:34:30 +00:00
char * friendly_name = NULL ;
char * unique_name = NULL ;
2011-05-21 12:24:50 +00:00
VARIANT var ;
2015-01-23 12:34:30 +00:00
IBindCtx * bind_ctx = NULL ;
LPOLESTR olestr = NULL ;
LPMALLOC co_malloc = NULL ;
2024-04-25 09:18:18 +00:00
AVDeviceInfo * device = NULL ;
enum AVMediaType * media_types = NULL ;
int nb_media_types = 0 ;
2015-01-23 12:34:30 +00:00
int i ;
r = CoGetMalloc ( 1 , & co_malloc ) ;
2016-02-13 15:55:02 +00:00
if ( r ! = S_OK )
2024-04-25 09:18:18 +00:00
goto fail ;
2015-01-23 12:34:30 +00:00
r = CreateBindCtx ( 0 , & bind_ctx ) ;
if ( r ! = S_OK )
2024-04-25 09:18:18 +00:00
goto fail ;
2015-01-23 12:34:30 +00:00
/* GetDisplayname works for both video and audio, DevicePath doesn't */
r = IMoniker_GetDisplayName ( m , bind_ctx , NULL , & olestr ) ;
if ( r ! = S_OK )
2024-04-25 09:18:18 +00:00
goto fail ;
2015-01-23 12:34:30 +00:00
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 ] = ' _ ' ;
}
2011-05-21 12:24:50 +00:00
r = IMoniker_BindToStorage ( m , 0 , 0 , & IID_IPropertyBag , ( void * ) & bag ) ;
if ( r ! = S_OK )
2024-04-25 09:18:18 +00:00
goto fail ;
2011-05-21 12:24:50 +00:00
var . vt = VT_BSTR ;
r = IPropertyBag_Read ( bag , L " FriendlyName " , & var , NULL ) ;
if ( r ! = S_OK )
2024-04-25 09:18:18 +00:00
goto fail ;
2015-01-23 12:34:30 +00:00
friendly_name = dup_wchar_to_utf8 ( var . bstrVal ) ;
2011-05-21 12:24:50 +00:00
2015-01-23 13:54:44 +00:00
if ( pfilter ) {
2015-01-23 12:34:30 +00:00
if ( strcmp ( device_name , friendly_name ) & & strcmp ( device_name , unique_name ) )
2024-04-25 09:18:18 +00:00
goto fail ;
2011-05-21 12:24:50 +00:00
2015-01-23 12:34:30 +00:00
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 ) ;
2024-04-25 09:18:18 +00:00
goto fail ;
2015-01-23 12:34:30 +00:00
}
2016-06-15 08:17:11 +00:00
* device_unique_name = unique_name ;
2019-01-03 07:41:12 +00:00
unique_name = NULL ;
2016-06-15 08:17:11 +00:00
// success, loop will end now
2015-01-23 12:34:30 +00:00
}
2011-09-09 03:09:23 +00:00
} else {
2024-04-25 09:18:18 +00:00
// get media types exposed by pins of device
if ( IMoniker_BindToObject ( m , 0 , 0 , & IID_IBaseFilter , ( void * ) & device_filter ) = = S_OK ) {
dshow_get_device_media_types ( avctx , devtype , sourcetype , device_filter , & media_types , & nb_media_types ) ;
IBaseFilter_Release ( device_filter ) ;
device_filter = NULL ;
}
if ( device_list ) {
device = av_mallocz ( sizeof ( AVDeviceInfo ) ) ;
if ( ! device )
goto fail ;
device - > device_name = av_strdup ( unique_name ) ;
device - > device_description = av_strdup ( friendly_name ) ;
if ( ! device - > device_name | | ! device - > device_description )
goto fail ;
// make space in device_list for this new device
if ( av_reallocp_array ( & ( * device_list ) - > devices ,
( * device_list ) - > nb_devices + 1 ,
sizeof ( * ( * device_list ) - > devices ) ) < 0 )
goto fail ;
// attach media_types to device
device - > nb_media_types = nb_media_types ;
device - > media_types = media_types ;
nb_media_types = 0 ;
media_types = NULL ;
// store device in list
( * device_list ) - > devices [ ( * device_list ) - > nb_devices ] = device ;
( * device_list ) - > nb_devices + + ;
device = NULL ; // copied into array, make sure not freed below
}
else {
av_log ( avctx , AV_LOG_INFO , " \" %s \" " , friendly_name ) ;
if ( nb_media_types > 0 ) {
const char * media_type = av_get_media_type_string ( media_types [ 0 ] ) ;
av_log ( avctx , AV_LOG_INFO , " (%s " , media_type ? media_type : " unknown " ) ;
for ( int i = 1 ; i < nb_media_types ; + + i ) {
media_type = av_get_media_type_string ( media_types [ i ] ) ;
av_log ( avctx , AV_LOG_INFO , " , %s " , media_type ? media_type : " unknown " ) ;
}
av_log ( avctx , AV_LOG_INFO , " ) " ) ;
} else {
av_log ( avctx , AV_LOG_INFO , " (none) " ) ;
}
av_log ( avctx , AV_LOG_INFO , " \n " ) ;
av_log ( avctx , AV_LOG_INFO , " Alternative name \" %s \" \n " , unique_name ) ;
}
2011-09-09 03:09:23 +00:00
}
2011-05-21 12:24:50 +00:00
2024-04-25 09:18:18 +00:00
fail :
av_freep ( & media_types ) ;
if ( device ) {
av_freep ( & device - > device_name ) ;
av_freep ( & device - > device_description ) ;
// NB: no need to av_freep(&device->media_types), its only moved to device once nothing can fail anymore
av_free ( device ) ;
}
2015-01-23 12:34:30 +00:00
if ( olestr & & co_malloc )
IMalloc_Free ( co_malloc , olestr ) ;
if ( bind_ctx )
IBindCtx_Release ( bind_ctx ) ;
2019-01-03 07:41:12 +00:00
av_freep ( & friendly_name ) ;
av_freep ( & unique_name ) ;
2011-05-21 12:24:50 +00:00
if ( bag )
IPropertyBag_Release ( bag ) ;
IMoniker_Release ( m ) ;
}
2011-09-09 03:08:43 +00:00
IEnumMoniker_Release ( classenum ) ;
2011-09-09 03:09:23 +00:00
if ( pfilter ) {
2011-09-09 03:09:42 +00:00
if ( ! device_filter ) {
2015-01-23 13:54:44 +00:00
av_log ( avctx , AV_LOG_ERROR , " Could not find %s device with name [%s] among source devices of type %s. \n " ,
devtypename , device_name , sourcetypename ) ;
2011-09-09 03:09:42 +00:00
return AVERROR ( EIO ) ;
}
* pfilter = device_filter ;
2011-09-09 03:09:23 +00:00
}
2011-09-09 03:08:43 +00:00
return 0 ;
}
2024-04-25 09:18:18 +00:00
static int dshow_get_device_list ( AVFormatContext * avctx , AVDeviceInfoList * device_list )
{
ICreateDevEnum * devenum = NULL ;
int r ;
int ret = AVERROR ( EIO ) ;
if ( ! device_list )
return AVERROR ( EINVAL ) ;
CoInitialize ( 0 ) ;
r = CoCreateInstance ( & CLSID_SystemDeviceEnum , NULL , CLSCTX_INPROC_SERVER ,
& IID_ICreateDevEnum , ( void * * ) & devenum ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not enumerate system devices. \n " ) ;
goto error ;
}
ret = dshow_cycle_devices ( avctx , devenum , VideoDevice , VideoSourceDevice , NULL , NULL , & device_list ) ;
if ( ret < S_OK )
goto error ;
ret = dshow_cycle_devices ( avctx , devenum , AudioDevice , AudioSourceDevice , NULL , NULL , & device_list ) ;
error :
if ( devenum )
ICreateDevEnum_Release ( devenum ) ;
CoUninitialize ( ) ;
return ret ;
}
static int dshow_should_set_format ( AVFormatContext * avctx , enum dshowDeviceType devtype )
{
struct dshow_ctx * ctx = avctx - > priv_data ;
return ( devtype = = VideoDevice & & ( ctx - > framerate | |
( ctx - > requested_width & & ctx - > requested_height ) | |
ctx - > pixel_format ! = AV_PIX_FMT_NONE | |
ctx - > video_codec_id ! = AV_CODEC_ID_RAWVIDEO ) )
| | ( devtype = = AudioDevice & & ( ctx - > channels | | ctx - > sample_size | | ctx - > sample_rate ) ) ;
}
struct dshow_format_info {
enum dshowDeviceType devtype ;
// video
int64_t framerate ;
enum AVPixelFormat pix_fmt ;
enum AVCodecID codec_id ;
enum AVColorRange col_range ;
enum AVColorSpace col_space ;
enum AVColorPrimaries col_prim ;
enum AVColorTransferCharacteristic col_trc ;
enum AVChromaLocation chroma_loc ;
int width ;
int height ;
// audio
int sample_rate ;
int sample_size ;
int channels ;
} ;
// user must av_free the returned pointer
static struct dshow_format_info * dshow_get_format_info ( AM_MEDIA_TYPE * type )
{
struct dshow_format_info * fmt_info = NULL ;
BITMAPINFOHEADER * bih ;
DXVA2_ExtendedFormat * extended_format_info = NULL ;
WAVEFORMATEX * fx ;
enum dshowDeviceType devtype ;
int64_t framerate ;
if ( ! type )
return NULL ;
if ( IsEqualGUID ( & type - > formattype , & FORMAT_VideoInfo ) ) {
VIDEOINFOHEADER * v = ( void * ) type - > pbFormat ;
framerate = v - > AvgTimePerFrame ;
bih = & v - > bmiHeader ;
devtype = VideoDevice ;
} else if ( IsEqualGUID ( & type - > formattype , & FORMAT_VideoInfo2 ) ) {
VIDEOINFOHEADER2 * v = ( void * ) type - > pbFormat ;
devtype = VideoDevice ;
framerate = v - > AvgTimePerFrame ;
bih = & v - > bmiHeader ;
if ( v - > dwControlFlags & AMCONTROL_COLORINFO_PRESENT )
extended_format_info = ( DXVA2_ExtendedFormat * ) & v - > dwControlFlags ;
} else if ( IsEqualGUID ( & type - > formattype , & FORMAT_WaveFormatEx ) ) {
fx = ( void * ) type - > pbFormat ;
devtype = AudioDevice ;
} else {
return NULL ;
}
fmt_info = av_mallocz ( sizeof ( struct dshow_format_info ) ) ;
if ( ! fmt_info )
return NULL ;
// initialize fields where unset is not zero
fmt_info - > pix_fmt = AV_PIX_FMT_NONE ;
fmt_info - > col_space = AVCOL_SPC_UNSPECIFIED ;
fmt_info - > col_prim = AVCOL_PRI_UNSPECIFIED ;
fmt_info - > col_trc = AVCOL_TRC_UNSPECIFIED ;
// now get info about format
fmt_info - > devtype = devtype ;
if ( devtype = = VideoDevice ) {
fmt_info - > width = bih - > biWidth ;
fmt_info - > height = bih - > biHeight ;
fmt_info - > framerate = framerate ;
fmt_info - > pix_fmt = dshow_pixfmt ( bih - > biCompression , bih - > biBitCount ) ;
if ( fmt_info - > pix_fmt = = AV_PIX_FMT_NONE ) {
const AVCodecTag * const tags [ ] = { avformat_get_riff_video_tags ( ) , NULL } ;
fmt_info - > codec_id = av_codec_get_id ( tags , bih - > biCompression ) ;
}
else
fmt_info - > codec_id = AV_CODEC_ID_RAWVIDEO ;
if ( extended_format_info ) {
fmt_info - > col_range = dshow_color_range ( extended_format_info ) ;
fmt_info - > col_space = dshow_color_space ( extended_format_info ) ;
fmt_info - > col_prim = dshow_color_primaries ( extended_format_info ) ;
fmt_info - > col_trc = dshow_color_trc ( extended_format_info ) ;
fmt_info - > chroma_loc = dshow_chroma_loc ( extended_format_info ) ;
}
} else {
fmt_info - > sample_rate = fx - > nSamplesPerSec ;
fmt_info - > sample_size = fx - > wBitsPerSample ;
fmt_info - > channels = fx - > nChannels ;
}
return fmt_info ;
}
static void dshow_get_default_format ( IPin * pin , IAMStreamConfig * config , enum dshowDeviceType devtype , AM_MEDIA_TYPE * * type )
{
HRESULT hr ;
if ( ( hr = IAMStreamConfig_GetFormat ( config , type ) ) ! = S_OK ) {
if ( hr = = E_NOTIMPL | | ! IsEqualGUID ( & ( * type ) - > majortype , devtype = = VideoDevice ? & MEDIATYPE_Video : & MEDIATYPE_Audio ) ) {
// default not available or of wrong type,
// fall back to iterating exposed formats
// until one of the right type is found
IEnumMediaTypes * types = NULL ;
if ( IPin_EnumMediaTypes ( pin , & types ) ! = S_OK )
return ;
IEnumMediaTypes_Reset ( types ) ;
while ( IEnumMediaTypes_Next ( types , 1 , type , NULL ) = = S_OK ) {
if ( IsEqualGUID ( & ( * type ) - > majortype , devtype = = VideoDevice ? & MEDIATYPE_Video : & MEDIATYPE_Audio ) ) {
break ;
}
CoTaskMemFree ( * type ) ;
* type = NULL ;
}
IEnumMediaTypes_Release ( types ) ;
}
}
}
2011-09-09 03:12:42 +00:00
/**
2024-04-25 09:18:18 +00:00
* Cycle through available formats available from the specified pin ,
* try to set parameters specified through AVOptions , or the pin ' s
* default format if no such parameters were set . If successful ,
2011-09-09 03:12:42 +00:00
* return 1 in * pformat_set .
2011-09-09 03:15:14 +00:00
* If pformat_set is NULL , list all pin capabilities .
2011-09-09 03:12:42 +00:00
*/
static void
dshow_cycle_formats ( AVFormatContext * avctx , enum dshowDeviceType devtype ,
IPin * pin , int * pformat_set )
{
struct dshow_ctx * ctx = avctx - > priv_data ;
IAMStreamConfig * config = NULL ;
AM_MEDIA_TYPE * type = NULL ;
2024-04-25 09:18:18 +00:00
AM_MEDIA_TYPE * previous_match_type = NULL ;
2011-09-09 03:12:42 +00:00
int format_set = 0 ;
void * caps = NULL ;
2015-01-23 13:01:32 +00:00
int i , n , size , r ;
2024-04-25 09:18:18 +00:00
int wait_for_better = 0 ;
int use_default ;
// format parameters requested by user
// if none are requested by user, the values will below be set to
// those of the default format
// video
enum AVCodecID requested_video_codec_id = ctx - > video_codec_id ;
enum AVPixelFormat requested_pixel_format = ctx - > pixel_format ;
int64_t requested_framerate = ctx - > framerate ? ( ( int64_t ) ctx - > requested_framerate . den * 10000000 )
/ ctx - > requested_framerate . num : 0 ;
int requested_width = ctx - > requested_width ;
int requested_height = ctx - > requested_height ;
// audio
int requested_sample_rate = ctx - > sample_rate ;
int requested_sample_size = ctx - > sample_size ;
int requested_channels = ctx - > channels ;
2011-09-09 03:12:42 +00:00
if ( IPin_QueryInterface ( pin , & IID_IAMStreamConfig , ( void * * ) & config ) ! = S_OK )
return ;
if ( IAMStreamConfig_GetNumberOfCapabilities ( config , & n , & size ) ! = S_OK )
goto end ;
caps = av_malloc ( size ) ;
if ( ! caps )
goto end ;
2024-04-25 09:18:18 +00:00
/**
* If we should open the device with the default format ,
* then :
* 1. check what the format of the default device is , and
* 2. below we iterate all formats till we find a matching
* one , with most info exposed ( see comment below ) .
*/
use_default = ! dshow_should_set_format ( avctx , devtype ) ;
if ( use_default & & pformat_set )
{
// get default
dshow_get_default_format ( pin , config , devtype , & type ) ;
if ( ! type )
// this pin does not expose any formats of the expected type
goto end ;
if ( type ) {
// interrogate default format, so we know what to search for below
struct dshow_format_info * fmt_info = dshow_get_format_info ( type ) ;
if ( fmt_info ) {
if ( fmt_info - > devtype = = VideoDevice ) {
requested_video_codec_id = fmt_info - > codec_id ;
requested_pixel_format = fmt_info - > pix_fmt ;
requested_framerate = fmt_info - > framerate ;
requested_width = fmt_info - > width ;
requested_height = fmt_info - > height ;
} else {
requested_sample_rate = fmt_info - > sample_rate ;
requested_sample_size = fmt_info - > sample_size ;
requested_channels = fmt_info - > channels ;
}
av_free ( fmt_info ) ; // free but don't set to NULL to enable below check
}
if ( type & & type - > pbFormat )
CoTaskMemFree ( type - > pbFormat ) ;
CoTaskMemFree ( type ) ;
type = NULL ;
if ( ! fmt_info )
// default format somehow invalid, can't continue with this pin
goto end ;
fmt_info = NULL ;
}
}
// NB: some devices (e.g. Logitech C920) expose each video format twice:
// both a format containing a VIDEOINFOHEADER and a format containing
// a VIDEOINFOHEADER2. We want, if possible, to select a format with a
// VIDEOINFOHEADER2, as this potentially provides more info about the
// format. So, if in the iteration below we have found a matching format,
// but it is a VIDEOINFOHEADER, keep looking for a matching format that
// exposes contains a VIDEOINFOHEADER2. Fall back to the VIDEOINFOHEADER
// format if no corresponding VIDEOINFOHEADER2 is found when we finish
// iterating.
2011-09-09 03:12:42 +00:00
for ( i = 0 ; i < n & & ! format_set ; i + + ) {
2024-04-25 09:18:18 +00:00
struct dshow_format_info * fmt_info = NULL ;
2015-01-23 13:01:32 +00:00
r = IAMStreamConfig_GetStreamCaps ( config , i , & type , ( void * ) caps ) ;
if ( r ! = S_OK )
goto next ;
2011-09-09 03:12:42 +00:00
# if DSHOWDEBUG
ff_print_AM_MEDIA_TYPE ( type ) ;
# endif
2024-04-25 09:18:18 +00:00
fmt_info = dshow_get_format_info ( type ) ;
if ( ! fmt_info )
goto next ;
2011-09-09 03:12:42 +00:00
if ( devtype = = VideoDevice ) {
VIDEO_STREAM_CONFIG_CAPS * vcaps = caps ;
BITMAPINFOHEADER * bih ;
int64_t * fr ;
# if DSHOWDEBUG
ff_print_VIDEO_STREAM_CONFIG_CAPS ( vcaps ) ;
# endif
2024-04-25 09:18:18 +00:00
if ( fmt_info - > devtype ! = VideoDevice )
goto next ;
2011-09-09 03:12:42 +00:00
if ( IsEqualGUID ( & type - > formattype , & FORMAT_VideoInfo ) ) {
VIDEOINFOHEADER * v = ( void * ) type - > pbFormat ;
2024-04-25 09:18:18 +00:00
fr = & v - > AvgTimePerFrame ;
2011-09-09 03:12:42 +00:00
bih = & v - > bmiHeader ;
2024-04-25 09:18:18 +00:00
wait_for_better = 1 ;
2011-09-09 03:12:42 +00:00
} else if ( IsEqualGUID ( & type - > formattype , & FORMAT_VideoInfo2 ) ) {
VIDEOINFOHEADER2 * v = ( void * ) type - > pbFormat ;
2024-04-25 09:18:18 +00:00
fr = & v - > AvgTimePerFrame ;
2011-09-09 03:12:42 +00:00
bih = & v - > bmiHeader ;
2024-04-25 09:18:18 +00:00
wait_for_better = 0 ;
2011-09-09 03:12:42 +00:00
}
2024-04-25 09:18:18 +00:00
2011-09-09 03:15:14 +00:00
if ( ! pformat_set ) {
2024-04-25 09:18:18 +00:00
const char * chroma = av_chroma_location_name ( fmt_info - > chroma_loc ) ;
if ( fmt_info - > pix_fmt = = AV_PIX_FMT_NONE ) {
const AVCodec * codec = avcodec_find_decoder ( fmt_info - > codec_id ) ;
if ( fmt_info - > codec_id = = AV_CODEC_ID_NONE | | ! codec ) {
2012-09-07 21:52:32 +00:00
av_log ( avctx , AV_LOG_INFO , " unknown compression type 0x%X " , ( int ) bih - > biCompression ) ;
2012-09-06 23:41:19 +00:00
} else {
av_log ( avctx , AV_LOG_INFO , " vcodec=%s " , codec - > name ) ;
}
} else {
2024-04-25 09:18:18 +00:00
av_log ( avctx , AV_LOG_INFO , " pixel_format=%s " , av_get_pix_fmt_name ( fmt_info - > pix_fmt ) ) ;
2012-09-06 23:41:19 +00:00
}
2024-04-25 09:18:18 +00:00
av_log ( avctx , AV_LOG_INFO , " min s=%ldx%ld fps=%g max s=%ldx%ld fps=%g " ,
2011-09-09 03:15:14 +00:00
vcaps - > MinOutputSize . cx , vcaps - > MinOutputSize . cy ,
2011-09-30 21:10:30 +00:00
1e7 / vcaps - > MaxFrameInterval ,
2011-09-09 03:15:14 +00:00
vcaps - > MaxOutputSize . cx , vcaps - > MaxOutputSize . cy ,
2011-09-30 21:10:30 +00:00
1e7 / vcaps - > MinFrameInterval ) ;
2024-04-25 09:18:18 +00:00
if ( fmt_info - > col_range ! = AVCOL_RANGE_UNSPECIFIED | |
fmt_info - > col_space ! = AVCOL_SPC_UNSPECIFIED | |
fmt_info - > col_prim ! = AVCOL_PRI_UNSPECIFIED | |
fmt_info - > col_trc ! = AVCOL_TRC_UNSPECIFIED ) {
const char * range = av_color_range_name ( fmt_info - > col_range ) ;
const char * space = av_color_space_name ( fmt_info - > col_space ) ;
const char * prim = av_color_primaries_name ( fmt_info - > col_prim ) ;
const char * trc = av_color_transfer_name ( fmt_info - > col_trc ) ;
av_log ( avctx , AV_LOG_INFO , " (%s, %s/%s/%s " ,
range ? range : " unknown " ,
space ? space : " unknown " ,
prim ? prim : " unknown " ,
trc ? trc : " unknown " ) ;
if ( fmt_info - > chroma_loc ! = AVCHROMA_LOC_UNSPECIFIED )
av_log ( avctx , AV_LOG_INFO , " , %s " , chroma ? chroma : " unknown " ) ;
av_log ( avctx , AV_LOG_INFO , " ) " ) ;
}
else if ( fmt_info - > chroma_loc ! = AVCHROMA_LOC_UNSPECIFIED )
av_log ( avctx , AV_LOG_INFO , " (%s) " , chroma ? chroma : " unknown " ) ;
av_log ( avctx , AV_LOG_INFO , " \n " ) ;
goto next ;
2011-09-09 03:15:14 +00:00
}
2024-04-25 09:18:18 +00:00
if ( requested_video_codec_id ! = AV_CODEC_ID_RAWVIDEO ) {
if ( requested_video_codec_id ! = fmt_info - > codec_id )
2012-09-06 23:41:19 +00:00
goto next ;
}
2024-04-25 09:18:18 +00:00
if ( requested_pixel_format ! = AV_PIX_FMT_NONE & &
requested_pixel_format ! = fmt_info - > pix_fmt ) {
2012-09-06 23:41:19 +00:00
goto next ;
}
2024-04-25 09:18:18 +00:00
if ( requested_framerate ) {
if ( requested_framerate > vcaps - > MaxFrameInterval | |
requested_framerate < vcaps - > MinFrameInterval )
2011-09-09 03:12:42 +00:00
goto next ;
2024-04-25 09:18:18 +00:00
* fr = requested_framerate ;
2011-09-09 03:12:42 +00:00
}
2024-04-25 09:18:18 +00:00
if ( requested_width & & requested_height ) {
if ( requested_width > vcaps - > MaxOutputSize . cx | |
requested_width < vcaps - > MinOutputSize . cx | |
requested_height > vcaps - > MaxOutputSize . cy | |
requested_height < vcaps - > MinOutputSize . cy )
2011-09-09 03:12:42 +00:00
goto next ;
2024-04-25 09:18:18 +00:00
bih - > biWidth = requested_width ;
bih - > biHeight = requested_height ;
2011-09-09 03:12:42 +00:00
}
} else {
2024-02-05 11:18:57 +00:00
WAVEFORMATEX * fx ;
2024-04-25 09:18:18 +00:00
AUDIO_STREAM_CONFIG_CAPS * acaps = caps ;
2011-09-09 03:12:42 +00:00
# if DSHOWDEBUG
ff_print_AUDIO_STREAM_CONFIG_CAPS ( acaps ) ;
# endif
if ( IsEqualGUID ( & type - > formattype , & FORMAT_WaveFormatEx ) ) {
fx = ( void * ) type - > pbFormat ;
} else {
goto next ;
}
2011-09-09 03:15:14 +00:00
if ( ! pformat_set ) {
2024-04-25 09:18:18 +00:00
av_log (
avctx ,
AV_LOG_INFO ,
" ch=%2u, bits=%2u, rate=%6lu \n " ,
fx - > nChannels , fx - > wBitsPerSample , fx - > nSamplesPerSec
) ;
2011-09-09 03:15:14 +00:00
continue ;
}
2024-04-25 09:18:18 +00:00
if (
( requested_sample_rate & & requested_sample_rate ! = fx - > nSamplesPerSec ) | |
( requested_sample_size & & requested_sample_size ! = fx - > wBitsPerSample ) | |
( requested_channels & & requested_channels ! = fx - > nChannels )
) {
goto next ;
2011-09-09 03:12:42 +00:00
}
}
2024-04-25 09:18:18 +00:00
// found a matching format. Either apply or store
// for safekeeping if we might maybe find a better
// format with more info attached to it (see comment
// above loop)
if ( ! wait_for_better ) {
if ( IAMStreamConfig_SetFormat ( config , type ) ! = S_OK )
goto next ;
format_set = 1 ;
}
else if ( ! previous_match_type ) {
// store this matching format for possible later use.
// If we have already found a matching format, ignore it
previous_match_type = type ;
type = NULL ;
}
2011-09-09 03:12:42 +00:00
next :
2024-04-25 09:18:18 +00:00
av_freep ( & fmt_info ) ;
if ( type & & type - > pbFormat )
2011-09-09 03:12:42 +00:00
CoTaskMemFree ( type - > pbFormat ) ;
CoTaskMemFree ( type ) ;
2024-04-25 09:18:18 +00:00
type = NULL ;
2011-09-09 03:12:42 +00:00
}
2024-04-25 09:18:18 +00:00
// set the pin's format, if wanted
if ( pformat_set & & ! format_set ) {
if ( previous_match_type ) {
// previously found a matching VIDEOINFOHEADER format and stored
// it for safe keeping. Searching further for a matching
// VIDEOINFOHEADER2 format yielded nothing. So set the pin's
// format based on the VIDEOINFOHEADER format.
// NB: this never applies to an audio format because
// previous_match_type always NULL in that case
if ( IAMStreamConfig_SetFormat ( config , previous_match_type ) = = S_OK )
format_set = 1 ;
}
else if ( use_default ) {
// default format returned by device apparently was not contained
// in the capabilities of any of the formats returned by the device
// (sic?). Fall back to directly setting the default format
dshow_get_default_format ( pin , config , devtype , & type ) ;
if ( IAMStreamConfig_SetFormat ( config , type ) = = S_OK )
format_set = 1 ;
if ( type & & type - > pbFormat )
CoTaskMemFree ( type - > pbFormat ) ;
CoTaskMemFree ( type ) ;
type = NULL ;
}
}
2011-09-09 03:12:42 +00:00
end :
2024-04-25 09:18:18 +00:00
if ( previous_match_type & & previous_match_type - > pbFormat )
CoTaskMemFree ( previous_match_type - > pbFormat ) ;
CoTaskMemFree ( previous_match_type ) ;
2011-09-09 03:12:42 +00:00
IAMStreamConfig_Release ( config ) ;
2014-12-28 17:17:12 +00:00
av_free ( caps ) ;
2011-09-09 03:15:14 +00:00
if ( pformat_set )
2011-09-09 03:15:22 +00:00
* pformat_set = format_set ;
2011-09-09 03:12:42 +00:00
}
2012-08-25 08:09:37 +00:00
/**
* Set audio device buffer size in milliseconds ( which can directly impact
* latency , depending on the device ) .
*/
static int
dshow_set_audio_buffer_size ( AVFormatContext * avctx , IPin * pin )
{
struct dshow_ctx * ctx = avctx - > priv_data ;
IAMBufferNegotiation * buffer_negotiation = NULL ;
ALLOCATOR_PROPERTIES props = { - 1 , - 1 , - 1 , - 1 } ;
IAMStreamConfig * config = NULL ;
AM_MEDIA_TYPE * type = NULL ;
int ret = AVERROR ( EIO ) ;
if ( IPin_QueryInterface ( pin , & IID_IAMStreamConfig , ( void * * ) & config ) ! = S_OK )
goto end ;
if ( IAMStreamConfig_GetFormat ( config , & type ) ! = S_OK )
goto end ;
if ( ! IsEqualGUID ( & type - > formattype , & FORMAT_WaveFormatEx ) )
goto end ;
props . cbBuffer = ( ( ( WAVEFORMATEX * ) type - > pbFormat ) - > nAvgBytesPerSec )
* ctx - > audio_buffer_size / 1000 ;
if ( IPin_QueryInterface ( pin , & IID_IAMBufferNegotiation , ( void * * ) & buffer_negotiation ) ! = S_OK )
goto end ;
if ( IAMBufferNegotiation_SuggestAllocatorProperties ( buffer_negotiation , & props ) ! = S_OK )
goto end ;
ret = 0 ;
end :
if ( buffer_negotiation )
IAMBufferNegotiation_Release ( buffer_negotiation ) ;
if ( type ) {
if ( type - > pbFormat )
CoTaskMemFree ( type - > pbFormat ) ;
CoTaskMemFree ( type ) ;
}
if ( config )
IAMStreamConfig_Release ( config ) ;
return ret ;
}
2015-01-23 13:49:37 +00:00
/**
* Pops up a user dialog allowing them to adjust properties for the given filter , if possible .
*/
void
2022-05-23 03:23:35 +00:00
ff_dshow_show_filter_properties ( IBaseFilter * device_filter , AVFormatContext * avctx ) {
2015-01-23 13:49:37 +00:00
ISpecifyPropertyPages * property_pages = NULL ;
IUnknown * device_filter_iunknown = NULL ;
HRESULT hr ;
2015-01-23 13:54:44 +00:00
FILTER_INFO filter_info = { 0 } ; /* a warning on this line is false positive GCC bug 53119 AFAICT */
2015-01-23 13:49:37 +00:00
CAUUID ca_guid = { 0 } ;
hr = IBaseFilter_QueryInterface ( device_filter , & IID_ISpecifyPropertyPages , ( void * * ) & property_pages ) ;
if ( hr ! = S_OK ) {
av_log ( avctx , AV_LOG_WARNING , " requested filter does not have a property page to show " ) ;
goto end ;
}
hr = IBaseFilter_QueryFilterInfo ( device_filter , & filter_info ) ;
if ( hr ! = S_OK ) {
goto fail ;
}
hr = IBaseFilter_QueryInterface ( device_filter , & IID_IUnknown , ( void * * ) & device_filter_iunknown ) ;
if ( hr ! = S_OK ) {
goto fail ;
}
hr = ISpecifyPropertyPages_GetPages ( property_pages , & ca_guid ) ;
if ( hr ! = S_OK ) {
goto fail ;
}
hr = OleCreatePropertyFrame ( NULL , 0 , 0 , filter_info . achName , 1 , & device_filter_iunknown , ca_guid . cElems ,
ca_guid . pElems , 0 , 0 , NULL ) ;
if ( hr ! = S_OK ) {
goto fail ;
}
goto end ;
fail :
av_log ( avctx , AV_LOG_ERROR , " Failure showing property pages for filter " ) ;
end :
if ( property_pages )
ISpecifyPropertyPages_Release ( property_pages ) ;
if ( device_filter_iunknown )
IUnknown_Release ( device_filter_iunknown ) ;
if ( filter_info . pGraph )
IFilterGraph_Release ( filter_info . pGraph ) ;
if ( ca_guid . pElems )
CoTaskMemFree ( ca_guid . pElems ) ;
}
2011-09-09 03:10:07 +00:00
/**
* Cycle through available pins using the device_filter device , of type
* devtype , retrieve the first output pin and return the pointer to the
* object found in * ppin .
2011-09-09 03:15:14 +00:00
* If ppin is NULL , cycle through all pins listing audio / video capabilities .
2011-09-09 03:10:07 +00:00
*/
2011-09-09 03:08:43 +00:00
static int
2011-09-09 03:10:07 +00:00
dshow_cycle_pins ( AVFormatContext * avctx , enum dshowDeviceType devtype ,
2015-01-23 13:54:44 +00:00
enum dshowSourceFilterType sourcetype , IBaseFilter * device_filter , IPin * * ppin )
2011-09-09 03:08:43 +00:00
{
2011-09-09 03:12:42 +00:00
struct dshow_ctx * ctx = avctx - > priv_data ;
2011-09-09 03:08:43 +00:00
IEnumPins * pins = 0 ;
IPin * device_pin = NULL ;
IPin * pin ;
int r ;
2015-01-23 13:54:44 +00:00
const char * devtypename = ( devtype = = VideoDevice ) ? " video " : " audio only " ;
const char * sourcetypename = ( sourcetype = = VideoSourceDevice ) ? " video " : " audio " ;
2011-05-21 12:24:50 +00:00
2024-04-25 09:18:18 +00:00
int set_format = dshow_should_set_format ( avctx , devtype ) ;
2011-09-09 03:12:42 +00:00
int format_set = 0 ;
2015-01-23 13:49:37 +00:00
int should_show_properties = ( devtype = = VideoDevice ) ? ctx - > show_video_device_dialog : ctx - > show_audio_device_dialog ;
if ( should_show_properties )
2022-05-23 03:23:35 +00:00
ff_dshow_show_filter_properties ( device_filter , avctx ) ;
2011-09-09 03:12:42 +00:00
2011-05-21 12:24:50 +00:00
r = IBaseFilter_EnumPins ( device_filter , & pins ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not enumerate pins. \n " ) ;
2011-09-09 03:10:07 +00:00
return AVERROR ( EIO ) ;
2011-05-21 12:24:50 +00:00
}
2011-09-09 03:15:14 +00:00
if ( ! ppin ) {
2015-01-23 13:54:44 +00:00
av_log ( avctx , AV_LOG_INFO , " DirectShow %s device options (from %s devices) \n " ,
devtypename , sourcetypename ) ;
2011-09-09 03:15:14 +00:00
}
2015-01-23 13:54:44 +00:00
2011-09-09 03:16:17 +00:00
while ( ! device_pin & & IEnumPins_Next ( pins , 1 , & pin , NULL ) = = S_OK ) {
2011-05-21 12:24:50 +00:00
IKsPropertySet * p = NULL ;
PIN_INFO info = { 0 } ;
GUID category ;
DWORD r2 ;
2015-01-23 12:34:30 +00:00
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 ;
2011-05-21 12:24:50 +00:00
IPin_QueryPinInfo ( pin , & info ) ;
IBaseFilter_Release ( info . pFilter ) ;
if ( info . dir ! = PINDIR_OUTPUT )
goto next ;
if ( IPin_QueryInterface ( pin , & IID_IKsPropertySet , ( void * * ) & p ) ! = S_OK )
goto next ;
if ( IKsPropertySet_Get ( p , & AMPROPSETID_Pin , AMPROPERTY_PIN_CATEGORY ,
NULL , 0 , & category , sizeof ( GUID ) , & r2 ) ! = S_OK )
goto next ;
if ( ! IsEqualGUID ( & category , & PIN_CATEGORY_CAPTURE ) )
goto next ;
2015-01-23 12:34:30 +00:00
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 ) ;
2011-09-09 03:15:14 +00:00
if ( ! ppin ) {
2015-01-23 12:34:30 +00:00
av_log ( avctx , AV_LOG_INFO , " Pin \" %s \" (alternative pin name \" %s \" ) \n " , name_buf , pin_buf ) ;
2011-09-09 03:15:14 +00:00
dshow_cycle_formats ( avctx , devtype , pin , NULL ) ;
goto next ;
}
2015-01-23 13:54:44 +00:00
2015-01-23 12:34:30 +00:00
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 ;
}
}
2024-04-25 09:18:18 +00:00
// will either try to find format matching options supplied by user
// or try to open default format. Successful if returns with format_set==1
dshow_cycle_formats ( avctx , devtype , pin , & format_set ) ;
if ( ! format_set ) {
goto next ;
2011-09-09 03:12:42 +00:00
}
2024-04-25 09:18:18 +00:00
2012-08-25 08:09:37 +00:00
if ( devtype = = AudioDevice & & ctx - > audio_buffer_size ) {
2014-03-25 16:08:49 +00:00
if ( dshow_set_audio_buffer_size ( avctx , pin ) < 0 ) {
av_log ( avctx , AV_LOG_ERROR , " unable to set audio buffer size %d to pin, using pin anyway... " , ctx - > audio_buffer_size ) ;
}
2012-08-25 08:09:37 +00:00
}
2011-09-09 03:12:42 +00:00
2024-04-25 09:18:18 +00:00
if ( format_set ) {
device_pin = pin ;
av_log ( avctx , AV_LOG_DEBUG , " Selecting pin %s on %s \n " , name_buf , devtypename ) ;
2011-05-21 12:24:50 +00:00
}
next :
if ( p )
IKsPropertySet_Release ( p ) ;
if ( device_pin ! = pin )
IPin_Release ( pin ) ;
2015-01-23 12:34:30 +00:00
av_free ( name_buf ) ;
av_free ( pin_buf ) ;
if ( pin_id )
CoTaskMemFree ( pin_id ) ;
2011-05-21 12:24:50 +00:00
}
2011-09-09 03:10:07 +00:00
IEnumPins_Release ( pins ) ;
2011-09-09 03:15:14 +00:00
if ( ppin ) {
2011-09-09 03:15:22 +00:00
if ( set_format & & ! format_set ) {
av_log ( avctx , AV_LOG_ERROR , " Could not set %s options \n " , devtypename ) ;
return AVERROR ( EIO ) ;
}
if ( ! device_pin ) {
av_log ( avctx , AV_LOG_ERROR ,
" Could not find output pin from %s capture device. \n " , devtypename ) ;
return AVERROR ( EIO ) ;
}
* ppin = device_pin ;
2011-09-09 03:15:14 +00:00
}
return 0 ;
}
/**
2015-01-23 13:54:44 +00:00
* List options for device with type devtype , source filter type sourcetype
2011-09-09 03:15:14 +00:00
*
* @ param devenum device enumerator used for accessing the device
*/
static int
dshow_list_device_options ( AVFormatContext * avctx , ICreateDevEnum * devenum ,
2015-01-23 13:54:44 +00:00
enum dshowDeviceType devtype , enum dshowSourceFilterType sourcetype )
2011-09-09 03:15:14 +00:00
{
2011-09-30 20:50:00 +00:00
struct dshow_ctx * ctx = avctx - > priv_data ;
2011-09-09 03:15:14 +00:00
IBaseFilter * device_filter = NULL ;
2016-06-15 08:17:11 +00:00
char * device_unique_name = NULL ;
2011-09-09 03:15:14 +00:00
int r ;
2024-04-25 09:18:18 +00:00
if ( ( r = dshow_cycle_devices ( avctx , devenum , devtype , sourcetype , & device_filter , & device_unique_name , NULL ) ) < 0 )
2011-09-09 03:15:14 +00:00
return r ;
2011-09-30 20:50:00 +00:00
ctx - > device_filter [ devtype ] = device_filter ;
2024-04-25 09:18:18 +00:00
ctx - > device_unique_name [ devtype ] = device_unique_name ;
2015-01-23 13:54:44 +00:00
if ( ( r = dshow_cycle_pins ( avctx , devtype , sourcetype , device_filter , NULL ) ) < 0 )
2011-09-09 03:15:14 +00:00
return r ;
2011-09-09 03:10:07 +00:00
return 0 ;
}
static int
2015-01-23 13:54:44 +00:00
dshow_open_device ( AVFormatContext * avctx , ICreateDevEnum * devenum ,
enum dshowDeviceType devtype , enum dshowSourceFilterType sourcetype )
2011-09-09 03:10:07 +00:00
{
struct dshow_ctx * ctx = avctx - > priv_data ;
IBaseFilter * device_filter = NULL ;
2016-06-15 08:17:11 +00:00
char * device_filter_unique_name = NULL ;
2011-09-09 03:10:07 +00:00
IGraphBuilder * graph = ctx - > graph ;
IPin * device_pin = NULL ;
2022-05-23 03:23:35 +00:00
DShowPin * capture_pin = NULL ;
DShowFilter * capture_filter = NULL ;
2015-01-23 13:35:16 +00:00
ICaptureGraphBuilder2 * graph_builder2 = NULL ;
2011-09-09 03:10:07 +00:00
int ret = AVERROR ( EIO ) ;
int r ;
2015-04-22 16:38:38 +00:00
IStream * ifile_stream = NULL ;
IStream * ofile_stream = NULL ;
IPersistStream * pers_stream = NULL ;
2016-06-15 08:17:11 +00:00
enum dshowDeviceType otherDevType = ( devtype = = VideoDevice ) ? AudioDevice : VideoDevice ;
2011-09-09 03:10:07 +00:00
const wchar_t * filter_name [ 2 ] = { L " Audio capture filter " , L " Video capture filter " } ;
2015-04-22 16:38:38 +00:00
if ( ( ( ctx - > audio_filter_load_file ) & & ( strlen ( ctx - > audio_filter_load_file ) > 0 ) & & ( sourcetype = = AudioSourceDevice ) ) | |
( ( ctx - > video_filter_load_file ) & & ( strlen ( ctx - > video_filter_load_file ) > 0 ) & & ( sourcetype = = VideoSourceDevice ) ) ) {
HRESULT hr ;
char * filename = NULL ;
if ( sourcetype = = AudioSourceDevice )
filename = ctx - > audio_filter_load_file ;
else
filename = ctx - > video_filter_load_file ;
hr = SHCreateStreamOnFile ( ( LPCSTR ) filename , STGM_READ , & ifile_stream ) ;
if ( S_OK ! = hr ) {
av_log ( avctx , AV_LOG_ERROR , " Could not open capture filter description file. \n " ) ;
goto error ;
}
hr = OleLoadFromStream ( ifile_stream , & IID_IBaseFilter , ( void * * ) & device_filter ) ;
if ( hr ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not load capture filter from file. \n " ) ;
goto error ;
}
if ( sourcetype = = AudioSourceDevice )
av_log ( avctx , AV_LOG_INFO , " Audio- " ) ;
else
av_log ( avctx , AV_LOG_INFO , " Video- " ) ;
av_log ( avctx , AV_LOG_INFO , " Capture filter loaded successfully from file \" %s \" . \n " , filename ) ;
} else {
2024-04-25 09:18:18 +00:00
if ( ( r = dshow_cycle_devices ( avctx , devenum , devtype , sourcetype , & device_filter , & device_filter_unique_name , NULL ) ) < 0 ) {
2015-04-22 16:38:38 +00:00
ret = r ;
goto error ;
}
2011-09-09 03:10:07 +00:00
}
2016-06-15 08:17:11 +00:00
if ( ctx - > device_filter [ otherDevType ] ) {
// avoid adding add two instances of the same device to the graph, one for video, one for audio
// a few devices don't support this (could also do this check earlier to avoid double crossbars, etc. but they seem OK)
if ( strcmp ( device_filter_unique_name , ctx - > device_unique_name [ otherDevType ] ) = = 0 ) {
av_log ( avctx , AV_LOG_DEBUG , " reusing previous graph capture filter... %s \n " , device_filter_unique_name ) ;
IBaseFilter_Release ( device_filter ) ;
device_filter = ctx - > device_filter [ otherDevType ] ;
IBaseFilter_AddRef ( ctx - > device_filter [ otherDevType ] ) ;
} else {
av_log ( avctx , AV_LOG_DEBUG , " not reusing previous graph capture filter %s != %s \n " , device_filter_unique_name , ctx - > device_unique_name [ otherDevType ] ) ;
}
}
2011-09-09 03:10:07 +00:00
ctx - > device_filter [ devtype ] = device_filter ;
2016-06-15 08:17:11 +00:00
ctx - > device_unique_name [ devtype ] = device_filter_unique_name ;
2011-09-09 03:10:07 +00:00
r = IGraphBuilder_AddFilter ( graph , device_filter , NULL ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not add device filter to graph. \n " ) ;
goto error ;
}
2015-01-23 13:54:44 +00:00
if ( ( r = dshow_cycle_pins ( avctx , devtype , sourcetype , device_filter , & device_pin ) ) < 0 ) {
2011-09-09 03:10:07 +00:00
ret = r ;
2011-05-21 12:24:50 +00:00
goto error ;
}
2015-01-23 13:35:16 +00:00
2011-05-21 12:24:50 +00:00
ctx - > device_pin [ devtype ] = device_pin ;
2022-05-23 03:23:35 +00:00
capture_filter = ff_dshow_filter_Create ( avctx , callback , devtype ) ;
2011-05-21 12:24:50 +00:00
if ( ! capture_filter ) {
av_log ( avctx , AV_LOG_ERROR , " Could not create grabber filter. \n " ) ;
goto error ;
}
ctx - > capture_filter [ devtype ] = capture_filter ;
2015-04-22 16:38:38 +00:00
if ( ( ( ctx - > audio_filter_save_file ) & & ( strlen ( ctx - > audio_filter_save_file ) > 0 ) & & ( sourcetype = = AudioSourceDevice ) ) | |
( ( ctx - > video_filter_save_file ) & & ( strlen ( ctx - > video_filter_save_file ) > 0 ) & & ( sourcetype = = VideoSourceDevice ) ) ) {
HRESULT hr ;
char * filename = NULL ;
if ( sourcetype = = AudioSourceDevice )
filename = ctx - > audio_filter_save_file ;
else
filename = ctx - > video_filter_save_file ;
hr = SHCreateStreamOnFile ( ( LPCSTR ) filename , STGM_CREATE | STGM_READWRITE , & ofile_stream ) ;
if ( S_OK ! = hr ) {
av_log ( avctx , AV_LOG_ERROR , " Could not create capture filter description file. \n " ) ;
goto error ;
}
hr = IBaseFilter_QueryInterface ( device_filter , & IID_IPersistStream , ( void * * ) & pers_stream ) ;
if ( hr ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Query for IPersistStream failed. \n " ) ;
goto error ;
}
hr = OleSaveToStream ( pers_stream , ofile_stream ) ;
if ( hr ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not save capture filter \n " ) ;
goto error ;
}
hr = IStream_Commit ( ofile_stream , STGC_DEFAULT ) ;
if ( S_OK ! = hr ) {
av_log ( avctx , AV_LOG_ERROR , " Could not commit capture filter data to file. \n " ) ;
goto error ;
}
if ( sourcetype = = AudioSourceDevice )
av_log ( avctx , AV_LOG_INFO , " Audio- " ) ;
else
av_log ( avctx , AV_LOG_INFO , " Video- " ) ;
av_log ( avctx , AV_LOG_INFO , " Capture filter saved successfully to file \" %s \" . \n " , filename ) ;
}
2011-05-21 12:24:50 +00:00
r = IGraphBuilder_AddFilter ( graph , ( IBaseFilter * ) capture_filter ,
filter_name [ devtype ] ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not add capture filter to graph \n " ) ;
goto error ;
}
2022-05-23 03:23:35 +00:00
ff_dshow_pin_AddRef ( capture_filter - > pin ) ;
2011-05-21 12:24:50 +00:00
capture_pin = capture_filter - > pin ;
ctx - > capture_pin [ devtype ] = capture_pin ;
2015-01-23 13:35:16 +00:00
r = CoCreateInstance ( & CLSID_CaptureGraphBuilder2 , NULL , CLSCTX_INPROC_SERVER ,
& IID_ICaptureGraphBuilder2 , ( void * * ) & graph_builder2 ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not create CaptureGraphBuilder2 \n " ) ;
goto error ;
}
ICaptureGraphBuilder2_SetFiltergraph ( graph_builder2 , graph ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not set graph for CaptureGraphBuilder2 \n " ) ;
goto error ;
}
r = ICaptureGraphBuilder2_RenderStream ( graph_builder2 , NULL , NULL , ( IUnknown * ) device_pin , NULL /* no intermediate filter */ ,
( IBaseFilter * ) capture_filter ) ; /* connect pins, optionally insert intermediate filters like crossbar if necessary */
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not RenderStream to connect pins \n " ) ;
goto error ;
}
2022-05-23 03:23:35 +00:00
r = ff_dshow_try_setup_crossbar_options ( graph_builder2 , device_filter , devtype , avctx ) ;
2015-01-23 13:35:16 +00:00
2011-05-21 12:24:50 +00:00
if ( r ! = S_OK ) {
2015-01-23 13:35:16 +00:00
av_log ( avctx , AV_LOG_ERROR , " Could not setup CrossBar \n " ) ;
2011-05-21 12:24:50 +00:00
goto error ;
}
ret = 0 ;
error :
2015-01-23 13:35:16 +00:00
if ( graph_builder2 ! = NULL )
ICaptureGraphBuilder2_Release ( graph_builder2 ) ;
2015-04-22 16:38:38 +00:00
if ( pers_stream )
IPersistStream_Release ( pers_stream ) ;
if ( ifile_stream )
IStream_Release ( ifile_stream ) ;
if ( ofile_stream )
IStream_Release ( ofile_stream ) ;
2011-05-21 12:24:50 +00:00
return ret ;
}
2012-08-07 21:57:21 +00:00
static enum AVCodecID waveform_codec_id ( enum AVSampleFormat sample_fmt )
2011-05-21 12:24:50 +00:00
{
switch ( sample_fmt ) {
2012-08-07 20:45:46 +00:00
case AV_SAMPLE_FMT_U8 : return AV_CODEC_ID_PCM_U8 ;
case AV_SAMPLE_FMT_S16 : return AV_CODEC_ID_PCM_S16LE ;
case AV_SAMPLE_FMT_S32 : return AV_CODEC_ID_PCM_S32LE ;
default : return AV_CODEC_ID_NONE ; /* Should never happen. */
2011-05-21 12:24:50 +00:00
}
}
2012-01-28 03:23:26 +00:00
static enum AVSampleFormat sample_fmt_bits_per_sample ( int bits )
2011-05-21 12:24:50 +00:00
{
switch ( bits ) {
case 8 : return AV_SAMPLE_FMT_U8 ;
case 16 : return AV_SAMPLE_FMT_S16 ;
case 32 : return AV_SAMPLE_FMT_S32 ;
default : return AV_SAMPLE_FMT_NONE ; /* Should never happen. */
}
}
static int
2012-01-28 03:23:26 +00:00
dshow_add_device ( AVFormatContext * avctx ,
2011-05-21 12:24:50 +00:00
enum dshowDeviceType devtype )
{
struct dshow_ctx * ctx = avctx - > priv_data ;
AM_MEDIA_TYPE type ;
2016-04-10 19:58:15 +00:00
AVCodecParameters * par ;
2011-05-21 12:24:50 +00:00
AVStream * st ;
2024-04-25 09:18:18 +00:00
struct dshow_format_info * fmt_info = NULL ;
2011-05-21 12:24:50 +00:00
int ret = AVERROR ( EIO ) ;
2019-01-03 07:41:12 +00:00
type . pbFormat = NULL ;
2011-11-05 12:11:18 +00:00
st = avformat_new_stream ( avctx , NULL ) ;
2011-05-21 12:24:50 +00:00
if ( ! st ) {
ret = AVERROR ( ENOMEM ) ;
goto error ;
}
2011-11-05 12:11:18 +00:00
st - > id = devtype ;
2011-05-21 12:24:50 +00:00
ctx - > capture_filter [ devtype ] - > stream_index = st - > index ;
2022-05-23 03:23:35 +00:00
ff_dshow_pin_ConnectionMediaType ( ctx - > capture_pin [ devtype ] , & type ) ;
2024-04-25 09:18:18 +00:00
fmt_info = dshow_get_format_info ( & type ) ;
if ( ! fmt_info ) {
ret = AVERROR ( EIO ) ;
goto error ;
}
2011-05-21 12:24:50 +00:00
2016-04-10 19:58:15 +00:00
par = st - > codecpar ;
2011-05-21 12:24:50 +00:00
if ( devtype = = VideoDevice ) {
BITMAPINFOHEADER * bih = NULL ;
2012-02-03 16:55:20 +00:00
AVRational time_base ;
2011-05-21 12:24:50 +00:00
if ( IsEqualGUID ( & type . formattype , & FORMAT_VideoInfo ) ) {
VIDEOINFOHEADER * v = ( void * ) type . pbFormat ;
2012-02-03 16:55:20 +00:00
time_base = ( AVRational ) { v - > AvgTimePerFrame , 10000000 } ;
2011-05-21 12:24:50 +00:00
bih = & v - > bmiHeader ;
} else if ( IsEqualGUID ( & type . formattype , & FORMAT_VideoInfo2 ) ) {
VIDEOINFOHEADER2 * v = ( void * ) type . pbFormat ;
2012-02-03 16:55:20 +00:00
time_base = ( AVRational ) { v - > AvgTimePerFrame , 10000000 } ;
2011-05-21 12:24:50 +00:00
bih = & v - > bmiHeader ;
}
if ( ! bih ) {
av_log ( avctx , AV_LOG_ERROR , " Could not get media type. \n " ) ;
goto error ;
}
2016-04-10 19:58:15 +00:00
st - > avg_frame_rate = av_inv_q ( time_base ) ;
2016-06-07 00:32:13 +00:00
st - > r_frame_rate = av_inv_q ( time_base ) ;
2016-04-10 19:58:15 +00:00
par - > codec_type = AVMEDIA_TYPE_VIDEO ;
2024-04-25 09:18:18 +00:00
par - > width = fmt_info - > width ;
par - > height = fmt_info - > height ;
2016-04-10 19:58:15 +00:00
par - > codec_tag = bih - > biCompression ;
2024-04-25 09:18:18 +00:00
par - > format = fmt_info - > pix_fmt ;
2013-03-19 20:25:49 +00:00
if ( bih - > biCompression = = MKTAG ( ' H ' , ' D ' , ' Y ' , ' C ' ) ) {
av_log ( avctx , AV_LOG_DEBUG , " attempt to use full range for HDYC... \n " ) ;
2016-04-10 19:58:15 +00:00
par - > color_range = AVCOL_RANGE_MPEG ; // just in case it needs this...
2013-01-16 01:37:30 +00:00
}
2024-04-25 09:18:18 +00:00
par - > color_range = fmt_info - > col_range ;
par - > color_space = fmt_info - > col_space ;
par - > color_primaries = fmt_info - > col_prim ;
par - > color_trc = fmt_info - > col_trc ;
par - > chroma_location = fmt_info - > chroma_loc ;
par - > codec_id = fmt_info - > codec_id ;
if ( par - > codec_id = = AV_CODEC_ID_RAWVIDEO ) {
2011-10-08 18:00:00 +00:00
if ( bih - > biCompression = = BI_RGB | | bih - > biCompression = = BI_BITFIELDS ) {
2016-04-10 19:58:15 +00:00
par - > bits_per_coded_sample = bih - > biBitCount ;
2018-09-17 22:16:42 +00:00
if ( par - > height < 0 ) {
par - > height * = - 1 ;
} else {
2018-09-19 16:14:40 +00:00
par - > extradata = av_malloc ( 9 + AV_INPUT_BUFFER_PADDING_SIZE ) ;
if ( par - > extradata ) {
par - > extradata_size = 9 ;
memcpy ( par - > extradata , " BottomUp " , 9 ) ;
}
2018-09-17 22:16:42 +00:00
}
2011-05-21 12:24:50 +00:00
}
2024-04-25 09:18:18 +00:00
} else {
if ( par - > codec_id = = AV_CODEC_ID_NONE ) {
av_log ( avctx , AV_LOG_ERROR , " Unknown compression type. "
" Please report type 0x%X. \n " , ( int ) bih - > biCompression ) ;
ret = AVERROR_PATCHWELCOME ;
goto error ;
}
par - > bits_per_coded_sample = bih - > biBitCount ;
2011-05-21 12:24:50 +00:00
}
} else {
2024-04-25 09:18:18 +00:00
if ( ! IsEqualGUID ( & type . formattype , & FORMAT_WaveFormatEx ) ) {
2011-05-21 12:24:50 +00:00
av_log ( avctx , AV_LOG_ERROR , " Could not get media type. \n " ) ;
goto error ;
}
2016-04-10 19:58:15 +00:00
par - > codec_type = AVMEDIA_TYPE_AUDIO ;
2024-04-25 09:18:18 +00:00
par - > format = sample_fmt_bits_per_sample ( fmt_info - > sample_size ) ;
2016-04-10 19:58:15 +00:00
par - > codec_id = waveform_codec_id ( par - > format ) ;
2024-04-25 09:18:18 +00:00
par - > sample_rate = fmt_info - > sample_rate ;
par - > ch_layout . nb_channels = fmt_info - > channels ;
2011-05-21 12:24:50 +00:00
}
2011-12-02 23:45:46 +00:00
avpriv_set_pts_info ( st , 64 , 1 , 10000000 ) ;
2011-05-21 12:24:50 +00:00
ret = 0 ;
error :
2024-04-25 09:18:18 +00:00
av_freep ( & fmt_info ) ;
2019-01-03 07:41:12 +00:00
if ( type . pbFormat )
CoTaskMemFree ( type . pbFormat ) ;
2011-05-21 12:24:50 +00:00
return ret ;
}
static int parse_device_name ( AVFormatContext * avctx )
{
struct dshow_ctx * ctx = avctx - > priv_data ;
char * * device_name = ctx - > device_name ;
2017-12-29 22:29:52 +00:00
char * name = av_strdup ( avctx - > url ) ;
2011-05-21 12:24:50 +00:00
char * tmp = name ;
int ret = 1 ;
char * type ;
while ( ( type = strtok ( tmp , " = " ) ) ) {
char * token = strtok ( NULL , " : " ) ;
tmp = NULL ;
if ( ! strcmp ( type , " video " ) ) {
device_name [ 0 ] = token ;
} else if ( ! strcmp ( type , " audio " ) ) {
device_name [ 1 ] = token ;
} else {
device_name [ 0 ] = NULL ;
device_name [ 1 ] = NULL ;
break ;
}
}
if ( ! device_name [ 0 ] & & ! device_name [ 1 ] ) {
ret = 0 ;
} else {
if ( device_name [ 0 ] )
device_name [ 0 ] = av_strdup ( device_name [ 0 ] ) ;
if ( device_name [ 1 ] )
device_name [ 1 ] = av_strdup ( device_name [ 1 ] ) ;
}
av_free ( name ) ;
return ret ;
}
2012-01-28 03:23:26 +00:00
static int dshow_read_header ( AVFormatContext * avctx )
2011-05-21 12:24:50 +00:00
{
struct dshow_ctx * ctx = avctx - > priv_data ;
IGraphBuilder * graph = NULL ;
ICreateDevEnum * devenum = NULL ;
IMediaControl * control = NULL ;
2012-12-17 05:44:12 +00:00
IMediaEvent * media_event = NULL ;
HANDLE media_event_handle ;
HANDLE proc ;
2011-05-21 12:24:50 +00:00
int ret = AVERROR ( EIO ) ;
int r ;
2012-12-17 05:44:51 +00:00
CoInitialize ( 0 ) ;
2011-09-09 03:09:23 +00:00
if ( ! ctx - > list_devices & & ! parse_device_name ( avctx ) ) {
2011-05-21 12:24:50 +00:00
av_log ( avctx , AV_LOG_ERROR , " Malformed dshow input string. \n " ) ;
goto error ;
}
2012-09-06 23:41:19 +00:00
ctx - > video_codec_id = avctx - > video_codec_id ? avctx - > video_codec_id
: AV_CODEC_ID_RAWVIDEO ;
2012-10-08 18:54:00 +00:00
if ( ctx - > pixel_format ! = AV_PIX_FMT_NONE ) {
2012-09-06 23:41:19 +00:00
if ( ctx - > video_codec_id ! = AV_CODEC_ID_RAWVIDEO ) {
av_log ( avctx , AV_LOG_ERROR , " Pixel format may only be set when "
" video codec is not set or set to rawvideo \n " ) ;
ret = AVERROR ( EINVAL ) ;
goto error ;
}
}
2011-09-09 03:12:42 +00:00
if ( ctx - > framerate ) {
r = av_parse_video_rate ( & ctx - > requested_framerate , ctx - > framerate ) ;
if ( r < 0 ) {
av_log ( avctx , AV_LOG_ERROR , " Could not parse framerate '%s'. \n " , ctx - > framerate ) ;
goto error ;
}
}
2011-05-21 12:24:50 +00:00
r = CoCreateInstance ( & CLSID_FilterGraph , NULL , CLSCTX_INPROC_SERVER ,
& IID_IGraphBuilder , ( void * * ) & graph ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not create capture graph. \n " ) ;
goto error ;
}
ctx - > graph = graph ;
r = CoCreateInstance ( & CLSID_SystemDeviceEnum , NULL , CLSCTX_INPROC_SERVER ,
& IID_ICreateDevEnum , ( void * * ) & devenum ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not enumerate system devices. \n " ) ;
goto error ;
}
2011-09-09 03:09:23 +00:00
if ( ctx - > list_devices ) {
2024-04-25 09:18:18 +00:00
dshow_cycle_devices ( avctx , devenum , VideoDevice , VideoSourceDevice , NULL , NULL , NULL ) ;
dshow_cycle_devices ( avctx , devenum , AudioDevice , AudioSourceDevice , NULL , NULL , NULL ) ;
2011-09-09 03:09:23 +00:00
ret = AVERROR_EXIT ;
goto error ;
}
2011-09-09 03:15:14 +00:00
if ( ctx - > list_options ) {
if ( ctx - > device_name [ VideoDevice ] )
2015-01-23 13:54:44 +00:00
if ( ( r = dshow_list_device_options ( avctx , devenum , VideoDevice , VideoSourceDevice ) ) ) {
2015-01-23 13:35:16 +00:00
ret = r ;
goto error ;
}
2015-01-23 13:54:44 +00:00
if ( ctx - > device_name [ AudioDevice ] ) {
if ( dshow_list_device_options ( avctx , devenum , AudioDevice , AudioSourceDevice ) ) {
/* show audio options from combined video+audio sources as fallback */
if ( ( r = dshow_list_device_options ( avctx , devenum , AudioDevice , VideoSourceDevice ) ) ) {
ret = r ;
goto error ;
}
2015-01-23 13:35:16 +00:00
}
2015-01-23 13:54:44 +00:00
}
2024-04-25 09:18:18 +00:00
// don't exit yet, allow it to list crossbar options in dshow_open_device
2011-09-09 03:15:14 +00:00
}
2011-05-21 12:24:50 +00:00
if ( ctx - > device_name [ VideoDevice ] ) {
2015-01-23 13:54:44 +00:00
if ( ( r = dshow_open_device ( avctx , devenum , VideoDevice , VideoSourceDevice ) ) < 0 | |
2012-12-06 04:32:47 +00:00
( r = dshow_add_device ( avctx , VideoDevice ) ) < 0 ) {
ret = r ;
2011-05-21 12:24:50 +00:00
goto error ;
2012-12-06 04:32:47 +00:00
}
2011-05-21 12:24:50 +00:00
}
if ( ctx - > device_name [ AudioDevice ] ) {
2015-01-23 13:54:44 +00:00
if ( ( r = dshow_open_device ( avctx , devenum , AudioDevice , AudioSourceDevice ) ) < 0 | |
2012-12-06 04:32:47 +00:00
( r = dshow_add_device ( avctx , AudioDevice ) ) < 0 ) {
2015-01-26 09:03:48 +00:00
av_log ( avctx , AV_LOG_INFO , " Searching for audio device within video devices for %s \n " , ctx - > device_name [ AudioDevice ] ) ;
2015-01-23 13:54:44 +00:00
/* see if there's a video source with an audio pin with the given audio name */
if ( ( r = dshow_open_device ( avctx , devenum , AudioDevice , VideoSourceDevice ) ) < 0 | |
( r = dshow_add_device ( avctx , AudioDevice ) ) < 0 ) {
ret = r ;
goto error ;
}
2012-12-06 04:32:47 +00:00
}
2011-05-21 12:24:50 +00:00
}
2015-01-23 13:35:16 +00:00
if ( ctx - > list_options ) {
/* allow it to list crossbar options in dshow_open_device */
ret = AVERROR_EXIT ;
goto error ;
}
2014-03-21 22:27:01 +00:00
ctx - > curbufsize [ 0 ] = 0 ;
ctx - > curbufsize [ 1 ] = 0 ;
2011-05-21 12:24:50 +00:00
ctx - > mutex = CreateMutex ( NULL , 0 , NULL ) ;
if ( ! ctx - > mutex ) {
av_log ( avctx , AV_LOG_ERROR , " Could not create Mutex \n " ) ;
goto error ;
}
2012-12-17 05:44:12 +00:00
ctx - > event [ 1 ] = CreateEvent ( NULL , 1 , 0 , NULL ) ;
if ( ! ctx - > event [ 1 ] ) {
2011-05-21 12:24:50 +00:00
av_log ( avctx , AV_LOG_ERROR , " Could not create Event \n " ) ;
goto error ;
}
r = IGraphBuilder_QueryInterface ( graph , & IID_IMediaControl , ( void * * ) & control ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not get media control. \n " ) ;
goto error ;
}
ctx - > control = control ;
2012-12-17 05:44:12 +00:00
r = IGraphBuilder_QueryInterface ( graph , & IID_IMediaEvent , ( void * * ) & media_event ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not get media event. \n " ) ;
goto error ;
}
ctx - > media_event = media_event ;
r = IMediaEvent_GetEventHandle ( media_event , ( void * ) & media_event_handle ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not get media event handle. \n " ) ;
goto error ;
}
proc = GetCurrentProcess ( ) ;
r = DuplicateHandle ( proc , media_event_handle , proc , & ctx - > event [ 0 ] ,
0 , 0 , DUPLICATE_SAME_ACCESS ) ;
if ( ! r ) {
av_log ( avctx , AV_LOG_ERROR , " Could not duplicate media event handle. \n " ) ;
goto error ;
}
2011-05-21 12:24:50 +00:00
r = IMediaControl_Run ( control ) ;
if ( r = = S_FALSE ) {
OAFilterState pfs ;
r = IMediaControl_GetState ( control , 0 , & pfs ) ;
}
if ( r ! = S_OK ) {
2015-01-26 09:03:48 +00:00
av_log ( avctx , AV_LOG_ERROR , " Could not run graph (sometimes caused by a device already in use by other application) \n " ) ;
2011-05-21 12:24:50 +00:00
goto error ;
}
ret = 0 ;
error :
if ( devenum )
ICreateDevEnum_Release ( devenum ) ;
2012-12-17 05:44:51 +00:00
if ( ret < 0 )
dshow_read_close ( avctx ) ;
2011-05-21 12:24:50 +00:00
return ret ;
}
2012-12-17 05:44:12 +00:00
/**
* Checks media events from DirectShow and returns - 1 on error or EOF . Also
* purges all events that might be in the event queue to stop the trigger
* of event notification .
*/
static int dshow_check_event_queue ( IMediaEvent * media_event )
{
LONG_PTR p1 , p2 ;
long code ;
int ret = 0 ;
while ( IMediaEvent_GetEvent ( media_event , & code , & p1 , & p2 , 0 ) ! = E_ABORT ) {
if ( code = = EC_COMPLETE | | code = = EC_DEVICE_LOST | | code = = EC_ERRORABORT )
ret = - 1 ;
IMediaEvent_FreeEventParams ( media_event , code , p1 , p2 ) ;
}
return ret ;
}
2011-05-21 12:24:50 +00:00
static int dshow_read_packet ( AVFormatContext * s , AVPacket * pkt )
{
struct dshow_ctx * ctx = s - > priv_data ;
2024-04-25 09:18:18 +00:00
PacketListEntry * pktl = NULL ;
2011-05-21 12:24:50 +00:00
2012-12-17 05:44:12 +00:00
while ( ! ctx - > eof & & ! pktl ) {
2011-05-21 12:24:50 +00:00
WaitForSingleObject ( ctx - > mutex , INFINITE ) ;
pktl = ctx - > pktl ;
2012-08-16 16:42:46 +00:00
if ( pktl ) {
* pkt = pktl - > pkt ;
2011-05-21 12:24:50 +00:00
ctx - > pktl = ctx - > pktl - > next ;
av_free ( pktl ) ;
2014-03-21 22:27:01 +00:00
ctx - > curbufsize [ pkt - > stream_index ] - = pkt - > size ;
2011-05-21 12:24:50 +00:00
}
2012-12-17 05:44:12 +00:00
ResetEvent ( ctx - > event [ 1 ] ) ;
2011-05-21 12:24:50 +00:00
ReleaseMutex ( ctx - > mutex ) ;
if ( ! pktl ) {
2012-12-17 05:44:12 +00:00
if ( dshow_check_event_queue ( ctx - > media_event ) < 0 ) {
ctx - > eof = 1 ;
} else if ( s - > flags & AVFMT_FLAG_NONBLOCK ) {
2011-05-21 12:24:50 +00:00
return AVERROR ( EAGAIN ) ;
} else {
2012-12-17 05:44:12 +00:00
WaitForMultipleObjects ( 2 , ctx - > event , 0 , INFINITE ) ;
2011-05-21 12:24:50 +00:00
}
}
}
2012-12-17 05:44:12 +00:00
return ctx - > eof ? AVERROR ( EIO ) : pkt - > size ;
2011-05-21 12:24:50 +00:00
}
2011-09-09 03:09:23 +00:00
# define OFFSET(x) offsetof(struct dshow_ctx, x)
# define DEC AV_OPT_FLAG_DECODING_PARAM
static const AVOption options [ ] = {
2012-09-06 23:50:06 +00:00
{ " video_size " , " set video size given a string such as 640x480 or hd720. " , OFFSET ( requested_width ) , AV_OPT_TYPE_IMAGE_SIZE , { . str = NULL } , 0 , 0 , DEC } ,
2013-12-16 15:11:49 +00:00
{ " pixel_format " , " set video pixel format " , OFFSET ( pixel_format ) , AV_OPT_TYPE_PIXEL_FMT , { . i64 = AV_PIX_FMT_NONE } , - 1 , INT_MAX , DEC } ,
2011-10-17 05:33:10 +00:00
{ " framerate " , " set video frame rate " , OFFSET ( framerate ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , 0 , DEC } ,
2012-09-05 12:26:01 +00:00
{ " 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 } ,
2015-01-23 12:34:30 +00:00
{ " 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 } ,
2015-09-06 17:23:08 +00:00
{ " list_devices " , " list available devices " , OFFSET ( list_devices ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , DEC } ,
{ " list_options " , " list available options for specified device " , OFFSET ( list_options ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , DEC } ,
2012-09-05 12:26:01 +00:00
{ " 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 } ,
2015-01-23 12:34:30 +00:00
{ " 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 } ,
2015-01-23 13:35:16 +00:00
{ " crossbar_video_input_pin_number " , " set video input pin number for crossbar device " , OFFSET ( crossbar_video_input_pin_number ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , DEC } ,
{ " crossbar_audio_input_pin_number " , " set audio input pin number for crossbar device " , OFFSET ( crossbar_audio_input_pin_number ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , DEC } ,
2015-09-06 17:23:08 +00:00
{ " show_video_device_dialog " , " display property dialog for video capture device " , OFFSET ( show_video_device_dialog ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , DEC } ,
{ " show_audio_device_dialog " , " display property dialog for audio capture device " , OFFSET ( show_audio_device_dialog ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , DEC } ,
{ " show_video_crossbar_connection_dialog " , " display property dialog for crossbar connecting pins filter on video device " , OFFSET ( show_video_crossbar_connection_dialog ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , DEC } ,
{ " show_audio_crossbar_connection_dialog " , " display property dialog for crossbar connecting pins filter on audio device " , OFFSET ( show_audio_crossbar_connection_dialog ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , DEC } ,
{ " show_analog_tv_tuner_dialog " , " display property dialog for analog tuner filter " , OFFSET ( show_analog_tv_tuner_dialog ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , DEC } ,
{ " show_analog_tv_tuner_audio_dialog " , " display property dialog for analog tuner audio filter " , OFFSET ( show_analog_tv_tuner_audio_dialog ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , DEC } ,
2015-04-22 16:38:38 +00:00
{ " audio_device_load " , " load audio capture filter device (and properties) from file " , OFFSET ( audio_filter_load_file ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , 0 , DEC } ,
{ " audio_device_save " , " save audio capture filter device (and properties) to file " , OFFSET ( audio_filter_save_file ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , 0 , DEC } ,
{ " video_device_load " , " load video capture filter device (and properties) from file " , OFFSET ( video_filter_load_file ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , 0 , DEC } ,
{ " video_device_save " , " save video capture filter device (and properties) to file " , OFFSET ( video_filter_save_file ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , 0 , DEC } ,
2024-04-25 09:18:18 +00:00
{ " use_video_device_timestamps " , " use device instead of wallclock timestamps for video frames " , OFFSET ( use_video_device_timestamps ) , AV_OPT_TYPE_BOOL , { . i64 = 1 } , 0 , 1 , DEC } ,
2011-09-09 03:09:23 +00:00
{ NULL } ,
} ;
static const AVClass dshow_class = {
2012-12-13 20:33:59 +00:00
. class_name = " dshow indev " ,
2011-09-09 03:09:23 +00:00
. item_name = av_default_item_name ,
. option = options ,
. version = LIBAVUTIL_VERSION_INT ,
2014-02-22 22:32:51 +00:00
. category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT ,
2011-09-09 03:09:23 +00:00
} ;
2024-04-25 09:18:18 +00:00
const AVInputFormat ff_dshow_demuxer = {
2012-02-03 16:50:19 +00:00
. name = " dshow " ,
. long_name = NULL_IF_CONFIG_SMALL ( " DirectShow capture " ) ,
. priv_data_size = sizeof ( struct dshow_ctx ) ,
. read_header = dshow_read_header ,
. read_packet = dshow_read_packet ,
. read_close = dshow_read_close ,
2024-04-25 09:18:18 +00:00
. get_device_list = dshow_get_device_list ,
. flags = AVFMT_NOFILE | AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK ,
2012-02-03 16:50:19 +00:00
. priv_class = & dshow_class ,
2011-05-21 12:24:50 +00:00
} ;