[154] | 1 | //////////////////////////////////////////////////////////// |
---|
| 2 | // Copyright (C) Roman Ryltsov, 2006-2012 |
---|
| 3 | // Created by Roman Ryltsov roman@alax.info |
---|
| 4 | // |
---|
| 5 | // A permission to use the source code is granted as long as reference to |
---|
| 6 | // source website http://alax.info is retained. |
---|
| 7 | |
---|
| 8 | #include "stdafx.h" |
---|
| 9 | #import "libid:1469D378-8829-4ff0-9B3B-07DD5B16F3CB" raw_interfaces_only // DecklinkPublicLib |
---|
| 10 | #include <windows.h> |
---|
| 11 | #include <dshow.h> |
---|
| 12 | #include <dvdmedia.h> // VIDEOINFOHEADER2 |
---|
| 13 | |
---|
| 14 | #pragma comment(lib, "strmiids.lib") |
---|
| 15 | |
---|
| 16 | inline VOID __C(HRESULT nResult) { ATLENSURE_SUCCEEDED(nResult); } |
---|
| 17 | inline VOID __D(BOOL bResult, HRESULT nResult) { ATLENSURE_THROW(bResult, nResult); } |
---|
| 18 | inline VOID __D(const VOID* pvResult, HRESULT nResult) { ATLENSURE_THROW(pvResult, nResult); } |
---|
| 19 | |
---|
| 20 | //#pragma pack(show) |
---|
| 21 | |
---|
| 22 | CString StringFromData(const BYTE* pnData, SIZE_T nDataSize) |
---|
| 23 | { |
---|
| 24 | CString sString; |
---|
| 25 | for(SIZE_T nIndex = 0; nIndex < nDataSize; nIndex++) |
---|
| 26 | sString.AppendFormat(_T("%02X "), pnData[nIndex]); |
---|
| 27 | sString.TrimRight(); |
---|
| 28 | return sString; |
---|
| 29 | } |
---|
| 30 | CString StringFromData(const VOID* pvData, SIZE_T nDataSize) |
---|
| 31 | { |
---|
| 32 | return StringFromData((const BYTE*) pvData, nDataSize); |
---|
| 33 | } |
---|
| 34 | CString StringFromCode(DWORD nCode) |
---|
| 35 | { |
---|
| 36 | // NOTE: More precisely, we need to compare each byte against 0x20, but this one is good enough too |
---|
| 37 | if(nCode < 0x20202020) |
---|
| 38 | return (LPCTSTR) NULL; |
---|
| 39 | TCHAR pszCode[] = |
---|
| 40 | { |
---|
| 41 | (nCode >> 0) & 0xFF, |
---|
| 42 | (nCode >> 8) & 0xFF, |
---|
| 43 | (nCode >> 16) & 0xFF, |
---|
| 44 | (nCode >> 24) & 0xFF, |
---|
| 45 | 0 |
---|
| 46 | }; |
---|
| 47 | return pszCode; |
---|
| 48 | } |
---|
| 49 | |
---|
| 50 | int _tmain(int argc, _TCHAR* argv[]) |
---|
| 51 | { |
---|
| 52 | _ATLTRY |
---|
| 53 | { |
---|
| 54 | __C(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); |
---|
| 55 | _ATLTRY |
---|
| 56 | { |
---|
| 57 | CComPtr<ICreateDevEnum> pCreateDevEnum; |
---|
| 58 | __C(pCreateDevEnum.CoCreateInstance(CLSID_SystemDeviceEnum)); |
---|
| 59 | CComPtr<IEnumMoniker> pEnumMoniker; |
---|
| 60 | __C(pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumMoniker, 0)); |
---|
| 61 | CComPtr<IMoniker> pMoniker; |
---|
| 62 | while(pEnumMoniker->Next(1, &pMoniker, NULL) == S_OK) |
---|
| 63 | { |
---|
| 64 | _ATLTRY |
---|
| 65 | { |
---|
| 66 | LPOLESTR pszDisplayName = NULL; |
---|
| 67 | ATLVERIFY(SUCCEEDED(pMoniker->GetDisplayName(NULL, NULL, &pszDisplayName))); |
---|
| 68 | // TODO: Free pszDisplayName |
---|
| 69 | if(pszDisplayName) |
---|
| 70 | _tprintf(_T("Moniker Display Name: %ls\n"), pszDisplayName); |
---|
| 71 | CComPtr<IPropertyBag> pPropertyBag; |
---|
| 72 | __C(pMoniker->BindToStorage(NULL, NULL, __uuidof(IPropertyBag), (VOID**) &pPropertyBag)); |
---|
| 73 | CComVariant vFriendlyName; |
---|
| 74 | __C(pPropertyBag->Read(L"FriendlyName", &vFriendlyName, NULL)); |
---|
| 75 | __D(vFriendlyName.vt == VT_BSTR, E_FAIL); |
---|
| 76 | _tprintf(_T("Friendly Name: %s\n"), CString(vFriendlyName.bstrVal)); |
---|
| 77 | CComPtr<IBaseFilter> pBaseFilter; |
---|
| 78 | __C(pMoniker->BindToObject(NULL, NULL, __uuidof(IBaseFilter), (VOID**) &pBaseFilter)); |
---|
| 79 | #pragma region DeckLink Specific |
---|
| 80 | const CComQIPtr<DecklinkPublicLib::IDecklinkIOControl> pDecklinkIoControl = pBaseFilter; |
---|
| 81 | if(pDecklinkIoControl) |
---|
| 82 | _ATLTRY |
---|
| 83 | { |
---|
| 84 | ULONG nIoFeatures = 0; |
---|
| 85 | __C(pDecklinkIoControl->GetIOFeatures(&nIoFeatures)); |
---|
| 86 | _tprintf(_T("DeckLink IO Features: 0x%08x\n"), nIoFeatures); |
---|
| 87 | } |
---|
| 88 | _ATLCATCHALL() |
---|
| 89 | { |
---|
| 90 | } |
---|
| 91 | #pragma endregion |
---|
| 92 | CComPtr<IEnumPins> pEnumPins; |
---|
| 93 | __C(pBaseFilter->EnumPins(&pEnumPins)); |
---|
| 94 | CComPtr<IPin> pPin; |
---|
| 95 | while(pEnumPins->Next(1, &pPin, NULL) == S_OK) |
---|
| 96 | { |
---|
| 97 | _ATLTRY |
---|
| 98 | { |
---|
| 99 | CComQIPtr<IAMStreamConfig> pAmStreamConfig = pPin; |
---|
| 100 | if(pAmStreamConfig) |
---|
| 101 | { |
---|
| 102 | PIN_INFO PinInformation; |
---|
| 103 | __C(pPin->QueryPinInfo(&PinInformation)); |
---|
| 104 | reinterpret_cast<CComPtr<IBaseFilter>&>(PinInformation.pFilter) = NULL; |
---|
| 105 | _tprintf(_T(" Pin: %s\n"), CString(PinInformation.achName)); |
---|
| 106 | INT nCapabilityCount = 0; |
---|
| 107 | INT nSize = 0; |
---|
| 108 | __C(pAmStreamConfig->GetNumberOfCapabilities(&nCapabilityCount, &nSize)); |
---|
| 109 | _tprintf(_T(" Capability Count: %d\n"), nCapabilityCount); |
---|
| 110 | _tprintf(_T(" Structure Size: %d (expected %d)\n"), nSize, sizeof (VIDEO_STREAM_CONFIG_CAPS)); |
---|
| 111 | CTempBuffer<VIDEO_STREAM_CONFIG_CAPS> pCapability; |
---|
| 112 | __D(nSize >= sizeof *pCapability, E_FAIL); |
---|
| 113 | __D(pCapability.AllocateBytes(nSize), E_OUTOFMEMORY); |
---|
| 114 | for(INT nCapabilityIndex = 0; nCapabilityIndex < nCapabilityCount; nCapabilityIndex++) |
---|
| 115 | { |
---|
| 116 | _tprintf(_T(" Capability %d:\n"), nCapabilityIndex); |
---|
| 117 | AM_MEDIA_TYPE* pMediaType = NULL; |
---|
| 118 | __C(pAmStreamConfig->GetStreamCaps(nCapabilityIndex, &pMediaType, (BYTE*) (VIDEO_STREAM_CONFIG_CAPS*) pCapability)); |
---|
| 119 | ATLASSERT(pMediaType); |
---|
| 120 | // TODO: Free pMediaType |
---|
| 121 | _tprintf(_T(" AM_MEDIA_TYPE:\n")); |
---|
| 122 | _tprintf(_T(" Media Type Data: %s\n"), StringFromData(pMediaType, sizeof *pMediaType)); |
---|
| 123 | if(pMediaType->cbFormat) |
---|
| 124 | _tprintf(_T(" Media Type Format Data: %s\n"), StringFromData(pMediaType->pbFormat, pMediaType->cbFormat)); |
---|
| 125 | // SUGG: majortype, subtype |
---|
| 126 | if(memcmp((const BYTE*) &pMediaType->subtype + sizeof (DWORD), (const BYTE*) &MEDIASUBTYPE_MJPG + sizeof (DWORD), sizeof (GUID) - sizeof (DWORD)) == 0) |
---|
| 127 | { |
---|
| 128 | const CString sSubtypeCode = StringFromCode(pMediaType->subtype.Data1); |
---|
| 129 | if(!sSubtypeCode.IsEmpty()) |
---|
| 130 | _tprintf(_T(" .subtype: %s\n"), sSubtypeCode); |
---|
| 131 | } |
---|
| 132 | _tprintf(_T(" .bFixedSizeSamples: %d\n"), pMediaType->bFixedSizeSamples); |
---|
| 133 | _tprintf(_T(" .bTemporalCompression: %d\n"), pMediaType->bTemporalCompression); |
---|
| 134 | _tprintf(_T(" .lSampleSize: %d\n"), pMediaType->lSampleSize); |
---|
| 135 | // SUGG: formattype, pUnk |
---|
| 136 | _tprintf(_T(" .cbFormat: %d\n"), pMediaType->cbFormat); |
---|
| 137 | const BYTE* pnExtraData = pMediaType->pbFormat; |
---|
| 138 | SIZE_T nExtraDataSize = pMediaType->cbFormat; |
---|
| 139 | if(pMediaType->formattype == FORMAT_VideoInfo) |
---|
| 140 | { |
---|
| 141 | const VIDEOINFOHEADER* pVideoInfoHeader = (VIDEOINFOHEADER*) pMediaType->pbFormat; |
---|
| 142 | _tprintf(_T(" VIDEOINFOHEADER:\n")); |
---|
| 143 | _tprintf(_T(" .rcSource: (%d, %d) - (%d, %d)\n"), pVideoInfoHeader->rcSource); |
---|
| 144 | _tprintf(_T(" .rcSource: (%d, %d) - (%d, %d)\n"), pVideoInfoHeader->rcTarget); |
---|
| 145 | _tprintf(_T(" .dwBitRate: %d\n"), pVideoInfoHeader->dwBitRate); |
---|
| 146 | _tprintf(_T(" .dwBitErrorRate: %d\n"), pVideoInfoHeader->dwBitErrorRate); |
---|
| 147 | _tprintf(_T(" .AvgTimePerFrame: %I64d\n"), pVideoInfoHeader->AvgTimePerFrame); |
---|
| 148 | _tprintf(_T(" BITMAPINFOHEADER:\n")); |
---|
| 149 | _tprintf(_T(" .biSize: %d\n"), pVideoInfoHeader->bmiHeader.biSize); |
---|
| 150 | _tprintf(_T(" .biWidth: %d\n"), pVideoInfoHeader->bmiHeader.biWidth); |
---|
| 151 | _tprintf(_T(" .biHeight: %d\n"), pVideoInfoHeader->bmiHeader.biHeight); |
---|
| 152 | _tprintf(_T(" .biPlanes: %d\n"), pVideoInfoHeader->bmiHeader.biPlanes); |
---|
| 153 | _tprintf(_T(" .biBitCount: %d\n"), pVideoInfoHeader->bmiHeader.biBitCount); |
---|
| 154 | _tprintf(_T(" .biCompression: %d %s\n"), pVideoInfoHeader->bmiHeader.biCompression, StringFromCode(pVideoInfoHeader->bmiHeader.biCompression)); |
---|
| 155 | _tprintf(_T(" .biSizeImage: %d\n"), pVideoInfoHeader->bmiHeader.biSizeImage); |
---|
| 156 | pnExtraData += sizeof *pVideoInfoHeader; |
---|
| 157 | nExtraDataSize -= sizeof *pVideoInfoHeader; |
---|
| 158 | } else |
---|
| 159 | if(pMediaType->formattype == FORMAT_VideoInfo2) |
---|
| 160 | { |
---|
| 161 | const VIDEOINFOHEADER2* pVideoInfoHeader2 = (VIDEOINFOHEADER2*) pMediaType->pbFormat; |
---|
| 162 | _tprintf(_T(" VIDEOINFOHEADER2:\n")); |
---|
| 163 | // SUGG: Extra data |
---|
| 164 | pnExtraData += sizeof *pVideoInfoHeader2; |
---|
| 165 | nExtraDataSize -= sizeof *pVideoInfoHeader2; |
---|
| 166 | } |
---|
| 167 | if(nExtraDataSize > 0) |
---|
| 168 | { |
---|
| 169 | CString sLine; |
---|
| 170 | for(SIZE_T nIndex = 0; nIndex < nExtraDataSize && nIndex < 63; nIndex++) |
---|
| 171 | { |
---|
| 172 | sLine.AppendFormat(_T("%02X "), pnExtraData[nIndex]); |
---|
| 173 | if(((nIndex + 1) % 0x10) == 0x00 || nIndex == 62) |
---|
| 174 | { |
---|
| 175 | if(nIndex == 62 && nExtraDataSize > nIndex + 1) |
---|
| 176 | sLine.Append(_T("...")); |
---|
| 177 | _tprintf(_T(" Extra [%04X]: %s\n"), nIndex & ~0x000F, sLine); |
---|
| 178 | sLine.Empty(); |
---|
| 179 | } |
---|
| 180 | } |
---|
| 181 | ATLASSERT(sLine.IsEmpty()); |
---|
| 182 | } |
---|
| 183 | ATLASSERT(pCapability->guid == MEDIATYPE_Video); |
---|
| 184 | _tprintf(_T(" VIDEO_STREAM_CONFIG_CAPS:\n")); |
---|
| 185 | _tprintf(_T(" Data: %s\n"), StringFromData((VIDEO_STREAM_CONFIG_CAPS*) pCapability, sizeof *pCapability)); |
---|
| 186 | _tprintf(_T(" .VideoStandard: %d\n"), pCapability->VideoStandard); |
---|
| 187 | _tprintf(_T(" .InputSize: %d x %d\n"), pCapability->InputSize); |
---|
| 188 | _tprintf(_T(" .MinCroppingSize: %d x %d\n"), pCapability->MinCroppingSize); |
---|
| 189 | _tprintf(_T(" .MaxCroppingSize: %d x %d\n"), pCapability->MaxCroppingSize); |
---|
| 190 | _tprintf(_T(" .CropGranularityX: %d\n"), pCapability->CropGranularityX); |
---|
| 191 | _tprintf(_T(" .CropAlignX: %d\n"), pCapability->CropAlignX); |
---|
| 192 | _tprintf(_T(" .CropAlignY: %d\n"), pCapability->CropAlignY); |
---|
| 193 | _tprintf(_T(" .MinOutputSize: %d x %d\n"), pCapability->MinOutputSize); |
---|
| 194 | _tprintf(_T(" .MaxOutputSize: %d x %d\n"), pCapability->MaxOutputSize); |
---|
| 195 | _tprintf(_T(" .OutputGranularityX: %d\n"), pCapability->OutputGranularityX); |
---|
| 196 | _tprintf(_T(" .OutputGranularityY: %d\n"), pCapability->OutputGranularityY); |
---|
| 197 | _tprintf(_T(" .StretchTapsX: %d\n"), pCapability->StretchTapsX); |
---|
| 198 | _tprintf(_T(" .StretchTapsY: %d\n"), pCapability->StretchTapsY); |
---|
| 199 | _tprintf(_T(" .ShrinkTapsX: %d\n"), pCapability->ShrinkTapsX); |
---|
| 200 | _tprintf(_T(" .ShrinkTapsY: %d\n"), pCapability->ShrinkTapsY); |
---|
| 201 | _tprintf(_T(" .MinFrameInterval: %I64d\n"), pCapability->MinFrameInterval); |
---|
| 202 | _tprintf(_T(" .MaxFrameInterval: %I64d\n"), pCapability->MaxFrameInterval); |
---|
| 203 | _tprintf(_T(" .MinBitsPerSecond: %d\n"), pCapability->MinBitsPerSecond); |
---|
| 204 | _tprintf(_T(" .MaxBitsPerSecond: %d\n"), pCapability->MaxBitsPerSecond); |
---|
| 205 | } |
---|
| 206 | } |
---|
| 207 | } |
---|
| 208 | _ATLCATCHALL() |
---|
| 209 | { |
---|
| 210 | _tprintf(_T("An exception has been caught\n")); |
---|
| 211 | } |
---|
| 212 | pPin.Release(); |
---|
| 213 | } |
---|
| 214 | } |
---|
| 215 | _ATLCATCHALL() |
---|
| 216 | { |
---|
| 217 | _tprintf(_T("An exception has been caught\n")); |
---|
| 218 | } |
---|
| 219 | pMoniker.Release(); |
---|
| 220 | _tprintf(_T("\n")); |
---|
| 221 | } |
---|
| 222 | } |
---|
| 223 | _ATLCATCHALL() |
---|
| 224 | { |
---|
| 225 | CoUninitialize(); |
---|
| 226 | _ATLRETHROW; |
---|
| 227 | } |
---|
| 228 | CoUninitialize(); |
---|
| 229 | } |
---|
| 230 | _ATLCATCHALL() |
---|
| 231 | { |
---|
| 232 | } |
---|
| 233 | return 0; |
---|
| 234 | } |
---|
| 235 | |
---|