├── .gitignore
├── EtLib.dll
├── README.md
├── TouchPlusLib.sln
├── TouchPlusLib.vcxproj
├── TouchPlusLib.vcxproj.filters
├── curllib.dll
├── eSPAEAWBCtrl.dll
├── eSPDI.dll
├── jpeg62.dll
├── libeay32.dll
├── libsasl.dll
├── libssl32.dll
├── libusb-1.0.dll
├── libusb0.dll
├── nuron.dll
├── opencv_calib3d248.dll
├── opencv_core248.dll
├── opencv_features2d248.dll
├── opencv_flann248.dll
├── opencv_gpu248.dll
├── opencv_highgui248.dll
├── opencv_imgproc248.dll
├── opencv_ml248.dll
├── opencv_nonfree248.dll
├── opencv_objdetect248.dll
├── opencv_ocl248.dll
├── opencv_video248.dll
├── openldap.dll
├── padlock.dll
├── pthreadGC2.dll
├── pthreadGCE2.dll
├── pthreadVC2.dll
├── pthreadVSE2.dll
├── src
├── DSVideoCapture.cpp
├── DSVideoCapture.h
├── Main.cpp
├── TouchPlus.h
└── qedit.h
├── ssleay32.dll
├── turbojpeg.dll
└── uvc.dll
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # Build results
11 | [Dd]ebug/
12 | [Dd]ebugPublic/
13 | [Rr]elease/
14 | [Rr]eleases/
15 | x64/
16 | x86/
17 | build/
18 | bld/
19 | [Bb]in/
20 | [Oo]bj/
21 |
22 | # Roslyn cache directories
23 | *.ide/
24 |
25 | # MSTest test Results
26 | [Tt]est[Rr]esult*/
27 | [Bb]uild[Ll]og.*
28 |
29 | #NUNIT
30 | *.VisualState.xml
31 | TestResult.xml
32 |
33 | # Build Results of an ATL Project
34 | [Dd]ebugPS/
35 | [Rr]eleasePS/
36 | dlldata.c
37 |
38 | *_i.c
39 | *_p.c
40 | *_i.h
41 | *.ilk
42 | *.meta
43 | *.obj
44 | *.pch
45 | *.pdb
46 | *.pgc
47 | *.pgd
48 | *.rsp
49 | *.sbr
50 | *.tlb
51 | *.tli
52 | *.tlh
53 | *.tmp
54 | *.tmp_proj
55 | *.log
56 | *.vspscc
57 | *.vssscc
58 | .builds
59 | *.pidb
60 | *.svclog
61 | *.scc
62 |
63 | # Chutzpah Test files
64 | _Chutzpah*
65 |
66 | # Visual C++ cache files
67 | ipch/
68 | *.aps
69 | *.ncb
70 | *.opensdf
71 | *.sdf
72 | *.cachefile
73 |
74 | # Visual Studio profiler
75 | *.psess
76 | *.vsp
77 | *.vspx
78 |
79 | # TFS 2012 Local Workspace
80 | $tf/
81 |
82 | # Guidance Automation Toolkit
83 | *.gpState
84 |
85 | # ReSharper is a .NET coding add-in
86 | _ReSharper*/
87 | *.[Rr]e[Ss]harper
88 | *.DotSettings.user
89 |
90 | # JustCode is a .NET coding addin-in
91 | .JustCode
92 |
93 | # TeamCity is a build add-in
94 | _TeamCity*
95 |
96 | # DotCover is a Code Coverage Tool
97 | *.dotCover
98 |
99 | # NCrunch
100 | _NCrunch_*
101 | .*crunch*.local.xml
102 |
103 | # MightyMoose
104 | *.mm.*
105 | AutoTest.Net/
106 |
107 | # Web workbench (sass)
108 | .sass-cache/
109 |
110 | # Installshield output folder
111 | [Ee]xpress/
112 |
113 | # DocProject is a documentation generator add-in
114 | DocProject/buildhelp/
115 | DocProject/Help/*.HxT
116 | DocProject/Help/*.HxC
117 | DocProject/Help/*.hhc
118 | DocProject/Help/*.hhk
119 | DocProject/Help/*.hhp
120 | DocProject/Help/Html2
121 | DocProject/Help/html
122 |
123 | # Click-Once directory
124 | publish/
125 |
126 | # Publish Web Output
127 | *.[Pp]ublish.xml
128 | *.azurePubxml
129 | # TODO: Comment the next line if you want to checkin your web deploy settings
130 | # but database connection strings (with potential passwords) will be unencrypted
131 | *.pubxml
132 | *.publishproj
133 |
134 | # NuGet Packages
135 | *.nupkg
136 | # The packages folder can be ignored because of Package Restore
137 | **/packages/*
138 | # except build/, which is used as an MSBuild target.
139 | !**/packages/build/
140 | # If using the old MSBuild-Integrated Package Restore, uncomment this:
141 | #!**/packages/repositories.config
142 |
143 | # Windows Azure Build Output
144 | csx/
145 | *.build.csdef
146 |
147 | # Windows Store app package directory
148 | AppPackages/
149 |
150 | # Others
151 | sql/
152 | *.Cache
153 | ClientBin/
154 | [Ss]tyle[Cc]op.*
155 | ~$*
156 | *~
157 | *.dbmdl
158 | *.dbproj.schemaview
159 | *.pfx
160 | *.publishsettings
161 | node_modules/
162 | bower_components/
163 |
164 | # RIA/Silverlight projects
165 | Generated_Code/
166 |
167 | # Backup & report files from converting an old project file
168 | # to a newer Visual Studio version. Backup files are not needed,
169 | # because we have git ;-)
170 | _UpgradeReport_Files/
171 | Backup*/
172 | UpgradeLog*.XML
173 | UpgradeLog*.htm
174 |
175 | # SQL Server files
176 | *.mdf
177 | *.ldf
178 |
179 | # Business Intelligence projects
180 | *.rdl.data
181 | *.bim.layout
182 | *.bim_*.settings
183 |
184 | # Microsoft Fakes
185 | FakesAssemblies/
--------------------------------------------------------------------------------
/EtLib.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/EtLib.dll
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | TouchPlusLib
2 | ============
3 |
4 | Code to access video stream for Ractiv Touch+
5 |
--------------------------------------------------------------------------------
/TouchPlusLib.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TouchPlusLib", "TouchPlusLib.vcxproj", "{79C8312E-E2F2-42F8-BA21-1EDA2EA77E76}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Win32 = Debug|Win32
9 | Release|Win32 = Release|Win32
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {79C8312E-E2F2-42F8-BA21-1EDA2EA77E76}.Debug|Win32.ActiveCfg = Debug|Win32
13 | {79C8312E-E2F2-42F8-BA21-1EDA2EA77E76}.Debug|Win32.Build.0 = Debug|Win32
14 | {79C8312E-E2F2-42F8-BA21-1EDA2EA77E76}.Release|Win32.ActiveCfg = Release|Win32
15 | {79C8312E-E2F2-42F8-BA21-1EDA2EA77E76}.Release|Win32.Build.0 = Release|Win32
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/TouchPlusLib.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | {79C8312E-E2F2-42F8-BA21-1EDA2EA77E76}
24 | Win32Proj
25 | RactivTest2
26 |
27 |
28 |
29 | Application
30 | true
31 | v110
32 | Unicode
33 |
34 |
35 | Application
36 | false
37 | v110
38 | true
39 | Unicode
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | true
53 |
54 |
55 | false
56 |
57 |
58 |
59 |
60 |
61 | Level3
62 | Disabled
63 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
64 | E:\ImageAnalysis\opencv\build\include;C:\Program Files %28x86%29\Windows Kits\8.0\Include;E:\Programming\libuvc\include;E:\Programming\libusb-1.0;%(AdditionalIncludeDirectories)
65 |
66 |
67 | Console
68 | true
69 | E:\ImageAnalysis\opencv\build\lib\Debug;E:\Programming\libusb-win32-bin-1.2.6.0\lib\msvc;%(AdditionalLibraryDirectories)
70 | libusb.lib;opencv_stitching248d.lib;opencv_contrib248d.lib;opencv_videostab248d.lib;opencv_superres248d.lib;opencv_nonfree248d.lib;opencv_gpu248d.lib;opencv_ocl248d.lib;opencv_legacy248d.lib;opencv_ts248d.lib;opencv_calib3d248d.lib;opencv_features2d248d.lib;opencv_objdetect248d.lib;opencv_highgui248d.lib;opencv_video248d.lib;opencv_photo248d.lib;opencv_imgproc248d.lib;opencv_flann248d.lib;opencv_ml248d.lib;opencv_core248d.lib;%(AdditionalDependencies)
71 |
72 |
73 |
74 |
75 | Level3
76 |
77 |
78 | MaxSpeed
79 | true
80 | true
81 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
82 |
83 |
84 | Console
85 | true
86 | true
87 | true
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/TouchPlusLib.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 |
26 |
27 | Source Files
28 |
29 |
30 | Source Files
31 |
32 |
33 | Source Files
34 |
35 |
36 |
--------------------------------------------------------------------------------
/curllib.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/curllib.dll
--------------------------------------------------------------------------------
/eSPAEAWBCtrl.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/eSPAEAWBCtrl.dll
--------------------------------------------------------------------------------
/eSPDI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/eSPDI.dll
--------------------------------------------------------------------------------
/jpeg62.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/jpeg62.dll
--------------------------------------------------------------------------------
/libeay32.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/libeay32.dll
--------------------------------------------------------------------------------
/libsasl.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/libsasl.dll
--------------------------------------------------------------------------------
/libssl32.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/libssl32.dll
--------------------------------------------------------------------------------
/libusb-1.0.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/libusb-1.0.dll
--------------------------------------------------------------------------------
/libusb0.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/libusb0.dll
--------------------------------------------------------------------------------
/nuron.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/nuron.dll
--------------------------------------------------------------------------------
/opencv_calib3d248.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/opencv_calib3d248.dll
--------------------------------------------------------------------------------
/opencv_core248.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/opencv_core248.dll
--------------------------------------------------------------------------------
/opencv_features2d248.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/opencv_features2d248.dll
--------------------------------------------------------------------------------
/opencv_flann248.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/opencv_flann248.dll
--------------------------------------------------------------------------------
/opencv_gpu248.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/opencv_gpu248.dll
--------------------------------------------------------------------------------
/opencv_highgui248.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/opencv_highgui248.dll
--------------------------------------------------------------------------------
/opencv_imgproc248.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/opencv_imgproc248.dll
--------------------------------------------------------------------------------
/opencv_ml248.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/opencv_ml248.dll
--------------------------------------------------------------------------------
/opencv_nonfree248.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/opencv_nonfree248.dll
--------------------------------------------------------------------------------
/opencv_objdetect248.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/opencv_objdetect248.dll
--------------------------------------------------------------------------------
/opencv_ocl248.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/opencv_ocl248.dll
--------------------------------------------------------------------------------
/opencv_video248.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/opencv_video248.dll
--------------------------------------------------------------------------------
/openldap.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/openldap.dll
--------------------------------------------------------------------------------
/padlock.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/padlock.dll
--------------------------------------------------------------------------------
/pthreadGC2.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/pthreadGC2.dll
--------------------------------------------------------------------------------
/pthreadGCE2.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/pthreadGCE2.dll
--------------------------------------------------------------------------------
/pthreadVC2.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/pthreadVC2.dll
--------------------------------------------------------------------------------
/pthreadVSE2.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/pthreadVSE2.dll
--------------------------------------------------------------------------------
/src/DSVideoCapture.cpp:
--------------------------------------------------------------------------------
1 | #include "DSVideoCapture.h"
2 |
3 | //change this macro to fit your style of error handling
4 | #define CHECK_HR(hr, msg) if (hrcheck(hr, msg)) return hr;
5 |
6 | BOOL hrcheck(HRESULT hr, TCHAR* errtext)
7 | {
8 | if (hr >= S_OK)
9 | return FALSE;
10 |
11 | printf("Error %x: %s\n", hr, errtext);
12 |
13 | return TRUE;
14 | }
15 |
16 | CComPtr DSVideoCapture::GetPin(IBaseFilter *pFilter, LPCOLESTR pinname)
17 | {
18 | IEnumPins *pEnum = NULL;
19 | CComPtr pPin;
20 |
21 | HRESULT hr = pFilter->EnumPins(&pEnum);
22 | if (hrcheck(hr, L"Can't enumerate pins."))
23 | return NULL;
24 |
25 | while(pEnum->Next(1, &pPin, 0) == S_OK)
26 | {
27 | PIN_INFO pinfo;
28 | pPin->QueryPinInfo(&pinfo);
29 | BOOL found = !_wcsicmp(pinname, pinfo.achName);
30 |
31 | if (pinfo.pFilter) pinfo.pFilter->Release();
32 |
33 | if (found)
34 | return pPin;
35 |
36 | pPin.Release();
37 | }
38 | printf("Pin not found!\n");
39 | return NULL;
40 | }
41 |
42 | HRESULT DSVideoCapture::EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
43 | {
44 | // Create the System Device Enumerator.
45 | ICreateDevEnum *pDevEnum;
46 | HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
47 | CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
48 |
49 | if (SUCCEEDED(hr))
50 | {
51 | // Create an enumerator for the category.
52 | hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);
53 | if (hr == S_FALSE)
54 | {
55 | hr = VFW_E_NOT_FOUND; // The category is empty. Treat as an error.
56 | }
57 | pDevEnum->Release();
58 | }
59 | return hr;
60 | }
61 |
62 |
63 | IBaseFilter* DSVideoCapture::FindTouchFilter(IEnumMoniker *pEnum)
64 | {
65 | IMoniker *pMoniker = NULL;
66 |
67 | while (pEnum->Next(1, &pMoniker, NULL) == S_OK)
68 | {
69 | IPropertyBag *pPropBag;
70 | HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
71 | if (FAILED(hr))
72 | {
73 | pMoniker->Release();
74 | continue;
75 | }
76 |
77 | VARIANT var;
78 | VariantInit(&var);
79 |
80 | // Get description or friendly name.
81 | hr = pPropBag->Read(L"Description", &var, 0);
82 | if (FAILED(hr))
83 | {
84 | hr = pPropBag->Read(L"FriendlyName", &var, 0);
85 | }
86 | if (SUCCEEDED(hr))
87 | {
88 | if(0 == wcscmp(var.bstrVal, L"Touch+ Camera"))
89 | {
90 | printf("Found Touch+ Camera\n");
91 |
92 | IBaseFilter *pCap = NULL;
93 | hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
94 |
95 | VariantClear(&var);
96 | pPropBag->Release();
97 | pMoniker->Release();
98 |
99 | return pCap;
100 | }
101 |
102 | printf("%S\n", var.bstrVal);
103 | VariantClear(&var);
104 | }
105 |
106 | hr = pPropBag->Write(L"FriendlyName", &var);
107 |
108 | // WaveInID applies only to audio capture devices.
109 | hr = pPropBag->Read(L"WaveInID", &var, 0);
110 | if (SUCCEEDED(hr))
111 | {
112 | printf("WaveIn ID: %d\n", var.lVal);
113 | VariantClear(&var);
114 | }
115 |
116 | hr = pPropBag->Read(L"DevicePath", &var, 0);
117 | if (SUCCEEDED(hr))
118 | {
119 | // The device path is not intended for display.
120 | printf("Device path: %S\n", var.bstrVal);
121 | VariantClear(&var);
122 | }
123 |
124 | pPropBag->Release();
125 | pMoniker->Release();
126 | }
127 |
128 | return false;
129 | }
130 |
131 | HRESULT DSVideoCapture::BuildGraph(IGraphBuilder *pGraph)
132 | {
133 | HRESULT hr = S_OK;
134 |
135 | CComPtr pTouchCamera;
136 | CComPtr pSampleGrabberF;
137 |
138 | IEnumMoniker *pEnum;
139 |
140 | //graph builder
141 | CComPtr pBuilder;
142 | hr = pBuilder.CoCreateInstance(CLSID_CaptureGraphBuilder2);
143 | CHECK_HR(hr, L"Can't create Capture Graph Builder");
144 | hr = pBuilder->SetFiltergraph(pGraph);
145 | CHECK_HR(hr, L"Can't SetFiltergraph");
146 |
147 | //add Touch+ Camera
148 | hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
149 | if (SUCCEEDED(hr))
150 | {
151 | pTouchCamera = FindTouchFilter(pEnum);
152 | pEnum->Release();
153 | }
154 |
155 | hr = pGraph->AddFilter(pTouchCamera, L"Touch+ Camera");
156 | CHECK_HR(hr, L"Can't add Touch+ Camera to graph");
157 |
158 | //add SampleGrabber
159 | // Initialize core variables
160 | hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSampleGrabberF));
161 | CHECK_HR(hr, L"Can't create SampleGrabber");
162 | hr = pSampleGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&pSampleGrabber);
163 | CHECK_HR(hr, L"Can't get SampleGrabber from filter");
164 |
165 | // Setup media format
166 | AM_MEDIA_TYPE pSampleGrabber_pmt;
167 | ZeroMemory(&pSampleGrabber_pmt, sizeof(AM_MEDIA_TYPE));
168 | pSampleGrabber_pmt.majortype = MEDIATYPE_Video;
169 | pSampleGrabber_pmt.subtype = MEDIASUBTYPE_RGB24;
170 | pSampleGrabber_pmt.formattype = FORMAT_VideoInfo;
171 | pSampleGrabber_pmt.bFixedSizeSamples = TRUE;
172 | pSampleGrabber_pmt.cbFormat = 88;
173 | pSampleGrabber_pmt.lSampleSize = 2457600;
174 | pSampleGrabber_pmt.bTemporalCompression = FALSE;
175 | VIDEOINFOHEADER pSampleGrabber_format;
176 | ZeroMemory(&pSampleGrabber_format, sizeof(VIDEOINFOHEADER));
177 | pSampleGrabber_format.dwBitRate = 1179652719;
178 | pSampleGrabber_format.AvgTimePerFrame = 166666;
179 | pSampleGrabber_format.bmiHeader.biSize = 40;
180 | pSampleGrabber_format.bmiHeader.biWidth = 1280;
181 | pSampleGrabber_format.bmiHeader.biHeight = 480;
182 | pSampleGrabber_format.bmiHeader.biPlanes = 1;
183 | pSampleGrabber_format.bmiHeader.biBitCount = 24;
184 | pSampleGrabber_format.bmiHeader.biSizeImage = 2457600;
185 | pSampleGrabber_pmt.pbFormat = (BYTE*)&pSampleGrabber_format;
186 |
187 |
188 | AM_MEDIA_TYPE pCam_pmt;
189 | ZeroMemory(&pCam_pmt, sizeof(AM_MEDIA_TYPE));
190 | pCam_pmt.majortype = MEDIATYPE_Video;
191 | pCam_pmt.subtype = MEDIASUBTYPE_MJPG;
192 | pCam_pmt.formattype = FORMAT_VideoInfo;
193 | pCam_pmt.bFixedSizeSamples = TRUE;
194 | pCam_pmt.cbFormat = 88;
195 | pCam_pmt.lSampleSize = 1843200;
196 | pCam_pmt.bTemporalCompression = FALSE;
197 | VIDEOINFOHEADER pCamFmt;
198 | ZeroMemory(&pCamFmt, sizeof(VIDEOINFOHEADER));
199 | pCamFmt.dwBitRate = 884736000;
200 | pCamFmt.AvgTimePerFrame = 166666;
201 | pCamFmt.bmiHeader.biSize = 40;
202 | pCamFmt.bmiHeader.biWidth = 1280;
203 | pCamFmt.bmiHeader.biHeight = 480;
204 | pCamFmt.bmiHeader.biPlanes = 1;
205 | pCamFmt.bmiHeader.biBitCount = 24;
206 | pCamFmt.bmiHeader.biCompression = 1196444237;
207 | pCamFmt.bmiHeader.biSizeImage = 1843200;
208 | pCam_pmt.pbFormat = (BYTE*)&pCamFmt;
209 |
210 | // Get pins for sample grabber and camera
211 | CComPtr camPin = GetPin(pTouchCamera, L"Capture");
212 | CComPtr sampleInput = GetPin(pSampleGrabberF, L"Input");
213 | CComPtr sampleOutput = GetPin(pSampleGrabberF, L"Output");
214 |
215 | // Set media type for sample grabber and camera
216 | hr = pSampleGrabber->SetMediaType(&pSampleGrabber_pmt);
217 | CHECK_HR(hr, L"Can't set media type to sample grabber");
218 |
219 | pSampleGrabber->SetBufferSamples( TRUE );
220 |
221 |
222 | CComQIPtr camConfig(camPin);
223 | hr = camConfig->SetFormat(&pCam_pmt);
224 | CHECK_HR(hr, L"Can't set camera pin format");
225 |
226 |
227 | // Add sample grabber filter
228 | hr = pGraph->AddFilter(pSampleGrabberF, L"SampleGrabber");
229 | CHECK_HR(hr, L"Can't add SampleGrabber to graph");
230 |
231 |
232 |
233 | printf("add MJPEG Decompressor\n");
234 | //add MJPEG Decompressor
235 | CComPtr pMJPEGDecompressor;
236 | hr = pMJPEGDecompressor.CoCreateInstance(CLSID_MjpegDec);
237 | CHECK_HR(hr, L"Can't create MJPEG Decompressor");
238 | hr = pGraph->AddFilter(pMJPEGDecompressor, L"MJPEG Decompressor");
239 |
240 | CHECK_HR(hr, L"Can't add MJPEG Decompressor to graph");
241 | //connect SampleGrabber and MJPEG Decompressor
242 |
243 | //connect Touch+ Camera and SampleGrabber
244 | hr = pGraph->ConnectDirect(camPin, GetPin(pMJPEGDecompressor, L"XForm In"), NULL);
245 | CHECK_HR(hr, L"Can't connect Touch+ Camera and SampleGrabber");
246 |
247 | hr = pGraph->ConnectDirect(GetPin(pMJPEGDecompressor, L"XForm Out"), sampleInput, NULL);
248 | CHECK_HR(hr, L"Can't connect SampleGrabber and MJPEG Decompressor");
249 |
250 | //add Video Renderer
251 | CComPtr pVideoRenderer;
252 | //hr = pVideoRenderer.CoCreateInstance(CLSID_VideoRenderer);
253 | hr = pVideoRenderer.CoCreateInstance(CLSID_NullRenderer);
254 | CHECK_HR(hr, L"Can't create Video Renderer");
255 | hr = pGraph->AddFilter(pVideoRenderer, L"Video Renderer");
256 | CHECK_HR(hr, L"Can't add Video Renderer to graph");
257 |
258 | hr = pGraph->ConnectDirect(sampleOutput, GetPin(pVideoRenderer, L"In"), NULL);
259 |
260 | VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER *)pSampleGrabber_pmt.pbFormat;
261 |
262 | // STEP18: Copy the BMP infomation to BITMAPINFO structure
263 | ZeroMemory( &bitmapInfo, sizeof(bitmapInfo) );
264 | CopyMemory( &bitmapInfo.bmiHeader, &(pVideoHeader->bmiHeader), sizeof(BITMAPINFOHEADER) );
265 |
266 | printf ("Built Filter graph successfully\n");
267 |
268 | return S_OK;
269 | }
270 |
271 | HRESULT DSVideoCapture::Start()
272 | {
273 | HRESULT hr;
274 |
275 | bSize = 0;
276 |
277 | CoInitialize(NULL);
278 |
279 | CComPtr graph;
280 | graph.CoCreateInstance(CLSID_FilterGraph);
281 | printf("Building graph...\n");
282 |
283 | hr = BuildGraph(graph);
284 | CHECK_HR(hr, L"Can't run the graph");
285 | if (hr==S_OK)
286 | {
287 | printf("Running\n");
288 | CComQIPtr mediaControl(graph);
289 | hr = mediaControl->Run();
290 |
291 | mediaEvent = CComQIPtr(graph);
292 |
293 | initSuccess = true;
294 |
295 | return S_OK;
296 | }
297 | }
298 |
299 | bool DSVideoCapture::GrabFrame(long* frameData)
300 | {
301 | if (initSuccess)
302 | {
303 | // Update Camera Input
304 | long ev=0, p1=0, p2=0;
305 | Sleep(50);
306 | printf(".");
307 | while(PeekMessage(&msg, NULL, 0,0, PM_REMOVE))
308 | DispatchMessage(&msg);
309 | while (mediaEvent->GetEvent(&ev, &p1, &p2, 0)==S_OK)
310 | if (ev == EC_COMPLETE || ev == EC_USERABORT)
311 | {
312 | printf("Done!\n");
313 | stop = TRUE;
314 | }
315 | else if (ev == EC_ERRORABORT)
316 | {
317 | printf("An error occured: HRESULT=%x\n", p1);
318 | mediaControl->Stop();
319 | stop = TRUE;
320 | }
321 | mediaEvent->FreeEventParams(ev, p1, p2);
322 |
323 | if (bSize == 0)
324 | {
325 | // Try to get current buffer size
326 | pSampleGrabber->GetCurrentBuffer(&bSize, NULL);
327 |
328 | // If the buffer is null return
329 | if (bSize == 0)
330 | return false;
331 | }
332 |
333 | HRESULT hr = pSampleGrabber->GetCurrentBuffer( &bSize, (long*)frameData);
334 |
335 | return true;
336 | }
337 | else
338 | return false;
339 | }
340 |
341 | void DSVideoCapture::Finish()
342 | {
343 | printf("Finishing");
344 |
345 | mediaControl->Stop();
346 | CoUninitialize();
347 | }
348 |
349 | int DSVideoCapture::GetSampleWidth()
350 | {
351 | return bitmapInfo.bmiHeader.biWidth;
352 | }
353 |
354 | int DSVideoCapture::GetSampleHeight()
355 | {
356 | return bitmapInfo.bmiHeader.biHeight;
357 | }
358 |
359 | int DSVideoCapture::GetSampleChannels()
360 | {
361 | return bitmapInfo.bmiHeader.biBitCount / 8;
362 | }
363 |
--------------------------------------------------------------------------------
/src/DSVideoCapture.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma comment(lib, "strmiids")
3 | //#pragma comment(linker, "/alternatename:_pWeakValue=_pDefaultWeakValue")
4 |
5 | #include
6 | #include
7 | #include
8 | #include "qedit.h"
9 | #include
10 |
11 | class __declspec(uuid("6B652FFF-11FE-4fce-92AD-0266B5D7C78F")) SampleGrabber;
12 | class __declspec(uuid("0579154A-2B53-4994-B0D0-E773148EFF85")) SampleGrabberCB;
13 |
14 | //class __declspec(uuid("17CCA71B-ECD7-11D0-B908-00A0C9223196")) CLSID_TouchCamera;
15 | //class __declspec(uuid("C1F400A0-3F08-11D3-9F0B-006008039E37")) CLSID_SampleGrabber;
16 | //class __declspec(uuid("B87BEB7B-8D29-423F-AE4D-6582C10175AC")) CLSID_VideoRenderer;
17 |
18 | //{17CCA71B-ECD7-11D0-B908-00A0C9223196}
19 |
20 | DEFINE_GUID(CLSID_TouchCamera, 0x17CCA71B, 0xECD7, 0x11D0, 0xB9, 0x08, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96); //ksproxy.ax
21 |
22 | //{C1F400A0-3F08-11D3-9F0B-006008039E37}
23 | DEFINE_GUID(CLSID_SampleGrabber2, 0xC1F400A0, 0x3F08, 0x11D3, 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37); //qedit.dll
24 |
25 | //{B87BEB7B-8D29-423F-AE4D-6582C10175AC}
26 | DEFINE_GUID(CLSID_VideoRenderer, 0xB87BEB7B, 0x8D29, 0x423F, 0xAE, 0x4D, 0x65, 0x82, 0xC1, 0x01, 0x75, 0xAC); //quartz.dll
27 |
28 |
29 | class DSVideoCapture
30 | {
31 | public:
32 | HRESULT Start();
33 | bool GrabFrame(long* byteData);
34 | void Finish();
35 |
36 | int GetSampleWidth();
37 | int GetSampleHeight();
38 | int GetSampleChannels();
39 |
40 |
41 | private:
42 | HRESULT BuildGraph(IGraphBuilder *pGraph);
43 |
44 | CComPtr GetPin(IBaseFilter *pFilter, LPCOLESTR pinname);
45 |
46 | HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum);
47 | IBaseFilter* FindTouchFilter(IEnumMoniker *pEnum);
48 |
49 | // Members
50 | BITMAPINFO bitmapInfo;
51 | bool initSuccess;
52 | CComPtr pSampleGrabber;
53 | CComQIPtr mediaControl;
54 |
55 | CComQIPtr mediaEvent;
56 |
57 | // Window Parameters
58 | long bSize;
59 | bool stop;
60 | MSG msg;
61 | };
--------------------------------------------------------------------------------
/src/Main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "DSVideoCapture.h"
3 | #include "TouchPlus.h"
4 |
5 | #include "opencv2\highgui\highgui.hpp"
6 | #include "opencv2\opencv.hpp"
7 |
8 | using namespace cv;
9 |
10 | int main()
11 | {
12 | if (!UnlockSoftware())
13 | printf("Failed to unlock\n");
14 |
15 | DSVideoCapture* vc = new DSVideoCapture();
16 | vc->Start();
17 |
18 | int height = vc->GetSampleHeight();
19 | int width = vc->GetSampleWidth();
20 | int channels = vc->GetSampleChannels();
21 | Mat frame = Mat(height, width, CV_8UC3);
22 |
23 | assert(frame.isContinuous());
24 |
25 | Mat frameL, frameR;
26 |
27 | while (1)
28 | {
29 | cvWaitKey(10);
30 | vc->GrabFrame((long*)frame.data);
31 |
32 | frameL = Mat(frame, Rect(0,0,width/2,height));
33 | frameR = Mat(frame, Rect(width/2,0,width/2,height));
34 |
35 | imshow( "FrameL", frameL );
36 | imshow( "FrameR", frameR );
37 | }
38 |
39 | vc->Finish();
40 | lockDevice(0);
41 |
42 | return 0;
43 | }
--------------------------------------------------------------------------------
/src/TouchPlus.h:
--------------------------------------------------------------------------------
1 |
2 | #include "DSVideoCapture.h"
3 |
4 | typedef int (CALLBACK* SPAEWB_EnumDevice)(int* param);
5 | typedef int (CALLBACK* SPAEWB_GetDeviceName)(int id, char* name, char* data);
6 | typedef int (CALLBACK* SPAEWB_SelectDevice)(int param);
7 | typedef int (CALLBACK* SPAEWB_UnlockDevice)(int param);
8 | typedef int (CALLBACK* SPAEWB_LockDevice)(int param);
9 | typedef int (CALLBACK* SPAEWB_SetSensorType)(int type);
10 | typedef int (CALLBACK* SPAEWB_DisableAE)();
11 | typedef int (CALLBACK* SPAEWB_DisableAWB)();
12 |
13 | SPAEWB_EnumDevice enumDevice; // Function pointer
14 | SPAEWB_GetDeviceName getDeviceName; // Function pointer
15 | SPAEWB_SelectDevice selectDevice; // Function pointer
16 | SPAEWB_UnlockDevice unlockDevice; // Function pointer
17 | SPAEWB_LockDevice lockDevice; // Function pointer
18 | SPAEWB_SetSensorType setSensorType;
19 | SPAEWB_DisableAE disableAE;
20 | SPAEWB_DisableAWB disableAWB;
21 |
22 | bool InitSPAEAWB()
23 | {
24 | HINSTANCE hDLL; // Handle to DLL
25 |
26 | hDLL = LoadLibrary(L"eSPAEAWBCtrl");
27 | if (hDLL != NULL)
28 | {
29 | enumDevice = (SPAEWB_EnumDevice)GetProcAddress(hDLL,
30 | "_eSPAEAWB_EnumDevice@4");
31 |
32 | getDeviceName = (SPAEWB_GetDeviceName)GetProcAddress(hDLL,
33 | "_eSPAEAWB_GetDevicename@12");
34 |
35 | selectDevice = (SPAEWB_SelectDevice)GetProcAddress(hDLL,
36 | "_eSPAEAWB_SelectDevice@4");
37 |
38 | unlockDevice = (SPAEWB_UnlockDevice)GetProcAddress(hDLL,
39 | "_eSPAEAWB_SWUnlock@4");
40 |
41 | lockDevice = (SPAEWB_LockDevice)GetProcAddress(hDLL,
42 | "_eSPAEAWB_SWLock@4");
43 |
44 | setSensorType = (SPAEWB_SetSensorType)GetProcAddress(hDLL,
45 | "_eSPAEAWB_SetSensorType@4");
46 |
47 | disableAE = (SPAEWB_DisableAE)GetProcAddress(hDLL,
48 | "_eSPAEAWB_DisableAE@0");
49 |
50 | disableAWB = (SPAEWB_DisableAWB)GetProcAddress(hDLL,
51 | "_eSPAEAWB_DisableAWB@0");
52 |
53 | if (!enumDevice || !getDeviceName || !selectDevice || !unlockDevice ||!lockDevice ||!setSensorType || !disableAE || !disableAWB)
54 | {
55 | // handle the error
56 | FreeLibrary(hDLL);
57 | printf("Error opening eSPAEAWBCtrl\n");
58 | }
59 | else
60 | return true;
61 | }
62 | else
63 | printf("Failed opening eSPDI.dll\n");
64 |
65 | return false;
66 | }
67 |
68 |
69 | typedef void* (WINAPIV* SPDI_Init)(void *ptr);
70 | typedef int (WINAPIV* SPDI_GetDeviceNumber)(void* ptr);
71 | typedef int (WINAPIV* SPDI_FindDevice)(void* ptr, int id);
72 |
73 | SPDI_Init spdi_init; // Function pointer
74 | SPDI_GetDeviceNumber spdi_getDeviceNumber; // Function pointer
75 | SPDI_FindDevice spdi_findDevice; // Function pointer
76 |
77 | bool InitSPDI()
78 | {
79 | HINSTANCE hDLL; // Handle to DLL
80 |
81 | hDLL = LoadLibrary(L"eSPDI.dll");
82 | if (hDLL != NULL)
83 | {
84 | spdi_init = (SPDI_Init)GetProcAddress(hDLL,
85 | "EtronDI_Init");
86 |
87 | spdi_getDeviceNumber = (SPDI_GetDeviceNumber)GetProcAddress(hDLL,
88 | "EtronDI_GetDeviceNumber");
89 |
90 | spdi_findDevice = (SPDI_FindDevice)GetProcAddress(hDLL,
91 | "EtronDI_FindDevice");
92 |
93 | if (!spdi_init || !spdi_getDeviceNumber || !spdi_findDevice)
94 | {
95 | // handle the error
96 | FreeLibrary(hDLL);
97 | printf("Error opening SPDI\n");
98 | }
99 | else
100 | return true;
101 | }
102 | else
103 | printf("Failed opening eSPDI.dll\n");
104 |
105 | return false;
106 | }
107 |
108 | void* passPtr = 0;
109 |
110 | bool UnlockSoftware()
111 | {
112 | printf("Sizes: int %i char %i bool %i short %i pointer %i\n", sizeof(int), sizeof(char), sizeof(bool), sizeof(short), sizeof(void*));
113 |
114 | int result = 0;
115 |
116 | if (!InitSPAEAWB())
117 | return false;
118 |
119 | if (!InitSPDI())
120 | return false;
121 |
122 | printf("Loaded libraries\n");
123 |
124 | int deviceCount;
125 |
126 | void* temp;
127 | spdi_init(&passPtr);
128 | printf("spdi_init %i\n", result);
129 |
130 |
131 | deviceCount = spdi_getDeviceNumber(passPtr);
132 | printf("spdi_getDeviceNumber %i\n", deviceCount);
133 | result = spdi_findDevice(passPtr, deviceCount);
134 | printf("spdi_findDevice %i\n", result);
135 |
136 | int numDevices = 0;
137 | // call the function
138 | int ret = enumDevice(&numDevices);
139 |
140 |
141 | printf("Found %i devices - Return %i\n", numDevices, ret);
142 | for (int i=0;i // for IMediaSample
11 |
12 | ///////////////////////////////////////////////////////////////////////////////////
13 |
14 | interface ISampleGrabberCB : public IUnknown
15 | {
16 | virtual STDMETHODIMP SampleCB( double SampleTime, IMediaSample *pSample ) = 0;
17 | virtual STDMETHODIMP BufferCB( double SampleTime, BYTE *pBuffer, long BufferLen ) = 0;
18 | };
19 |
20 | ///////////////////////////////////////////////////////////////////////////////////
21 |
22 | static
23 | const
24 | IID IID_ISampleGrabberCB = { 0x0579154A, 0x2B53, 0x4994, { 0xB0, 0xD0, 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85 } };
25 |
26 | ///////////////////////////////////////////////////////////////////////////////////
27 |
28 | interface
29 | ISampleGrabber
30 | :
31 | public IUnknown
32 | {
33 | virtual HRESULT STDMETHODCALLTYPE SetOneShot( BOOL OneShot ) = 0;
34 | virtual HRESULT STDMETHODCALLTYPE SetMediaType( const AM_MEDIA_TYPE *pType ) = 0;
35 | virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType( AM_MEDIA_TYPE *pType ) = 0;
36 | virtual HRESULT STDMETHODCALLTYPE SetBufferSamples( BOOL BufferThem ) = 0;
37 | virtual HRESULT STDMETHODCALLTYPE GetCurrentBuffer( long *pBufferSize, long *pBuffer ) = 0;
38 | virtual HRESULT STDMETHODCALLTYPE GetCurrentSample( IMediaSample **ppSample ) = 0;
39 | virtual HRESULT STDMETHODCALLTYPE SetCallback( ISampleGrabberCB *pCallback, long WhichMethodToCallback ) = 0;
40 | };
41 |
42 | ///////////////////////////////////////////////////////////////////////////////////
43 |
44 | static
45 | const
46 | IID IID_ISampleGrabber = { 0x6B652FFF, 0x11FE, 0x4fce, { 0x92, 0xAD, 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F } };
47 |
48 | ///////////////////////////////////////////////////////////////////////////////////
49 |
50 | static
51 | const
52 | CLSID CLSID_SampleGrabber = { 0xC1F400A0, 0x3F08, 0x11d3, { 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 } };
53 |
54 | ///////////////////////////////////////////////////////////////////////////////////
55 |
56 | static
57 | const
58 | CLSID CLSID_NullRenderer = { 0xC1F400A4, 0x3F08, 0x11d3, { 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 } };
59 |
60 | ///////////////////////////////////////////////////////////////////////////////////
61 |
62 | static
63 | const
64 | CLSID CLSID_VideoEffects1Category = { 0xcc7bfb42, 0xf175, 0x11d1, { 0xa3, 0x92, 0x0, 0xe0, 0x29, 0x1f, 0x39, 0x59 } };
65 |
66 | ///////////////////////////////////////////////////////////////////////////////////
67 |
68 | static
69 | const
70 | CLSID CLSID_VideoEffects2Category = { 0xcc7bfb43, 0xf175, 0x11d1, { 0xa3, 0x92, 0x0, 0xe0, 0x29, 0x1f, 0x39, 0x59 } };
71 |
72 | ///////////////////////////////////////////////////////////////////////////////////
73 |
74 | static
75 | const
76 | CLSID CLSID_AudioEffects1Category = { 0xcc7bfb44, 0xf175, 0x11d1, { 0xa3, 0x92, 0x0, 0xe0, 0x29, 0x1f, 0x39, 0x59 } };
77 |
78 | ///////////////////////////////////////////////////////////////////////////////////
79 |
80 | static
81 | const
82 | CLSID CLSID_AudioEffects2Category = { 0xcc7bfb45, 0xf175, 0x11d1, { 0xa3, 0x92, 0x0, 0xe0, 0x29, 0x1f, 0x39, 0x59 } };
83 |
84 | ///////////////////////////////////////////////////////////////////////////////////
85 |
86 | #endif
87 |
88 | ///////////////////////////////////////////////////////////////////////////////////
--------------------------------------------------------------------------------
/ssleay32.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/ssleay32.dll
--------------------------------------------------------------------------------
/turbojpeg.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/turbojpeg.dll
--------------------------------------------------------------------------------
/uvc.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umarniz/TouchPlusLib/176f2744a533f517b97b39274682adccefef6037/uvc.dll
--------------------------------------------------------------------------------