synchronization, improve capture device support.
here how to use it to display a capture device:
osg::Options* options = new osg::Options;
options->setPluginStringData("captureWantedWidth", "800");
options->setPluginStringData("captureWantedHeight", "600");
options->setPluginStringData("captureWantedFps", "30");
options->setPluginStringData("captureVideoDevice", "USB Video Device" );
options->setPluginStringData("captureSoundDevice", "");
then
osgDB::readImageFile("capture.directshow", options)
you can use a graphedit application to list devices available in
directshow.
for classic avi file you just need to do a
osgDB::readImageFile("file.avi.directshow");
You will need of course to install the codec needed by directshow to
read the avi files.
I recommand this tool http://avicodec.duby.info/, that check which
video/sound codec is needed to play an avi file.
You can test it with the osgmovie example.
"
1873 lines
71 KiB
C++
1873 lines
71 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) 2009 Tharsis Software
|
|
*
|
|
* This library is open source and may be redistributed and/or modified under
|
|
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
|
* (at your option) any later version. The full license is in LICENSE file
|
|
* included with this distribution, and on the openscenegraph.org website.
|
|
*
|
|
* This library 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
|
|
* OpenSceneGraph Public License for more details.
|
|
*
|
|
* Authors:
|
|
* Cedric Pinson <cedric.pinson@plopbyte.net>
|
|
*/
|
|
|
|
#include "DirectShowTexture"
|
|
#include <osg/notify>
|
|
#include <osgDB/WriteFile>
|
|
#include <sstream>
|
|
#include <windows.h>
|
|
#include <mmsystem.h>
|
|
#include <comdef.h>
|
|
|
|
#include <strsafe.h>
|
|
#include <functional>
|
|
#include <locale>
|
|
#include <string>
|
|
|
|
HRESULT GetPin(IBaseFilter* pFilter, LPCWSTR pName, IPin** ppPin);
|
|
HRESULT GetPin(IBaseFilter* pFilter, const GUID* pFormat, PIN_DIRECTION PinDir, IPin** ppPin);
|
|
|
|
|
|
struct NamedGuid
|
|
{
|
|
const GUID *pguid;
|
|
const TCHAR *psz;
|
|
};
|
|
|
|
// 73646976-0000-0010-8000-00AA00389B71 'vids' == WMMEDIATYPE_Video
|
|
EXTERN_GUID(WMMEDIATYPE_Video,
|
|
0x73646976, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
|
|
// 73647561-0000-0010-8000-00AA00389B71 'auds' == WMMEDIATYPE_Audio
|
|
EXTERN_GUID(WMMEDIATYPE_Audio,
|
|
0x73647561, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
|
|
// 73636d64-0000-0010-8000-00AA00389B71 'scmd' == MEDIATYPE_Script
|
|
EXTERN_GUID(WMMEDIATYPE_Script,
|
|
0x73636d64, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
|
|
// 34A50FD8-8AA5-4386-81FE-A0EFE0488E31 WMMEDIATYPE_Image
|
|
EXTERN_GUID(WMMEDIATYPE_Image,
|
|
0x34a50fd8, 0x8aa5, 0x4386, 0x81, 0xfe, 0xa0, 0xef, 0xe0, 0x48, 0x8e, 0x31);
|
|
// D9E47579-930E-4427-ADFC-AD80F290E470 'fxfr' == WMMEDIATYPE_FileTransfer
|
|
EXTERN_GUID(WMMEDIATYPE_FileTransfer,
|
|
0xd9e47579, 0x930e, 0x4427, 0xad, 0xfc, 0xad, 0x80, 0xf2, 0x90, 0xe4, 0x70);
|
|
// 9BBA1EA7-5AB2-4829-BA57-0940209BCF3E 'text' == WMMEDIATYPE_Text
|
|
EXTERN_GUID(WMMEDIATYPE_Text,
|
|
0x9bba1ea7, 0x5ab2, 0x4829, 0xba, 0x57, 0x9, 0x40, 0x20, 0x9b, 0xcf, 0x3e);
|
|
|
|
// 00000000-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_Base
|
|
EXTERN_GUID(WMMEDIASUBTYPE_Base,
|
|
0x00000000, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// e436eb78-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB1
|
|
EXTERN_GUID(WMMEDIASUBTYPE_RGB1,
|
|
0xe436eb78, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
|
|
// e436eb79-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB4
|
|
EXTERN_GUID(WMMEDIASUBTYPE_RGB4,
|
|
0xe436eb79, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
|
|
// e436eb7a-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB8
|
|
EXTERN_GUID(WMMEDIASUBTYPE_RGB8,
|
|
0xe436eb7a, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
|
|
// e436eb7b-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB565
|
|
EXTERN_GUID(WMMEDIASUBTYPE_RGB565,
|
|
0xe436eb7b, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
|
|
// e436eb7c-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB555
|
|
EXTERN_GUID(WMMEDIASUBTYPE_RGB555,
|
|
0xe436eb7c, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
|
|
// e436eb7d-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB24
|
|
EXTERN_GUID(WMMEDIASUBTYPE_RGB24,
|
|
0xe436eb7d, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
|
|
// e436eb7e-524f-11ce-9f53-0020af0ba770 MEDIASUBTYPE_RGB32
|
|
EXTERN_GUID(WMMEDIASUBTYPE_RGB32,
|
|
0xe436eb7e, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
|
|
// 30323449-0000-0010-8000-00AA00389B71 'YV12' == MEDIASUBTYPE_I420
|
|
EXTERN_GUID(WMMEDIASUBTYPE_I420,
|
|
0x30323449, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
|
|
// 56555949-0000-0010-8000-00AA00389B71 'YV12' == MEDIASUBTYPE_IYUV
|
|
EXTERN_GUID(WMMEDIASUBTYPE_IYUV,
|
|
0x56555949, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
|
|
// 31313259-0000-0010-8000-00AA00389B71 'YV12' == MEDIASUBTYPE_YV12
|
|
EXTERN_GUID(WMMEDIASUBTYPE_YV12,
|
|
0x32315659, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
|
|
// 32595559-0000-0010-8000-00AA00389B71 'YUY2' == MEDIASUBTYPE_YUY2
|
|
EXTERN_GUID(WMMEDIASUBTYPE_YUY2,
|
|
0x32595559, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
|
|
// 59565955-0000-0010-8000-00AA00389B71 'UYVY' == MEDIASUBTYPE_UYVY
|
|
EXTERN_GUID(WMMEDIASUBTYPE_UYVY,
|
|
0x59565955, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
|
|
// 55595659-0000-0010-8000-00AA00389B71 'YVYU' == MEDIASUBTYPE_YVYU
|
|
EXTERN_GUID(WMMEDIASUBTYPE_YVYU,
|
|
0x55595659, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
|
|
// 39555659-0000-0010-8000-00AA00389B71 'YVU9' == MEDIASUBTYPE_YVU9
|
|
EXTERN_GUID(WMMEDIASUBTYPE_YVU9,
|
|
0x39555659, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
|
|
// 3334504D-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_MP43
|
|
EXTERN_GUID(WMMEDIASUBTYPE_MP43,
|
|
0x3334504D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 5334504D-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_MP4S
|
|
EXTERN_GUID(WMMEDIASUBTYPE_MP4S,
|
|
0x5334504D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 31564D57-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMV1
|
|
EXTERN_GUID(WMMEDIASUBTYPE_WMV1,
|
|
0x31564D57, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 32564D57-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMV2
|
|
EXTERN_GUID(WMMEDIASUBTYPE_WMV2,
|
|
0x32564D57, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 3153534D-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_MSS1
|
|
EXTERN_GUID(WMMEDIASUBTYPE_MSS1,
|
|
0x3153534D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// e06d8026-db46-11cf-b4d1-00805f6cbbea WMMEDIASUBTYPE_MPEG2_VIDEO
|
|
EXTERN_GUID(WMMEDIASUBTYPE_MPEG2_VIDEO,
|
|
0xe06d8026, 0xdb46, 0x11cf, 0xb4, 0xd1, 0x00, 0x80, 0x5f, 0x6c, 0xbb, 0xea);
|
|
// 00000001-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_PCM
|
|
EXTERN_GUID(WMMEDIASUBTYPE_PCM,
|
|
0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 00000009-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_DRM
|
|
EXTERN_GUID(WMMEDIASUBTYPE_DRM,
|
|
0x00000009, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 00000162-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMAudioV9
|
|
EXTERN_GUID(WMMEDIASUBTYPE_WMAudioV9,
|
|
0x00000162, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 00000163-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMAudio_Lossless
|
|
EXTERN_GUID(WMMEDIASUBTYPE_WMAudio_Lossless,
|
|
0x00000163, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 3253534D-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_MSS2
|
|
EXTERN_GUID(WMMEDIASUBTYPE_MSS2,
|
|
0x3253534D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 0000000A-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMSP1
|
|
EXTERN_GUID( WMMEDIASUBTYPE_WMSP1,
|
|
0x0000000A,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71);
|
|
// 33564D57-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMV3
|
|
EXTERN_GUID(WMMEDIASUBTYPE_WMV3,
|
|
0x33564D57, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 00000161-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMAudioV8
|
|
EXTERN_GUID(WMMEDIASUBTYPE_WMAudioV8,
|
|
0x00000161, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 00000161-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMAudioV7
|
|
EXTERN_GUID(WMMEDIASUBTYPE_WMAudioV7,
|
|
0x00000161, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 00000161-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_WMAudioV2
|
|
EXTERN_GUID(WMMEDIASUBTYPE_WMAudioV2,
|
|
0x00000161, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 00000130-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_ACELPnet
|
|
EXTERN_GUID(WMMEDIASUBTYPE_ACELPnet,
|
|
0x00000130, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 00000050-0000-0010-8000-00AA00389B71 WMMEDIASUBTYPE_MP3
|
|
EXTERN_GUID(WMMEDIASUBTYPE_MP3,
|
|
0x00000055, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
|
// 776257d4-c627-41cb-8f81-7ac7ff1c40cc WMMEDIASUBTYPE_WebStream
|
|
EXTERN_GUID(WMMEDIASUBTYPE_WebStream,
|
|
0x776257d4, 0xc627, 0x41cb, 0x8f, 0x81, 0x7a, 0xc7, 0xff, 0x1c, 0x40, 0xcc);
|
|
|
|
// 05589f80-c356-11ce-bf01-00aa0055595a WMFORMAT_VideoInfo
|
|
EXTERN_GUID(WMFORMAT_VideoInfo,
|
|
0x05589f80, 0xc356, 0x11ce, 0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a);
|
|
// 05589f81-c356-11ce-bf01-00aa0055595a WMFORMAT_WaveFormatEx
|
|
EXTERN_GUID(WMFORMAT_WaveFormatEx,
|
|
0x05589f81, 0xc356, 0x11ce, 0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a);
|
|
// 5C8510F2-DEBE-4ca7-BBA5-F07A104F8DFF WMFORMAT_Script
|
|
EXTERN_GUID(WMFORMAT_Script,
|
|
0x5c8510f2, 0xdebe, 0x4ca7, 0xbb, 0xa5, 0xf0, 0x7a, 0x10, 0x4f, 0x8d, 0xff);
|
|
|
|
// 82f38a70-c29f-11d1-97ad-00a0c95ea850 WMSCRIPTTYPE_TwoStrings
|
|
EXTERN_GUID( WMSCRIPTTYPE_TwoStrings,
|
|
0x82f38a70,0xc29f,0x11d1,0x97,0xad,0x00,0xa0,0xc9,0x5e,0xa8,0x50);
|
|
|
|
// e06d80e3-db46-11cf-b4d1-00805f6cbbea WMFORMAT_MPEG2Video
|
|
EXTERN_GUID(WMFORMAT_MPEG2Video,
|
|
0xe06d80e3, 0xdb46, 0x11cf, 0xb4, 0xd1, 0x00, 0x80, 0x05f, 0x6c, 0xbb, 0xea);
|
|
|
|
EXTERN_GUID( CLSID_WMMUTEX_Language, 0xD6E22A00,0x35DA,0x11D1,0x90,0x34,0x00,0xA0,0xC9,0x03,0x49,0xBE );
|
|
EXTERN_GUID( CLSID_WMMUTEX_Bitrate, 0xD6E22A01,0x35DA,0x11D1,0x90,0x34,0x00,0xA0,0xC9,0x03,0x49,0xBE );
|
|
EXTERN_GUID( CLSID_WMMUTEX_Presentation, 0xD6E22A02,0x35DA,0x11D1,0x90,0x34,0x00,0xA0,0xC9,0x03,0x49,0xBE );
|
|
EXTERN_GUID( CLSID_WMMUTEX_Unknown, 0xD6E22A03,0x35DA,0x11D1,0x90,0x34,0x00,0xA0,0xC9,0x03,0x49,0xBE );
|
|
EXTERN_GUID( CLSID_WMBandwidthSharing_Exclusive, 0xaf6060aa,0x5197,0x11d2,0xb6,0xaf,0x00,0xc0,0x4f,0xd9,0x08,0xe9 );
|
|
EXTERN_GUID( CLSID_WMBandwidthSharing_Partial, 0xaf6060ab,0x5197,0x11d2,0xb6,0xaf,0x00,0xc0,0x4f,0xd9,0x08,0xe9 );
|
|
|
|
const NamedGuid MediaType[]=
|
|
{
|
|
{&MEDIASUBTYPE_AIFF, TEXT("AIFF\0")},
|
|
{&MEDIASUBTYPE_AU, TEXT("AU\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_NTSC_M, TEXT("AnalogVideo_NTSC_M\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_PAL_B, TEXT("AnalogVideo_PAL_B\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_PAL_D, TEXT("AnalogVideo_PAL_D\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_PAL_G, TEXT("AnalogVideo_PAL_G\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_PAL_H, TEXT("AnalogVideo_PAL_H\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_PAL_I, TEXT("AnalogVideo_PAL_I\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_PAL_M, TEXT("AnalogVideo_PAL_M\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_PAL_N, TEXT("AnalogVideo_PAL_N\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_SECAM_B, TEXT("AnalogVideo_SECAM_B\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_SECAM_D, TEXT("AnalogVideo_SECAM_D\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_SECAM_G, TEXT("AnalogVideo_SECAM_G\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_SECAM_H, TEXT("AnalogVideo_SECAM_H\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_SECAM_K, TEXT("AnalogVideo_SECAM_K\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_SECAM_K1, TEXT("AnalogVideo_SECAM_K1\0")},
|
|
{&MEDIASUBTYPE_AnalogVideo_SECAM_L, TEXT("AnalogVideo_SECAM_L\0")},
|
|
|
|
{&MEDIASUBTYPE_ARGB1555, TEXT("ARGB1555\0")},
|
|
{&MEDIASUBTYPE_ARGB4444, TEXT("ARGB4444\0")},
|
|
{&MEDIASUBTYPE_ARGB32, TEXT("ARGB32\0")},
|
|
{&MEDIASUBTYPE_A2R10G10B10, TEXT("A2R10G10B10\0")},
|
|
{&MEDIASUBTYPE_A2B10G10R10, TEXT("A2B10G10R10\0")},
|
|
|
|
{&MEDIASUBTYPE_AYUV, TEXT("AYUV\0")},
|
|
{&MEDIASUBTYPE_AI44, TEXT("AI44\0")},
|
|
{&MEDIASUBTYPE_IA44, TEXT("IA44\0")},
|
|
{&MEDIASUBTYPE_NV12, TEXT("NV12\0")},
|
|
{&MEDIASUBTYPE_IMC1, TEXT("IMC1\0")},
|
|
{&MEDIASUBTYPE_IMC2, TEXT("IMC2\0")},
|
|
{&MEDIASUBTYPE_IMC3, TEXT("IMC3\0")},
|
|
{&MEDIASUBTYPE_IMC4, TEXT("IMC4\0")},
|
|
|
|
{&MEDIASUBTYPE_Asf, TEXT("Asf\0")},
|
|
{&MEDIASUBTYPE_Avi, TEXT("Avi\0")},
|
|
{&MEDIASUBTYPE_CFCC, TEXT("CFCC\0")},
|
|
{&MEDIASUBTYPE_CLJR, TEXT("CLJR\0")},
|
|
{&MEDIASUBTYPE_CPLA, TEXT("CPLA\0")},
|
|
{&MEDIASUBTYPE_CLPL, TEXT("CLPL\0")},
|
|
{&MEDIASUBTYPE_DOLBY_AC3, TEXT("DOLBY_AC3\0")},
|
|
{&MEDIASUBTYPE_DOLBY_AC3_SPDIF, TEXT("DOLBY_AC3_SPDIF\0")},
|
|
{&MEDIASUBTYPE_DVCS, TEXT("DVCS\0")},
|
|
{&MEDIASUBTYPE_DVD_LPCM_AUDIO, TEXT("DVD_LPCM_AUDIO\0")},
|
|
{&MEDIASUBTYPE_DVD_NAVIGATION_DSI, TEXT("DVD_NAVIGATION_DSI\0")},
|
|
{&MEDIASUBTYPE_DVD_NAVIGATION_PCI, TEXT("DVD_NAVIGATION_PCI\0")},
|
|
{&MEDIASUBTYPE_DVD_NAVIGATION_PROVIDER, TEXT("DVD_NAVIGATION_PROVIDER\0")},
|
|
{&MEDIASUBTYPE_DVD_SUBPICTURE, TEXT("DVD_SUBPICTURE\0")},
|
|
{&MEDIASUBTYPE_DVSD, TEXT("DVSD\0")},
|
|
{&MEDIASUBTYPE_DRM_Audio, TEXT("DRM_Audio\0")},
|
|
{&MEDIASUBTYPE_DssAudio, TEXT("DssAudio\0")},
|
|
{&MEDIASUBTYPE_DssVideo, TEXT("DssVideo\0")},
|
|
{&MEDIASUBTYPE_IF09, TEXT("IF09\0")},
|
|
{&MEDIASUBTYPE_IEEE_FLOAT, TEXT("IEEE_FLOAT\0")},
|
|
{&MEDIASUBTYPE_IJPG, TEXT("IJPG\0")},
|
|
{&MEDIASUBTYPE_IYUV, TEXT("IYUV\0")},
|
|
{&MEDIASUBTYPE_Line21_BytePair, TEXT("Line21_BytePair\0")},
|
|
{&MEDIASUBTYPE_Line21_GOPPacket, TEXT("Line21_GOPPacket\0")},
|
|
{&MEDIASUBTYPE_Line21_VBIRawData, TEXT("Line21_VBIRawData\0")},
|
|
{&MEDIASUBTYPE_MDVF, TEXT("MDVF\0")},
|
|
{&MEDIASUBTYPE_MJPG, TEXT("MJPG\0")},
|
|
{&MEDIASUBTYPE_MPEG1Audio, TEXT("MPEG1Audio\0")},
|
|
{&MEDIASUBTYPE_MPEG1AudioPayload, TEXT("MPEG1AudioPayload\0")},
|
|
{&MEDIASUBTYPE_MPEG1Packet, TEXT("MPEG1Packet\0")},
|
|
{&MEDIASUBTYPE_MPEG1Payload, TEXT("MPEG1Payload\0")},
|
|
{&MEDIASUBTYPE_MPEG1System, TEXT("MPEG1System\0")},
|
|
{&MEDIASUBTYPE_MPEG1Video, TEXT("MPEG1Video\0")},
|
|
{&MEDIASUBTYPE_MPEG1VideoCD, TEXT("MPEG1VideoCD\0")},
|
|
{&MEDIASUBTYPE_MPEG2_AUDIO, TEXT("MPEG2_AUDIO\0")},
|
|
{&MEDIASUBTYPE_MPEG2_PROGRAM, TEXT("MPEG2_PROGRAM\0")},
|
|
{&MEDIASUBTYPE_MPEG2_TRANSPORT, TEXT("MPEG2_TRANSPORT\0")},
|
|
{&MEDIASUBTYPE_MPEG2_VIDEO, TEXT("MPEG2_VIDEO\0")},
|
|
{&MEDIASUBTYPE_None, TEXT("None\0")},
|
|
{&MEDIASUBTYPE_Overlay, TEXT("Overlay\0")},
|
|
{&MEDIASUBTYPE_PCM, TEXT("PCM\0")},
|
|
{&MEDIASUBTYPE_PCMAudio_Obsolete, TEXT("PCMAudio_Obsolete\0")},
|
|
{&MEDIASUBTYPE_Plum, TEXT("Plum\0")},
|
|
{&MEDIASUBTYPE_QTJpeg, TEXT("QTJpeg\0")},
|
|
{&MEDIASUBTYPE_QTMovie, TEXT("QTMovie\0")},
|
|
{&MEDIASUBTYPE_QTRle, TEXT("QTRle\0")},
|
|
{&MEDIASUBTYPE_QTRpza, TEXT("QTRpza\0")},
|
|
{&MEDIASUBTYPE_QTSmc, TEXT("QTSmc\0")},
|
|
{&MEDIASUBTYPE_RAW_SPORT, TEXT("RAW_SPORT\0")},
|
|
{&MEDIASUBTYPE_RGB1, TEXT("RGB1\0")},
|
|
{&MEDIASUBTYPE_RGB24, TEXT("RGB24\0")},
|
|
{&MEDIASUBTYPE_RGB32, TEXT("RGB32\0")},
|
|
{&MEDIASUBTYPE_RGB4, TEXT("RGB4\0")},
|
|
{&MEDIASUBTYPE_RGB555, TEXT("RGB555\0")},
|
|
{&MEDIASUBTYPE_RGB565, TEXT("RGB565\0")},
|
|
{&MEDIASUBTYPE_RGB8, TEXT("RGB8\0")},
|
|
{&MEDIASUBTYPE_SPDIF_TAG_241h, TEXT("SPDIF_TAG_241h\0")},
|
|
{&MEDIASUBTYPE_TELETEXT, TEXT("TELETEXT\0")},
|
|
{&MEDIASUBTYPE_TVMJ, TEXT("TVMJ\0")},
|
|
{&MEDIASUBTYPE_UYVY, TEXT("UYVY\0")},
|
|
{&MEDIASUBTYPE_VPVBI, TEXT("VPVBI\0")},
|
|
{&MEDIASUBTYPE_VPVideo, TEXT("VPVideo\0")},
|
|
{&MEDIASUBTYPE_WAKE, TEXT("WAKE\0")},
|
|
{&MEDIASUBTYPE_WAVE, TEXT("WAVE\0")},
|
|
{&MEDIASUBTYPE_Y211, TEXT("Y211\0")},
|
|
{&MEDIASUBTYPE_Y411, TEXT("Y411\0")},
|
|
{&MEDIASUBTYPE_Y41P, TEXT("Y41P\0")},
|
|
{&MEDIASUBTYPE_YUY2, TEXT("YUY2\0")},
|
|
{&MEDIASUBTYPE_YV12, TEXT("YV12\0")},
|
|
{&MEDIASUBTYPE_YVU9, TEXT("YVU9\0")},
|
|
{&MEDIASUBTYPE_YVYU, TEXT("YVYU\0")},
|
|
{&MEDIASUBTYPE_YUYV, TEXT("YUYV\0")},
|
|
{&MEDIASUBTYPE_dvhd, TEXT("dvhd\0")},
|
|
{&MEDIASUBTYPE_dvsd, TEXT("dvsd\0")},
|
|
{&MEDIASUBTYPE_dvsl, TEXT("dvsl\0")},
|
|
|
|
{&MEDIATYPE_AUXLine21Data, TEXT("AUXLine21Data\0")},
|
|
{&MEDIATYPE_AnalogAudio, TEXT("AnalogAudio\0")},
|
|
{&MEDIATYPE_AnalogVideo, TEXT("AnalogVideo\0")},
|
|
{&MEDIATYPE_Audio, TEXT("Audio\0")},
|
|
{&MEDIATYPE_DVD_ENCRYPTED_PACK, TEXT("DVD_ENCRYPTED_PACK\0")},
|
|
{&MEDIATYPE_DVD_NAVIGATION, TEXT("DVD_NAVIGATION\0")},
|
|
{&MEDIATYPE_File, TEXT("File\0")},
|
|
{&MEDIATYPE_Interleaved, TEXT("Interleaved\0")},
|
|
{&MEDIATYPE_LMRT, TEXT("LMRT\0")},
|
|
{&MEDIATYPE_MPEG1SystemStream, TEXT("MPEG1SystemStream\0")},
|
|
{&MEDIATYPE_MPEG2_PES, TEXT("MPEG2_PES\0")},
|
|
{&MEDIATYPE_Midi, TEXT("Midi\0")},
|
|
{&MEDIATYPE_ScriptCommand, TEXT("ScriptCommand\0")},
|
|
{&MEDIATYPE_Stream, TEXT("Stream\0")},
|
|
{&MEDIATYPE_Text, TEXT("Text\0")},
|
|
{&MEDIATYPE_Timecode, TEXT("Timecode\0")},
|
|
{&MEDIATYPE_URL_STREAM, TEXT("URL_STREAM\0")},
|
|
{&MEDIATYPE_VBI, TEXT("VBI\0")},
|
|
{&MEDIATYPE_Video, TEXT("Video\0")},
|
|
|
|
{&WMMEDIATYPE_Audio, TEXT("WMMEDIATYPE_Audio\0")},
|
|
{&WMMEDIATYPE_Video, TEXT("WMMEDIATYPE_Video\0")},
|
|
{&WMMEDIATYPE_Script, TEXT("WMMEDIATYPE_Script\0")},
|
|
{&WMMEDIATYPE_Image, TEXT("WMMEDIATYPE_Image\0")},
|
|
{&WMMEDIATYPE_FileTransfer, TEXT("WMMEDIATYPE_FileTransfer\0")},
|
|
{&WMMEDIATYPE_Text, TEXT("WMMEDIATYPE_Text\0")},
|
|
|
|
{&WMMEDIASUBTYPE_Base, TEXT("WMMEDIASUBTYPE_Base\0")},
|
|
{&WMMEDIASUBTYPE_RGB1, TEXT("WMMEDIASUBTYPE_RGB1\0")},
|
|
{&WMMEDIASUBTYPE_RGB4, TEXT("WMMEDIASUBTYPE_RGB4\0")},
|
|
{&WMMEDIASUBTYPE_RGB8, TEXT("WMMEDIASUBTYPE_RGB8\0")},
|
|
{&WMMEDIASUBTYPE_RGB565, TEXT("WMMEDIASUBTYPE_RGB565\0")},
|
|
{&WMMEDIASUBTYPE_RGB555, TEXT("WMMEDIASUBTYPE_RGB555\0")},
|
|
{&WMMEDIASUBTYPE_RGB24, TEXT("WMMEDIASUBTYPE_RGB24\0")},
|
|
{&WMMEDIASUBTYPE_RGB32, TEXT("WMMEDIASUBTYPE_RGB32\0")},
|
|
{&WMMEDIASUBTYPE_I420, TEXT("WMMEDIASUBTYPE_I420\0")},
|
|
{&WMMEDIASUBTYPE_IYUV, TEXT("WMMEDIASUBTYPE_IYUV\0")},
|
|
{&WMMEDIASUBTYPE_YV12, TEXT("WMMEDIASUBTYPE_YV12\0")},
|
|
{&WMMEDIASUBTYPE_YUY2, TEXT("WMMEDIASUBTYPE_YUY2\0")},
|
|
{&WMMEDIASUBTYPE_UYVY, TEXT("WMMEDIASUBTYPE_UYVY\0")},
|
|
{&WMMEDIASUBTYPE_YVYU, TEXT("WMMEDIASUBTYPE_YVYU\0")},
|
|
{&WMMEDIASUBTYPE_YVU9, TEXT("WMMEDIASUBTYPE_YVU9\0")},
|
|
{&WMMEDIASUBTYPE_MP43, TEXT("WMMEDIASUBTYPE_MP43\0")},
|
|
{&WMMEDIASUBTYPE_MP4S, TEXT("WMMEDIASUBTYPE_MP4S\0")},
|
|
|
|
{&WMMEDIASUBTYPE_WMV1, TEXT("WMMEDIASUBTYPE_WMV1\0")},
|
|
{&WMMEDIASUBTYPE_WMV2, TEXT("WMMEDIASUBTYPE_WMV2\0")},
|
|
{&WMMEDIASUBTYPE_WMV3, TEXT("WMMEDIASUBTYPE_WMV3\0")},
|
|
{&WMMEDIASUBTYPE_MSS1, TEXT("WMMEDIASUBTYPE_MSS1\0")},
|
|
{&WMMEDIASUBTYPE_MSS2, TEXT("WMMEDIASUBTYPE_MSS2\0")},
|
|
{&WMMEDIASUBTYPE_MPEG2_VIDEO, TEXT("WMMEDIASUBTYPE_MPEG2_VIDEO\0")},
|
|
{&WMMEDIASUBTYPE_PCM, TEXT("WMMEDIASUBTYPE_PCM\0")},
|
|
{&WMMEDIASUBTYPE_DRM, TEXT("WMMEDIASUBTYPE_DRM\0")},
|
|
{&WMMEDIASUBTYPE_WMAudioV9, TEXT("WMMEDIASUBTYPE_WMAudioV9\0")},
|
|
{&WMMEDIASUBTYPE_WMAudio_Lossless, TEXT("WMMEDIASUBTYPE_WMAudio_Lossless\0")},
|
|
{&WMMEDIASUBTYPE_WMAudioV8, TEXT("WMMEDIASUBTYPE_WMAudioV8\0")},
|
|
{&WMMEDIASUBTYPE_WMAudioV7, TEXT("WMMEDIASUBTYPE_WMAudioV7\0")},
|
|
{&WMMEDIASUBTYPE_WMAudioV2, TEXT("WMMEDIASUBTYPE_WMAudioV2\0")},
|
|
{&WMMEDIASUBTYPE_ACELPnet, TEXT("WMMEDIASUBTYPE_ACELPnet\0")},
|
|
{&WMMEDIASUBTYPE_WMSP1, TEXT("WMMEDIASUBTYPE_WMSP1\0")},
|
|
|
|
{&WMFORMAT_VideoInfo, TEXT("WMFORMAT_VideoInfo\0")},
|
|
{&WMFORMAT_WaveFormatEx, TEXT("WMFORMAT_WaveFormatEx\0")},
|
|
{&WMFORMAT_Script, TEXT("WMFORMAT_Script\0")},
|
|
{&WMFORMAT_MPEG2Video, TEXT("WMFORMAT_MPEG2Video\0")},
|
|
|
|
{&WMSCRIPTTYPE_TwoStrings, TEXT("WMSCRIPTTYPE_TwoStrings\0")},
|
|
|
|
{&PIN_CATEGORY_ANALOGVIDEOIN, TEXT("PIN_CATEGORY_ANALOGVIDEOIN\0")},
|
|
{&PIN_CATEGORY_CAPTURE, TEXT("PIN_CATEGORY_CAPTURE\0")},
|
|
{&PIN_CATEGORY_CC, TEXT("PIN_CATEGORY_CC\0")},
|
|
{&PIN_CATEGORY_EDS, TEXT("PIN_CATEGORY_EDS\0")},
|
|
{&PIN_CATEGORY_NABTS, TEXT("PIN_CATEGORY_NABTS\0")},
|
|
{&PIN_CATEGORY_PREVIEW, TEXT("PIN_CATEGORY_PREVIEW\0")},
|
|
{&PIN_CATEGORY_STILL, TEXT("PIN_CATEGORY_STILL\0")},
|
|
{&PIN_CATEGORY_TELETEXT, TEXT("PIN_CATEGORY_TELETEXT\0")},
|
|
{&PIN_CATEGORY_TIMECODE, TEXT("PIN_CATEGORY_TIMECODE\0")},
|
|
{&PIN_CATEGORY_VBI, TEXT("PIN_CATEGORY_VBI\0")},
|
|
{&PIN_CATEGORY_VIDEOPORT, TEXT("PIN_CATEGORY_VIDEOPORT\0")},
|
|
{&PIN_CATEGORY_VIDEOPORT_VBI, TEXT("PIN_CATEGORY_VIDEOPORT_VBI\0")},
|
|
|
|
{&CLSID_ACMWrapper, TEXT("CLSID_ACMWrapper\0")},
|
|
{&CLSID_AVICo, TEXT("CLSID_AVICo\0")},
|
|
{&CLSID_AVIDec, TEXT("CLSID_AVIDec\0")},
|
|
{&CLSID_AVIDoc, TEXT("CLSID_AVIDoc\0")},
|
|
{&CLSID_AVIDraw, TEXT("CLSID_AVIDraw\0")},
|
|
{&CLSID_AVIMIDIRender, TEXT("CLSID_AVIMIDIRender\0")},
|
|
{&CLSID_ActiveMovieCategories, TEXT("CLSID_ActiveMovieCategories\0")},
|
|
{&CLSID_AnalogVideoDecoderPropertyPage, TEXT("CLSID_AnalogVideoDecoderPropertyPage\0")},
|
|
{&CLSID_WMAsfReader, TEXT("CLSID_WMAsfReader\0")},
|
|
{&CLSID_WMAsfWriter, TEXT("CLSID_WMAsfWriter\0")},
|
|
{&CLSID_AsyncReader, TEXT("CLSID_AsyncReader\0")},
|
|
{&CLSID_AudioCompressorCategory, TEXT("CLSID_AudioCompressorCategory\0")},
|
|
{&CLSID_AudioInputDeviceCategory, TEXT("CLSID_AudioInputDeviceCategory\0")},
|
|
{&CLSID_AudioProperties, TEXT("CLSID_AudioProperties\0")},
|
|
{&CLSID_AudioRecord, TEXT("CLSID_AudioRecord\0")},
|
|
{&CLSID_AudioRender, TEXT("CLSID_AudioRender\0")},
|
|
{&CLSID_AudioRendererCategory, TEXT("CLSID_AudioRendererCategory\0")},
|
|
{&CLSID_AviDest, TEXT("CLSID_AviDest\0")},
|
|
{&CLSID_AviMuxProptyPage, TEXT("CLSID_AviMuxProptyPage\0")},
|
|
{&CLSID_AviMuxProptyPage1, TEXT("CLSID_AviMuxProptyPage1\0")},
|
|
{&CLSID_AviReader, TEXT("CLSID_AviReader\0")},
|
|
{&CLSID_AviSplitter, TEXT("CLSID_AviSplitter\0")},
|
|
{&CLSID_CAcmCoClassManager, TEXT("CLSID_CAcmCoClassManager\0")},
|
|
{&CLSID_CDeviceMoniker, TEXT("CLSID_CDeviceMoniker\0")},
|
|
{&CLSID_CIcmCoClassManager, TEXT("CLSID_CIcmCoClassManager\0")},
|
|
{&CLSID_CMidiOutClassManager, TEXT("CLSID_CMidiOutClassManager\0")},
|
|
{&CLSID_CMpegAudioCodec, TEXT("CLSID_CMpegAudioCodec\0")},
|
|
{&CLSID_CMpegVideoCodec, TEXT("CLSID_CMpegVideoCodec\0")},
|
|
{&CLSID_CQzFilterClassManager, TEXT("CLSID_CQzFilterClassManager\0")},
|
|
{&CLSID_CVidCapClassManager, TEXT("CLSID_CVidCapClassManager\0")},
|
|
{&CLSID_CWaveOutClassManager, TEXT("CLSID_CWaveOutClassManager\0")},
|
|
{&CLSID_CWaveinClassManager, TEXT("CLSID_CWaveinClassManager\0")},
|
|
{&CLSID_CameraControlPropertyPage, TEXT("CLSID_CameraControlPropertyPage\0")},
|
|
{&CLSID_CaptureGraphBuilder, TEXT("CLSID_CaptureGraphBuilder\0")},
|
|
{&CLSID_CaptureProperties, TEXT("CLSID_CaptureProperties\0")},
|
|
{&CLSID_Colour, TEXT("CLSID_Colour\0")},
|
|
{&CLSID_CrossbarFilterPropertyPage, TEXT("CLSID_CrossbarFilterPropertyPage\0")},
|
|
{&CLSID_DSoundRender, TEXT("CLSID_DSoundRender\0")},
|
|
{&CLSID_DVDHWDecodersCategory, TEXT("CLSID_DVDHWDecodersCategory\0")},
|
|
{&CLSID_DVDNavigator, TEXT("CLSID_DVDNavigator\0")},
|
|
{&CLSID_DVDecPropertiesPage, TEXT("CLSID_DVDecPropertiesPage\0")},
|
|
{&CLSID_DVEncPropertiesPage, TEXT("CLSID_DVEncPropertiesPage\0")},
|
|
{&CLSID_DVMux, TEXT("CLSID_DVMux\0")},
|
|
{&CLSID_DVMuxPropertyPage, TEXT("CLSID_DVMuxPropertyPage\0")},
|
|
{&CLSID_DVSplitter, TEXT("CLSID_DVSplitter\0")},
|
|
{&CLSID_DVVideoCodec, TEXT("CLSID_DVVideoCodec\0")},
|
|
{&CLSID_DVVideoEnc, TEXT("CLSID_DVVideoEnc\0")},
|
|
{&CLSID_DirectDraw, TEXT("CLSID_DirectDraw\0")},
|
|
{&CLSID_DirectDrawClipper, TEXT("CLSID_DirectDrawClipper\0")},
|
|
{&CLSID_DirectDrawProperties, TEXT("CLSID_DirectDrawProperties\0")},
|
|
{&CLSID_Dither, TEXT("CLSID_Dither\0")},
|
|
{&CLSID_DvdGraphBuilder, TEXT("CLSID_DvdGraphBuilder\0")},
|
|
{&CLSID_FGControl, TEXT("CLSID_FGControl\0")},
|
|
{&CLSID_FileSource, TEXT("CLSID_FileSource\0")},
|
|
{&CLSID_FileWriter, TEXT("CLSID_FileWriter\0")},
|
|
{&CLSID_FilterGraph, TEXT("CLSID_FilterGraph\0")},
|
|
{&CLSID_FilterGraphNoThread, TEXT("CLSID_FilterGraphNoThread\0")},
|
|
{&CLSID_FilterMapper, TEXT("CLSID_FilterMapper\0")},
|
|
{&CLSID_FilterMapper2, TEXT("CLSID_FilterMapper2\0")},
|
|
{&CLSID_InfTee, TEXT("CLSID_InfTee\0")},
|
|
{&CLSID_LegacyAmFilterCategory, TEXT("CLSID_LegacyAmFilterCategory\0")},
|
|
{&CLSID_Line21Decoder, TEXT("CLSID_Line21Decoder\0")},
|
|
{&CLSID_MOVReader, TEXT("CLSID_MOVReader\0")},
|
|
{&CLSID_MPEG1Doc, TEXT("CLSID_MPEG1Doc\0")},
|
|
{&CLSID_MPEG1PacketPlayer, TEXT("CLSID_MPEG1PacketPlayer\0")},
|
|
{&CLSID_MPEG1Splitter, TEXT("CLSID_MPEG1Splitter\0")},
|
|
{&CLSID_MediaPropertyBag, TEXT("CLSID_MediaPropertyBag\0")},
|
|
{&CLSID_MemoryAllocator, TEXT("CLSID_MemoryAllocator\0")},
|
|
{&CLSID_MidiRendererCategory, TEXT("CLSID_MidiRendererCategory\0")},
|
|
{&CLSID_ModexProperties, TEXT("CLSID_ModexProperties\0")},
|
|
{&CLSID_ModexRenderer, TEXT("CLSID_ModexRenderer\0")},
|
|
{&CLSID_OverlayMixer, TEXT("CLSID_OverlayMixer\0")},
|
|
{&CLSID_PerformanceProperties, TEXT("CLSID_PerformanceProperties\0")},
|
|
{&CLSID_PersistMonikerPID, TEXT("CLSID_PersistMonikerPID\0")},
|
|
{&CLSID_ProtoFilterGraph, TEXT("CLSID_ProtoFilterGraph\0")},
|
|
{&CLSID_QualityProperties, TEXT("CLSID_QualityProperties\0")},
|
|
{&CLSID_SeekingPassThru, TEXT("CLSID_SeekingPassThru\0")},
|
|
{&CLSID_SmartTee, TEXT("CLSID_SmartTee\0")},
|
|
{&CLSID_SystemClock, TEXT("CLSID_SystemClock\0")},
|
|
{&CLSID_SystemDeviceEnum, TEXT("CLSID_SystemDeviceEnum\0")},
|
|
{&CLSID_TVAudioFilterPropertyPage, TEXT("CLSID_TVAudioFilterPropertyPage\0")},
|
|
{&CLSID_TVTunerFilterPropertyPage, TEXT("CLSID_TVTunerFilterPropertyPage\0")},
|
|
{&CLSID_TextRender, TEXT("CLSID_TextRender\0")},
|
|
{&CLSID_URLReader, TEXT("CLSID_URLReader\0")},
|
|
{&CLSID_VBISurfaces, TEXT("CLSID_VBISurfaces\0")},
|
|
{&CLSID_VPObject, TEXT("CLSID_VPObject\0")},
|
|
{&CLSID_VPVBIObject, TEXT("CLSID_VPVBIObject\0")},
|
|
{&CLSID_VfwCapture, TEXT("CLSID_VfwCapture\0")},
|
|
{&CLSID_VideoCompressorCategory, TEXT("CLSID_VideoCompressorCategory\0")},
|
|
{&CLSID_VideoInputDeviceCategory, TEXT("CLSID_VideoInputDeviceCategory\0")},
|
|
{&CLSID_VideoProcAmpPropertyPage, TEXT("CLSID_VideoProcAmpPropertyPage\0")},
|
|
{&CLSID_VideoRenderer, TEXT("CLSID_VideoRenderer\0")},
|
|
{&CLSID_VideoStreamConfigPropertyPage, TEXT("CLSID_VideoStreamConfigPropertyPage\0")},
|
|
|
|
{&CLSID_WMMUTEX_Language, TEXT("CLSID_WMMUTEX_Language\0")},
|
|
{&CLSID_WMMUTEX_Bitrate, TEXT("CLSID_WMMUTEX_Bitrate\0")},
|
|
{&CLSID_WMMUTEX_Presentation, TEXT("CLSID_WMMUTEX_Presentation\0")},
|
|
{&CLSID_WMMUTEX_Unknown, TEXT("CLSID_WMMUTEX_Unknown\0")},
|
|
|
|
{&CLSID_WMBandwidthSharing_Exclusive, TEXT("CLSID_WMBandwidthSharing_Exclusive\0")},
|
|
{&CLSID_WMBandwidthSharing_Partial, TEXT("CLSID_WMBandwidthSharing_Partial\0")},
|
|
|
|
{&FORMAT_AnalogVideo, TEXT("FORMAT_AnalogVideo\0")},
|
|
{&FORMAT_DVD_LPCMAudio, TEXT("FORMAT_DVD_LPCMAudio\0")},
|
|
{&FORMAT_DolbyAC3, TEXT("FORMAT_DolbyAC3\0")},
|
|
{&FORMAT_DvInfo, TEXT("FORMAT_DvInfo\0")},
|
|
{&FORMAT_MPEG2Audio, TEXT("FORMAT_MPEG2Audio\0")},
|
|
{&FORMAT_MPEG2Video, TEXT("FORMAT_MPEG2Video\0")},
|
|
{&FORMAT_MPEG2_VIDEO, TEXT("FORMAT_MPEG2_VIDEO\0")},
|
|
{&FORMAT_MPEGStreams, TEXT("FORMAT_MPEGStreams\0")},
|
|
{&FORMAT_MPEGVideo, TEXT("FORMAT_MPEGVideo\0")},
|
|
{&FORMAT_None, TEXT("FORMAT_None\0")},
|
|
{&FORMAT_VIDEOINFO2, TEXT("FORMAT_VIDEOINFO2\0")},
|
|
{&FORMAT_VideoInfo, TEXT("FORMAT_VideoInfo\0")},
|
|
{&FORMAT_VideoInfo2, TEXT("FORMAT_VideoInfo2\0")},
|
|
{&FORMAT_WaveFormatEx, TEXT("FORMAT_WaveFormatEx\0")},
|
|
|
|
{&TIME_FORMAT_BYTE, TEXT("TIME_FORMAT_BYTE\0")},
|
|
{&TIME_FORMAT_FIELD, TEXT("TIME_FORMAT_FIELD\0")},
|
|
{&TIME_FORMAT_FRAME, TEXT("TIME_FORMAT_FRAME\0")},
|
|
{&TIME_FORMAT_MEDIA_TIME, TEXT("TIME_FORMAT_MEDIA_TIME\0")},
|
|
{&TIME_FORMAT_SAMPLE, TEXT("TIME_FORMAT_SAMPLE\0")},
|
|
|
|
{&ROPSETID_Pin, TEXT("AMPROPSETID_Pin\0")},
|
|
{&AM_INTERFACESETID_Standard, TEXT("AM_INTERFACESETID_Standard\0")},
|
|
{&AM_KSCATEGORY_AUDIO, TEXT("AM_KSCATEGORY_AUDIO\0")},
|
|
{&AM_KSCATEGORY_CAPTURE, TEXT("AM_KSCATEGORY_CAPTURE\0")},
|
|
{&AM_KSCATEGORY_CROSSBAR, TEXT("AM_KSCATEGORY_CROSSBAR\0")},
|
|
{&AM_KSCATEGORY_DATACOMPRESSOR, TEXT("AM_KSCATEGORY_DATACOMPRESSOR\0")},
|
|
{&AM_KSCATEGORY_RENDER, TEXT("AM_KSCATEGORY_RENDER\0")},
|
|
{&AM_KSCATEGORY_TVAUDIO, TEXT("AM_KSCATEGORY_TVAUDIO\0")},
|
|
{&AM_KSCATEGORY_TVTUNER, TEXT("AM_KSCATEGORY_TVTUNER\0")},
|
|
{&AM_KSCATEGORY_VIDEO, TEXT("AM_KSCATEGORY_VIDEO\0")},
|
|
{&AM_KSPROPSETID_AC3, TEXT("AM_KSPROPSETID_AC3\0")},
|
|
{&AM_KSPROPSETID_CopyProt, TEXT("AM_KSPROPSETID_CopyProt\0")},
|
|
{&AM_KSPROPSETID_DvdSubPic, TEXT("AM_KSPROPSETID_DvdSubPic\0")},
|
|
{&AM_KSPROPSETID_TSRateChange, TEXT("AM_KSPROPSETID_TSRateChange\0")},
|
|
|
|
{&IID_IAMDirectSound, TEXT("IID_IAMDirectSound\0")},
|
|
{&IID_IAMLine21Decoder, TEXT("IID_IAMLine21Decoder\0")},
|
|
{&IID_IBaseVideoMixer, TEXT("IID_IBaseVideoMixer\0")},
|
|
{&IID_IDDVideoPortContainer, TEXT("IID_IDDVideoPortContainer\0")},
|
|
{&IID_IDirectDraw, TEXT("IID_IDirectDraw\0")},
|
|
{&IID_IDirectDraw2, TEXT("IID_IDirectDraw2\0")},
|
|
{&IID_IDirectDrawClipper, TEXT("IID_IDirectDrawClipper\0")},
|
|
{&IID_IDirectDrawColorControl, TEXT("IID_IDirectDrawColorControl\0")},
|
|
{&IID_IDirectDrawKernel, TEXT("IID_IDirectDrawKernel\0")},
|
|
{&IID_IDirectDrawPalette, TEXT("IID_IDirectDrawPalette\0")},
|
|
{&IID_IDirectDrawSurface, TEXT("IID_IDirectDrawSurface\0")},
|
|
{&IID_IDirectDrawSurface2, TEXT("IID_IDirectDrawSurface2\0")},
|
|
{&IID_IDirectDrawSurface3, TEXT("IID_IDirectDrawSurface3\0")},
|
|
{&IID_IDirectDrawSurfaceKernel, TEXT("IID_IDirectDrawSurfaceKernel\0")},
|
|
{&IID_IDirectDrawVideo, TEXT("IID_IDirectDrawVideo\0")},
|
|
{&IID_IFullScreenVideo, TEXT("IID_IFullScreenVideo\0")},
|
|
{&IID_IFullScreenVideoEx, TEXT("IID_IFullScreenVideoEx\0")},
|
|
{&IID_IKsDataTypeHandler, TEXT("IID_IKsDataTypeHandler\0")},
|
|
{&IID_IKsInterfaceHandler, TEXT("IID_IKsInterfaceHandler\0")},
|
|
{&IID_IKsPin, TEXT("IID_IKsPin\0")},
|
|
{&IID_IMixerPinConfig, TEXT("IID_IMixerPinConfig\0")},
|
|
{&IID_IMixerPinConfig2, TEXT("IID_IMixerPinConfig2\0")},
|
|
{&IID_IMpegAudioDecoder, TEXT("IID_IMpegAudioDecoder\0")},
|
|
{&IID_IQualProp, TEXT("IID_IQualProp\0")},
|
|
{&IID_IVPConfig, TEXT("IID_IVPConfig\0")},
|
|
{&IID_IVPControl, TEXT("IID_IVPControl\0")},
|
|
{&IID_IVPNotify, TEXT("IID_IVPNotify\0")},
|
|
{&IID_IVPNotify2, TEXT("IID_IVPNotify2\0")},
|
|
{&IID_IVPObject, TEXT("IID_IVPObject\0")},
|
|
{&IID_IVPVBIConfig, TEXT("IID_IVPVBIConfig\0")},
|
|
{&IID_IVPVBINotify, TEXT("IID_IVPVBINotify\0")},
|
|
{&IID_IVPVBIObject, TEXT("IID_IVPVBIObject\0")},
|
|
|
|
{&LOOK_DOWNSTREAM_ONLY, TEXT("LOOK_DOWNSTREAM_ONLY\0")},
|
|
{&LOOK_UPSTREAM_ONLY, TEXT("LOOK_UPSTREAM_ONLY\0")},
|
|
{0, 0},
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetPin
|
|
// Find the pin of the specified format type on the given filter
|
|
// This method leaves an outstanding reference on the pin if successful
|
|
HRESULT GetPin(IBaseFilter* pFilter, const GUID* pFormat, PIN_DIRECTION PinDir, IPin** ppPin)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pFilter && pFormat && ppPin)
|
|
{
|
|
IEnumPins* pIEnumPins = NULL;
|
|
hr = pFilter->EnumPins(&pIEnumPins);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// find the pin with the specified format
|
|
IPin* pIPin = NULL;
|
|
while (S_OK == pIEnumPins->Next(1, &pIPin, NULL))
|
|
{
|
|
// match the pin direction
|
|
PIN_DIRECTION pinDir;
|
|
pIPin->QueryDirection(&pinDir);
|
|
if (pinDir == PinDir)
|
|
{
|
|
// match pin direction check the first media type returned from the upstream pin
|
|
IEnumMediaTypes* pIEnumMT = NULL;
|
|
hr = pIPin->EnumMediaTypes(&pIEnumMT);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
AM_MEDIA_TYPE* pmt = NULL;
|
|
hr = pIEnumMT->Next(1, &pmt, NULL);
|
|
if (S_OK == hr)
|
|
{
|
|
if (pmt->majortype == *pFormat)
|
|
{
|
|
// found the pin with the specified format
|
|
*ppPin = pIPin;
|
|
DeleteMediaType(pmt);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
DeleteMediaType(pmt);
|
|
}
|
|
}
|
|
pIEnumMT->Release();
|
|
}
|
|
}
|
|
if (pIPin) pIPin->Release(); pIPin = 0;
|
|
}
|
|
|
|
if (NULL == *ppPin)
|
|
{
|
|
// failed to find the named pin
|
|
hr = E_FAIL;
|
|
}
|
|
pIEnumPins->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// GetPin
|
|
// Find the pin of the specified name on the given filter
|
|
// This method leaves an outstanding reference on the pin if successful
|
|
HRESULT GetPin(IBaseFilter* pFilter, LPCWSTR pName, IPin** ppPin)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pFilter && pName && ppPin)
|
|
{
|
|
IEnumPins* pIEnumPins = NULL;
|
|
hr = pFilter->EnumPins(&pIEnumPins);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IPin* pIPin = NULL;
|
|
while (S_OK == pIEnumPins->Next(1, &pIPin, NULL))
|
|
{
|
|
PIN_INFO info = {0};
|
|
hr = pIPin->QueryPinInfo(&info);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (info.pFilter) info.pFilter->Release(); info.pFilter = 0;
|
|
|
|
if (0 == wcsncmp(info.achName, pName, wcslen(pName)))
|
|
{
|
|
// matched the pin category
|
|
*ppPin = pIPin;
|
|
break;
|
|
}
|
|
}
|
|
if (pIPin) pIPin->Release(); pIPin = 0;
|
|
}
|
|
pIEnumPins->Release();
|
|
}
|
|
|
|
if (NULL == *ppPin)
|
|
{
|
|
// failed to find the named pin
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// FindPinInterface
|
|
// Attempt to locate the interface on the pin with the specified format or on the first pin if no
|
|
// format is provided.
|
|
HRESULT FindPinInterface(IBaseFilter* pFilter, const GUID* pFormat, PIN_DIRECTION PinDir, const IID& riid, void** ppvInterface)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pFilter && ppvInterface)
|
|
{
|
|
IPin* pIPin = NULL;
|
|
if (pFormat)
|
|
{
|
|
hr = GetPin(pFilter, pFormat, PinDir, &pIPin);
|
|
}
|
|
else
|
|
{
|
|
IEnumPins* pIEnumPins = NULL;
|
|
hr = pFilter->EnumPins(&pIEnumPins);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pIEnumPins->Next(1, &pIPin, NULL);
|
|
}
|
|
pIEnumPins->Release();
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pIPin->QueryInterface(riid, ppvInterface);
|
|
}
|
|
pIPin->Release();
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
std::string getStringFromGUID(const GUID *pGUID)
|
|
{
|
|
int i=0;
|
|
// Find format GUID's name in the named guids table
|
|
while (MediaType[i].pguid != 0)
|
|
{
|
|
if(*pGUID == *(MediaType[i].pguid))
|
|
{
|
|
return std::string(MediaType[i].psz);
|
|
}
|
|
i++;
|
|
}
|
|
|
|
// return the guid if does not recognize the type
|
|
const int maxChar = 60;
|
|
LPOLESTR pwszClsid = (LPOLESTR) CoTaskMemAlloc(maxChar*2);
|
|
CHAR szCLSID[maxChar];
|
|
int nchar = StringFromGUID2(*pGUID, pwszClsid, maxChar);
|
|
// Convert result to ANSI
|
|
WideCharToMultiByte(CP_ACP, 0, pwszClsid, -1, szCLSID, nchar, NULL, NULL);
|
|
CoTaskMemFree(pwszClsid);
|
|
return std::string(szCLSID);
|
|
}
|
|
const GUID* getGUIDFromString(const std::string& str)
|
|
{
|
|
int i=0;
|
|
// Find format GUID's name in the named guids table
|
|
while (MediaType[i].pguid != 0)
|
|
{
|
|
if(str == std::string((MediaType[i].psz)))
|
|
return MediaType[i].pguid;
|
|
i++;
|
|
}
|
|
return 0;
|
|
}
|
|
static std::string getErrorMessage(HRESULT hr)
|
|
{
|
|
if (FAILED(hr))
|
|
{
|
|
TCHAR szErr[MAX_ERROR_TEXT_LEN];
|
|
DWORD res = AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
|
|
if (res == 0)
|
|
{
|
|
StringCchPrintf(szErr, MAX_ERROR_TEXT_LEN, "Unknown Error: 0x%2x", hr);
|
|
}
|
|
return std::string (szErr);
|
|
}
|
|
return std::string("");
|
|
}
|
|
|
|
static bool checkError(const std::string& prefix, HRESULT hr)
|
|
{
|
|
if (FAILED(hr))
|
|
osg::notify(osg::WARN) << prefix << " " << getErrorMessage(hr) << std::endl;
|
|
|
|
if (hr == E_ABORT)
|
|
return false;
|
|
if (hr == E_FAIL)
|
|
return false;
|
|
if (hr == E_OUTOFMEMORY)
|
|
return false;
|
|
if (hr == E_POINTER)
|
|
return false;
|
|
if (hr == VFW_E_CANNOT_CONNECT)
|
|
return false;
|
|
if (hr == 0x80040256)
|
|
return false;
|
|
if (hr == 0x80040216)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CTextureRenderer::initBuildGraph()
|
|
{
|
|
std::string prefixForMessage;
|
|
{
|
|
std::stringstream ss;
|
|
ss << _imageStream.get();
|
|
prefixForMessage = ss.str();
|
|
}
|
|
|
|
HRESULT hr;
|
|
hr = CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,IID_IGraphBuilder, (void **)&_graphBuilder );
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
hr = _graphBuilder->QueryInterface( IID_IMediaControl, (void **)&_mediaControl );
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
hr = _graphBuilder->QueryInterface( IID_IMediaSeeking, (void **)&_mediaSeeking );
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
hr = _graphBuilder->AddFilter((IBaseFilter*)this, L"Sampler");
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
struct ListDeviceAvailable
|
|
{
|
|
struct DeviceEntry
|
|
{
|
|
std::string _name;
|
|
std::string _clsid;
|
|
IMoniker* _device;
|
|
DeviceEntry(const std::string& name = "" , const std::string& clsid = "", IMoniker* device = 0) : _name(name), _clsid(clsid), _device(device) {}
|
|
};
|
|
std::vector<DeviceEntry> _listDevice;
|
|
IEnumMoniker* _enumMoniker;
|
|
ListDeviceAvailable(IEnumMoniker *enumMoniker) : _enumMoniker(enumMoniker)
|
|
{
|
|
createList();
|
|
}
|
|
~ListDeviceAvailable()
|
|
{
|
|
for (int i = 0; i < (int)_listDevice.size(); i++)
|
|
if (_listDevice[i]._device)
|
|
_listDevice[i]._device->Release();
|
|
}
|
|
|
|
void displayDevicesFound(const std::string& prefixForMessage, osg::NotifySeverity serverity = osg::NOTICE) const
|
|
{
|
|
for (int i = 0; i < (int)_listDevice.size(); i++)
|
|
osg::notify(serverity) << prefixForMessage << " device \"" << _listDevice[i]._name << "\" clsid " << _listDevice[i]._clsid << std::endl;
|
|
}
|
|
|
|
DeviceEntry getDevice(const std::string& name)
|
|
{
|
|
for (int i = 0; i < (int)_listDevice.size(); i++)
|
|
if (_listDevice[i]._name == name)
|
|
return _listDevice[i];
|
|
//if (!_listDevice.empty())
|
|
// return _listDevice.front();
|
|
return DeviceEntry();
|
|
}
|
|
|
|
void createList()
|
|
{
|
|
IMoniker *device = NULL;
|
|
HRESULT hr;
|
|
// Enumerate all items associated with the moniker
|
|
while (_enumMoniker->Next(1, &device, NULL) == S_OK)
|
|
{
|
|
IPropertyBag *pPropBag = NULL;
|
|
CLSID clsidFilter;
|
|
|
|
VARIANT varName;
|
|
VARIANT varFilterClsid;
|
|
|
|
VariantInit(&varName);
|
|
VariantInit(&varFilterClsid);
|
|
|
|
// Associate moniker with a file
|
|
hr = device->BindToStorage(0, 0, IID_IPropertyBag,
|
|
(void **)&pPropBag);
|
|
|
|
// Read filter name from property bag
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
|
|
}
|
|
|
|
// Read filter's CLSID from property bag. This CLSID string will be
|
|
// converted to a binary CLSID and passed to AddFilter(), which will
|
|
// add the filter's name to the listbox and its CLSID to the listbox
|
|
// item's DataPtr item. When the user clicks on a filter name in
|
|
// the listbox, we'll read the stored CLSID, convert it to a string,
|
|
// and use it to find the filter's filename in the registry.
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Read CLSID string from property bag
|
|
hr = pPropBag->Read(L"CLSID", &varFilterClsid, 0);
|
|
|
|
// Add filter name and CLSID to listbox
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CLSIDFromString(varFilterClsid.bstrVal, &clsidFilter);
|
|
}
|
|
else if (hr == E_PROP_ID_UNSUPPORTED)
|
|
{
|
|
clsidFilter = GUID_NULL; // No CLSID is listed.
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
// covert to std::string
|
|
_bstr_t bstr_t(varName.bstrVal);
|
|
std::string deviceName(bstr_t);
|
|
std::string deviceGUID;
|
|
|
|
// Add filter name and filename to list
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
LPOLESTR pwszClsid;
|
|
CHAR szCLSID[60];
|
|
hr = StringFromCLSID(clsidFilter, &pwszClsid);
|
|
if (!FAILED(hr))
|
|
{
|
|
// Convert result to ANSI
|
|
WideCharToMultiByte(CP_ACP, 0, pwszClsid, -1, szCLSID, 60, NULL, NULL);
|
|
//osg::notify(osg::NOTICE) << "device \"" << truename << "\" id " << szCLSID << std::endl;
|
|
deviceGUID = std::string(szCLSID);
|
|
}
|
|
CoTaskMemFree(pwszClsid);
|
|
}
|
|
|
|
VariantClear(&varName);
|
|
VariantClear(&varFilterClsid);
|
|
|
|
// Cleanup interfaces
|
|
if (pPropBag) pPropBag->Release();
|
|
|
|
_listDevice.push_back(DeviceEntry(deviceName, deviceGUID, device));
|
|
}
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
struct ListCapDeviceAvailable
|
|
{
|
|
typedef std::pair<AM_MEDIA_TYPE*, VIDEOINFOHEADER *> CapEntry;
|
|
std::vector<CapEntry> _capsList;
|
|
IAMStreamConfig* _config;
|
|
ListCapDeviceAvailable(IAMStreamConfig* config) : _config(config)
|
|
{
|
|
createList();
|
|
}
|
|
~ListCapDeviceAvailable()
|
|
{
|
|
for (int i = 0; i < (int)_capsList.size(); i++)
|
|
if (_capsList[i].first)
|
|
DeleteMediaType(_capsList[i].first);
|
|
}
|
|
|
|
void displayCapsFound(const std::string& prefixForMessage = "") const
|
|
{
|
|
for (int i = 0; i < (int)_capsList.size(); i++)
|
|
{
|
|
VIDEOINFOHEADER* video= _capsList[i].second;
|
|
displayCap(video, prefixForMessage);
|
|
}
|
|
}
|
|
|
|
static void displayCap(VIDEOINFOHEADER* video, const std::string& prefix = "")
|
|
{
|
|
if (!video)
|
|
return;
|
|
double fps = 1.0/ (video->AvgTimePerFrame * 100.0 * 1e-9);
|
|
FOURCCMap fccMap(video->bmiHeader.biCompression);
|
|
GUID g1 = (GUID)fccMap;
|
|
osg::notify(osg::NOTICE) << prefix << " cap " << video->bmiHeader.biWidth << " x " << video->bmiHeader.biHeight << " bit per pixel " << video->bmiHeader.biBitCount << " (" << getStringFromGUID(&g1) << ") at " << fps << " fps" << std::endl;
|
|
}
|
|
|
|
std::pair<AM_MEDIA_TYPE*, VIDEOINFOHEADER *> getCaps(int width, int height, double fps)
|
|
{
|
|
std::vector<CapEntry> filterResolution;
|
|
for (int i = 0; i < (int)_capsList.size(); i++)
|
|
{
|
|
VIDEOINFOHEADER* video= _capsList[i].second;
|
|
if (video->bmiHeader.biWidth == width && video->bmiHeader.biHeight == height)
|
|
{
|
|
filterResolution.push_back(_capsList[i]);
|
|
}
|
|
}
|
|
// get the max fps if the fps are not reach on the desired resolution
|
|
typedef std::multimap<double, CapEntry> ContainerFrameRateSorted;
|
|
ContainerFrameRateSorted filterFrameRate;
|
|
for (int i = 0; i < (int)filterResolution.size(); i++)
|
|
{
|
|
VIDEOINFOHEADER* video= filterResolution[i].second;
|
|
double capfps = 1.0/ (video->AvgTimePerFrame * 100.0 * 1e-9);
|
|
double error = fabs(capfps - fps);
|
|
filterFrameRate.insert(std::pair<double, CapEntry>(error, filterResolution[i]));
|
|
}
|
|
|
|
CapEntry best = CapEntry(0,0);
|
|
CapEntry first = CapEntry(0,0);
|
|
for (ContainerFrameRateSorted::iterator it = filterFrameRate.begin();
|
|
it != filterFrameRate.end();
|
|
++it)
|
|
{
|
|
if (first == CapEntry(0,0))
|
|
first = it->second;
|
|
|
|
if (it->first < 1e-3)
|
|
{
|
|
VIDEOINFOHEADER* video= it->second.second;
|
|
FOURCCMap fccMap(video->bmiHeader.biCompression);
|
|
GUID g1 = (GUID)fccMap;
|
|
if (getStringFromGUID(&g1) == std::string("YUY2"))
|
|
best = it->second;
|
|
}
|
|
}
|
|
if (best != CapEntry(0,0))
|
|
return best;
|
|
if (first != CapEntry(0,0))
|
|
return first;
|
|
|
|
if (!_capsList.empty())
|
|
return _capsList.front();
|
|
return CapEntry(0,0);
|
|
}
|
|
|
|
void createList()
|
|
{
|
|
std::string device = "capture";
|
|
// Use the IPin to get the interface:
|
|
|
|
// get the number of formats and make sure the strutucre size matches
|
|
int iCount, iSize;
|
|
VIDEO_STREAM_CONFIG_CAPS caps;
|
|
_config->GetNumberOfCapabilities(&iCount, &iSize);
|
|
if( sizeof(caps) != iSize )
|
|
return;
|
|
|
|
// now go through all formats and use the one you like
|
|
for(int i=0; i < iCount; i++)
|
|
{
|
|
// GetStreamCaps allocats the AM_MEDIA_TYPE, which must be deleted by using DeleteMediaType
|
|
AM_MEDIA_TYPE *pmt = NULL;
|
|
if( _config->GetStreamCaps(i, &pmt, (BYTE*)&caps) == S_OK )
|
|
{
|
|
if (pmt->formattype == FORMAT_VideoInfo && pmt->cbFormat >= sizeof(VIDEOINFOHEADER))
|
|
{
|
|
VIDEOINFOHEADER *video=
|
|
reinterpret_cast<VIDEOINFOHEADER*>(pmt->pbFormat);
|
|
_capsList.push_back(CapEntry(pmt, video));
|
|
}
|
|
else
|
|
{
|
|
DeleteMediaType(pmt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
bool CTextureRenderer::setupOutputSoundDevice(ICreateDevEnum* devs)
|
|
{
|
|
if (!devs)
|
|
return false;
|
|
|
|
std::string prefixForMessage;
|
|
{
|
|
std::stringstream ss;
|
|
ss << _imageStream.get();
|
|
prefixForMessage = ss.str();
|
|
}
|
|
|
|
HRESULT hr;
|
|
std::string outputdevice = "Default DirectSound Device";
|
|
IEnumMoniker* audioRenderer = 0; hr = devs?devs->CreateClassEnumerator (CLSID_AudioRendererCategory, &audioRenderer, 0):0;
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
ListDeviceAvailable deviceFinder(audioRenderer);
|
|
|
|
deviceFinder.displayDevicesFound(prefixForMessage + " sounddevice", osg::INFO);
|
|
|
|
ListDeviceAvailable::DeviceEntry device = deviceFinder.getDevice(outputdevice);
|
|
if (!device._device)
|
|
{
|
|
osg::notify(osg::WARN) << prefixForMessage << " no output sound device \"" << outputdevice << "\" found" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
_soundOutputDeviceName = device._name;
|
|
IMoniker* mon = device._device;
|
|
hr = mon?mon->BindToObject(0,0,IID_IBaseFilter, (void**)&_soundOutputDevice):0;
|
|
checkError(prefixForMessage, hr);
|
|
if (FAILED(hr))
|
|
return false;
|
|
|
|
hr = _graphBuilder->AddFilter(_soundOutputDevice,NULL);
|
|
checkError(prefixForMessage, hr);
|
|
if (FAILED(hr))
|
|
{
|
|
if (_soundOutputDevice) _soundOutputDevice->Release(); _soundOutputDevice = 0;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CTextureRenderer::openVideoCaptureDevice(const std::string& capture, int wantWidth, int wantHeight, double wantFps)
|
|
{
|
|
std::string prefixForMessage;
|
|
{
|
|
std::stringstream ss;
|
|
ss << _imageStream.get();
|
|
prefixForMessage = ss.str();
|
|
}
|
|
|
|
HRESULT hr;
|
|
ICreateDevEnum* devs = 0; hr = CoCreateInstance (CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC, IID_ICreateDevEnum, (void **) &devs);
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
IEnumMoniker* cams = 0; hr = devs?devs->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &cams, 0):0;
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
ListDeviceAvailable deviceFinder(cams);
|
|
{
|
|
std::stringstream ss;
|
|
ss << std::hex << _imageStream.get() << " capture";
|
|
deviceFinder.displayDevicesFound(ss.str(), osg::INFO);
|
|
}
|
|
ListDeviceAvailable::DeviceEntry device = deviceFinder.getDevice(capture);
|
|
|
|
if (!device._device)
|
|
{
|
|
osg::notify(osg::WARN) << _imageStream.get() << " no capture device \"" << capture << "\" found" << std::endl;
|
|
return false;
|
|
}
|
|
_videoCaptureDeviceName = device._name;
|
|
osg::notify(osg::NOTICE) << _imageStream.get() << " use capture device \"" << getVideoCaptureDeviceName() << "\"" << std::endl;
|
|
|
|
{
|
|
std::stringstream ss;
|
|
ss << _imageStream.get() << " \"" << getVideoCaptureDeviceName() << "\"";
|
|
prefixForMessage = ss.str();
|
|
}
|
|
|
|
|
|
IMoniker* mon = device._device;
|
|
|
|
hr = mon?mon->BindToObject(0,0,IID_IBaseFilter, (void**)&_videoCaptureDevice):0;
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
IEnumPins* pins = 0; hr = _videoCaptureDevice?_videoCaptureDevice->EnumPins(&pins):0;
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
IPin* cap = 0; hr = pins?pins->Next(1,&cap, 0):0;
|
|
if (pins) pins->Release(); pins = 0;
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
|
|
IAMStreamConfig* capConfig = 0; hr = cap->QueryInterface( IID_IAMStreamConfig, (void **)&capConfig);
|
|
if (capConfig)
|
|
{
|
|
ListCapDeviceAvailable capsDevice(capConfig);
|
|
capsDevice.displayCapsFound(prefixForMessage);
|
|
ListCapDeviceAvailable::CapEntry found = capsDevice.getCaps(wantWidth, wantHeight, wantFps);
|
|
if (found.first)
|
|
{
|
|
ListCapDeviceAvailable::displayCap(found.second, prefixForMessage + " use ");
|
|
capConfig->SetFormat(found.first);
|
|
}
|
|
capConfig->Release();
|
|
}
|
|
|
|
hr = _graphBuilder->AddFilter(_videoCaptureDevice, L"Capture Source");
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
IPin* rnd = 0;
|
|
hr = FindPin(L"In", &rnd);
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
hr = _graphBuilder->Connect(cap,rnd);
|
|
|
|
if (rnd) rnd->Release();
|
|
if (cap) cap->Release();
|
|
|
|
bool result = checkError(prefixForMessage, hr);
|
|
return result;
|
|
}
|
|
|
|
|
|
bool CTextureRenderer::openSoundCaptureDevice(const std::string& capture, int nbChannels)
|
|
{
|
|
std::string prefixForMessage;
|
|
{
|
|
std::stringstream ss;
|
|
ss << _imageStream.get();
|
|
prefixForMessage = ss.str();
|
|
}
|
|
|
|
HRESULT hr;
|
|
ICreateDevEnum* devs = 0; hr = CoCreateInstance (CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC, IID_ICreateDevEnum, (void **) &devs);
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
IEnumMoniker* captureDevices = 0; hr = devs?devs->CreateClassEnumerator (CLSID_AudioInputDeviceCategory, &captureDevices, 0):0;
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
ListDeviceAvailable deviceFinder(captureDevices);
|
|
{
|
|
std::stringstream ss;
|
|
ss << std::hex << _imageStream.get() << " capture sound ";
|
|
deviceFinder.displayDevicesFound(ss.str(), osg::INFO);
|
|
}
|
|
ListDeviceAvailable::DeviceEntry device = deviceFinder.getDevice(capture);
|
|
|
|
if (!device._device)
|
|
{
|
|
osg::notify(osg::WARN) << _imageStream.get() << " no sound capture device \"" << capture << "\" found" << std::endl;
|
|
return false;
|
|
}
|
|
_soundCaptureDeviceName = device._name;
|
|
osg::notify(osg::NOTICE) << _imageStream.get() << " use sound capture device \"" << getSoundCaptureDeviceName() << "\"" << std::endl;
|
|
|
|
{
|
|
std::stringstream ss;
|
|
ss << _imageStream.get() << " \"" << getSoundCaptureDeviceName() << "\"";
|
|
prefixForMessage = ss.str();
|
|
}
|
|
|
|
|
|
IMoniker* mon = device._device;
|
|
|
|
hr = mon?mon->BindToObject(0,0,IID_IBaseFilter, (void**)&_soundCaptureDevice):0;
|
|
if (FAILED(hr))
|
|
{
|
|
checkError(prefixForMessage, hr);
|
|
return false;
|
|
}
|
|
|
|
IAMStreamConfig* pISC = NULL;
|
|
hr = FindPinInterface(_soundCaptureDevice, &MEDIATYPE_Audio, PINDIR_OUTPUT, IID_IAMStreamConfig, reinterpret_cast<void**>(&pISC));
|
|
if (FAILED(hr))
|
|
{
|
|
checkError(prefixForMessage, hr);
|
|
return false;
|
|
}
|
|
// loop through all the capabilities (audio formats) and populate the control
|
|
int count, size;
|
|
hr = pISC->GetNumberOfCapabilities(&count, &size);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (sizeof(AUDIO_STREAM_CONFIG_CAPS) == size)
|
|
{
|
|
AM_MEDIA_TYPE* pmt = NULL;
|
|
AUDIO_STREAM_CONFIG_CAPS ascc;
|
|
WAVEFORMATEX* pwfex = NULL;
|
|
|
|
for (int index=0; index<count; ++index)
|
|
{
|
|
hr = pISC->GetStreamCaps(index, &pmt, reinterpret_cast<BYTE*>(&ascc));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR buffer[32];
|
|
|
|
ZeroMemory(buffer, sizeof(buffer));
|
|
|
|
pwfex = (WAVEFORMATEX*)pmt->pbFormat;
|
|
|
|
// provide a useful description of the formats
|
|
if (1 == pwfex->nChannels)
|
|
{
|
|
StringCbPrintf(buffer, sizeof(buffer), TEXT("%d channel, %2.1fkHz, %d-bit"), (int)pwfex->nChannels, (float)pwfex->nSamplesPerSec / 1000, (int)pwfex->wBitsPerSample);
|
|
}
|
|
else
|
|
{
|
|
StringCbPrintf(buffer, sizeof(buffer), TEXT("%d channels, %2.1fkHz, %d-bit"), (int)pwfex->nChannels, (float)pwfex->nSamplesPerSec / 1000, (int)pwfex->wBitsPerSample);
|
|
}
|
|
|
|
// set default format
|
|
if (pwfex->nChannels == nbChannels)
|
|
{
|
|
pISC->SetFormat(pmt);
|
|
osg::notify(osg::NOTICE) << prefixForMessage << " use format " << buffer << std::endl;
|
|
break;
|
|
} else
|
|
osg::notify(osg::NOTICE) << prefixForMessage << buffer << std::endl;
|
|
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
osg::notify(osg::WARN) << prefixForMessage << " can t retrieve informations pins" << std::endl;
|
|
}
|
|
}
|
|
if (pISC) pISC->Release(); pISC = 0;
|
|
IPin* captureOutputDevicePinOut = 0; hr = _soundCaptureDevice? ::GetPin(_soundCaptureDevice,L"Capture",&captureOutputDevicePinOut) : 0;
|
|
if (FAILED(hr)) {
|
|
checkError(prefixForMessage, hr);
|
|
return false;
|
|
}
|
|
|
|
hr = _graphBuilder->AddFilter(_soundCaptureDevice, L"Sound Capture Source");
|
|
if (FAILED(hr))
|
|
{
|
|
checkError(prefixForMessage, hr);
|
|
return false;
|
|
}
|
|
|
|
if (!setupOutputSoundDevice(devs))
|
|
{
|
|
devs->Release(); devs = 0;
|
|
if (captureOutputDevicePinOut) captureOutputDevicePinOut->Release(); captureOutputDevicePinOut = 0;
|
|
return false;
|
|
}
|
|
devs->Release(); devs = 0;
|
|
|
|
std::string prefixForMessageSound;
|
|
{
|
|
std::stringstream ss;
|
|
ss << _imageStream.get() << " " << getSoundOutputDeviceName();
|
|
prefixForMessageSound = ss.str();
|
|
}
|
|
|
|
IPin* soundOutputDevicePinIn = 0;
|
|
hr = _soundOutputDevice->FindPin(L"Audio Input pin (rendered)", &soundOutputDevicePinIn);
|
|
if (FAILED(hr))
|
|
{
|
|
checkError(prefixForMessageSound, hr);
|
|
if (soundOutputDevicePinIn) soundOutputDevicePinIn->Release(); soundOutputDevicePinIn = 0;
|
|
if (captureOutputDevicePinOut) captureOutputDevicePinOut->Release(); captureOutputDevicePinOut = 0;
|
|
return false;
|
|
}
|
|
|
|
hr = _graphBuilder->Connect(captureOutputDevicePinOut, soundOutputDevicePinIn);
|
|
|
|
if (soundOutputDevicePinIn) soundOutputDevicePinIn->Release(); soundOutputDevicePinIn = 0;
|
|
if (captureOutputDevicePinOut) captureOutputDevicePinOut->Release(); captureOutputDevicePinOut = 0;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
checkError(prefixForMessageSound, hr);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CTextureRenderer::openCaptureDevices(const DirectShowImageStream::Options& o)
|
|
{
|
|
std::string prefixForMessage;
|
|
{
|
|
std::stringstream ss;
|
|
ss << _imageStream.get();
|
|
prefixForMessage = ss.str();
|
|
}
|
|
|
|
DirectShowImageStream::Options options = o;
|
|
syncStreams(false);
|
|
|
|
for (DirectShowImageStream::Options::iterator it = options.begin(); it != options.end(); it++)
|
|
osg::notify(osg::NOTICE) << prefixForMessage << " option " << it->first << " = " << it->second << std::endl;
|
|
|
|
std::string soundCaptureDevice = options["captureSoundDevice"];
|
|
std::string videoCaptureDevice = options["captureVideoDevice"];
|
|
|
|
osg::notify(osg::NOTICE) << prefixForMessage << " try to open video capture device " << videoCaptureDevice;
|
|
if (!soundCaptureDevice .empty())
|
|
osg::notify(osg::NOTICE) << " and sound capture device " << soundCaptureDevice ;
|
|
osg::notify(osg::NOTICE) << std::endl;
|
|
|
|
if (!initBuildGraph())
|
|
return false;
|
|
|
|
int wantWidth = atoi(options["captureWantedWidth"].c_str());
|
|
int wantHeight = atoi(options["captureWantedHeight"].c_str());
|
|
float wantFps = atof(options["captureWantedFps"].c_str());
|
|
if (!openVideoCaptureDevice(videoCaptureDevice, wantWidth, wantHeight, wantFps))
|
|
return false;
|
|
|
|
if (!soundCaptureDevice.empty() && !openSoundCaptureDevice(soundCaptureDevice ))
|
|
osg::notify(osg::WARN) << prefixForMessage << " failed to setup sound capture device " << soundCaptureDevice << std::endl;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CTextureRenderer::openFile(const std::string& file)
|
|
{
|
|
syncStreams(true);
|
|
WCHAR wFileName[MAX_PATH];
|
|
wFileName[MAX_PATH-1] = 0; // NULL-terminate
|
|
if (file.empty())
|
|
return false;
|
|
|
|
_filename = file;
|
|
std::string prefixForMessage;
|
|
{
|
|
std::stringstream ss;
|
|
ss << _imageStream.get() << " " << getFilename();
|
|
prefixForMessage = ss.str();
|
|
}
|
|
|
|
const char *ansistr = file.c_str();
|
|
int lenA = lstrlenA(ansistr);
|
|
int lenW;
|
|
BSTR unicodestr;
|
|
|
|
lenW = ::MultiByteToWideChar(CP_ACP, 0, ansistr, lenA, 0, 0);
|
|
if (lenW > 0)
|
|
{
|
|
// Check whether conversion was successful
|
|
unicodestr = ::SysAllocStringLen(0, lenW);
|
|
::MultiByteToWideChar(CP_ACP, 0, ansistr, lenA, unicodestr, lenW);
|
|
}
|
|
|
|
(void)StringCchCopyW(wFileName, NUMELMS(wFileName), unicodestr);
|
|
|
|
// when done, free the BSTR
|
|
::SysFreeString(unicodestr);
|
|
|
|
HRESULT hr;
|
|
if (!initBuildGraph())
|
|
return false;
|
|
|
|
IPin* videoOutputPin = 0;
|
|
|
|
std::string lowercase = file;
|
|
std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(), tolower);
|
|
if (lowercase.rfind(".wmv") != std::string::npos)
|
|
{
|
|
hr = _graphBuilder->AddSourceFilter(wFileName, L"Windows Media source filter", &_fileSource);
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
hr = _fileSource?_fileSource->FindPin(L"Raw Video 1", &videoOutputPin):0;
|
|
}
|
|
else
|
|
{
|
|
hr = _graphBuilder->AddSourceFilter(wFileName, L"File Source", &_fileSource);
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
hr = _fileSource?_fileSource->FindPin(L"Output", &videoOutputPin):0;
|
|
}
|
|
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
IPin* rnd = 0;
|
|
hr = FindPin(L"In", &rnd);
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
hr = _graphBuilder->Connect(videoOutputPin, rnd);
|
|
if (videoOutputPin) videoOutputPin->Release(); videoOutputPin = 0;
|
|
|
|
if (rnd) rnd->Release(); rnd = 0;
|
|
if (!checkError(prefixForMessage, hr))
|
|
return false;
|
|
|
|
|
|
if (lowercase.rfind(".avi") == std::string::npos) // not an avi, dont try to connect sounds
|
|
return true;
|
|
|
|
// check if we find the sounds output pin on the streams
|
|
IBaseFilter* AVISpliterFilter = 0;
|
|
hr = _graphBuilder->FindFilterByName(L"AVI Splitter", &AVISpliterFilter);
|
|
if (FAILED(hr))
|
|
osg::notify(osg::WARN) << prefixForMessage << " did not find AVI SPlitter to connect sound, " << getErrorMessage(hr) << std::endl;
|
|
|
|
if (AVISpliterFilter)
|
|
{
|
|
IPin* soundStreamPinOut = 0;
|
|
hr = AVISpliterFilter->FindPin(L"Stream 01",&soundStreamPinOut);
|
|
AVISpliterFilter->Release(); AVISpliterFilter = 0;
|
|
|
|
if (FAILED(hr))
|
|
osg::notify(osg::WARN) << prefixForMessage << " can't find Stream 01 pin on AVIS Splitter, maybe the flux does have sound, " << getErrorMessage(hr) << std::endl;
|
|
|
|
if (soundStreamPinOut)
|
|
{
|
|
// connect sounds to graph
|
|
ICreateDevEnum* devs = 0; hr = CoCreateInstance (CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC, IID_ICreateDevEnum, (void **) &devs);
|
|
checkError(prefixForMessage, hr);
|
|
if (devs && setupOutputSoundDevice(devs))
|
|
{
|
|
devs->Release(); devs = 0;
|
|
std::string prefixForMessageSound;
|
|
{
|
|
std::stringstream ss;
|
|
ss << _imageStream.get() << " " << getSoundOutputDeviceName();
|
|
prefixForMessageSound = ss.str();
|
|
}
|
|
|
|
IPin* soundOutputDevicePinIn = 0;
|
|
hr = _soundOutputDevice->FindPin(L"Audio Input pin (rendered)", &soundOutputDevicePinIn);
|
|
checkError(prefixForMessageSound, hr);
|
|
|
|
hr = _graphBuilder->Connect(soundStreamPinOut, soundOutputDevicePinIn);
|
|
|
|
if (soundOutputDevicePinIn) soundOutputDevicePinIn->Release(); soundOutputDevicePinIn = 0;
|
|
if (soundStreamPinOut) soundStreamPinOut->Release(); soundStreamPinOut = 0;
|
|
|
|
if (!checkError(prefixForMessageSound, hr) && _soundOutputDevice)
|
|
{
|
|
_graphBuilder->RemoveFilter(_soundOutputDevice);
|
|
_soundOutputDevice->Release(); _soundOutputDevice = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CleanupDShow
|
|
//-----------------------------------------------------------------------------
|
|
void CTextureRenderer::releaseRessources()
|
|
{
|
|
// Shut down the graph
|
|
if (_mediaControl) _mediaControl->Stop();
|
|
_imageStream = 0;
|
|
|
|
if (_mediaControl) _mediaControl->Release(); _mediaControl = 0;
|
|
if (_mediaEvent) _mediaEvent->Release(); _mediaEvent = 0;
|
|
if (_mediaSeeking) _mediaSeeking->Release(); _mediaSeeking = 0;
|
|
// remove filter outside because this is a filter too.
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CTextureRenderer constructor
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CTextureRenderer::CTextureRenderer( DirectShowImageStream* is, HRESULT* valid)
|
|
: CBaseVideoRenderer(__uuidof(CLSID_TextureRenderer),
|
|
NAME("Texture Renderer"),
|
|
NULL,
|
|
valid)
|
|
{
|
|
std::string prefixForMessage;
|
|
{
|
|
std::stringstream ss;
|
|
ss << is;
|
|
prefixForMessage = ss.str();
|
|
}
|
|
|
|
if (FAILED(*valid))
|
|
checkError(prefixForMessage, *valid);
|
|
|
|
_imageStream = is;
|
|
_fileSource = 0;
|
|
_mediaControl = 0;
|
|
_mediaEvent = 0;
|
|
_mediaSeeking = 0;
|
|
_graphBuilder = 0;
|
|
_videoCaptureDevice = 0;
|
|
_soundOutputDevice = 0;
|
|
_soundCaptureDevice = 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CTextureRenderer destructor
|
|
//-----------------------------------------------------------------------------
|
|
CTextureRenderer::~CTextureRenderer()
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CheckMediaType: This method forces the graph to give us an R8G8B8 video
|
|
// type, making our copy to texture memory trivial.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CTextureRenderer::CheckMediaType(const CMediaType *pmt)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
VIDEOINFO *pvi=0;
|
|
|
|
CheckPointer(pmt,E_POINTER);
|
|
|
|
// Reject the connection if this is not a video type
|
|
if( *pmt->FormatType() != FORMAT_VideoInfo ) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// Only accept RGB24 video
|
|
pvi = (VIDEOINFO *)pmt->Format();
|
|
|
|
if (!IsEqualGUID( *pmt->Type(), MEDIATYPE_Video))
|
|
osg::notify(osg::WARN) << _imageStream.get() << " media type not a video format" << std::endl;
|
|
|
|
|
|
if( IsEqualGUID( *pmt->Subtype(), MEDIASUBTYPE_RGB24))
|
|
{
|
|
osg::notify(osg::NOTICE) << _imageStream.get() << " Texture Renderer use media " << getStringFromGUID(pmt->Subtype()) << std::endl;
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
osg::notify(osg::INFO) << _imageStream.get() << " Texture Renderer check media " << getStringFromGUID(pmt->Subtype()) << std::endl;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SetMediaType: Graph connection has been made.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CTextureRenderer::SetMediaType(const CMediaType *pmt)
|
|
{
|
|
// Retrive the size of this media type
|
|
VIDEOINFO *pviBmp; // Bitmap info header
|
|
pviBmp = (VIDEOINFO *)pmt->Format();
|
|
|
|
_width = pviBmp->bmiHeader.biWidth;
|
|
_height = abs(pviBmp->bmiHeader.biHeight);
|
|
_pitch = (_width * 3 + 3) & ~(3); // We are forcing RGB24
|
|
_imageStream->setImage(_width, _height, 1, GL_RGB, GL_BGR, GL_UNSIGNED_BYTE, 0, osg::Image::NO_DELETE);
|
|
return S_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// DoRenderSample: A sample has been delivered. Copy it to the texture.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CTextureRenderer::DoRenderSample( IMediaSample * pSample )
|
|
{
|
|
BYTE *pBmpBuffer; // Bitmap buffer, texture buffer
|
|
CheckPointer(pSample,E_POINTER);
|
|
|
|
// Get the video bitmap buffer
|
|
pSample->GetPointer( &pBmpBuffer );
|
|
if (_imageStream.valid())
|
|
_imageStream->setImage(_width, _height, 1, GL_RGB, GL_BGR, GL_UNSIGNED_BYTE, pBmpBuffer, osg::Image::NO_DELETE);
|
|
return S_OK;
|
|
}
|
|
|
|
void CTextureRenderer::syncStreams(bool state)
|
|
{
|
|
if (state == true)
|
|
_dropFrame = !S_OK;
|
|
else
|
|
_dropFrame = S_OK;
|
|
}
|
|
HRESULT CTextureRenderer::ShouldDrawSampleNow(IMediaSample *sample, REFERENCE_TIME *start, REFERENCE_TIME *stop) {
|
|
return _dropFrame; // disable droping of frames
|
|
}
|
|
|
|
bool CTextureRenderer::StopFilters()
|
|
{
|
|
HRESULT hr;
|
|
if (_mediaControl)
|
|
{
|
|
hr = _mediaControl->Stop();
|
|
if (FAILED(hr))
|
|
{
|
|
osg::notify(osg::WARN) << _imageStream.get() << " " << getErrorMessage(hr) << std::endl;
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
DirectShowImageStream::DirectShowImageStream()
|
|
{
|
|
_options["captureWantedWidth"] = "1920";
|
|
_options["captureWantedHeight"] = "1080";
|
|
_options["captureWantedFps"] = "30";
|
|
|
|
HRESULT hr = CoInitialize (NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
osg::notify(osg::WARN) << this << " error in constructor " << getErrorMessage(hr) << std::endl;
|
|
}
|
|
|
|
}
|
|
DirectShowImageStream::DirectShowImageStream(const DirectShowImageStream& d,const osg::CopyOp& c) : osg::ImageStream(d, c)
|
|
{
|
|
// i guess it's invalid
|
|
}
|
|
|
|
DirectShowImageStream::~DirectShowImageStream()
|
|
{
|
|
stop();
|
|
CoUninitialize();
|
|
}
|
|
|
|
bool DirectShowImageStream::openFile(const std::string& file)
|
|
{
|
|
HRESULT valid = S_OK;
|
|
_renderer = new CTextureRenderer(this, &valid);
|
|
if (FAILED(valid))
|
|
{
|
|
return false;
|
|
}
|
|
if (!_renderer->openFile(file))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool DirectShowImageStream::openCaptureDevices()
|
|
{
|
|
HRESULT valid = S_OK;
|
|
_renderer = new CTextureRenderer(this, &valid);
|
|
if (FAILED(valid))
|
|
{
|
|
return false;
|
|
}
|
|
if (!_renderer->openCaptureDevices(_options))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
void DirectShowImageStream::play()
|
|
{
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
|
if (_status == PLAYING)
|
|
return;
|
|
|
|
if (_renderer.valid() && _renderer->_mediaControl)
|
|
{
|
|
HRESULT hr;
|
|
hr = _renderer->_mediaControl->Run();
|
|
// Start the graph running;
|
|
if (FAILED(hr))
|
|
{
|
|
osg::notify(osg::WARN) << this << " can't run the graph " << getErrorMessage(hr) << std::endl;
|
|
}
|
|
else
|
|
{
|
|
_status = PLAYING;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DirectShowImageStream::pause()
|
|
{
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
|
if (_status == PAUSED)
|
|
return;
|
|
|
|
if (_renderer.valid() && _renderer->_mediaControl)
|
|
{
|
|
HRESULT hr;
|
|
hr = _renderer->_mediaControl->Pause();
|
|
if (FAILED(hr))
|
|
{
|
|
osg::notify(osg::NOTICE) << this << " " << getErrorMessage(hr) << std::endl;
|
|
}
|
|
else
|
|
{
|
|
_status = PAUSED;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DirectShowImageStream::rewind()
|
|
{
|
|
seek(0);
|
|
}
|
|
|
|
osg::ImageStream::StreamStatus DirectShowImageStream::getStatus()
|
|
{
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
|
return _status;
|
|
}
|
|
|
|
void DirectShowImageStream::seek(double time)
|
|
{
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
|
if (_renderer.valid() && _renderer->_mediaSeeking)
|
|
{
|
|
double start = time / (100 * 1e-9);
|
|
LONGLONG start2 = static_cast<LONGLONG>(start);
|
|
HRESULT hr = _renderer->_mediaSeeking->SetPositions(&start2,AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
|
|
if (FAILED(hr))
|
|
{
|
|
osg::notify(osg::NOTICE) << this << " " << getErrorMessage(hr) << std::endl;
|
|
}
|
|
}
|
|
|
|
}
|
|
void DirectShowImageStream::setOptions(const Options& map)
|
|
{
|
|
for (Options::const_iterator it = map.begin(); it != map.end(); it++)
|
|
_options[it->first] = it->second;
|
|
}
|
|
|
|
void DirectShowImageStream::quit(bool waitForThreadToExit)
|
|
{
|
|
stop();
|
|
}
|
|
|
|
double DirectShowImageStream::getLength() const
|
|
{
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
|
double duration = 0;
|
|
if (_renderer.valid() && _renderer->_mediaSeeking)
|
|
{
|
|
LONGLONG d = 0;
|
|
_renderer->_mediaSeeking->GetDuration(&d);
|
|
duration = static_cast<double>(d);
|
|
duration = duration * (100.0 * 1e-9); // default unit in directshow IMediaSeeking
|
|
}
|
|
return duration;
|
|
}
|
|
|
|
double DirectShowImageStream::getFrameRate() const
|
|
{
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
|
int frameRate = 0;
|
|
if (_renderer.valid())
|
|
_renderer->get_AvgFrameRate(&frameRate);
|
|
return static_cast<double>(frameRate) * 1e-2;
|
|
}
|
|
|
|
void DirectShowImageStream::setTimeMultiplier(double rate)
|
|
{
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
|
if (_renderer.valid() && _renderer->_mediaSeeking)
|
|
_renderer->_mediaSeeking->SetRate(rate);
|
|
}
|
|
|
|
double DirectShowImageStream::getTimeMultiplier() const
|
|
{
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
|
double rate = 1.0;
|
|
if (_renderer.valid() && _renderer->_mediaSeeking)
|
|
_renderer->_mediaSeeking->GetRate(&rate);
|
|
return rate;
|
|
}
|
|
|
|
void DirectShowImageStream::stop()
|
|
{
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
|
if (!_renderer.valid())
|
|
return;
|
|
if (!_renderer->StopFilters())
|
|
osg::notify(osg::WARN) << this << " cant stop filters" << std::endl;
|
|
|
|
_renderer->releaseRessources();
|
|
// Enumerate the filters in the graph.
|
|
IEnumFilters *pEnum = NULL;
|
|
IGraphBuilder* gb = _renderer->getGraphBuilder();
|
|
if (!gb)
|
|
return;
|
|
HRESULT hr = gb->EnumFilters(&pEnum);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IBaseFilter *pFilter = NULL;
|
|
while (S_OK == pEnum->Next(1, &pFilter, NULL))
|
|
{
|
|
// Remove the filter.
|
|
gb->RemoveFilter(pFilter);
|
|
// Reset the enumerator.
|
|
pEnum->Reset();
|
|
pFilter->Release();
|
|
}
|
|
pEnum->Release();
|
|
}
|
|
if (gb) gb->Release(); gb = 0;
|
|
_renderer = 0;
|
|
}
|