AJA NTV2 SDK  18.1.0.2439
NTV2 SDK 18.1.0.2439
ntv2streamplayer.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
8 #include "ntv2streamplayer.h"
9 #include "ntv2debug.h"
10 #include "ntv2devicescanner.h"
11 #include "ntv2testpatterngen.h"
13 #include "ajabase/system/process.h"
14 #include <fstream> // For ifstream
15 
16 using namespace std;
17 
18 // Convenience macros for EZ logging:
19 #define TCFAIL(_expr_) AJA_sERROR (AJA_DebugUnit_TimecodeGeneric, AJAFUNC << ": " << _expr_)
20 #define TCWARN(_expr_) AJA_sWARNING(AJA_DebugUnit_TimecodeGeneric, AJAFUNC << ": " << _expr_)
21 #define TCNOTE(_expr_) AJA_sNOTICE (AJA_DebugUnit_TimecodeGeneric, AJAFUNC << ": " << _expr_)
22 #define TCINFO(_expr_) AJA_sINFO (AJA_DebugUnit_TimecodeGeneric, AJAFUNC << ": " << _expr_)
23 #define TCDBG(_expr_) AJA_sDEBUG (AJA_DebugUnit_TimecodeGeneric, AJAFUNC << ": " << _expr_)
24 
25 static const bool BUFFER_PAGE_ALIGNED (true);
26 
27 
29  : mConfig (inConfig),
30  mConsumerThread (),
31  mProducerThread (),
32  mDevice (),
33  mSavedTaskMode (NTV2_TASK_MODE_INVALID),
34  mCurrentFrame (0),
35  mFormatDesc (),
36  mGlobalQuit (false),
37  mTCBurner (),
38  mHostBuffers (),
39  mTestPatRasters ()
40 {
41 }
42 
43 
45 {
46  // Stop my playout and producer threads, then destroy them...
47  Quit();
48 } // destructor
49 
50 
52 {
53  // Set the global 'quit' flag, and wait for the threads to go inactive...
54  mGlobalQuit = true;
55 
56  while (mProducerThread.Active())
57  AJATime::Sleep(10);
58 
59  while (mConsumerThread.Active())
60  AJATime::Sleep(10);
61 
62  if (!mConfig.fDoMultiFormat && mDevice.IsOpen())
63  {
65  if (NTV2_IS_VALID_TASK_MODE(mSavedTaskMode))
66  mDevice.SetTaskMode(mSavedTaskMode); // Restore prior task mode
67  }
68 } // Quit
69 
70 
72 {
74 
75  // Open the device...
77  {cerr << "## ERROR: Device '" << mConfig.fDeviceSpec << "' not found" << endl; return AJA_STATUS_OPEN;}
78  if (!mDevice.IsDeviceReady(false))
79  {cerr << "## ERROR: Device '" << mDevice.GetDisplayName() << "' not ready" << endl; return AJA_STATUS_INITIALIZE;}
80  if (!mDevice.features().CanDoPlayback())
81  {cerr << "## ERROR: '" << mDevice.GetDisplayName() << "' is capture-only" << endl; return AJA_STATUS_FEATURE;}
82  if (!mDevice.features().CanDoStreamingDMA())
83  {cerr << "## ERROR: '" << mDevice.GetDisplayName() << "' does not support streaming DMA" << endl; return AJA_STATUS_FEATURE;}
84 
85  const UWord maxNumChannels (mDevice.features().GetNumFrameStores());
86 
87  // Beware -- some older devices (e.g. Corvid1) can only output from FrameStore 2...
88  if ((mConfig.fOutputChannel == NTV2_CHANNEL1) && (!mDevice.features().CanDoFrameStore1Display()))
89  mConfig.fOutputChannel = NTV2_CHANNEL2;
90  if (UWord(mConfig.fOutputChannel) >= maxNumChannels)
91  {
92  cerr << "## ERROR: '" << mDevice.GetDisplayName() << "' can't use Ch" << DEC(mConfig.fOutputChannel+1)
93  << " -- only supports Ch1" << (maxNumChannels > 1 ? string("-Ch") + string(1, char(maxNumChannels+'0')) : "") << endl;
95  }
96 
97  if (!mConfig.fDoMultiFormat)
98  {
99  mDevice.GetTaskMode(mSavedTaskMode); // Save the current task mode
101  return AJA_STATUS_BUSY; // Device is in use by another app -- fail
102  }
103  mDevice.SetTaskMode(NTV2_OEM_TASKS); // Set OEM service level
104 
105  if (mDevice.features().CanDoMultiFormat())
106  mDevice.SetMultiFormatMode(mConfig.fDoMultiFormat);
107  else
108  mConfig.fDoMultiFormat = false;
109 
110  // Set up the video and audio...
111  status = SetUpVideo();
112  if (AJA_FAILURE(status))
113  return status;
114 
115  // Set up the circular buffers, and the test pattern buffers...
116  status = SetUpHostBuffers();
117  if (AJA_FAILURE(status))
118  return status;
119  status = SetUpTestPatternBuffers();
120  if (AJA_FAILURE(status))
121  return status;
122 
123  // Set up the device signal routing...
124  if (!RouteOutputSignal())
125  return AJA_STATUS_FAIL;
126 
127  // Lastly, prepare my AJATimeCodeBurn instance...
128  if (!mTCBurner.RenderTimeCodeFont (CNTV2DemoCommon::GetAJAPixelFormat(mConfig.fPixelFormat), mFormatDesc.numPixels, mFormatDesc.numLines))
129  {cerr << "## ERROR: RenderTimeCodeFont failed for: " << mFormatDesc << endl; return AJA_STATUS_UNSUPPORTED;}
130 
131  // Ready to go...
132  #if defined(_DEBUG)
133  cerr << mConfig
134  << "Device Description: " << mDevice.GetDescription() << endl
135  << endl;
136  #endif // defined(_DEBUG)
137  return AJA_STATUS_SUCCESS;
138 
139 } // Init
140 
141 
143 {
144  // Configure the device to output the requested video format...
145  if (mConfig.fVideoFormat == NTV2_FORMAT_UNKNOWN)
146  return AJA_STATUS_BAD_PARAM;
147  if (!mDevice.features().CanDoVideoFormat(mConfig.fVideoFormat))
148  { cerr << "## ERROR: '" << mDevice.GetDisplayName() << "' doesn't support "
149  << ::NTV2VideoFormatToString(mConfig.fVideoFormat) << endl;
150  return AJA_STATUS_UNSUPPORTED;
151  }
152  if (!mDevice.features().CanDoFrameBufferFormat(mConfig.fPixelFormat))
153  { cerr << "## ERROR: '" << mDevice.GetDisplayName() << "' doesn't support "
154  << ::NTV2FrameBufferFormatString(mConfig.fPixelFormat) << endl;
155  return AJA_STATUS_UNSUPPORTED;
156  }
157 
158  // This demo doesn't playout dual-link RGB over SDI -- only YCbCr.
159  // Check that this device has a CSC to convert RGB to YUV...
160  if (::IsRGBFormat(mConfig.fPixelFormat)) // If RGB FBF...
161  if (UWord(mConfig.fOutputChannel) > mDevice.features().GetNumCSCs()) // No CSC for this channel?
162  {cerr << "## ERROR: No CSC for channel " << DEC(mConfig.fOutputChannel+1) << " to convert RGB pixel format" << endl;
163  return AJA_STATUS_UNSUPPORTED;}
164 
165  if (!mDevice.features().CanDo3GLevelConversion() && mConfig.fDoABConversion && ::IsVideoFormatA(mConfig.fVideoFormat))
166  mConfig.fDoABConversion = false;
167  if (mConfig.fDoABConversion)
169 
170  // Keep the raster description handy...
171  mFormatDesc = NTV2FormatDescriptor(mConfig.fVideoFormat, mConfig.fPixelFormat);
172  if (!mFormatDesc.IsValid())
173  return AJA_STATUS_FAIL;
174 
175  // Turn on the FrameStore (to read frame buffer memory and transmit video)...
176  mDevice.EnableChannel(mConfig.fOutputChannel);
177  mDevice.SetMode(mConfig.fOutputChannel, NTV2_MODE_DISPLAY);
178 
179  // This demo assumes VANC is disabled...
180  mDevice.SetVANCMode(NTV2_VANCMODE_OFF, mConfig.fOutputChannel);
182 
183  // Set the FrameStore video format...
184  mDevice.SetVideoFormat (mConfig.fVideoFormat, false, false, mConfig.fOutputChannel);
185 // mDevice.SetTsiFrameEnable(true, mConfig.fOutputChannel);
186 
187  // Set the frame buffer pixel format for the device FrameStore...
188  mDevice.SetFrameBufferFormat (mConfig.fOutputChannel, mConfig.fPixelFormat);
189 
190  // Set output clock reference...
192 
193  // At this point, video setup is complete (except for widget signal routing).
194  return AJA_STATUS_SUCCESS;
195 
196 } // SetUpVideo
197 
198 
200 {
201  CNTV2DemoCommon::SetDefaultPageSize(); // Set host-specific page size
202 
203  // Allocate and add each in-host NTV2FrameData to my circular buffer member variable...
204  mHostBuffers.reserve(CIRCULAR_BUFFER_SIZE);
205  while (mHostBuffers.size() < CIRCULAR_BUFFER_SIZE)
206  {
207  mHostBuffers.push_back(FrameData()); // Make a new NTV2FrameData...
208  FrameData & frameData(mHostBuffers.back()); // ...and get a reference to it
209 
210  // Allocate a page-aligned video buffer
211  if (mConfig.WithVideo())
212  {
213  if (!frameData.fVideoBuffer.Allocate (mFormatDesc.GetTotalBytes(), BUFFER_PAGE_ALIGNED))
214  {
215  PLFAIL("Failed to allocate " << xHEX0N(mFormatDesc.GetTotalBytes(),8) << "-byte video buffer");
216  return AJA_STATUS_MEMORY;
217  }
218  }
219  frameData.fDataReady = false;
220  } // for each NTV2FrameData
221 
222  mProducerIndex = 0;
223  mConsumerIndex = 0;
224 
225  return AJA_STATUS_SUCCESS;
226 
227 } // SetUpHostBuffers
228 
229 
231 {
232  vector<NTV2TestPatternSelect> testPatIDs;
233  testPatIDs.push_back(NTV2_TestPatt_ColorBars100);
234  testPatIDs.push_back(NTV2_TestPatt_ColorBars75);
235  testPatIDs.push_back(NTV2_TestPatt_Ramp);
236  testPatIDs.push_back(NTV2_TestPatt_MultiBurst);
237  testPatIDs.push_back(NTV2_TestPatt_LineSweep);
238  testPatIDs.push_back(NTV2_TestPatt_CheckField);
239  testPatIDs.push_back(NTV2_TestPatt_FlatField);
240  testPatIDs.push_back(NTV2_TestPatt_MultiPattern);
241  testPatIDs.push_back(NTV2_TestPatt_Border);
242 
243  mTestPatRasters.clear();
244  for (size_t tpNdx(0); tpNdx < testPatIDs.size(); tpNdx++)
245  mTestPatRasters.push_back(NTV2Buffer());
246 
247  if (!mFormatDesc.IsValid())
248  {PLFAIL("Bad format descriptor"); return AJA_STATUS_FAIL;}
249  if (mFormatDesc.IsVANC())
250  {PLFAIL("VANC should have been disabled: " << mFormatDesc); return AJA_STATUS_FAIL;}
251 
252  // Set up one video buffer for each test pattern...
253  for (size_t tpNdx(0); tpNdx < testPatIDs.size(); tpNdx++)
254  {
255  // Allocate the buffer memory...
256  if (!mTestPatRasters.at(tpNdx).Allocate (mFormatDesc.GetTotalBytes(), BUFFER_PAGE_ALIGNED))
257  { PLFAIL("Test pattern buffer " << DEC(tpNdx+1) << " of " << DEC(testPatIDs.size()) << ": "
258  << xHEX0N(mFormatDesc.GetTotalBytes(),8) << "-byte page-aligned alloc failed");
259  return AJA_STATUS_MEMORY;
260  }
261 
262  // Fill the buffer with test pattern...
263  NTV2TestPatternGen testPatternGen;
264  if (!testPatternGen.DrawTestPattern (testPatIDs.at(tpNdx), mFormatDesc, mTestPatRasters.at(tpNdx)))
265  {
266  cerr << "## ERROR: DrawTestPattern " << DEC(tpNdx) << " failed: " << mFormatDesc << endl;
267  return AJA_STATUS_FAIL;
268  }
269  } // loop for each predefined pattern
270 
271  return AJA_STATUS_SUCCESS;
272 
273 } // SetUpTestPatternBuffers
274 
275 
277 {
278  const NTV2Standard outputStandard (::GetNTV2StandardFromVideoFormat(mConfig.fVideoFormat));
279  const UWord numSDIOutputs (mDevice.features().GetNumVideoOutputs());
280  const bool isRGB (::IsRGBFormat(mConfig.fPixelFormat));
281  const bool canVerify (mDevice.features().HasCrosspointConnectROM());
282  UWord connectFailures (0);
283 
284  const NTV2OutputXptID cscVidOutXpt(::GetCSCOutputXptFromChannel(mConfig.fOutputChannel, false/*isKey*/, !isRGB/*isRGB*/));
285  const NTV2OutputXptID fsVidOutXpt (::GetFrameStoreOutputXptFromChannel(mConfig.fOutputChannel, isRGB/*isRGB*/, false/*is425*/));
286  const NTV2InputXptID cscInputXpt (isRGB ? ::GetCSCInputXptFromChannel(mConfig.fOutputChannel, false/*isKeyInput*/) : NTV2_INPUT_CROSSPOINT_INVALID);
287  if (isRGB)
288  if (!mDevice.Connect (cscInputXpt, fsVidOutXpt, canVerify))
289  connectFailures++;
290 
291  if (mConfig.fDoMultiFormat)
292  {
293  // Multiformat --- We may be sharing the device with other processes, so route only one SDI output...
294  if (mDevice.features().HasBiDirectionalSDI())
295  mDevice.SetSDITransmitEnable(mConfig.fOutputChannel, true);
296 
297  if (!mDevice.Connect (::GetSDIOutputInputXpt (mConfig.fOutputChannel, false/*isDS2*/), isRGB ? cscVidOutXpt : fsVidOutXpt, canVerify))
298  connectFailures++;
299  // NOTE: No need to send VITC2 with VITC1 (for "i" formats) -- firmware does this automatically
300  mDevice.SetSDIOutputStandard (mConfig.fOutputChannel, outputStandard);
301  }
302  else
303  {
304  // Not multiformat: We own the whole device, so connect all possible SDI outputs...
305  const UWord numFrameStores(mDevice.features().GetNumFrameStores());
306  mDevice.ClearRouting(); // Start with clean slate
307 
308  if (isRGB)
309  if (!mDevice.Connect (cscInputXpt, fsVidOutXpt, canVerify))
310  connectFailures++;
311 
312  for (NTV2Channel chan(NTV2_CHANNEL1); ULWord(chan) < numSDIOutputs; chan = NTV2Channel(chan+1))
313  {
314  if (chan != mConfig.fOutputChannel && chan < numFrameStores)
315  mDevice.DisableChannel(chan); // Disable unused FrameStore
316  if (mDevice.features().HasBiDirectionalSDI())
317  mDevice.SetSDITransmitEnable (chan, true); // Make it an output
318 
319  if (!mDevice.Connect (::GetSDIOutputInputXpt (chan, false/*isDS2*/), isRGB ? cscVidOutXpt : fsVidOutXpt, canVerify))
320  connectFailures++;
321  mDevice.SetSDIOutputStandard (chan, outputStandard);
322  // NOTE: No need to send VITC2 with VITC1 (for "i" formats) -- firmware does this automatically
323  } // for each SDI output spigot
324 
325  // And connect analog video output, if the device has one...
326  if (mDevice.features().GetNumAnalogVideoOutputs())
327  if (!mDevice.Connect (::GetOutputDestInputXpt(NTV2_OUTPUTDESTINATION_ANALOG1), isRGB ? cscVidOutXpt : fsVidOutXpt, canVerify))
328  connectFailures++;
329 
330  // And connect HDMI video output, if the device has one...
331  if (mDevice.features().GetNumHDMIVideoOutputs())
332  if (!mDevice.Connect (::GetOutputDestInputXpt(NTV2_OUTPUTDESTINATION_HDMI1), isRGB ? cscVidOutXpt : fsVidOutXpt, canVerify))
333  connectFailures++;
334  }
335  if (connectFailures)
336  PLWARN(DEC(connectFailures) << " 'Connect' call(s) failed");
337  return connectFailures == 0;
338 
339 } // RouteOutputSignal
340 
341 
343 {
344  // Start my consumer and producer threads...
347  return AJA_STATUS_SUCCESS;
348 
349 } // Run
350 
351 
352 
354 // This is where the play thread starts
355 
357 {
358  // Create and start the playout thread...
359  mConsumerThread.Attach (ConsumerThreadStatic, this);
360  mConsumerThread.SetPriority(AJA_ThreadPriority_High);
361  mConsumerThread.Start();
362 
363 } // StartConsumerThread
364 
365 
366 // The playout thread function
367 void NTV2StreamPlayer::ConsumerThreadStatic (AJAThread * pThread, void * pContext) // static
368 { (void) pThread;
369  // Grab the NTV2StreamPlayer instance pointer from the pContext parameter,
370  // then call its ConsumeFrames method...
371  NTV2StreamPlayer * pApp (reinterpret_cast<NTV2StreamPlayer*>(pContext));
372  if (pApp)
373  pApp->ConsumeFrames();
374 
375 } // ConsumerThreadStatic
376 
377 
379 {
380  NTV2StreamChannel strStatus;
381  NTV2StreamBuffer bfrStatus;
382  ULWord goodQueue(0), badQueue(0), goodRelease(0), badRelease(0), starves(0), noRoomWaits(0), status(0);
383  PLNOTE("Thread started");
384 
385  // Lock and map the buffers...
386  for (FrameDataArrayIter iterHost (mHostBuffers.begin()); iterHost != mHostBuffers.end(); ++iterHost)
387  if (iterHost->fVideoBuffer)
388  mDevice.DMABufferLock(iterHost->fVideoBuffer, true);
389 
390  // Initialize and claim ownership of the stream
391  status = mDevice.StreamChannelInitialize(mConfig.fOutputChannel);
392  if (status != NTV2_STREAM_STATUS_SUCCESS)
393  {
394  cerr << "## ERROR: Stream initialize failed: " << status << endl;
395  mGlobalQuit = true;
396  }
397 
398  while (!mGlobalQuit)
399  {
400  // Get stream status
401  status = mDevice.StreamChannelStatus(mConfig.fOutputChannel, strStatus);
402  if (status != NTV2_STREAM_STATUS_SUCCESS)
403  {cerr << "## ERROR: Stream status failed: " << status << endl; return;}
404 
405  if (strStatus.GetQueueDepth() < 6)
406  {
407  FrameData * pFrameData (&mHostBuffers[mConsumerIndex]);
408  if (pFrameData->fDataReady)
409  {
410  // Queue frame to stream
411  status = mDevice.StreamBufferQueue (mConfig.fOutputChannel, pFrameData->fVideoBuffer, mConsumerIndex, bfrStatus);
412  if (status == NTV2_STREAM_STATUS_SUCCESS)
413  {
414  goodQueue++;
415  mConsumerIndex = (mConsumerIndex + 1) % CIRCULAR_BUFFER_SIZE;
416  }
417  else
418  {
419  badQueue++;
420  cerr << "## ERROR: Stream buffer add failed: " << status << endl;
421  }
422 
423  if (goodQueue == 3)
424  {
425  // Stop the stream (this will start streaming the first buffer to the output)
426  status = mDevice.StreamChannelStop (mConfig.fOutputChannel, strStatus);
427  if (status != NTV2_STREAM_STATUS_SUCCESS)
428  {cerr << "## ERROR: Stream stop failed: " << status << endl; return;}
429 
430  // Wait for stream to start...
431  mDevice.StreamChannelWait (mConfig.fOutputChannel, strStatus);
432  while (!strStatus.IsIdle())
433  mDevice.StreamChannelWait (mConfig.fOutputChannel, strStatus);
434 
435  // Wait a few more frames for output to stabilize...
436  for (int i = 0; i < 30; i++)
437  mDevice.StreamChannelWait (mConfig.fOutputChannel, strStatus);
438 
439  // Now start the stream...
440  status = mDevice.StreamChannelStart (mConfig.fOutputChannel, strStatus);
441  if (status != NTV2_STREAM_STATUS_SUCCESS)
442  {cerr << "## ERROR: Stream start failed: " << status << endl; return;}
443  }
444  }
445  else
446  starves++;
447  continue; // Back to top of while loop
448  }
449  else
450  noRoomWaits++;
451 
452  // Look for buffers to release
453  status = mDevice.StreamBufferRelease(mConfig.fOutputChannel, bfrStatus);
454  while (status == NTV2_STREAM_STATUS_SUCCESS)
455  {
456  if (bfrStatus.mBufferCookie < CIRCULAR_BUFFER_SIZE)
457  {
458  mHostBuffers[bfrStatus.mBufferCookie].fDataReady = false;
459  goodRelease++;
460  }
461  else
462  {
463  badRelease++;
464  }
465  status = mDevice.StreamBufferRelease(mConfig.fOutputChannel, bfrStatus);
466  }
467 
468  // Wait for one or more buffers to become available on the device, which should occur at next VBI...
469  if (mDevice.StreamChannelWait(mConfig.fOutputChannel, strStatus) != NTV2_STREAM_STATUS_SUCCESS)
470  break;
471  } // loop til quit signaled
472 
473  // Stop streaming...
474  status = mDevice.StreamChannelInitialize (mConfig.fOutputChannel);
475  if (status != NTV2_STREAM_STATUS_SUCCESS)
476  {cerr << "## ERROR: Stream initialize failed: " << status << endl; return;}
477 
478  // Release all buffers
479  while (mDevice.StreamBufferRelease (mConfig.fOutputChannel, bfrStatus) == NTV2_STREAM_STATUS_SUCCESS)
480  {
481  if (bfrStatus.mBufferCookie < CIRCULAR_BUFFER_SIZE)
482  { // Signal that I'm done consuming this FrameData, making it immediately available for more data...
483  mHostBuffers[bfrStatus.mBufferCookie].fDataReady = false;
484  goodRelease++;
485  }
486  else
487  badRelease++;
488  }
489 
490  // Release stream ownership
491  status = mDevice.StreamChannelRelease (mConfig.fOutputChannel);
492  if (status != NTV2_STREAM_STATUS_SUCCESS)
493  {
494  cerr << "## ERROR: Stream release failed: " << status << endl;
495  return;
496  }
497 
498  PLNOTE("Thread completed: " << DEC(goodQueue) << " queued, " << DEC(badQueue) << " failed, "
499  << DEC(starves) << " starves, " << DEC(noRoomWaits) << " waits, "
500  << DEC(goodRelease) << " releases (" << DEC(badRelease) << " failed)");
501 
502 } // ConsumeFrames
503 
504 
505 
507 // This is where the producer thread starts
508 
510 {
511  // Create and start the producer thread...
512  mProducerThread.Attach(ProducerThreadStatic, this);
513  mProducerThread.SetPriority(AJA_ThreadPriority_High);
514  mProducerThread.Start();
515 
516 } // StartProducerThread
517 
518 
519 void NTV2StreamPlayer::ProducerThreadStatic (AJAThread * pThread, void * pContext) // static
520 { (void) pThread;
521  NTV2StreamPlayer * pApp (reinterpret_cast<NTV2StreamPlayer*>(pContext));
522  if (pApp)
523  pApp->ProduceFrames();
524 
525 } // ProducerThreadStatic
526 
527 
529 {
530  ULWord testPatNdx(0), badTally(0);
531  double timeOfLastSwitch (0.0);
532 
535  const bool isInterlace (!NTV2_VIDEO_FORMAT_HAS_PROGRESSIVE_PICTURE(mConfig.fVideoFormat));
536  const bool isPAL (NTV2_IS_PAL_VIDEO_FORMAT(mConfig.fVideoFormat));
537  const NTV2FrameRate ntv2FrameRate (::GetNTV2FrameRateFromVideoFormat(mConfig.fVideoFormat));
538  const TimecodeFormat tcFormat (CNTV2DemoCommon::NTV2FrameRate2TimecodeFormat(ntv2FrameRate));
539 
540  PLNOTE("Thread started");
541 
542  while (!mGlobalQuit)
543  {
544  FrameData * pFrameData (&mHostBuffers[mProducerIndex]);
545  if (pFrameData->fDataReady)
546  {
547  badTally++; // No frame available!
548  AJATime::Sleep(10); // Wait a bit for the consumer thread to free one up for me...
549  continue; // ...then try again
550  }
551 
552  // Copy fresh, unmodified, pre-rendered test pattern into this frame's video buffer...
553  pFrameData->fVideoBuffer.CopyFrom (mTestPatRasters.at(testPatNdx),
554  /*srcOffset*/ 0,
555  /*dstOffset*/ 0,
556  /*byteCount*/ ULWord(pFrameData->fVideoBuffer.GetByteCount()));
557 
558  const CRP188 rp188Info (mCurrentFrame++, 0, 0, 10, tcFormat);
559  NTV2_RP188 tcF1, tcF2;
560  string tcString;
561 
562  rp188Info.GetRP188Reg(tcF1);
563  rp188Info.GetRP188Str(tcString);
564 
565  // Include timecode in output signal...
566  tcF2 = tcF1;
567  if (isInterlace)
568  { // Set bit 27 of Hi word (PAL) or Lo word (NTSC)
569  if (isPAL) tcF2.fHi |= BIT(27); else tcF2.fLo |= BIT(27);
570  }
571 
572  if (pFrameData->fVideoBuffer.GetHostAddress(0))
573  { // Burn current timecode into the video buffer...
574  mTCBurner.BurnTimeCode (pFrameData->fVideoBuffer.GetHostAddress(0), tcString.c_str(), 80);
575  }
576  TCDBG("F" << DEC0N(mCurrentFrame-1,6) << ": " << tcF1 << ": " << tcString);
577 
578  // Every few seconds, change the test pattern and tone frequency...
579  const double currentTime (timeBase.FramesToSeconds(mCurrentFrame));
580  if (currentTime > timeOfLastSwitch + 4.0)
581  {
582  testPatNdx = (testPatNdx + 1) % ULWord(mTestPatRasters.size());
583  timeOfLastSwitch = currentTime;
584  PLINFO("F" << DEC0N(mCurrentFrame,6) << ": " << tcString << "pattern='" << tpNames.at(testPatNdx) << "'");
585  } // if time to switch test pattern
586 
587  // Signal that I'm done producing this FrameData, making it immediately available for transfer/playout...
588  pFrameData->fDataReady = true;
589  mProducerIndex = (mProducerIndex + 1) % CIRCULAR_BUFFER_SIZE;
590  } // loop til mGlobalQuit goes true
591 
592  PLNOTE("Thread completed: " << DEC(mCurrentFrame) << " frame(s) produced, " << DEC(badTally) << " failed");
593 } // ProduceFrames
594 
595 
597 {
598  mDevice.StreamChannelStatus(mConfig.fOutputChannel, outStatus);
599 }
600 
NTV2FrameRate GetNTV2FrameRateFromVideoFormat(const NTV2VideoFormat inVideoFormat)
Definition: ntv2utils.cpp:3630
virtual ULWord StreamChannelInitialize(const NTV2Channel inChannel)
Initialize a stream. Put the stream queue and hardware in a known good state ready for use...
Definition: ntv2stream.cpp:11
double FramesToSeconds(int64_t frames) const
Definition: timebase.cpp:205
virtual bool SetTaskMode(const NTV2TaskMode inMode)
Sets the device&#39;s task mode.
virtual ULWord StreamBufferQueue(const NTV2Channel inChannel, NTV2Buffer &inBuffer, ULWord64 bufferCookie, NTV2StreamBuffer &status)
Queue a buffer to the stream. The bufferCookie is a user defined identifier of the buffer used by the...
Definition: ntv2stream.cpp:67
#define NTV2_IS_VALID_TASK_MODE(__m__)
virtual void ConsumeFrames(void)
My consumer thread that repeatedly plays frames using AutoCirculate (until quit). ...
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...
The NTV2 test pattern generator.
virtual void Quit(void)
Gracefully stops me from running.
#define DEC0N(__x__, __n__)
I play out SD or HD test pattern (with timecode) to an output of an AJA device with or without audio ...
virtual ULWord StreamChannelRelease(const NTV2Channel inChannel)
Release a stream. Releases all buffers remaining in the queue.
Definition: ntv2stream.cpp:19
#define BIT(_x_)
Definition: ajatypes.h:496
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
virtual void StartConsumerThread(void)
Starts my consumer thread.
virtual bool IsDeviceReady(const bool inCheckValid=(0))
virtual bool DisableChannel(const NTV2Channel inChannel)
Disables the given FrameStore.
static uint64_t GetPid()
Definition: process.cpp:35
#define AJA_FAILURE(_status_)
Definition: types.h:373
#define PLINFO(_xpr_)
virtual AJAStatus SetUpHostBuffers(void)
Sets up my host video & audio buffers.
Declares the NTV2TestPatternGen class.
static void ConsumerThreadStatic(AJAThread *pThread, void *pContext)
This is the consumer thread&#39;s static callback function that gets called when the consumer thread star...
virtual AJAStatus Run(void)
Runs me.
#define NTV2_VIDEO_FORMAT_HAS_PROGRESSIVE_PICTURE(__f__)
Definition: ntv2enums.h:1053
virtual AJAStatus SetPriority(AJAThreadPriority priority)
Definition: thread.cpp:133
if(!(riid==IID_IUnknown) &&!(riid==IID_IClassFactory))
Definition: dllentry.cpp:196
ULWord GetTotalBytes(void) const
virtual bool RouteOutputSignal(void)
Performs all widget/signal routing for playout.
bool fDoABConversion
If true, do level-A/B conversion; otherwise don&#39;t.
Definition: json.hpp:5362
bool IsIdle(void)
Is the stream idle.
virtual AJAStatus Start()
Definition: thread.cpp:91
std::string fDeviceSpec
The AJA device to use.
#define false
uint32_t ULWord
Definition: ajatypes.h:236
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
virtual class DeviceCapabilities & features(void)
Definition: ntv2card.h:148
virtual bool SetMultiFormatMode(const bool inEnable)
Enables or disables multi-format (per channel) device operation. If enabled, each device channel can ...
virtual bool ClearRouting(void)
Removes all existing signal path connections between any and all widgets on the AJA device...
Declares the AJATimeBase class.
This struct replaces the old RP188_STRUCT.
ULWord numPixels
Width – total number of pixels per line.
virtual bool Active()
Definition: thread.cpp:116
virtual bool GetTaskMode(NTV2TaskMode &outMode)
Retrieves the device&#39;s current task mode.
static AJA_PixelFormat GetAJAPixelFormat(const NTV2PixelFormat inFormat)
NTV2FrameRate
Identifies a particular video frame rate.
Definition: ntv2enums.h:416
virtual bool DrawTestPattern(const std::string &inTPName, const NTV2FormatDescriptor &inFormatDesc, NTV2Buffer &inBuffer)
Renders the given test pattern or color into a host raster buffer.
NTV2Standard
Identifies a particular video standard.
Definition: ntv2enums.h:169
Playout (output) mode, which reads from device SDRAM.
Definition: ntv2enums.h:1245
virtual std::string GetDescription(void) const
Definition: ntv2card.cpp:139
virtual AJAStatus SetUpVideo(void)
Performs all video setup.
virtual bool SetMode(const NTV2Channel inChannel, const NTV2Mode inNewValue, const bool inIsRetail=(!(0)))
Determines if a given FrameStore on the AJA device will be used to capture or playout video...
static TimecodeFormat NTV2FrameRate2TimecodeFormat(const NTV2FrameRate inFrameRate)
#define NTV2_IS_PAL_VIDEO_FORMAT(__f__)
Definition: ntv2enums.h:737
NTV2InputXptID GetOutputDestInputXpt(const NTV2OutputDestination inOutputDest, const bool inIsSDI_DS2=false, const UWord inHDMI_Quadrant=99)
virtual bool IsOpen(void) const
virtual ~NTV2StreamPlayer(void)
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.
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 ...
virtual bool DMABufferLock(const NTV2Buffer &inBuffer, bool inMap=(0), bool inRDMA=(0))
Page-locks the given host buffer to reduce transfer time and CPU usage of DMA transfers.
Definition: ntv2dma.cpp:429
virtual std::string GetDisplayName(void)
Answers with this device&#39;s display name.
Definition: ntv2card.cpp:88
NTV2InputXptID GetCSCInputXptFromChannel(const NTV2Channel inCSC, const bool inIsKeyInput=false)
virtual ULWord StreamBufferRelease(const NTV2Channel inChannel, NTV2StreamBuffer &status)
Remove the oldest buffer released by the streaming engine from the buffer queue.
Definition: ntv2stream.cpp:77
Describes a video frame for a given video standard or format and pixel format, including the total nu...
static const bool BUFFER_PAGE_ALIGNED((!(0)))
static void Sleep(const int32_t inMilliseconds)
Suspends execution of the current thread for a given number of milliseconds.
Definition: systemtime.cpp:284
NTV2PixelFormat fPixelFormat
The pixel format to use.
2: OEM (recommended): device configured by client application(s) with some driver involvement...
virtual ULWord StreamChannelStart(const NTV2Channel inChannel, NTV2StreamChannel &status)
Start a stream. Put the stream is the active state to start processing queued buffers. For frame based video, the stream will start with the current buffer on the next frame sync.
Definition: ntv2stream.cpp:27
#define PLNOTE(_xpr_)
NTV2VideoFormat fVideoFormat
The video format to use.
std::string NTV2VideoFormatToString(const NTV2VideoFormat inValue, const bool inUseFrameRate=false)
Definition: ntv2utils.cpp:6750
virtual bool SetVANCShiftMode(NTV2Channel inChannel, NTV2VANCDataShiftMode inMode)
Enables or disables the "VANC Shift Mode" feature for the given channel.
AJA_EXPORT bool RenderTimeCodeFont(AJA_PixelFormat pixelFormat, uint32_t numPixels, uint32_t numLines)
Specifies the PTP source on SFP 1.
Definition: ntv2enums.h:1473
bool IsVideoFormatA(const NTV2VideoFormat format)
Definition: ntv2utils.cpp:5462
virtual ULWord StreamChannelStatus(const NTV2Channel inChannel, NTV2StreamChannel &status)
Get the current stream status.
Definition: ntv2stream.cpp:51
Specifies channel or FrameStore 2 (or the 2nd item).
Definition: ntv2enums.h:1364
virtual AJAStatus Init(void)
Initializes me and prepares me to Run.
Declares the CNTV2DeviceScanner class.
Declares the AJAProcess class.
Describes a user-space buffer on the host computer. I have an address and a length, plus some optional attributes (allocated by SDK?, page-aligned? etc.).
#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).
bool fDoMultiFormat
If true, enable device-sharing; otherwise take exclusive control of device.
static NTV2TestPatternNames getTestPatternNames(void)
bool IsRGBFormat(const NTV2FrameBufferFormat format)
Definition: ntv2utils.cpp:5414
virtual ULWord StreamChannelWait(const NTV2Channel inChannel, NTV2StreamChannel &status)
Wait for any stream event. Returns for any state or buffer change.
Definition: ntv2stream.cpp:59
static void ProducerThreadStatic(AJAThread *pThread, void *pContext)
This is the producer thread&#39;s static callback function that gets called when the producer thread star...
#define TCDBG(_expr_)
virtual void GetStreamStatus(NTV2StreamChannel &outStatus)
Provides status information about my output (playout) process.
virtual void StartProducerThread(void)
Starts my producer thread.
#define DEC(__x__)
NTV2StreamPlayer(const PlayerConfig &inConfig)
Constructs me using the given configuration settings.
NTV2Channel fOutputChannel
The device channel to use.
static const size_t CIRCULAR_BUFFER_SIZE(10)
Number of NTV2FrameData&#39;s in our ring.
static const ULWord kDemoAppSignature((((uint32_t)( 'D'))<< 24)|(((uint32_t)( 'E'))<< 16)|(((uint32_t)( 'M'))<< 8)|(((uint32_t)( 'O'))<< 0))
ULWord numLines
Height – total number of lines.
virtual AJAStatus Attach(AJAThreadFunction *pThreadFunction, void *pUserContext)
Definition: thread.cpp:169
mFormatDesc
Definition: ntv2vcam.cpp:942
virtual bool SetSDIOutLevelAtoLevelBConversion(const UWord inOutputSpigot, const bool inEnable)
Enables or disables 3G level A to 3G level B conversion at the SDI output widget (assuming the AJA de...
NTV2OutputXptID GetFrameStoreOutputXptFromChannel(const NTV2Channel inFrameStore, const bool inIsRGB=false, const bool inIs425=false)
uint16_t UWord
Definition: ajatypes.h:234
Specifies channel or FrameStore 1 (or the first item).
Definition: ntv2enums.h:1363
bool CanDoFrameBufferFormat(const NTV2PixelFormat inPF)
#define xHEX0N(__x__, __n__)
UWord GetNumAnalogVideoOutputs(void)
TimecodeFormat
Definition: ntv2rp188.h:22
virtual ULWord StreamChannelStop(const NTV2Channel inChannel, NTV2StreamChannel &status)
Stop a stream. Put the stream is the idle state. For frame based video, the stream will idle on the b...
Definition: ntv2stream.cpp:35
static AJA_FrameRate GetAJAFrameRate(const NTV2FrameRate inFrameRate)
#define NTV2_STREAM_STATUS_SUCCESS
Used in NTV2Stream success.
AJA_EXPORT bool BurnTimeCode(void *pBaseVideoAddress, const std::string &inTimeCodeStr, const uint32_t inYPercent)
enum NTV2InputCrosspointID NTV2InputXptID
NTV2Standard GetNTV2StandardFromVideoFormat(const NTV2VideoFormat inVideoFormat)
Definition: ntv2utils.cpp:2375
Configures an NTV2Player instance.
bool GetRP188Reg(RP188_STRUCT &outRP188) const
Definition: ntv2rp188.cpp:1241
ULWord fLo
| BG 4 | Secs10 | BG 3 | Secs 1 | BG 2 | Frms10 | BG 1 | Frms 1 |
static size_t SetDefaultPageSize(void)
#define PLWARN(_xpr_)
std::vector< std::string > NTV2StringList
bool CanDoVideoFormat(const NTV2VideoFormat inVF)
const char * NTV2FrameBufferFormatString(NTV2FrameBufferFormat fmt)
Definition: ntv2debug.cpp:220
bool GetRP188Str(std::string &sRP188) const
Definition: ntv2rp188.cpp:918
bool WithVideo(void) const
virtual AJAStatus SetUpTestPatternBuffers(void)
Creates my test pattern buffers.
virtual bool SetSDIOutputStandard(const UWord inOutputSpigot, const NTV2Standard inValue)
Sets the SDI output spigot&#39;s video standard.
NTV2InputXptID GetSDIOutputInputXpt(const NTV2Channel inSDIOutput, const bool inIsDS2=false)
ULWord GetQueueDepth(void)
Gets the queue depth.
virtual bool SetVANCMode(const NTV2VANCMode inVancMode, const NTV2Channel inChannel=NTV2_CHANNEL1)
Sets the VANC mode for the given FrameStore.
ULWord fHi
| BG 8 | Hrs 10 | BG 7 | Hrs 1 | BG 6 | Mins10 | BG 5 | Mins 1 |
enum NTV2OutputCrosspointID NTV2OutputXptID
ULWord64 mBufferCookie
Buffer User cookie.
NTV2OutputXptID GetCSCOutputXptFromChannel(const NTV2Channel inCSC, const bool inIsKey=false, const bool inIsRGB=false)
This identifies the mode in which there are no VANC lines in the frame buffer.
Definition: ntv2enums.h:3805
virtual void ProduceFrames(void)
My producer thread that repeatedly produces video frames.
virtual bool EnableChannel(const NTV2Channel inChannel)
Enables the given FrameStore.