AJA NTV2 SDK  18.0.0.2122
NTV2 SDK 18.0.0.2122
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  mDeviceID (DEVICE_ID_INVALID),
34  mSavedTaskMode (NTV2_TASK_MODE_INVALID),
35  mCurrentFrame (0),
36  mFormatDesc (),
37  mGlobalQuit (false),
38  mTCBurner (),
39  mHostBuffers (),
40  mTestPatRasters ()
41 {
42 }
43 
44 
46 {
47  // Stop my playout and producer threads, then destroy them...
48  Quit();
49 } // destructor
50 
51 
53 {
54  // Set the global 'quit' flag, and wait for the threads to go inactive...
55  mGlobalQuit = true;
56 
57  while (mProducerThread.Active())
58  AJATime::Sleep(10);
59 
60  while (mConsumerThread.Active())
61  AJATime::Sleep(10);
62 
63  if (!mConfig.fDoMultiFormat && mDevice.IsOpen())
64  {
66  if (NTV2_IS_VALID_TASK_MODE(mSavedTaskMode))
67  mDevice.SetTaskMode(mSavedTaskMode); // Restore prior task mode
68  }
69 } // Quit
70 
71 
73 {
75 
76  // Open the device...
78  {cerr << "## ERROR: Device '" << mConfig.fDeviceSpec << "' not found" << endl; return AJA_STATUS_OPEN;}
79  mDeviceID = mDevice.GetDeviceID(); // Keep this ID handy -- it's used frequently
80 
81  if (!mDevice.IsDeviceReady(false))
82  {cerr << "## ERROR: Device '" << mDevice.GetDisplayName() << "' not ready" << endl; return AJA_STATUS_INITIALIZE;}
83  if (!mDevice.features().CanDoPlayback())
84  {cerr << "## ERROR: '" << mDevice.GetDisplayName() << "' is capture-only" << endl; return AJA_STATUS_FEATURE;}
85  if (!mDevice.features().CanDoStreamingDMA())
86  {cerr << "## ERROR: '" << mDevice.GetDisplayName() << "' does not support streaming DMA" << endl; return AJA_STATUS_FEATURE;}
87 
88  const UWord maxNumChannels (mDevice.features().GetNumFrameStores());
89 
90  // Beware -- some older devices (e.g. Corvid1) can only output from FrameStore 2...
91  if ((mConfig.fOutputChannel == NTV2_CHANNEL1) && (!mDevice.features().CanDoFrameStore1Display()))
92  mConfig.fOutputChannel = NTV2_CHANNEL2;
93  if (UWord(mConfig.fOutputChannel) >= maxNumChannels)
94  {
95  cerr << "## ERROR: '" << mDevice.GetDisplayName() << "' can't use Ch" << DEC(mConfig.fOutputChannel+1)
96  << " -- only supports Ch1" << (maxNumChannels > 1 ? string("-Ch") + string(1, char(maxNumChannels+'0')) : "") << endl;
98  }
99 
100  if (!mConfig.fDoMultiFormat)
101  {
102  mDevice.GetTaskMode(mSavedTaskMode); // Save the current task mode
104  return AJA_STATUS_BUSY; // Device is in use by another app -- fail
105  }
106  mDevice.SetTaskMode(NTV2_OEM_TASKS); // Set OEM service level
107 
108  if (mDevice.features().CanDoMultiFormat())
109  mDevice.SetMultiFormatMode(mConfig.fDoMultiFormat);
110  else
111  mConfig.fDoMultiFormat = false;
112 
113  // Set up the video and audio...
114  status = SetUpVideo();
115  if (AJA_FAILURE(status))
116  return status;
117 
118  // Set up the circular buffers, and the test pattern buffers...
119  status = SetUpHostBuffers();
120  if (AJA_FAILURE(status))
121  return status;
122  status = SetUpTestPatternBuffers();
123  if (AJA_FAILURE(status))
124  return status;
125 
126  // Set up the device signal routing...
127  if (!RouteOutputSignal())
128  return AJA_STATUS_FAIL;
129 
130  // Lastly, prepare my AJATimeCodeBurn instance...
131  if (!mTCBurner.RenderTimeCodeFont (CNTV2DemoCommon::GetAJAPixelFormat(mConfig.fPixelFormat), mFormatDesc.numPixels, mFormatDesc.numLines))
132  {cerr << "## ERROR: RenderTimeCodeFont failed for: " << mFormatDesc << endl; return AJA_STATUS_UNSUPPORTED;}
133 
134  // Ready to go...
135  #if defined(_DEBUG)
136  cerr << mConfig << endl;
137  #endif // defined(_DEBUG)
138  return AJA_STATUS_SUCCESS;
139 
140 } // Init
141 
142 
144 {
145  // Configure the device to output the requested video format...
146  if (mConfig.fVideoFormat == NTV2_FORMAT_UNKNOWN)
147  return AJA_STATUS_BAD_PARAM;
148  if (!mDevice.features().CanDoVideoFormat(mConfig.fVideoFormat))
149  { cerr << "## ERROR: '" << mDevice.GetDisplayName() << "' doesn't support "
150  << ::NTV2VideoFormatToString(mConfig.fVideoFormat) << endl;
151  return AJA_STATUS_UNSUPPORTED;
152  }
153  if (!mDevice.features().CanDoFrameBufferFormat(mConfig.fPixelFormat))
154  { cerr << "## ERROR: '" << mDevice.GetDisplayName() << "' doesn't support "
155  << ::NTV2FrameBufferFormatString(mConfig.fPixelFormat) << endl;
156  return AJA_STATUS_UNSUPPORTED;
157  }
158 
159  // This demo doesn't playout dual-link RGB over SDI -- only YCbCr.
160  // Check that this device has a CSC to convert RGB to YUV...
161  if (::IsRGBFormat(mConfig.fPixelFormat)) // If RGB FBF...
162  if (UWord(mConfig.fOutputChannel) > mDevice.features().GetNumCSCs()) // No CSC for this channel?
163  {cerr << "## ERROR: No CSC for channel " << DEC(mConfig.fOutputChannel+1) << " to convert RGB pixel format" << endl;
164  return AJA_STATUS_UNSUPPORTED;}
165 
166  if (!mDevice.features().CanDo3GLevelConversion() && mConfig.fDoABConversion && ::IsVideoFormatA(mConfig.fVideoFormat))
167  mConfig.fDoABConversion = false;
168  if (mConfig.fDoABConversion)
170 
171  // Keep the raster description handy...
172  mFormatDesc = NTV2FormatDescriptor(mConfig.fVideoFormat, mConfig.fPixelFormat);
173  if (!mFormatDesc.IsValid())
174  return AJA_STATUS_FAIL;
175 
176  // Turn on the FrameStore (to read frame buffer memory and transmit video)...
177  mDevice.EnableChannel(mConfig.fOutputChannel);
178  mDevice.SetMode(mConfig.fOutputChannel, NTV2_MODE_DISPLAY);
179 
180  // This demo assumes VANC is disabled...
181  mDevice.SetVANCMode(NTV2_VANCMODE_OFF, mConfig.fOutputChannel);
183 
184  // Set the FrameStore video format...
185  mDevice.SetVideoFormat (mConfig.fVideoFormat, false, false, mConfig.fOutputChannel);
186 // mDevice.SetTsiFrameEnable(true, mConfig.fOutputChannel);
187 
188  // Set the frame buffer pixel format for the device FrameStore...
189  mDevice.SetFrameBufferFormat (mConfig.fOutputChannel, mConfig.fPixelFormat);
190 
191  // Set output clock reference...
193 
194  // At this point, video setup is complete (except for widget signal routing).
195  return AJA_STATUS_SUCCESS;
196 
197 } // SetUpVideo
198 
199 
201 {
202  CNTV2DemoCommon::SetDefaultPageSize(); // Set host-specific page size
203 
204  // Allocate and add each in-host NTV2FrameData to my circular buffer member variable...
205  mHostBuffers.reserve(CIRCULAR_BUFFER_SIZE);
206  while (mHostBuffers.size() < CIRCULAR_BUFFER_SIZE)
207  {
208  mHostBuffers.push_back(FrameData()); // Make a new NTV2FrameData...
209  FrameData & frameData(mHostBuffers.back()); // ...and get a reference to it
210 
211  // Allocate a page-aligned video buffer
212  if (mConfig.WithVideo())
213  {
214  if (!frameData.fVideoBuffer.Allocate (mFormatDesc.GetTotalBytes(), BUFFER_PAGE_ALIGNED))
215  {
216  PLFAIL("Failed to allocate " << xHEX0N(mFormatDesc.GetTotalBytes(),8) << "-byte video buffer");
217  return AJA_STATUS_MEMORY;
218  }
219  }
220  frameData.fDataReady = false;
221  } // for each NTV2FrameData
222 
223  mProducerIndex = 0;
224  mConsumerIndex = 0;
225 
226  return AJA_STATUS_SUCCESS;
227 
228 } // SetUpHostBuffers
229 
230 
232 {
233  vector<NTV2TestPatternSelect> testPatIDs;
234  testPatIDs.push_back(NTV2_TestPatt_ColorBars100);
235  testPatIDs.push_back(NTV2_TestPatt_ColorBars75);
236  testPatIDs.push_back(NTV2_TestPatt_Ramp);
237  testPatIDs.push_back(NTV2_TestPatt_MultiBurst);
238  testPatIDs.push_back(NTV2_TestPatt_LineSweep);
239  testPatIDs.push_back(NTV2_TestPatt_CheckField);
240  testPatIDs.push_back(NTV2_TestPatt_FlatField);
241  testPatIDs.push_back(NTV2_TestPatt_MultiPattern);
242  testPatIDs.push_back(NTV2_TestPatt_Border);
243 
244  mTestPatRasters.clear();
245  for (size_t tpNdx(0); tpNdx < testPatIDs.size(); tpNdx++)
246  mTestPatRasters.push_back(NTV2Buffer());
247 
248  if (!mFormatDesc.IsValid())
249  {PLFAIL("Bad format descriptor"); return AJA_STATUS_FAIL;}
250  if (mFormatDesc.IsVANC())
251  {PLFAIL("VANC should have been disabled: " << mFormatDesc); return AJA_STATUS_FAIL;}
252 
253  // Set up one video buffer for each test pattern...
254  for (size_t tpNdx(0); tpNdx < testPatIDs.size(); tpNdx++)
255  {
256  // Allocate the buffer memory...
257  if (!mTestPatRasters.at(tpNdx).Allocate (mFormatDesc.GetTotalBytes(), BUFFER_PAGE_ALIGNED))
258  { PLFAIL("Test pattern buffer " << DEC(tpNdx+1) << " of " << DEC(testPatIDs.size()) << ": "
259  << xHEX0N(mFormatDesc.GetTotalBytes(),8) << "-byte page-aligned alloc failed");
260  return AJA_STATUS_MEMORY;
261  }
262 
263  // Fill the buffer with test pattern...
264  NTV2TestPatternGen testPatternGen;
265  if (!testPatternGen.DrawTestPattern (testPatIDs.at(tpNdx), mFormatDesc, mTestPatRasters.at(tpNdx)))
266  {
267  cerr << "## ERROR: DrawTestPattern " << DEC(tpNdx) << " failed: " << mFormatDesc << endl;
268  return AJA_STATUS_FAIL;
269  }
270  } // loop for each predefined pattern
271 
272  return AJA_STATUS_SUCCESS;
273 
274 } // SetUpTestPatternBuffers
275 
276 
278 {
279  const NTV2Standard outputStandard (::GetNTV2StandardFromVideoFormat(mConfig.fVideoFormat));
280  const UWord numSDIOutputs (mDevice.features().GetNumVideoOutputs());
281  const bool isRGB (::IsRGBFormat(mConfig.fPixelFormat));
282  const bool canVerify (mDevice.features().HasCrosspointConnectROM());
283  UWord connectFailures (0);
284 
285  const NTV2OutputXptID cscVidOutXpt(::GetCSCOutputXptFromChannel(mConfig.fOutputChannel, false/*isKey*/, !isRGB/*isRGB*/));
286  const NTV2OutputXptID fsVidOutXpt (::GetFrameStoreOutputXptFromChannel(mConfig.fOutputChannel, isRGB/*isRGB*/, false/*is425*/));
287  const NTV2InputXptID cscInputXpt (isRGB ? ::GetCSCInputXptFromChannel(mConfig.fOutputChannel, false/*isKeyInput*/) : NTV2_INPUT_CROSSPOINT_INVALID);
288  if (isRGB)
289  if (!mDevice.Connect (cscInputXpt, fsVidOutXpt, canVerify))
290  connectFailures++;
291 
292  if (mConfig.fDoMultiFormat)
293  {
294  // Multiformat --- We may be sharing the device with other processes, so route only one SDI output...
295  if (mDevice.features().HasBiDirectionalSDI())
296  mDevice.SetSDITransmitEnable(mConfig.fOutputChannel, true);
297 
298  if (!mDevice.Connect (::GetSDIOutputInputXpt (mConfig.fOutputChannel, false/*isDS2*/), isRGB ? cscVidOutXpt : fsVidOutXpt, canVerify))
299  connectFailures++;
300  // NOTE: No need to send VITC2 with VITC1 (for "i" formats) -- firmware does this automatically
301  mDevice.SetSDIOutputStandard (mConfig.fOutputChannel, outputStandard);
302  }
303  else
304  {
305  // Not multiformat: We own the whole device, so connect all possible SDI outputs...
306  const UWord numFrameStores(mDevice.features().GetNumFrameStores());
307  mDevice.ClearRouting(); // Start with clean slate
308 
309  if (isRGB)
310  if (!mDevice.Connect (cscInputXpt, fsVidOutXpt, canVerify))
311  connectFailures++;
312 
313  for (NTV2Channel chan(NTV2_CHANNEL1); ULWord(chan) < numSDIOutputs; chan = NTV2Channel(chan+1))
314  {
315  if (chan != mConfig.fOutputChannel && chan < numFrameStores)
316  mDevice.DisableChannel(chan); // Disable unused FrameStore
317  if (mDevice.features().HasBiDirectionalSDI())
318  mDevice.SetSDITransmitEnable (chan, true); // Make it an output
319 
320  if (!mDevice.Connect (::GetSDIOutputInputXpt (chan, false/*isDS2*/), isRGB ? cscVidOutXpt : fsVidOutXpt, canVerify))
321  connectFailures++;
322  mDevice.SetSDIOutputStandard (chan, outputStandard);
323  // NOTE: No need to send VITC2 with VITC1 (for "i" formats) -- firmware does this automatically
324  } // for each SDI output spigot
325 
326  // And connect analog video output, if the device has one...
327  if (mDevice.features().GetNumAnalogVideoOutputs())
328  if (!mDevice.Connect (::GetOutputDestInputXpt(NTV2_OUTPUTDESTINATION_ANALOG1), isRGB ? cscVidOutXpt : fsVidOutXpt, canVerify))
329  connectFailures++;
330 
331  // And connect HDMI video output, if the device has one...
332  if (mDevice.features().GetNumHDMIVideoOutputs())
333  if (!mDevice.Connect (::GetOutputDestInputXpt(NTV2_OUTPUTDESTINATION_HDMI1), isRGB ? cscVidOutXpt : fsVidOutXpt, canVerify))
334  connectFailures++;
335  }
336  if (connectFailures)
337  PLWARN(DEC(connectFailures) << " 'Connect' call(s) failed");
338  return connectFailures == 0;
339 
340 } // RouteOutputSignal
341 
342 
344 {
345  // Start my consumer and producer threads...
348  return AJA_STATUS_SUCCESS;
349 
350 } // Run
351 
352 
353 
355 // This is where the play thread starts
356 
358 {
359  // Create and start the playout thread...
360  mConsumerThread.Attach (ConsumerThreadStatic, this);
361  mConsumerThread.SetPriority(AJA_ThreadPriority_High);
362  mConsumerThread.Start();
363 
364 } // StartConsumerThread
365 
366 
367 // The playout thread function
368 void NTV2StreamPlayer::ConsumerThreadStatic (AJAThread * pThread, void * pContext) // static
369 { (void) pThread;
370  // Grab the NTV2StreamPlayer instance pointer from the pContext parameter,
371  // then call its ConsumeFrames method...
372  NTV2StreamPlayer * pApp (reinterpret_cast<NTV2StreamPlayer*>(pContext));
373  if (pApp)
374  pApp->ConsumeFrames();
375 
376 } // ConsumerThreadStatic
377 
378 
380 {
381  NTV2StreamChannel strStatus;
382  NTV2StreamBuffer bfrStatus;
383  ULWord goodQueue(0), badQueue(0), goodRelease(0), badRelease(0), starves(0), noRoomWaits(0), status(0);
384  PLNOTE("Thread started");
385 
386  // Lock and map the buffers...
387  for (FrameDataArrayIter iterHost (mHostBuffers.begin()); iterHost != mHostBuffers.end(); ++iterHost)
388  if (iterHost->fVideoBuffer)
389  mDevice.DMABufferLock(iterHost->fVideoBuffer, true);
390 
391  // Initialize and claim ownership of the stream
392  status = mDevice.StreamChannelInitialize(mConfig.fOutputChannel);
393  if (status != NTV2_STREAM_STATUS_SUCCESS)
394  {
395  cerr << "## ERROR: Stream initialize failed: " << status << endl;
396  mGlobalQuit = true;
397  }
398 
399  while (!mGlobalQuit)
400  {
401  // Get stream status
402  status = mDevice.StreamChannelStatus(mConfig.fOutputChannel, strStatus);
403  if (status != NTV2_STREAM_STATUS_SUCCESS)
404  {cerr << "## ERROR: Stream status failed: " << status << endl; return;}
405 
406  if (strStatus.GetQueueDepth() < 6)
407  {
408  FrameData * pFrameData (&mHostBuffers[mConsumerIndex]);
409  if (pFrameData->fDataReady)
410  {
411  // Queue frame to stream
412  status = mDevice.StreamBufferQueue (mConfig.fOutputChannel, pFrameData->fVideoBuffer, mConsumerIndex, bfrStatus);
413  if (status == NTV2_STREAM_STATUS_SUCCESS)
414  {
415  goodQueue++;
416  mConsumerIndex = (mConsumerIndex + 1) % CIRCULAR_BUFFER_SIZE;
417  }
418  else
419  {
420  badQueue++;
421  cerr << "## ERROR: Stream buffer add failed: " << status << endl;
422  }
423 
424  if (goodQueue == 3)
425  {
426  // Stop the stream (this will start streaming the first buffer to the output)
427  status = mDevice.StreamChannelStop (mConfig.fOutputChannel, strStatus);
428  if (status != NTV2_STREAM_STATUS_SUCCESS)
429  {cerr << "## ERROR: Stream stop failed: " << status << endl; return;}
430 
431  // Wait for stream to start...
432  mDevice.StreamChannelWait (mConfig.fOutputChannel, strStatus);
433  while (!strStatus.IsIdle())
434  mDevice.StreamChannelWait (mConfig.fOutputChannel, strStatus);
435 
436  // Wait a few more frames for output to stabilize...
437  for (int i = 0; i < 30; i++)
438  mDevice.StreamChannelWait (mConfig.fOutputChannel, strStatus);
439 
440  // Now start the stream...
441  status = mDevice.StreamChannelStart (mConfig.fOutputChannel, strStatus);
442  if (status != NTV2_STREAM_STATUS_SUCCESS)
443  {cerr << "## ERROR: Stream start failed: " << status << endl; return;}
444  }
445  }
446  else
447  starves++;
448  continue; // Back to top of while loop
449  }
450  else
451  noRoomWaits++;
452 
453  // Look for buffers to release
454  status = mDevice.StreamBufferRelease(mConfig.fOutputChannel, bfrStatus);
455  while (status == NTV2_STREAM_STATUS_SUCCESS)
456  {
457  if (bfrStatus.mBufferCookie < CIRCULAR_BUFFER_SIZE)
458  {
459  mHostBuffers[bfrStatus.mBufferCookie].fDataReady = false;
460  goodRelease++;
461  }
462  else
463  {
464  badRelease++;
465  }
466  status = mDevice.StreamBufferRelease(mConfig.fOutputChannel, bfrStatus);
467  }
468 
469  // Wait for one or more buffers to become available on the device, which should occur at next VBI...
470  if (mDevice.StreamChannelWait(mConfig.fOutputChannel, strStatus) != NTV2_STREAM_STATUS_SUCCESS)
471  break;
472  } // loop til quit signaled
473 
474  // Stop streaming...
475  status = mDevice.StreamChannelInitialize (mConfig.fOutputChannel);
476  if (status != NTV2_STREAM_STATUS_SUCCESS)
477  {cerr << "## ERROR: Stream initialize failed: " << status << endl; return;}
478 
479  // Release all buffers
480  while (mDevice.StreamBufferRelease (mConfig.fOutputChannel, bfrStatus) == NTV2_STREAM_STATUS_SUCCESS)
481  {
482  if (bfrStatus.mBufferCookie < CIRCULAR_BUFFER_SIZE)
483  { // Signal that I'm done consuming this FrameData, making it immediately available for more data...
484  mHostBuffers[bfrStatus.mBufferCookie].fDataReady = false;
485  goodRelease++;
486  }
487  else
488  badRelease++;
489  }
490 
491  // Release stream ownership
492  status = mDevice.StreamChannelRelease (mConfig.fOutputChannel);
493  if (status != NTV2_STREAM_STATUS_SUCCESS)
494  {
495  cerr << "## ERROR: Stream release failed: " << status << endl;
496  return;
497  }
498 
499  PLNOTE("Thread completed: " << DEC(goodQueue) << " queued, " << DEC(badQueue) << " failed, "
500  << DEC(starves) << " starves, " << DEC(noRoomWaits) << " waits, "
501  << DEC(goodRelease) << " releases (" << DEC(badRelease) << " failed)");
502 
503 } // ConsumeFrames
504 
505 
506 
508 // This is where the producer thread starts
509 
511 {
512  // Create and start the producer thread...
513  mProducerThread.Attach(ProducerThreadStatic, this);
514  mProducerThread.SetPriority(AJA_ThreadPriority_High);
515  mProducerThread.Start();
516 
517 } // StartProducerThread
518 
519 
520 void NTV2StreamPlayer::ProducerThreadStatic (AJAThread * pThread, void * pContext) // static
521 { (void) pThread;
522  NTV2StreamPlayer * pApp (reinterpret_cast<NTV2StreamPlayer*>(pContext));
523  if (pApp)
524  pApp->ProduceFrames();
525 
526 } // ProducerThreadStatic
527 
528 
530 {
531  ULWord testPatNdx(0), badTally(0);
532  double timeOfLastSwitch (0.0);
533 
536  const bool isInterlace (!NTV2_VIDEO_FORMAT_HAS_PROGRESSIVE_PICTURE(mConfig.fVideoFormat));
537  const bool isPAL (NTV2_IS_PAL_VIDEO_FORMAT(mConfig.fVideoFormat));
538  const NTV2FrameRate ntv2FrameRate (::GetNTV2FrameRateFromVideoFormat(mConfig.fVideoFormat));
539  const TimecodeFormat tcFormat (CNTV2DemoCommon::NTV2FrameRate2TimecodeFormat(ntv2FrameRate));
540 
541  PLNOTE("Thread started");
542 
543  while (!mGlobalQuit)
544  {
545  FrameData * pFrameData (&mHostBuffers[mProducerIndex]);
546  if (pFrameData->fDataReady)
547  {
548  badTally++; // No frame available!
549  AJATime::Sleep(10); // Wait a bit for the consumer thread to free one up for me...
550  continue; // ...then try again
551  }
552 
553  // Copy fresh, unmodified, pre-rendered test pattern into this frame's video buffer...
554  pFrameData->fVideoBuffer.CopyFrom (mTestPatRasters.at(testPatNdx),
555  /*srcOffset*/ 0,
556  /*dstOffset*/ 0,
557  /*byteCount*/ pFrameData->fVideoBuffer.GetByteCount());
558 
559  const CRP188 rp188Info (mCurrentFrame++, 0, 0, 10, tcFormat);
560  NTV2_RP188 tcF1, tcF2;
561  string tcString;
562 
563  rp188Info.GetRP188Reg(tcF1);
564  rp188Info.GetRP188Str(tcString);
565 
566  // Include timecode in output signal...
567  tcF2 = tcF1;
568  if (isInterlace)
569  { // Set bit 27 of Hi word (PAL) or Lo word (NTSC)
570  if (isPAL) tcF2.fHi |= BIT(27); else tcF2.fLo |= BIT(27);
571  }
572 
573  if (pFrameData->fVideoBuffer.GetHostAddress(0))
574  { // Burn current timecode into the video buffer...
575  mTCBurner.BurnTimeCode (pFrameData->fVideoBuffer.GetHostAddress(0), tcString.c_str(), 80);
576  }
577  TCDBG("F" << DEC0N(mCurrentFrame-1,6) << ": " << tcF1 << ": " << tcString);
578 
579  // Every few seconds, change the test pattern and tone frequency...
580  const double currentTime (timeBase.FramesToSeconds(mCurrentFrame));
581  if (currentTime > timeOfLastSwitch + 4.0)
582  {
583  testPatNdx = (testPatNdx + 1) % ULWord(mTestPatRasters.size());
584  timeOfLastSwitch = currentTime;
585  PLINFO("F" << DEC0N(mCurrentFrame,6) << ": " << tcString << "pattern='" << tpNames.at(testPatNdx) << "'");
586  } // if time to switch test pattern
587 
588  // Signal that I'm done producing this FrameData, making it immediately available for transfer/playout...
589  pFrameData->fDataReady = true;
590  mProducerIndex = (mProducerIndex + 1) % CIRCULAR_BUFFER_SIZE;
591  } // loop til mGlobalQuit goes true
592 
593  PLNOTE("Thread completed: " << DEC(mCurrentFrame) << " frame(s) produced, " << DEC(badTally) << " failed");
594 } // ProduceFrames
595 
596 
598 {
599  mDevice.StreamChannelStatus(mConfig.fOutputChannel, outStatus);
600 }
601 
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:197
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: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...
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:578
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:1049
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:223
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
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:412
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:165
Playout (output) mode, which reads from device SDRAM.
Definition: ntv2enums.h:1241
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:733
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
std::vector< std::string > NTV2StringList
Definition: ntv2utils.h:1155
#define PLNOTE(_xpr_)
NTV2VideoFormat fVideoFormat
The video format to use.
std::string NTV2VideoFormatToString(const NTV2VideoFormat inValue, const bool inUseFrameRate=false)
Definition: ntv2utils.cpp:6746
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:1468
bool IsVideoFormatA(const NTV2VideoFormat format)
Definition: ntv2utils.cpp:5458
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:1360
virtual NTV2DeviceID GetDeviceID(void)
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:5410
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:221
Specifies channel or FrameStore 1 (or the first item).
Definition: ntv2enums.h:1359
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_)
bool CanDoVideoFormat(const NTV2VideoFormat inVF)
const char * NTV2FrameBufferFormatString(NTV2FrameBufferFormat fmt)
Definition: ntv2debug.cpp:214
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:3799
virtual void ProduceFrames(void)
My producer thread that repeatedly produces video frames.
virtual bool EnableChannel(const NTV2Channel inChannel)
Enables the given FrameStore.