AJA NTV2 SDK  18.0.0.2122
NTV2 SDK 18.0.0.2122
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');
37 static const uint32_t MAX_ACCUM_FRAME_COUNT (30); // At least every second?
38 
39 
41 
42  : mConfig (inConfigData),
43  mCaptureThread (AJAThread()),
44  mDeviceID (DEVICE_ID_NOTFOUND),
45  mSavedTaskMode (NTV2_DISABLE_TASKS),
46  mAudioSystem (mConfig.fWithAudio ? NTV2_AUDIOSYSTEM_1 : NTV2_AUDIOSYSTEM_INVALID),
47  mVancMode (NTV2_VANCMODE_INVALID),
48  mGlobalQuit (false),
49  mSquares (false),
50  mLastOutStr (),
51  mLastOutFrame (0),
52  mErrorTally (0),
53  mCaptionDataTally (0),
54  m608Channel (mConfig.fCaptionChannel),
55  m608Mode (NTV2_CC608_CapModeUnknown),
56  m608Decoder (),
57  mVPIDInfoDS1 (0),
58  mVPIDInfoDS2 (0),
59  mInputFrameStores (),
60  mActiveSDIInputs (),
61  mActiveCSCs (),
62  mInputConnections (),
63  mHostBuffers (),
64  mCircularBuffer (),
65  mInputXferInfo (),
66  mHeadUpDisplayOn (true),
67  mOutputChannel (NTV2_CHANNEL_INVALID),
68  mPlayoutFBF (NTV2_FBF_ARGB),
69  mPlayoutThread (AJAThread()),
70  mOutputConnections ()
71 {
72  CNTV2CaptionDecoder608::Create(m608Decoder);
73  CNTV2CaptionDecoder708::Create(m708DecoderAnc);
74  CNTV2CaptionDecoder708::Create(m708DecoderVanc);
75  NTV2_ASSERT (m608Decoder && m708DecoderAnc && m708DecoderVanc);
76 
77 } // constructor
78 
79 
81 {
82  if (m608Decoder)
84 
85  // Stop my capture thread, then destroy it...
86  Quit();
87 
88  // Unsubscribe from input vertical event...
89  mDevice.UnsubscribeInputVerticalEvent(mInputFrameStores);
90 
92 
93  if (!mConfig.fDoMultiFormat)
94  {
95  mDevice.SetTaskMode(mSavedTaskMode);
96  mDevice.ReleaseStreamForApplication (kAppSignature, static_cast<int32_t>(AJAProcess::GetPid()));
97  }
98 
99 } // destructor
100 
101 
103 {
104  // Set the 'quit' flag, and wait for the threads to go inactive...
105  mGlobalQuit = true;
106 
107  while (mCaptureThread.Active())
108  AJATime::Sleep(10);
109 
110  while (mPlayoutThread.Active())
111  AJATime::Sleep(10);
112 
113  if (!mConfig.fDoMultiFormat)
114  mDevice.ClearRouting();
115 
116 } // Quit
117 
118 
120 {
121  CNTV2DemoCommon::SetDefaultPageSize(); // Set host-specific page size
122 
123  // Open the device...
125  {cerr << "## ERROR: Device '" << mConfig.fDeviceSpec << "' not found" << endl; return AJA_STATUS_OPEN;}
126 
127  if (!mDevice.IsDeviceReady(false))
128  {cerr << "## ERROR: Device '" << mConfig.fDeviceSpec << "' not ready" << endl; return AJA_STATUS_INITIALIZE;}
129 
130  mDeviceID = mDevice.GetDeviceID(); // Keep this handy because it's used frequently
131  const string deviceStr(::NTV2DeviceIDToString(mDeviceID));
132 
133  if (mConfig.fBurnCaptions)
134  {
135  if (mDevice.features().GetNumFrameStores() < 2) // Need 2+ frame stores
136  {
137  cerr << "## ERROR: Device '" << deviceStr << "' can't burn-in captions because at least 2 frame stores are required" << endl;
138  return AJA_STATUS_FAIL;
139  }
140  if (!mDevice.features().CanDoPlayback())
141  {
142  cerr << "## ERROR: Device '" << deviceStr << "' can't burn-in captions because device can only capture/ingest" << endl;
143  return AJA_STATUS_FAIL;
144  }
145  if (mDevice.features().GetNumVideoInputs() < 1 || mDevice.features().GetNumVideoOutputs() < 1) // Need 1 input & 1 output
146  {
147  cerr << "## ERROR: Device '" << deviceStr << "' can't be used -- at least 1 SDI input and 1 SDI output required" << endl;
148  return AJA_STATUS_FAIL;
149  }
150  if (!mDevice.features().GetNumMixers()) // Need 1 or more mixers
151  {
152  cerr << "## ERROR: Device '" << deviceStr << "' can't burn-in captions because a mixer/keyer widget is required" << endl;
153  return AJA_STATUS_FAIL;
154  }
155  if (!mDevice.features().CanDoFrameBufferFormat(mPlayoutFBF)) // FrameStore must handle 8-bit RGB with alpha
156  {
157  cerr << "## ERROR: Device '" << deviceStr << "' can't burn-in captions because it can't do 8-bit RGB (with alpha)" << endl;
158  return AJA_STATUS_FAIL;
159  }
160  } // if --burn
161 
162  if (!mConfig.fDoMultiFormat)
163  {
164  if (!mDevice.AcquireStreamForApplication (kAppSignature, static_cast<int32_t>(AJAProcess::GetPid())))
165  {cerr << "## ERROR: Cannot acquire -- device busy" << endl; return AJA_STATUS_BUSY;} // Some other app owns the device
166  mDevice.GetTaskMode(mSavedTaskMode); // Save the current task mode
167  }
168 
169  mDevice.SetTaskMode(NTV2_OEM_TASKS); // Use the OEM service level
170 
171  if (mDevice.features().CanDoMultiFormat())
172  mDevice.SetMultiFormatMode(mConfig.fDoMultiFormat);
173 
174  if (!mConfig.fUseVanc && !mDevice.features().CanDoCustomAnc()) // --vanc not specified && no anc extractors?
175  {
176  cerr << "## WARNING: Enabling VANC because no Anc extractors" << endl;
177  mConfig.fUseVanc = true;
178  }
179 
180  // Set up the input video...
181  AJAStatus status = SetupInputVideo();
182  if (AJA_FAILURE(status))
183  return status;
184 
185  // Set up the audio...
186  status = SetupAudio();
187  if (AJA_FAILURE(status))
188  return status;
189 
190  if (!m608Decoder->SubscribeChangeNotification(Caption608ChangedStatic, this))
191  {cerr << "## WARNING: SubscribeChangeNotification failed" << endl; return AJA_STATUS_FAIL;}
192  #if defined(_DEBUG)
193  cerr << mConfig << endl;
194  #endif // defined(_DEBUG)
195  return AJA_STATUS_SUCCESS;
196 
197 } // Init
198 
199 
201 {
203  mDevice.GetVANCMode (vancMode, mConfig.fInputChannel);
204  const ULWord captureBufferSize (::GetVideoWriteSize (inVideoFormat, mConfig.fPixelFormat, vancMode));
205 
207  mCircularBuffer.SetAbortFlag (&mGlobalQuit);
208 
209  // Allocate and add each NTV2FrameData to my circular buffer member variable...
210  mHostBuffers.reserve(CIRCULAR_BUFFER_SIZE);
211  while (mHostBuffers.size() < CIRCULAR_BUFFER_SIZE)
212  {
213  mHostBuffers.push_back(NTV2FrameData()); // Make a new NTV2FrameData...
214  NTV2FrameData & frameData(mHostBuffers.back()); // ...and get a reference to it
215  // Allocate a page-aligned video buffer
216  if (!frameData.fVideoBuffer.Allocate(captureBufferSize, /*pageAlign?*/true))
217  return AJA_STATUS_MEMORY;
218  if (NTV2_IS_VALID_AUDIO_SYSTEM(mAudioSystem))
219  if (!frameData.fAudioBuffer.Allocate(NTV2_AUDIOSIZE_MAX, /*pageAlign?*/true))
220  return AJA_STATUS_MEMORY;
221  // Anc data buffers --- only used if Anc extractors supported...
222  if (mDevice.features().CanDoCustomAnc())
223  {
224  if (!frameData.fAncBuffer.Allocate(NTV2_ANCSIZE_MAX, /*pageAlign?*/true))
225  return AJA_STATUS_MEMORY;
226  if (!frameData.fAncBuffer2.Allocate(NTV2_ANCSIZE_MAX, /*pageAlign?*/true))
227  return AJA_STATUS_MEMORY;
228  }
229  #if defined(NTV2_BUFFER_LOCK)
230  frameData.LockAll(mDevice);
231  #endif
232  mCircularBuffer.Add(&frameData); // Add to my circular buffer
233  } // for each NTV2FrameData
234 
235  return AJA_STATUS_SUCCESS;
236 
237 } // SetupHostBuffers
238 
239 
241 {
242  // Unlock each in-host NTV2FrameData...
243  #if defined(NTV2_BUFFER_LOCK)
244  for (size_t ndx(0); ndx < mHostBuffers.size(); ndx++)
245  {
246  NTV2FrameData & frameData(mHostBuffers.at(ndx));
247  frameData.UnlockAll(mDevice);
248  }
249  #endif // NTV2_BUFFER_LOCK
250  mHostBuffers.clear();
251  mCircularBuffer.Clear();
252  return;
253 
254 } // ReleaseHostBuffers
255 
256 
258 {
259  bool isTransmit (false);
260  const UWord numFrameStores (mDevice.features().GetNumFrameStores());
261  const NTV2DeviceID deviceID (mDevice.GetDeviceID());
262  const string deviceName (::NTV2DeviceIDToString(deviceID));
263  const string channelName (::NTV2ChannelToString(mConfig.fInputChannel, true));
264 
265  // CCGrabber is SDI only
266  // User must have specified at least --input or --channel
268  {cerr << "## ERROR: Must specify at least input source or input channel" << endl; return AJA_STATUS_FAIL;}
269  else if (!NTV2_IS_VALID_INPUT_SOURCE(mConfig.fInputSource))
271  else if (!NTV2_IS_VALID_CHANNEL(mConfig.fInputChannel))
273 
274  // Check input source
275  const string inputName (::NTV2InputSourceToString(mConfig.fInputSource,true));
276  if (!mDevice.features().CanDoInputSource(mConfig.fInputSource))
277  {cerr << "## ERROR: '" << deviceName << "' cannot grab captions from '" << inputName << "'" << endl; return AJA_STATUS_FAIL;}
279  {cerr << "## ERROR: Input '" << inputName << "' not SDI" << endl; return AJA_STATUS_FAIL;}
280 
281  // Check channel
282  if (numFrameStores < UWord(mConfig.fInputChannel+1))
283  {cerr << "## ERROR: " << deviceName << " has no " << channelName << " input" << endl; return AJA_STATUS_FAIL;}
284 
285  const NTV2Channel sdiInput(::NTV2InputSourceToChannel(mConfig.fInputSource));
286  mActiveSDIInputs.insert(sdiInput);
287  if (mDevice.features().HasBiDirectionalSDI()) // If device has bidirectional SDI connectors...
288  if (mDevice.GetSDITransmitEnable(sdiInput, isTransmit)) // ...and GetSDITransmitEnable succeeds...
289  if (isTransmit) // ...and input is set to "transmit"...
290  {
291  mDevice.SetSDITransmitEnable(sdiInput, false); // ...then disable transmit mode...
292  mDevice.WaitForOutputVerticalInterrupt(NTV2_CHANNEL1, 12); // ...and give the device some time to lock to a signal
293  } // if input SDI connector needs to switch from transmit mode
294 
296  mDevice.GetReference(refSrc);
297  if (mConfig.fBurnCaptions || (!mConfig.fBurnCaptions && !mConfig.fDoMultiFormat))
298  {
299  // Set the device output clock reference to the SDI input.
300  // This is necessary only when...
301  // - Doing caption burn-in, which requires syncing the Mixer input to the SDI input;
302  // - Routing E-E, which is only done when not doing burn-in and not doing multi-format mode.
304  mDevice.SetReference(refSrc);
305  }
306  if (mConfig.fBurnCaptions) // Caption burn-in/playout requires choosing an output channel
307  switch (mConfig.fInputChannel)
308  {
309  case NTV2_CHANNEL1: mOutputChannel = (numFrameStores == 2 || numFrameStores > 4) ? NTV2_CHANNEL2 : NTV2_CHANNEL3; break;
310  case NTV2_CHANNEL2: mOutputChannel = (numFrameStores > 4) ? NTV2_CHANNEL3 : NTV2_CHANNEL4; break;
311  case NTV2_CHANNEL3: mOutputChannel = NTV2_CHANNEL4; break;
312  case NTV2_CHANNEL4: mOutputChannel = (numFrameStores > 4) ? NTV2_CHANNEL5 : NTV2_CHANNEL3; break;
313  case NTV2_CHANNEL5: mOutputChannel = NTV2_CHANNEL6; break;
314  case NTV2_CHANNEL6: mOutputChannel = NTV2_CHANNEL7; break;
315  case NTV2_CHANNEL7: mOutputChannel = NTV2_CHANNEL8; break;
316  case NTV2_CHANNEL8: mOutputChannel = NTV2_CHANNEL7; break;
318  }
319 
320  if (!mDevice.features().CanDoFrameBufferFormat(mConfig.fPixelFormat))
321  {cerr << "## ERROR: '" << deviceName << "' doesn't support '" << ::NTV2FrameBufferFormatToString(mConfig.fPixelFormat) << "'" << endl; return AJA_STATUS_FAIL;}
322 
323  // "Tune" the 608 decoder to the desired channel...
324  m608Decoder->SetDisplayChannel(m608Channel);
325  m708DecoderAnc->SetDisplayChannel(m608Channel);
326  m708DecoderVanc->SetDisplayChannel(m608Channel);
327 
328  cerr << "## NOTE: Using " << deviceName << " " << (mConfig.fUseVanc ? "VANC" : "AncExt") << " with spigot=" << inputName
329  << ", ref=" << ::NTV2ReferenceSourceToString(refSrc,true) << ", input=" << channelName;
330  if (mConfig.fBurnCaptions) cerr << ", output=" << ::NTV2ChannelToString(mOutputChannel,true);
331  cerr << endl;
332 
333  return AJA_STATUS_SUCCESS;
334 
335 } // SetupInputVideo
336 
337 
339 {
340  if (NTV2_IS_VALID_AUDIO_SYSTEM(mAudioSystem))
341  {
342  const UWord numAudioSystems (mDevice.features().GetNumAudioSystems());
343  if (numAudioSystems > 1 && UWord(mConfig.fInputChannel) < numAudioSystems)
344  mAudioSystem = ::NTV2ChannelToAudioSystem(mConfig.fInputChannel);
345 
346  // Configure the audio system...
348  mDevice.SetNumberAudioChannels (mDevice.features().GetMaxAudioChannels(), mAudioSystem);
349  mDevice.SetAudioRate (NTV2_AUDIO_48K, mAudioSystem);
350  mDevice.SetAudioBufferSize (NTV2_AUDIO_BUFFER_BIG, mAudioSystem);
351 
352  // Set up the output audio embedders...
353  if (mConfig.fBurnCaptions && numAudioSystems > 1)
354  {
355  if (mConfig.fDoMultiFormat)
356  {
357  UWord sdiOutput(mOutputChannel);
358  if (sdiOutput >= mDevice.features().GetNumVideoOutputs()) // Kona1 has 2 FrameStores/Channels, but only 1 SDI output
359  sdiOutput = mDevice.features().GetNumVideoOutputs() - 1;
360  mDevice.SetSDIOutputAudioSystem(NTV2Channel(sdiOutput), mAudioSystem);
361  }
362  else // Have all device outputs use the same audio system...
363  for (unsigned sdiOutput(0); sdiOutput < mDevice.features().GetNumVideoOutputs(); sdiOutput++)
364  if (!mDevice.features().HasBiDirectionalSDI()
365  || NTV2Channel(sdiOutput) != ::NTV2InputSourceToChannel(mConfig.fInputSource))
366  mDevice.SetSDIOutputAudioSystem(NTV2Channel(sdiOutput), mAudioSystem);
367  }
368 
369  // Loopback mode (E-E audio) should be enabled only when not burning-in captions (i.e. when routing E-E).
370  // If caption burn-in and loopback are enabled, output video will lag the audio, as video frames are delayed
371  // in the ring buffer.
373  }
374  return AJA_STATUS_SUCCESS;
375 
376 } // SetupAudio
377 
378 
381 
384 
387 
388 
390 {
391  const bool isRGBFBF (::IsRGBFormat(mConfig.fPixelFormat));
392  const bool isRGBWire (mVPIDInfoDS1.IsRGBSampling());
393  const bool isSquares (!mVPIDInfoDS1.IsStandardTwoSampleInterleave());
394  const bool is4KHFR (NTV2_IS_HFR_STANDARD(::GetNTV2StandardFromVideoFormat(inVideoFormat)));
395  const NTV2Channel sdiInput (::NTV2InputSourceToChannel(mConfig.fInputSource));
396  const NTV2ChannelList frameStores (::NTV2MakeChannelList(mInputFrameStores));
397  NTV2ChannelList sdiInputs (::NTV2MakeChannelList(mActiveSDIInputs));
398  const NTV2ChannelList activeCSCs (::NTV2MakeChannelList(mActiveCSCs));
399  static const bool ShowRoutingProgress(false);
400 
401  mInputConnections.clear();
402  if (ShowRoutingProgress) mDevice.ClearRouting();
403 
404  // Route frameStore's input to sdiInput's output (possibly through CSC, if required)
405  if (isRGBFBF && isRGBWire)
406  {
407  if (isSquares) // SDIIn ==> DLIn ==> FrameStore
408  {
409  for (size_t ndx(0); ndx < sdiInputs.size(); ndx++)
410  { NTV2Channel frmSt(frameStores.at(ndx)), sdiIn(sdiInputs.at(ndx));
411  mInputConnections.insert(NTV2XptConnection(::GetDLInInputXptFromChannel(sdiIn, /*linkB?*/false),
412  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/false)));
413  mInputConnections.insert(NTV2XptConnection(::GetDLInInputXptFromChannel(sdiIn, /*linkB?*/true),
414  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/true)));
415  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(sdiIn),
416  ::GetDLInOutputXptFromChannel(frmSt)));
417  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
418  }
419  }
420  else // TSI // 2x SDIIn ==> 2x DLIn ==> 425MUX ==> RGBFrameStore
421  {
422  NTV2ChannelSet sdiIns = ::NTV2MakeChannelSet(sdiInput, UWord(2*frameStores.size()));
423  sdiInputs = ::NTV2MakeChannelList(sdiIns);
424  NTV2ChannelList tsiMuxes = CNTV2DemoCommon::GetTSIMuxesForFrameStore(mDevice, frameStores.at(0),
425  UWord(frameStores.size()*2));
426  mDevice.SetSDITransmitEnable(sdiIns, true); // Gotta do this again, since sdiInputs changed
427  for (size_t ndx(0); ndx < sdiInputs.size(); ndx++)
428  { NTV2Channel frmSt(frameStores.at(ndx/2)), tsiMux(tsiMuxes.at(ndx/2)), sdiIn(sdiInputs.at(ndx));
429  mInputConnections.insert(NTV2XptConnection(::GetDLInInputXptFromChannel(sdiIn, /*DS2?*/false),
430  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/false)));
431  mInputConnections.insert(NTV2XptConnection(::GetDLInInputXptFromChannel(sdiIn, /*DS2?*/true),
432  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/true)));
433  mInputConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux, /*lnkB?*/ndx & 1),
434  ::GetDLInOutputXptFromChannel(sdiIn)));
435  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt, /*lnkB?*/false),
436  ::GetTSIMuxOutputXptFromChannel(tsiMux,/*lnkB?*/false, /*rgb?*/true)));
437  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt, /*lnkB?*/true),
438  ::GetTSIMuxOutputXptFromChannel(tsiMux,/*lnkB?*/true, /*rgb?*/true)));
439  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
440  }
441  }
442  }
443  else if (isRGBFBF && !isRGBWire)
444  {
445  if (isSquares) // SDIIn ==> CSC ==> RGBFrameStore
446  for (size_t ndx(0); ndx < sdiInputs.size(); ndx++)
447  { NTV2Channel frmSt(frameStores.at(ndx)), sdiIn(sdiInputs.at(ndx));
448  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt),
449  ::GetCSCOutputXptFromChannel(frmSt, /*key?*/false, /*RGB?*/true)));
450  mInputConnections.insert(NTV2XptConnection(::GetCSCInputXptFromChannel(frmSt),
452  }
453  else // TSI // SDIIn ==> 2 x CSC ==> 425MUX ==> RGBFrameStore
454  {
455  NTV2ChannelSet sdiIns = ::NTV2MakeChannelSet(sdiInput, UWord(frameStores.size()));
456  sdiInputs = ::NTV2MakeChannelList(sdiIns);
458  UWord(2*sdiInputs.size()));
459  NTV2ChannelList tsiMuxes = CNTV2DemoCommon::GetTSIMuxesForFrameStore(mDevice, frameStores.at(0),
460  UWord(frameStores.size()));
461  cerr << "FrameStores: " << ::NTV2ChannelListToStr(frameStores) << endl
462  << "SDIInputs: " << ::NTV2ChannelListToStr(sdiInputs) << endl
463  << "TSIMuxers: " << ::NTV2ChannelListToStr(tsiMuxes) << endl;
464  mDevice.SetSDITransmitEnable(sdiIns, false); // Gotta do this again, since sdiIns changed
465  for (size_t ndx(0); ndx < cscs.size(); ndx++)
466  { NTV2Channel frmSt(frameStores.at(ndx/2)), sdiIn(sdiInputs.at(ndx/2)), tsiMux(tsiMuxes.at(ndx/2)),
467  csc(cscs.at(ndx));
468  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt, /*inputB?*/ndx & 1),
469  ::GetTSIMuxOutputXptFromChannel(tsiMux,/*linkB?*/ndx & 1,/*rgb?*/true)));
470  mInputConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux, /*linkB?*/ndx & 1),
471  ::GetCSCOutputXptFromChannel(csc, /*key?*/false, /*rgb?*/true)));
472  mInputConnections.insert(NTV2XptConnection(::GetCSCInputXptFromChannel(csc),
473  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/ndx & 1)));
474  }
475  }
476  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
477  }
478  else if (!isRGBFBF && isRGBWire)
479  {
480  if (isSquares) // SDIIn ==> DLIn ==> CSC ==> FrameStore
481  {
482  for (size_t ndx(0); ndx < sdiInputs.size(); ndx++)
483  { NTV2Channel frmSt(frameStores.at(ndx)), csc(activeCSCs.at(ndx)), sdi(sdiInputs.at(ndx));
484  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt, /*BInput?*/false),
486  mInputConnections.insert(NTV2XptConnection(::GetCSCInputXptFromChannel(csc),
488  mInputConnections.insert(NTV2XptConnection(::GetDLInInputXptFromChannel(sdi, /*lnkB?*/false),
489  ::GetSDIInputOutputXptFromChannel(sdi, /*DS2?*/false)));
490  mInputConnections.insert(NTV2XptConnection(::GetDLInInputXptFromChannel(sdi, /*lnkB?*/true),
491  ::GetSDIInputOutputXptFromChannel(sdi, /*DS2?*/true)));
492  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
493  }
494  }
495  else // TSI // SDIIn ==> DLIn ==> CSC ==> TSIMux ==> FrameStore
496  {
497  //TBD
498  }
499  }
500  else // SDIIn ==> YUVFrameStore
501  {
502  if (isSquares) // SDIIn ==> FrameStore
503  {
504  for (size_t ndx(0); ndx < sdiInputs.size(); ndx++)
505  { NTV2Channel frmSt(frameStores.at(ndx)), sdiIn(sdiInputs.at(ndx));
506  mInputConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt),
508  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
509  }
510  }
511  else // TSI // SDIIn (LFR: 2 x DS1&DS2, 4KHFR: 4 x DS1) ==> 425MUX ==> YUVFrameStore
512  {
513  NTV2XptConnections & mConnections(mInputConnections);
514  sdiInputs = ::NTV2MakeChannelList(sdiInputs.at(0), is4KHFR ? 4 : UWord(frameStores.size()));
515  NTV2ChannelList tsiMuxes = CNTV2DemoCommon::GetTSIMuxesForFrameStore(mDevice, frameStores.at(0),
516  UWord(frameStores.size()));
517  cerr << (is4KHFR ? "4KHFR" : "") << endl << "FrameStores: " << ::NTV2ChannelListToStr(frameStores) << endl
518  << "SDIInputs: " << ::NTV2ChannelListToStr(sdiInputs) << endl << "TSIMuxes: " << ::NTV2ChannelListToStr(tsiMuxes) << endl;
519  for (size_t ndx(0); ndx < sdiInputs.size(); ndx++)
520  { NTV2Channel frmSt(frameStores.at(is4KHFR ? ndx/2 : ndx)),
521  tsiMux(tsiMuxes.at(is4KHFR ? ndx/2 : ndx)),
522  sdiIn(sdiInputs.at(ndx));
523  mConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux, /*linkB?*/is4KHFR && (ndx & 1)),
524  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/false)));
525  if (!is4KHFR)
526  mConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux, /*linkB?*/true),
527  ::GetSDIInputOutputXptFromChannel(sdiIn, /*DS2?*/true)));
528  mConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt, /*inputB?*/is4KHFR && (ndx & 1)),
529  ::GetTSIMuxOutputXptFromChannel(tsiMux,/*linkB?*/is4KHFR && (ndx & 1))));
530  if (!is4KHFR)
531  mConnections.insert(NTV2XptConnection(::GetFrameStoreInputXptFromChannel(frmSt, /*inputB?*/true),
532  ::GetTSIMuxOutputXptFromChannel(tsiMux,/*linkB?*/true)));
533  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
534  }
535  }
536  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
537  }
538  // At this point, sdiInputs is authoritative, so update mActiveSDIInputs...
539  mActiveSDIInputs = ::NTV2MakeChannelSet(sdiInputs);
540 
541  // E-E ROUTING
542  if ((false) /* not ready for prime-time */ && !mConfig.fBurnCaptions && !mConfig.fDoMultiFormat)
543  { // Not doing caption burn-in: route E-E pass-thru...
544  NTV2ChannelList sdiOutputs;
545  if (mDevice.features().HasBiDirectionalSDI())
546  {
548  NTV2ChannelSet sdiOuts;
549  set_difference (allSDIs.begin(), allSDIs.end(), // allSDIs
550  mActiveSDIInputs.begin(), mActiveSDIInputs.end(), // - mActiveSDIInputs
551  inserter(sdiOuts, sdiOuts.begin())); // ==> sdiOuts
552  sdiOutputs = ::NTV2MakeChannelList(sdiOuts);
553  cerr << "allSDIs: " << ::NTV2ChannelSetToStr(allSDIs) << endl << "actSDIIns: " << ::NTV2ChannelSetToStr(mActiveSDIInputs) << endl; // DEBUG
554  }
555  else
557  cerr << "SDIOuts: " << ::NTV2ChannelListToStr(sdiOutputs) << endl << "SDIIns: " << ::NTV2ChannelListToStr(sdiInputs) << endl; // DEBUG
558  for (size_t sdiNdx(0); sdiNdx < sdiOutputs.size(); sdiNdx++)
559  { const NTV2Channel sdiOut(sdiOutputs.at(sdiNdx));
560  const NTV2Channel sdiIn(sdiInputs.at(sdiNdx < sdiInputs.size() ? sdiNdx : sdiInputs.size()-1));
561  if (mDevice.features().HasBiDirectionalSDI() && mActiveSDIInputs.find(sdiOut) == mActiveSDIInputs.end())
562  {
563  cerr << "Switching SDI " << (sdiOut+1) << " to output" << endl; // DEBUG
564  mDevice.SetSDITransmitEnable(sdiOut, true);
565  }
566  if (isRGBWire)
567  { // Route DLIn output to DLOut...
568  mInputConnections.insert(NTV2XptConnection(::GetDLOutInputXptFromChannel(sdiOut),
569  ::GetDLInOutputXptFromChannel(sdiIn)));
570  mInputConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut,false),
571  ::GetDLOutOutputXptFromChannel(sdiOut,false)));
572  mInputConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut,true),
573  ::GetDLOutOutputXptFromChannel(sdiOut,true)));
574  }
575  else
576  mInputConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut),
578  if (ShowRoutingProgress) mDevice.ApplySignalRoute(mInputConnections);
579  } // for each output spigot
580  } // if not burning captions and not multiFormat
581 
582  return mDevice.ApplySignalRoute(mInputConnections, /*replaceExistingRouting?*/!mConfig.fDoMultiFormat);
583 
584 } // RouteInputSignal
585 
586 
588 {
589  NTV2_ASSERT (!mConfig.fBurnCaptions); // Must not be burning captions
590 
591  const NTV2Channel sdiInputAsChan (::NTV2InputSourceToChannel(mConfig.fInputSource));
592  const NTV2Standard outputStandard (::GetNTV2StandardFromVideoFormat(inVideoFormat));
593  const NTV2Channel startNum (sdiInputAsChan == NTV2_CHANNEL1 ? NTV2_CHANNEL1 : NTV2_CHANNEL5);
594  const NTV2Channel endNum (sdiInputAsChan == NTV2_CHANNEL1 ? NTV2_CHANNEL5 : NTV2_MAX_NUM_CHANNELS);
595 
596  for (NTV2Channel chan(startNum); chan < endNum; chan = NTV2Channel(chan + 1))
597  {
598  if (ULWord(chan) >= mDevice.features().GetNumVideoChannels())
599  break;
600  if (chan != sdiInputAsChan)
601  if (mDevice.features().CanDoWidget(g3GSDIOutputs[chan]) || mDevice.features().CanDoWidget(gSDIOutputs[chan]))
602  mDevice.SetSDIOutputStandard(chan, outputStandard);
603  } // for each output spigot
604 
605 } // SetOutputStandards
606 
607 
609 {
610  // Start the capture thread...
611  AJAStatus result (StartCaptureThread());
612  if (AJA_FAILURE(result))
613  return result;
614 
615  AJATime::Sleep(500); // Wait a half second for the capture thread to start (or fail?)...
617 
618 } // Run
619 
620 
621 
623 
624 // Starts the capture thread
626 {
627  // Create and start the capture thread...
628  AJAStatus result (mCaptureThread.Attach(CaptureThreadStatic, this));
629  if (AJA_SUCCESS(result))
630  result = mCaptureThread.SetPriority(AJA_ThreadPriority_High);
631  if (AJA_SUCCESS(result))
632  result = mCaptureThread.Start();
633  return result;
634 
635 } // StartCaptureThread
636 
637 
638 // The capture thread function
639 void NTV2CCGrabber::CaptureThreadStatic (AJAThread * pThread, void * pContext) // static
640 {
641  (void) pThread;
642  // Grab the NTV2CCGrabber instance pointer from the pContext parameter,
643  // then call its CaptureFrames method...
644  NTV2CCGrabber * pApp (reinterpret_cast <NTV2CCGrabber *> (pContext));
645  pApp->CaptureFrames ();
646 
647 } // CaptureThreadStatic
648 
649 
650 // The capture function -- capture frames until told to quit...
652 {
653  ULWord xferTally(0), xferFails(0), noVideoTally(0), waitTally(0);
654  bool bUsingVanc (mConfig.fUseVanc); // To detect fUseVanc changes
655  CAPNOTE("Thread started");
656  NTV2_ASSERT(!mActiveSDIInputs.empty());
657 
658  // Loop until time to quit...
659  while (!mGlobalQuit)
660  {
661  NTV2PixelFormat currentPF (mConfig.fPixelFormat);
663  if (currentVF == NTV2_FORMAT_UNKNOWN)
664  break; // Quit
665 
666  // At this point, the input video format is stable.
667 
668  // Configure the input FrameStore(s): pixel format, mode...
669  mDevice.EnableChannels(mInputFrameStores);
670  mDevice.SetFrameBufferFormat(mInputFrameStores, mConfig.fPixelFormat);
671 
672  // Enable and subscribe to the interrupts for the channel to be used...
673  mDevice.EnableInputInterrupt (mInputFrameStores);
674  mDevice.SubscribeInputVerticalEvent (mInputFrameStores);
675 
676  // Set up the device signal routing...
677  RouteInputSignal(currentVF);
678 
679  // Set the device format to the input format detected, and set VANC mode...
680  mDevice.SetVideoFormat (mInputFrameStores, currentVF, /*retailMode*/false);
681  if (NTV2_IS_4K_VIDEO_FORMAT(currentVF))
682  {
683  if (mDevice.features().CanDo12gRouting())
684  mDevice.SetTsiFrameEnable(true, mConfig.fInputChannel);
685  else if (mSquares)
686  mDevice.Set4kSquaresEnable(true, mConfig.fInputChannel);
687  else
688  mDevice.SetTsiFrameEnable(true, mConfig.fInputChannel);
689  mVancMode = NTV2_VANCMODE_OFF;
690  if (mConfig.fUseVanc)
691  CAPWARN("VANC mode incompatible with 4K/UHD format");
692  }
693  else
694  mVancMode = mConfig.fUseVanc ? NTV2_VANCMODE_TALL : NTV2_VANCMODE_OFF; // "Tall" mode is sufficient to grab captions
695  mDevice.SetVANCMode(mInputFrameStores, mVancMode);
696  if (::Is8BitFrameBufferFormat(mConfig.fPixelFormat))
697  mDevice.SetVANCShiftMode (mConfig.fInputChannel, // 8-bit FBFs require VANC bit shift
699 
700  // Set up the circular buffers based on the detected currentVF...
701  AJAStatus status (SetupHostBuffers(currentVF));
702  if (AJA_FAILURE(status))
703  return;
704 
705  if (mConfig.fBurnCaptions) // If burning-in captions...
706  StartPlayThread(); // ...start a new playout thread
707  else // else E-E mode...
708  SetOutputStandards(currentVF); // ...output standard may need changing
709 
710  mDevice.AutoCirculateStop(mConfig.fInputChannel);
711  if (!mDevice.AutoCirculateInitForInput( mConfig.fInputChannel, mConfig.fFrames, mAudioSystem, AUTOCIRCULATE_WITH_RP188
712  | (mDevice.features().CanDoCustomAnc() ? AUTOCIRCULATE_WITH_ANC : 0)))
713  {CAPFAIL("Failed to init Ch" << DEC(mConfig.fInputChannel+1) << " for input"); break;}
714 
715  // Start AutoCirculate...
716  if (!mDevice.AutoCirculateStart(mConfig.fInputChannel))
717  {CAPFAIL("Failed to start Ch" << DEC(mConfig.fInputChannel+1)); break;}
718 
719  // Process frames until signal format changes...
720  while (!mGlobalQuit)
721  {
722  AUTOCIRCULATE_STATUS acStatus;
723  mDevice.AutoCirculateGetStatus (mConfig.fInputChannel, acStatus);
724  if (acStatus.IsRunning() && acStatus.HasAvailableInputFrame())
725  {
726  // At this point, there's at least one fully-formed frame available in the device's
727  // frame buffer to transfer to the host. Reserve an NTV2FrameData to "produce", and
728  // use it to store the next frame to be transferred from the device...
729  NTV2FrameData * pCaptureData (mCircularBuffer.StartProduceNextBuffer());
730  if (pCaptureData)
731  {
732  mInputXferInfo.acFrameBufferFormat = mConfig.fPixelFormat;
733  mInputXferInfo.SetBuffers (pCaptureData->VideoBuffer(), pCaptureData->VideoBufferSize(),
734  pCaptureData->AudioBuffer(), pCaptureData->AudioBufferSize(),
735  pCaptureData->AncBuffer(), pCaptureData->AncBufferSize(),
736  pCaptureData->AncBuffer2(), pCaptureData->AncBuffer2Size());
737 
738  // Transfer the frame data from the device into our host NTV2FrameData...
739  if (mDevice.AutoCirculateTransfer (mConfig.fInputChannel, mInputXferInfo))
740  {
741  xferTally++;
742  if (mConfig.fBurnCaptions)
743  mInputXferInfo.GetInputTimeCodes(pCaptureData->fTimecodes, ::NTV2InputSourceToChannel(mConfig.fInputSource)); // Captured timecodes
744 
745  // Extract closed-captioning data from the host NTV2FrameData while we have full access to it...
746  ExtractClosedCaptionData (mInputXferInfo.GetTransferStatus().GetProcessedFrameCount(), currentVF);
747  }
748  else
749  xferFails++;
750 
751  // Signal that we're done "producing" the frame, making it available for future "consumption"...
752  mCircularBuffer.EndProduceNextBuffer();
753 
754  if (!mConfig.fBurnCaptions)
755  {
756  // If no caption burn-in is taking place, there's nobody to consume the buffer.
757  // In this case, simply consume it now, thus recycling it immediately...
758  mCircularBuffer.StartConsumeNextBuffer();
759  mCircularBuffer.EndConsumeNextBuffer();
760  }
761  } // if pCaptureData != NULL
762  } // if A/C running and frame(s) are available for transfer
763  else
764  {
765  // Either AutoCirculate is not running, or there were no frames available on the device to transfer.
766  // Rather than waste CPU cycles spinning, waiting until a frame becomes available, it's far more
767  // efficient to wait for the next input vertical interrupt event to get signaled...
769  ++waitTally;
770 
771  // Did incoming video format or VPID(s) change?
772  const NTV2Channel sdiConnector (mActiveSDIInputs.empty() ? NTV2_CHANNEL1 : *(mActiveSDIInputs.begin()));
773  ULWord vpidDS1(0), vpidDS2(0);
774  if (mDevice.GetVPIDValidA(sdiConnector))
775  mDevice.ReadSDIInVPID (sdiConnector, vpidDS1, vpidDS2);
776 
777  NTV2VideoFormat newVF (mDevice.GetInputVideoFormat(mConfig.fInputSource));
778  const bool vfChanged(newVF != currentVF);
779  const bool vpidChgd(mVPIDInfoDS1.GetVPID() != vpidDS1 || mVPIDInfoDS2.GetVPID() != vpidDS2);
780  if (vfChanged || vpidChgd) // || squares != mSquares)
781  {
782  ++noVideoTally;
783  if (vfChanged)
784  CAPWARN("Input video format changed from '" << ::NTV2VideoFormatToString(currentVF)
785  << "' to '" << ::NTV2VideoFormatToString(newVF) << "'");
786  else if (vpidChgd)
787  CAPWARN("Input VPID changed: DS1 (" << xHEX0N(mVPIDInfoDS1.GetVPID(),8) << " to " << xHEX0N(vpidDS1,8)
788  << "), DS2 (" << xHEX0N(mVPIDInfoDS2.GetVPID(),8) << " to " << xHEX0N(vpidDS2,8) << ")");
789 
790  // Terminate the playout thread...
791  mCircularBuffer.StartProduceNextBuffer();
792  mCircularBuffer.EndProduceNextBuffer();
793  break; // exit frame processing loop to restart AutoCirculate
794  } // if incoming video format changed
795  } // else not running or no frames available
796 
797  // Check if pixel format change requested (user pressed P key)...
798  if (mConfig.fPixelFormat != currentPF)
799  {
800  CAPWARN("FrameStore pixel format changed from '"
801  << ::NTV2FrameBufferFormatToString(currentPF,true) << "' to '"
802  << ::NTV2FrameBufferFormatToString(mConfig.fPixelFormat,true) << "'");
803  break; // exit frame processing loop -- restart AutoCirculate
804  }
805  if (mConfig.fUseVanc != bUsingVanc)
806  {
807  CAPWARN("Vanc " << (mConfig.fUseVanc?"enabled":"disabled"));
808  bUsingVanc = mConfig.fUseVanc;
809  break; // exit frame processing loop -- restart AutoCirculate
810  }
811  } // normal frame processing loop -- loop until signal or pixel format change
812 
813  // Stop AutoCirculate...
814  mDevice.AutoCirculateStop(mConfig.fInputChannel);
815 
816  } // loop til quit signaled
817  CAPNOTE("Thread completed, " << DEC(xferTally) << " of " << DEC(xferTally+xferFails) << " frms xferred, "
818  << DEC(waitTally) << " waits, " << DEC(noVideoTally) << " sig chgs");
819 
820 } // CaptureFrames
821 
823 {
825  ULWord numConsecutiveFrames(0), MIN_NUM_CONSECUTIVE_FRAMES(6);
826  NTV2_ASSERT(!mActiveSDIInputs.empty());
827  NTV2Channel sdiConnector(*(mActiveSDIInputs.begin()));
828 
829  // Detection loop:
830  while (result == NTV2_FORMAT_UNKNOWN)
831  {
832  // Determine the input video signal format...
833  // Warning: if there's no input signal, this loop won't exit until mGlobalQuit goes true!
834  mVPIDInfoDS1.MakeInvalid(); mVPIDInfoDS2.MakeInvalid(); // Reset VPID info
835  UWord loopCount(0);
836  while (result == NTV2_FORMAT_UNKNOWN)
837  {
839  if (mGlobalQuit)
840  return NTV2_FORMAT_UNKNOWN; // Terminate if asked to do so
841 
842  const NTV2VideoFormat currVF (mDevice.GetInputVideoFormat(mConfig.fInputSource));
843  if (currVF == NTV2_FORMAT_UNKNOWN)
844  { // Wait for video signal to appear
845  if (++loopCount % 500 == 0) // Log message every minute or so at ~50ms
846  CAPDBG("Waiting for valid video signal to appear at "
847  << ::NTV2InputSourceToString(mConfig.fInputSource,true));
848  }
849  else if (numConsecutiveFrames == 0)
850  {
851  lastVF = currVF; // First valid video format to appear
852  numConsecutiveFrames++; // Start debounce counter
853  }
854  else if (numConsecutiveFrames == MIN_NUM_CONSECUTIVE_FRAMES)
855  {
856  numConsecutiveFrames = 0; // Reset for next signal outage
857  result = currVF; // Set official video format to use
858  }
859  else
860  numConsecutiveFrames = (lastVF == currVF) ? numConsecutiveFrames + 1 : 0;
861  } // loop while input video format is unstable
862 
863  // At this point, the video format is stable and valid.
864 
865  // Grab input VPID info...
866  if (mDevice.GetVPIDValidA(sdiConnector))
867  { ULWord vpidDS1(0), vpidDS2(0);
868  mDevice.ReadSDIInVPID (sdiConnector, vpidDS1, vpidDS2);
869  mVPIDInfoDS1.SetVPID(vpidDS1);
870  mVPIDInfoDS2.SetVPID(vpidDS2);
871  }
872  if (mVPIDInfoDS1.IsValid())
873  { // DS1 VPID valid ---
874  CAPNOTE(::NTV2InputSourceToString(mConfig.fInputSource,true) << " DS1: " << mVPIDInfoDS1);
875  NTV2VideoFormat vfVPID (mVPIDInfoDS1.GetVideoFormat());
876  if (mVPIDInfoDS2.IsValid())
877  CAPNOTE(::NTV2InputSourceToString(mConfig.fInputSource,true) << " DS2: " << mVPIDInfoDS2);
878  if (vfVPID != result && !mSquares)
879  {
880  CAPWARN("VPID=" << ::NTV2VideoFormatToString(vfVPID) << " != " << ::NTV2VideoFormatToString(result));
881  result = vfVPID;
882  }
883  }
884 
885  ostringstream osserr;
886  if (!mDevice.features().CanDoVideoFormat(result)) // Can this device handle this video format?
887  osserr << mDevice.GetModelName() << " can't handle " << ::NTV2VideoFormatToString(result);
888  else if (mVPIDInfoDS1.IsValid() && mVPIDInfoDS1.IsStandardTwoSampleInterleave() && !mDevice.features().CanDo425Mux())
889  osserr << mDevice.GetModelName() << " can't handle TSI";
890  if (!osserr.str().empty())
891  {
892  CAPWARN(osserr.str());
893  result = NTV2_FORMAT_UNKNOWN;
894  mDevice.WaitForInputVerticalInterrupt(mConfig.fInputChannel, 30); // Wait 30 frames
895  continue; // Retry
896  }
897 
898  CAPNOTE(::NTV2InputSourceToString(mConfig.fInputSource,true) << " video format: " << ::NTV2VideoFormatToString(result));
899  cerr << endl << "## NOTE: " << ::NTV2InputSourceToString(mConfig.fInputSource,true)
900  << " video format is " << ::NTV2VideoFormatToString(result) << endl;
901  break; // Done!
902  } // loop
903 
904  // Using 'result' & possibly mVPIDInfoDS1 & mVPIDInfoDS2 --
905  // Does this format require another SDI wire? So we should check for another SDI input?
906  // For now, use just 1 framestore, 1 SDI input, 1 CSC...
907  mDevice.DisableChannels(mInputFrameStores);
908  mInputFrameStores.clear(); mInputFrameStores.insert(mConfig.fInputChannel);
909  mActiveSDIInputs.clear(); mActiveSDIInputs.insert(sdiConnector);
910  if (NTV2_IS_4K_VIDEO_FORMAT(result))
911  {
912  mInputFrameStores = ::NTV2MakeChannelSet(mConfig.fInputChannel,
913  mVPIDInfoDS1.IsValid() && mVPIDInfoDS1.IsStandardTwoSampleInterleave() ? 2 : 4);
914  mActiveSDIInputs = ::NTV2MakeChannelSet(sdiConnector, UWord(mInputFrameStores.size()));
915  }
916  mActiveCSCs = mActiveSDIInputs;
917  CAPDBG(::NTV2VideoFormatToString(result) << ": SDIs=" << ::NTV2ChannelSetToStr(mActiveSDIInputs)
918  << " FrameStores=" << ::NTV2ChannelSetToStr(mInputFrameStores)
919  << " CSCs=" << ::NTV2ChannelSetToStr(mActiveCSCs));
920  cerr << "WaitForStableInputSignal: " << ::NTV2VideoFormatToString(result) << ": SDIIns=" << ::NTV2ChannelSetToStr(mActiveSDIInputs)
921  << " FrameStores=" << ::NTV2ChannelSetToStr(mInputFrameStores)
922  << " CSCs=" << ::NTV2ChannelSetToStr(mActiveCSCs) << endl;
923  NTV2_ASSERT(result != NTV2_FORMAT_UNKNOWN);
924  return result;
925 } // WaitForStableInputSignal
926 
927 
929 
930 
932 {
933  mConfig.fUseVanc = !mConfig.fUseVanc;
934  cerr << endl << "## NOTE: VANC frame geometry " << (mConfig.fUseVanc ? "enabled" : "disabled") << endl;
935 }
936 
937 
939 {
940  OutputMode mode (mConfig.fOutputMode);
941  mode = OutputMode(mode+1);
942  if (!IS_VALID_OutputMode(mode))
944  if (mConfig.fOutputMode != mode)
945  cerr << endl << "## NOTE: Output changed to '" << CCGrabberConfig::OutputModeToString(mode) << "'" << endl;
946  mConfig.fOutputMode = mode;
947 }
948 
950 {
951  CaptionDataSrc src (mConfig.fCaptionSrc);
952  src = CaptionDataSrc(src+1);
953  if (!IS_VALID_CaptionDataSrc(src))
955  if (mConfig.fCaptionSrc != src)
956  cerr << endl << "## NOTE: CC source changed to '" << CCGrabberConfig::CaptionDataSrcToString(src) << "'" << endl;
957  mConfig.fCaptionSrc = src;
958 }
959 
961 {
962  NTV2PixelFormat pf (mConfig.fPixelFormat);
963  do
964  {
965  pf = NTV2PixelFormat(pf+1);
966  if (pf == NTV2_FBF_LAST)
967  pf = NTV2_FBF_FIRST;
968  } while (NTV2_IS_FBF_PLANAR(pf) || !mDevice.features().CanDoFrameBufferFormat(pf));
969  if (mConfig.fPixelFormat != pf)
970  cerr << endl << "## NOTE: Pixel format changed to " << ::NTV2FrameBufferFormatToString(pf) << endl;
971  mConfig.fPixelFormat = pf;
972 }
973 
974 void NTV2CCGrabber::ExtractClosedCaptionData (const uint32_t inFrameNum, const NTV2VideoFormat inVideoFormat)
975 {
976  AJAAncillaryList ancPackets, vancPackets;
977  CaptionData captionData708Anc, captionData708Vanc, captionData608Anc, captionData608Vanc, captionDataL21Anc, captionDataL21; // The 608 caption byte pairs (one pair per field)
978  const NTV2FormatDescriptor formatDesc (inVideoFormat, mConfig.fPixelFormat, mVancMode);
979 
980  if (NTV2_IS_VANCMODE_ON(mVancMode) || mDevice.features().CanDoCustomAnc()) // Gotta have at least VANC or AncExt
981  {
982  // Get all VANC packets...
983  if (NTV2_IS_VANCMODE_ON(mVancMode))
984  {
985  AJAAncillaryList::SetFromVANCData (mInputXferInfo.acVideoBuffer, formatDesc, vancPackets, inFrameNum);
986  vancPackets.ParseAllAncillaryData();
987  }
988 
989  // Get all anc extractor packets...
990  if (mDevice.features().CanDoCustomAnc())
991  {
992  const NTV2Buffer validAncF1 (mInputXferInfo.acANCBuffer.GetHostAddress(0), mInputXferInfo.GetCapturedAncByteCount(false));
993  const NTV2Buffer validAncF2 (mInputXferInfo.acANCField2Buffer.GetHostAddress(0), mInputXferInfo.GetCapturedAncByteCount(true));
994  AJAAncillaryList::SetFromDeviceAncBuffers (validAncF1, validAncF2, ancPackets, inFrameNum);
995  ancPackets.ParseAllAncillaryData();
996  }
997 
998  if (NTV2_IS_VANCMODE_ON(mVancMode))
999  { // Compare with what we got from VANC lines:
1000  NTV2StringList diffs;
1001  if (!ancPackets.CompareWithInfo (diffs, vancPackets, true/*ignoreLoc*/, false /*ignoreChksum*/))
1002  {
1003  NTV2StringList lines(aja::split(diffs.at(0), "\n")); // Only log first diff
1004  CAPDBG(DEC(diffs.size()) << " VANC/AncExt diff(s): " << lines.at(0));
1005  for (size_t n(1); n < lines.size(); n++)
1006  CAPDBG(lines.at(n));
1007  }
1008  }
1009  }
1010 
1011  // Get Line21 CC data...
1012  if (NTV2_IS_SD_VIDEO_FORMAT(inVideoFormat) && (mConfig.fPixelFormat == NTV2_FBF_8BIT_YCBCR || mConfig.fPixelFormat == NTV2_FBF_10BIT_YCBCR))
1013  { // Anything encoded in Line 21?
1014  ULWord line21RowOffset(0);
1015  const UByte * pLine21(AJA_NULL);
1016  formatDesc.GetLineOffsetFromSMPTELine (21, line21RowOffset);
1017  pLine21 = AsConstUBytePtr(formatDesc.GetRowAddress(mInputXferInfo.acVideoBuffer.GetHostPointer(),
1018  line21RowOffset));
1019  if (pLine21)
1020  {
1021  if (mConfig.fPixelFormat == NTV2_FBF_10BIT_YCBCR) // CNTV2Line21Captioner::DecodeLine requires 8-bit YUV
1022  ::ConvertLine_v210_to_2vuy(AsConstULWordPtr(pLine21), (UByte*)(pLine21), 720); // Convert YUV10 to YUV8 in-place
1023  captionDataL21.bGotField1Data = CNTV2Line21Captioner::DecodeLine(pLine21, captionDataL21.f1_char1, captionDataL21.f1_char2);
1024  }
1025  pLine21 = AsConstUBytePtr(formatDesc.GetRowAddress(mInputXferInfo.acVideoBuffer.GetHostPointer(),
1026  line21RowOffset+1)); // F2 should be on next row
1027  if (pLine21)
1028  {
1029  if (mConfig.fPixelFormat == NTV2_FBF_10BIT_YCBCR) // CNTV2Line21Captioner::DecodeLine requires 8-bit YUV
1030  ::ConvertLine_v210_to_2vuy(AsConstULWordPtr(pLine21), (UByte*)(pLine21), 720); // Convert YUV10 to YUV8 in-place
1031  captionDataL21.bGotField2Data = CNTV2Line21Captioner::DecodeLine(pLine21, captionDataL21.f2_char1, captionDataL21.f2_char2);
1032  }
1033  }
1034 
1035  // Any 608 packets (anc extractor)?
1036  if (ancPackets.GetAncillaryDataWithType(AJAAncDataType_Cea608_Vanc, 0)) // F1
1037  {
1039  if (pkt608F1.GetPayloadData() && pkt608F1.GetPayloadByteCount() && AJA_SUCCESS(pkt608F1.ParsePayloadData()))
1040  pkt608F1.GetCEA608Bytes (captionData608Anc.f1_char1, captionData608Anc.f1_char2, captionData608Anc.bGotField1Data);
1041  }
1042  if (ancPackets.GetAncillaryDataWithType(AJAAncDataType_Cea608_Vanc, 1)) // F2
1043  {
1045  if (pkt608F2.GetPayloadData() && pkt608F2.GetPayloadByteCount() && AJA_SUCCESS(pkt608F2.ParsePayloadData()))
1046  pkt608F2.GetCEA608Bytes(captionData608Anc.f2_char1, captionData608Anc.f2_char2, captionData608Anc.bGotField2Data);
1047  }
1048 
1049  // Any 608 packets (Vanc)?
1051  {
1053  if (pkt608F1.GetPayloadData() && pkt608F1.GetPayloadByteCount() && AJA_SUCCESS(pkt608F1.ParsePayloadData()))
1054  pkt608F1.GetCEA608Bytes (captionData608Vanc.f1_char1, captionData608Vanc.f1_char2, captionData608Vanc.bGotField1Data);
1055  }
1057  {
1059  if (pkt608F2.GetPayloadData() && pkt608F2.GetPayloadByteCount() && AJA_SUCCESS(pkt608F2.ParsePayloadData()))
1060  pkt608F2.GetCEA608Bytes(captionData608Vanc.f2_char1, captionData608Vanc.f2_char2, captionData608Vanc.bGotField2Data);
1061  }
1062 
1063  // Any 708 packets (vanc)?
1065  {
1066  AJAAncillaryData vancCEA708DataIn (vancPackets.GetAncillaryDataWithType(AJAAncDataType_Cea708));
1067  bool hasParityErrors (false);
1068  if (vancCEA708DataIn.GetPayloadData() && vancCEA708DataIn.GetPayloadByteCount() && AJA_SUCCESS(vancCEA708DataIn.ParsePayloadData()))
1069  if (m708DecoderVanc->SetSMPTE334AncData (vancCEA708DataIn.GetPayloadData(), vancCEA708DataIn.GetPayloadByteCount()))
1070  if (m708DecoderVanc->ParseSMPTE334AncPacket(hasParityErrors))
1071  {
1072  vector<UByte> svcBlk;
1073  size_t blkSize(0), byteCount(0);
1074  int svcNum(0);
1075  bool isExtendedSvc(false);
1076  if (!hasParityErrors)
1077  captionData708Vanc = m708DecoderVanc->GetCC608CaptionData();
1078  if (m708DecoderVanc->GetNextServiceBlockInfoFromQueue (NTV2_CC708PrimaryCaptionServiceNum, blkSize, byteCount, svcNum, isExtendedSvc))
1079  m708DecoderVanc->GetNextServiceBlockFromQueue(NTV2_CC708PrimaryCaptionServiceNum, svcBlk); // Pop queued service block
1080  }
1081  }
1082  // Any 708 packets (anc extractor)?
1084  {
1085  AJAAncillaryData ancCEA708DataIn (ancPackets.GetAncillaryDataWithType(AJAAncDataType_Cea708));
1086  bool hasParityErrors (false);
1087  if (ancCEA708DataIn.GetPayloadData() && ancCEA708DataIn.GetPayloadByteCount() && AJA_SUCCESS(ancCEA708DataIn.ParsePayloadData()))
1088  if (m708DecoderAnc->SetSMPTE334AncData (ancCEA708DataIn.GetPayloadData(), ancCEA708DataIn.GetPayloadByteCount()))
1089  if (m708DecoderAnc->ParseSMPTE334AncPacket(hasParityErrors))
1090  {
1091  vector<UByte> svcBlk;
1092  size_t blkSize(0), byteCount(0);
1093  int svcNum(0);
1094  bool isExtendedSvc(false);
1095  if (!hasParityErrors)
1096  captionData708Anc = m708DecoderAnc->GetCC608CaptionData();
1097  if (m708DecoderAnc->GetNextServiceBlockInfoFromQueue (NTV2_CC708PrimaryCaptionServiceNum, blkSize, byteCount, svcNum, isExtendedSvc))
1098  m708DecoderAnc->GetNextServiceBlockFromQueue(NTV2_CC708PrimaryCaptionServiceNum, svcBlk); // Pop queued service block
1099  }
1100  }
1101  // Any "analog" packets?
1103  {
1105  if (AJA_SUCCESS(ancEIA608DataIn.ParsePayloadData()))
1106  ancEIA608DataIn.GetCEA608Bytes(captionDataL21Anc.f1_char1, captionDataL21Anc.f1_char2, captionDataL21Anc.bGotField1Data);
1108  {
1110  if (AJA_SUCCESS(ancEIA608F2.ParsePayloadData()))
1111  ancEIA608F2.GetCEA608Bytes(captionDataL21Anc.f2_char1, captionDataL21Anc.f2_char2, captionDataL21Anc.bGotField2Data);
1112  }
1113  }
1114 
1115  // Compare CaptionData results...
1116  ostringstream ossCompare;
1117  const CaptionData * p608CaptionData(AJA_NULL);
1118  if (NTV2_IS_SD_VIDEO_FORMAT(inVideoFormat))
1119  {
1120  const CaptionData * pL21CaptionData (AJA_NULL);
1121  if (captionDataL21.HasData() && captionDataL21Anc.HasData())
1122  if (captionDataL21 != captionDataL21Anc)
1123  ossCompare << "L21Vanc != L21Anlg: " << captionDataL21 << " " << captionDataL21Anc << endl;
1124  if (captionDataL21.HasData())
1125  pL21CaptionData = &captionDataL21;
1126  else if (captionDataL21Anc.HasData())
1127  pL21CaptionData = &captionDataL21Anc;
1128  if (captionData608Anc.HasData() && pL21CaptionData)
1129  if (captionData608Anc != *pL21CaptionData)
1130  ossCompare << "608 != L21: " << captionData608Anc << " " << *pL21CaptionData << endl;
1131  if (captionData608Anc.HasData())
1132  p608CaptionData = &captionData608Anc; // 608 anc has precedence
1133  else if (pL21CaptionData)
1134  p608CaptionData = pL21CaptionData; // followed by line 21
1135  }
1136  else
1137  {
1138  if (captionData608Anc.HasData() && captionData708Anc.HasData())
1139  if (captionData608Anc != captionData708Anc)
1140  ossCompare << "608anc != 708anc: " << captionData608Anc << " " << captionData708Anc << endl;
1141  if (captionData608Vanc.HasData() && captionData708Vanc.HasData())
1142  if (captionData608Vanc != captionData708Vanc)
1143  ossCompare << "608vanc != 708vanc: " << captionData608Vanc << " " << captionData708Vanc << endl;
1144  if (captionData708Anc.HasData())
1145  p608CaptionData = &captionData708Anc; // 608-in-708anc has highest precedence
1146  else if (captionData708Vanc.HasData())
1147  p608CaptionData = &captionData708Vanc; // followed by 608-in-708vanc
1148  else if (captionData608Anc.HasData())
1149  p608CaptionData = &captionData608Anc; // followed by 608anc
1150  else if (captionData608Vanc.HasData())
1151  p608CaptionData = &captionData608Vanc; // followed by 608vanc
1152  }
1153  if (!ossCompare.str().empty())
1154  CAPDBG("CaptionData mis-compare(s): " << ossCompare.str());
1155 
1156  // Set p608CaptionData based on mConfig.fCaptionSrc...
1157  switch (mConfig.fCaptionSrc)
1158  { // captionData708Anc, captionData708Vanc, captionData608Anc, captionData608Vanc, captionDataL21Anc, captionDataL21
1159  case kCaptionDataSrc_Line21: p608CaptionData = &captionDataL21Anc; break;
1160  case kCaptionDataSrc_608FBVanc: p608CaptionData = &captionDataL21; break;
1161  case kCaptionDataSrc_708FBVanc: p608CaptionData = &captionData708Vanc; break;
1162  case kCaptionDataSrc_608Anc: p608CaptionData = &captionData608Anc; break;
1163  case kCaptionDataSrc_708Anc: p608CaptionData = &captionData708Anc; break;
1164  default: break;
1165  }
1166 
1167  if (!p608CaptionData)
1168  return; // Got nothing
1169 
1170  // This demo only handles CEA-608 captions (no Teletext, IBU, etc.)
1171  // The 608 decoder expects to be called once per frame (to implement flashing characters, smooth-scroll roll-up, etc.).
1172  // Pass the caption byte pairs to it for processing (even if captionData.HasData returns false)...
1173  m608Decoder->ProcessNew608FrameData(*p608CaptionData);
1174 
1175  DoCCOutput(inFrameNum, *p608CaptionData, inVideoFormat);
1176 
1177 } // ExtractClosedCaptionData
1178 
1179 
1180 void NTV2CCGrabber::DoCCOutput (const uint32_t inFrameNum, const CaptionData & inCCData, const NTV2VideoFormat inVideoFormat)
1181 {
1182  // Print out the caption characters...
1183  const bool isFirstTime (mLastOutFrame == 0 && inFrameNum > mLastOutFrame);
1184  char char1(0), char2(0);
1185  const bool showField2 (IsField2Line21CaptionChannel(m608Channel));
1186  const bool gotData (showField2 ? inCCData.bGotField2Data : inCCData.bGotField1Data);
1187  switch (mConfig.fOutputMode)
1188  {
1190  if (gotData)
1191  { // Can't distinguish between CC1/CC2/Tx1/Tx2 for F1 (nor CC3/CC4/Tx3/Tx4 for F2).
1192  // They'll just have to be interspersed for now...
1193  char1 = (char(showField2 ? inCCData.f2_char1 : inCCData.f1_char1) & 0x7F);
1194  char2 = (char(showField2 ? inCCData.f2_char2 : inCCData.f1_char2) & 0x7F);
1195  if (char1 >= ' ' && char1 <= '~')
1196  {
1197  if (mLastOutStr != " " || char1 != ' ')
1198  {cout << char1 << flush; mLastOutStr = string(1,char1);}
1199  if (char2 >= ' ' && char2 <= '~')
1200  {
1201  if (mLastOutStr != " " || char2 != ' ')
1202  {cout << char2 << flush; mLastOutStr = string(1,char2);}
1203  }
1204  }
1205  else if (mLastOutStr != " ")
1206  {cout << " " << flush; mLastOutStr = " ";}
1207  }
1208  break;
1210  {
1211  if (inFrameNum == (mLastOutFrame+1))
1212  {
1213  mLastOutFrame = inFrameNum;
1214  if ((mLastOutFrame - mFirstOutFrame) < MAX_ACCUM_FRAME_COUNT)
1215  break; // Don't spew yet -- keep going
1216  }
1217  const string currentScreen(m608Decoder->GetOnAirCharacters());
1218  if (currentScreen != mLastOutStr)
1219  cout << currentScreen << endl;
1220  mLastOutStr = currentScreen;
1221  mFirstOutFrame = mLastOutFrame = inFrameNum;
1222  break;
1223  }
1225  {
1226  uint16_t u16(uint16_t(uint16_t(showField2 ? inCCData.f2_char1 : inCCData.f1_char1) << 8) | uint16_t(showField2 ? inCCData.f2_char2 : inCCData.f1_char2));
1227  ostringstream oss;
1228  oss << Hex0N(u16,4);
1229  mLastOutStr.append(mLastOutStr.empty() ? "\t" : " ");
1230  mLastOutStr.append(oss.str());
1231  if (inFrameNum == (mLastOutFrame+1))
1232  { // Save for later
1233  mLastOutFrame = inFrameNum;
1234  if ((mLastOutFrame - mFirstOutFrame) < MAX_ACCUM_FRAME_COUNT)
1235  break; // Don't spew yet -- keep going
1236  }
1237  if (isFirstTime)
1238  cout << "Scenarist_SCC V1.0" << endl;
1239 
1240  string tcStr;
1241  AJATimeCode tcFirst(mFirstOutFrame);
1243  tcFirst.QueryString(tcStr, tcBase, false);
1244  cout << endl << tcStr << ":" << mLastOutStr << endl;
1245  mFirstOutFrame = mLastOutFrame = inFrameNum;
1246  mLastOutStr.clear();
1247  break;
1248  }
1249  case kOutputMode_Stats:
1250  if (inFrameNum % 60 == 0) // Every 60 frames
1251  {
1252  CNTV2CaptionDecodeChannel608Ptr chDecoder (m608Decoder->Get608ChannelDecoder(m608Decoder->GetDisplayChannel()));
1253  if (chDecoder)
1254  {
1255  const vector<uint32_t> stats (chDecoder->GetStats());
1256  AJALabelValuePairs info;
1258  for (size_t num(0); num < stats.size(); num++)
1259  {
1261  if (title.empty())
1262  break;
1263  if (!stats[num])
1264  continue;
1265  ostringstream oss; oss << DEC(stats[num]);
1266  AJASystemInfo::append(info, title, oss.str());
1267  }
1268  cout << AJASystemInfo::ToString(info) << endl;
1269  }
1270  }
1271  break;
1272  default: break;
1273  }
1274 } // DoCCOutput
1275 
1276 
1278 
1279 
1280 static const UWord gMixerNums [] = {0, 0, 1, 1, 2, 2, 3, 3};
1281 
1282 
1284 {
1285  NTV2_ASSERT (mConfig.fBurnCaptions); // Must be burning captions
1286 
1287  // Configure the output FrameStore...
1288  mDevice.EnableChannel (mOutputChannel);
1289  mDevice.SetMode (mOutputChannel, NTV2_MODE_DISPLAY);
1290  mDevice.SetFrameBufferFormat (mOutputChannel, mPlayoutFBF);
1291  mDevice.SetVideoFormat (inVideoFormat, /*retailMode?*/false, /*keepVANC?*/false, /*channel*/mOutputChannel);
1292  mDevice.SetEnableVANCData(NTV2_IS_VANCMODE_TALL(mVancMode), NTV2_IS_VANCMODE_TALLER(mVancMode), mOutputChannel);
1293 
1294  // RGB: Set up mixer to "mix" mode, FG raster "unshaped", BG raster "full raster" and VANC pass-thru from BG...
1295  const UWord mixerNumber (gMixerNums[mOutputChannel]);
1296  mDevice.SetMixerMode (mixerNumber, NTV2MIXERMODE_FOREGROUND_ON);
1299  mDevice.SetMixerVancOutputFromForeground (mixerNumber, false); // false means "use BG VANC, not FG"
1300  cerr << "## NOTE: Caption burn-in using mixer/keyer " << (mixerNumber+1) << " on " << ::NTV2ChannelToString(mOutputChannel)
1301  << ", " << ::NTV2FrameBufferFormatToString(mPlayoutFBF)
1302  << ", " << ::NTV2VideoFormatToString(inVideoFormat) << endl;
1303 
1304  return AJA_STATUS_SUCCESS;
1305 
1306 } // SetupOutputVideo
1307 
1308 
1310 {
1311  NTV2_ASSERT (mConfig.fBurnCaptions); // Must be burning captions
1312  const NTV2OutputCrosspointID frameStoreOutputRGB (::GetFrameStoreOutputXptFromChannel (mOutputChannel, true)); // true=RGB
1313  const NTV2OutputCrosspointID cscOutputYUV (::GetCSCOutputXptFromChannel (mOutputChannel));
1314  const NTV2OutputCrosspointID cscOutputKey (::GetCSCOutputXptFromChannel (mOutputChannel, true)); // true=key
1315  const NTV2OutputCrosspointID mixerOutputYUV (::GetMixerOutputXptFromChannel (mOutputChannel));
1317  const NTV2Standard outputStandard (::GetNTV2StandardFromVideoFormat (inVideoFormat));
1318  const bool canVerify (mDevice.features().HasCrosspointConnectROM());
1319  UWord connectFailures (0);
1320 
1321  if (mConfig.fDoMultiFormat)
1322  {
1323  // Multiformat --- route the one SDI output to the mixer's YUV output, and set its output standard...
1324  if (mDevice.features().HasBiDirectionalSDI())
1325  mDevice.SetSDITransmitEnable (mOutputChannel, true);
1326  if (mDevice.features().CanDoWidget(g12GSDIOutputs[mOutputChannel])
1327  || mDevice.features().CanDoWidget(g3GSDIOutputs[mOutputChannel])
1328  || mDevice.features().CanDoWidget(gSDIOutputs[mOutputChannel]))
1329  {
1330  if (!mDevice.Connect (::GetSDIOutputInputXpt(mOutputChannel), mixerOutputYUV, canVerify)) connectFailures++;
1331  mDevice.SetSDIOutputStandard (mOutputChannel, outputStandard);
1332  }
1333  }
1334  else
1335  {
1336  // If not multiformat: Route all SDI outputs to the mixer's YUV output...
1337  const ULWord numVideoOutputs (mDevice.features().GetNumVideoOutputs());
1338  const NTV2Channel startNum (NTV2_CHANNEL1);
1339  const NTV2Channel endNum (NTV2_CHANNEL_INVALID);
1340  const NTV2Channel sdiInputAsChan (::NTV2InputSourceToChannel(mConfig.fInputSource));
1341 
1342  for (NTV2Channel chan(startNum); chan < endNum; chan = NTV2Channel(chan + 1))
1343  {
1344  if (ULWord(chan) >= numVideoOutputs)
1345  break;
1346  if (mDevice.features().HasBiDirectionalSDI())
1347  {
1348  if (chan == sdiInputAsChan)
1349  continue; // Skip the input
1350  mDevice.SetSDITransmitEnable (chan, true);
1351  }
1352  if (mDevice.features().CanDoWidget(g12GSDIOutputs[chan])
1353  || mDevice.features().CanDoWidget(g3GSDIOutputs[chan])
1354  || mDevice.features().CanDoWidget(gSDIOutputs[chan]))
1355  {
1356  if (!mDevice.Connect (::GetSDIOutputInputXpt(chan), mixerOutputYUV, canVerify)) connectFailures++;
1357  mDevice.SetSDIOutputStandard (chan, outputStandard);
1358  }
1359  } // for each output spigot
1360  }
1361 
1362  // Connect CSC video input to frame buffer's RGB output:
1363  if (!mDevice.Connect (::GetCSCInputXptFromChannel(mOutputChannel), frameStoreOutputRGB, canVerify)) connectFailures++;
1364  // Connect mixer's foreground video input to the CSC's YUV video output:
1365  if (!mDevice.Connect (::GetMixerFGInputXpt(mOutputChannel), cscOutputYUV, canVerify)) connectFailures++;
1366  // Connect mixer's foreground key input to the CSC's YUV key output:
1367  if (!mDevice.Connect (::GetMixerFGInputXpt(mOutputChannel, true), cscOutputKey, canVerify)) connectFailures++;
1368  // Connect mixer's background video input to the SDI input:
1369  if (!mDevice.Connect (::GetMixerBGInputXpt(mOutputChannel), signalInput, canVerify)) connectFailures++;
1370 
1371  if (!mConfig.fDoMultiFormat)
1372  {
1373  // Connect more outputs -- HDMI, analog, SDI monitor, etc... (Don't bother to verify these connections)
1374  if (mDevice.features().CanDoWidget(NTV2_WgtHDMIOut1))
1375  mDevice.Connect (NTV2_XptHDMIOutInput, mixerOutputYUV);
1376  if (mDevice.features().CanDoWidget(NTV2_WgtHDMIOut1v2))
1377  mDevice.Connect (NTV2_XptHDMIOutQ1Input, mixerOutputYUV);
1378  if (mDevice.features().CanDoWidget(NTV2_WgtAnalogOut1))
1379  mDevice.Connect (NTV2_XptAnalogOutInput, mixerOutputYUV);
1380  if (mDevice.features().CanDoWidget(NTV2_WgtSDIMonOut1))
1381  mDevice.Connect (::GetSDIOutputInputXpt (NTV2_CHANNEL5), mixerOutputYUV);
1382  }
1383  return connectFailures == 0;
1384 
1385 } // RouteOutputSignal
1386 
1387 
1388 // Starts the play thread
1390 {
1391  // Create and start the playout thread...
1392  NTV2_ASSERT(mConfig.fBurnCaptions);
1393  AJAStatus result (mPlayoutThread.Attach(PlayThreadStatic, this));
1394  if (AJA_SUCCESS(result))
1395  result = mPlayoutThread.SetPriority(AJA_ThreadPriority_High);
1396  if (AJA_SUCCESS(result))
1397  result = mPlayoutThread.Start();
1398  return result;
1399 
1400 } // StartPlayThread
1401 
1402 
1403 // The playout thread function
1404 void NTV2CCGrabber::PlayThreadStatic (AJAThread * pThread, void * pContext) // static
1405 {
1406  (void) pThread;
1407  // Grab the NTV2Burn instance pointer from the pContext parameter,
1408  // then call its PlayFrames method...
1409  NTV2CCGrabber * pApp (reinterpret_cast <NTV2CCGrabber *> (pContext));
1410  pApp->PlayFrames ();
1411 
1412 } // PlayThreadStatic
1413 
1414 
1416 {
1417  const NTV2VideoFormat videoFormat (mDevice.GetInputVideoFormat(mConfig.fInputSource));
1419  ULWord fbNum (10); // Bounce between frames 10 & 11
1420  const string indicators [] = {"/", "-", "\\", "|", ""};
1421  AUTOCIRCULATE_STATUS acStatus;
1422 
1423  CAPNOTE("Thread started");
1424  SetupOutputVideo (videoFormat); // Set up device output
1425  RouteOutputSignal (videoFormat); // Set up output signal routing
1426  mDevice.GetVANCMode (vancMode, mConfig.fInputChannel);
1427  if (mDevice.AutoCirculateInitForOutput (mOutputChannel, 2) && mDevice.AutoCirculateGetStatus (mOutputChannel, acStatus)) // Find out which buffers we got
1428  fbNum = ULWord(acStatus.acStartFrame); // Use them
1429  else if (mDevice.AutoCirculateGetStatus(mConfig.fInputChannel, acStatus)) // Use the frame just past the last input A/C frame
1430  fbNum = ULWord(acStatus.GetEndFrame()) + 1;
1431 
1432  const NTV2FormatDesc formatDesc (videoFormat, mPlayoutFBF, vancMode);
1433  const uint32_t bufferSizeBytes (formatDesc.GetTotalRasterBytes ());
1434  const uint32_t activeSizeBytes (formatDesc.GetVisibleRasterBytes ());
1435  ULWord pingPong (0); // Bounce between 0 and 1
1436  UWord consecSyncErrs (0);
1437  // Caption status head-up-display...
1438  static uint64_t frameTally (0);
1439  const string strVideoFormat (CNTV2DemoCommon::StripFormatString (::NTV2VideoFormatToString (videoFormat)));
1440  ULWord lastErrorTally (0);
1441 
1442  // Allocate host frame buffer for blitting captions into...
1443  NTV2Buffer hostBuffer;
1444  if (!hostBuffer.Allocate(bufferSizeBytes, /*pageAligned*/true))
1445  {cerr << "## NOTE: Caption burn-in failed -- unable to allocate " << bufferSizeBytes << "-byte caption video buffer" << endl; return;}
1446  NTV2Buffer visibleRgn (formatDesc.GetTopVisibleRowAddress(AsUBytePtr(hostBuffer.GetHostPointer())),activeSizeBytes);
1447 
1448  // Clear both device ping/pong buffers to fully transparent, all black...
1449  hostBuffer.Fill(ULWord(0));
1450  mDevice.DMAWriteFrame (fbNum + 0, AsULWordPtr(hostBuffer.GetHostPointer()), bufferSizeBytes);
1451  mDevice.DMAWriteFrame (fbNum + 1, AsULWordPtr(hostBuffer.GetHostPointer()), bufferSizeBytes);
1452  mDevice.SetOutputFrame (mOutputChannel, fbNum + pingPong);
1453  pingPong = pingPong ? 0 : 1;
1454 
1455  // Do forever (until Quit)...
1456  while (!mGlobalQuit)
1457  {
1458  // Wait for the next frame to become ready to "consume"...
1459  NTV2FrameData * pFrameData(mCircularBuffer.StartConsumeNextBuffer());
1460  if (pFrameData)
1461  {
1462  // "Burn" captions into the host buffer before it gets sent to the AJA device...
1463  m608Decoder->BurnCaptions (hostBuffer, formatDesc);
1464  m608Decoder->IdleFrame(); // This is needed for captions that flash/blink
1465 
1466  if (mHeadUpDisplayOn)
1467  {
1468  ostringstream oss;
1469  const string strCaptionChan (::NTV2Line21ChannelToStr(NTV2_IS_HD_VIDEO_FORMAT(videoFormat)
1470  ? m708DecoderAnc->GetDisplayChannel()
1471  : m608Decoder->GetDisplayChannel()));
1472  oss << indicators [mCaptionDataTally % 4] << " " << strCaptionChan << " " << frameTally++ << " "
1473  << formatDesc.GetRasterWidth() << "x" << formatDesc.GetFullRasterHeight() << (mConfig.fUseVanc ? "v" : " ") << strVideoFormat;
1474 
1475  const ULWord newErrorTally (mErrorTally);
1476  const NTV2Line21Attributes & color (lastErrorTally != newErrorTally ? kRedOnTransparentBG : kGreenOnTransparentBG);
1477  CNTV2CaptionRenderer::BurnString (oss.str(), color, hostBuffer, formatDesc, 7, 1);
1478  lastErrorTally = newErrorTally;
1479 
1480  if (!pFrameData->fTimecodes.empty())
1481  {
1482  const NTV2_RP188 & tc (pFrameData->fTimecodes.begin()->second);
1483  if (tc.IsValid() && tc.fDBB & BIT(16)) // Bit 16 will be set if this frame had timecode
1484  {
1485  CRP188 rp188(tc);
1486  CNTV2CaptionRenderer::BurnString (rp188.GetRP188CString(), kGreenOnTransparentBG, hostBuffer, formatDesc, 8, 1);
1487  }
1488  }
1489  }
1490 
1491  // Transfer the caption raster to the device, then ping-pong it into the mixer foreground...
1492  mDevice.DMAWriteFrame (fbNum + pingPong, AsULWordPtr(visibleRgn.GetHostPointer()), activeSizeBytes);
1493  mDevice.SetOutputFrame (mOutputChannel, fbNum + pingPong); // Toggle device frame buffer
1494  pingPong = pingPong ? 0 : 1; // Switch device frame numbers for next time
1495  visibleRgn.Fill(ULWord(0)); // Clear visible region of host buffer to fully-transparent, all-black again
1496 
1497  // Signal that the frame has been "consumed"...
1498  mCircularBuffer.EndConsumeNextBuffer ();
1499 
1500  // Check for format change...
1501  if (videoFormat != mDevice.GetInputVideoFormat(mConfig.fInputSource))
1502  {
1503  cerr << "## NOTE: Caption burn-in stopped due to video format change -- was " << strVideoFormat
1504  << ", now " << ::NTV2VideoFormatToString (mDevice.GetInputVideoFormat(mConfig.fInputSource)) << endl;
1505  m608Decoder->Reset(); // Don't leave captions from old video stream on-screen
1506  m708DecoderAnc->Reset();
1507  m708DecoderVanc->Reset();
1508  break;
1509  }
1510 
1511  // Check mixer sync...
1512  bool mixerSyncOK (false);
1513  mDevice.GetMixerSyncStatus (gMixerNums[mOutputChannel], mixerSyncOK);
1514  if (mixerSyncOK)
1515  consecSyncErrs = 0;
1516  else if (++consecSyncErrs > 60) // Bail if lack of mixer sync for longer than ~1 sec
1517  {cerr << "#MXSYNC#"; consecSyncErrs = 0;} // break;}
1518  } // if pPlayData
1519  } // loop til quit signaled
1520 
1521  if (mDevice.AutoCirculateGetStatus (mOutputChannel, acStatus) && !acStatus.IsStopped())
1522  mDevice.AutoCirculateStop(mOutputChannel);
1523  CAPNOTE("Thread completed, will exit");
1524 
1525 } // PlayFrames
1526 
1527 
1529 {
1530  if (m608Channel != inNewChannel)
1531  {
1532  m608Channel = inNewChannel;
1533  if (m608Decoder)
1534  m608Decoder->SetDisplayChannel(m608Channel);
1535  if (m708DecoderAnc)
1536  m708DecoderAnc->SetDisplayChannel(m608Channel);
1537  if (m708DecoderVanc)
1538  m708DecoderVanc->SetDisplayChannel(m608Channel);
1539  cerr << endl << "## NOTE: Caption display channel changed to '" << ::NTV2Line21ChannelToStr(m608Channel) << "'" << endl;
1540  }
1541 }
1542 
1543 
1545 { (void) inChangeInfo;
1546  mCaptionDataTally++;
1547 }
1548 
1549 
1550 void NTV2CCGrabber::Caption608ChangedStatic (void * pInstance, const NTV2Caption608ChangeInfo & inChangeInfo) // STATIC
1551 {
1552  NTV2CCGrabber * pGrabber(reinterpret_cast<NTV2CCGrabber*>(pInstance));
1553  if (pGrabber)
1554  pGrabber->CaptioningChanged(inChangeInfo);
1555 }
1556 
1557 
1558 string NTV2CCGrabber::GetLine21ChannelNames (string inDelimiterStr) // static
1559 {
1560  string result;
1561  for (unsigned enumVal(0); enumVal < NTV2_CC608_ChannelMax; )
1562  {
1563  result += ::NTV2Line21ChannelToStr (NTV2Line21Channel(enumVal++));
1564  if (enumVal < NTV2_CC608_ChannelMax)
1565  result += inDelimiterStr;
1566  else
1567  break;
1568  }
1569  return result;
1570 
1571 } // GetLine21ChannelNames
1572 
1573 AJALabelValuePairs CCGrabberConfig::Get (const bool inCompact) const
1574 {
1575  AJALabelValuePairs result (CaptureConfig::Get(inCompact));
1576  AJASystemInfo::append(result, "Output Mode", IS_VALID_OutputMode(fOutputMode) ? OutputModeToString(fOutputMode) : "(invalid)");
1578  AJASystemInfo::append(result, "Timecode Source", ::NTV2TCIndexToString(fTimecodeSource, inCompact));
1579  AJASystemInfo::append(result, "Caption Channel", ::NTV2Line21ChannelToStr(fCaptionChannel, inCompact));
1580  AJASystemInfo::append(result, "Burn-In Captions", fBurnCaptions ? "Y" : "N");
1581  AJASystemInfo::append(result, "MultiFormat Mode", fDoMultiFormat ? "Y" : "N");
1582  AJASystemInfo::append(result, "Use Vanc", fUseVanc ? "Y" : "N");
1583  return result;
1584 }
1585 
1586 
1588 {
1589  string result;
1591  {
1592  result += OutputModeToString(mode);
1593  mode = OutputMode(mode+1);
1594  if (mode < kOutputMode_INVALID)
1595  result += ",";
1596  }
1597  return result;
1598 }
1599 
1601 {
1602  static const string gModeStrs[] = {"stream","screen","scc","mcc","stats",""};
1603  if (IS_VALID_OutputMode(inMode))
1604  return gModeStrs[inMode];
1605  string result;
1606  for (unsigned ndx(0); ndx < 5; )
1607  {
1608  result += gModeStrs[ndx];
1609  if (!(gModeStrs[++ndx].empty()))
1610  result += "|";
1611  }
1612  return result;
1613 }
1614 
1616 {
1617  typedef pair<string,OutputMode> StringToOutputModePair;
1618  typedef map<string,OutputMode> StringToOutputModeMap;
1619  typedef StringToOutputModeMap::const_iterator StringToOutputModeConstIter;
1620  static StringToOutputModeMap sStringToOutputModeMap;
1621  static AJALock sStringToOutputModeMapLock;
1622  if (sStringToOutputModeMap.empty())
1623  {
1624  AJAAutoLock autoLock(&sStringToOutputModeMapLock);
1626  {
1627  string outputModeStr (OutputModeToString(om));
1628  aja::lower(outputModeStr);
1629  sStringToOutputModeMap.insert(StringToOutputModePair(outputModeStr,om));
1630  }
1631  }
1632  string modeStr(inModeStr);
1633  aja::lower(aja::strip(modeStr));
1634  StringToOutputModeConstIter iter(sStringToOutputModeMap.find(modeStr));
1635  return iter != sStringToOutputModeMap.end() ? iter->second : kOutputMode_INVALID;
1636 }
1637 
1639 {
1640  string result;
1642  {
1643  result += CaptionDataSrcToString(src);
1644  src = CaptionDataSrc(src+1);
1645  if (src < kCaptionDataSrc_INVALID)
1646  result += ",";
1647  }
1648  return result;
1649 }
1650 
1652 {
1653  static const string gSrcStrs[] = {"default","line21","608vanc","708vanc","608anc","708anc",""};
1654  if (IS_VALID_CaptionDataSrc(inDataSrc))
1655  return gSrcStrs[inDataSrc];
1656  string result;
1657  for (unsigned ndx(0); ndx < 6; )
1658  {
1659  result += gSrcStrs[ndx];
1660  if (!gSrcStrs[++ndx].empty())
1661  result += "|";
1662  }
1663  return result;
1664 }
1665 
1667 {
1668  typedef pair<string,CaptionDataSrc> StringToCaptionDataSrcPair;
1669  typedef map<string,CaptionDataSrc> StringToCaptionDataSrcMap;
1670  typedef StringToCaptionDataSrcMap::const_iterator StringToCaptionDataSrcConstIter;
1671  static StringToCaptionDataSrcMap sStringToCaptionDataSrcMap;
1672  static AJALock sStringToCaptionDataSrcMapLock;
1673  if (sStringToCaptionDataSrcMap.empty())
1674  {
1675  AJAAutoLock autoLock(&sStringToCaptionDataSrcMapLock);
1677  {
1678  string captionDataSrcStr (CaptionDataSrcToString(cds));
1679  aja::lower(captionDataSrcStr);
1680  sStringToCaptionDataSrcMap.insert(StringToCaptionDataSrcPair(captionDataSrcStr,cds));
1681  }
1682  }
1683  string cdsStr(inDataSrcStr);
1684  aja::lower(aja::strip(cdsStr));
1685  StringToCaptionDataSrcConstIter iter(sStringToCaptionDataSrcMap.find(cdsStr));
1686  return iter != sStringToCaptionDataSrcMap.end() ? iter->second : kCaptionDataSrc_INVALID;
1687 }
1688 
1689 
1690 std::ostream & operator << (std::ostream & ioStrm, const CCGrabberConfig & inObj)
1691 {
1692  ioStrm << AJASystemInfo::ToString(inObj.Get());
1693  return ioStrm;
1694 }
NTV2Channel NTV2InputSourceToChannel(const NTV2InputSource inInputSource)
Converts a given NTV2InputSource to its equivalent NTV2Channel value.
Definition: ntv2utils.cpp:5047
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:744
#define NTV2_IS_VANCMODE_TALLER(__v__)
Definition: ntv2enums.h:3807
Passes only foreground video + key to the Mixer output.
Definition: ntv2enums.h:1793
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.
UByte f2_char1
Caption Byte 1 of Field 2.
virtual bool UnsubscribeChangeNotification(NTV2Caption608Changed *pInCallback, void *pInUserData=0)
Unsubscribes a prior change notification subscription.
virtual bool GetSDITransmitEnable(const NTV2Channel inChannel, bool &outEnabled)
Answers whether or not the specified SDI connector is currently acting as a transmitter (i...
virtual bool SetSMPTE334AncData(const AJAAncillaryData_Cea708 &inPacket)
Copies the given SMPTE 334 CDP data from the given ancillary data packet into my private CDP buffer...
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:300
Declares the AJAMemory class.
virtual bool RouteOutputSignal(const NTV2VideoFormat inVideoFormat)
This class is used to respond to dynamic events that occur during CEA-608 caption decoding...
UByte f1_char2
Caption Byte 2 of Field 1.
static const NTV2WidgetID g3GSDIOutputs[]
CaptionDataSrc fCaptionSrc
Caption data source (Line21? 608 VANC? 608 Anc? etc)
Definition: ntv2ccgrabber.h:66
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 HasData(void) const
bool Is8BitFrameBufferFormat(const NTV2FrameBufferFormat fbFormat)
Definition: ntv2utils.cpp:5452
This identifies the invalid (unspecified, uninitialized) VANC mode.
Definition: ntv2enums.h:3802
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:219
virtual bool SetMixerMode(const UWord inWhichMixer, const NTV2MixerKeyerMode inMode)
Sets the mode for the given mixer/keyer.
#define BIT(_x_)
Definition: ajatypes.h:578
#define IsField2Line21CaptionChannel(_chan_)
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:222
bool fDoMultiFormat
If true, use multi-format/multi-channel mode, if device supports it; otherwise normal mode...
#define AsULWordPtr(__p__)
UByte f1_char1
Caption Byte 1 of Field 1.
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:70
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:267
#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:4877
NTV2InputSource NTV2ChannelToInputSource(const NTV2Channel inChannel, const NTV2IOKinds inKinds=NTV2_IOKINDS_SDI)
Definition: ntv2utils.cpp:5132
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.
UByte f2_char2
Caption Byte 2 of Field 2.
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:783
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)
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:2007
bool fBurnCaptions
If true, burn-in captions on 2nd channel.
Definition: ntv2ccgrabber.h:69
const char * GetRP188CString() const
Definition: ntv2rp188.cpp:924
virtual CaptionData GetCC608CaptionData(void)
Pops the next CC608 data.
I am a reference-counted pointer template class. I am intended to be a proxy for an underlying object...
Definition: ajarefptr.h:89
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:205
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:62
#define NTV2_IS_HFR_STANDARD(__s__)
Definition: ntv2enums.h:213
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...
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:223
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:2031
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:1357
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 ...
Unknown or invalid caption mode.
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:476
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:260
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...
#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:485
std::string NTV2InputSourceToString(const NTV2InputSource inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:7377
virtual AJAStatus SetupAudio(void)
Sets up audio for capture (and playout, if burning captions).
static bool Create(CNTV2CaptionDecoder708Ptr &outDecoder)
Creates a new CNTV2CaptionEncoder708 instance.
static std::string GetStatTitle(const CaptionDecode608Stats inStat)
virtual CNTV2CaptionDecodeChannel608Ptr Get608ChannelDecoder(const NTV2Line21Channel inChannel) const
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:165
0: Disabled (never recommended): device configured exclusively by client application(s).
Playout (output) mode, which reads from device SDRAM.
Definition: ntv2enums.h:1241
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.
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...
enum _CaptionDecode608Stats CaptionDecode608Stats
The currently supported caption decoder stats.
virtual AJAStatus Init(void)
Initializes me and prepares me to Run.
virtual void Reset(void)
Flushes me, clearing all in-progress data.
Invalid or "not found".
Definition: ntv2enums.h:98
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...
bool bGotField2Data
True if Field 2 bytes have been set; otherwise false.
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:1454
static bool BurnString(const std::string &inString, const NTV2Line21Attrs &inAttribs, NTV2Buffer &inFB, const NTV2FormatDesc &inFBDescriptor, const UWord inRowNum=15, const UWord inColumnNum=1)
Blits the contents of the given UTF-8 encoded string into the given host buffer using the given displ...
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 ...
CEA-608 Character Attributes.
Utility class for timecodes.
Definition: timecode.h:28
ULWord GetProcessedFrameCount(void) const
#define NTV2_IS_HD_VIDEO_FORMAT(__f__)
Definition: ntv2enums.h:737
#define AJA_NULL
Definition: ajatypes.h:167
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...
virtual NTV2Line21Channel GetDisplayChannel(void) const
Answers with the caption channel that I&#39;m currently focused on (or that I&#39;m currently "burning" into ...
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.
static bool Create(CNTV2CaptionDecoder608Ptr &outEncoder)
Creates a new CNTV2CaptionEncoder608 instance.
virtual bool SubscribeChangeNotification(NTV2Caption608Changed *pInCallback, void *pInUserData=0)
Subscribes to change notifications.
NTV2InputXptID GetCSCInputXptFromChannel(const NTV2Channel inCSC, const bool inIsKeyInput=false)
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:42
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:68
virtual bool SetDisplayChannel(const NTV2Line21Channel inChannel)
Changes the caption channel that I&#39;m focused on (or that I&#39;m currently "burning" into video)...
bool bGotField1Data
True if Field 1 bytes have been set; otherwise false.
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)
std::vector< std::string > NTV2StringList
Definition: ntv2utils.h:1155
virtual void IdleFrame(void)
Call this once per video frame when I&#39;m doing display "burn-in", whether there is new caption data to...
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:6746
See 8-Bit ARGB, RGBA, ABGR Formats.
Definition: ntv2enums.h:224
Embeds silence (zeroes) into the data stream.
Definition: ntv2enums.h:2030
virtual bool ProcessNew608FrameData(const CaptionData &inCC608Data)
Notifies me that new frame data has arrived. Clients should call this method once per video frame wit...
virtual bool SetVANCShiftMode(NTV2Channel inChannel, NTV2VANCDataShiftMode inMode)
Enables or disables the "VANC Shift Mode" feature for the given channel.
Declares the CNTV2CaptionRenderer class.
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:1366
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:1360
virtual NTV2DeviceID GetDeviceID(void)
static std::string OutputModeToString(const OutputMode inMode)
std::string NTV2TCIndexToString(const NTV2TCIndex inValue, const bool inCompactDisplay=false)
Definition: ntv2utils.cpp:6394
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:218
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:3808
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:1371
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 void Reset(void)
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...
Declares the CNTV2Line21Captioner class.
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...
uint16_t GetEndFrame(void) const
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:5410
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:249
virtual bool ParseSMPTE334AncPacket(bool &outHasParityErrors)
Parses the current frame&#39;s SMPTE 334 Ancillary packet and extracts the 608 and 708 caption data from ...
virtual bool SetDisplayChannel(const NTV2Line21Channel inChan)
Setsthe caption channel I&#39;m currently focused on (i.e. that I&#39;m currently "burning" into video)...
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:3897
static const NTV2Line21Attributes kRedOnTransparentBG(NTV2_CC608_Red, NTV2_CC608_Blue, NTV2_CC608_Transparent)
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:1284
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 std::string GetOnAirCharacters(const UWord inRowNumber=0) const
Retrieves all "on-air" characters either for all rows, or a specific row.
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:2527
static bool DecodeLine(const UByte *pLineData, UByte &outChar1, UByte &outChar2)
Decodes the supplied line of 8-bit uncompressed (&#39;2vuy&#39;) data and, if successful, returns the two 8-b...
This structure encapsulates all possible CEA-608 caption data bytes that may be associated with a giv...
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:3806
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:2909
bool UnlockAll(CNTV2Card &inDevice)
uint16_t UWord
Definition: ajatypes.h:221
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_)
virtual size_t GetNextServiceBlockFromQueue(const size_t svcIndex, std::vector< UByte > &outData)
Specifies channel or FrameStore 1 (or the first item).
Definition: ntv2enums.h:1359
virtual bool AutoCirculateStart(const NTV2Channel inChannel, const ULWord64 inStartTime=0)
Starts AutoCirculating the specified channel that was previously initialized by CNTV2Card::AutoCircul...
bool CanDoFrameBufferFormat(const NTV2PixelFormat inPF)
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 playout, designating a contiguous block of frame buffers on the...
std::string NTV2ReferenceSourceToString(const NTV2ReferenceSource inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:7420
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:3797
static CaptionDataSrc StringToCaptionDataSrc(const std::string &inDataSrcStr)
bool CanDoWidget(const NTV2WidgetID inWgtID)
const std::string & NTV2Line21ChannelToStr(const NTV2Line21Channel inLine21Channel, const bool inCompact=true)
Converts the given NTV2Line21Channel value into a human-readable string.
#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:3914
std::string NTV2FrameBufferFormatToString(const NTV2FrameBufferFormat inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:6936
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:4869
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:1362
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:56
Specifies channel or FrameStore 5 (or the 5th item).
Definition: ntv2enums.h:1363
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:67
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
virtual bool BurnCaptions(NTV2Buffer &inFB, const NTV2FormatDesc &inFD)
Blits all of my current caption channel&#39;s "on-air" captions into the given host buffer with the corre...
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:65
static std::string GetLegalOutputModes(void)
Specifies channel or FrameStore 6 (or the 6th item).
Definition: ntv2enums.h:1364
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, designating a contiguous block of frame buffers on the ...
#define AUTOCIRCULATE_WITH_RP188
Use this to AutoCirculate with RP188.
std::string NTV2ChannelToString(const NTV2Channel inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:5727
Specifies channel or FrameStore 7 (or the 7th item).
Definition: ntv2enums.h:1365
virtual ULWord GetVPID(void) const
Definition: ntv2vpid.h:40
#define NTV2_INPUT_SOURCE_IS_SDI(_inpSrc_)
Definition: ntv2enums.h:1283
virtual NTV2Line21Channel GetDisplayChannel(void) const
Answers with the caption channel that I&#39;m currently focused on (or that I&#39;m currently "burning" into ...
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)
NTV2Line21Channel
The CEA-608 caption channels: CC1 thru CC4, TX1 thru TX4, plus XDS.
const int NTV2_CC708PrimaryCaptionServiceNum
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 GetNextServiceBlockInfoFromQueue(const size_t svcIndex, size_t &outBlockSize, size_t &outDataSize, int &outServiceNum, bool &outIsExtended) const
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
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:146
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.
static const NTV2Line21Attributes kGreenOnTransparentBG(NTV2_CC608_Green, NTV2_CC608_Blue, NTV2_CC608_Transparent)
This identifies the "tall" mode in which there are some VANC lines in the frame buffer.
Definition: ntv2enums.h:3800
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:3799
Specifies channel or FrameStore 3 (or the 3rd item).
Definition: ntv2enums.h:1361
NTV2ReferenceSource NTV2InputSourceToReferenceSource(const NTV2InputSource inInputSource)
Converts a given NTV2InputSource to its equivalent NTV2ReferenceSource value.
Definition: ntv2utils.cpp:5023
See 8-Bit YCbCr Format.
Definition: ntv2enums.h:223
static const UWord gMixerNums[]
static std::string CaptionDataSrcToString(const CaptionDataSrc inDataSrc)
virtual bool EnableChannel(const NTV2Channel inChannel)
Enables the given FrameStore.