AJA NTV2 SDK  18.0.0.2122
NTV2 SDK 18.0.0.2122
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
The invalid video input.
Definition: ntv2enums.h:1277
NTV2AudioSystem
Used to identify an Audio System on an NTV2 device. See Audio System Operation for more information...
Definition: ntv2enums.h:3895
Specifies SDI input/output kinds.
Definition: ntv2enums.h:1292
CHAR * pName
Definition: amvideo.cpp:26
I interrogate and control an AJA video/audio capture/playout device.
Definition: ntv2card.h:28
NTV2FrameBufferFormat
Identifies a particular video frame buffer pixel format. See Device Frame Buffer Formats for details...
Definition: ntv2enums.h:219
NTV2TaskMode
Describes the task mode state. See also: Sharing AJA Devices With Other Applications.
enum _NTV2VideoFormat NTV2VideoFormat
Identifies a particular video format.
ULONG(__stdcall *_RegisterTraceGuids)(__in IN WMIDPREQUEST RequestAddress
Definition: json.hpp:5362
#define false
uint32_t ULWord
Definition: ajatypes.h:223
NTV2Channel
These enum values are mostly used to identify a specific widget_framestore. They&#39;re also commonly use...
Definition: ntv2enums.h:1357
mVideoFormat
Definition: ntv2vcam.cpp:801
mPixelFormat
Definition: ntv2vcam.cpp:710
AutoCirculate Frame Range.
Definition: ntv2utils.h:971
#define AJA_NULL
Definition: ajatypes.h:167
Describes a video frame for a given video standard or format and pixel format, including the total nu...
mInputChannel
Definition: ntv2vcam.cpp:1010
#define AUTOCIRCULATE_WITH_ANC
Use this to AutoCirculate with ancillary data.
STDMETHODIMP_(ULONG) CUnknown
Definition: combase.cpp:163
Declares the CNTV2DeviceScanner class.
Declares the AJAProcess class.
Describes a user-space buffer on the host computer. I have an address and a length, plus some optional attributes (allocated by SDK?, page-aligned? etc.).
NTV2InputSource
Identifies a specific video input source.
Definition: ntv2enums.h:1262
This object specifies the information that will be transferred to or from the AJA device in the CNTV2...
__in REFIID riid
Definition: dllentry.cpp:192
#define AJA_VW_SUCCESS
Definition: ntv2vcam.h:51
std::set< NTV2Channel > NTV2ChannelSet
A set of distinct NTV2Channel values.
mFormatDesc
Definition: ntv2vcam.cpp:942
uint16_t UWord
Definition: ajatypes.h:221
SetupAudio()
Definition: source.h:43
This file contains some structures, constants, classes and functions that are used in some of the dem...
Private include file for all ajabase sources.
DEFINE_GUID(GUID_DSHOW_CTL, 0x28cf047a, 0x2437, 0x4b24, 0xb6, 0x53, 0xb9, 0x44, 0x6a, 0x41, 0x9a, 0x69)
std::map< NTV2InputXptID, NTV2OutputXptID > NTV2XptConnections
#define AUTOCIRCULATE_WITH_RP188
Use this to AutoCirculate with RP188.
Declares enums and structs used by all platform drivers and the SDK.
ULWord NTV2IOKinds
Definition: ntv2enums.h:1310
See 8-Bit YCbCr Format.
Definition: ntv2enums.h:223