12 #if !defined(AJA_WINDOWS)
19 #else // begin AJA_WINDOWS section
20 OutputVideoPin::OutputVideoPin(HRESULT* phr,
CSource* pFilter, LPCWSTR pPinName)
25 OutputVideoPin::~OutputVideoPin()
29 STDMETHODIMP OutputVideoPin::QueryInterface(REFIID
riid,
void** ppv)
36 if (
riid == IID_IKsPropertySet)
37 *ppv =
static_cast<IKsPropertySet*
>(
this);
38 else if (
riid == IID_IAMStreamConfig)
39 *ppv =
static_cast<IAMStreamConfig*
>(
this);
41 return CSourceStream::QueryInterface(
riid, ppv);
49 return CSourceStream::AddRef();
54 return CSourceStream::Release();
57 STDMETHODIMP OutputVideoPin::CheckMediaType(
const CMediaType* pmt)
62 if (*pmt->
Type() != MEDIATYPE_Video)
68 if (*pmt->
Subtype() != MEDIASUBTYPE_UYVY)
74 HRESULT OutputVideoPin::GetMediaType(
CMediaType* pMediaType)
76 if (VCAM()->Initialize())
82 HRESULT OutputVideoPin::FillBuffer(IMediaSample* pSample)
84 return VCAM()->GetNextFrame(
this, pSample);
87 HRESULT OutputVideoPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pRequest)
89 CAutoLock cAutoLock(m_pFilter->pStateLock());
94 VIDEOINFO* pvi =
reinterpret_cast<VIDEOINFO*
>(m_mt.Format());
98 pRequest->cBuffers = 1;
99 pRequest->cbBuffer = pvi->bmiHeader.biSizeImage;
101 ALLOCATOR_PROPERTIES Actual;
102 HRESULT
hr = pAlloc->SetProperties(pRequest, &Actual);
106 if (Actual.cbBuffer < pRequest->cbBuffer)
109 if (Actual.cBuffers != 1)
115 STDMETHODIMP OutputVideoPin::EnumMediaTypes(IEnumMediaTypes** ppEnum)
120 STDMETHODIMP OutputVideoPin::Notify(IBaseFilter* pSender, Quality q)
125 STDMETHODIMP OutputVideoPin::Set(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData)
130 STDMETHODIMP OutputVideoPin::Get(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData, DWORD* pcbReturned)
132 if (guidPropSet != AMPROPSETID_Pin)
133 return E_PROP_SET_UNSUPPORTED;
135 if (dwPropID != AMPROPERTY_PIN_CATEGORY)
136 return E_PROP_ID_UNSUPPORTED;
138 if (pPropData ==
NULL && pcbReturned ==
NULL)
142 *pcbReturned =
sizeof(GUID);
144 if (pPropData ==
NULL)
147 if (cbPropData <
sizeof(GUID))
150 *(GUID*)pPropData = PIN_CATEGORY_CAPTURE;
155 STDMETHODIMP OutputVideoPin::QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD* pTypeSupport)
157 if (guidPropSet != AMPROPSETID_Pin)
158 return E_PROP_SET_UNSUPPORTED;
160 if (dwPropID != AMPROPERTY_PIN_CATEGORY)
161 return E_PROP_ID_UNSUPPORTED;
164 *pTypeSupport = KSPROPERTY_SUPPORT_GET;
169 STDMETHODIMP OutputVideoPin::SetFormat(AM_MEDIA_TYPE* pmt)
174 if (pmt->majortype == m_mt.majortype &&
175 pmt->subtype == m_mt.subtype &&
176 pmt->formattype == m_mt.formattype)
182 return VFW_E_INVALIDMEDIATYPE;
185 STDMETHODIMP OutputVideoPin::GetFormat(AM_MEDIA_TYPE** ppmt)
192 return E_OUTOFMEMORY;
197 STDMETHODIMP OutputVideoPin::GetNumberOfCapabilities(
int* piCount,
int* piSize)
199 if (!piCount || !piSize)
203 *piSize =
sizeof(VIDEO_STREAM_CONFIG_CAPS);
208 STDMETHODIMP OutputVideoPin::GetStreamCaps(
int iIndex, AM_MEDIA_TYPE** ppmt, BYTE* pSCC)
213 if (iIndex < 0 || iIndex >= 1)
217 if (FAILED(GetMediaType(&mediaType)))
221 return E_OUTOFMEMORY;
223 VIDEOINFO* vih =
reinterpret_cast<decltype(vih)
>((*ppmt)->pbFormat);
224 VIDEO_STREAM_CONFIG_CAPS* caps =
reinterpret_cast<VIDEO_STREAM_CONFIG_CAPS*
>(pSCC);
225 ZeroMemory(caps,
sizeof(VIDEO_STREAM_CONFIG_CAPS));
226 caps->guid = FORMAT_VideoInfo;
227 caps->MinFrameInterval = vih->AvgTimePerFrame;
228 caps->MaxFrameInterval = vih->AvgTimePerFrame;
229 caps->MinOutputSize.cx = vih->bmiHeader.biWidth;
230 caps->MinOutputSize.cy = vih->bmiHeader.biHeight;
231 caps->MaxOutputSize = caps->MinOutputSize;
232 caps->InputSize = caps->MinOutputSize;
233 caps->MinCroppingSize = caps->MinOutputSize;
234 caps->MaxCroppingSize = caps->MinOutputSize;
235 caps->CropGranularityX = vih->bmiHeader.biWidth;
236 caps->CropGranularityY = vih->bmiHeader.biHeight;
237 caps->MinBitsPerSecond = vih->dwBitRate;
238 caps->MaxBitsPerSecond = caps->MinBitsPerSecond;
243 OutputAudioPin::OutputAudioPin(HRESULT* phr,
CSource* pFilter, LPCWSTR pPinName)
248 OutputAudioPin::~OutputAudioPin()
252 STDMETHODIMP OutputAudioPin::QueryInterface(REFIID
riid,
void** ppv)
259 if (
riid == IID_IKsPropertySet)
260 *ppv =
static_cast<IKsPropertySet*
>(
this);
261 else if (
riid == IID_IAMStreamConfig)
262 *ppv =
static_cast<IAMStreamConfig*
>(
this);
264 return CSourceStream::QueryInterface(
riid, ppv);
272 return CSourceStream::AddRef();
277 return CSourceStream::Release();
280 STDMETHODIMP OutputAudioPin::CheckMediaType(
const CMediaType* pmt)
285 if (*pmt->
Type() != MEDIATYPE_Audio)
288 if (*pmt->
Subtype() != MEDIASUBTYPE_PCM)
291 if (*pmt->
FormatType() != FORMAT_WaveFormatEx)
294 WAVEFORMATEX* pwfex =
reinterpret_cast<WAVEFORMATEX*
>(pmt->
Format());
301 if (pwfex->nChannels != VCAM()->GetNumAudioChannels())
304 if (pwfex->nSamplesPerSec != VCAM()->GetAudioSampleRate())
307 if (pwfex->wBitsPerSample != VCAM()->GetAudioBitsPerSample())
313 if (pwfxext->
SubFormat != KSDATAFORMAT_SUBTYPE_PCM)
320 HRESULT OutputAudioPin::GetMediaType(
CMediaType* pMediaType)
322 if (VCAM()->Initialize())
328 HRESULT OutputAudioPin::FillBuffer(IMediaSample* pSample)
330 return VCAM()->GetNextFrame(
this, pSample);
333 HRESULT OutputAudioPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pRequest)
335 CAutoLock cAutoLock(m_pFilter->pStateLock());
340 WAVEFORMATEX* pwfx =
reinterpret_cast<WAVEFORMATEX*
>(m_mt.Format());
344 pRequest->cBuffers = 1;
347 ALLOCATOR_PROPERTIES Actual;
348 HRESULT
hr = pAlloc->SetProperties(pRequest, &Actual);
352 if (Actual.cbBuffer < pRequest->cbBuffer)
355 if (Actual.cBuffers != 1)
361 STDMETHODIMP OutputAudioPin::EnumMediaTypes(IEnumMediaTypes** ppEnum)
366 STDMETHODIMP OutputAudioPin::Notify(IBaseFilter* pSender, Quality q)
371 STDMETHODIMP OutputAudioPin::Set(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData)
376 STDMETHODIMP OutputAudioPin::Get(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData, DWORD* pcbReturned)
378 if (guidPropSet != AMPROPSETID_Pin)
379 return E_PROP_SET_UNSUPPORTED;
381 if (dwPropID != AMPROPERTY_PIN_CATEGORY)
382 return E_PROP_ID_UNSUPPORTED;
384 if (pPropData ==
NULL && pcbReturned ==
NULL)
388 *pcbReturned =
sizeof(GUID);
390 if (pPropData ==
NULL)
393 if (cbPropData <
sizeof(GUID))
396 *(GUID*)pPropData = PIN_CATEGORY_CAPTURE;
401 STDMETHODIMP OutputAudioPin::QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD* pTypeSupport)
403 if (guidPropSet != AMPROPSETID_Pin)
404 return E_PROP_SET_UNSUPPORTED;
406 if (dwPropID != AMPROPERTY_PIN_CATEGORY)
407 return E_PROP_ID_UNSUPPORTED;
410 *pTypeSupport = KSPROPERTY_SUPPORT_GET;
415 STDMETHODIMP OutputAudioPin::SetFormat(AM_MEDIA_TYPE* pmt)
420 if (pmt->majortype == m_mt.majortype &&
421 pmt->subtype == m_mt.subtype &&
422 pmt->formattype == m_mt.formattype)
428 return VFW_E_INVALIDMEDIATYPE;
431 STDMETHODIMP OutputAudioPin::GetFormat(AM_MEDIA_TYPE** ppmt)
438 return E_OUTOFMEMORY;
443 STDMETHODIMP OutputAudioPin::GetNumberOfCapabilities(
int* piCount,
int* piSize)
445 if (!piCount || !piSize)
449 *piSize =
sizeof(AUDIO_STREAM_CONFIG_CAPS);
454 STDMETHODIMP OutputAudioPin::GetStreamCaps(
int iIndex, AM_MEDIA_TYPE** ppmt, BYTE* pSCC)
459 if (iIndex < 0 || iIndex >= 1)
463 if (FAILED(GetMediaType(&mediaType)))
467 return E_OUTOFMEMORY;
469 WAVEFORMATEX* wfex =
reinterpret_cast<decltype(wfex)
>((*ppmt)->pbFormat);
470 AUDIO_STREAM_CONFIG_CAPS* caps =
reinterpret_cast<AUDIO_STREAM_CONFIG_CAPS*
>(pSCC);
471 ZeroMemory(caps,
sizeof(AUDIO_STREAM_CONFIG_CAPS));
472 caps->guid = FORMAT_WaveFormatEx;
473 caps->MinimumChannels = wfex->nChannels;
474 caps->MaximumChannels = wfex->nChannels;
475 caps->MinimumBitsPerSample = wfex->wBitsPerSample;
476 caps->MaximumBitsPerSample = wfex->wBitsPerSample;
477 caps->MinimumSampleFrequency = wfex->nSamplesPerSec;
478 caps->MaximumSampleFrequency = wfex->nSamplesPerSec;
483 CUnknown* WINAPI NTV2VCAM::CreateInstance(LPUNKNOWN pUnk, HRESULT* phr)
485 NTV2VCAM* pFilter =
new NTV2VCAM(pUnk, phr);
487 *phr = E_OUTOFMEMORY;
491 STDMETHODIMP NTV2VCAM::QueryInterface(REFIID
riid,
void** ppv)
493 return CSource::QueryInterface(
riid, ppv);
498 return CSource::AddRef();
503 return CSource::Release();
506 STDMETHODIMP NTV2VCAM::EnumPins(IEnumPins** ppEnum)
511 STDMETHODIMP NTV2VCAM::FindPin(LPCWSTR Id, IPin** ppPin)
513 if (Id ==
nullptr || ppPin ==
nullptr)
516 if (lstrcmpW(Id, VCAM_VIDEO_PIN_NAME_W) == 0)
524 return VFW_E_NOT_FOUND;
527 STDMETHODIMP NTV2VCAM::QueryFilterInfo(FILTER_INFO* pInfo)
532 memcpy(pInfo->achName, VCAM_FILTER_NAME_W,
sizeof(VCAM_FILTER_NAME_W));
534 pInfo->pGraph = m_pGraph;
540 STDMETHODIMP NTV2VCAM::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR
pName)
548 STDMETHODIMP NTV2VCAM::QueryVendorInfo(LPWSTR* pVendorInfo)
553 NTV2VCAM::NTV2VCAM (LPUNKNOWN pUnk, HRESULT* phr)
554 :
CSource(
NAME(VCAM_FILTER_NAME), pUnk, CLSID_VirtualWebcam)
555 , mVideos(MAX_VIDEOS)
556 , mAudios(MAX_AUDIOS)
560 if (m_paStreams ==
NULL)
563 *phr = E_OUTOFMEMORY;
567 m_paStreams[0] =
new OutputVideoPin(phr,
this, VCAM_VIDEO_PIN_NAME_W);
568 if (m_paStreams[0] ==
NULL)
571 *phr = E_OUTOFMEMORY;
575 m_paStreams[1] =
new OutputAudioPin(phr,
this, VCAM_AUDIO_PIN_NAME_W);
576 if (m_paStreams[1] ==
NULL)
579 *phr = E_OUTOFMEMORY;
587 mPixelFormatStr =
"uyvy";
589 #endif // end AJA_WINDOWS section
591 NTV2VCAM::~NTV2VCAM()
593 cout <<
"## NOTE: NTV2VCAM terminated" << endl;
595 #if defined(AJALinux)
599 #if !defined(AJA_MISSING_DEV_V4L2LOOPBACK)
602 cerr <<
"## ERROR (" << errno <<
"): failed to remove V4L2 device for output" << endl;
608 #if !defined(AJA_MISSING_DEV_V4L2LOOPBACK)
615 snd_pcm_drain(mPcmHandle);
616 snd_pcm_close(mPcmHandle);
629 #if defined(AJALinux)
630 bool NTV2VCAM::Initialize (
int argc,
const char** argv)
633 int showVersion(0), useHDMI(0), inputChannel(0);
641 {
"device",
'd',
POPT_ARG_STRING, &pAjaDevSpec, 0,
"AJA device",
"index#, serial#, or model"},
643 {
"channel",
'c',
POPT_ARG_INT, &inputChannel, 0,
"input channel",
"1-8"},
644 {
"pixelformat",
'p',
POPT_ARG_STRING, &pPixFormat, 0,
"pixel format",
"FourCC string or 'list'"},
645 {
"vdev",
'i',
POPT_ARG_STRING, &pVideoDevice, 0,
"video device",
"/dev/video1"},
646 {
"adev",
'u',
POPT_ARG_STRING, &pAudioDevice, 0,
"audio device",
"hw:Loopback,1,1"},
647 {
"audiolinks",
'a',
POPT_ARG_INT, &mNumAudioLinks,0,
"multilink audio systems",
"0 for silence or 1-4"},
654 cerr <<
"## ERROR (" << errno <<
"): " << popt.errorStr() << endl;
658 mAjaDevice = pAjaDevSpec ? pAjaDevSpec :
"0";
659 mInputType = useHDMI ?
"hdmi" :
"sdi";
660 mPixelFormatStr = pPixFormat ? pPixFormat :
"2vuy";
661 mVideoDevice = pVideoDevice ? pVideoDevice :
"";
662 mAudioDevice = pAudioDevice ? pAudioDevice :
"";
665 cout << argv[0] <<
", NTV2 SDK " <<
NTV2Version() << endl;
671 #elif defined(AJA_WINDOWS)
673 bool NTV2VCAM::Initialize()
677 #endif // AJA_WINDOWS or AJALinux
679 if (mAjaDevice.empty())
681 cerr <<
"## ERROR (" << errno <<
"): Parameter 'AJA device' is required." << endl;
685 if (mInputType.empty())
687 cerr <<
"## ERROR (" << errno <<
"): Parameter 'input type' is required." << endl;
691 if (mPixelFormatStr.empty())
693 cerr <<
"## ERROR (" << errno <<
"): Parameter 'pixel format' is required." << endl;
697 #if defined(AJALinux)
698 if (mVideoDevice.empty())
700 cerr <<
"## ERROR (" << errno <<
"): Parameter 'video device' is required." << endl;
705 if (mPixelFormatStr ==
"list")
713 cerr <<
"## ERROR (" << errno <<
"): invalid pixel format" << endl;
720 cerr <<
"## ERROR (" << errno <<
"): invalid channel '" <<
DEC(
mInputChannel+1) <<
"'" << endl;
727 cerr <<
"## ERROR (" << errno <<
"): cannot find AJA device '" << mAjaDevice <<
"'" << endl;
734 cerr <<
"## ERROR (" << errno <<
"): AJA device not ready" << endl;
741 cerr <<
"## ERROR (" << errno <<
"): AJA device does not support capture" << endl;
746 if (mInputType ==
"hdmi")
748 if (mDevice.
features().GetNumHDMIVideoInputs() <= 0)
750 cerr <<
"## ERROR (" << errno <<
"): AJA device does not support HDMI" << endl;
760 cerr <<
"## ERROR (" << errno <<
"): AJA device does not support pixel format" << endl;
769 cerr <<
"## ERROR: (" << errno <<
") Unable to get device's current owner" << endl;
777 cerr <<
"## ERROR: (" << errno <<
") Unable to acquire AJA device because another app (pid " <<
appPID <<
") owns it" << endl;
784 cerr <<
"## ERROR: (" << errno <<
") Unable to get device's retail service task mode" << endl;
792 cerr <<
"## ERROR: (" << errno <<
") Unable to set device's retail service task mode to oem tasks" << endl;
798 if (mDevice.
features().CanDoMultiFormat())
806 cerr <<
"## ERROR (" << errno <<
"): invalid video format '" <<
mVideoFormat <<
"'" << endl;
814 cerr <<
"## ERROR (" << errno <<
"): invalid channel '" <<
DEC(
mInputChannel) <<
"'" << endl;
823 cerr <<
"## ERROR (" << errno <<
"): invalid input source" << endl;
839 cerr <<
"## ERROR (" << errno <<
"): AJA device requires TSI support" << endl;
847 else if (mDevice.
features().CanDo12gRouting())
849 mDoTSIRouting =
false;
852 cerr <<
"## ERROR (" << errno <<
"): invalid channel '" <<
DEC(
mInputChannel) <<
"'" << endl;
858 else if (mDoTSIRouting)
879 cerr <<
"## ERROR (" << errno <<
"): invalid channel '" <<
DEC(
mInputChannel) <<
"'" << endl;
885 cerr <<
"## ERROR (" << errno <<
"): invalid input source '" <<
DEC(mInputSource) <<
"'" << endl;
891 cerr <<
"## WARNING: Specified channel Ch" <<
DEC(origCh + 1) <<
" corrected to use Ch" <<
DEC(
mInputChannel + 1) <<
" to work for UHD/4K on '" << mDevice.
GetDisplayName() <<
"'" << endl;
893 mNumSpigots = mDevice.
features().CanDo12gRouting() ? 1 : (mDoTSIRouting ? 2 : 4);
900 cerr <<
"## ERROR (" << errno <<
"): enable channels failed" << endl;
907 cerr <<
"## ERROR (" << errno <<
"): enable input interrupt failed" << endl;
914 cerr <<
"## ERROR (" << errno <<
"): subscribe input vertical event failed" << endl;
921 cerr <<
"## ERROR (" << errno <<
"): subscribe output vertical event failed" << endl;
930 cerr <<
"## ERROR (" << errno <<
"): set SDI transmit enabled failed" << endl;
936 cerr <<
"## ERROR (" << errno <<
"): wait for output vertical interrupt failed" << endl;
946 cerr <<
"## ERROR (" << errno <<
"): failed to set capture mode" << endl;
954 cerr <<
"## ERROR (" << errno <<
"): set freerun reference failed" << endl;
961 cerr <<
"## ERROR (" << errno <<
"): failed to set video format on AJA device" << endl;
968 cerr <<
"## ERROR (" << errno <<
"): set VANC mode off failed" << endl;
975 if (mDevice.
features().CanDo12gRouting() || mDoTSIRouting)
980 cerr <<
"## ERROR (" << errno <<
"): set TSI frame enable failed" << endl;
989 cerr <<
"## ERROR (" << errno <<
"): set 4k squares enable failed" << endl;
998 cerr <<
"## ERROR (" << errno <<
"): set frame buffer format failed" << endl;
1016 cerr <<
"## ERROR (" << errno <<
"): get input routing failed" << endl;
1025 cerr <<
"## ERROR (" << errno <<
"): get input routing failed" << endl;
1032 cerr <<
"## ERROR (" << errno <<
"): apply signal route failed" << endl;
1037 #if defined(AJALinux)
1038 #if !defined(AJA_MISSING_DEV_V4L2LOOPBACK)
1039 mLbDevice = open(V4L2_DRIVER_NAME, O_RDONLY);
1040 if (mLbDevice == -1)
1042 cerr <<
"## ERROR (" << errno <<
"): failed to open V4L2 driver" << endl;
1048 cfg.
output_nr = mLbDeviceNR = ExtractNumber(mVideoDevice.c_str());
1049 string labelName =
"AJA virtual webcam device " +
to_string(mLbDeviceNR);
1052 if (mLbDeviceNR == -1)
1054 cerr <<
"## ERROR (" << errno <<
"): failed to create V4L2 device for output" << endl;
1058 #endif // !defined(AJA_MISSING_DEV_V4L2LOOPBACK)
1059 mLbDisplay = open(mVideoDevice.c_str(), O_RDWR);
1060 if (mLbDisplay == -1)
1062 cerr <<
"## ERROR (" << errno <<
"): failed to open V4L2 output device" << endl;
1067 struct v4l2_format lbFormat;
1068 memset(&lbFormat, 0,
sizeof(lbFormat));
1069 lbFormat.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1070 lbFormat.fmt.pix.width =
mFormatDesc.GetRasterWidth();
1071 lbFormat.fmt.pix.height =
mFormatDesc.GetRasterHeight();
1072 lbFormat.fmt.pix.field = V4L2_FIELD_NONE;
1073 lbFormat.fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
1074 lbFormat.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
1075 if (ioctl(mLbDisplay, VIDIOC_S_FMT, &lbFormat) == -1)
1076 cerr <<
"## ERROR (" << errno <<
"): cannot set video format on video loopback device" << endl;
1078 struct v4l2_streamparm streamParm;
1079 memset(&streamParm, 0,
sizeof(streamParm));
1080 streamParm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1081 streamParm.parm.output.timeperframe.numerator = 1;
1082 streamParm.parm.output.timeperframe.denominator = GetFps();
1083 if (ioctl(mLbDisplay, VIDIOC_S_PARM, &streamParm) == -1)
1084 cerr <<
"## ERROR (" << errno <<
"): cannot set frame rate on video loopback device" << endl;
1092 const UWord startFrame12g[] = { 0, 7, 64, 71 };
1093 const UWord startFrame[] = { 0, 7, 14, 21 };
1094 if (mDevice.
features().CanDo12gRouting())
1103 cerr <<
"## ERROR (" << errno <<
"): failed to set AC frame range" << endl;
1108 #if defined(AJA_WINDOWS)
1109 if (OutputVideoPin* pVideoPin =
dynamic_cast<OutputVideoPin*
>(m_paStreams[0]))
1112 ZeroMemory(&vi,
sizeof(VIDEOINFO));
1113 vi.bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
1114 vi.bmiHeader.biWidth =
mFormatDesc.GetRasterWidth();
1115 vi.bmiHeader.biHeight =
mFormatDesc.GetRasterHeight();
1116 vi.bmiHeader.biPlanes =
mFormatDesc.GetNumPlanes();
1118 vi.bmiHeader.biCompression = 0x59565955;
1119 vi.bmiHeader.biSizeImage =
mFormatDesc.GetTotalRasterBytes();
1120 vi.AvgTimePerFrame = GetFps();
1122 pVideoPin->m_mt.SetType(&MEDIATYPE_Video);
1123 pVideoPin->m_mt.SetSubtype(&MEDIASUBTYPE_UYVY);
1124 pVideoPin->m_mt.SetFormatType(&FORMAT_VideoInfo);
1125 pVideoPin->m_mt.SetSampleSize(vi.bmiHeader.biSizeImage);
1126 pVideoPin->m_mt.SetTemporalCompression(FALSE);
1127 pVideoPin->m_mt.SetFormat(
reinterpret_cast<BYTE*
>(&vi),
sizeof(VIDEOINFO));
1130 if (OutputAudioPin* pAudioPin =
dynamic_cast<OutputAudioPin*
>(m_paStreams[1]))
1135 wfx.
Format.nChannels = mNumAudioChannels;
1136 wfx.
Format.nSamplesPerSec = mSampleRate;
1137 wfx.
Format.wBitsPerSample = mBitsPerSample;
1143 if (mNumAudioChannels == 2)
1145 wfx.
dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
1147 else if (mNumAudioChannels == 16)
1150 SPEAKER_FRONT_LEFT |
1151 SPEAKER_FRONT_RIGHT |
1152 SPEAKER_FRONT_CENTER |
1153 SPEAKER_LOW_FREQUENCY |
1155 SPEAKER_BACK_RIGHT |
1156 SPEAKER_FRONT_LEFT_OF_CENTER |
1157 SPEAKER_FRONT_RIGHT_OF_CENTER |
1158 SPEAKER_BACK_CENTER |
1160 SPEAKER_SIDE_RIGHT |
1161 SPEAKER_TOP_CENTER |
1162 SPEAKER_TOP_FRONT_LEFT |
1163 SPEAKER_TOP_FRONT_CENTER |
1164 SPEAKER_TOP_FRONT_RIGHT |
1165 SPEAKER_TOP_BACK_CENTER;
1167 wfx.
SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1169 pAudioPin->m_mt.ResetFormatBuffer();
1170 pAudioPin->m_mt.SetType(&MEDIATYPE_Audio);
1171 pAudioPin->m_mt.SetSubtype(&MEDIASUBTYPE_PCM);
1172 pAudioPin->m_mt.SetFormatType(&FORMAT_WaveFormatEx);
1173 pAudioPin->m_mt.SetTemporalCompression(FALSE);
1174 pAudioPin->m_mt.SetSampleSize(wfx.
Format.nBlockAlign);
1180 mInitialized =
true;
1181 #endif // AJA_WINDOWS
1185 #if defined(AJALinux)
1186 bool NTV2VCAM::Run(
void)
1192 {cerr <<
"## ERROR: AC start failed" << endl; mErrorCode =
AJA_VW_ACSTARTFAILED;
return false;}
1210 if (write(mLbDisplay, mVideoBuffer, mVideoBuffer.
GetByteCount()) == -1)
1211 cerr <<
"## ERROR (" << errno <<
"): write to video loopback device failed" << endl;
1216 unsigned long pcmReturn = snd_pcm_writei(mPcmHandle, mAudioBuffer, mAudioFrames);
1218 pcmReturn = snd_pcm_recover(mPcmHandle, pcmReturn, 0);
1220 cerr <<
"## ERROR (" << errno <<
"): snd_pcm_writei failed" << endl;
1221 if (pcmReturn > 0 && pcmReturn < mAudioFrames)
1222 cerr <<
"## ERROR (" << errno <<
"): short write - expected '" << mAudioFrames <<
"' frames, wrote '" << pcmReturn <<
"' frames" << endl;
1232 #if defined(AJA_WINDOWS)
1233 HRESULT NTV2VCAM::GetNextFrame (OutputPin* pPin, IMediaSample* pSample)
1242 {cerr <<
"## ERROR: AC start failed" << endl; mErrorCode =
AJA_VW_ACSTARTFAILED;
return S_FALSE;}
1258 mVideos.push(mVideoBuffer);
1259 mAudioBuffer ? mAudios.push(mAudioBuffer) : 0;
1265 HRESULT
hr = pSample->GetPointer(&pData);
1268 cerr <<
"## ERROR (" << errno <<
"): failed to get pointer to sample buffer" << endl;
1272 ULWord cbData = pSample->GetSize();
1273 if (OutputVideoPin* pVideoPin =
dynamic_cast<OutputVideoPin*
>(pPin))
1276 if (mVideos.pop(tmpVideoBuffer))
1280 cerr <<
"## ERROR: sample buffer size mismatch: AJA is " << tmpVideoBuffer.
GetByteCount() <<
", output is " << cbData << endl;
1284 memcpy(pData, tmpVideoBuffer, cbData);
1285 pSample->SetActualDataLength(tmpVideoBuffer.
GetByteCount());
1288 if (OutputAudioPin* pAudioPin =
dynamic_cast<OutputAudioPin*
>(pPin))
1291 if (mAudios.pop(tmpAudioBuffer))
1295 cerr <<
"## ERROR: sample buffer size mismatch: AJA is " << tmpAudioBuffer.
GetByteCount() <<
", output is " << cbData << endl;
1303 pSample->SetSyncPoint(TRUE);
1307 #endif // defined(AJA_WINDOWS)
1309 string NTV2VCAM::ULWordToString(
const ULWord inNum)
1318 static struct VideoFormatPair
1322 } VideoFormatPairs[] = {
1350 for (
size_t formatNdx(0); formatNdx <
sizeof(VideoFormatPairs) /
sizeof(VideoFormatPair); formatNdx++)
1351 if (VideoFormatPairs[formatNdx].vIn == inOutVideoFormat)
1353 inOutVideoFormat = VideoFormatPairs[formatNdx].vOut;
1361 #if defined(AJALinux)
1362 if (mAudioDevice.empty())
1370 if (!mDevice.
features().CanDoMultiLinkAudio())
1373 int fNumAudioSystems = mDevice.
features().GetNumAudioSystems();
1374 if (mDoMultiFormat && fNumAudioSystems > 1 &&
UWord(
mInputChannel) < fNumAudioSystems)
1377 if (mNumAudioLinks > 1)
1382 cerr <<
"## ERROR (" << errno <<
"): multi-Link audio only intended for input Ch1, not Ch" <<
DEC(
mInputChannel) << endl;
1395 mNumAudioChannels = mDevice.
features().GetMaxAudioChannels();
1412 cerr <<
"## ERROR (" << errno <<
"): configure audio system failed" << endl;
1416 #if defined(AJALinux)
1417 int pcmReturn = snd_pcm_open(&mPcmHandle, mAudioDevice.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
1420 cerr <<
"## ERROR (" << errno <<
"): snd_pcm_open failed" << endl;
1423 pcmReturn = snd_pcm_set_params(mPcmHandle, SND_PCM_FORMAT_S32_LE, SND_PCM_ACCESS_RW_INTERLEAVED, mNumAudioChannels, mSampleRate, 1, 500000);
1426 cerr <<
"## ERROR (" << errno <<
"): snd_pcm_set_params failed" << endl;
1446 if (isInputRGB && !isFrameRGB)
1451 else if (!isInputRGB && isFrameRGB)
1459 return !conns.empty();
1464 UWord sdi(0), mux(0), csc(0), fb(0), path(0);
1471 if (mDevice.
features().CanDo12gRouting())
1481 if (isInputRGB == isFrameRGB)
1483 for (path = 0; path < 4; path++)
1494 else if (isInputRGB && !isFrameRGB)
1496 for (path = 0; path < 4; path++)
1514 for (path = 0; path < 4; path++)
1533 cerr <<
"## ERROR (" << errno <<
"): Ch5678 must be for Corvid88, but no HDMI on that device" << endl;
1539 if (mDevice.
features().CanDo12gRouting())
1549 fb = 4; sdi = fb; mux = fb / 2; csc = fb;
1555 for (path = 0; path < 4; path++)
1573 for (path = 0; path < 4; path++)
1590 for (path = 0; path < 4; path++)
1604 for (path = 0; path < 4; path++)
1614 return !conns.empty();
1617 #if defined(AJALinux)
1618 int NTV2VCAM::ExtractNumber(
const char* str)
1621 int i = s.length() - 1;
1622 while (i >= 0 && isdigit(s[i]))
1624 return stoi(s.substr(i + 1));
1628 int NTV2VCAM::GetFps()
1665 #if defined(AJA_WINDOWS)
1666 EnumPins::EnumPins(NTV2VCAM* filter_, EnumPins* pEnum)
1668 , mCurPin(pEnum ? pEnum->mCurPin : 0)
1672 STDMETHODIMP EnumPins::QueryInterface(REFIID
riid,
void** ppv)
1677 if (
riid == IID_IUnknown ||
riid == IID_IEnumPins)
1679 *ppv =
static_cast<IEnumPins*
>(
this);
1685 return E_NOINTERFACE;
1690 return (
ULONG)InterlockedIncrement(&mRefCount);
1695 long ref = InterlockedDecrement(&mRefCount);
1705 STDMETHODIMP EnumPins::Next(
ULONG cPins, IPin * *ppPins,
ULONG * pcFetched)
1707 if (!ppPins || (cPins > 1 && !pcFetched))
1711 for (
int i = 0; i < cPins && mCurPin < mpFilter->GetPinCount(); ++i)
1713 IPin* pPin = mpFilter->GetPin(mCurPin);
1717 ppPins[fetched++] = pPin;
1723 *pcFetched = fetched;
1725 return fetched == cPins ? S_OK : S_FALSE;
1728 STDMETHODIMP EnumPins::Skip(
ULONG cPins)
1731 if (mCurPin >= mpFilter->GetPinCount())
1733 mCurPin = mpFilter->GetPinCount();
1739 STDMETHODIMP EnumPins::Reset()
1745 STDMETHODIMP EnumPins::Clone(IEnumPins * *ppEnum)
1750 EnumPins* pNew =
new EnumPins(mpFilter,
this);
1752 return E_OUTOFMEMORY;
1759 EnumMediaTypes::EnumMediaTypes(OutputVideoPin * pin_) : pin(pin_)
1763 STDMETHODIMP EnumMediaTypes::QueryInterface(REFIID
riid,
void** ppv)
1765 if (
riid == IID_IUnknown ||
riid == IID_IEnumMediaTypes)
1768 *ppv =
static_cast<IEnumMediaTypes*
>(
this);
1773 return E_NOINTERFACE;
1778 return (
ULONG)InterlockedIncrement(&mRefCount);
1783 long ref = InterlockedDecrement(&mRefCount);
1792 STDMETHODIMP EnumMediaTypes::Next(
ULONG cMediaTypes, AM_MEDIA_TYPE** ppMediaTypes,
ULONG * pcFetched)
1795 if (curMT == 0 && cMediaTypes > 0)
1797 AM_MEDIA_TYPE* pmt = (AM_MEDIA_TYPE*)CoTaskMemAlloc(
sizeof(AM_MEDIA_TYPE));
1799 return E_OUTOFMEMORY;
1801 ZeroMemory(pmt,
sizeof(AM_MEDIA_TYPE));
1803 HRESULT
hr = pin->GetMediaType(&mt);
1808 return hr == VFW_S_NO_MORE_ITEMS ? S_FALSE :
hr;
1812 ppMediaTypes[0] = pmt;
1818 *pcFetched = nFetched;
1820 return (nFetched == cMediaTypes) ? S_OK : S_FALSE;
1823 STDMETHODIMP EnumMediaTypes::Skip(
ULONG cMediaTypes)
1825 if ((curMT + cMediaTypes) > 1)
1830 curMT += cMediaTypes;
1834 STDMETHODIMP EnumMediaTypes::Reset()
1840 STDMETHODIMP EnumMediaTypes::Clone(IEnumMediaTypes** ppEnum)
1845 EnumMediaTypes* pNew =
new EnumMediaTypes(pin);
1847 return E_OUTOFMEMORY;
1849 pNew->curMT = curMT;
1854 #endif // defined(AJA_WINDOWS)