AJA NTV2 SDK  18.1.0.2439
NTV2 SDK 18.1.0.2439
ntv2ccgrabber.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
8 #include "ntv2ccgrabber.h"
9 #include "ntv2captionrenderer.h"
10 #include "ntv2line21captioner.h"
15 #include "ntv2debug.h"
16 #include "ntv2transcode.h"
17 #include "ajabase/common/types.h"
18 #include "ajabase/system/memory.h"
19 #include <iostream>
20 #include <iomanip>
21 #include <utility> // std::rel_ops
22 #include <algorithm> // set_difference
23 #include <iterator> // for inserter
24 
25 using namespace std;
26 using namespace std::rel_ops;
27 
28 #define AsConstUBytePtr(__p__) reinterpret_cast<const UByte*>(__p__)
29 #define AsConstULWordPtr(__p__) reinterpret_cast<const ULWord*>(__p__)
30 #define AsULWordPtr(__p__) reinterpret_cast<ULWord*>(__p__)
31 #define AsUBytePtr(__p__) reinterpret_cast<UByte*>(__p__)
32 //#define NTV2_BUFFER_LOCK // Define this to use buffer locking in kernel driver
33 
34 static const ULWord kAppSignature NTV2_FOURCC ('C','C','G','R');
35 static const NTV2Line21Attributes kRedOnTransparentBG (NTV2_CC608_Red, NTV2_CC608_Blue, NTV2_CC608_Transparent);
36 static const NTV2Line21Attributes kGreenOnTransparentBG (NTV2_CC608_Green, NTV2_CC608_Blue, NTV2_CC608_Transparent);
37 static const uint32_t MAX_ACCUM_FRAME_COUNT (30); // At least every second?
38 
39 
41 
42  : mConfig (inConfigData),
43  mCaptureThread (AJAThread()),
44  mSavedTaskMode (NTV2_DISABLE_TASKS),
45  mAudioSystem (mConfig.fWithAudio ? NTV2_AUDIOSYSTEM_1 : NTV2_AUDIOSYSTEM_INVALID),
46  mVancMode (NTV2_VANCMODE_INVALID),
47  mGlobalQuit (false),
48  mSquares (false),
49  mLastOutStr (),
50  mLastOutFrame (0),
51  mErrorTally (0),
52  mCaptionDataTally (0),
53  m608Channel (mConfig.fCaptionChannel),
54  m608Mode (NTV2_CC608_CapModeUnknown),
55  m608Decoder (),
56  mVPIDInfoDS1 (0),
57  mVPIDInfoDS2 (0),
58  mInputFrameStores (),
59  mActiveSDIInputs (),
60  mActiveCSCs (),
61  mInputConnections (),
62  mHostBuffers (),
63  mCircularBuffer (),
64  mInputXferInfo (),
65  mHeadUpDisplayOn (true),
66  mOutputChannel (NTV2_CHANNEL_INVALID),
67  mPlayoutFBF (NTV2_FBF_ARGB),
68  mPlayoutThread (AJAThread()),
69  mOutputConnections ()
70 {
71  CNTV2CaptionDecoder608::Create(m608Decoder);
72  CNTV2CaptionDecoder708::Create(m708DecoderAnc);
73  CNTV2CaptionDecoder708::Create(m708DecoderVanc);
74  NTV2_ASSERT (m608Decoder && m708DecoderAnc && m708DecoderVanc);
75 
76 } // constructor
77 
78 
80 {
81  if (m608Decoder)
82  m608Decoder->UnsubscribeChangeNotification (Caption608ChangedStatic, this);
83 
84  // Stop my capture thread, then destroy it...
85  Quit();
86 
87  // Unsubscribe from input vertical event...
88  mDevice.UnsubscribeInputVerticalEvent(mInputFrameStores);
89 
91 
92  if (!mConfig.fDoMultiFormat)
93  {
94  mDevice.SetTaskMode(mSavedTaskMode);
95  mDevice.ReleaseStreamForApplication (kAppSignature, static_cast<int32_t>(AJAProcess::GetPid()));
96  }
97 
98 } // destructor
99 
100 
102 {
103  // Set the 'quit' flag, and wait for the threads to go inactive...
104  mGlobalQuit = true;
105 
106  while (mCaptureThread.Active())
107  AJATime::Sleep(10);
108 
109  while (mPlayoutThread.Active())
110  AJATime::Sleep(10);
111 
112  if (!mConfig.fDoMultiFormat)
113  mDevice.ClearRouting();
114 
115 } // Quit
116 
117 
119 {
120  CNTV2DemoCommon::SetDefaultPageSize(); // Set host-specific page size
121 
122  // Open the device...
124  { if (aja::lower(mConfig.fDeviceSpec) != "list" && mConfig.fDeviceSpec != "?")
125  cerr << "## ERROR: Device '" << mConfig.fDeviceSpec << "' not found" << endl;
126  return AJA_STATUS_OPEN;
127  }
128  if (!mDevice.IsDeviceReady(false))
129  {cerr << "## ERROR: Device '" << mConfig.fDeviceSpec << "' not ready" << endl; return AJA_STATUS_INITIALIZE;}
130 
131  const string devStr(mDevice.GetDescription());
132  if (mConfig.fBurnCaptions)
133  {
134  if (mDevice.features().GetNumFrameStores() < 2) // Need 2+ frame stores
135  {
136  cerr << "## ERROR: '" << devStr << "' can't burn-in captions because at least 2 frame stores are required" << endl;
137  return AJA_STATUS_FAIL;
138  }
139  if (!mDevice.features().CanDoPlayback())
140  {
141  cerr << "## ERROR: '" << devStr << "' can't burn-in captions because device can only capture/ingest" << endl;
142  return AJA_STATUS_FAIL;
143  }
144  if (mDevice.features().GetNumVideoInputs() < 1 || mDevice.features().GetNumVideoOutputs() < 1) // Need 1 input & 1 output
145  {
146  cerr << "## ERROR: '" << devStr << "' can't be used -- at least 1 SDI input and 1 SDI output required" << endl;
147  return AJA_STATUS_FAIL;
148  }
149  if (!mDevice.features().GetNumMixers()) // Need 1 or more mixers
150  {
151  cerr << "## ERROR: '" << devStr << "' can't burn-in captions because a mixer/keyer widget is required" << endl;
152  return AJA_STATUS_FAIL;
153  }
154  if (!mDevice.features().CanDoFrameBufferFormat(mPlayoutFBF)) // FrameStore must handle 8-bit RGB with alpha
155  {
156  cerr << "## ERROR: '" << devStr << "' can't burn-in captions because it can't do 8-bit RGB (with alpha)" << endl;
157  return AJA_STATUS_FAIL;
158  }
159  } // if --burn
160 
161  ULWord appSignature (0);
162  int32_t appPID (0);
163  mDevice.GetStreamingApplication (appSignature, appPID); // Who currently "owns" the device?
164  mDevice.GetTaskMode(mSavedTaskMode); // Save the current device state
165  if (!mConfig.fDoMultiFormat)
166  {
167  if (!mDevice.AcquireStreamForApplication (kAppSignature, static_cast<int32_t>(AJAProcess::GetPid())))
168  {
169  cerr << "## ERROR: Unable to acquire '" << devStr << "' because another app (pid " << appPID << ") owns it" << endl;
170  return AJA_STATUS_BUSY; // Another app is using the device
171  }
172  }
173  mDevice.SetTaskMode(NTV2_OEM_TASKS); // Use the OEM service level
174 
175  if (mDevice.features().CanDoMultiFormat())
176  mDevice.SetMultiFormatMode(mConfig.fDoMultiFormat);
177 
178  if (!mConfig.fUseVanc && !mDevice.features().CanDoCustomAnc()) // --vanc not specified && no anc extractors?
179  {
180  cerr << "## WARNING: Enabling VANC because no Anc extractors" << endl;
181  mConfig.fUseVanc = true;
182  }
183 
184  // Set up the input video...
185  AJAStatus status = SetupInputVideo();
186  if (AJA_FAILURE(status))
187  return status;
188 
189  // Set up the audio...
190  status = SetupAudio();
191  if (AJA_FAILURE(status))
192  return status;
193 
194  if (!m608Decoder->SubscribeChangeNotification(Caption608ChangedStatic, this))
195  {cerr << "## WARNING: SubscribeChangeNotification failed" << endl; return AJA_STATUS_FAIL;}
196  #if defined(_DEBUG)
197  cerr << mConfig
198  << "Device Description: " << mDevice.GetDescription() << endl
199  << endl;
200  #endif // defined(_DEBUG)
201  return AJA_STATUS_SUCCESS;
202 
203 } // Init
204 
205 
207 {
209  mDevice.GetVANCMode (vancMode, mConfig.fInputChannel);
210  const ULWord captureBufferSize (::GetVideoWriteSize (inVideoFormat, mConfig.fPixelFormat, vancMode));
211 
213  mCircularBuffer.SetAbortFlag (&mGlobalQuit);
214 
215  // Allocate and add each NTV2FrameData to my circular buffer member variable...
216  mHostBuffers.reserve(CIRCULAR_BUFFER_SIZE);
217  while (mHostBuffers.size() < CIRCULAR_BUFFER_SIZE)
218  {
219  mHostBuffers.push_back(NTV2FrameData()); // Make a new NTV2FrameData...
220  NTV2FrameData & frameData(mHostBuffers.back()); // ...and get a reference to it
221  // Allocate a page-aligned video buffer
222  if (!frameData.fVideoBuffer.Allocate(captureBufferSize, /*pageAlign?*/true))
223  return AJA_STATUS_MEMORY;
224  if (NTV2_IS_VALID_AUDIO_SYSTEM(mAudioSystem))
225  if (!frameData.fAudioBuffer.Allocate(NTV2_AUDIOSIZE_MAX, /*pageAlign?*/true))
226  return AJA_STATUS_MEMORY;
227  // Anc data buffers --- only used if Anc extractors supported...
228  if (mDevice.features().CanDoCustomAnc())
229  {
230  if (!frameData.fAncBuffer.Allocate(NTV2_ANCSIZE_MAX, /*pageAlign?*/true))
231  return AJA_STATUS_MEMORY;
232  if (!frameData.fAncBuffer2.Allocate(NTV2_ANCSIZE_MAX, /*pageAlign?*/true))
233  return AJA_STATUS_MEMORY;
234  }
235  #if defined(NTV2_BUFFER_LOCK)
236  frameData.LockAll(mDevice);
237  #endif
238  mCircularBuffer.Add(&frameData); // Add to my circular buffer
239  } // for each NTV2FrameData
240 
241  return AJA_STATUS_SUCCESS;
242 
243 } // SetupHostBuffers
244 
245 
247 {
248  // Unlock each in-host NTV2FrameData...
249  #if defined(NTV2_BUFFER_LOCK)
250  for (size_t ndx(0); ndx < mHostBuffers.size(); ndx++)
251  {
252  NTV2FrameData & frameData(mHostBuffers.at(ndx));
253  frameData.UnlockAll(mDevice);
254  }
255  #endif // NTV2_BUFFER_LOCK
256  mHostBuffers.clear();
257  mCircularBuffer.Clear();
258  return;
259 
260 } // ReleaseHostBuffers
261 
262 
264 {
265  bool isTransmit (false);
266  const UWord numFrameStores (mDevice.features().GetNumFrameStores());
267  const NTV2DeviceID deviceID (mDevice.GetDeviceID());
268  const string deviceName (::NTV2DeviceIDToString(deviceID));
269  const string channelName (::NTV2ChannelToString(mConfig.fInputChannel, true));
270 
271  // CCGrabber is SDI only
272  // User must have specified at least --input or --channel
274  {cerr << "## ERROR: Must specify at least input source or input channel" << endl; return AJA_STATUS_FAIL;}
275  else if (!NTV2_IS_VALID_INPUT_SOURCE(mConfig.fInputSource))
277  else if (!NTV2_IS_VALID_CHANNEL(mConfig.fInputChannel))
279 
280  // Check input source
281  const string inputName (::NTV2InputSourceToString(mConfig.fInputSource,true));
282  if (!mDevice.features().CanDoInputSource(mConfig.fInputSource))
283  {cerr << "## ERROR: '" << deviceName << "' cannot grab captions from '" << inputName << "'" << endl; return AJA_STATUS_FAIL;}
285  {cerr << "## ERROR: Input '" << inputName << "' not SDI" << endl; return AJA_STATUS_FAIL;}
286 
287  // Check channel
288  if (numFrameStores < UWord(mConfig.fInputChannel+1))
289  {cerr << "## ERROR: " << deviceName << " has no " << channelName << " input" << endl; return AJA_STATUS_FAIL;}
290 
291  const NTV2Channel sdiInput(::NTV2InputSourceToChannel(mConfig.fInputSource));
292  mActiveSDIInputs.insert(sdiInput);
293  if (mDevice.features().HasBiDirectionalSDI()) // If device has bidirectional SDI connectors...
294  if (mDevice.GetSDITransmitEnable(sdiInput, isTransmit)) // ...and GetSDITransmitEnable succeeds...
295  if (isTransmit) // ...and input is set to "transmit"...
296  {
297  mDevice.SetSDITransmitEnable(sdiInput, false); // ...then disable transmit mode...
298  mDevice.WaitForOutputVerticalInterrupt(NTV2_CHANNEL1, 12); // ...and give the device some time to lock to a signal
299  } // if input SDI connector needs to switch from transmit mode
300 
302  mDevice.GetReference(refSrc);
303  if (mConfig.fBurnCaptions || (!mConfig.fBurnCaptions && !mConfig.fDoMultiFormat))
304  {
305  // Set the device output clock reference to the SDI input.
306  // This is necessary only when...
307  // - Doing caption burn-in, which requires syncing the Mixer input to the SDI input;
308  // - Routing E-E, which is only done when not doing burn-in and not doing multi-format mode.
310  mDevice.SetReference(refSrc);
311  }
312  if (mConfig.fBurnCaptions) // Caption burn-in/playout requires choosing an output channel
313  switch (mConfig.fInputChannel)
314  {
315  case NTV2_CHANNEL1: mOutputChannel = (numFrameStores == 2 || numFrameStores > 4) ? NTV2_CHANNEL2 : NTV2_CHANNEL3; break;
316  case NTV2_CHANNEL2: mOutputChannel = (numFrameStores > 4) ? NTV2_CHANNEL3 : NTV2_CHANNEL4; break;
317  case NTV2_CHANNEL3: mOutputChannel = NTV2_CHANNEL4; break;
318  case NTV2_CHANNEL4: mOutputChannel = (numFrameStores > 4) ? NTV2_CHANNEL5 : NTV2_CHANNEL3; break;
319  case NTV2_CHANNEL5: mOutputChannel = NTV2_CHANNEL6; break;
320  case NTV2_CHANNEL6: mOutputChannel = NTV2_CHANNEL7; break;
321  case NTV2_CHANNEL7: mOutputChannel = NTV2_CHANNEL8; break;
322  case NTV2_CHANNEL8: mOutputChannel = NTV2_CHANNEL7; break;
324  }
325 
326  if (!mDevice.features().CanDoFrameBufferFormat(mConfig.fPixelFormat))
327  {cerr << "## ERROR: '" << deviceName << "' doesn't support '" << ::NTV2FrameBufferFormatToString(mConfig.fPixelFormat) << "'" << endl; return AJA_STATUS_FAIL;}
328 
329  // "Tune" the 608 decoder to the desired channel...
330  m608Decoder->SetDisplayChannel(m608Channel);
331  m708DecoderAnc->SetDisplayChannel(m608Channel);
332  m708DecoderVanc->SetDisplayChannel(m608Channel);
333 
334  cerr << "## NOTE: Using " << deviceName << " " << (mConfig.fUseVanc ? "VANC" : "AncExt") << " with spigot=" << inputName
335  << ", ref=" << ::NTV2ReferenceSourceToString(refSrc,true) << ", input=" << channelName;
336  if (mConfig.fBurnCaptions) cerr << ", output=" << ::NTV2ChannelToString(mOutputChannel,true);
337  cerr << endl;
338 
339  return AJA_STATUS_SUCCESS;
340 
341 } // SetupInputVideo
342 
343 
345 {
346  if (NTV2_IS_VALID_AUDIO_SYSTEM(mAudioSystem))
347  {
348  const UWord numAudioSystems (mDevice.features().GetNumAudioSystems());
349  if (numAudioSystems > 1 && UWord(mConfig.fInputChannel) < numAudioSystems)
350  mAudioSystem = ::NTV2ChannelToAudioSystem(mConfig.fInputChannel);
351 
352  // Configure the audio system...
354  mDevice.SetNumberAudioChannels (mDevice.features().GetMaxAudioChannels(), mAudioSystem);
355  mDevice.SetAudioRate (NTV2_AUDIO_48K, mAudioSystem);
356  mDevice.SetAudioBufferSize (NTV2_AUDIO_BUFFER_BIG, mAudioSystem);
357 
358  // Set up the output audio embedders...
359  if (mConfig.fBurnCaptions && numAudioSystems > 1)
360  {
361  if (mConfig.fDoMultiFormat)
362  {
363  UWord sdiOutput(mOutputChannel);
364  if (sdiOutput >= mDevice.features().GetNumVideoOutputs()) // Kona1 has 2 FrameStores/Channels, but only 1 SDI output
365  sdiOutput = mDevice.features().GetNumVideoOutputs() - 1;
366  mDevice.SetSDIOutputAudioSystem(NTV2Channel(sdiOutput), mAudioSystem);
367  }
368  else // Have all device outputs use the same audio system...
369  for (unsigned sdiOutput(0); sdiOutput < mDevice.features().GetNumVideoOutputs(); sdiOutput++)
370  if (!mDevice.features().HasBiDirectionalSDI()
371  || NTV2Channel(sdiOutput) != ::NTV2InputSourceToChannel(mConfig.fInputSource))
372  mDevice.SetSDIOutputAudioSystem(NTV2Channel(sdiOutput), mAudioSystem);
373  }
374 
375  // Loopback mode (E-E audio) should be enabled only when not burning-in captions (i.e. when routing E-E).
376  // If caption burn-in and loopback are enabled, output video will lag the audio, as video frames are delayed
377  // in the ring buffer.
379  }
380  return AJA_STATUS_SUCCESS;
381 
382 } // SetupAudio
383 
384 
387 
390 
393 
394 
396 {
397  const bool isRGBFBF (::IsRGBFormat(mConfig.fPixelFormat));
398  const bool isRGBWire (mVPIDInfoDS1.IsRGBSampling());
399  const bool isSquares (!mVPIDInfoDS1.IsStandardTwoSampleInterleave());
400  const bool is4KHFR (NTV2_IS_HFR_STANDARD(::GetNTV2StandardFromVideoFormat(inVideoFormat)));
401  const NTV2Channel sdiInput (::NTV2InputSourceToChannel(mConfig.fInputSource));
402  const NTV2ChannelList frameStores (::NTV2MakeChannelList(mInputFrameStores));
403  NTV2ChannelList sdiInputs (::NTV2MakeChannelList(mActiveSDIInputs));
404  const NTV2ChannelList activeCSCs (::NTV2MakeChannelList(mActiveCSCs));
405  static const bool ShowRoutingProgress(false);
406 
407  mInputConnections.clear();
408  if (ShowRoutingProgress) mDevice.ClearRouting();
409 
410  // Route frameStore's input to sdiInput's output (possibly through CSC, if required)
411  if (isRGBFBF && isRGBWire)
412  {
413  if (isSquares) // SDIIn ==> DLIn ==> FrameStore
414  {
415  for (size_t ndx(0); ndx < sdiInputs.size(); ndx++)
416  { NTV2Channel frmSt(frameStores.at(ndx)), sdiIn(sdiInputs.at(ndx));
417  mInputConnections.insert(NTV2XptConnection(::GetDLInInputXptFromChannel(sdiIn, /*linkB?*/false),
418  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/false)));
419  mInputConnections.insert(NTV2XptConnection(::GetDLInInputXptFromChannel(sdiIn, /*linkB?*/true),
420  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/true)));
421  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(sdiIn),
422  ::GetDLInOutputXptFromChannel(frmSt)));
423  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
424  }
425  }
426  else // TSI // 2x SDIIn ==> 2x DLIn ==> 425MUX ==> RGBFrameStore
427  {
428  NTV2ChannelSet sdiIns = ::NTV2MakeChannelSet(sdiInput, UWord(2*frameStores.size()));
429  sdiInputs = ::NTV2MakeChannelList(sdiIns);
430  NTV2ChannelList tsiMuxes = CNTV2DemoCommon::GetTSIMuxesForFrameStore(mDevice, frameStores.at(0),
431  UWord(frameStores.size()*2));
432  mDevice.SetSDITransmitEnable(sdiIns, true); // Gotta do this again, since sdiInputs changed
433  for (size_t ndx(0); ndx < sdiInputs.size(); ndx++)
434  { NTV2Channel frmSt(frameStores.at(ndx/2)), tsiMux(tsiMuxes.at(ndx/2)), sdiIn(sdiInputs.at(ndx));
435  mInputConnections.insert(NTV2XptConnection(::GetDLInInputXptFromChannel(sdiIn, /*DS2?*/false),
436  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/false)));
437  mInputConnections.insert(NTV2XptConnection(::GetDLInInputXptFromChannel(sdiIn, /*DS2?*/true),
438  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/true)));
439  mInputConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux, /*lnkB?*/ndx & 1),
440  ::GetDLInOutputXptFromChannel(sdiIn)));
441  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt, /*lnkB?*/false),
442  ::GetTSIMuxOutputXptFromChannel(tsiMux,/*lnkB?*/false, /*rgb?*/true)));
443  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt, /*lnkB?*/true),
444  ::GetTSIMuxOutputXptFromChannel(tsiMux,/*lnkB?*/true, /*rgb?*/true)));
445  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
446  }
447  }
448  }
449  else if (isRGBFBF && !isRGBWire)
450  {
451  if (isSquares) // SDIIn ==> CSC ==> RGBFrameStore
452  for (size_t ndx(0); ndx < sdiInputs.size(); ndx++)
453  { NTV2Channel frmSt(frameStores.at(ndx)), sdiIn(sdiInputs.at(ndx));
454  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt),
455  ::GetCSCOutputXptFromChannel(frmSt, /*key?*/false, /*RGB?*/true)));
456  mInputConnections.insert(NTV2XptConnection(::GetCSCInputXptFromChannel(frmSt),
458  }
459  else // TSI // SDIIn ==> 2 x CSC ==> 425MUX ==> RGBFrameStore
460  {
461  NTV2ChannelSet sdiIns = ::NTV2MakeChannelSet(sdiInput, UWord(frameStores.size()));
462  sdiInputs = ::NTV2MakeChannelList(sdiIns);
464  UWord(2*sdiInputs.size()));
465  NTV2ChannelList tsiMuxes = CNTV2DemoCommon::GetTSIMuxesForFrameStore(mDevice, frameStores.at(0),
466  UWord(frameStores.size()));
467  cerr << "FrameStores: " << ::NTV2ChannelListToStr(frameStores) << endl
468  << "SDIInputs: " << ::NTV2ChannelListToStr(sdiInputs) << endl
469  << "TSIMuxers: " << ::NTV2ChannelListToStr(tsiMuxes) << endl;
470  mDevice.SetSDITransmitEnable(sdiIns, false); // Gotta do this again, since sdiIns changed
471  for (size_t ndx(0); ndx < cscs.size(); ndx++)
472  { NTV2Channel frmSt(frameStores.at(ndx/2)), sdiIn(sdiInputs.at(ndx/2)), tsiMux(tsiMuxes.at(ndx/2)),
473  csc(cscs.at(ndx));
474  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt, /*inputB?*/ndx & 1),
475  ::GetTSIMuxOutputXptFromChannel(tsiMux,/*linkB?*/ndx & 1,/*rgb?*/true)));
476  mInputConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux, /*linkB?*/ndx & 1),
477  ::GetCSCOutputXptFromChannel(csc, /*key?*/false, /*rgb?*/true)));
478  mInputConnections.insert(NTV2XptConnection(::GetCSCInputXptFromChannel(csc),
479  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/ndx & 1)));
480  }
481  }
482  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
483  }
484  else if (!isRGBFBF && isRGBWire)
485  {
486  if (isSquares) // SDIIn ==> DLIn ==> CSC ==> FrameStore
487  {
488  for (size_t ndx(0); ndx < sdiInputs.size(); ndx++)
489  { NTV2Channel frmSt(frameStores.at(ndx)), csc(activeCSCs.at(ndx)), sdi(sdiInputs.at(ndx));
490  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt, /*BInput?*/false),
492  mInputConnections.insert(NTV2XptConnection(::GetCSCInputXptFromChannel(csc),
494  mInputConnections.insert(NTV2XptConnection(::GetDLInInputXptFromChannel(sdi, /*lnkB?*/false),
495  ::GetSDIInputOutputXptFromChannel(sdi, /*DS2?*/false)));
496  mInputConnections.insert(NTV2XptConnection(::GetDLInInputXptFromChannel(sdi, /*lnkB?*/true),
497  ::GetSDIInputOutputXptFromChannel(sdi, /*DS2?*/true)));
498  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
499  }
500  }
501  else // TSI // SDIIn ==> DLIn ==> CSC ==> TSIMux ==> FrameStore
502  {
503  //TBD
504  }
505  }
506  else // SDIIn ==> YUVFrameStore
507  {
508  if (isSquares) // SDIIn ==> FrameStore
509  {
510  for (size_t ndx(0); ndx < sdiInputs.size(); ndx++)
511  { NTV2Channel frmSt(frameStores.at(ndx)), sdiIn(sdiInputs.at(ndx));
512  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt),
514  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
515  }
516  }
517  else // TSI // SDIIn (LFR: 2 x DS1&DS2, 4KHFR: 4 x DS1) ==> 425MUX ==> YUVFrameStore
518  {
519  NTV2XptConnections & mConnections(mInputConnections);
520  sdiInputs = ::NTV2MakeChannelList(sdiInputs.at(0), is4KHFR ? 4 : UWord(frameStores.size()));
521  NTV2ChannelList tsiMuxes = CNTV2DemoCommon::GetTSIMuxesForFrameStore(mDevice, frameStores.at(0),
522  UWord(frameStores.size()));
523  cerr << (is4KHFR ? "4KHFR" : "") << endl << "FrameStores: " << ::NTV2ChannelListToStr(frameStores) << endl
524  << "SDIInputs: " << ::NTV2ChannelListToStr(sdiInputs) << endl << "TSIMuxes: " << ::NTV2ChannelListToStr(tsiMuxes) << endl;
525  for (size_t ndx(0); ndx < sdiInputs.size(); ndx++)
526  { NTV2Channel frmSt(frameStores.at(is4KHFR ? ndx/2 : ndx)),
527  tsiMux(tsiMuxes.at(is4KHFR ? ndx/2 : ndx)),
528  sdiIn(sdiInputs.at(ndx));
529  mConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux, /*linkB?*/is4KHFR && (ndx & 1)),
530  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/false)));
531  if (!is4KHFR)
532  mConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux, /*linkB?*/true),
533  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/true)));
534  mConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt, /*inputB?*/is4KHFR && (ndx & 1)),
535  ::GetTSIMuxOutputXptFromChannel(tsiMux,/*linkB?*/is4KHFR && (ndx & 1))));
536  if (!is4KHFR)
537  mConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt, /*inputB?*/true),
538  ::GetTSIMuxOutputXptFromChannel(tsiMux,/*linkB?*/true)));
539  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
540  }
541  }
542  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
543  }
544  // At this point, sdiInputs is authoritative, so update mActiveSDIInputs...
545  mActiveSDIInputs = ::NTV2MakeChannelSet(sdiInputs);
546 
547  // E-E ROUTING
548  if ((false) /* not ready for prime-time */ && !mConfig.fBurnCaptions && !mConfig.fDoMultiFormat)
549  { // Not doing caption burn-in: route E-E pass-thru...
550  NTV2ChannelList sdiOutputs;
551  if (mDevice.features().HasBiDirectionalSDI())
552  {
554  NTV2ChannelSet sdiOuts;
555  set_difference (allSDIs.begin(), allSDIs.end(), // allSDIs
556  mActiveSDIInputs.begin(), mActiveSDIInputs.end(), // - mActiveSDIInputs
557  inserter(sdiOuts, sdiOuts.begin())); // ==> sdiOuts
558  sdiOutputs = ::NTV2MakeChannelList(sdiOuts);
559  cerr << "allSDIs: " << ::NTV2ChannelSetToStr(allSDIs) << endl << "actSDIIns: " << ::NTV2ChannelSetToStr(mActiveSDIInputs) << endl; // DEBUG
560  }
561  else
563  cerr << "SDIOuts: " << ::NTV2ChannelListToStr(sdiOutputs) << endl << "SDIIns: " << ::NTV2ChannelListToStr(sdiInputs) << endl; // DEBUG
564  for (size_t sdiNdx(0); sdiNdx < sdiOutputs.size(); sdiNdx++)
565  { const NTV2Channel sdiOut(sdiOutputs.at(sdiNdx));
566  const NTV2Channel sdiIn(sdiInputs.at(sdiNdx < sdiInputs.size() ? sdiNdx : sdiInputs.size()-1));
567  if (mDevice.features().HasBiDirectionalSDI() && mActiveSDIInputs.find(sdiOut) == mActiveSDIInputs.end())
568  {
569  cerr << "Switching SDI " << (sdiOut+1) << " to output" << endl; // DEBUG
570  mDevice.SetSDITransmitEnable(sdiOut, true);
571  }
572  if (isRGBWire)
573  { // Route DLIn output to DLOut...
574  mInputConnections.insert(NTV2XptConnection(::GetDLOutInputXptFromChannel(sdiOut),
575  ::GetDLInOutputXptFromChannel(sdiIn)));
576  mInputConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut,false),
577  ::GetDLOutOutputXptFromChannel(sdiOut,false)));
578  mInputConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut,true),
579  ::GetDLOutOutputXptFromChannel(sdiOut,true)));
580  }
581  else
582  mInputConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut),
584  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
585  } // for each output spigot
586  } // if not burning captions and not multiFormat
587 
588  return mDevice.ApplySignalRoute(mInputConnections, /*replaceExistingRouting?*/!mConfig.fDoMultiFormat);
589 
590 } // RouteInputSignal
591 
592 
594 {
595  NTV2_ASSERT (!mConfig.fBurnCaptions); // Must not be burning captions
596 
597  const NTV2Channel sdiInputAsChan (::NTV2InputSourceToChannel(mConfig.fInputSource));
598  const NTV2Standard outputStandard (::GetNTV2StandardFromVideoFormat(inVideoFormat));
599  const NTV2Channel startNum (sdiInputAsChan == NTV2_CHANNEL1 ? NTV2_CHANNEL1 : NTV2_CHANNEL5);
600  const NTV2Channel endNum (sdiInputAsChan == NTV2_CHANNEL1 ? NTV2_CHANNEL5 : NTV2_MAX_NUM_CHANNELS);
601 
602  for (NTV2Channel chan(startNum); chan < endNum; chan = NTV2Channel(chan + 1))
603  {
604  if (ULWord(chan) >= mDevice.features().GetNumVideoChannels())
605  break;
606  if (chan != sdiInputAsChan)
607  if (mDevice.features().CanDoWidget(g3GSDIOutputs[chan]) || mDevice.features().CanDoWidget(gSDIOutputs[chan]))
608  mDevice.SetSDIOutputStandard(chan, outputStandard);
609  } // for each output spigot
610 
611 } // SetOutputStandards
612 
613 
615 {
616  // Start the capture thread...
617  AJAStatus result (StartCaptureThread());
618  if (AJA_FAILURE(result))
619  return result;
620 
621  AJATime::Sleep(500); // Wait a half second for the capture thread to start (or fail?)...
623 
624 } // Run
625 
626 
627 
629 
630 // Starts the capture thread
632 {
633  // Create and start the capture thread...
634  AJAStatus result (mCaptureThread.Attach(CaptureThreadStatic, this));
635  if (AJA_SUCCESS(result))
636  result = mCaptureThread.SetPriority(AJA_ThreadPriority_High);
637  if (AJA_SUCCESS(result))
638  result = mCaptureThread.Start();
639  return result;
640 
641 } // StartCaptureThread
642 
643 
644 // The capture thread function
645 void NTV2CCGrabber::CaptureThreadStatic (AJAThread * pThread, void * pContext) // static
646 {
647  (void) pThread;
648  // Grab the NTV2CCGrabber instance pointer from the pContext parameter,
649  // then call its CaptureFrames method...
650  NTV2CCGrabber * pApp (reinterpret_cast <NTV2CCGrabber *> (pContext));
651  pApp->CaptureFrames ();
652 
653 } // CaptureThreadStatic
654 
655 
656 // The capture function -- capture frames until told to quit...
658 {
659  ULWord xferTally(0), xferFails(0), noVideoTally(0), waitTally(0);
660  bool bUsingVanc (mConfig.fUseVanc); // To detect fUseVanc changes
661  CAPNOTE("Thread started");
662  NTV2_ASSERT(!mActiveSDIInputs.empty());
663 
664  // Loop until time to quit...
665  while (!mGlobalQuit)
666  {
667  NTV2PixelFormat currentPF (mConfig.fPixelFormat);
669  if (currentVF == NTV2_FORMAT_UNKNOWN)
670  break; // Quit
671 
672  // At this point, the input video format is stable.
673 
674  // Configure the input FrameStore(s): pixel format, mode...
675  mDevice.EnableChannels(mInputFrameStores);
676  mDevice.SetFrameBufferFormat(mInputFrameStores, mConfig.fPixelFormat);
677 
678  // Enable and subscribe to the interrupts for the channel to be used...
679  mDevice.EnableInputInterrupt (mInputFrameStores);
680  mDevice.SubscribeInputVerticalEvent (mInputFrameStores);
681 
682  // Set up the device signal routing...
683  RouteInputSignal(currentVF);
684 
685  // Set the device format to the input format detected, and set VANC mode...
686  mDevice.SetVideoFormat (mInputFrameStores, currentVF, /*retailMode*/false);
687  if (NTV2_IS_4K_VIDEO_FORMAT(currentVF))
688  {
689  if (mDevice.features().CanDo12gRouting())
690  mDevice.SetTsiFrameEnable(true, mConfig.fInputChannel);
691  else if (mSquares)
692  mDevice.Set4kSquaresEnable(true, mConfig.fInputChannel);
693  else
694  mDevice.SetTsiFrameEnable(true, mConfig.fInputChannel);
695  mVancMode = NTV2_VANCMODE_OFF;
696  if (mConfig.fUseVanc)
697  CAPWARN("VANC mode incompatible with 4K/UHD format");
698  }
699  else
700  mVancMode = mConfig.fUseVanc ? NTV2_VANCMODE_TALL : NTV2_VANCMODE_OFF; // "Tall" mode is sufficient to grab captions
701  mDevice.SetVANCMode(mInputFrameStores, mVancMode);
702  if (::Is8BitFrameBufferFormat(mConfig.fPixelFormat))
703  mDevice.SetVANCShiftMode (mConfig.fInputChannel, // 8-bit FBFs require VANC bit shift
705 
706  // Set up the circular buffers based on the detected currentVF...
707  AJAStatus status (SetupHostBuffers(currentVF));
708  if (AJA_FAILURE(status))
709  return;
710 
711  if (mConfig.fBurnCaptions) // If burning-in captions...
712  StartPlayThread(); // ...start a new playout thread
713  else // else E-E mode...
714  SetOutputStandards(currentVF); // ...output standard may need changing
715 
716  mDevice.AutoCirculateStop(mConfig.fInputChannel);
717  if (!mDevice.AutoCirculateInitForInput( mConfig.fInputChannel, mConfig.fFrames, mAudioSystem, AUTOCIRCULATE_WITH_RP188
718  | (mDevice.features().CanDoCustomAnc() ? AUTOCIRCULATE_WITH_ANC : 0)))
719  {CAPFAIL("Failed to init Ch" << DEC(mConfig.fInputChannel+1) << " for input"); break;}
720 
721  // Start AutoCirculate...
722  if (!mDevice.AutoCirculateStart(mConfig.fInputChannel))
723  {CAPFAIL("Failed to start Ch" << DEC(mConfig.fInputChannel+1)); break;}
724 
725  // Process frames until signal format changes...
726  while (!mGlobalQuit)
727  {
728  AUTOCIRCULATE_STATUS acStatus;
729  mDevice.AutoCirculateGetStatus (mConfig.fInputChannel, acStatus);
730  if (acStatus.IsRunning() && acStatus.HasAvailableInputFrame())
731  {
732  // At this point, there's at least one fully-formed frame available in the device's
733  // frame buffer to transfer to the host. Reserve an NTV2FrameData to "produce", and
734  // use it to store the next frame to be transferred from the device...
735  NTV2FrameData * pCaptureData (mCircularBuffer.StartProduceNextBuffer());
736  if (pCaptureData)
737  {
738  mInputXferInfo.acFrameBufferFormat = mConfig.fPixelFormat;
739  mInputXferInfo.SetBuffers (pCaptureData->VideoBuffer(), pCaptureData->VideoBufferSize(),
740  pCaptureData->AudioBuffer(), pCaptureData->AudioBufferSize(),
741  pCaptureData->AncBuffer(), pCaptureData->AncBufferSize(),
742  pCaptureData->AncBuffer2(), pCaptureData->AncBuffer2Size());
743 
744  // Transfer the frame data from the device into our host NTV2FrameData...
745  if (mDevice.AutoCirculateTransfer (mConfig.fInputChannel, mInputXferInfo))
746  {
747  xferTally++;
748  if (mConfig.fBurnCaptions)
749  mInputXferInfo.GetInputTimeCodes(pCaptureData->fTimecodes, ::NTV2InputSourceToChannel(mConfig.fInputSource)); // Captured timecodes
750 
751  // Extract closed-captioning data from the host NTV2FrameData while we have full access to it...
752  ExtractClosedCaptionData (mInputXferInfo.GetTransferStatus().GetProcessedFrameCount(), currentVF);
753  }
754  else
755  xferFails++;
756 
757  // Signal that we're done "producing" the frame, making it available for future "consumption"...
758  mCircularBuffer.EndProduceNextBuffer();
759 
760  if (!mConfig.fBurnCaptions)
761  {
762  // If no caption burn-in is taking place, there's nobody to consume the buffer.
763  // In this case, simply consume it now, thus recycling it immediately...
764  mCircularBuffer.StartConsumeNextBuffer();
765  mCircularBuffer.EndConsumeNextBuffer();
766  }
767  } // if pCaptureData != NULL
768  } // if A/C running and frame(s) are available for transfer
769  else
770  {
771  // Either AutoCirculate is not running, or there were no frames available on the device to transfer.
772  // Rather than waste CPU cycles spinning, waiting until a frame becomes available, it's far more
773  // efficient to wait for the next input vertical interrupt event to get signaled...
775  ++waitTally;
776 
777  // Did incoming video format or VPID(s) change?
778  const NTV2Channel sdiConnector (mActiveSDIInputs.empty() ? NTV2_CHANNEL1 : *(mActiveSDIInputs.begin()));
779  ULWord vpidDS1(0), vpidDS2(0);
780  if (mDevice.GetVPIDValidA(sdiConnector))
781  mDevice.ReadSDIInVPID (sdiConnector, vpidDS1, vpidDS2);
782 
783  NTV2VideoFormat newVF (mDevice.GetInputVideoFormat(mConfig.fInputSource));
784  const bool vfChanged(newVF != currentVF);
785  const bool vpidChgd(mVPIDInfoDS1.GetVPID() != vpidDS1 || mVPIDInfoDS2.GetVPID() != vpidDS2);
786  if (vfChanged || vpidChgd) // || squares != mSquares)
787  {
788  ++noVideoTally;
789  if (vfChanged)
790  CAPWARN("Input video format changed from '" << ::NTV2VideoFormatToString(currentVF)
791  << "' to '" << ::NTV2VideoFormatToString(newVF) << "'");
792  else if (vpidChgd)
793  CAPWARN("Input VPID changed: DS1 (" << xHEX0N(mVPIDInfoDS1.GetVPID(),8) << " to " << xHEX0N(vpidDS1,8)
794  << "), DS2 (" << xHEX0N(mVPIDInfoDS2.GetVPID(),8) << " to " << xHEX0N(vpidDS2,8) << ")");
795 
796  // Terminate the playout thread...
797  mCircularBuffer.StartProduceNextBuffer();
798  mCircularBuffer.EndProduceNextBuffer();
799  break; // exit frame processing loop to restart AutoCirculate
800  } // if incoming video format changed
801  } // else not running or no frames available
802 
803  // Check if pixel format change requested (user pressed P key)...
804  if (mConfig.fPixelFormat != currentPF)
805  {
806  CAPWARN("FrameStore pixel format changed from '"
807  << ::NTV2FrameBufferFormatToString(currentPF,true) << "' to '"
808  << ::NTV2FrameBufferFormatToString(mConfig.fPixelFormat,true) << "'");
809  break; // exit frame processing loop -- restart AutoCirculate
810  }
811  if (mConfig.fUseVanc != bUsingVanc)
812  {
813  CAPWARN("Vanc " << (mConfig.fUseVanc?"enabled":"disabled"));
814  bUsingVanc = mConfig.fUseVanc;
815  break; // exit frame processing loop -- restart AutoCirculate
816  }
817  } // normal frame processing loop -- loop until signal or pixel format change
818 
819  // Stop AutoCirculate...
820  mDevice.AutoCirculateStop(mConfig.fInputChannel);
821 
822  } // loop til quit signaled
823  CAPNOTE("Thread completed, " << DEC(xferTally) << " of " << DEC(xferTally+xferFails) << " frms xferred, "
824  << DEC(waitTally) << " waits, " << DEC(noVideoTally) << " sig chgs");
825 
826 } // CaptureFrames
827 
829 {
831  ULWord numConsecutiveFrames(0), MIN_NUM_CONSECUTIVE_FRAMES(6);
832  NTV2_ASSERT(!mActiveSDIInputs.empty());
833  NTV2Channel sdiConnector(*(mActiveSDIInputs.begin()));
834 
835  // Detection loop:
836  while (result == NTV2_FORMAT_UNKNOWN)
837  {
838  // Determine the input video signal format...
839  // Warning: if there's no input signal, this loop won't exit until mGlobalQuit goes true!
840  mVPIDInfoDS1.MakeInvalid(); mVPIDInfoDS2.MakeInvalid(); // Reset VPID info
841  UWord loopCount(0);
842  while (result == NTV2_FORMAT_UNKNOWN)
843  {
845  if (mGlobalQuit)
846  return NTV2_FORMAT_UNKNOWN; // Terminate if asked to do so
847 
848  const NTV2VideoFormat currVF (mDevice.GetInputVideoFormat(mConfig.fInputSource));
849  if (currVF == NTV2_FORMAT_UNKNOWN)
850  { // Wait for video signal to appear
851  if (++loopCount % 500 == 0) // Log message every minute or so at ~50ms
852  CAPDBG("Waiting for valid video signal to appear at "
853  << ::NTV2InputSourceToString(mConfig.fInputSource,true));
854  }
855  else if (numConsecutiveFrames == 0)
856  {
857  lastVF = currVF; // First valid video format to appear
858  numConsecutiveFrames++; // Start debounce counter
859  }
860  else if (numConsecutiveFrames == MIN_NUM_CONSECUTIVE_FRAMES)
861  {
862  numConsecutiveFrames = 0; // Reset for next signal outage
863  result = currVF; // Set official video format to use
864  }
865  else
866  numConsecutiveFrames = (lastVF == currVF) ? numConsecutiveFrames + 1 : 0;
867  } // loop while input video format is unstable
868 
869  // At this point, the video format is stable and valid.
870 
871  // Grab input VPID info...
872  if (mDevice.GetVPIDValidA(sdiConnector))
873  { ULWord vpidDS1(0), vpidDS2(0);
874  mDevice.ReadSDIInVPID (sdiConnector, vpidDS1, vpidDS2);
875  mVPIDInfoDS1.SetVPID(vpidDS1);
876  mVPIDInfoDS2.SetVPID(vpidDS2);
877  }
878  if (mVPIDInfoDS1.IsValid())
879  { // DS1 VPID valid ---
880  CAPNOTE(::NTV2InputSourceToString(mConfig.fInputSource,true) << " DS1: " << mVPIDInfoDS1);
881  NTV2VideoFormat vfVPID (mVPIDInfoDS1.GetVideoFormat());
882  if (mVPIDInfoDS2.IsValid())
883  CAPNOTE(::NTV2InputSourceToString(mConfig.fInputSource,true) << " DS2: " << mVPIDInfoDS2);
884  if (vfVPID != result && !mSquares)
885  {
886  CAPWARN("VPID=" << ::NTV2VideoFormatToString(vfVPID) << " != " << ::NTV2VideoFormatToString(result));
887  result = vfVPID;
888  }
889  }
890 
891  ostringstream osserr;
892  if (!mDevice.features().CanDoVideoFormat(result)) // Can this device handle this video format?
893  osserr << mDevice.GetModelName() << " can't handle " << ::NTV2VideoFormatToString(result);
894  else if (mVPIDInfoDS1.IsValid() && mVPIDInfoDS1.IsStandardTwoSampleInterleave() && !mDevice.features().CanDo425Mux())
895  osserr << mDevice.GetModelName() << " can't handle TSI";
896  if (!osserr.str().empty())
897  {
898  CAPWARN(osserr.str());
899  result = NTV2_FORMAT_UNKNOWN;
900  mDevice.WaitForInputVerticalInterrupt(mConfig.fInputChannel, 30); // Wait 30 frames
901  continue; // Retry
902  }
903 
904  CAPNOTE(::NTV2InputSourceToString(mConfig.fInputSource,true) << " video format: " << ::NTV2VideoFormatToString(result));
905  cerr << endl << "## NOTE: " << ::NTV2InputSourceToString(mConfig.fInputSource,true)
906  << " video format is " << ::NTV2VideoFormatToString(result) << endl;
907  break; // Done!
908  } // loop
909 
910  // Using 'result' & possibly mVPIDInfoDS1 & mVPIDInfoDS2 --
911  // Does this format require another SDI wire? So we should check for another SDI input?
912  // For now, use just 1 framestore, 1 SDI input, 1 CSC...
913  mDevice.DisableChannels(mInputFrameStores);
914  mInputFrameStores.clear(); mInputFrameStores.insert(mConfig.fInputChannel);
915  mActiveSDIInputs.clear(); mActiveSDIInputs.insert(sdiConnector);
916  if (NTV2_IS_4K_VIDEO_FORMAT(result))
917  {
918  mInputFrameStores = ::NTV2MakeChannelSet(mConfig.fInputChannel,
919  mVPIDInfoDS1.IsValid() && mVPIDInfoDS1.IsStandardTwoSampleInterleave() ? 2 : 4);
920  mActiveSDIInputs = ::NTV2MakeChannelSet(sdiConnector, UWord(mInputFrameStores.size()));
921  }
922  mActiveCSCs = mActiveSDIInputs;
923  CAPDBG(::NTV2VideoFormatToString(result) << ": SDIs=" << ::NTV2ChannelSetToStr(mActiveSDIInputs)
924  << " FrameStores=" << ::NTV2ChannelSetToStr(mInputFrameStores)
925  << " CSCs=" << ::NTV2ChannelSetToStr(mActiveCSCs));
926  cerr << "WaitForStableInputSignal: " << ::NTV2VideoFormatToString(result) << ": SDIIns=" << ::NTV2ChannelSetToStr(mActiveSDIInputs)
927  << " FrameStores=" << ::NTV2ChannelSetToStr(mInputFrameStores)
928  << " CSCs=" << ::NTV2ChannelSetToStr(mActiveCSCs) << endl;
929  NTV2_ASSERT(result != NTV2_FORMAT_UNKNOWN);
930  return result;
931 } // WaitForStableInputSignal
932 
933 
935 
936 
938 {
939  mConfig.fUseVanc = !mConfig.fUseVanc;
940  cerr << endl << "## NOTE: VANC frame geometry " << (mConfig.fUseVanc ? "enabled" : "disabled") << endl;
941 }
942 
943 
945 {
946  OutputMode mode (mConfig.fOutputMode);
947  mode = OutputMode(mode+1);
948  if (!IS_VALID_OutputMode(mode))
950  if (mConfig.fOutputMode != mode)
951  cerr << endl << "## NOTE: Output changed to '" << CCGrabberConfig::OutputModeToString(mode) << "'" << endl;
952  mConfig.fOutputMode = mode;
953 }
954 
956 {
957  CaptionDataSrc src (mConfig.fCaptionSrc);
958  src = CaptionDataSrc(src+1);
959  if (!IS_VALID_CaptionDataSrc(src))
961  if (mConfig.fCaptionSrc != src)
962  cerr << endl << "## NOTE: CC source changed to '" << CCGrabberConfig::CaptionDataSrcToString(src) << "'" << endl;
963  mConfig.fCaptionSrc = src;
964 }
965 
967 {
968  NTV2PixelFormat pf (mConfig.fPixelFormat);
969  do
970  {
971  pf = NTV2PixelFormat(pf+1);
972  if (pf == NTV2_FBF_LAST)
973  pf = NTV2_FBF_FIRST;
974  } while (NTV2_IS_FBF_PLANAR(pf) || !mDevice.features().CanDoFrameBufferFormat(pf));
975  if (mConfig.fPixelFormat != pf)
976  cerr << endl << "## NOTE: Pixel format changed to " << ::NTV2FrameBufferFormatToString(pf) << endl;
977  mConfig.fPixelFormat = pf;
978 }
979 
980 void NTV2CCGrabber::ExtractClosedCaptionData (const uint32_t inFrameNum, const NTV2VideoFormat inVideoFormat)
981 {
982  AJAAncillaryList ancPackets, vancPackets;
983  CaptionData captionData708Anc, captionData708Vanc, captionData608Anc, captionData608Vanc, captionDataL21Anc, captionDataL21; // The 608 caption byte pairs (one pair per field)
984  const NTV2FormatDescriptor formatDesc (inVideoFormat, mConfig.fPixelFormat, mVancMode);
985 
986  if (NTV2_IS_VANCMODE_ON(mVancMode) || mDevice.features().CanDoCustomAnc()) // Gotta have at least VANC or AncExt
987  {
988  // Get all VANC packets...
989  if (NTV2_IS_VANCMODE_ON(mVancMode))
990  {
991  AJAAncillaryList::SetFromVANCData (mInputXferInfo.acVideoBuffer, formatDesc, vancPackets, inFrameNum);
992  vancPackets.ParseAllAncillaryData();
993  }
994 
995  // Get all anc extractor packets...
996  if (mDevice.features().CanDoCustomAnc())
997  {
998  const NTV2Buffer validAncF1 (mInputXferInfo.acANCBuffer.GetHostAddress(0), mInputXferInfo.GetCapturedAncByteCount(false));
999  const NTV2Buffer validAncF2 (mInputXferInfo.acANCField2Buffer.GetHostAddress(0), mInputXferInfo.GetCapturedAncByteCount(true));
1000  AJAAncillaryList::SetFromDeviceAncBuffers (validAncF1, validAncF2, ancPackets, inFrameNum);
1001  ancPackets.ParseAllAncillaryData();
1002  }
1003 
1004  if (NTV2_IS_VANCMODE_ON(mVancMode))
1005  { // Compare with what we got from VANC lines:
1006  NTV2StringList diffs;
1007  if (!ancPackets.CompareWithInfo (diffs, vancPackets, true/*ignoreLoc*/, false /*ignoreChksum*/))
1008  {
1009  NTV2StringList lines(aja::split(diffs.at(0), "\n")); // Only log first diff
1010  CAPDBG(DEC(diffs.size()) << " VANC/AncExt diff(s): " << lines.at(0));
1011  for (size_t n(1); n < lines.size(); n++)
1012  CAPDBG(lines.at(n));
1013  }
1014  }
1015  }
1016 
1017  // Get Line21 CC data...
1018  if (NTV2_IS_SD_VIDEO_FORMAT(inVideoFormat) && (mConfig.fPixelFormat == NTV2_FBF_8BIT_YCBCR || mConfig.fPixelFormat == NTV2_FBF_10BIT_YCBCR))
1019  { // Anything encoded in Line 21?
1020  ULWord line21RowOffset(0);
1021  const UByte * pLine21(AJA_NULL);
1022  formatDesc.GetLineOffsetFromSMPTELine (21, line21RowOffset);
1023  pLine21 = AsConstUBytePtr(formatDesc.GetRowAddress(mInputXferInfo.acVideoBuffer.GetHostPointer(),
1024  line21RowOffset));
1025  if (pLine21)
1026  {
1027  if (mConfig.fPixelFormat == NTV2_FBF_10BIT_YCBCR) // CNTV2Line21Captioner::DecodeLine requires 8-bit YUV
1028  ::ConvertLine_v210_to_2vuy(AsConstULWordPtr(pLine21), (UByte*)(pLine21), 720); // Convert YUV10 to YUV8 in-place
1029  captionDataL21.bGotField1Data = CNTV2Line21Captioner::DecodeLine(pLine21, captionDataL21.f1_char1, captionDataL21.f1_char2);
1030  }
1031  pLine21 = AsConstUBytePtr(formatDesc.GetRowAddress(mInputXferInfo.acVideoBuffer.GetHostPointer(),
1032  line21RowOffset+1)); // F2 should be on next row
1033  if (pLine21)
1034  {
1035  if (mConfig.fPixelFormat == NTV2_FBF_10BIT_YCBCR) // CNTV2Line21Captioner::DecodeLine requires 8-bit YUV
1036  ::ConvertLine_v210_to_2vuy(AsConstULWordPtr(pLine21), (UByte*)(pLine21), 720); // Convert YUV10 to YUV8 in-place
1037  captionDataL21.bGotField2Data = CNTV2Line21Captioner::DecodeLine(pLine21, captionDataL21.f2_char1, captionDataL21.f2_char2);
1038  }
1039  }
1040 
1041  // Any 608 packets (anc extractor)?
1042  if (ancPackets.GetAncillaryDataWithType(AJAAncDataType_Cea608_Vanc, 0)) // F1
1043  {
1045  if (pkt608F1.GetPayloadData() && pkt608F1.GetPayloadByteCount() && AJA_SUCCESS(pkt608F1.ParsePayloadData()))
1046  pkt608F1.GetCEA608Bytes (captionData608Anc.f1_char1, captionData608Anc.f1_char2, captionData608Anc.bGotField1Data);
1047  }
1048  if (ancPackets.GetAncillaryDataWithType(AJAAncDataType_Cea608_Vanc, 1)) // F2
1049  {
1051  if (pkt608F2.GetPayloadData() && pkt608F2.GetPayloadByteCount() && AJA_SUCCESS(pkt608F2.ParsePayloadData()))
1052  pkt608F2.GetCEA608Bytes(captionData608Anc.f2_char1, captionData608Anc.f2_char2, captionData608Anc.bGotField2Data);
1053  }
1054 
1055  // Any 608 packets (Vanc)?
1057  {
1059  if (pkt608F1.GetPayloadData() && pkt608F1.GetPayloadByteCount() && AJA_SUCCESS(pkt608F1.ParsePayloadData()))
1060  pkt608F1.GetCEA608Bytes (captionData608Vanc.f1_char1, captionData608Vanc.f1_char2, captionData608Vanc.bGotField1Data);
1061  }
1063  {
1065  if (pkt608F2.GetPayloadData() && pkt608F2.GetPayloadByteCount() && AJA_SUCCESS(pkt608F2.ParsePayloadData()))
1066  pkt608F2.GetCEA608Bytes(captionData608Vanc.f2_char1, captionData608Vanc.f2_char2, captionData608Vanc.bGotField2Data);
1067  }
1068 
1069  // Any 708 packets (vanc)?
1071  {
1072  AJAAncillaryData vancCEA708DataIn (vancPackets.GetAncillaryDataWithType(AJAAncDataType_Cea708));
1073  bool hasParityErrors (false);
1074  if (vancCEA708DataIn.GetPayloadData() && vancCEA708DataIn.GetPayloadByteCount() && AJA_SUCCESS(vancCEA708DataIn.ParsePayloadData()))
1075  if (m708DecoderVanc->SetSMPTE334AncData (vancCEA708DataIn.GetPayloadData(), vancCEA708DataIn.GetPayloadByteCount()))
1076  if (m708DecoderVanc->ParseSMPTE334AncPacket(hasParityErrors))
1077  {
1078  vector<UByte> svcBlk;
1079  size_t blkSize(0), byteCount(0);
1080  int svcNum(0);
1081  bool isExtendedSvc(false);
1082  if (!hasParityErrors)
1083  captionData708Vanc = m708DecoderVanc->GetCC608CaptionData();
1084  if (m708DecoderVanc->GetNextServiceBlockInfoFromQueue (NTV2_CC708PrimaryCaptionServiceNum, blkSize, byteCount, svcNum, isExtendedSvc))
1085  m708DecoderVanc->GetNextServiceBlockFromQueue(NTV2_CC708PrimaryCaptionServiceNum, svcBlk); // Pop queued service block
1086  }
1087  }
1088  // Any 708 packets (anc extractor)?
1090  {
1091  AJAAncillaryData ancCEA708DataIn (ancPackets.GetAncillaryDataWithType(AJAAncDataType_Cea708));
1092  bool hasParityErrors (false);
1093  if (ancCEA708DataIn.GetPayloadData() && ancCEA708DataIn.GetPayloadByteCount() && AJA_SUCCESS(ancCEA708DataIn.ParsePayloadData()))
1094  if (m708DecoderAnc->SetSMPTE334AncData (ancCEA708DataIn.GetPayloadData(), ancCEA708DataIn.GetPayloadByteCount()))
1095  if (m708DecoderAnc->ParseSMPTE334AncPacket(hasParityErrors))
1096  {
1097  vector<UByte> svcBlk;
1098  size_t blkSize(0), byteCount(0);
1099  int svcNum(0);
1100  bool isExtendedSvc(false);
1101  if (!hasParityErrors)
1102  captionData708Anc = m708DecoderAnc->GetCC608CaptionData();
1103  if (m708DecoderAnc->GetNextServiceBlockInfoFromQueue (NTV2_CC708PrimaryCaptionServiceNum, blkSize, byteCount, svcNum, isExtendedSvc))
1104  m708DecoderAnc->GetNextServiceBlockFromQueue(NTV2_CC708PrimaryCaptionServiceNum, svcBlk); // Pop queued service block
1105  }
1106  }
1107  // Any "analog" packets?
1109  {
1111  if (AJA_SUCCESS(ancEIA608DataIn.ParsePayloadData()))
1112  ancEIA608DataIn.GetCEA608Bytes(captionDataL21Anc.f1_char1, captionDataL21Anc.f1_char2, captionDataL21Anc.bGotField1Data);
1114  {
1116  if (AJA_SUCCESS(ancEIA608F2.ParsePayloadData()))
1117  ancEIA608F2.GetCEA608Bytes(captionDataL21Anc.f2_char1, captionDataL21Anc.f2_char2, captionDataL21Anc.bGotField2Data);
1118  }
1119  }
1120 
1121  // Compare CaptionData results...
1122  ostringstream ossCompare;
1123  const CaptionData * p608CaptionData(AJA_NULL);
1124  if (NTV2_IS_SD_VIDEO_FORMAT(inVideoFormat))
1125  {
1126  const CaptionData * pL21CaptionData (AJA_NULL);
1127  if (captionDataL21.HasData() && captionDataL21Anc.HasData())
1128  if (captionDataL21 != captionDataL21Anc)
1129  ossCompare << "L21Vanc != L21Anlg: " << captionDataL21 << " " << captionDataL21Anc << endl;
1130  if (captionDataL21.HasData())
1131  pL21CaptionData = &captionDataL21;
1132  else if (captionDataL21Anc.HasData())
1133  pL21CaptionData = &captionDataL21Anc;
1134  if (captionData608Anc.HasData() && pL21CaptionData)
1135  if (captionData608Anc != *pL21CaptionData)
1136  ossCompare << "608 != L21: " << captionData608Anc << " " << *pL21CaptionData << endl;
1137  if (captionData608Anc.HasData())
1138  p608CaptionData = &captionData608Anc; // 608 anc has precedence
1139  else if (pL21CaptionData)
1140  p608CaptionData = pL21CaptionData; // followed by line 21
1141  }
1142  else
1143  {
1144  if (captionData608Anc.HasData() && captionData708Anc.HasData())
1145  if (captionData608Anc != captionData708Anc)
1146  ossCompare << "608anc != 708anc: " << captionData608Anc << " " << captionData708Anc << endl;
1147  if (captionData608Vanc.HasData() && captionData708Vanc.HasData())
1148  if (captionData608Vanc != captionData708Vanc)
1149  ossCompare << "608vanc != 708vanc: " << captionData608Vanc << " " << captionData708Vanc << endl;
1150  if (captionData708Anc.HasData())
1151  p608CaptionData = &captionData708Anc; // 608-in-708anc has highest precedence
1152  else if (captionData708Vanc.HasData())
1153  p608CaptionData = &captionData708Vanc; // followed by 608-in-708vanc
1154  else if (captionData608Anc.HasData())
1155  p608CaptionData = &captionData608Anc; // followed by 608anc
1156  else if (captionData608Vanc.HasData())
1157  p608CaptionData = &captionData608Vanc; // followed by 608vanc
1158  }
1159  if (!ossCompare.str().empty())
1160  CAPDBG("CaptionData mis-compare(s): " << ossCompare.str());
1161 
1162  // Set p608CaptionData based on mConfig.fCaptionSrc...
1163  switch (mConfig.fCaptionSrc)
1164  { // captionData708Anc, captionData708Vanc, captionData608Anc, captionData608Vanc, captionDataL21Anc, captionDataL21
1165  case kCaptionDataSrc_Line21: p608CaptionData = &captionDataL21Anc; break;
1166  case kCaptionDataSrc_608FBVanc: p608CaptionData = &captionDataL21; break;
1167  case kCaptionDataSrc_708FBVanc: p608CaptionData = &captionData708Vanc; break;
1168  case kCaptionDataSrc_608Anc: p608CaptionData = &captionData608Anc; break;
1169  case kCaptionDataSrc_708Anc: p608CaptionData = &captionData708Anc; break;
1170  default: break;
1171  }
1172 
1173  if (!p608CaptionData)
1174  return; // Got nothing
1175 
1176  // This demo only handles CEA-608 captions (no Teletext, IBU, etc.)
1177  // The 608 decoder expects to be called once per frame (to implement flashing characters, smooth-scroll roll-up, etc.).
1178  // Pass the caption byte pairs to it for processing (even if captionData.HasData returns false)...
1179  m608Decoder->ProcessNew608FrameData(*p608CaptionData);
1180 
1181  DoCCOutput(inFrameNum, *p608CaptionData, inVideoFormat);
1182 
1183 } // ExtractClosedCaptionData
1184 
1185 
1186 void NTV2CCGrabber::DoCCOutput (const uint32_t inFrameNum, const CaptionData & inCCData, const NTV2VideoFormat inVideoFormat)
1187 {
1188  // Print out the caption characters...
1189  const bool isFirstTime (mLastOutFrame == 0 && inFrameNum > mLastOutFrame);
1190  char char1(0), char2(0);
1191  const bool showField2 (IsField2Line21CaptionChannel(m608Channel));
1192  const bool gotData (showField2 ? inCCData.bGotField2Data : inCCData.bGotField1Data);
1193  switch (mConfig.fOutputMode)
1194  {
1196  if (gotData)
1197  { // Can't distinguish between CC1/CC2/Tx1/Tx2 for F1 (nor CC3/CC4/Tx3/Tx4 for F2).
1198  // They'll just have to be interspersed for now...
1199  char1 = (char(showField2 ? inCCData.f2_char1 : inCCData.f1_char1) & 0x7F);
1200  char2 = (char(showField2 ? inCCData.f2_char2 : inCCData.f1_char2) & 0x7F);
1201  if (char1 >= ' ' && char1 <= '~')
1202  {
1203  if (mLastOutStr != " " || char1 != ' ')
1204  {cout << char1 << flush; mLastOutStr = string(1,char1);}
1205  if (char2 >= ' ' && char2 <= '~')
1206  {
1207  if (mLastOutStr != " " || char2 != ' ')
1208  {cout << char2 << flush; mLastOutStr = string(1,char2);}
1209  }
1210  }
1211  else if (mLastOutStr != " ")
1212  {cout << " " << flush; mLastOutStr = " ";}
1213  }
1214  break;
1216  {
1217  if (inFrameNum == (mLastOutFrame+1))
1218  {
1219  mLastOutFrame = inFrameNum;
1220  if ((mLastOutFrame - mFirstOutFrame) < MAX_ACCUM_FRAME_COUNT)
1221  break; // Don't spew yet -- keep going
1222  }
1223  const string currentScreen(m608Decoder->GetOnAirCharacters());
1224  if (currentScreen != mLastOutStr)
1225  cout << currentScreen << endl;
1226  mLastOutStr = currentScreen;
1227  mFirstOutFrame = mLastOutFrame = inFrameNum;
1228  break;
1229  }
1231  {
1232  uint16_t u16(uint16_t(uint16_t(showField2 ? inCCData.f2_char1 : inCCData.f1_char1) << 8) | uint16_t(showField2 ? inCCData.f2_char2 : inCCData.f1_char2));
1233  ostringstream oss;
1234  oss << Hex0N(u16,4);
1235  mLastOutStr.append(mLastOutStr.empty() ? "\t" : " ");
1236  mLastOutStr.append(oss.str());
1237  if (inFrameNum == (mLastOutFrame+1))
1238  { // Save for later
1239  mLastOutFrame = inFrameNum;
1240  if ((mLastOutFrame - mFirstOutFrame) < MAX_ACCUM_FRAME_COUNT)
1241  break; // Don't spew yet -- keep going
1242  }
1243  if (isFirstTime)
1244  cout << "Scenarist_SCC V1.0" << endl;
1245 
1246  string tcStr;
1247  AJATimeCode tcFirst(mFirstOutFrame);
1249  tcFirst.QueryString(tcStr, tcBase, false);
1250  cout << endl << tcStr << ":" << mLastOutStr << endl;
1251  mFirstOutFrame = mLastOutFrame = inFrameNum;
1252  mLastOutStr.clear();
1253  break;
1254  }
1255  case kOutputMode_Stats:
1256  if (inFrameNum % 60 == 0) // Every 60 frames
1257  {
1258  CNTV2CaptionDecodeChannel608Ptr chDecoder (m608Decoder->Get608ChannelDecoder(m608Decoder->GetDisplayChannel()));
1259  if (chDecoder)
1260  {
1261  const vector<uint32_t> stats (chDecoder->GetStats());
1262  AJALabelValuePairs info;
1263  AJASystemInfo::append(info, ::NTV2Line21ChannelToStr(m608Decoder->GetDisplayChannel()));
1264  for (size_t num(0); num < stats.size(); num++)
1265  {
1266  const string title(CNTV2CaptionDecodeChannel608::GetStatTitle(CaptionDecode608Stats(num)));
1267  if (title.empty())
1268  break;
1269  if (!stats[num])
1270  continue;
1271  ostringstream oss; oss << DEC(stats[num]);
1272  AJASystemInfo::append(info, title, oss.str());
1273  }
1274  cout << AJASystemInfo::ToString(info) << endl;
1275  }
1276  }
1277  break;
1278  default: break;
1279  }
1280 } // DoCCOutput
1281 
1282 
1284 
1285 
1286 static const UWord gMixerNums [] = {0, 0, 1, 1, 2, 2, 3, 3};
1287 
1288 
1290 {
1291  NTV2_ASSERT (mConfig.fBurnCaptions); // Must be burning captions
1292 
1293  // Configure the output FrameStore...
1294  mDevice.EnableChannel (mOutputChannel);
1295  mDevice.SetMode (mOutputChannel, NTV2_MODE_DISPLAY);
1296  mDevice.SetFrameBufferFormat (mOutputChannel, mPlayoutFBF);
1297  mDevice.SetVideoFormat (inVideoFormat, /*retailMode?*/false, /*keepVANC?*/false, /*channel*/mOutputChannel);
1298  mDevice.SetEnableVANCData(NTV2_IS_VANCMODE_TALL(mVancMode), NTV2_IS_VANCMODE_TALLER(mVancMode), mOutputChannel);
1299 
1300  // RGB: Set up mixer to "mix" mode, FG raster "unshaped", BG raster "full raster" and VANC pass-thru from BG...
1301  const UWord mixerNumber (gMixerNums[mOutputChannel]);
1302  mDevice.SetMixerMode (mixerNumber, NTV2MIXERMODE_FOREGROUND_ON);
1305  mDevice.SetMixerVancOutputFromForeground (mixerNumber, false); // false means "use BG VANC, not FG"
1306  cerr << "## NOTE: Caption burn-in using mixer/keyer " << (mixerNumber+1) << " on " << ::NTV2ChannelToString(mOutputChannel)
1307  << ", " << ::NTV2FrameBufferFormatToString(mPlayoutFBF)
1308  << ", " << ::NTV2VideoFormatToString(inVideoFormat) << endl;
1309 
1310  return AJA_STATUS_SUCCESS;
1311 
1312 } // SetupOutputVideo
1313 
1314 
1316 {
1317  NTV2_ASSERT (mConfig.fBurnCaptions); // Must be burning captions
1318  const NTV2OutputCrosspointID frameStoreOutputRGB (::GetFrameStoreOutputXptFromChannel (mOutputChannel, true)); // true=RGB
1319  const NTV2OutputCrosspointID cscOutputYUV (::GetCSCOutputXptFromChannel (mOutputChannel));
1320  const NTV2OutputCrosspointID cscOutputKey (::GetCSCOutputXptFromChannel (mOutputChannel, true)); // true=key
1321  const NTV2OutputCrosspointID mixerOutputYUV (::GetMixerOutputXptFromChannel (mOutputChannel));
1323  const NTV2Standard outputStandard (::GetNTV2StandardFromVideoFormat (inVideoFormat));
1324  const bool canVerify (mDevice.features().HasCrosspointConnectROM());
1325  UWord connectFailures (0);
1326 
1327  if (mConfig.fDoMultiFormat)
1328  {
1329  // Multiformat --- route the one SDI output to the mixer's YUV output, and set its output standard...
1330  if (mDevice.features().HasBiDirectionalSDI())
1331  mDevice.SetSDITransmitEnable (mOutputChannel, true);
1332  if (mDevice.features().CanDoWidget(g12GSDIOutputs[mOutputChannel])
1333  || mDevice.features().CanDoWidget(g3GSDIOutputs[mOutputChannel])
1334  || mDevice.features().CanDoWidget(gSDIOutputs[mOutputChannel]))
1335  {
1336  if (!mDevice.Connect (::GetSDIOutputInputXpt(mOutputChannel), mixerOutputYUV, canVerify)) connectFailures++;
1337  mDevice.SetSDIOutputStandard (mOutputChannel, outputStandard);
1338  }
1339  }
1340  else
1341  {
1342  // If not multiformat: Route all SDI outputs to the mixer's YUV output...
1343  const ULWord numVideoOutputs (mDevice.features().GetNumVideoOutputs());
1344  const NTV2Channel startNum (NTV2_CHANNEL1);
1345  const NTV2Channel endNum (NTV2_CHANNEL_INVALID);
1346  const NTV2Channel sdiInputAsChan (::NTV2InputSourceToChannel(mConfig.fInputSource));
1347 
1348  for (NTV2Channel chan(startNum); chan < endNum; chan = NTV2Channel(chan + 1))
1349  {
1350  if (ULWord(chan) >= numVideoOutputs)
1351  break;
1352  if (mDevice.features().HasBiDirectionalSDI())
1353  {
1354  if (chan == sdiInputAsChan)
1355  continue; // Skip the input
1356  mDevice.SetSDITransmitEnable (chan, true);
1357  }
1358  if (mDevice.features().CanDoWidget(g12GSDIOutputs[chan])
1359  || mDevice.features().CanDoWidget(g3GSDIOutputs[chan])
1360  || mDevice.features().CanDoWidget(gSDIOutputs[chan]))
1361  {
1362  if (!mDevice.Connect (::GetSDIOutputInputXpt(chan), mixerOutputYUV, canVerify)) connectFailures++;
1363  mDevice.SetSDIOutputStandard (chan, outputStandard);
1364  }
1365  } // for each output spigot
1366  }
1367 
1368  // Connect CSC video input to frame buffer's RGB output:
1369  if (!mDevice.Connect (::GetCSCInputXptFromChannel(mOutputChannel), frameStoreOutputRGB, canVerify)) connectFailures++;
1370  // Connect mixer's foreground video input to the CSC's YUV video output:
1371  if (!mDevice.Connect (::GetMixerFGInputXpt(mOutputChannel), cscOutputYUV, canVerify)) connectFailures++;
1372  // Connect mixer's foreground key input to the CSC's YUV key output:
1373  if (!mDevice.Connect (::GetMixerFGInputXpt(mOutputChannel, true), cscOutputKey, canVerify)) connectFailures++;
1374  // Connect mixer's background video input to the SDI input:
1375  if (!mDevice.Connect (::GetMixerBGInputXpt(mOutputChannel), signalInput, canVerify)) connectFailures++;
1376 
1377  if (!mConfig.fDoMultiFormat)
1378  {
1379  // Connect more outputs -- HDMI, analog, SDI monitor, etc... (Don't bother to verify these connections)
1380  if (mDevice.features().CanDoWidget(NTV2_WgtHDMIOut1))
1381  mDevice.Connect (NTV2_XptHDMIOutInput, mixerOutputYUV);
1382  if (mDevice.features().CanDoWidget(NTV2_WgtHDMIOut1v2))
1383  mDevice.Connect (NTV2_XptHDMIOutQ1Input, mixerOutputYUV);
1384  if (mDevice.features().CanDoWidget(NTV2_WgtAnalogOut1))
1385  mDevice.Connect (NTV2_XptAnalogOutInput, mixerOutputYUV);
1386  if (mDevice.features().CanDoWidget(NTV2_WgtSDIMonOut1))
1387  mDevice.Connect (::GetSDIOutputInputXpt (NTV2_CHANNEL5), mixerOutputYUV);
1388  }
1389  return connectFailures == 0;
1390 
1391 } // RouteOutputSignal
1392 
1393 
1394 // Starts the play thread
1396 {
1397  // Create and start the playout thread...
1398  NTV2_ASSERT(mConfig.fBurnCaptions);
1399  AJAStatus result (mPlayoutThread.Attach(PlayThreadStatic, this));
1400  if (AJA_SUCCESS(result))
1401  result = mPlayoutThread.SetPriority(AJA_ThreadPriority_High);
1402  if (AJA_SUCCESS(result))
1403  result = mPlayoutThread.Start();
1404  return result;
1405 
1406 } // StartPlayThread
1407 
1408 
1409 // The playout thread function
1410 void NTV2CCGrabber::PlayThreadStatic (AJAThread * pThread, void * pContext) // static
1411 {
1412  (void) pThread;
1413  // Grab the NTV2Burn instance pointer from the pContext parameter,
1414  // then call its PlayFrames method...
1415  NTV2CCGrabber * pApp (reinterpret_cast <NTV2CCGrabber *> (pContext));
1416  pApp->PlayFrames ();
1417 
1418 } // PlayThreadStatic
1419 
1420 
1422 {
1423  const NTV2VideoFormat videoFormat (mDevice.GetInputVideoFormat(mConfig.fInputSource));
1425  ULWord fbNum (10); // Bounce between frames 10 & 11
1426  const string indicators [] = {"/", "-", "\\", "|", ""};
1427  AUTOCIRCULATE_STATUS acStatus;
1428 
1429  CAPNOTE("Thread started");
1430  SetupOutputVideo (videoFormat); // Set up device output
1431  RouteOutputSignal (videoFormat); // Set up output signal routing
1432  mDevice.GetVANCMode (vancMode, mConfig.fInputChannel);
1433  if (mDevice.AutoCirculateInitForOutput (mOutputChannel, 2) && mDevice.AutoCirculateGetStatus (mOutputChannel, acStatus)) // Find out which buffers we got
1434  fbNum = ULWord(acStatus.acStartFrame); // Use them
1435  else if (mDevice.AutoCirculateGetStatus(mConfig.fInputChannel, acStatus)) // Use the frame just past the last input A/C frame
1436  fbNum = ULWord(acStatus.GetEndFrame()) + 1;
1437 
1438  const NTV2FormatDesc formatDesc (videoFormat, mPlayoutFBF, vancMode);
1439  const uint32_t bufferSizeBytes (formatDesc.GetTotalRasterBytes ());
1440  const uint32_t activeSizeBytes (formatDesc.GetVisibleRasterBytes ());
1441  ULWord pingPong (0); // Bounce between 0 and 1
1442  UWord consecSyncErrs (0);
1443  // Caption status head-up-display...
1444  static uint64_t frameTally (0);
1445  const string strVideoFormat (CNTV2DemoCommon::StripFormatString (::NTV2VideoFormatToString (videoFormat)));
1446  ULWord lastErrorTally (0);
1447 
1448  // Allocate host frame buffer for blitting captions into...
1449  NTV2Buffer hostBuffer;
1450  if (!hostBuffer.Allocate(bufferSizeBytes, /*pageAligned*/true))
1451  {cerr << "## NOTE: Caption burn-in failed -- unable to allocate " << bufferSizeBytes << "-byte caption video buffer" << endl; return;}
1452  NTV2Buffer visibleRgn (formatDesc.GetTopVisibleRowAddress(AsUBytePtr(hostBuffer.GetHostPointer())),activeSizeBytes);
1453 
1454  // Clear both device ping/pong buffers to fully transparent, all black...
1455  hostBuffer.Fill(ULWord(0));
1456  mDevice.DMAWriteFrame (fbNum + 0, AsULWordPtr(hostBuffer.GetHostPointer()), bufferSizeBytes);
1457  mDevice.DMAWriteFrame (fbNum + 1, AsULWordPtr(hostBuffer.GetHostPointer()), bufferSizeBytes);
1458  mDevice.SetOutputFrame (mOutputChannel, fbNum + pingPong);
1459  pingPong = pingPong ? 0 : 1;
1460 
1461  // Do forever (until Quit)...
1462  while (!mGlobalQuit)
1463  {
1464  // Wait for the next frame to become ready to "consume"...
1465  NTV2FrameData * pFrameData(mCircularBuffer.StartConsumeNextBuffer());
1466  if (pFrameData)
1467  {
1468  // "Burn" captions into the host buffer before it gets sent to the AJA device...
1469  m608Decoder->BurnCaptions (hostBuffer, formatDesc);
1470  m608Decoder->IdleFrame(); // This is needed for captions that flash/blink
1471 
1472  if (mHeadUpDisplayOn)
1473  {
1474  ostringstream oss;
1475  const string strCaptionChan (::NTV2Line21ChannelToStr(NTV2_IS_HD_VIDEO_FORMAT(videoFormat)
1476  ? m708DecoderAnc->GetDisplayChannel()
1477  : m608Decoder->GetDisplayChannel()));
1478  oss << indicators [mCaptionDataTally % 4] << " " << strCaptionChan << " " << frameTally++ << " "
1479  << formatDesc.GetRasterWidth() << "x" << formatDesc.GetFullRasterHeight() << (mConfig.fUseVanc ? "v" : " ") << strVideoFormat;
1480 
1481  const ULWord newErrorTally (mErrorTally);
1482  const NTV2Line21Attributes & color (lastErrorTally != newErrorTally ? kRedOnTransparentBG : kGreenOnTransparentBG);
1483  CNTV2CaptionRenderer::BurnString (oss.str(), color, hostBuffer, formatDesc, 7, 1);
1484  lastErrorTally = newErrorTally;
1485 
1486  if (!pFrameData->fTimecodes.empty())
1487  {
1488  const NTV2_RP188 & tc (pFrameData->fTimecodes.begin()->second);
1489  if (tc.IsValid() && tc.fDBB & BIT(16)) // Bit 16 will be set if this frame had timecode
1490  {
1491  CRP188 rp188(tc);
1492  CNTV2CaptionRenderer::BurnString (rp188.GetRP188CString(), kGreenOnTransparentBG, hostBuffer, formatDesc, 8, 1);
1493  }
1494  }
1495  }
1496 
1497  // Transfer the caption raster to the device, then ping-pong it into the mixer foreground...
1498  mDevice.DMAWriteFrame (fbNum + pingPong, AsULWordPtr(visibleRgn.GetHostPointer()), activeSizeBytes);
1499  mDevice.SetOutputFrame (mOutputChannel, fbNum + pingPong); // Toggle device frame buffer
1500  pingPong = pingPong ? 0 : 1; // Switch device frame numbers for next time
1501  visibleRgn.Fill(ULWord(0)); // Clear visible region of host buffer to fully-transparent, all-black again
1502 
1503  // Signal that the frame has been "consumed"...
1504  mCircularBuffer.EndConsumeNextBuffer ();
1505 
1506  // Check for format change...
1507  if (videoFormat != mDevice.GetInputVideoFormat(mConfig.fInputSource))
1508  {
1509  cerr << "## NOTE: Caption burn-in stopped due to video format change -- was " << strVideoFormat
1510  << ", now " << ::NTV2VideoFormatToString (mDevice.GetInputVideoFormat(mConfig.fInputSource)) << endl;
1511  m608Decoder->Reset(); // Don't leave captions from old video stream on-screen
1512  m708DecoderAnc->Reset();
1513  m708DecoderVanc->Reset();
1514  break;
1515  }
1516 
1517  // Check mixer sync...
1518  bool mixerSyncOK (false);
1519  mDevice.GetMixerSyncStatus (gMixerNums[mOutputChannel], mixerSyncOK);
1520  if (mixerSyncOK)
1521  consecSyncErrs = 0;
1522  else if (++consecSyncErrs > 60) // Bail if lack of mixer sync for longer than ~1 sec
1523  {cerr << "#MXSYNC#"; consecSyncErrs = 0;} // break;}
1524  } // if pPlayData
1525  } // loop til quit signaled
1526 
1527  if (mDevice.AutoCirculateGetStatus (mOutputChannel, acStatus) && !acStatus.IsStopped())
1528  mDevice.AutoCirculateStop(mOutputChannel);
1529  CAPNOTE("Thread completed, will exit");
1530 
1531 } // PlayFrames
1532 
1533 
1534 void NTV2CCGrabber::SetCaptionDisplayChannel (const NTV2Line21Channel inNewChannel)
1535 {
1536  if (m608Channel != inNewChannel)
1537  {
1538  m608Channel = inNewChannel;
1539  if (m608Decoder)
1540  m608Decoder->SetDisplayChannel(m608Channel);
1541  if (m708DecoderAnc)
1542  m708DecoderAnc->SetDisplayChannel(m608Channel);
1543  if (m708DecoderVanc)
1544  m708DecoderVanc->SetDisplayChannel(m608Channel);
1545  cerr << endl << "## NOTE: Caption display channel changed to '" << ::NTV2Line21ChannelToStr(m608Channel) << "'" << endl;
1546  }
1547 }
1548 
1549 
1550 void NTV2CCGrabber::CaptioningChanged (const NTV2Caption608ChangeInfo & inChangeInfo)
1551 { (void) inChangeInfo;
1552  mCaptionDataTally++;
1553 }
1554 
1555 
1556 void NTV2CCGrabber::Caption608ChangedStatic (void * pInstance, const NTV2Caption608ChangeInfo & inChangeInfo) // STATIC
1557 {
1558  NTV2CCGrabber * pGrabber(reinterpret_cast<NTV2CCGrabber*>(pInstance));
1559  if (pGrabber)
1560  pGrabber->CaptioningChanged(inChangeInfo);
1561 }
1562 
1563 
1564 string NTV2CCGrabber::GetLine21ChannelNames (string inDelimiterStr) // static
1565 {
1566  string result;
1567  for (unsigned enumVal(0); enumVal < NTV2_CC608_ChannelMax; )
1568  {
1569  result += ::NTV2Line21ChannelToStr (NTV2Line21Channel(enumVal++));
1570  if (enumVal < NTV2_CC608_ChannelMax)
1571  result += inDelimiterStr;
1572  else
1573  break;
1574  }
1575  return result;
1576 
1577 } // GetLine21ChannelNames
1578 
1579 AJALabelValuePairs CCGrabberConfig::Get (const bool inCompact) const
1580 {
1581  AJALabelValuePairs result (CaptureConfig::Get(inCompact));
1582  AJASystemInfo::append(result, "Output Mode", IS_VALID_OutputMode(fOutputMode) ? OutputModeToString(fOutputMode) : "(invalid)");
1584  AJASystemInfo::append(result, "Timecode Source", ::NTV2TCIndexToString(fTimecodeSource, inCompact));
1585  AJASystemInfo::append(result, "Caption Channel", ::NTV2Line21ChannelToStr(fCaptionChannel, inCompact));
1586  AJASystemInfo::append(result, "Burn-In Captions", fBurnCaptions ? "Y" : "N");
1587  AJASystemInfo::append(result, "MultiFormat Mode", fDoMultiFormat ? "Y" : "N");
1588  AJASystemInfo::append(result, "Use Vanc", fUseVanc ? "Y" : "N");
1589  return result;
1590 }
1591 
1592 
1594 {
1595  string result;
1597  {
1598  result += OutputModeToString(mode);
1599  mode = OutputMode(mode+1);
1600  if (mode < kOutputMode_INVALID)
1601  result += ",";
1602  }
1603  return result;
1604 }
1605 
1607 {
1608  static const string gModeStrs[] = {"stream","screen","scc","mcc","stats",""};
1609  if (IS_VALID_OutputMode(inMode))
1610  return gModeStrs[inMode];
1611  string result;
1612  for (unsigned ndx(0); ndx < 5; )
1613  {
1614  result += gModeStrs[ndx];
1615  if (!(gModeStrs[++ndx].empty()))
1616  result += "|";
1617  }
1618  return result;
1619 }
1620 
1622 {
1623  typedef pair<string,OutputMode> StringToOutputModePair;
1624  typedef map<string,OutputMode> StringToOutputModeMap;
1625  typedef StringToOutputModeMap::const_iterator StringToOutputModeConstIter;
1626  static StringToOutputModeMap sStringToOutputModeMap;
1627  static AJALock sStringToOutputModeMapLock;
1628  if (sStringToOutputModeMap.empty())
1629  {
1630  AJAAutoLock autoLock(&sStringToOutputModeMapLock);
1632  {
1633  string outputModeStr (OutputModeToString(om));
1634  aja::lower(outputModeStr);
1635  sStringToOutputModeMap.insert(StringToOutputModePair(outputModeStr,om));
1636  }
1637  }
1638  string modeStr(inModeStr);
1639  aja::lower(aja::strip(modeStr));
1640  StringToOutputModeConstIter iter(sStringToOutputModeMap.find(modeStr));
1641  return iter != sStringToOutputModeMap.end() ? iter->second : kOutputMode_INVALID;
1642 }
1643 
1645 {
1646  string result;
1648  {
1649  result += CaptionDataSrcToString(src);
1650  src = CaptionDataSrc(src+1);
1651  if (src < kCaptionDataSrc_INVALID)
1652  result += ",";
1653  }
1654  return result;
1655 }
1656 
1658 {
1659  static const string gSrcStrs[] = {"default","line21","608vanc","708vanc","608anc","708anc",""};
1660  if (IS_VALID_CaptionDataSrc(inDataSrc))
1661  return gSrcStrs[inDataSrc];
1662  string result;
1663  for (unsigned ndx(0); ndx < 6; )
1664  {
1665  result += gSrcStrs[ndx];
1666  if (!gSrcStrs[++ndx].empty())
1667  result += "|";
1668  }
1669  return result;
1670 }
1671 
1673 {
1674  typedef pair<string,CaptionDataSrc> StringToCaptionDataSrcPair;
1675  typedef map<string,CaptionDataSrc> StringToCaptionDataSrcMap;
1676  typedef StringToCaptionDataSrcMap::const_iterator StringToCaptionDataSrcConstIter;
1677  static StringToCaptionDataSrcMap sStringToCaptionDataSrcMap;
1678  static AJALock sStringToCaptionDataSrcMapLock;
1679  if (sStringToCaptionDataSrcMap.empty())
1680  {
1681  AJAAutoLock autoLock(&sStringToCaptionDataSrcMapLock);
1683  {
1684  string captionDataSrcStr (CaptionDataSrcToString(cds));
1685  aja::lower(captionDataSrcStr);
1686  sStringToCaptionDataSrcMap.insert(StringToCaptionDataSrcPair(captionDataSrcStr,cds));
1687  }
1688  }
1689  string cdsStr(inDataSrcStr);
1690  aja::lower(aja::strip(cdsStr));
1691  StringToCaptionDataSrcConstIter iter(sStringToCaptionDataSrcMap.find(cdsStr));
1692  return iter != sStringToCaptionDataSrcMap.end() ? iter->second : kCaptionDataSrc_INVALID;
1693 }
1694 
1695 
1696 std::ostream & operator << (std::ostream & ioStrm, const CCGrabberConfig & inObj)
1697 {
1698  ioStrm << AJASystemInfo::ToString(inObj.Get());
1699  return ioStrm;
1700 }
NTV2Channel NTV2InputSourceToChannel(const NTV2InputSource inInputSource)
Converts a given NTV2InputSource to its equivalent NTV2Channel value.
Definition: ntv2utils.cpp:5051
static const NTV2WidgetID g12GSDIOutputs[]
This class handles "analog" (Line 21) based CEA-608 caption data packets.
#define NTV2_IS_SD_VIDEO_FORMAT(__f__)
Definition: ntv2enums.h:748
#define NTV2_IS_VANCMODE_TALLER(__v__)
Definition: ntv2enums.h:3813
Passes only foreground video + key to the Mixer output.
Definition: ntv2enums.h:1798
virtual ~NTV2CCGrabber()
NTV2FrameRate GetNTV2FrameRateFromVideoFormat(const NTV2VideoFormat inVideoFormat)
Definition: ntv2utils.cpp:3630
virtual void SetCaptionDisplayChannel(const NTV2Line21Channel inNewChannel)
Changes the caption channel I&#39;m displaying.
CEA708 (SMPTE 334) HD Closed Captioning.
Definition: ancillarydata.h:50
#define AJA_SUCCESS(_status_)
Definition: types.h:372
virtual bool SetTaskMode(const NTV2TaskMode inMode)
Sets the device&#39;s task mode.
virtual bool GetSDITransmitEnable(const NTV2Channel inChannel, bool &outEnabled)
Answers whether or not the specified SDI connector is currently acting as a transmitter (i...
static const uint32_t MAX_ACCUM_FRAME_COUNT(30)
Declares a number of pixel format transcoder functions.
#define CAPDBG(_expr_)
std::string NTV2ChannelSetToStr(const NTV2ChannelSet &inObj, const bool inCompact=true)
bool Allocate(const size_t inByteCount, const bool inPageAligned=false)
Allocates (or re-allocates) my user-space storage using the given byte count. I assume full responsib...
Declares common types used in the ajabase library.
virtual bool SetAudioLoopBack(const NTV2AudioLoopBack inMode, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Enables or disables NTV2AudioLoopBack mode for the given NTV2AudioSystem.
Definition: ntv2audio.cpp:301
Declares the AJAMemory class.
virtual bool RouteOutputSignal(const NTV2VideoFormat inVideoFormat)
static const NTV2WidgetID g3GSDIOutputs[]
CaptionDataSrc fCaptionSrc
Caption data source (Line21? 608 VANC? 608 Anc? etc)
Definition: ntv2ccgrabber.h:65
virtual bool SetReference(const NTV2ReferenceSource inRefSource, const bool inKeepFramePulseSelect=(0))
Sets the device&#39;s clock reference source. See Video Output Clocking & Synchronization for more inform...
virtual bool ReleaseStreamForApplication(ULWord inApplicationType, int32_t inProcessID)
Releases exclusive use of the AJA device for the given process, permitting other processes to acquire...
bool Is8BitFrameBufferFormat(const NTV2FrameBufferFormat fbFormat)
Definition: ntv2utils.cpp:5456
This identifies the invalid (unspecified, uninitialized) VANC mode.
Definition: ntv2enums.h:3808
AJAStatus Add(FrameDataPtr pInFrameData)
Appends a new frame buffer to me, increasing my frame storage capacity by one frame.
static const ULWord kAppSignature((((uint32_t)( 'C'))<< 24)|(((uint32_t)( 'C'))<< 16)|(((uint32_t)( 'G'))<< 8)|(((uint32_t)( 'R'))<< 0))
NTV2FrameBufferFormat
Identifies a particular video frame buffer pixel format. See Device Frame Buffer Formats for details...
Definition: ntv2enums.h:223
virtual bool SetMixerMode(const UWord inWhichMixer, const NTV2MixerKeyerMode inMode)
Sets the mode for the given mixer/keyer.
#define BIT(_x_)
Definition: ajatypes.h:496
bool SetBuffers(ULWord *pInVideoBuffer, const ULWord inVideoByteCount, ULWord *pInAudioBuffer, const ULWord inAudioByteCount, ULWord *pInANCBuffer, const ULWord inANCByteCount, ULWord *pInANCF2Buffer=NULL, const ULWord inANCF2ByteCount=0)
Sets my buffers for use in a subsequent call to CNTV2Card::AutoCirculateTransfer. ...
virtual bool SetVideoFormat(const NTV2VideoFormat inVideoFormat, const bool inIsAJARetail=(!(0)), const bool inKeepVancSettings=(0), const NTV2Channel inChannel=NTV2_CHANNEL1)
Configures the AJA device to handle a specific video format.
virtual bool Set4kSquaresEnable(const bool inIsEnabled, const NTV2Channel inChannel)
Enables or disables SMPTE 425 "2K quadrants" mode for the given FrameStore bank on the device...
AJAStatus
Definition: types.h:380
See 10-Bit YCbCr Format.
Definition: ntv2enums.h:226
bool fDoMultiFormat
If true, use multi-format/multi-channel mode, if device supports it; otherwise normal mode...
#define AsULWordPtr(__p__)
virtual bool IsDeviceReady(const bool inCheckValid=(0))
bool GetLineOffsetFromSMPTELine(const ULWord inSMPTELine, ULWord &outLineOffset) const
Answers with the equivalent line offset into the raster I describe for the given SMPTE line number...
enum _NTV2VideoFormat NTV2VideoFormat
Identifies a particular video format.
bool fUseVanc
If true, use Vanc, even if the device supports Anc insertion.
Definition: ntv2ccgrabber.h:69
Declares the AJAAncillaryData_Cea608_line21 class.
static uint64_t GetPid()
Definition: process.cpp:35
#define AsUBytePtr(__p__)
#define NTV2_IS_FBF_PLANAR(__s__)
Definition: ntv2enums.h:271
#define AJA_FAILURE(_status_)
Definition: types.h:373
static void Caption608ChangedStatic(void *pInstance, const NTV2Caption608ChangeInfo &inChangeInfo)
This static function gets called whenever 608 captioning changes.
static NTV2ChannelList GetTSIMuxesForFrameStore(CNTV2Card &inDevice, const NTV2Channel in1stFrameStore, const UWord inCount)
ULWord GetFullRasterHeight(void) const
NTV2EmbeddedAudioInput NTV2InputSourceToEmbeddedAudioInput(const NTV2InputSource inInputSource)
Converts a given NTV2InputSource to its equivalent NTV2EmbeddedAudioInput value.
Definition: ntv2utils.cpp:4881
NTV2InputSource NTV2ChannelToInputSource(const NTV2Channel inChannel, const NTV2IOKinds inKinds=NTV2_IOKINDS_SDI)
Definition: ntv2utils.cpp:5136
virtual bool DMAWriteFrame(const ULWord inFrameNumber, const ULWord *pInFrameBuffer, const ULWord inByteCount)
Transfers a single frame from the host to the AJA device.
Definition: ntv2dma.cpp:65
virtual NTV2VideoFormat WaitForStableInputSignal(void)
Wait for a stable input signal, and return it.
virtual bool ReadSDIInVPID(const NTV2Channel inSDIInput, ULWord &outValueA, ULWord &outValueB)
Definition: ntv2regvpid.cpp:85
virtual bool GetMixerSyncStatus(const UWord inWhichMixer, bool &outIsSyncOK)
Returns the current sync state of the given mixer/keyer.
LWord acStartFrame
First frame to circulate. FIXFIXFIX Why is this signed? CHANGE TO ULWord??
virtual bool GetVPIDValidA(const NTV2Channel inChannel)
Definition: ntv2regvpid.cpp:67
std::vector< AJALabelValuePair > AJALabelValuePairs
An ordered sequence of label/value pairs.
Definition: info.h:71
void Clear(void)
Clears my frame collection, their locks, everything.
NTV2InputXptID GetDLOutInputXptFromChannel(const NTV2Channel inDLOutWidget)
#define NTV2_IS_4K_VIDEO_FORMAT(__f__)
Definition: ntv2enums.h:787
NTV2Buffer acVideoBuffer
The host video buffer. This field is owned by the client application, and thus is responsible for all...
virtual AJAStatus SetPriority(AJAThreadPriority priority)
Definition: thread.cpp:133
virtual CNTV2VPID & MakeInvalid(void)
Definition: ntv2vpid.h:102
NTV2OutputXptID GetTSIMuxOutputXptFromChannel(const NTV2Channel inTSIMuxer, const bool inLinkB=false, const bool inIsRGB=false)
static const NTV2Line21Attributes kRedOnTransparentBG(NTV2_CC608_Red, NTV2_CC608_Blue, NTV2_CC608_Transparent)
FrameDataPtr StartConsumeNextBuffer(void)
The thread that&#39;s responsible for processing incoming frames – the consumer – calls this function t...
#define NTV2_FOURCC(_a_, _b_, _c_, _d_)
Obtain audio samples from the audio that&#39;s embedded in the video HANC.
Definition: ntv2enums.h:2012
bool fBurnCaptions
If true, burn-in captions on 2nd channel.
Definition: ntv2ccgrabber.h:68
const char * GetRP188CString() const
Definition: ntv2rp188.cpp:924
NTV2InputXptID GetDLInInputXptFromChannel(const NTV2Channel inChannel, const bool inLinkB=false)
virtual bool SetMixerBGInputControl(const UWord inWhichMixer, const NTV2MixerKeyerInputControl inInputControl)
Sets the background input control value for the given mixer/keyer.
static void CaptureThreadStatic(AJAThread *pThread, void *pContext)
This is the capture thread&#39;s static callback function that gets called when the capture thread runs...
Declares the AJAAncillaryData_Cea608_Vanc class.
Definition: lock.h:28
I can decode captions from frames captured from an AJA device in real time. I can optionally play the...
virtual bool IsCaptureThreadRunning(void) const
Returns true if my capture thread is currently running.
virtual AJAStatus Run(void)
Runs me.
Definition: json.hpp:5362
virtual bool SetAudioRate(const NTV2AudioRate inRate, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Sets the NTV2AudioRate for the given Audio System.
Definition: ntv2audio.cpp:206
virtual AJAStatus Start()
Definition: thread.cpp:91
virtual bool EnableInputInterrupt(const NTV2Channel channel=NTV2_CHANNEL1)
Allows the CNTV2Card instance to wait for and respond to input vertical blanking interrupts originati...
This class is used to configure an NTV2CCGrabber instance.
Definition: ntv2ccgrabber.h:61
#define NTV2_IS_HFR_STANDARD(__s__)
Definition: ntv2enums.h:217
void EndConsumeNextBuffer(void)
The consumer thread calls this function to signal that it has finished processing the frame it obtain...
#define false
ULWord GetVisibleRasterBytes(const UWord inPlaneIndex0=0) const
uint32_t ULWord
Definition: ajatypes.h:236
virtual bool AutoCirculateGetStatus(const NTV2Channel inChannel, AUTOCIRCULATE_STATUS &outStatus)
Returns the current AutoCirculate status for the given channel.
virtual bool SetFrameBufferFormat(NTV2Channel inChannel, NTV2FrameBufferFormat inNewFormat, bool inIsAJARetail=(!(0)), NTV2HDRXferChars inXferChars=NTV2_VPID_TC_SDR_TV, NTV2HDRColorimetry inColorimetry=NTV2_VPID_Color_Rec709, NTV2HDRLuminance inLuminance=NTV2_VPID_Luminance_YCbCr)
Sets the frame buffer format for the given FrameStore on the AJA device.
Embeds SDI input source audio into the data stream.
Definition: ntv2enums.h:2036
NTV2OutputXptID GetDLOutOutputXptFromChannel(const NTV2Channel inDLOutput, const bool inIsLinkB=false)
NTV2Channel
These enum values are mostly used to identify a specific widget_framestore. They&#39;re also commonly use...
Definition: ntv2enums.h:1361
const void * GetRowAddress(const void *pInStartAddress, const ULWord inRowIndex0, const UWord inPlaneIndex0=0) const
virtual class DeviceCapabilities & features(void)
Definition: ntv2card.h:148
bool CanDoInputSource(const NTV2InputSource inSrc)
std::ostream & operator<<(std::ostream &ioStrm, const CCGrabberConfig &inObj)
virtual bool SetMultiFormatMode(const bool inEnable)
Enables or disables multi-format (per channel) device operation. If enabled, each device channel can ...
virtual void ToggleVANC(void)
Toggles the use of VANC. (Debug, experimental)
virtual void PlayFrames(void)
Repeatedly updates captions (until global quit flag set).
#define NTV2_ASSERT(_expr_)
Definition: ajatypes.h:489
virtual bool ClearRouting(void)
Removes all existing signal path connections between any and all widgets on the AJA device...
virtual AJAStatus GetCEA608Bytes(uint8_t &outByte1, uint8_t &outByte2, bool &outIsValid) const
Answers with the CEA608 payload bytes.
This struct replaces the old RP188_STRUCT.
NTV2FrameBufferFormat NTV2PixelFormat
An alias for NTV2FrameBufferFormat.
Definition: ntv2enums.h:264
static void PlayThreadStatic(AJAThread *pThread, void *pContext)
This is the playout thread&#39;s static callback function that gets called when the playout thread runs...
int32_t appPID(0)
#define NTV2_AUDIOSIZE_MAX
NTV2Channel fInputChannel
The device channel to use.
NTV2ChannelList NTV2MakeChannelList(const NTV2Channel inFirstChannel, const UWord inNumChannels=1)
virtual bool Active()
Definition: thread.cpp:116
bool Fill(const T &inValue)
Fills me with the given scalar value.
virtual bool GetTaskMode(NTV2TaskMode &outMode)
Retrieves the device&#39;s current task mode.
virtual AJAStatus SetupInputVideo(void)
Sets up everything I need for capturing video.
virtual bool SetAudioSystemInputSource(const NTV2AudioSystem inAudioSystem, const NTV2AudioSource inAudioSource, const NTV2EmbeddedAudioInput inEmbeddedInput)
Sets the audio source for the given NTV2AudioSystem on the device.
Definition: ntv2audio.cpp:486
std::string NTV2InputSourceToString(const NTV2InputSource inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:7043
virtual AJAStatus SetupAudio(void)
Sets up audio for capture (and playout, if burning captions).
NTV2FrameBufferFormat acFrameBufferFormat
Specifies the frame buffer format to change to. Ignored if AUTOCIRCULATE_WITH_FBFCHANGE option is not...
virtual bool SetOutputFrame(const NTV2Channel inChannel, const ULWord inValue)
Sets the output frame index number for the given FrameStore. This identifies which frame in device SD...
unsigned int n
Definition: pstream.cpp:148
#define true
virtual bool EnableChannels(const NTV2ChannelSet &inChannels, const bool inDisableOthers=(0))
Enables the given FrameStore(s).
NTV2Standard
Identifies a particular video standard.
Definition: ntv2enums.h:169
0: Disabled (never recommended): device configured exclusively by client application(s).
Playout (output) mode, which reads from device SDRAM.
Definition: ntv2enums.h:1245
static AJAStatus SetFromVANCData(const NTV2Buffer &inFrameBuffer, const NTV2FormatDescriptor &inFormatDesc, AJAAncillaryList &outPackets, const uint32_t inFrameNum=0)
Returns all packets found in the VANC lines of the given NTV2 frame buffer.
virtual std::string GetDescription(void) const
Definition: ntv2card.cpp:139
NTV2DeviceID
Identifies a specific AJA NTV2 device model number. The NTV2DeviceID is actually the PROM part number...
Definition: ntv2enums.h:20
virtual bool SetMode(const NTV2Channel inChannel, const NTV2Mode inNewValue, const bool inIsRetail=(!(0)))
Determines if a given FrameStore on the AJA device will be used to capture or playout video...
virtual AJAStatus Init(void)
Initializes me and prepares me to Run.
static bool GetFirstDeviceFromArgument(const std::string &inArgument, CNTV2Card &outDevice)
Rescans the host, and returns an open CNTV2Card instance for the AJA device that matches a command li...
virtual bool SetSDITransmitEnable(const NTV2Channel inChannel, const bool inEnable)
Sets the specified bidirectional SDI connector to act as an input or an output.
NTV2ReferenceSource
These enum values identify a specific source for the device&#39;s (output) reference clock.
Definition: ntv2enums.h:1459
const AUTOCIRCULATE_TRANSFER_STATUS & GetTransferStatus(void) const
Returns a constant reference to my AUTOCIRCULATE_TRANSFER_STATUS.
virtual bool AutoCirculateTransfer(const NTV2Channel inChannel, AUTOCIRCULATE_TRANSFER &transferInfo)
Transfers all or part of a frame as specified in the given AUTOCIRCULATE_TRANSFER object to/from the ...
virtual bool AcquireStreamForApplication(ULWord inApplicationType, int32_t inProcessID)
Reserves exclusive use of the AJA device for a given process, preventing other processes on the host ...
Utility class for timecodes.
Definition: timecode.h:28
ULWord GetProcessedFrameCount(void) const
#define NTV2_IS_HD_VIDEO_FORMAT(__f__)
Definition: ntv2enums.h:741
#define AJA_NULL
Definition: ajatypes.h:180
virtual bool GetVANCMode(NTV2VANCMode &outVancMode, const NTV2Channel inChannel=NTV2_CHANNEL1)
Retrieves the current VANC mode for the given FrameStore.
void SetAbortFlag(const bool *pAbortFlag)
Tells me the boolean variable I should monitor such that when it gets set to "true" will cause any th...
NTV2CCGrabber(const CCGrabberConfig &inConfigData)
Constructs me using the given configuration settings.
virtual AJAAncillaryData * GetAncillaryDataWithType(const AJAAncDataType inMatchType, const uint32_t inIndex=0) const
Answers with the AJAAncillaryData object having the given type and index.
NTV2InputXptID GetCSCInputXptFromChannel(const NTV2Channel inCSC, const bool inIsKeyInput=false)
virtual bool SubscribeInputVerticalEvent(const NTV2Channel inChannel=NTV2_CHANNEL1)
Causes me to be notified when an input vertical blanking interrupt occurs on the given input channel...
Definition: ntv2card.h:2787
virtual NTV2VideoFormat GetInputVideoFormat(const NTV2InputSource inVideoSource=NTV2_INPUTSOURCE_SDI1, const bool inIsProgressive=(0))
Returns the video format of the signal that is present on the given input source. ...
Describes a video frame for a given video standard or format and pixel format, including the total nu...
virtual void Switch608Source(void)
Switches/rotates –608src.
static void Sleep(const int32_t inMilliseconds)
Suspends execution of the current thread for a given number of milliseconds.
Definition: systemtime.cpp:284
#define IS_VALID_OutputMode(_x_)
Definition: ntv2ccgrabber.h:41
void split(const std::string &str, const char delim, std::vector< std::string > &elems)
Definition: common.cpp:350
bool IsStopped(void) const
2: OEM (recommended): device configured by client application(s) with some driver involvement...
NTV2Line21Channel fCaptionChannel
Caption channel to monitor (defaults to CC1)
Definition: ntv2ccgrabber.h:67
static AJAStatus SetFromDeviceAncBuffers(const NTV2Buffer &inF1AncBuffer, const NTV2Buffer &inF2AncBuffer, AJAAncillaryList &outPackets, const uint32_t inFrameNum=0)
Returns all ancillary data packets found in the given F1 and F2 ancillary data buffers.
NTV2InputXptID GetFrameStoreInputXptFromChannel(const NTV2Channel inFrameStore, const bool inIsBInput=false)
NTV2InputXptID GetMixerBGInputXpt(const NTV2Channel inChannel, const bool inIsKey=false)
virtual bool ApplySignalRoute(const CNTV2SignalRouter &inRouter, const bool inReplace=(0))
Applies the given routing table to the AJA device.
virtual bool SetSDIOutputAudioSystem(const NTV2Channel inSDIOutputConnector, const NTV2AudioSystem inAudioSystem)
Sets the device&#39;s NTV2AudioSystem that will provide audio for the given SDI output&#39;s audio embedder...
virtual void SwitchPixelFormat(void)
Switches/rotates –pixelFormat.
std::string NTV2VideoFormatToString(const NTV2VideoFormat inValue, const bool inUseFrameRate=false)
Definition: ntv2utils.cpp:6750
See 8-Bit ARGB, RGBA, ABGR Formats.
Definition: ntv2enums.h:228
Embeds silence (zeroes) into the data stream.
Definition: ntv2enums.h:2035
virtual bool SetVANCShiftMode(NTV2Channel inChannel, NTV2VANCDataShiftMode inMode)
Enables or disables the "VANC Shift Mode" feature for the given channel.
virtual AJAStatus SetupOutputVideo(const NTV2VideoFormat inVideoFormat)
Sets up everything I need for capturing video.
virtual bool SetTsiFrameEnable(const bool inIsEnabled, const NTV2Channel inChannel)
Enables or disables SMPTE 425 two-sample interleave (Tsi) frame mode on the device.
Specifies channel or FrameStore 8 (or the 8th item).
Definition: ntv2enums.h:1370
virtual void ReleaseHostBuffers(void)
Releases my circular buffers.
#define AsConstUBytePtr(__p__)
This class handles VANC-based CEA-608 caption data packets (not "analog" Line 21).
#define AsConstULWordPtr(__p__)
#define AUTOCIRCULATE_WITH_ANC
Use this to AutoCirculate with ancillary data.
Specifies channel or FrameStore 2 (or the 2nd item).
Definition: ntv2enums.h:1364
virtual NTV2DeviceID GetDeviceID(void)
static std::string OutputModeToString(const OutputMode inMode)
std::string NTV2TCIndexToString(const NTV2TCIndex inValue, const bool inCompactDisplay=false)
Definition: ntv2utils.cpp:6398
ULWord GetVideoWriteSize(const NTV2VideoFormat inVideoFormat, const NTV2FrameBufferFormat inFBFormat, const NTV2VANCMode inVancMode=NTV2_VANCMODE_OFF)
Identical to the GetVideoActiveSize function, except rounds the result up to the nearest 4K page size...
Definition: ntv2utils.cpp:2875
uint8_t UByte
Definition: ajatypes.h:231
virtual std::string CompareWithInfo(const AJAAncillaryList &inCompareList, const bool inIgnoreLocation=true, const bool inIgnoreChecksum=true) const
Compares me with another list and returns a std::string that contains a human-readable explanation of...
NTV2OutputXptID GetDLInOutputXptFromChannel(const NTV2Channel inDLInput)
#define NTV2_IS_VANCMODE_ON(__v__)
Definition: ntv2enums.h:3814
enum _CaptionDataSrc CaptionDataSrc
virtual bool AutoCirculateStop(const NTV2Channel inChannel, const bool inAbort=(0))
Stops AutoCirculate for the given channel, and releases the on-device frame buffers that were allocat...
#define NTV2_IS_VALID_CHANNEL(__x__)
Definition: ntv2enums.h:1375
virtual void CaptureFrames(void)
Repeatedly captures frames using AutoCirculate (until global quit flag set).
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.).
virtual bool Connect(const NTV2InputCrosspointID inInputXpt, const NTV2OutputCrosspointID inOutputXpt, const bool inValidate=(0))
Connects the given widget signal input (sink) to the given widget signal output (source).
virtual bool SetMixerVancOutputFromForeground(const UWord inWhichMixer, const bool inFromForegroundSource=(!(0)))
Sets the VANC source for the given mixer/keyer to the foreground video (or not). See the SDI Ancillar...
uint16_t GetEndFrame(void) const
static const NTV2Line21Attributes kGreenOnTransparentBG(NTV2_CC608_Green, NTV2_CC608_Blue, NTV2_CC608_Transparent)
virtual std::string GetModelName(void)
Answers with this device&#39;s model name.
Definition: ntv2card.cpp:82
std::string NTV2DeviceIDToString(const NTV2DeviceID inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:4608
virtual AJAStatus StartCaptureThread(void)
Starts my capture thread.
virtual void SetOutputStandards(const NTV2VideoFormat inVideoFormat)
Sets the device output standard based on the given video format.
bool IsRGBFormat(const NTV2FrameBufferFormat format)
Definition: ntv2utils.cpp:5414
virtual AJAStatus SetupHostBuffers(const NTV2VideoFormat inVideoFormat)
Sets up my circular buffers.
std::string & strip(std::string &str, const std::string &ws)
Definition: common.cpp:461
virtual bool SetAudioBufferSize(const NTV2AudioBufferSize inValue, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Changes the size of the audio buffer that is used for a given Audio System in the AJA device...
Definition: ntv2audio.cpp:250
virtual uint32_t CountAncillaryDataWithType(const AJAAncDataType inMatchType) const
Answers with the number of AJAAncillaryData objects having the given type.
NTV2InputSource fInputSource
The device input connector to use.
static AJALabelValuePairs & append(AJALabelValuePairs &inOutTable, const std::string &inLabel, const std::string &inValue=std::string())
A convenience function that appends the given label and value strings to the provided AJALabelValuePa...
Definition: info.h:170
virtual void DoCCOutput(const uint32_t inFrameNum, const CaptionData &inCCData, const NTV2VideoFormat inVideoFormat)
Outputs CC data.
#define DEC(__x__)
NTV2InputXptID GetTSIMuxInputXptFromChannel(const NTV2Channel inTSIMuxer, const bool inLinkB=false)
virtual AJAStatus StartPlayThread(void)
Starts my playout thread.
virtual bool SetMixerFGInputControl(const UWord inWhichMixer, const NTV2MixerKeyerInputControl inInputControl)
Sets the foreground input control value for the given mixer/keyer.
NTV2Buffer acANCField2Buffer
The host "Field 2" ancillary data buffer. This field is owned by the client application, and thus is responsible for allocating and/or freeing it. If the pointer is NULL or the size is zero, no "Field 2" ancillary data will be transferred. Use the AUTOCIRCULATE_TRANSFER::SetAncBuffers method to set or reset this field.
std::set< NTV2Channel > NTV2ChannelSet
A set of distinct NTV2Channel values.
void EndProduceNextBuffer(void)
The producer thread calls this function to signal that it has finished populating the frame it obtain...
This identifies the first Audio System.
Definition: ntv2enums.h:3903
virtual bool WaitForOutputVerticalInterrupt(const NTV2Channel inChannel=NTV2_CHANNEL1, UWord inRepeatCount=1)
Efficiently sleeps the calling thread/process until the next one or more field (interlaced video) or ...
#define NTV2_IS_VALID_INPUT_SOURCE(_inpSrc_)
Definition: ntv2enums.h:1288
virtual void SwitchOutput(void)
Switches/rotates –output mode.
static const size_t CIRCULAR_BUFFER_SIZE(10)
Number of NTV2FrameData&#39;s in our ring.
virtual CNTV2VPID & SetVPID(const ULWord inData)
Definition: ntv2vpid.h:71
virtual bool GetReference(NTV2ReferenceSource &outRefSource)
Answers with the device&#39;s current clock reference source.
virtual bool DisableChannels(const NTV2ChannelSet &inChannels)
Disables the given FrameStore(s).
virtual AJAStatus Attach(AJAThreadFunction *pThreadFunction, void *pUserContext)
Definition: thread.cpp:169
ULWord GetTotalRasterBytes(const UWord inPlaneIndex0=0) const
virtual bool RouteInputSignal(const NTV2VideoFormat inVideoFormat)
FrameDataPtr StartProduceNextBuffer(void)
The thread that&#39;s responsible for providing frames – the producer – calls this function to populate...
NTV2OutputCrosspointID
Identifies a widget output, a signal source, that potentially can drive another widget&#39;s input (ident...
Definition: ntv2enums.h:2532
bool GetInputTimeCodes(NTV2TimeCodeList &outValues) const
Intended for capture, answers with the timecodes captured in my acTransferStatus member&#39;s acFrameStam...
Header file for NTV2CCGrabber demonstration class.
#define NTV2_IS_VANCMODE_TALL(__v__)
Definition: ntv2enums.h:3812
virtual AJAStatus ParseAllAncillaryData(void)
Sends a "ParsePayloadData" command to all of my AJAAncillaryData objects.
This is returned from the CNTV2Card::AutoCirculateGetStatus function.
NTV2OutputXptID GetFrameStoreOutputXptFromChannel(const NTV2Channel inFrameStore, const bool inIsRGB=false, const bool inIs425=false)
NTV2WidgetID
Definition: ntv2enums.h:2914
bool UnlockAll(CNTV2Card &inDevice)
uint16_t UWord
Definition: ajatypes.h:234
ULWord GetRasterWidth(void) const
void QueryString(std::string &str, const AJATimeBase &timeBase, bool bDropFrame, bool bStdTcForHfr, AJATimecodeNotation notation=AJA_TIMECODE_LEGACY)
Definition: timecode.cpp:299
#define CAPWARN(_expr_)
Specifies channel or FrameStore 1 (or the first item).
Definition: ntv2enums.h:1363
virtual bool UnsubscribeInputVerticalEvent(const NTV2Channel inChannel=NTV2_CHANNEL1)
Unregisters me so I&#39;m no longer notified when an input VBI is signaled on the given input channel...
Definition: ntv2card.h:2837
virtual bool AutoCirculateStart(const NTV2Channel inChannel, const ULWord64 inStartTime=0)
Starts AutoCirculate streaming for the specified channel that was previously initialized by CNTV2Card...
bool CanDoFrameBufferFormat(const NTV2PixelFormat inPF)
ULWord appSignature(0)
virtual bool AutoCirculateInitForOutput(const NTV2Channel inChannel, const UWord inFrameCount=7, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_INVALID, const ULWord inOptionFlags=0, const UByte inNumChannels=1, const UWord inStartFrameNumber=0, const UWord inEndFrameNumber=0)
Prepares for subsequent AutoCirculate playback streaming, designating a contiguous block of frame buf...
std::string NTV2ReferenceSourceToString(const NTV2ReferenceSource inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:7086
NTV2ACFrameRange fFrames
AutoCirculate frame count or range.
#define xHEX0N(__x__, __n__)
virtual bool SetEnableVANCData(const bool inVANCenabled, const bool inTallerVANC, const NTV2Standard inStandard, const NTV2FrameGeometry inGeometry, const NTV2Channel inChannel=NTV2_CHANNEL1)
NTV2VANCMode
These enum values identify the available VANC modes.
Definition: ntv2enums.h:3803
static CaptionDataSrc StringToCaptionDataSrc(const std::string &inDataSrcStr)
bool CanDoWidget(const NTV2WidgetID inWgtID)
#define CAPFAIL(_expr_)
static OutputMode StringToOutputMode(const std::string &inModeStr)
NTV2PixelFormat fPixelFormat
Pixel format to use.
NTV2InputXptID GetMixerFGInputXpt(const NTV2Channel inChannel, const bool inIsKey=false)
#define NTV2_IS_VALID_AUDIO_SYSTEM(__x__)
Definition: ntv2enums.h:3920
std::string NTV2FrameBufferFormatToString(const NTV2FrameBufferFormat inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:6940
static AJA_FrameRate GetAJAFrameRate(const NTV2FrameRate inFrameRate)
enum _OutputMode OutputMode
static const NTV2WidgetID gSDIOutputs[]
I encapsulate the video, audio and anc host buffers used in the AutoCirculate demos. I&#39;m a more modern version of the AVDataBuffer.
NTV2AudioSystem NTV2ChannelToAudioSystem(const NTV2Channel inChannel)
Converts the given NTV2Channel value into its equivalent NTV2AudioSystem.
Definition: ntv2utils.cpp:4873
NTV2OutputXptID GetMixerOutputXptFromChannel(const NTV2Channel inChannel, const bool inIsKey=false)
bool HasAvailableInputFrame(void) const
Specifies channel or FrameStore 4 (or the 4th item).
Definition: ntv2enums.h:1366
static std::string GetLegalCaptionDataSources(void)
std::pair< NTV2InputXptID, NTV2OutputXptID > NTV2XptConnection
NTV2ChannelSet NTV2MakeChannelSet(const NTV2Channel inFirstChannel, const UWord inNumChannels=1)
#define IS_VALID_CaptionDataSrc(_x_)
Definition: ntv2ccgrabber.h:55
Specifies channel or FrameStore 5 (or the 5th item).
Definition: ntv2enums.h:1367
virtual bool IsStandardTwoSampleInterleave(void) const
Definition: ntv2vpid.cpp:281
NTV2Standard GetNTV2StandardFromVideoFormat(const NTV2VideoFormat inVideoFormat)
Definition: ntv2utils.cpp:2375
virtual void Quit(void)
Gracefully stops me from running.
virtual void ExtractClosedCaptionData(const uint32_t inFrameCount, const NTV2VideoFormat inVideoFormat)
Extracts closed-caption data, if present, and emits it on a character-by-character basis to the stand...
NTV2TCIndex fTimecodeSource
Timecode source to use (if any)
Definition: ntv2ccgrabber.h:66
CEA608 SD Closed Captioning (SMPTE 334 VANC packet)
Definition: ancillarydata.h:51
std::vector< NTV2Channel > NTV2ChannelList
An ordered sequence of NTV2Channel values.
bool IsRunning(void) const
AJALabelValuePairs Get(const bool inCompact=(0)) const
AJALabelValuePairs Get(const bool inCompact=(0)) const
std::string fDeviceSpec
The AJA device to use.
void * GetHostPointer(void) const
bool ConvertLine_v210_to_2vuy(const ULWord *pInSrcLine_v210, UByte *pOutDstLine_2vuy, const ULWord inNumPixels)
Converts a single 10-bit YCbCr &#39;v210&#39; raster line to 8-bit YCbCr &#39;2vuy&#39;.
static std::string StripFormatString(const std::string &inStr)
static size_t SetDefaultPageSize(void)
std::map< NTV2InputXptID, NTV2OutputXptID > NTV2XptConnections
NTV2OutputXptID GetSDIInputOutputXptFromChannel(const NTV2Channel inSDIInput, const bool inIsDS2=false)
ULWord GetCapturedAncByteCount(const bool inField2=false) const
OutputMode fOutputMode
Desired output (captionStream, Screen etc)
Definition: ntv2ccgrabber.h:64
static std::string GetLegalOutputModes(void)
std::vector< std::string > NTV2StringList
Specifies channel or FrameStore 6 (or the 6th item).
Definition: ntv2enums.h:1368
bool CanDoVideoFormat(const NTV2VideoFormat inVF)
I am the principal class that stores a single SMPTE-291 SDI ancillary data packet OR the digitized co...
virtual bool AutoCirculateInitForInput(const NTV2Channel inChannel, const UWord inFrameCount=7, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_INVALID, const ULWord inOptionFlags=0, const UByte inNumChannels=1, const UWord inStartFrameNumber=0, const UWord inEndFrameNumber=0)
Prepares for subsequent AutoCirculate ingest streaming, designating a contiguous block of frame buffe...
#define AUTOCIRCULATE_WITH_RP188
Use this to AutoCirculate with RP188.
std::string NTV2ChannelToString(const NTV2Channel inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:5731
Specifies channel or FrameStore 7 (or the 7th item).
Definition: ntv2enums.h:1369
virtual ULWord GetVPID(void) const
Definition: ntv2vpid.h:40
#define NTV2_INPUT_SOURCE_IS_SDI(_inpSrc_)
Definition: ntv2enums.h:1287
virtual NTV2VideoFormat GetVideoFormat(void) const
Definition: ntv2vpid.cpp:674
std::string & lower(std::string &str)
Definition: common.cpp:436
Declares the AJAAncillaryList class.
void * GetHostAddress(const ULWord inByteOffset, const bool inFromEnd=false) const
std::string NTV2ChannelListToStr(const NTV2ChannelList &inObj, const bool inCompact=true)
virtual void CaptioningChanged(const NTV2Caption608ChangeInfo &inChangeInfo)
This function gets called whenever caption changes occur.
virtual bool SetSDIOutputStandard(const UWord inOutputSpigot, const NTV2Standard inValue)
Sets the SDI output spigot&#39;s video standard.
NTV2Buffer acANCBuffer
The host ancillary data buffer. This field is owned by the client application, and thus is responsibl...
NTV2InputXptID GetSDIOutputInputXpt(const NTV2Channel inSDIOutput, const bool inIsDS2=false)
#define Hex0N(__x__, __n__)
static std::string GetLine21ChannelNames(std::string inDelimiter=", ")
Returns a string containing a concatenation of human-readable names of every available NTV2Line21Chan...
#define CAPNOTE(_expr_)
Declares the AJAAncillaryData_Cea708 class.
virtual bool SetVANCMode(const NTV2VANCMode inVancMode, const NTV2Channel inChannel=NTV2_CHANNEL1)
Sets the VANC mode for the given FrameStore.
virtual bool IsRGBSampling(void) const
Definition: ntv2vpid.cpp:414
virtual bool GetStreamingApplication(ULWord &outAppType, int32_t &outProcessID)
Answers with the four-CC type and process ID of the application that currently "owns" the AJA device ...
CEA608 SD Closed Captioning ("Line 21" waveform)
Definition: ancillarydata.h:52
virtual bool SetNumberAudioChannels(const ULWord inNumChannels, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Sets the number of audio channels to be concurrently captured or played for a given Audio System on t...
Definition: ntv2audio.cpp:147
virtual bool IsValid(void) const
Definition: ntv2vpid.h:56
virtual void ToString(std::string &outAllLabelsAndValues) const
Answers with a multi-line string that contains the complete host system info table.
This identifies the "tall" mode in which there are some VANC lines in the frame buffer.
Definition: ntv2enums.h:3806
NTV2OutputXptID GetCSCOutputXptFromChannel(const NTV2Channel inCSC, const bool inIsKey=false, const bool inIsRGB=false)
virtual bool WaitForInputVerticalInterrupt(const NTV2Channel inChannel=NTV2_CHANNEL1, UWord inRepeatCount=1)
Efficiently sleeps the calling thread/process until the next one or more field (interlaced video) or ...
I am an ordered collection of AJAAncillaryData instances which represent one or more SMPTE 291 data p...
Definition: ancillarylist.h:64
UByte * GetTopVisibleRowAddress(UByte *pInStartAddress) const
#define NTV2_ANCSIZE_MAX
This identifies the mode in which there are no VANC lines in the frame buffer.
Definition: ntv2enums.h:3805
Specifies channel or FrameStore 3 (or the 3rd item).
Definition: ntv2enums.h:1365
NTV2ReferenceSource NTV2InputSourceToReferenceSource(const NTV2InputSource inInputSource)
Converts a given NTV2InputSource to its equivalent NTV2ReferenceSource value.
Definition: ntv2utils.cpp:5027
See 8-Bit YCbCr Format.
Definition: ntv2enums.h:227
static const UWord gMixerNums[]
static std::string CaptionDataSrcToString(const CaptionDataSrc inDataSrc)
virtual bool EnableChannel(const NTV2Channel inChannel)
Enables the given FrameStore.