AJA NTV2 SDK  18.1.0.2439
NTV2 SDK 18.1.0.2439
ntv2fieldburn.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
8 #include "ntv2fieldburn.h"
9 #include "ntv2devicescanner.h"
10 #include "ajabase/common/types.h"
11 #include "ajabase/system/process.h"
13 #include <iostream>
14 
15 using namespace std;
16 
17 #define ToCharPtr(_p_) reinterpret_cast<char*>(_p_)
18 
19 static const uint32_t kAppSignature (NTV2_FOURCC('F','l','d','B'));
20 
21 
23 
24 
26  : mConfig (inConfig),
27  mPlayThread (AJAThread()),
28  mCaptureThread (AJAThread()),
30  mSavedTaskMode (NTV2_DISABLE_TASKS),
31  mOutputDest (NTV2_OUTPUTDESTINATION_INVALID),
32  mAudioSystem (inConfig.WithAudio() ? NTV2_AUDIOSYSTEM_1 : NTV2_AUDIOSYSTEM_INVALID),
33  mGlobalQuit (false)
34 {
35 } // constructor
36 
37 
39 {
40  Quit(); // Stop my capture and playout threads, then destroy them
41  mDevice.UnsubscribeInputVerticalEvent(mConfig.fInputChannel); // Unsubscribe from input VBI event
42 } // destructor
43 
44 
46 {
47  // Set the global 'quit' flag, and wait for the threads to go inactive...
48  mGlobalQuit = true;
49 
50  while (mPlayThread.Active())
51  AJATime::Sleep(10);
52 
53  while (mCaptureThread.Active())
54  AJATime::Sleep(10);
55 
56  if (!mConfig.fDoMultiFormat)
57  { // Release the device...
59  if (NTV2_IS_VALID_TASK_MODE(mSavedTaskMode))
60  mDevice.SetTaskMode(mSavedTaskMode); // Restore prior task mode
61  }
62 } // Quit
63 
64 
66 {
68 
69  // Open the device...
71  { if (aja::lower(mConfig.fDeviceSpec) != "list" && mConfig.fDeviceSpec != "?")
72  cerr << "## ERROR: Device '" << mConfig.fDeviceSpec << "' not found" << endl;
73  return AJA_STATUS_OPEN;
74  }
75  if (!mDevice.IsDeviceReady (false))
76  {cerr << "## ERROR: '" << mDevice.GetDescription() << "' not ready" << endl; return AJA_STATUS_INITIALIZE;}
77  if (!mDevice.features().CanDoCapture())
78  {cerr << "## ERROR: '" << mDevice.GetDescription() << "' cannot capture" << endl; return AJA_STATUS_FEATURE;}
79  if (!mDevice.features().CanDoPlayback())
80  {cerr << "## ERROR: '" << mDevice.GetDescription() << "' cannot playout" << endl; return AJA_STATUS_FEATURE;}
81 
82  ULWord appSignature (0);
83  int32_t appPID (0);
84  mDevice.GetStreamingApplication (appSignature, appPID); // Who currently "owns" the device?
85  mDevice.GetTaskMode(mSavedTaskMode); // Save the current device state
86  if (!mConfig.fDoMultiFormat)
87  {
89  {
90  cerr << "## ERROR: Unable to acquire '" << mDevice.GetDescription() << "' because another app (pid " << appPID << ") owns it" << endl;
91  return AJA_STATUS_BUSY; // Some other app is using the device
92  }
93  mDevice.ClearRouting(); // Clear the current device routing (since I "own" the device)
94  }
95  mDevice.SetTaskMode(NTV2_OEM_TASKS); // Force OEM tasks
96 
97  // Set up the video and audio...
98  status = SetupVideo();
99  if (AJA_FAILURE(status))
100  return status;
101 
102  if (NTV2_IS_VALID_AUDIO_SYSTEM(mAudioSystem))
103  status = SetupAudio();
104  if (AJA_FAILURE(status))
105  return status;
106 
107  // Set up the circular buffers...
108  status = SetupHostBuffers();
109  if (AJA_FAILURE(status))
110  return status;
111 
112  // Set up the signal routing...
115 
116  // Lastly, prepare my AJATimeCodeBurn instance...
117  mTCBurner.RenderTimeCodeFont (CNTV2DemoCommon::GetAJAPixelFormat (mConfig.fPixelFormat), mFormatDesc.numPixels, mFormatDesc.numLines);
118  // Ready to go...
119  if (mConfig.IsVerbose())
120  { cerr << mConfig
121  << "Device Description: " << mDevice.GetDescription() << endl
122  << endl;
123  }
124  BURNINFO("Configuration: " << mConfig);
125  return AJA_STATUS_SUCCESS;
126 
127 } // Init
128 
129 
131 {
132  const UWord numFrameStores (mDevice.features().GetNumFrameStores());
133 
134  // Does this device have the requested input source?
135  if (!mDevice.features().CanDoInputSource(mConfig.fInputSource))
136  {cerr << "## ERROR: Device does not have the specified input source" << endl; return AJA_STATUS_BAD_PARAM;}
137 
138  // Pick an input NTV2Channel from the input source, and enable its frame buffer...
140  mDevice.EnableChannel(mConfig.fInputChannel); // Enable the input frame buffer
141 
142  // Pick an appropriate output NTV2Channel, and enable its frame buffer...
143  switch (mConfig.fInputSource)
144  {
145  case NTV2_INPUTSOURCE_SDI1: mConfig.fOutputChannel = (numFrameStores == 2 || numFrameStores > 4) ? NTV2_CHANNEL2 : NTV2_CHANNEL3;
146  break;
147 
148  case NTV2_INPUTSOURCE_SDI2: mConfig.fOutputChannel = (numFrameStores > 4) ? NTV2_CHANNEL3 : NTV2_CHANNEL4;
149  break;
150 
152  break;
153 
154  case NTV2_INPUTSOURCE_SDI4: mConfig.fOutputChannel = (numFrameStores > 4) ? NTV2_CHANNEL5 : NTV2_CHANNEL3;
155  break;
156 
157  case NTV2_INPUTSOURCE_SDI5: mConfig.fOutputChannel = NTV2_CHANNEL6; break;
158  case NTV2_INPUTSOURCE_SDI6: mConfig.fOutputChannel = NTV2_CHANNEL7; break;
159  case NTV2_INPUTSOURCE_SDI7: mConfig.fOutputChannel = NTV2_CHANNEL8; break;
160  case NTV2_INPUTSOURCE_SDI8: mConfig.fOutputChannel = NTV2_CHANNEL7; break;
161 
163  case NTV2_INPUTSOURCE_HDMI1: mConfig.fOutputChannel = numFrameStores < 3 ? NTV2_CHANNEL2 : NTV2_CHANNEL3;
164  break;
165  default:
166  case NTV2_INPUTSOURCE_INVALID: cerr << "## ERROR: Bad input source" << endl; return AJA_STATUS_BAD_PARAM;
167  }
168  mDevice.EnableChannel(mConfig.fOutputChannel); // Enable the output frame buffer
169 
170  // Subscribe interrupts...
173 
174  // Pick an appropriate output spigot based on the output channel...
175  mOutputDest = ::NTV2ChannelToOutputDestination(mConfig.fOutputChannel);
176  if (!mDevice.features().CanDoWidget(NTV2_Wgt12GSDIOut2)
177  && !mDevice.features().CanDoWidget(NTV2_Wgt3GSDIOut2)
178  && !mDevice.features().CanDoWidget(NTV2_WgtSDIOut2))
179  mOutputDest = NTV2_OUTPUTDESTINATION_SDI1; // If device has only one SDI output
180  if (mDevice.features().HasBiDirectionalSDI() // If device has bidirectional SDI connectors...
181  && NTV2_OUTPUT_DEST_IS_SDI(mOutputDest)) // ...and output destination is SDI...
182  mDevice.SetSDITransmitEnable (mConfig.fOutputChannel, true); // ...then enable transmit mode
183 
184  // Flip the input spigot to "receive" if necessary...
185  bool isXmit (false);
186  if (mDevice.features().HasBiDirectionalSDI() // If device has bidirectional SDI connectors...
187  && NTV2_INPUT_SOURCE_IS_SDI(mConfig.fInputSource) // ...and desired input source is SDI...
188  && mDevice.GetSDITransmitEnable (mConfig.fInputChannel, isXmit) // ...and GetSDITransmitEnable succeeds...
189  && isXmit) // ...and input is set to "transmit"...
190  {
191  mDevice.SetSDITransmitEnable (mConfig.fInputChannel, false); // ...then disable transmit mode...
192  mDevice.WaitForOutputVerticalInterrupt (mConfig.fOutputChannel, 10); // ...and allow device to lock to input signal
193  } // if input SDI connector needs to switch from transmit mode
194 
195  // Is there an input signal? What format is it?
196  mVideoFormat = mDevice.GetInputVideoFormat(mConfig.fInputSource);
197  if (mVideoFormat == NTV2_FORMAT_UNKNOWN)
198  {cerr << "## ERROR: No input signal, or can't handle its format" << endl; return AJA_STATUS_NOINPUT;}
199 
200  // This demo requires an interlaced signal...
201  if (IsProgressiveTransport(mVideoFormat))
202  {cerr << "## ERROR: Input signal is progressive -- no fields" << endl; return AJA_STATUS_UNSUPPORTED;}
203 
204  // Free-run the device clock, since E-to-E mode isn't used, nor is a mixer tied to the input...
206 
207  // Check the timecode source...
208  if (!InputSignalHasTimecode())
209  cerr << "## WARNING: Timecode source '" << ::NTV2TCIndexToString(mConfig.fTimecodeSource, true) << "' has no embedded timecode" << endl;
210 
211  // If the device supports different per-channel video formats, configure it as requested...
212  if (mDevice.features().CanDoMultiFormat())
213  mDevice.SetMultiFormatMode (mConfig.fDoMultiFormat);
214 
215  // Set the input/output channel video formats to the video format that was detected earlier...
216  mDevice.SetVideoFormat (mVideoFormat, false, false, mDevice.features().CanDoMultiFormat() ? mConfig.fInputChannel : NTV2_CHANNEL1);
217  if (mDevice.features().CanDoMultiFormat()) // If device supports multiple formats per-channel...
218  mDevice.SetVideoFormat (mVideoFormat, false, false, mConfig.fOutputChannel); // ...then also set the output channel format to the detected input format
219 
220  // Can the device handle the requested frame buffer pixel format?
221  if (!mDevice.features().CanDoFrameBufferFormat(mConfig.fPixelFormat))
222  {cerr << "## ERROR: " << ::NTV2FrameBufferFormatToString(mConfig.fPixelFormat) << " unsupported" << endl; return AJA_STATUS_UNSUPPORTED;}
223 
224  // Set both input and output frame buffers' pixel formats...
225  mDevice.SetFrameBufferFormat (mConfig.fInputChannel, mConfig.fPixelFormat);
226  mDevice.SetFrameBufferFormat (mConfig.fOutputChannel, mConfig.fPixelFormat);
227 
228  // Normally, timecode embedded in the output signal comes from whatever is written into the RP188
229  // registers (30/31 for SDI out 1, 65/66 for SDIout2, etc.).
230  // AutoCirculate automatically writes the timecode in the AUTOCIRCULATE_TRANSFER's acRP188 field
231  // into these registers (if AutoCirculateInitForOutput was called with AUTOCIRCULATE_WITH_RP188 set).
232  // Newer AJA devices can also bypass these RP188 registers, and simply copy whatever timecode appears
233  // at any SDI input (called the "bypass source"). To ensure that AutoCirculate's playout timecode
234  // will actually be seen in the output signal, "bypass mode" must be disabled...
235  bool bypassIsEnabled (false);
236  mDevice.IsRP188BypassEnabled (::NTV2InputSourceToChannel(mConfig.fInputSource), bypassIsEnabled);
237  if (bypassIsEnabled)
239 
240  // Now that newer AJA devices can capture/play anc data from separate buffers,
241  // there's no need to enable VANC frame geometries...
242  mDevice.SetVANCMode (NTV2_VANCMODE_OFF, mConfig.fInputChannel);
243  mDevice.SetVANCMode (NTV2_VANCMODE_OFF, mConfig.fOutputChannel);
244  if (::Is8BitFrameBufferFormat (mConfig.fPixelFormat))
245  { // 8-bit FBFs: since not using VANC geometries, disable bit shift...
248  }
249 
250  // Now that the video is set up, get information about the current frame geometry...
251  mFormatDesc = NTV2FormatDescriptor (mVideoFormat, mConfig.fPixelFormat);
252  if (mFormatDesc.IsPlanar())
253  {cerr << "## ERROR: This demo doesn't work with planar pixel formats" << endl; return AJA_STATUS_UNSUPPORTED;}
254  return AJA_STATUS_SUCCESS;
255 
256 } // SetupVideo
257 
258 
260 {
261  if (!NTV2_IS_VALID_AUDIO_SYSTEM (mAudioSystem))
262  return AJA_STATUS_SUCCESS;
263 
264  if (mConfig.fDoMultiFormat)
265  if (mDevice.features().GetNumAudioSystems() > 1)
266  if (UWord(mConfig.fInputChannel) < mDevice.features().GetNumAudioSystems())
267  mAudioSystem = ::NTV2ChannelToAudioSystem(mConfig.fInputChannel);
268 
269  // Have the audio subsystem capture audio from the designated input source...
270  mDevice.SetAudioSystemInputSource (mAudioSystem, ::NTV2InputSourceToAudioSource(mConfig.fInputSource),
272 
273  // It's best to use all available audio channels...
274  mDevice.SetNumberAudioChannels (mDevice.features().GetMaxAudioChannels(), mAudioSystem);
275 
276  // Assume 48kHz PCM...
277  mDevice.SetAudioRate (NTV2_AUDIO_48K, mAudioSystem);
278 
279  // 4MB device audio buffers work best...
280  mDevice.SetAudioBufferSize (NTV2_AUDIO_BUFFER_BIG, mAudioSystem);
281 
282  // Set up the output audio embedders...
283  if (mDevice.features().GetNumAudioSystems() > 1)
284  {
285  // Some devices, like the Kona1, have 2 FrameStores but only 1 SDI output,
286  // which makes mConfig.fOutputChannel == NTV2_CHANNEL2, but need SDIoutput to be NTV2_CHANNEL1...
287  UWord SDIoutput(mConfig.fOutputChannel);
288  if (SDIoutput >= mDevice.features().GetNumVideoOutputs())
289  SDIoutput = mDevice.features().GetNumVideoOutputs() - 1;
290  mDevice.SetSDIOutputAudioSystem (NTV2Channel(SDIoutput), mAudioSystem);
291  }
292 
293  //
294  // Loopback mode plays whatever audio appears in the input signal when it's
295  // connected directly to an output (i.e., "end-to-end" mode). If loopback is
296  // left enabled, the video will lag the audio as video frames get briefly delayed
297  // in our ring buffer. Audio, therefore, needs to come out of the (buffered) frame
298  // data being played, so loopback must be turned off...
299  //
300  mDevice.SetAudioLoopBack (NTV2_AUDIO_LOOPBACK_OFF, mAudioSystem);
301  return AJA_STATUS_SUCCESS;
302 
303 } // SetupAudio
304 
305 
307 {
308  ULWordSequence failures;
309  CNTV2DemoCommon::SetDefaultPageSize(); // Set host-specific page size
310 
311  // Let my circular buffer know when it's time to quit...
312  mFrameDataRing.SetAbortFlag(&mGlobalQuit);
313 
314  // Make the video buffers half the size of a full frame (i.e. field-size)...
315  const ULWord vidBuffSizeBytes (mFormatDesc.GetTotalBytes() / 2);
316  NTV2_ASSERT(mFormatDesc.GetBytesPerRow() == mFormatDesc.linePitch * 4);
317 
318  // Allocate and add each in-host NTV2FrameData to my circular buffer member variable...
319  mHostBuffers.reserve(CIRCULAR_BUFFER_SIZE);
320  while (mHostBuffers.size() < CIRCULAR_BUFFER_SIZE)
321  {
322  mHostBuffers.push_back(NTV2FrameData()); // Make a new NTV2FrameData...
323  NTV2FrameData & frameData (mHostBuffers.back()); // ...and get a reference to it
324 
325  // In Field Mode, one buffer is used to hold each field's video data.
326  frameData.fVideoBuffer.Allocate (vidBuffSizeBytes, /*pageAligned*/true);
327  if (!mConfig.FieldMode())
328  { // In Frame Mode, use two buffers, one for each field. The DMA transfer
329  // of each field will be done as a group of lines, with each line considered a "segment".
330  frameData.fVideoBuffer2.Allocate (vidBuffSizeBytes, /*pageAligned*/true);
331  }
332 
333  // Allocate a page-aligned audio buffer (if handling audio)...
334  if (NTV2_IS_VALID_AUDIO_SYSTEM(mAudioSystem))
335  frameData.fAudioBuffer.Allocate (NTV2_AUDIOSIZE_MAX, /*pageAligned*/true);
336  if (frameData.AudioBuffer())
337  frameData.fAudioBuffer.Fill(ULWord(0));
338 
339  // Check for memory allocation failures...
340  if (!frameData.VideoBuffer()
341  || (NTV2_IS_VALID_AUDIO_SYSTEM(mAudioSystem) && !frameData.AudioBuffer())
342  || (!frameData.VideoBuffer2() && !mConfig.FieldMode()))
343  failures.push_back(ULWord(mHostBuffers.size()+1));
344 
345  // Add this NTV2FrameData to the ring...
346  mFrameDataRing.Add (&frameData);
347  } // for each NTV2FrameData
348 
349  if (!failures.empty())
350  {
351  cerr << "## ERROR: " << DEC(failures.size()) << " allocation failures in buffer(s): " << failures << endl;
352  return AJA_STATUS_MEMORY;
353  }
354  return AJA_STATUS_SUCCESS;
355 
356 } // SetupHostBuffers
357 
358 
360 {
361  const NTV2OutputCrosspointID inputOutputXpt (::GetInputSourceOutputXpt (mConfig.fInputSource));
363  const bool isRGB (::IsRGBFormat(mConfig.fPixelFormat));
364 
365  if (isRGB)
366  {
367  // If the frame buffer is configured for RGB pixel format, incoming YUV must be converted.
368  // This routes the video signal from the input through a color space converter before
369  // connecting to the RGB frame buffer...
370  const NTV2InputCrosspointID cscVideoInputXpt (::GetCSCInputXptFromChannel (mConfig.fInputChannel));
371  const NTV2OutputCrosspointID cscOutputXpt (::GetCSCOutputXptFromChannel (mConfig.fInputChannel, false/*isKey*/, true/*isRGB*/));
372 
373  mDevice.Connect (cscVideoInputXpt, inputOutputXpt); // Connect the CSC's video input to the input spigot's output
374  mDevice.Connect (fbInputXpt, cscOutputXpt); // Connect the frame store's input to the CSC's output
375  }
376  else
377  mDevice.Connect (fbInputXpt, inputOutputXpt); // Route the YCbCr signal directly from the input to the frame buffer's input
378 
379 } // RouteInputSignal
380 
381 
383 {
384  const NTV2InputCrosspointID outputInputXpt (::GetOutputDestInputXpt (mOutputDest));
386  const bool isRGB (::IsRGBFormat(mConfig.fPixelFormat));
387  NTV2OutputCrosspointID outputXpt (fbOutputXpt);
388 
389  if (isRGB)
390  {
391  const NTV2OutputCrosspointID cscVidOutputXpt (::GetCSCOutputXptFromChannel (mConfig.fOutputChannel, false, true));
392  const NTV2InputCrosspointID cscVidInputXpt (::GetCSCInputXptFromChannel (mConfig.fOutputChannel));
393 
394  mDevice.Connect (cscVidInputXpt, fbOutputXpt); // Connect the CSC's video input to the frame store's output
395  mDevice.Connect (outputInputXpt, cscVidOutputXpt); // Connect the SDI output's input to the CSC's video output
396  outputXpt = cscVidOutputXpt;
397  }
398  else
399  mDevice.Connect (outputInputXpt, outputXpt);
400 
401  mTCOutputs.clear();
402  mTCOutputs.push_back(mConfig.fOutputChannel);
403 
404  if (!mConfig.fDoMultiFormat)
405  {
406  // Route all SDI outputs to the outputXpt...
407  const NTV2Channel startNum (NTV2_CHANNEL1);
408  const NTV2Channel endNum (NTV2Channel(mDevice.features().GetNumVideoChannels()));
409  NTV2WidgetID outputWidgetID (NTV2_WIDGET_INVALID);
410 
411  for (NTV2Channel chan(startNum); chan < endNum; chan = NTV2Channel(chan+1))
412  {
413  if (chan == mConfig.fInputChannel || chan == mConfig.fOutputChannel)
414  continue; // Skip the input & output channel, already routed
415  if (mDevice.features().HasBiDirectionalSDI())
416  mDevice.SetSDITransmitEnable (chan, true);
417  if (CNTV2SignalRouter::GetWidgetForInput (::GetSDIOutputInputXpt (chan, mDevice.features().CanDoDualLink()), outputWidgetID))
418  if (mDevice.features().CanDoWidget(outputWidgetID))
419  {
420  mDevice.Connect (::GetSDIOutputInputXpt(chan), outputXpt);
421  mTCOutputs.push_back(chan);
422  }
423  } // for each output spigot
424 
425  // If HDMI and/or analog video outputs are available, route them, too...
426  if (mDevice.features().CanDoWidget(NTV2_WgtHDMIOut1))
427  mDevice.Connect (NTV2_XptHDMIOutInput, outputXpt); // Route output signal to HDMI output
428  if (mDevice.features().CanDoWidget(NTV2_WgtHDMIOut1v2))
429  mDevice.Connect (NTV2_XptHDMIOutQ1Input, outputXpt); // Route output signal to HDMI output
430  if (mDevice.features().CanDoWidget(NTV2_WgtAnalogOut1))
431  mDevice.Connect (NTV2_XptAnalogOutInput, outputXpt); // Route output signal to Analog output
432  if (mDevice.features().CanDoWidget(NTV2_WgtSDIMonOut1))
433  { // SDI Monitor output is spigot 4 (NTV2_CHANNEL5):
434  mDevice.Connect (::GetSDIOutputInputXpt(NTV2_CHANNEL5), outputXpt); // Route output signal to SDI monitor output
435  mTCOutputs.push_back(NTV2_CHANNEL5);
436  }
437  } // if not multiChannel
438  PLDBG(mTCOutputs.size() << " timecode destination(s): " << ::NTV2ChannelListToStr(mTCOutputs));
439 
440 } // RouteOutputSignal
441 
442 
444 {
445  // Start the playout and capture threads...
446  StartPlayThread();
448  return AJA_STATUS_SUCCESS;
449 
450 } // Run
451 
452 
453 
455 
456 // This is where we will start the play thread
458 {
459  // Create and start the playout thread...
460  mPlayThread.Attach(PlayThreadStatic, this);
462  mPlayThread.Start();
463 
464 } // StartPlayThread
465 
466 
467 // The playout thread function
468 void NTV2FieldBurn::PlayThreadStatic (AJAThread * pThread, void * pContext) // static
469 { (void) pThread;
470  // Grab the NTV2FieldBurn instance pointer from the pContext parameter,
471  // then call its PlayFrames method...
472  NTV2FieldBurn * pApp (reinterpret_cast<NTV2FieldBurn*>(pContext));
473  pApp->PlayFrames();
474 
475 } // PlayThreadStatic
476 
477 
479 {
480  const ULWord acOptions (AUTOCIRCULATE_WITH_RP188 | (mConfig.FieldMode() ? AUTOCIRCULATE_WITH_FIELDS : 0));
481  ULWord goodXfers(0), badXfers(0), starves(0), noRoomWaits(0);
482  AUTOCIRCULATE_TRANSFER outputXferInfo; // F1 transfer info
483  AUTOCIRCULATE_TRANSFER outputXferInfo2; // F2 transfer info (unused in Field Mode)
484  AUTOCIRCULATE_STATUS outputStatus;
485 
486  // Stop AutoCirculate on this channel, just in case some other app left it running...
487  mDevice.AutoCirculateStop(mConfig.fOutputChannel);
488  mDevice.WaitForOutputVerticalInterrupt(mConfig.fOutputChannel, 4); // Let it stop
489  BURNNOTE("Thread started");
490 
491  if (!mConfig.FieldMode())
492  {
493  // In Frame Mode, tell AutoCirculate to DMA F1's data as a group of "segments".
494  // Each segment is one line long, and the segments are contiguous in host
495  // memory, but are stored on every other line in the device frame buffer...
496  outputXferInfo.EnableSegmentedDMAs (mFormatDesc.numLines / 2, // number of segments: number of lines per field, i.e. half the line count
497  mFormatDesc.linePitch * 4, // number of active bytes per line
498  mFormatDesc.linePitch * 4, // host bytes per line: normal line pitch when reading from our half-height buffer
499  mFormatDesc.linePitch * 8); // device bytes per line: skip every other line when writing into device memory
500 
501  // F2 is identical to F1, except that F2 starts on 2nd line in device frame buffer...
502  outputXferInfo2.EnableSegmentedDMAs (mFormatDesc.numLines / 2, // number of segments: number of lines per field, i.e. half the line count
503  mFormatDesc.linePitch * 4, // number of active bytes per line
504  mFormatDesc.linePitch * 4, // host bytes per line: normal line pitch when reading from our half-height buffer
505  mFormatDesc.linePitch * 8); // device bytes per line: skip every other line when writing into device memory
506  outputXferInfo2.acInVideoDMAOffset = mFormatDesc.linePitch * 4; // F2 starts on 2nd line in device buffer
507  }
508 
509  // Initialize AutoCirculate...
510  if (!mDevice.AutoCirculateInitForOutput (mConfig.fOutputChannel, mConfig.fOutputFrames, mAudioSystem, acOptions))
511  {PLFAIL("AutoCirculateInitForOutput failed"); mGlobalQuit = true;}
512 
513  while (!mGlobalQuit)
514  {
515  mDevice.AutoCirculateGetStatus (mConfig.fOutputChannel, outputStatus);
516 
517  // Check if there's room for another frame on the card...
518  if (outputStatus.CanAcceptMoreOutputFrames())
519  {
520  // Device has at least one free frame buffer that can be filled.
521  // Wait for the next frame in our ring to become ready to "consume"...
522  NTV2FrameData * pFrameData (mFrameDataRing.StartConsumeNextBuffer());
523  if (!pFrameData)
524  {starves++; continue;} // Producer thread isn't producing frames fast enough
525 
526  // Prepare to transfer the timecode-burned field (F1) to the device for playout.
527  // Set the outputXfer struct's video and audio buffers from playData's buffers...
528  // IMPORTANT: In Frame Mode, for segmented DMAs, AutoCirculateTransfer expects the video
529  // buffer size to be set to the segment size, in bytes, which is one raster line length.
530  outputXferInfo.SetVideoBuffer (pFrameData->VideoBuffer(),
531  mConfig.FieldMode() ? pFrameData->VideoBufferSize() // Field Mode
532  : mFormatDesc.GetBytesPerRow()); // Frame Mode
533  if (pFrameData->AudioBuffer())
534  outputXferInfo.SetAudioBuffer (pFrameData->AudioBuffer(), pFrameData->AudioBufferSize());
535  if (mConfig.FieldMode())
536  outputXferInfo.acPeerToPeerFlags = pFrameData->fFrameFlags; // Which field was this?
537 
538  // Tell AutoCirculate to embed this frame's timecode into the SDI output(s)...
539  outputXferInfo.SetOutputTimeCodes(pFrameData->fTimecodes);
540  PLDBG(pFrameData->fTimecodes);
541 
542  // Transfer field to the device...
543  if (mDevice.AutoCirculateTransfer (mConfig.fOutputChannel, outputXferInfo))
544  goodXfers++;
545  else
546  badXfers++;
547 
548  if (!mConfig.FieldMode())
549  { // Frame Mode: Additionally transfer F2 to the same device frame buffer used for F1.
550  // Again, for segmented DMAs, AutoCirculateTransfer expects the video buffer size to be
551  // set to the segment size, in bytes, which is one raster line length.
552  outputXferInfo2.acDesiredFrame = outputXferInfo.acTransferStatus.acTransferFrame;
553  outputXferInfo2.SetVideoBuffer (pFrameData->VideoBuffer2(), mFormatDesc.GetBytesPerRow());
554  if (mDevice.AutoCirculateTransfer (mConfig.fOutputChannel, outputXferInfo2))
555  goodXfers++;
556  else
557  badXfers++;
558  }
559 
560  if (goodXfers == 6) // Start AutoCirculate playout once 6 fields are buffered on the device...
561  mDevice.AutoCirculateStart(mConfig.fOutputChannel);
562 
563  // Signal that the frame has been "consumed"...
564  mFrameDataRing.EndConsumeNextBuffer();
565  continue; // Back to top of while loop
566  } // if CanAcceptMoreOutputFrames
567 
568  // Wait for one or more buffers to become available on the device, which should occur at next VBI...
569  noRoomWaits++;
571  } // loop til quit signaled
572 
573  // Stop AutoCirculate...
574  mDevice.AutoCirculateStop (mConfig.fOutputChannel);
575  BURNNOTE("Thread completed: " << DEC(goodXfers) << " xfers, " << DEC(badXfers) << " failed, "
576  << DEC(starves) << " ring starves, " << DEC(noRoomWaits) << " device starves");
577 } // PlayFrames
578 
579 
581 
582 
583 
585 //
586 // This is where the capture thread gets started
587 //
589 {
590  // Create and start the capture thread...
591  mCaptureThread.Attach(CaptureThreadStatic, this);
592  mCaptureThread.SetPriority(AJA_ThreadPriority_High);
593  mCaptureThread.Start();
594 
595 } // StartCaptureThread
596 
597 
598 //
599 // The static capture thread function
600 //
601 void NTV2FieldBurn::CaptureThreadStatic (AJAThread * pThread, void * pContext) // static
602 { (void) pThread;
603  // Grab the NTV2FieldBurn instance pointer from the pContext parameter,
604  // then call its CaptureFrames method...
605  NTV2FieldBurn * pApp(reinterpret_cast<NTV2FieldBurn*>(pContext));
606  pApp->CaptureFrames();
607 } // CaptureThreadStatic
608 
609 
610 //
611 // Repeatedly captures frames until told to stop
612 //
614 {
615  AUTOCIRCULATE_TRANSFER inputXferInfo; // F1 transfer info
616  AUTOCIRCULATE_TRANSFER inputXferInfo2; // F2 transfer info (unused in Field Mode)
617  NTV2TCIndexes F1TCIndexes, F2TCIndexes;
618  const ULWord acOptions ((mConfig.WithTimecode() ? AUTOCIRCULATE_WITH_RP188 : 0) | (mConfig.FieldMode() ? AUTOCIRCULATE_WITH_FIELDS : 0));
619  ULWord goodXfers(0), badXfers(0), ringFulls(0), devWaits(0);
620  BURNNOTE("Thread started");
621 
622  // Prepare the Timecode Indexes we'll be setting for playout...
623  for (size_t ndx(0); ndx < mTCOutputs.size(); ndx++)
624  { const NTV2Channel sdiSpigot(mTCOutputs.at(ndx));
625  F1TCIndexes.insert(::NTV2ChannelToTimecodeIndex(sdiSpigot, /*LTC?*/true)); // F1 LTC
626  F1TCIndexes.insert(::NTV2ChannelToTimecodeIndex(sdiSpigot, /*LTC?*/false)); // F1 VITC
627  F2TCIndexes.insert(::NTV2ChannelToTimecodeIndex(sdiSpigot, /*LTC?*/false, true)); // F2 VITC
628  }
629 
630  if (!mConfig.FieldMode())
631  {
632  // In Frame Mode, use AutoCirculate's "segmented DMA" feature to transfer each field
633  // out of the device's full-frame video buffer as a group of "segments".
634  // Each segment is one line long, and the segments are contiguous in host memory,
635  // but originate on alternating lines in the device's frame buffer...
636  inputXferInfo.EnableSegmentedDMAs (mFormatDesc.numLines / 2, // Number of segments: number of lines per field, i.e. half the line count
637  mFormatDesc.linePitch * 4, // Segment size, in bytes: transfer this many bytes per segment (normal line pitch)
638  mFormatDesc.linePitch * 4, // Host bytes per line: normal line pitch when writing into our half-height buffer
639  mFormatDesc.linePitch * 8); // Device bytes per line: skip every other line when reading from device memory
640 
641  // IMPORTANT: For segmented DMAs, the video buffer size must contain the number of bytes to
642  // transfer per segment. This will be done just prior to calling AutoCirculateTransfer.
643  inputXferInfo2.EnableSegmentedDMAs (mFormatDesc.numLines / 2, // Number of segments: number of lines per field, i.e. half the line count
644  mFormatDesc.linePitch * 4, // Segment size, in bytes: transfer this many bytes per segment (normal line pitch)
645  mFormatDesc.linePitch * 4, // Host bytes per line: normal line pitch when writing into our half-height buffer
646  mFormatDesc.linePitch * 8); // Device bytes per line: skip every other line when reading from device memory
647  inputXferInfo2.acInVideoDMAOffset = mFormatDesc.linePitch * 4; // Field 2 starts on second line in device buffer
648  }
649 
650  // Stop AutoCirculate on this channel, just in case some other app left it running...
651  mDevice.AutoCirculateStop (mConfig.fInputChannel);
652 
653  // Initialize AutoCirculate...
654  if (!mDevice.AutoCirculateInitForInput (mConfig.fInputChannel, // channel
655  mConfig.fInputFrames, // frame count/range
656  mAudioSystem, // audio system
657  acOptions)) // flags
658  {BURNFAIL("AutoCirculateInitForInput failed"); mGlobalQuit = true;}
659  else
660  // Start AutoCirculate running...
661  mDevice.AutoCirculateStart (mConfig.fInputChannel);
662 
663  while (!mGlobalQuit)
664  {
665  AUTOCIRCULATE_STATUS acStatus;
666  mDevice.AutoCirculateGetStatus (mConfig.fInputChannel, acStatus);
667 
668  if (acStatus.IsRunning() && acStatus.HasAvailableInputFrame())
669  {
670  // At this point, there's at least one fully-formed frame available in the device's frame buffer
671  // memory waiting to be transferred to the host. Reserve an NTV2FrameData to fill ("produce"),
672  // and use it in the next frame transferred from the device...
673  NTV2FrameData * pFrameData (mFrameDataRing.StartProduceNextBuffer ());
674  if (!pFrameData)
675  {ringFulls++; continue;} // Ring full -- consumer thread isn't consuming frames fast enough
676 
677  inputXferInfo.SetVideoBuffer (pFrameData->VideoBuffer(),
678  mConfig.FieldMode() ? pFrameData->VideoBufferSize()
679  : mFormatDesc.GetBytesPerRow());
680  if (NTV2_IS_VALID_AUDIO_SYSTEM(mAudioSystem))
681  inputXferInfo.SetAudioBuffer (pFrameData->AudioBuffer(), NTV2_AUDIOSIZE_MAX);
682 
683  // Transfer this Field (Field Mode) or F1 (Frame Mode) from the device into our host buffers...
684  if (mDevice.AutoCirculateTransfer (mConfig.fInputChannel, inputXferInfo)) goodXfers++;
685  else badXfers++;
686 
687  // Remember the amount, in bytes, of captured audio data...
688  pFrameData->fNumAudioBytes = pFrameData->AudioBuffer() ? inputXferInfo.GetCapturedAudioByteCount() : 0;
689  if (mConfig.FieldMode())
690  pFrameData->fFrameFlags = inputXferInfo.acPeerToPeerFlags; // Remember which field this was
691 
692  // Get a timecode to use for burn-in...
693  NTV2_RP188 thisFrameTC;
694  inputXferInfo.GetInputTimeCodes (pFrameData->fTimecodes, mConfig.fInputChannel);
695  if (!pFrameData->fTimecodes.empty())
696  {
697  thisFrameTC = pFrameData->fTimecodes.begin()->second; // Use 1st "good" timecode for burn-in
698  CAPDBG("Captured TC: " << ::NTV2TCIndexToString(pFrameData->fTimecodes.begin()->first,true) << " " << thisFrameTC);
699  }
700  else
701  { // Invent a timecode (based on frame count)...
702  const NTV2FrameRate ntv2FrameRate (::GetNTV2FrameRateFromVideoFormat (mVideoFormat));
703  const TimecodeFormat tcFormat (CNTV2DemoCommon::NTV2FrameRate2TimecodeFormat(ntv2FrameRate));
704  const CRP188 inventedTC (inputXferInfo.GetTransferStatus().GetProcessedFrameCount(), 0, 0, 10, tcFormat);
705  inventedTC.GetRP188Reg(thisFrameTC);
706  }
707  CRP188 tc(thisFrameTC);
708  string tcStr;
709  tc.GetRP188Str(tcStr);
710 
711  if (!mConfig.FieldMode())
712  { // Frame Mode: Transfer F2 segments from same device frame buffer used for F1...
713  inputXferInfo2.acDesiredFrame = inputXferInfo.acTransferStatus.acTransferFrame;
714  inputXferInfo2.SetVideoBuffer (pFrameData->VideoBuffer2(), mFormatDesc.GetBytesPerRow());
715  if (mDevice.AutoCirculateTransfer (mConfig.fInputChannel, inputXferInfo2)) goodXfers++;
716  else badXfers++;
717  }
718 
719  // While this NTV2FrameData's buffers are locked, "burn" identical timecode into each field...
720  // F1 goes into top half, F2 into bottom half...
721  mTCBurner.BurnTimeCode (ToCharPtr(inputXferInfo.acVideoBuffer.GetHostPointer()), tcStr.c_str(),
722  !mConfig.FieldMode() || (pFrameData->fFrameFlags & AUTOCIRCULATE_FRAME_FIELD0) ? 10 : 30);
723  if (!mConfig.FieldMode()) // Frame Mode: "burn" F2 timecode
724  mTCBurner.BurnTimeCode (ToCharPtr(inputXferInfo2.acVideoBuffer.GetHostPointer()), tcStr.c_str(), 30);
725 
726  // Set NTV2FrameData::fTimecodes map for playout...
727  for (NTV2TCIndexesConstIter it(F1TCIndexes.begin()); it != F1TCIndexes.end(); ++it)
728  pFrameData->fTimecodes[*it] = thisFrameTC;
729  for (NTV2TCIndexesConstIter it(F2TCIndexes.begin()); it != F2TCIndexes.end(); ++it)
730  pFrameData->fTimecodes[*it] = thisFrameTC;
731 
732  // Signal that we're done "producing" the frame, making it available for future "consumption"...
733  mFrameDataRing.EndProduceNextBuffer();
734  } // if A/C running and frame(s) are available for transfer
735  else
736  {
737  // Either AutoCirculate is not running, or there were no frames available on the device to transfer.
738  // Rather than waste CPU cycles spinning, waiting until a field/frame becomes available, it's far more
739  // efficient to wait for the next input vertical interrupt event to get signaled...
740  devWaits++;
741  if (mConfig.FieldMode())
743  else
744  mDevice.WaitForInputFieldID (NTV2_FIELD0, mConfig.fInputChannel);
745  }
746  } // loop til quit signaled
747 
748  // Stop AutoCirculate...
749  mDevice.AutoCirculateStop(mConfig.fInputChannel);
750  BURNNOTE("Thread completed: " << DEC(goodXfers) << " xfers, " << DEC(badXfers) << " failed, "
751  << DEC(ringFulls) << " ring full(s), " << DEC(devWaits) << " device waits");
752 
753 } // CaptureFrames
754 
755 
757 
758 
759 void NTV2FieldBurn::GetStatus (ULWord & outFramesProcessed, ULWord & outCaptureFramesDropped, ULWord & outPlayoutFramesDropped,
760  ULWord & outCaptureBufferLevel, ULWord & outPlayoutBufferLevel)
761 {
762  AUTOCIRCULATE_STATUS inputStatus, outputStatus;
763 
764  mDevice.AutoCirculateGetStatus (mConfig.fInputChannel, inputStatus);
765  mDevice.AutoCirculateGetStatus (mConfig.fOutputChannel, outputStatus);
766 
767  outFramesProcessed = inputStatus.acFramesProcessed;
768  outCaptureFramesDropped = inputStatus.acFramesDropped;
769  outPlayoutFramesDropped = outputStatus.acFramesDropped;
770  outCaptureBufferLevel = inputStatus.acBufferLevel;
771  outPlayoutBufferLevel = outputStatus.acBufferLevel;
772 
773 } // GetStatus
774 
775 
776 static ULWord GetRP188RegisterForInput (const NTV2InputSource inInputSource)
777 {
778  switch (inInputSource)
779  {
780  case NTV2_INPUTSOURCE_SDI1: return kRegRP188InOut1DBB; // reg 29
781  case NTV2_INPUTSOURCE_SDI2: return kRegRP188InOut2DBB; // reg 64
782  case NTV2_INPUTSOURCE_SDI3: return kRegRP188InOut3DBB; // reg 268
783  case NTV2_INPUTSOURCE_SDI4: return kRegRP188InOut4DBB; // reg 273
784  case NTV2_INPUTSOURCE_SDI5: return kRegRP188InOut5DBB; // reg 342
785  case NTV2_INPUTSOURCE_SDI6: return kRegRP188InOut6DBB; // reg 418
786  case NTV2_INPUTSOURCE_SDI7: return kRegRP188InOut7DBB; // reg 427
787  case NTV2_INPUTSOURCE_SDI8: return kRegRP188InOut8DBB; // reg 436
788  default: return 0;
789  } // switch on input source
790 
791 } // GetRP188RegisterForInput
792 
793 
795 {
796  const ULWord regNum (::GetRP188RegisterForInput (mConfig.fInputSource));
797  ULWord regValue (0);
798 
799  // Bit 16 of the RP188 DBB register will be set if there is timecode embedded in the input signal...
800  if (regNum && mDevice.ReadRegister(regNum, regValue) && regValue & BIT(16))
801  return true;
802  return false;
803 
804 } // InputSignalHasTimecode
NTV2Channel NTV2InputSourceToChannel(const NTV2InputSource inInputSource)
Converts a given NTV2InputSource to its equivalent NTV2Channel value.
Definition: ntv2utils.cpp:5051
bool SetOutputTimeCodes(const NTV2TimeCodes &inValues)
Intended for playout, replaces the contents of my acOutputTimeCodes member.
virtual AJAStatus SetupAudio(void)
Sets up everything I need for capturing and playing audio.
Header file for the NTV2FieldBurn demonstration class.
The invalid video input.
Definition: ntv2enums.h:1281
NTV2FrameRate GetNTV2FrameRateFromVideoFormat(const NTV2VideoFormat inVideoFormat)
Definition: ntv2utils.cpp:3630
static ULWord GetRP188RegisterForInput(const NTV2InputSource inInputSource)
virtual bool SetTaskMode(const NTV2TaskMode inMode)
Sets the device&#39;s task mode.
virtual bool WaitForInputFieldID(const NTV2FieldID inFieldID, const NTV2Channel inChannel=NTV2_CHANNEL1)
Efficiently sleeps the calling thread/process until the next input VBI for the given field and input ...
#define NTV2_IS_VALID_TASK_MODE(__m__)
Identifies the 5th SDI video input.
Definition: ntv2enums.h:1277
virtual bool GetSDITransmitEnable(const NTV2Channel inChannel, bool &outEnabled)
Answers whether or not the specified SDI connector is currently acting as a transmitter (i...
#define CAPDBG(_expr_)
std::set< NTV2TCIndex > NTV2TCIndexes
bool Allocate(const size_t inByteCount, const bool inPageAligned=false)
Allocates (or re-allocates) my user-space storage using the given byte count. I assume full responsib...
Declares common types used in the ajabase library.
virtual bool SetAudioLoopBack(const NTV2AudioLoopBack inMode, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Enables or disables NTV2AudioLoopBack mode for the given NTV2AudioSystem.
Definition: ntv2audio.cpp:301
Specifies the device&#39;s internal clock.
Definition: ntv2enums.h:1464
virtual bool SetReference(const NTV2ReferenceSource inRefSource, const bool inKeepFramePulseSelect=(0))
Sets the device&#39;s clock reference source. See Video Output Clocking & Synchronization for more inform...
virtual bool ReleaseStreamForApplication(ULWord inApplicationType, int32_t inProcessID)
Releases exclusive use of the AJA device for the given process, permitting other processes to acquire...
bool Is8BitFrameBufferFormat(const NTV2FrameBufferFormat fbFormat)
Definition: ntv2utils.cpp:5456
ULWord GetBytesPerRow(const UWord inPlaneIndex0=0) const
AJAStatus Add(FrameDataPtr pInFrameData)
Appends a new frame buffer to me, increasing my frame storage capacity by one frame.
#define BIT(_x_)
Definition: ajatypes.h:496
bool EnableSegmentedDMAs(const ULWord inNumSegments, const ULWord inNumActiveBytesPerLine, const ULWord inHostBytesPerLine, const ULWord inDeviceBytesPerLine)
Enables segmented DMAs given a segment count, a host pitch, and device pitch value.
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.
AJAStatus
Definition: types.h:380
ULWord GetCapturedAudioByteCount(void) const
virtual AJAStatus Run(void)
Runs me.
virtual bool IsDeviceReady(const bool inCheckValid=(0))
Identifies the 1st HDMI video input.
Definition: ntv2enums.h:1269
NTV2OutputDestination NTV2ChannelToOutputDestination(const NTV2Channel inChannel, const NTV2IOKinds inKinds=NTV2_IOKINDS_SDI)
Converts the given NTV2Channel value into its ordinary equivalent NTV2OutputDestination.
Definition: ntv2utils.cpp:5171
static uint64_t GetPid()
Definition: process.cpp:35
#define AJA_FAILURE(_status_)
Definition: types.h:373
virtual void StartCaptureThread(void)
Starts my capture thread.
virtual bool SubscribeOutputVerticalEvent(const NTV2Channel inChannel=NTV2_CHANNEL1)
Causes me to be notified when an output vertical blanking interrupt is generated for the given output...
Definition: ntv2card.h:2763
NTV2EmbeddedAudioInput NTV2InputSourceToEmbeddedAudioInput(const NTV2InputSource inInputSource)
Converts a given NTV2InputSource to its equivalent NTV2EmbeddedAudioInput value.
Definition: ntv2utils.cpp:4881
Declares the AJATime class.
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
bool IsProgressiveTransport(const NTV2VideoFormat format)
Definition: ntv2utils.cpp:5401
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_)
ULWord GetTotalBytes(void) const
bool CanAcceptMoreOutputFrames(void) const
virtual void RouteOutputSignal(void)
Sets up board routing for playout.
Definition: json.hpp:5362
virtual bool SetAudioRate(const NTV2AudioRate inRate, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Sets the NTV2AudioRate for the given Audio System.
Definition: ntv2audio.cpp:206
virtual AJAStatus Start()
Definition: thread.cpp:91
ULWord acInVideoDMAOffset
Optional byte offset into the device frame buffer. Defaults to zero. If non-zero, should be a multipl...
void EndConsumeNextBuffer(void)
The consumer thread calls this function to signal that it has finished processing the frame it obtain...
#define false
bool WithTimecode(void) const
uint32_t ULWord
Definition: ajatypes.h:236
virtual bool AutoCirculateGetStatus(const NTV2Channel inChannel, AUTOCIRCULATE_STATUS &outStatus)
Returns the current AutoCirculate status for the given channel.
virtual bool SetFrameBufferFormat(NTV2Channel inChannel, NTV2FrameBufferFormat inNewFormat, bool inIsAJARetail=(!(0)), NTV2HDRXferChars inXferChars=NTV2_VPID_TC_SDR_TV, NTV2HDRColorimetry inColorimetry=NTV2_VPID_Color_Rec709, NTV2HDRLuminance inLuminance=NTV2_VPID_Luminance_YCbCr)
Sets the frame buffer format for the given FrameStore on the AJA device.
NTV2Channel
These enum values are mostly used to identify a specific widget_framestore. They&#39;re also commonly use...
Definition: ntv2enums.h:1361
mVideoFormat
Definition: ntv2vcam.cpp:801
Identifies the 8th SDI video input.
Definition: ntv2enums.h:1280
virtual class DeviceCapabilities & features(void)
Definition: ntv2card.h:148
bool CanDoInputSource(const NTV2InputSource inSrc)
virtual bool SetMultiFormatMode(const bool inEnable)
Enables or disables multi-format (per channel) device operation. If enabled, each device channel can ...
Identifies the 2nd SDI video input.
Definition: ntv2enums.h:1274
#define NTV2_ASSERT(_expr_)
Definition: ajatypes.h:489
virtual bool ClearRouting(void)
Removes all existing signal path connections between any and all widgets on the AJA device...
NTV2ACFrameRange fOutputFrames
Playout frame count or range.
virtual AJAStatus SetupHostBuffers(void)
Sets up my circular buffers.
This struct replaces the old RP188_STRUCT.
int32_t appPID(0)
NTV2TCIndex NTV2ChannelToTimecodeIndex(const NTV2Channel inChannel, const bool inEmbeddedLTC=false, const bool inIsF2=false)
Converts the given NTV2Channel value into the equivalent NTV2TCIndex value.
Definition: ntv2utils.cpp:4966
#define NTV2_AUDIOSIZE_MAX
ULWord numPixels
Width – total number of pixels per line.
virtual bool Active()
Definition: thread.cpp:116
virtual void RouteInputSignal(void)
Sets up board routing for capture.
virtual bool GetTaskMode(NTV2TaskMode &outMode)
Retrieves the device&#39;s current task mode.
virtual bool SetAudioSystemInputSource(const NTV2AudioSystem inAudioSystem, const NTV2AudioSource inAudioSource, const NTV2EmbeddedAudioInput inEmbeddedInput)
Sets the audio source for the given NTV2AudioSystem on the device.
Definition: ntv2audio.cpp:486
NTV2OutputXptID GetInputSourceOutputXpt(const NTV2InputSource inInputSource, const bool inIsSDI_DS2=false, const bool inIsHDMI_RGB=false, const UWord inHDMI_Quadrant=0)
NTV2PixelFormat fPixelFormat
The pixel format to use.
static AJA_PixelFormat GetAJAPixelFormat(const NTV2PixelFormat inFormat)
NTV2Channel fOutputChannel
The output channel to use.
NTV2FrameRate
Identifies a particular video frame rate.
Definition: ntv2enums.h:416
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...
0: Disabled (never recommended): device configured exclusively by client application(s).
virtual std::string GetDescription(void) const
Definition: ntv2card.cpp:139
static TimecodeFormat NTV2FrameRate2TimecodeFormat(const NTV2FrameRate inFrameRate)
NTV2InputXptID GetOutputDestInputXpt(const NTV2OutputDestination inOutputDest, const bool inIsSDI_DS2=false, const UWord inHDMI_Quadrant=99)
virtual void CaptureFrames(void)
Repeatedly captures frames using AutoCirculate (until global quit flag set).
static bool GetFirstDeviceFromArgument(const std::string &inArgument, CNTV2Card &outDevice)
Rescans the host, and returns an open CNTV2Card instance for the AJA device that matches a command li...
virtual bool SetSDITransmitEnable(const NTV2Channel inChannel, const bool inEnable)
Sets the specified bidirectional SDI connector to act as an input or an output.
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 AJAStatus Init(void)
Initializes me and prepares me to Run.
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 ...
ULWord GetProcessedFrameCount(void) const
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...
Identifies the 3rd SDI video input.
Definition: ntv2enums.h:1275
NTV2InputXptID GetCSCInputXptFromChannel(const NTV2Channel inCSC, const bool inIsKeyInput=false)
virtual bool SubscribeInputVerticalEvent(const NTV2Channel inChannel=NTV2_CHANNEL1)
Causes me to be notified when an input vertical blanking interrupt occurs on the given input channel...
Definition: ntv2card.h:2787
virtual NTV2VideoFormat GetInputVideoFormat(const NTV2InputSource inVideoSource=NTV2_INPUTSOURCE_SDI1, const bool inIsProgressive=(0))
Returns the video format of the signal that is present on the given input source. ...
Describes a video frame for a given video standard or format and pixel format, including the total nu...
static void Sleep(const int32_t inMilliseconds)
Suspends execution of the current thread for a given number of milliseconds.
Definition: systemtime.cpp:284
NTV2FieldBurn(const BurnConfig &inConfig)
Constructs me using the given configuration settings.
2: OEM (recommended): device configured by client application(s) with some driver involvement...
NTV2InputXptID GetFrameStoreInputXptFromChannel(const NTV2Channel inFrameStore, const bool inIsBInput=false)
for(int i=0;i< g_cTemplates;i++)
Definition: dllentry.cpp:202
bool FieldMode(void) const
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...
Embeds silence (zeroes) into the data stream.
Definition: ntv2enums.h:2035
virtual bool SetVANCShiftMode(NTV2Channel inChannel, NTV2VANCDataShiftMode inMode)
Enables or disables the "VANC Shift Mode" feature for the given channel.
I capture individual fields from an interlaced video signal provided to an SDI input. Each frame is captured as two fields in separate host buffers. I burn F1 timecode into the top of F1, and F2 timecode into the bottom half of F2. Then I reassemble both fields and play them through an output of the same device, with a 7-frame latency (by default). I make use of the AJACircularBuffer, which simplifies implementing a producer/consumer model, in which a "consumer" thread delivers burned-in frames to the AJA device output, and a "producer" thread captures raw frames from the AJA device input. I also demonstrate how to detect if an SDI input has embedded timecode, and if so, how AutoCirculate makes it available. I also show how to embed timecode into an SDI output signal using AutoCirculate during playout.
Definition: ntv2fieldburn.h:32
Configures an NTV2Burn or NTV2FieldBurn instance.
LWord acTransferFrame
Frame buffer number the frame was transferred to/from. (-1 if failed)
Specifies channel or FrameStore 8 (or the 8th item).
Definition: ntv2enums.h:1370
AJA_EXPORT bool RenderTimeCodeFont(AJA_PixelFormat pixelFormat, uint32_t numPixels, uint32_t numLines)
Specifies channel or FrameStore 2 (or the 2nd item).
Definition: ntv2enums.h:1364
std::string NTV2TCIndexToString(const NTV2TCIndex inValue, const bool inCompactDisplay=false)
Definition: ntv2utils.cpp:6398
static const uint32_t kAppSignature(((((uint32_t)( 'F'))<< 24)|(((uint32_t)( 'l'))<< 16)|(((uint32_t)( 'd'))<< 8)|(((uint32_t)( 'B'))<< 0)))
Declares the CNTV2DeviceScanner class.
bool IsVerbose(void) const
LWord acDesiredFrame
Used to specify a different frame in the circulate ring to transfer to/from.
Identifies the 4th SDI video input.
Definition: ntv2enums.h:1276
virtual bool ReadRegister(const ULWord inRegNum, ULWord &outValue, const ULWord inMask=0xFFFFFFFF, const ULWord inShift=0)
Reads all or part of the 32-bit contents of a specific register (real or virtual) on the AJA device...
std::string fDeviceSpec
The AJA device to use.
#define NTV2_OUTPUT_DEST_IS_SDI(_dest_)
Definition: ntv2enums.h:1350
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...
Declares the AJAProcess class.
#define PLFAIL(_xpr_)
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).
NTV2InputSource
Identifies a specific video input source.
Definition: ntv2enums.h:1266
bool IsRGBFormat(const NTV2FrameBufferFormat format)
Definition: ntv2utils.cpp:5414
Identifies the 6th SDI video input.
Definition: ntv2enums.h:1278
This object specifies the information that will be transferred to or from the AJA device in the CNTV2...
virtual bool SetAudioBufferSize(const NTV2AudioBufferSize inValue, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Changes the size of the audio buffer that is used for a given Audio System in the AJA device...
Definition: ntv2audio.cpp:250
#define BURNNOTE(_expr_)
#define DEC(__x__)
virtual AJAStatus SetupVideo(void)
Sets up everything I need for capturing and playing video.
static bool GetWidgetForInput(const NTV2InputXptID inInputXpt, NTV2WidgetID &outWidgetID, const NTV2DeviceID inDeviceID=DEVICE_ID_NOTFOUND)
Returns the widget that "owns" the specified input crosspoint.
void EndProduceNextBuffer(void)
The producer thread calls this function to signal that it has finished populating the frame it obtain...
This identifies the first Audio System.
Definition: ntv2enums.h:3903
virtual bool WaitForOutputVerticalInterrupt(const NTV2Channel inChannel=NTV2_CHANNEL1, UWord inRepeatCount=1)
Efficiently sleeps the calling thread/process until the next one or more field (interlaced video) or ...
virtual void GetStatus(ULWord &outNumProcessed, ULWord &outCaptureDrops, ULWord &outPlayoutDrops, ULWord &outCaptureLevel, ULWord &outPlayoutLevel)
Provides status information about my input (capture) and output (playout) processes.
Identifies the 7th SDI video input.
Definition: ntv2enums.h:1279
static const size_t CIRCULAR_BUFFER_SIZE(10)
Number of NTV2FrameData&#39;s in our ring.
ULWord numLines
Height – total number of lines.
virtual AJAStatus Attach(AJAThreadFunction *pThreadFunction, void *pUserContext)
Definition: thread.cpp:169
ULWord acBufferLevel
Number of buffered frames in driver ready to capture or play.
FrameDataPtr StartProduceNextBuffer(void)
The thread that&#39;s responsible for providing frames – the producer – calls this function to populate...
NTV2OutputCrosspointID
Identifies a widget output, a signal source, that potentially can drive another widget&#39;s input (ident...
Definition: ntv2enums.h:2532
NTV2InputCrosspointID
Identifies a widget input that potentially can accept a signal emitted from another widget&#39;s output (...
Definition: ntv2enums.h:2757
bool fDoMultiFormat
If true, enables device-sharing; otherwise takes exclusive control of the device. ...
bool GetInputTimeCodes(NTV2TimeCodeList &outValues) const
Intended for capture, answers with the timecodes captured in my acTransferStatus member&#39;s acFrameStam...
This is returned from the CNTV2Card::AutoCirculateGetStatus function.
NTV2OutputXptID GetFrameStoreOutputXptFromChannel(const NTV2Channel inFrameStore, const bool inIsRGB=false, const bool inIs425=false)
NTV2WidgetID
Definition: ntv2enums.h:2914
NTV2ACFrameRange fInputFrames
Ingest frame count or range.
uint16_t UWord
Definition: ajatypes.h:234
ULWord acFramesDropped
Total number of frames dropped since CNTV2Card::AutoCirculateStart called.
Specifies channel or FrameStore 1 (or the first item).
Definition: ntv2enums.h:1363
virtual bool UnsubscribeInputVerticalEvent(const NTV2Channel inChannel=NTV2_CHANNEL1)
Unregisters me so I&#39;m no longer notified when an input VBI is signaled on the given input channel...
Definition: ntv2card.h:2837
virtual bool AutoCirculateStart(const NTV2Channel inChannel, const ULWord64 inStartTime=0)
Starts AutoCirculate streaming for the specified channel that was previously initialized by CNTV2Card...
AUTOCIRCULATE_TRANSFER_STATUS acTransferStatus
Contains status information that&#39;s valid after CNTV2Card::AutoCirculateTransfer returns, including the driver buffer level, number of frames processed or dropped, audio and anc transfer byte counts, and a complete FRAME_STAMP that has even more detailed clocking information.
bool CanDoFrameBufferFormat(const NTV2PixelFormat inPF)
ULWord appSignature(0)
virtual bool AutoCirculateInitForOutput(const NTV2Channel inChannel, const UWord inFrameCount=7, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_INVALID, const ULWord inOptionFlags=0, const UByte inNumChannels=1, const UWord inStartFrameNumber=0, const UWord inEndFrameNumber=0)
Prepares for subsequent AutoCirculate playback streaming, designating a contiguous block of frame buf...
bool CanDoWidget(const NTV2WidgetID inWgtID)
TimecodeFormat
Definition: ntv2rp188.h:22
#define NTV2_IS_VALID_AUDIO_SYSTEM(__x__)
Definition: ntv2enums.h:3920
std::string NTV2FrameBufferFormatToString(const NTV2FrameBufferFormat inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:6940
#define ToCharPtr(_p_)
AJA_EXPORT bool BurnTimeCode(void *pBaseVideoAddress, const std::string &inTimeCodeStr, const uint32_t inYPercent)
I encapsulate the video, audio and anc host buffers used in the AutoCirculate demos. I&#39;m a more modern version of the AVDataBuffer.
NTV2Buffer fVideoBuffer
Host video buffer.
NTV2AudioSystem NTV2ChannelToAudioSystem(const NTV2Channel inChannel)
Converts the given NTV2Channel value into its equivalent NTV2AudioSystem.
Definition: ntv2utils.cpp:4873
bool HasAvailableInputFrame(void) const
Specifies channel or FrameStore 4 (or the 4th item).
Definition: ntv2enums.h:1366
virtual void Quit(void)
Gracefully stops me from running.
NTV2Channel fInputChannel
The input channel to use.
Specifies channel or FrameStore 5 (or the 5th item).
Definition: ntv2enums.h:1367
Identifies the first analog video input.
Definition: ntv2enums.h:1268
NTV2TCIndex fTimecodeSource
Timecode source to use.
bool GetRP188Reg(RP188_STRUCT &outRP188) const
Definition: ntv2rp188.cpp:1241
std::vector< uint32_t > ULWordSequence
An ordered sequence of ULWord (uint32_t) values.
bool IsRunning(void) const
void * GetHostPointer(void) const
NTV2AudioSource NTV2InputSourceToAudioSource(const NTV2InputSource inInputSource)
Definition: ntv2utils.cpp:4905
Identifies the first field in time for an interlaced video frame, or the first and only field in a pr...
Definition: ntv2enums.h:1847
static size_t SetDefaultPageSize(void)
#define BURNFAIL(_expr_)
ULWord linePitch
Number of 32-bit words per line – shadows mLinePitch[0] / sizeof(ULWord)
virtual bool DisableRP188Bypass(const NTV2Channel inSDIOutput)
Configures the SDI output&#39;s embedder to embed SMPTE 12M timecode specified in calls to CNTV2Card::Set...
NTV2TCIndexes::const_iterator NTV2TCIndexesConstIter
Specifies channel or FrameStore 6 (or the 6th item).
Definition: ntv2enums.h:1368
virtual void PlayFrames(void)
Repeatedly plays out frames using AutoCirculate (until global quit flag set).
virtual ~NTV2FieldBurn()
virtual bool AutoCirculateInitForInput(const NTV2Channel inChannel, const UWord inFrameCount=7, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_INVALID, const ULWord inOptionFlags=0, const UByte inNumChannels=1, const UWord inStartFrameNumber=0, const UWord inEndFrameNumber=0)
Prepares for subsequent AutoCirculate ingest streaming, designating a contiguous block of frame buffe...
#define BURNINFO(_expr_)
#define AUTOCIRCULATE_WITH_RP188
Use this to AutoCirculate with RP188.
Specifies channel or FrameStore 7 (or the 7th item).
Definition: ntv2enums.h:1369
#define NTV2_INPUT_SOURCE_IS_SDI(_inpSrc_)
Definition: ntv2enums.h:1287
bool GetRP188Str(std::string &sRP188) const
Definition: ntv2rp188.cpp:918
std::string & lower(std::string &str)
Definition: common.cpp:436
std::string NTV2ChannelListToStr(const NTV2ChannelList &inObj, const bool inCompact=true)
bool SetAudioBuffer(ULWord *pInAudioBuffer, const ULWord inAudioByteCount)
Sets my audio buffer for use in a subsequent call to CNTV2Card::AutoCirculateTransfer.
Identifies the 1st SDI video input.
Definition: ntv2enums.h:1273
#define PLDBG(_xpr_)
#define AUTOCIRCULATE_WITH_FIELDS
Use this to AutoCirculate with fields as frames for interlaced formats.
NTV2InputXptID GetSDIOutputInputXpt(const NTV2Channel inSDIOutput, const bool inIsDS2=false)
virtual bool SetVANCMode(const NTV2VANCMode inVancMode, const NTV2Channel inChannel=NTV2_CHANNEL1)
Sets the VANC mode for the given FrameStore.
virtual bool GetStreamingApplication(ULWord &outAppType, int32_t &outProcessID)
Answers with the four-CC type and process ID of the application that currently "owns" the AJA device ...
virtual bool SetNumberAudioChannels(const ULWord inNumChannels, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Sets the number of audio channels to be concurrently captured or played for a given Audio System on t...
Definition: ntv2audio.cpp:147
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...
#define AUTOCIRCULATE_FRAME_FIELD0
Frame contains field 0 of an interlaced image (first field in time)
virtual bool InputSignalHasTimecode(void)
Returns true if the current input signal has timecode embedded in it; otherwise returns false...
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 ...
virtual bool IsRP188BypassEnabled(const NTV2Channel inSDIOutput, bool &outIsBypassEnabled)
Answers if the SDI output&#39;s RP-188 bypass mode is enabled or not.
virtual void StartPlayThread(void)
Starts my playout thread.
ULWord acFramesProcessed
Total number of frames successfully processed since CNTV2Card::AutoCirculateStart called...
This identifies the mode in which there are no VANC lines in the frame buffer.
Definition: ntv2enums.h:3805
bool SetVideoBuffer(ULWord *pInVideoBuffer, const ULWord inVideoByteCount)
Sets my video buffer for use in a subsequent call to CNTV2Card::AutoCirculateTransfer.
Specifies channel or FrameStore 3 (or the 3rd item).
Definition: ntv2enums.h:1365
NTV2InputSource fInputSource
The device input connector to use.
virtual bool EnableChannel(const NTV2Channel inChannel)
Enables the given FrameStore.