AJA NTV2 SDK  17.6.0.2675
NTV2 SDK 17.6.0.2675
ntv2vcam.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
8 #ifndef _NTV2VCAM_H
9 #define _NTV2VCAM_H
10 
11 #if defined(AJA_WINDOWS)
12  #include <streams.h>
13  #include <initguid.h>
14  #include <vector>
15  #include <mutex>
16 #endif
17 
18 //AJA headers
19 #include <ntv2publicinterface.h>
20 #include <ntv2devicescanner.h>
21 #include <ajabase/common/common.h>
22 #include <ajabase/system/process.h>
23 #include "ntv2democommon.h"
24 
25 #if defined(AJALinux)
26  //V4L headers
27  #include <linux/videodev2.h>
28  #include <sys/ioctl.h>
29  //ALSA headers
30  #include <alsa/asoundlib.h>
31 #endif
32 
33 //std headers
34 #include <signal.h>
35 
36 //local headers
37 #if defined(AJALinux)
38  #include "v4l2loopback.h"
39 #endif
40 
41 #define AUDIO_BYTESPERSAMPLE 4
42 #if defined(AJALinux)
43  #define AJA_MISSING_DEV_V4L2LOOPBACK // Uncomment if /dev/v4l2loopback missing
44  #if !defined(AJA_MISSING_DEV_V4L2LOOPBACK)
45  #define V4L2_DRIVER_NAME "/dev/v4l2loopback"
46  #endif
47 #endif
48 
49 using namespace std;
50 
51 #define AJA_VW_SUCCESS 0
52 #define AJA_VW_INVALIDARGS 1
53 #define AJA_VW_INVALIDAJADEVICE 2
54 #define AJA_VW_AJADEVICENOTREADY 3
55 #define AJA_VW_AJADEVICENOCAPTURE 4
56 #define AJA_VW_INVALIDPIXELFORMAT 5
57 #define AJA_VW_AJADEVICENOPIXELFORMAT 6
58 #define AJA_VW_NOTSISUPPORT 7
59 #define AJA_VW_INVALIDINPUTCHANNEL 8
60 #define AJA_VW_INVALIDINPUTSOURCE 9
61 #define AJA_VW_ENABLECHANNELSFAILED 10
62 #define AJA_VW_ENABLEINPUTINTERRUPTFAILED 11
63 #define AJA_VW_SUBSCRIBEINPUTVERTICALEVENTFAILED 12
64 #define AJA_VW_SUBSCRIBEOUTPUTVERTICALEVENTFAILED 13
65 #define AJA_VW_SETSDITRANSITENABLEFAILED 14
66 #define AJA_VW_WAITFOROUTPUTVERTICALINTERRUPTFAILED 14
67 #define AJA_VW_INVALIDVIDEOFORMAT 15
68 #define AJA_VW_SETCAPTUREMODEFAILED 16
69 #define AJA_VW_SETFREERUNREFERENCEFAILED 17
70 #define AJA_VW_SETVIDEOFORMATFAILED 18
71 #define AJA_VW_SETVANCMODEOFFFAILED 19
72 #define AJA_VW_SETTSIFRAMEENABLEFAILED 20
73 #define AJA_VW_SET4KSQUARESENABLEFAILED 21
74 #define AJA_VW_SETFRAMEBUFFERFORMATFAILED 22
75 #define AJA_VW_INCORRECTMULTILINKAUDIOCHANNEL 23
76 #define AJA_VW_APPLYSIGNALROUTEFAILED 24
77 #define AJA_VW_ACINITFORINPUTFAILED 25
78 #define AJA_VW_ACSTARTFAILED 26
79 #define AJA_VW_ACSETVIDEOBUFFERFAILED 27
80 #define AJA_VW_ACSETAUDIOBUFFERFAILED 28
81 #define AJA_VW_ACSETANCBUFFERSFAILED 29
82 #define AJA_VW_V4L2DRIVEROPENFAILED 30
83 #define AJA_VW_V4L2DEVICECREATEFAILED 31
84 #define AJA_VW_V4L2DEVICEOPENFAILED 32
85 #define AJA_VW_ACTRANSFERFAILED 33
86 #define AJA_VW_ACGETINPUTTIMECODESFAILED 34
87 #define AJA_VW_ACSTOPFAILED 35
88 #define AJA_VW_V4L2DEVICEREMOVEFAILED 36
89 #define AJA_VW_ALSESETUPFAILED 37
90 #define AJA_VW_CONFIGAUDIOSYSTEMFAILED 38
91 #define AJA_VW_NOHDMISUPPORT 39
92 #define AJA_VW_GETFRAMESERVICESFAILED 40
93 #define AJA_VW_SETFRAMESERVICESFAILED 41
94 #define AJA_VW_GETDEVICEOWNERFAILED 42
95 #define AJA_VW_GETINPUTROUTEFAILED 43
96 #define AJA_VW_SETACFRAMERANGEFAILED 44
97 #define AJA_VW_MISSINGARGS 45
98 #define AJA_VW_GETPOINTERFAILED 46
99 #define AJA_VW_SAMPLEBUFFERSIZEMISMATCH 47
100 
101 #if defined(AJA_WINDOWS)
102 #define VCAM_FILTER_NAME_W L"AJA Virtual Webcam"
103 #define VCAM_VIDEO_PIN_NAME_W L"AJA Virtual Webcam Video Output Pin"
104 #define VCAM_AUDIO_PIN_NAME_W L"AJA Virtual Webcam Audio Output Pin"
105 
106 #define VCAM_FILTER_NAME "AJA Virtual Webcam"
107 #define VCAM_VIDEO_PIN_NAME "AJA Virtual Webcam Video Output Pin"
108 #define VCAM_AUDIO_PIN_NAME "AJA Virtual Webcam Audio Output Pin"
109 
110 const GUID CLSID_VirtualWebcam=
111 { 0xac313179, 0xa0af, 0x4110, { 0xa7, 0x15, 0xe5, 0xff, 0xe7, 0x26, 0x3c, 0xf0 } };
112 
113 DEFINE_GUID(IID_IAjaFilterInterface,
114  0x97d9d47a, 0x3851, 0x4298, 0xb8, 0x7c, 0x8a, 0xd, 0x11, 0xac, 0x9a, 0x19);
115 #endif // if defined(AJA_WINDOWS)
116 
117 /*
118  * Assumptions:
119  * app requires root access to create V4L2 device
120  * TSI only, no squares
121  * set OEM tasks to prevent interference from AJA retail services
122  * multi-channel not required for the time being
123  * tested with vlc for video, ffplay for both video and audio
124  * tested with obs for both video and audio; make sure the AJA plugins are not included in obs
125  */
126 
127 #if defined(AJA_WINDOWS)
128  #define MAX_VIDEOS 24
129  #define MAX_AUDIOS 24
130 
131  template <typename T>
132  class CircularBuffer
133  {
134  private:
135  std::vector<T> buffer;
136  size_t head;
137  size_t tail;
138  size_t maxSize;
139  bool isFull;
140  std::mutex mtx;
141 
142  public:
143  CircularBuffer(size_t size)
144  : buffer(size), head(0), tail(0), maxSize(size), isFull(false)
145  {
146  }
147 
148  bool isEmpty() const {return !isFull && (head == tail);}
149  size_t capacity() const {return maxSize;}
150 
151  void reset()
152  {
153  std::lock_guard<std::mutex> lock(mtx);
154  head = 0;
155  tail = 0;
156  isFull = false;
157  }
158 
159  bool push (const T& item)
160  {
161  std::lock_guard<std::mutex> lock(mtx);
162  buffer[head] = item;
163  head = (head + 1) % maxSize;
164  if (isFull)
165  tail = (tail + 1) % maxSize;
166  isFull = head == tail;
167  return true;
168  }
169 
170  bool pop (T& item)
171  {
172  std::lock_guard<std::mutex> lock(mtx);
173  if (isEmpty())
174  return false;
175 
176  item = buffer[tail];
177  tail = (tail + 1) % maxSize;
178  isFull = false;
179  return true;
180  }
181 
182  size_t size() const
183  {
184  size_t size = maxSize;
185  if (!isFull)
186  {
187  if (head >= tail)
188  size = head - tail;
189  else
190  size = maxSize + head - tail;
191  }
192  return size;
193  }
194  }; // CircularBuffer
195 
196  class OutputPin
197  {
198  public:
199  virtual ~OutputPin() {}
200  };
201 
202  class OutputVideoPin : public OutputPin, public CSourceStream, public IKsPropertySet, public IAMStreamConfig
203  {
204  friend class NTV2VCAM;
205  public:
206  OutputVideoPin (HRESULT* phr, CSource* pFilter, LPCWSTR pPinName);
207  ~OutputVideoPin();
208  NTV2VCAM * VCAM (void) const {return reinterpret_cast<NTV2VCAM*>(m_pFilter);}
209 
210  STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
211  STDMETHODIMP_(ULONG) AddRef() override;
212  STDMETHODIMP_(ULONG) Release() override;
213 
214  // CSourceStream methods
215  STDMETHODIMP CheckMediaType(const CMediaType* pMediaType) override;
216  STDMETHODIMP GetMediaType(CMediaType* pMediaType) override;
217  STDMETHODIMP FillBuffer(IMediaSample* pSample) override;
218 
219  // CBaseOutputPin methods
220  STDMETHODIMP DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pRequest) override;
221 
222  // CBasePin methods
223  STDMETHODIMP EnumMediaTypes(IEnumMediaTypes** ppEnum) override;
224 
225  // IQualityControl methods
226  STDMETHODIMP Notify(IBaseFilter* pSender, Quality q) override;
227 
228  // IKsPropertySet methods
229  STDMETHODIMP Set(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData) override;
230  STDMETHODIMP Get(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData, DWORD* pcbReturned) override;
231  STDMETHODIMP QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD* pTypeSupport) override;
232 
233  // IAMStreamConfig methods
234  STDMETHODIMP SetFormat(AM_MEDIA_TYPE* pmt) override;
235  STDMETHODIMP GetFormat(AM_MEDIA_TYPE** ppmt) override;
236  STDMETHODIMP GetNumberOfCapabilities(int* piCount, int* piSize) override;
237  STDMETHODIMP GetStreamCaps(int iIndex, AM_MEDIA_TYPE** ppmt, BYTE* pSCC) override;
238  }; // OutputVideoPin
239 
240  class OutputAudioPin : public OutputPin, public CSourceStream, public IKsPropertySet, public IAMStreamConfig
241  {
242  friend class NTV2VCAM;
243  public:
244  OutputAudioPin(HRESULT* phr, CSource* pFilter, LPCWSTR pPinName);
245  ~OutputAudioPin();
246  NTV2VCAM * VCAM (void) const {return reinterpret_cast<NTV2VCAM*>(m_pFilter);}
247 
248  STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
249  STDMETHODIMP_(ULONG) AddRef() override;
250  STDMETHODIMP_(ULONG) Release() override;
251 
252  // CSourceStream methods
253  STDMETHODIMP CheckMediaType(const CMediaType* pMediaType) override;
254  STDMETHODIMP GetMediaType(CMediaType* pMediaType) override;
255  STDMETHODIMP FillBuffer(IMediaSample* pSample) override;
256 
257  // CBaseOutputPin methods
258  STDMETHODIMP DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pRequest) override;
259 
260  // CBasePin methods
261  STDMETHODIMP EnumMediaTypes(IEnumMediaTypes** ppEnum) override;
262 
263  // IQualityControl methods
264  STDMETHODIMP Notify(IBaseFilter* pSender, Quality q) override;
265 
266  // IKsPropertySet methods
267  STDMETHODIMP Set(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData) override;
268  STDMETHODIMP Get(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData, DWORD* pcbReturned) override;
269  STDMETHODIMP QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD* pTypeSupport) override;
270 
271  // IAMStreamConfig methods
272  STDMETHODIMP SetFormat(AM_MEDIA_TYPE* pmt) override;
273  STDMETHODIMP GetFormat(AM_MEDIA_TYPE** ppmt) override;
274  STDMETHODIMP GetNumberOfCapabilities(int* piCount, int* piSize) override;
275  STDMETHODIMP GetStreamCaps(int iIndex, AM_MEDIA_TYPE** ppmt, BYTE* pSCC) override;
276  }; // OutputAudioPin
277 
278  class NTV2VCAM : public CSource
279  {
280  public:
281  static CUnknown* WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT* phr);
282 
283  // CSource methods
284  STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
285  STDMETHODIMP_(ULONG) AddRef() override;
286  STDMETHODIMP_(ULONG) Release() override;
287 
288  // CBaseFilter methods
289  STDMETHODIMP EnumPins(IEnumPins** ppEnum) override;
290  STDMETHODIMP FindPin(LPCWSTR Id, IPin** ppPin) override;
291  STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo) override;
292  STDMETHODIMP JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName) override;
293  STDMETHODIMP QueryVendorInfo(LPWSTR* pVendorInfo) override;
294 
295  NTV2VCAM(LPUNKNOWN pUnk, HRESULT* phr);
296  ~NTV2VCAM();
297 
298  bool Initialize();
299  HRESULT GetNextFrame(OutputPin* pPin, IMediaSample* pSample);
300  ULWord GetNumAudioChannels() { return mNumAudioChannels; }
301  ULWord GetAudioSampleRate() { return mSampleRate; }
302  ULWord GetAudioBitsPerSample() { return mBitsPerSample; }
303  ULWord GetNumAudioLinks() { return mNumAudioLinks; }
304 #endif // if defined(AJA_WINDOWS)
305 
306 #if defined(AJALinux)
307  class NTV2VCAM
308  {
309  public: // PUBLIC INSTANCE METHODS
310  ~NTV2VCAM();
311 
312  bool Initialize (int argc, const char** argv);
313  bool Run (void);
314 #endif // if defined(AJALinux)
315 
316  private: // PRIVATE INSTANCE METHODS
317  string ULWordToString(const ULWord inNum);
318  bool Get4KInputFormat(NTV2VideoFormat& inOutVideoFormat);
319  void SetupAudio();
320  bool GetInputRouting(NTV2XptConnections& conns, const bool isInputRGB);
321  bool GetInputRouting4K(NTV2XptConnections& conns, const bool isInputRGB);
322 #if defined(AJALinux)
323  int ExtractNumber(const char* str);
324 #endif // if defined(AJALinux)
325  int GetFps();
326 
327  private: // PRIVATE INSTANCE DATA
328  int mErrorCode = AJA_VW_SUCCESS;
329  string mAjaDevice;
330  string mInputType;
331  string mPixelFormatStr;
332 #if defined(AJALinux)
333  string mVideoDevice;
334  string mAudioDevice;
335 #endif // if defined(AJALinux)
336  CNTV2Card mDevice;
337  bool mIsKonaHDMI = false;
339  bool mDoMultiFormat = false;
340  bool mDoTSIRouting = true;
343  UWord mNumSpigots = 0;
344  NTV2ChannelSet mActiveFrameStores;
345  NTV2ChannelSet mActiveSDIs;
349  NTV2IOKinds mIOKinds = NTV2_IOKINDS_SDI;
350  NTV2Buffer mVideoBuffer;
351  NTV2TaskMode mSavedTaskMode = NTV2_TASK_MODE_INVALID;
352  NTV2Buffer mAudioBuffer;
354  UWord mNumAudioLinks = 1;
355  ULWord mNumAudioChannels = 1;
356  unsigned int mSampleRate = 48000;
357  ULWord mBitsPerSample = 32;
358  NTV2ACFrameRange mFrames;
359  AUTOCIRCULATE_TRANSFER mAcTransfer;
360 #if defined(AJALinux)
361  snd_pcm_t * mPcmHandle = AJA_NULL;
362  snd_pcm_uframes_t mAudioFrames = 2;
363  #if !defined(AJA_MISSING_DEV_V4L2LOOPBACK)
364  int mLbDevice = -1;
365  #endif
366  int mLbDeviceNR = -1;
367  int mLbDisplay = -1;
368 #endif // if defined(AJALinux)
369 #if defined(AJA_WINDOWS)
370  bool mInitialized = false;
371  bool mRunning = false;
372  CircularBuffer<NTV2Buffer> mVideos;
373  CircularBuffer<NTV2Buffer> mAudios;
374 #endif // if defined(AJA_WINDOWS)
375 }; // NTV2VCAM
376 
377 #if defined(AJA_WINDOWS)
378  class EnumPins : public IEnumPins
379  {
380  private:
381  volatile long mRefCount = 1;
382  NTV2VCAM* mpFilter = nullptr;
383  int mCurPin = 0;
384 
385  public:
386  EnumPins(NTV2VCAM* mpFilter, EnumPins* pEnum);
387 
388  // IUnknown
389  STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
390  STDMETHODIMP_(ULONG) AddRef();
391  STDMETHODIMP_(ULONG) Release();
392 
393  // IEnumPins
394  STDMETHODIMP Next(ULONG cPins, IPin** ppPins, ULONG* pcFetched);
395  STDMETHODIMP Skip(ULONG cPins);
396  STDMETHODIMP Reset();
397  STDMETHODIMP Clone(IEnumPins** ppEnum);
398  }; // EnumPins
399 
400  class EnumMediaTypes : public IEnumMediaTypes
401  {
402  private:
403  volatile long mRefCount = 1;
404  OutputVideoPin* pin = nullptr;
405  UINT curMT = 0;
406 
407  public:
408  EnumMediaTypes(OutputVideoPin* pin);
409 
410  // IUnknown
411  STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
412  STDMETHODIMP_(ULONG) AddRef();
413  STDMETHODIMP_(ULONG) Release();
414 
415  // IEnumMediaTypes
416  STDMETHODIMP Next(ULONG cMediaTypes, AM_MEDIA_TYPE** ppMediaTypes, ULONG* pcFetched);
417  STDMETHODIMP Skip(ULONG cMediaTypes);
418  STDMETHODIMP Reset();
419  STDMETHODIMP Clone(IEnumMediaTypes** ppEnum);
420  }; // EnumMediaTypes
421 #endif // if defined(AJA_WINDOWS)
422 
423 #endif // _NTV2VCAM_H
NTV2TaskMode
enum NTV2EveryFrameTaskMode NTV2TaskMode
DEFINE_GUID
DEFINE_GUID(GUID_DSHOW_CTL, 0x28cf047a, 0x2437, 0x4b24, 0xb6, 0x53, 0xb9, 0x44, 0x6a, 0x41, 0x9a, 0x69)
NTV2FormatDescriptor
Describes a video frame for a given video standard or format and pixel format, including the total nu...
Definition: ntv2formatdescriptor.h:41
streams.h
NTV2Channel
NTV2Channel
These enum values are mostly used to identify a specific widget_framestore. They're also commonly use...
Definition: ntv2enums.h:1346
NTV2Buffer
Describes a user-space buffer on the host computer. I have an address and a length,...
Definition: ntv2publicinterface.h:6212
CSourceStream
Definition: source.h:88
NTV2FrameBufferFormat
NTV2FrameBufferFormat
Identifies a particular video frame buffer format. See Device Frame Buffer Formats for details.
Definition: ntv2enums.h:213
STDMETHODIMP_
STDMETHODIMP_(ULONG) CUnknown
Definition: combase.cpp:163
mVideoFormat
mVideoFormat
Definition: ntv2vcam.cpp:801
mPixelFormat
mPixelFormat
Definition: ntv2vcam.cpp:710
CMediaType
Definition: mtype.h:18
NTV2_CHANNEL_INVALID
@ NTV2_CHANNEL_INVALID
Definition: ntv2enums.h:1357
AJA_VW_SUCCESS
#define AJA_VW_SUCCESS
Definition: ntv2vcam.h:51
AUTOCIRCULATE_WITH_ANC
#define AUTOCIRCULATE_WITH_ANC
Use this to AutoCirculate with ancillary data.
Definition: ntv2publicinterface.h:5705
NTV2_IOKINDS_SDI
@ NTV2_IOKINDS_SDI
Specifies SDI input/output kinds.
Definition: ntv2enums.h:1286
process.h
Declares the AJAProcess class.
ULWord
uint32_t ULWord
Definition: ajatypes.h:256
pName
CHAR * pName
Definition: amvideo.cpp:26
ntv2devicescanner.h
Declares the CNTV2DeviceScanner class.
NTV2ACFrameRange
AutoCirculate Frame Range.
Definition: ntv2utils.h:969
NTV2_INPUTSOURCE_INVALID
@ NTV2_INPUTSOURCE_INVALID
The invalid video input.
Definition: ntv2enums.h:1271
mInputChannel
mInputChannel
Definition: ntv2vcam.cpp:1010
riid
__in REFIID riid
Definition: dllentry.cpp:192
UWord
uint16_t UWord
Definition: ajatypes.h:254
NTV2_FBF_8BIT_YCBCR
@ NTV2_FBF_8BIT_YCBCR
See 8-Bit YCbCr Format.
Definition: ntv2enums.h:217
AUTOCIRCULATE_TRANSFER
This object specifies the information that will be transferred to or from the AJA device in the CNTV2...
Definition: ntv2publicinterface.h:8288
CNTV2Card
I interrogate and control an AJA video/audio capture/playout device.
Definition: ntv2card.h:28
NTV2_TASK_MODE_INVALID
@ NTV2_TASK_MODE_INVALID
Definition: ntv2publicinterface.h:4467
CSource
Definition: source.h:43
NTV2ChannelSet
std::set< NTV2Channel > NTV2ChannelSet
A set of distinct NTV2Channel values.
Definition: ntv2publicinterface.h:3938
CUnknown
Definition: combase.h:200
AJA_NULL
#define AJA_NULL
Definition: ajatypes.h:200
NTV2InputSource
NTV2InputSource
Identifies a specific video input source.
Definition: ntv2enums.h:1256
NTV2_FORMAT_UNKNOWN
@ NTV2_FORMAT_UNKNOWN
Definition: ntv2enums.h:528
mFormatDesc
mFormatDesc
Definition: ntv2vcam.cpp:942
false
#define false
Definition: ntv2devicefeatures.h:25
ntv2democommon.h
This file contains some structures, constants, classes and functions that are used in some of the dem...
common.h
Private include file for all ajabase sources.
AUTOCIRCULATE_WITH_RP188
#define AUTOCIRCULATE_WITH_RP188
Use this to AutoCirculate with RP188.
Definition: ntv2publicinterface.h:5699
SetupAudio
SetupAudio()
ULONG
ULONG(__stdcall *_RegisterTraceGuids)(__in IN WMIDPREQUEST RequestAddress
NTV2XptConnections
std::map< NTV2InputXptID, NTV2OutputXptID > NTV2XptConnections
Definition: ntv2signalrouter.h:39
std
Definition: json.hpp:5362
v4l2loopback.h
NTV2VideoFormat
enum _NTV2VideoFormat NTV2VideoFormat
Identifies a particular video format.
ntv2publicinterface.h
Declares enums and structs used by all platform drivers and the SDK.
NTV2AudioSystem
NTV2AudioSystem
Used to identify an Audio System on an NTV2 device. See Audio System Operation for more information.
Definition: ntv2enums.h:3873
NTV2IOKinds
ULWord NTV2IOKinds
Definition: ntv2enums.h:1299
NTV2_AUDIOSYSTEM_INVALID
@ NTV2_AUDIOSYSTEM_INVALID
Definition: ntv2enums.h:3885