AJA NTV2 SDK  18.0.0.2122
NTV2 SDK 18.0.0.2122
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()),
29  mDeviceID (DEVICE_ID_NOTFOUND),
31  mSavedTaskMode (NTV2_DISABLE_TASKS),
32  mOutputDest (NTV2_OUTPUTDESTINATION_INVALID),
33  mAudioSystem (inConfig.WithAudio() ? NTV2_AUDIOSYSTEM_1 : NTV2_AUDIOSYSTEM_INVALID),
34  mGlobalQuit (false)
35 {
36 } // constructor
37 
38 
40 {
41  Quit(); // Stop my capture and playout threads, then destroy them
42  mDevice.UnsubscribeInputVerticalEvent(mConfig.fInputChannel); // Unsubscribe from input VBI event
43 } // destructor
44 
45 
47 {
48  // Set the global 'quit' flag, and wait for the threads to go inactive...
49  mGlobalQuit = true;
50 
51  while (mPlayThread.Active())
52  AJATime::Sleep(10);
53 
54  while (mCaptureThread.Active())
55  AJATime::Sleep(10);
56 
57  if (!mConfig.fDoMultiFormat)
58  { // Release the device...
60  if (NTV2_IS_VALID_TASK_MODE(mSavedTaskMode))
61  mDevice.SetTaskMode(mSavedTaskMode); // Restore prior task mode
62  }
63 } // Quit
64 
65 
67 {
69 
70  // Open the device...
72  {cerr << "## ERROR: Device '" << mConfig.fDeviceSpec << "' not found" << endl; return AJA_STATUS_OPEN;}
73 
74  if (!mDevice.IsDeviceReady (false))
75  {cerr << "## ERROR: Device '" << mConfig.fDeviceSpec << "' not ready" << endl; return AJA_STATUS_INITIALIZE;}
76 
77  mDeviceID = mDevice.GetDeviceID(); // Keep the device ID handy since it will be used frequently
78  if (!mDevice.features().CanDoCapture())
79  {cerr << "## ERROR: Device '" << mDeviceID << "' cannot capture" << endl; return AJA_STATUS_FEATURE;}
80  if (!mDevice.features().CanDoPlayback())
81  {cerr << "## ERROR: Device '" << mDeviceID << "' cannot playout" << endl; return AJA_STATUS_FEATURE;}
82 
83  ULWord appSignature (0);
84  int32_t appPID (0);
85  mDevice.GetStreamingApplication (appSignature, appPID); // Who currently "owns" the device?
86  mDevice.GetTaskMode(mSavedTaskMode); // Save the current device state
87  if (!mConfig.fDoMultiFormat)
88  {
90  {
91  cerr << "## ERROR: Unable to acquire device because another app (pid " << appPID << ") owns it" << endl;
92  return AJA_STATUS_BUSY; // Some other app is using the device
93  }
94  mDevice.ClearRouting(); // Clear the current device routing (since I "own" the device)
95  }
96  mDevice.SetTaskMode(NTV2_OEM_TASKS); // Force OEM tasks
97 
98  // Set up the video and audio...
99  status = SetupVideo();
100  if (AJA_FAILURE(status))
101  return status;
102 
103  if (NTV2_IS_VALID_AUDIO_SYSTEM(mAudioSystem))
104  status = SetupAudio();
105  if (AJA_FAILURE(status))
106  return status;
107 
108  // Set up the circular buffers...
109  status = SetupHostBuffers();
110  if (AJA_FAILURE(status))
111  return status;
112 
113  // Set up the signal routing...
116 
117  // Lastly, prepare my AJATimeCodeBurn instance...
119  mFormatDesc.numPixels,
120  mFormatDesc.numLines);
121  // Ready to go...
122  #if defined(_DEBUG)
123  cerr << mConfig << endl;
124  #endif // not _DEBUG
125  BURNINFO("Configuration: " << mConfig);
126  return AJA_STATUS_SUCCESS;
127 
128 } // Init
129 
130 
132 {
133  const UWord numFrameStores (mDevice.features().GetNumFrameStores());
134 
135  // Does this device have the requested input source?
136  if (!mDevice.features().CanDoInputSource(mConfig.fInputSource))
137  {cerr << "## ERROR: Device does not have the specified input source" << endl; return AJA_STATUS_BAD_PARAM;}
138 
139  // Pick an input NTV2Channel from the input source, and enable its frame buffer...
141  mDevice.EnableChannel(mConfig.fInputChannel); // Enable the input frame buffer
142 
143  // Pick an appropriate output NTV2Channel, and enable its frame buffer...
144  switch (mConfig.fInputSource)
145  {
146  case NTV2_INPUTSOURCE_SDI1: mConfig.fOutputChannel = (numFrameStores == 2 || numFrameStores > 4) ? NTV2_CHANNEL2 : NTV2_CHANNEL3;
147  break;
148 
149  case NTV2_INPUTSOURCE_SDI2: mConfig.fOutputChannel = (numFrameStores > 4) ? NTV2_CHANNEL3 : NTV2_CHANNEL4;
150  break;
151 
153  break;
154 
155  case NTV2_INPUTSOURCE_SDI4: mConfig.fOutputChannel = (numFrameStores > 4) ? NTV2_CHANNEL5 : NTV2_CHANNEL3;
156  break;
157 
158  case NTV2_INPUTSOURCE_SDI5: mConfig.fOutputChannel = NTV2_CHANNEL6; break;
159  case NTV2_INPUTSOURCE_SDI6: mConfig.fOutputChannel = NTV2_CHANNEL7; break;
160  case NTV2_INPUTSOURCE_SDI7: mConfig.fOutputChannel = NTV2_CHANNEL8; break;
161  case NTV2_INPUTSOURCE_SDI8: mConfig.fOutputChannel = NTV2_CHANNEL7; break;
162 
164  case NTV2_INPUTSOURCE_HDMI1: mConfig.fOutputChannel = numFrameStores < 3 ? NTV2_CHANNEL2 : NTV2_CHANNEL3;
165  break;
166  default:
167  case NTV2_INPUTSOURCE_INVALID: cerr << "## ERROR: Bad input source" << endl; return AJA_STATUS_BAD_PARAM;
168  }
169  mDevice.EnableChannel(mConfig.fOutputChannel); // Enable the output frame buffer
170 
171  // Enable/subscribe interrupts...
172  mDevice.EnableInputInterrupt(mConfig.fInputChannel);
174  mDevice.EnableOutputInterrupt(mConfig.fOutputChannel);
176 
177  // Pick an appropriate output spigot based on the output channel...
178  mOutputDest = ::NTV2ChannelToOutputDestination(mConfig.fOutputChannel);
179  if (!mDevice.features().CanDoWidget(NTV2_Wgt12GSDIOut2)
180  && !mDevice.features().CanDoWidget(NTV2_Wgt3GSDIOut2)
181  && !mDevice.features().CanDoWidget(NTV2_WgtSDIOut2))
182  mOutputDest = NTV2_OUTPUTDESTINATION_SDI1; // If device has only one SDI output
183  if (mDevice.features().HasBiDirectionalSDI() // If device has bidirectional SDI connectors...
184  && NTV2_OUTPUT_DEST_IS_SDI(mOutputDest)) // ...and output destination is SDI...
185  mDevice.SetSDITransmitEnable (mConfig.fOutputChannel, true); // ...then enable transmit mode
186 
187  // Flip the input spigot to "receive" if necessary...
188  bool isXmit (false);
189  if (mDevice.features().HasBiDirectionalSDI() // If device has bidirectional SDI connectors...
190  && NTV2_INPUT_SOURCE_IS_SDI(mConfig.fInputSource) // ...and desired input source is SDI...
191  && mDevice.GetSDITransmitEnable (mConfig.fInputChannel, isXmit) // ...and GetSDITransmitEnable succeeds...
192  && isXmit) // ...and input is set to "transmit"...
193  {
194  mDevice.SetSDITransmitEnable (mConfig.fInputChannel, false); // ...then disable transmit mode...
195  mDevice.WaitForOutputVerticalInterrupt (mConfig.fOutputChannel, 10); // ...and allow device to lock to input signal
196  } // if input SDI connector needs to switch from transmit mode
197 
198  // Is there an input signal? What format is it?
199  mVideoFormat = mDevice.GetInputVideoFormat(mConfig.fInputSource);
200  if (mVideoFormat == NTV2_FORMAT_UNKNOWN)
201  {cerr << "## ERROR: No input signal, or can't handle its format" << endl; return AJA_STATUS_NOINPUT;}
202 
203  // This demo requires an interlaced signal...
204  if (IsProgressiveTransport(mVideoFormat))
205  {cerr << "## ERROR: Input signal is progressive -- no fields" << endl; return AJA_STATUS_UNSUPPORTED;}
206 
207  // Free-run the device clock, since E-to-E mode isn't used, nor is a mixer tied to the input...
209 
210  // Check the timecode source...
211  if (!InputSignalHasTimecode())
212  cerr << "## WARNING: Timecode source '" << ::NTV2TCIndexToString(mConfig.fTimecodeSource, true) << "' has no embedded timecode" << endl;
213 
214  // If the device supports different per-channel video formats, configure it as requested...
215  if (mDevice.features().CanDoMultiFormat())
216  mDevice.SetMultiFormatMode (mConfig.fDoMultiFormat);
217 
218  // Set the input/output channel video formats to the video format that was detected earlier...
219  mDevice.SetVideoFormat (mVideoFormat, false, false, mDevice.features().CanDoMultiFormat() ? mConfig.fInputChannel : NTV2_CHANNEL1);
220  if (mDevice.features().CanDoMultiFormat()) // If device supports multiple formats per-channel...
221  mDevice.SetVideoFormat (mVideoFormat, false, false, mConfig.fOutputChannel); // ...then also set the output channel format to the detected input format
222 
223  // Can the device handle the requested frame buffer pixel format?
224  if (!mDevice.features().CanDoFrameBufferFormat(mConfig.fPixelFormat))
225  {cerr << "## ERROR: " << ::NTV2FrameBufferFormatToString(mConfig.fPixelFormat) << " unsupported" << endl; return AJA_STATUS_UNSUPPORTED;}
226 
227  // Set both input and output frame buffers' pixel formats...
228  mDevice.SetFrameBufferFormat (mConfig.fInputChannel, mConfig.fPixelFormat);
229  mDevice.SetFrameBufferFormat (mConfig.fOutputChannel, mConfig.fPixelFormat);
230 
231  // Normally, timecode embedded in the output signal comes from whatever is written into the RP188
232  // registers (30/31 for SDI out 1, 65/66 for SDIout2, etc.).
233  // AutoCirculate automatically writes the timecode in the AUTOCIRCULATE_TRANSFER's acRP188 field
234  // into these registers (if AutoCirculateInitForOutput was called with AUTOCIRCULATE_WITH_RP188 set).
235  // Newer AJA devices can also bypass these RP188 registers, and simply copy whatever timecode appears
236  // at any SDI input (called the "bypass source"). To ensure that AutoCirculate's playout timecode
237  // will actually be seen in the output signal, "bypass mode" must be disabled...
238  bool bypassIsEnabled (false);
239  mDevice.IsRP188BypassEnabled (::NTV2InputSourceToChannel(mConfig.fInputSource), bypassIsEnabled);
240  if (bypassIsEnabled)
242 
243  // Now that newer AJA devices can capture/play anc data from separate buffers,
244  // there's no need to enable VANC frame geometries...
245  mDevice.SetVANCMode (NTV2_VANCMODE_OFF, mConfig.fInputChannel);
246  mDevice.SetVANCMode (NTV2_VANCMODE_OFF, mConfig.fOutputChannel);
247  if (::Is8BitFrameBufferFormat (mConfig.fPixelFormat))
248  { // 8-bit FBFs: since not using VANC geometries, disable bit shift...
251  }
252 
253  // Now that the video is set up, get information about the current frame geometry...
254  mFormatDesc = NTV2FormatDescriptor (mVideoFormat, mConfig.fPixelFormat);
255  if (mFormatDesc.IsPlanar())
256  {cerr << "## ERROR: This demo doesn't work with planar pixel formats" << endl; return AJA_STATUS_UNSUPPORTED;}
257  return AJA_STATUS_SUCCESS;
258 
259 } // SetupVideo
260 
261 
263 {
264  if (!NTV2_IS_VALID_AUDIO_SYSTEM (mAudioSystem))
265  return AJA_STATUS_SUCCESS;
266 
267  if (mConfig.fDoMultiFormat)
268  if (mDevice.features().GetNumAudioSystems() > 1)
269  if (UWord(mConfig.fInputChannel) < mDevice.features().GetNumAudioSystems())
270  mAudioSystem = ::NTV2ChannelToAudioSystem(mConfig.fInputChannel);
271 
272  // Have the audio subsystem capture audio from the designated input source...
273  mDevice.SetAudioSystemInputSource (mAudioSystem, ::NTV2InputSourceToAudioSource(mConfig.fInputSource),
275 
276  // It's best to use all available audio channels...
277  mDevice.SetNumberAudioChannels (mDevice.features().GetMaxAudioChannels(), mAudioSystem);
278 
279  // Assume 48kHz PCM...
280  mDevice.SetAudioRate (NTV2_AUDIO_48K, mAudioSystem);
281 
282  // 4MB device audio buffers work best...
283  mDevice.SetAudioBufferSize (NTV2_AUDIO_BUFFER_BIG, mAudioSystem);
284 
285  // Set up the output audio embedders...
286  if (mDevice.features().GetNumAudioSystems() > 1)
287  {
288  // Some devices, like the Kona1, have 2 FrameStores but only 1 SDI output,
289  // which makes mConfig.fOutputChannel == NTV2_CHANNEL2, but need SDIoutput to be NTV2_CHANNEL1...
290  UWord SDIoutput(mConfig.fOutputChannel);
291  if (SDIoutput >= mDevice.features().GetNumVideoOutputs())
292  SDIoutput = mDevice.features().GetNumVideoOutputs() - 1;
293  mDevice.SetSDIOutputAudioSystem (NTV2Channel(SDIoutput), mAudioSystem);
294  }
295 
296  //
297  // Loopback mode plays whatever audio appears in the input signal when it's
298  // connected directly to an output (i.e., "end-to-end" mode). If loopback is
299  // left enabled, the video will lag the audio as video frames get briefly delayed
300  // in our ring buffer. Audio, therefore, needs to come out of the (buffered) frame
301  // data being played, so loopback must be turned off...
302  //
303  mDevice.SetAudioLoopBack (NTV2_AUDIO_LOOPBACK_OFF, mAudioSystem);
304  return AJA_STATUS_SUCCESS;
305 
306 } // SetupAudio
307 
308 
310 {
311  ULWordSequence failures;
312  CNTV2DemoCommon::SetDefaultPageSize(); // Set host-specific page size
313 
314  // Let my circular buffer know when it's time to quit...
315  mFrameDataRing.SetAbortFlag(&mGlobalQuit);
316 
317  // Make the video buffers half the size of a full frame (i.e. field-size)...
318  const ULWord vidBuffSizeBytes (mFormatDesc.GetTotalBytes() / 2);
319  NTV2_ASSERT(mFormatDesc.GetBytesPerRow() == mFormatDesc.linePitch * 4);
320 
321  // Allocate and add each in-host NTV2FrameData to my circular buffer member variable...
322  mHostBuffers.reserve(CIRCULAR_BUFFER_SIZE);
323  while (mHostBuffers.size() < CIRCULAR_BUFFER_SIZE)
324  {
325  mHostBuffers.push_back(NTV2FrameData()); // Make a new NTV2FrameData...
326  NTV2FrameData & frameData (mHostBuffers.back()); // ...and get a reference to it
327 
328  // In Field Mode, one buffer is used to hold each field's video data.
329  frameData.fVideoBuffer.Allocate (vidBuffSizeBytes, /*pageAligned*/true);
330  if (!mConfig.FieldMode())
331  { // In Frame Mode, use two buffers, one for each field. The DMA transfer
332  // of each field will be done as a group of lines, with each line considered a "segment".
333  frameData.fVideoBuffer2.Allocate (vidBuffSizeBytes, /*pageAligned*/true);
334  }
335 
336  // Allocate a page-aligned audio buffer (if handling audio)...
337  if (NTV2_IS_VALID_AUDIO_SYSTEM(mAudioSystem))
338  frameData.fAudioBuffer.Allocate (NTV2_AUDIOSIZE_MAX, /*pageAligned*/true);
339  if (frameData.AudioBuffer())
340  frameData.fAudioBuffer.Fill(ULWord(0));
341 
342  // Check for memory allocation failures...
343  if (!frameData.VideoBuffer()
344  || (NTV2_IS_VALID_AUDIO_SYSTEM(mAudioSystem) && !frameData.AudioBuffer())
345  || (!frameData.VideoBuffer2() && !mConfig.FieldMode()))
346  failures.push_back(ULWord(mHostBuffers.size()+1));
347 
348  // Add this NTV2FrameData to the ring...
349  mFrameDataRing.Add (&frameData);
350  } // for each NTV2FrameData
351 
352  if (!failures.empty())
353  {
354  cerr << "## ERROR: " << DEC(failures.size()) << " allocation failures in buffer(s): " << failures << endl;
355  return AJA_STATUS_MEMORY;
356  }
357  return AJA_STATUS_SUCCESS;
358 
359 } // SetupHostBuffers
360 
361 
363 {
364  const NTV2OutputCrosspointID inputOutputXpt (::GetInputSourceOutputXpt (mConfig.fInputSource));
366  const bool isRGB (::IsRGBFormat(mConfig.fPixelFormat));
367 
368  if (isRGB)
369  {
370  // If the frame buffer is configured for RGB pixel format, incoming YUV must be converted.
371  // This routes the video signal from the input through a color space converter before
372  // connecting to the RGB frame buffer...
373  const NTV2InputCrosspointID cscVideoInputXpt (::GetCSCInputXptFromChannel (mConfig.fInputChannel));
374  const NTV2OutputCrosspointID cscOutputXpt (::GetCSCOutputXptFromChannel (mConfig.fInputChannel, false/*isKey*/, true/*isRGB*/));
375 
376  mDevice.Connect (cscVideoInputXpt, inputOutputXpt); // Connect the CSC's video input to the input spigot's output
377  mDevice.Connect (fbInputXpt, cscOutputXpt); // Connect the frame store's input to the CSC's output
378  }
379  else
380  mDevice.Connect (fbInputXpt, inputOutputXpt); // Route the YCbCr signal directly from the input to the frame buffer's input
381 
382 } // RouteInputSignal
383 
384 
386 {
387  const NTV2InputCrosspointID outputInputXpt (::GetOutputDestInputXpt (mOutputDest));
389  const bool isRGB (::IsRGBFormat(mConfig.fPixelFormat));
390  NTV2OutputCrosspointID outputXpt (fbOutputXpt);
391 
392  if (isRGB)
393  {
394  const NTV2OutputCrosspointID cscVidOutputXpt (::GetCSCOutputXptFromChannel (mConfig.fOutputChannel, false, true));
395  const NTV2InputCrosspointID cscVidInputXpt (::GetCSCInputXptFromChannel (mConfig.fOutputChannel));
396 
397  mDevice.Connect (cscVidInputXpt, fbOutputXpt); // Connect the CSC's video input to the frame store's output
398  mDevice.Connect (outputInputXpt, cscVidOutputXpt); // Connect the SDI output's input to the CSC's video output
399  outputXpt = cscVidOutputXpt;
400  }
401  else
402  mDevice.Connect (outputInputXpt, outputXpt);
403 
404  mTCOutputs.clear();
405  mTCOutputs.push_back(mConfig.fOutputChannel);
406 
407  if (!mConfig.fDoMultiFormat)
408  {
409  // Route all SDI outputs to the outputXpt...
410  const NTV2Channel startNum (NTV2_CHANNEL1);
411  const NTV2Channel endNum (NTV2Channel(mDevice.features().GetNumVideoChannels()));
412  NTV2WidgetID outputWidgetID (NTV2_WIDGET_INVALID);
413 
414  for (NTV2Channel chan(startNum); chan < endNum; chan = NTV2Channel(chan+1))
415  {
416  if (chan == mConfig.fInputChannel || chan == mConfig.fOutputChannel)
417  continue; // Skip the input & output channel, already routed
418  if (mDevice.features().HasBiDirectionalSDI())
419  mDevice.SetSDITransmitEnable (chan, true);
420  if (CNTV2SignalRouter::GetWidgetForInput (::GetSDIOutputInputXpt (chan, mDevice.features().CanDoDualLink()), outputWidgetID))
421  if (mDevice.features().CanDoWidget(outputWidgetID))
422  {
423  mDevice.Connect (::GetSDIOutputInputXpt(chan), outputXpt);
424  mTCOutputs.push_back(chan);
425  }
426  } // for each output spigot
427 
428  // If HDMI and/or analog video outputs are available, route them, too...
429  if (mDevice.features().CanDoWidget(NTV2_WgtHDMIOut1))
430  mDevice.Connect (NTV2_XptHDMIOutInput, outputXpt); // Route output signal to HDMI output
431  if (mDevice.features().CanDoWidget(NTV2_WgtHDMIOut1v2))
432  mDevice.Connect (NTV2_XptHDMIOutQ1Input, outputXpt); // Route output signal to HDMI output
433  if (mDevice.features().CanDoWidget(NTV2_WgtAnalogOut1))
434  mDevice.Connect (NTV2_XptAnalogOutInput, outputXpt); // Route output signal to Analog output
435  if (mDevice.features().CanDoWidget(NTV2_WgtSDIMonOut1))
436  { // SDI Monitor output is spigot 4 (NTV2_CHANNEL5):
437  mDevice.Connect (::GetSDIOutputInputXpt(NTV2_CHANNEL5), outputXpt); // Route output signal to SDI monitor output
438  mTCOutputs.push_back(NTV2_CHANNEL5);
439  }
440  } // if not multiChannel
441  PLDBG(mTCOutputs.size() << " timecode destination(s): " << ::NTV2ChannelListToStr(mTCOutputs));
442 
443 } // RouteOutputSignal
444 
445 
447 {
448  // Start the playout and capture threads...
449  StartPlayThread();
451  return AJA_STATUS_SUCCESS;
452 
453 } // Run
454 
455 
456 
458 
459 // This is where we will start the play thread
461 {
462  // Create and start the playout thread...
463  mPlayThread.Attach(PlayThreadStatic, this);
465  mPlayThread.Start();
466 
467 } // StartPlayThread
468 
469 
470 // The playout thread function
471 void NTV2FieldBurn::PlayThreadStatic (AJAThread * pThread, void * pContext) // static
472 { (void) pThread;
473  // Grab the NTV2FieldBurn instance pointer from the pContext parameter,
474  // then call its PlayFrames method...
475  NTV2FieldBurn * pApp (reinterpret_cast<NTV2FieldBurn*>(pContext));
476  pApp->PlayFrames();
477 
478 } // PlayThreadStatic
479 
480 
482 {
483  const ULWord acOptions (AUTOCIRCULATE_WITH_RP188 | (mConfig.FieldMode() ? AUTOCIRCULATE_WITH_FIELDS : 0));
484  ULWord goodXfers(0), badXfers(0), starves(0), noRoomWaits(0);
485  AUTOCIRCULATE_TRANSFER outputXferInfo; // F1 transfer info
486  AUTOCIRCULATE_TRANSFER outputXferInfo2; // F2 transfer info (unused in Field Mode)
487  AUTOCIRCULATE_STATUS outputStatus;
488 
489  // Stop AutoCirculate on this channel, just in case some other app left it running...
490  mDevice.AutoCirculateStop(mConfig.fOutputChannel);
491  mDevice.WaitForOutputVerticalInterrupt(mConfig.fOutputChannel, 4); // Let it stop
492  BURNNOTE("Thread started");
493 
494  if (!mConfig.FieldMode())
495  {
496  // In Frame Mode, tell AutoCirculate to DMA F1's data as a group of "segments".
497  // Each segment is one line long, and the segments are contiguous in host
498  // memory, but are stored on every other line in the device frame buffer...
499  outputXferInfo.EnableSegmentedDMAs (mFormatDesc.numLines / 2, // number of segments: number of lines per field, i.e. half the line count
500  mFormatDesc.linePitch * 4, // number of active bytes per line
501  mFormatDesc.linePitch * 4, // host bytes per line: normal line pitch when reading from our half-height buffer
502  mFormatDesc.linePitch * 8); // device bytes per line: skip every other line when writing into device memory
503 
504  // F2 is identical to F1, except that F2 starts on 2nd line in device frame buffer...
505  outputXferInfo2.EnableSegmentedDMAs (mFormatDesc.numLines / 2, // number of segments: number of lines per field, i.e. half the line count
506  mFormatDesc.linePitch * 4, // number of active bytes per line
507  mFormatDesc.linePitch * 4, // host bytes per line: normal line pitch when reading from our half-height buffer
508  mFormatDesc.linePitch * 8); // device bytes per line: skip every other line when writing into device memory
509  outputXferInfo2.acInVideoDMAOffset = mFormatDesc.linePitch * 4; // F2 starts on 2nd line in device buffer
510  }
511 
512  // Initialize AutoCirculate...
513  if (!mDevice.AutoCirculateInitForOutput (mConfig.fOutputChannel, mConfig.fOutputFrames, mAudioSystem, acOptions))
514  {PLFAIL("AutoCirculateInitForOutput failed"); mGlobalQuit = true;}
515 
516  while (!mGlobalQuit)
517  {
518  mDevice.AutoCirculateGetStatus (mConfig.fOutputChannel, outputStatus);
519 
520  // Check if there's room for another frame on the card...
521  if (outputStatus.CanAcceptMoreOutputFrames())
522  {
523  // Device has at least one free frame buffer that can be filled.
524  // Wait for the next frame in our ring to become ready to "consume"...
525  NTV2FrameData * pFrameData (mFrameDataRing.StartConsumeNextBuffer());
526  if (!pFrameData)
527  {starves++; continue;} // Producer thread isn't producing frames fast enough
528 
529  // Prepare to transfer the timecode-burned field (F1) to the device for playout.
530  // Set the outputXfer struct's video and audio buffers from playData's buffers...
531  // IMPORTANT: In Frame Mode, for segmented DMAs, AutoCirculateTransfer expects the video
532  // buffer size to be set to the segment size, in bytes, which is one raster line length.
533  outputXferInfo.SetVideoBuffer (pFrameData->VideoBuffer(),
534  mConfig.FieldMode() ? pFrameData->VideoBufferSize() // Field Mode
535  : mFormatDesc.GetBytesPerRow()); // Frame Mode
536  if (pFrameData->AudioBuffer())
537  outputXferInfo.SetAudioBuffer (pFrameData->AudioBuffer(), pFrameData->AudioBufferSize());
538  if (mConfig.FieldMode())
539  outputXferInfo.acPeerToPeerFlags = pFrameData->fFrameFlags; // Which field was this?
540 
541  // Tell AutoCirculate to embed this frame's timecode into the SDI output(s)...
542  outputXferInfo.SetOutputTimeCodes(pFrameData->fTimecodes);
543  PLDBG(pFrameData->fTimecodes);
544 
545  // Transfer field to the device...
546  if (mDevice.AutoCirculateTransfer (mConfig.fOutputChannel, outputXferInfo))
547  goodXfers++;
548  else
549  badXfers++;
550 
551  if (!mConfig.FieldMode())
552  { // Frame Mode: Additionally transfer F2 to the same device frame buffer used for F1.
553  // Again, for segmented DMAs, AutoCirculateTransfer expects the video buffer size to be
554  // set to the segment size, in bytes, which is one raster line length.
555  outputXferInfo2.acDesiredFrame = outputXferInfo.acTransferStatus.acTransferFrame;
556  outputXferInfo2.SetVideoBuffer (pFrameData->VideoBuffer2(), mFormatDesc.GetBytesPerRow());
557  if (mDevice.AutoCirculateTransfer (mConfig.fOutputChannel, outputXferInfo2))
558  goodXfers++;
559  else
560  badXfers++;
561  }
562 
563  if (goodXfers == 6) // Start AutoCirculate playout once 6 fields are buffered on the device...
564  mDevice.AutoCirculateStart(mConfig.fOutputChannel);
565 
566  // Signal that the frame has been "consumed"...
567  mFrameDataRing.EndConsumeNextBuffer();
568  continue; // Back to top of while loop
569  } // if CanAcceptMoreOutputFrames
570 
571  // Wait for one or more buffers to become available on the device, which should occur at next VBI...
572  noRoomWaits++;
574  } // loop til quit signaled
575 
576  // Stop AutoCirculate...
577  mDevice.AutoCirculateStop (mConfig.fOutputChannel);
578  BURNNOTE("Thread completed: " << DEC(goodXfers) << " xfers, " << DEC(badXfers) << " failed, "
579  << DEC(starves) << " ring starves, " << DEC(noRoomWaits) << " device starves");
580 } // PlayFrames
581 
582 
584 
585 
586 
588 //
589 // This is where the capture thread gets started
590 //
592 {
593  // Create and start the capture thread...
594  mCaptureThread.Attach(CaptureThreadStatic, this);
595  mCaptureThread.SetPriority(AJA_ThreadPriority_High);
596  mCaptureThread.Start();
597 
598 } // StartCaptureThread
599 
600 
601 //
602 // The static capture thread function
603 //
604 void NTV2FieldBurn::CaptureThreadStatic (AJAThread * pThread, void * pContext) // static
605 { (void) pThread;
606  // Grab the NTV2FieldBurn instance pointer from the pContext parameter,
607  // then call its CaptureFrames method...
608  NTV2FieldBurn * pApp(reinterpret_cast<NTV2FieldBurn*>(pContext));
609  pApp->CaptureFrames();
610 } // CaptureThreadStatic
611 
612 
613 //
614 // Repeatedly captures frames until told to stop
615 //
617 {
618  AUTOCIRCULATE_TRANSFER inputXferInfo; // F1 transfer info
619  AUTOCIRCULATE_TRANSFER inputXferInfo2; // F2 transfer info (unused in Field Mode)
620  NTV2TCIndexes F1TCIndexes, F2TCIndexes;
621  const ULWord acOptions ((mConfig.WithTimecode() ? AUTOCIRCULATE_WITH_RP188 : 0) | (mConfig.FieldMode() ? AUTOCIRCULATE_WITH_FIELDS : 0));
622  ULWord goodXfers(0), badXfers(0), ringFulls(0), devWaits(0);
623  BURNNOTE("Thread started");
624 
625  // Prepare the Timecode Indexes we'll be setting for playout...
626  for (size_t ndx(0); ndx < mTCOutputs.size(); ndx++)
627  { const NTV2Channel sdiSpigot(mTCOutputs.at(ndx));
628  F1TCIndexes.insert(::NTV2ChannelToTimecodeIndex(sdiSpigot, /*LTC?*/true)); // F1 LTC
629  F1TCIndexes.insert(::NTV2ChannelToTimecodeIndex(sdiSpigot, /*LTC?*/false)); // F1 VITC
630  F2TCIndexes.insert(::NTV2ChannelToTimecodeIndex(sdiSpigot, /*LTC?*/false, true)); // F2 VITC
631  }
632 
633  if (!mConfig.FieldMode())
634  {
635  // In Frame Mode, use AutoCirculate's "segmented DMA" feature to transfer each field
636  // out of the device's full-frame video buffer as a group of "segments".
637  // Each segment is one line long, and the segments are contiguous in host memory,
638  // but originate on alternating lines in the device's frame buffer...
639  inputXferInfo.EnableSegmentedDMAs (mFormatDesc.numLines / 2, // Number of segments: number of lines per field, i.e. half the line count
640  mFormatDesc.linePitch * 4, // Segment size, in bytes: transfer this many bytes per segment (normal line pitch)
641  mFormatDesc.linePitch * 4, // Host bytes per line: normal line pitch when writing into our half-height buffer
642  mFormatDesc.linePitch * 8); // Device bytes per line: skip every other line when reading from device memory
643 
644  // IMPORTANT: For segmented DMAs, the video buffer size must contain the number of bytes to
645  // transfer per segment. This will be done just prior to calling AutoCirculateTransfer.
646  inputXferInfo2.EnableSegmentedDMAs (mFormatDesc.numLines / 2, // Number of segments: number of lines per field, i.e. half the line count
647  mFormatDesc.linePitch * 4, // Segment size, in bytes: transfer this many bytes per segment (normal line pitch)
648  mFormatDesc.linePitch * 4, // Host bytes per line: normal line pitch when writing into our half-height buffer
649  mFormatDesc.linePitch * 8); // Device bytes per line: skip every other line when reading from device memory
650  inputXferInfo2.acInVideoDMAOffset = mFormatDesc.linePitch * 4; // Field 2 starts on second line in device buffer
651  }
652 
653  // Stop AutoCirculate on this channel, just in case some other app left it running...
654  mDevice.AutoCirculateStop (mConfig.fInputChannel);
655 
656  // Initialize AutoCirculate...
657  if (!mDevice.AutoCirculateInitForInput (mConfig.fInputChannel, // channel
658  mConfig.fInputFrames, // frame count/range
659  mAudioSystem, // audio system
660  acOptions)) // flags
661  {BURNFAIL("AutoCirculateInitForInput failed"); mGlobalQuit = true;}
662  else
663  // Start AutoCirculate running...
664  mDevice.AutoCirculateStart (mConfig.fInputChannel);
665 
666  while (!mGlobalQuit)
667  {
668  AUTOCIRCULATE_STATUS acStatus;
669  mDevice.AutoCirculateGetStatus (mConfig.fInputChannel, acStatus);
670 
671  if (acStatus.IsRunning() && acStatus.HasAvailableInputFrame())
672  {
673  // At this point, there's at least one fully-formed frame available in the device's frame buffer
674  // memory waiting to be transferred to the host. Reserve an NTV2FrameData to fill ("produce"),
675  // and use it in the next frame transferred from the device...
676  NTV2FrameData * pFrameData (mFrameDataRing.StartProduceNextBuffer ());
677  if (!pFrameData)
678  {ringFulls++; continue;} // Ring full -- consumer thread isn't consuming frames fast enough
679 
680  inputXferInfo.SetVideoBuffer (pFrameData->VideoBuffer(),
681  mConfig.FieldMode() ? pFrameData->VideoBufferSize()
682  : mFormatDesc.GetBytesPerRow());
683  if (NTV2_IS_VALID_AUDIO_SYSTEM(mAudioSystem))
684  inputXferInfo.SetAudioBuffer (pFrameData->AudioBuffer(), NTV2_AUDIOSIZE_MAX);
685 
686  // Transfer this Field (Field Mode) or F1 (Frame Mode) from the device into our host buffers...
687  if (mDevice.AutoCirculateTransfer (mConfig.fInputChannel, inputXferInfo)) goodXfers++;
688  else badXfers++;
689 
690  // Remember the amount, in bytes, of captured audio data...
691  pFrameData->fNumAudioBytes = pFrameData->AudioBuffer() ? inputXferInfo.GetCapturedAudioByteCount() : 0;
692  if (mConfig.FieldMode())
693  pFrameData->fFrameFlags = inputXferInfo.acPeerToPeerFlags; // Remember which field this was
694 
695  // Get a timecode to use for burn-in...
696  NTV2_RP188 thisFrameTC;
697  inputXferInfo.GetInputTimeCodes (pFrameData->fTimecodes, mConfig.fInputChannel);
698  if (!pFrameData->fTimecodes.empty())
699  {
700  thisFrameTC = pFrameData->fTimecodes.begin()->second; // Use 1st "good" timecode for burn-in
701  CAPDBG("Captured TC: " << ::NTV2TCIndexToString(pFrameData->fTimecodes.begin()->first,true) << " " << thisFrameTC);
702  }
703  else
704  { // Invent a timecode (based on frame count)...
705  const NTV2FrameRate ntv2FrameRate (::GetNTV2FrameRateFromVideoFormat (mVideoFormat));
706  const TimecodeFormat tcFormat (CNTV2DemoCommon::NTV2FrameRate2TimecodeFormat(ntv2FrameRate));
707  const CRP188 inventedTC (inputXferInfo.GetTransferStatus().GetProcessedFrameCount(), 0, 0, 10, tcFormat);
708  inventedTC.GetRP188Reg(thisFrameTC);
709  }
710  CRP188 tc(thisFrameTC);
711  string tcStr;
712  tc.GetRP188Str(tcStr);
713 
714  if (!mConfig.FieldMode())
715  { // Frame Mode: Transfer F2 segments from same device frame buffer used for F1...
716  inputXferInfo2.acDesiredFrame = inputXferInfo.acTransferStatus.acTransferFrame;
717  inputXferInfo2.SetVideoBuffer (pFrameData->VideoBuffer2(), mFormatDesc.GetBytesPerRow());
718  if (mDevice.AutoCirculateTransfer (mConfig.fInputChannel, inputXferInfo2)) goodXfers++;
719  else badXfers++;
720  }
721 
722  // While this NTV2FrameData's buffers are locked, "burn" identical timecode into each field...
723  // F1 goes into top half, F2 into bottom half...
724  mTCBurner.BurnTimeCode (ToCharPtr(inputXferInfo.acVideoBuffer.GetHostPointer()), tcStr.c_str(),
725  !mConfig.FieldMode() || (pFrameData->fFrameFlags & AUTOCIRCULATE_FRAME_FIELD0) ? 10 : 30);
726  if (!mConfig.FieldMode()) // Frame Mode: "burn" F2 timecode
727  mTCBurner.BurnTimeCode (ToCharPtr(inputXferInfo2.acVideoBuffer.GetHostPointer()), tcStr.c_str(), 30);
728 
729  // Set NTV2FrameData::fTimecodes map for playout...
730  for (NTV2TCIndexesConstIter it(F1TCIndexes.begin()); it != F1TCIndexes.end(); ++it)
731  pFrameData->fTimecodes[*it] = thisFrameTC;
732  for (NTV2TCIndexesConstIter it(F2TCIndexes.begin()); it != F2TCIndexes.end(); ++it)
733  pFrameData->fTimecodes[*it] = thisFrameTC;
734 
735  // Signal that we're done "producing" the frame, making it available for future "consumption"...
736  mFrameDataRing.EndProduceNextBuffer();
737  } // if A/C running and frame(s) are available for transfer
738  else
739  {
740  // Either AutoCirculate is not running, or there were no frames available on the device to transfer.
741  // Rather than waste CPU cycles spinning, waiting until a field/frame becomes available, it's far more
742  // efficient to wait for the next input vertical interrupt event to get signaled...
743  devWaits++;
744  if (mConfig.FieldMode())
746  else
747  mDevice.WaitForInputFieldID (NTV2_FIELD0, mConfig.fInputChannel);
748  }
749  } // loop til quit signaled
750 
751  // Stop AutoCirculate...
752  mDevice.AutoCirculateStop(mConfig.fInputChannel);
753  BURNNOTE("Thread completed: " << DEC(goodXfers) << " xfers, " << DEC(badXfers) << " failed, "
754  << DEC(ringFulls) << " ring full(s), " << DEC(devWaits) << " device waits");
755 
756 } // CaptureFrames
757 
758 
760 
761 
762 void NTV2FieldBurn::GetStatus (ULWord & outFramesProcessed, ULWord & outCaptureFramesDropped, ULWord & outPlayoutFramesDropped,
763  ULWord & outCaptureBufferLevel, ULWord & outPlayoutBufferLevel)
764 {
765  AUTOCIRCULATE_STATUS inputStatus, outputStatus;
766 
767  mDevice.AutoCirculateGetStatus (mConfig.fInputChannel, inputStatus);
768  mDevice.AutoCirculateGetStatus (mConfig.fOutputChannel, outputStatus);
769 
770  outFramesProcessed = inputStatus.acFramesProcessed;
771  outCaptureFramesDropped = inputStatus.acFramesDropped;
772  outPlayoutFramesDropped = outputStatus.acFramesDropped;
773  outCaptureBufferLevel = inputStatus.acBufferLevel;
774  outPlayoutBufferLevel = outputStatus.acBufferLevel;
775 
776 } // GetStatus
777 
778 
779 static ULWord GetRP188RegisterForInput (const NTV2InputSource inInputSource)
780 {
781  switch (inInputSource)
782  {
783  case NTV2_INPUTSOURCE_SDI1: return kRegRP188InOut1DBB; // reg 29
784  case NTV2_INPUTSOURCE_SDI2: return kRegRP188InOut2DBB; // reg 64
785  case NTV2_INPUTSOURCE_SDI3: return kRegRP188InOut3DBB; // reg 268
786  case NTV2_INPUTSOURCE_SDI4: return kRegRP188InOut4DBB; // reg 273
787  case NTV2_INPUTSOURCE_SDI5: return kRegRP188InOut5DBB; // reg 342
788  case NTV2_INPUTSOURCE_SDI6: return kRegRP188InOut6DBB; // reg 418
789  case NTV2_INPUTSOURCE_SDI7: return kRegRP188InOut7DBB; // reg 427
790  case NTV2_INPUTSOURCE_SDI8: return kRegRP188InOut8DBB; // reg 436
791  default: return 0;
792  } // switch on input source
793 
794 } // GetRP188RegisterForInput
795 
796 
798 {
799  const ULWord regNum (::GetRP188RegisterForInput (mConfig.fInputSource));
800  ULWord regValue (0);
801 
802  // Bit 16 of the RP188 DBB register will be set if there is timecode embedded in the input signal...
803  if (regNum && mDevice.ReadRegister(regNum, regValue) && regValue & BIT(16))
804  return true;
805  return false;
806 
807 } // InputSignalHasTimecode
NTV2Channel NTV2InputSourceToChannel(const NTV2InputSource inInputSource)
Converts a given NTV2InputSource to its equivalent NTV2Channel value.
Definition: ntv2utils.cpp:5047
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:1277
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:1273
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:300
Specifies the device&#39;s internal clock.
Definition: ntv2enums.h:1459
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:5452
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:578
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:1265
NTV2OutputDestination NTV2ChannelToOutputDestination(const NTV2Channel inChannel, const NTV2IOKinds inKinds=NTV2_IOKINDS_SDI)
Converts the given NTV2Channel value into its ordinary equivalent NTV2OutputDestination.
Definition: ntv2utils.cpp:5167
static uint64_t GetPid()
Definition: process.cpp:35
#define AJA_FAILURE(_status_)
Definition: types.h:373
virtual void StartCaptureThread(void)
Starts my capture thread.
NTV2EmbeddedAudioInput NTV2InputSourceToEmbeddedAudioInput(const NTV2InputSource inInputSource)
Converts a given NTV2InputSource to its equivalent NTV2EmbeddedAudioInput value.
Definition: ntv2utils.cpp:4877
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:5397
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: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...
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...
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: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.
NTV2Channel
These enum values are mostly used to identify a specific widget_framestore. They&#39;re also commonly use...
Definition: ntv2enums.h:1357
mVideoFormat
Definition: ntv2vcam.cpp:801
Identifies the 8th SDI video input.
Definition: ntv2enums.h:1276
virtual class DeviceCapabilities & features(void)
Definition: ntv2card.h:148
bool CanDoInputSource(const NTV2InputSource inSrc)
virtual bool EnableOutputInterrupt(const NTV2Channel channel=NTV2_CHANNEL1)
Allows the CNTV2Card instance to wait for and respond to output vertical blanking interrupts originat...
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:1270
#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...
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:4962
#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:485
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:412
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).
static TimecodeFormat NTV2FrameRate2TimecodeFormat(const NTV2FrameRate inFrameRate)
NTV2InputXptID GetOutputDestInputXpt(const NTV2OutputDestination inOutputDest, const bool inIsSDI_DS2=false, const UWord inHDMI_Quadrant=99)
Invalid or "not found".
Definition: ntv2enums.h:98
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:1271
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...
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:2030
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:1366
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:1360
virtual NTV2DeviceID GetDeviceID(void)
std::string NTV2TCIndexToString(const NTV2TCIndex inValue, const bool inCompactDisplay=false)
Definition: ntv2utils.cpp:6394
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.
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:1272
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:1346
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).
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...
NTV2InputSource
Identifies a specific video input source.
Definition: ntv2enums.h:1262
bool IsRGBFormat(const NTV2FrameBufferFormat format)
Definition: ntv2utils.cpp:5410
Identifies the 6th SDI video input.
Definition: ntv2enums.h:1274
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:249
#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:3897
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:1275
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:2527
NTV2InputCrosspointID
Identifies a widget input that potentially can accept a signal emitted from another widget&#39;s output (...
Definition: ntv2enums.h:2752
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:2909
NTV2ACFrameRange fInputFrames
Ingest frame count or range.
uint16_t UWord
Definition: ajatypes.h:221
ULWord acFramesDropped
Total number of frames dropped since CNTV2Card::AutoCirculateStart called.
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...
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 SubscribeOutputVerticalEvent(const NTV2Channel inChannel)
Causes me to be notified when an output vertical blanking interrupt is generated for the given output...
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...
bool CanDoWidget(const NTV2WidgetID inWgtID)
TimecodeFormat
Definition: ntv2rp188.h:22
#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
#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:4869
bool HasAvailableInputFrame(void) const
Specifies channel or FrameStore 4 (or the 4th item).
Definition: ntv2enums.h:1362
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:1363
Identifies the first analog video input.
Definition: ntv2enums.h:1264
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:4901
Identifies the first field in time for an interlaced video frame, or the first and only field in a pr...
Definition: ntv2enums.h:1842
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:1364
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, designating a contiguous block of frame buffers on the ...
#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:1365
#define NTV2_INPUT_SOURCE_IS_SDI(_inpSrc_)
Definition: ntv2enums.h:1283
bool GetRP188Str(std::string &sRP188) const
Definition: ntv2rp188.cpp:918
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:1269
#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:146
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:3799
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:1361
NTV2InputSource fInputSource
The device input connector to use.
virtual bool EnableChannel(const NTV2Channel inChannel)
Enables the given FrameStore.