AJA NTV2 SDK  18.1.0.2439
NTV2 SDK 18.1.0.2439
ntv2dolbyplayer.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
8 #include "ntv2dolbyplayer.h"
9 #include "ntv2debug.h"
10 #include "ntv2devicescanner.h"
11 #include "ntv2testpatterngen.h"
12 #include "ntv2audiodefines.h"
14 #include "ajabase/system/process.h"
15 
16 //#include "ajabase/system/debug.h"
17 
18 
19 using namespace std;
20 
21 // Convenience macros for EZ logging:
22 #define TCFAIL(_expr_) AJA_sERROR (AJA_DebugUnit_TimecodeGeneric, AJAFUNC << ": " << _expr_)
23 #define TCWARN(_expr_) AJA_sWARNING(AJA_DebugUnit_TimecodeGeneric, AJAFUNC << ": " << _expr_)
24 #define TCNOTE(_expr_) AJA_sNOTICE (AJA_DebugUnit_TimecodeGeneric, AJAFUNC << ": " << _expr_)
25 #define TCINFO(_expr_) AJA_sINFO (AJA_DebugUnit_TimecodeGeneric, AJAFUNC << ": " << _expr_)
26 #define TCDBG(_expr_) AJA_sDEBUG (AJA_DebugUnit_TimecodeGeneric, AJAFUNC << ": " << _expr_)
27 
35 static const uint32_t AUDIOBYTES_MAX_48K (201 * 1024);
36 
44 static const uint32_t AUDIOBYTES_MAX_192K (824 * 1024);
45 
46 static const bool BUFFER_PAGE_ALIGNED (true);
47 
48 // Audio tone generator data
49 static const double gFrequencies [] = {250.0, 500.0, 1000.0, 2000.0};
50 static const ULWord gNumFrequencies (sizeof (gFrequencies) / sizeof (double));
51 static const double gAmplitudes [] = { 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85,
52  0.85, 0.80, 0.75, 0.70, 0.65, 0.60, 0.55, 0.50, 0.45, 0.40, 0.35, 0.30, 0.25, 0.20, 0.15, 0.10};
53 
55  : mConfig (inConfig),
56  mConsumerThread (),
57  mProducerThread (),
58  mDevice (),
59  mSavedTaskMode (NTV2_TASK_MODE_INVALID),
60  mCurrentFrame (0),
61  mCurrentSample (0),
62  mToneFrequency (440.0),
63  mAudioSystem (NTV2_AUDIOSYSTEM_INVALID),
64  mFormatDesc (),
65  mTCIndexes (),
66  mGlobalQuit (false),
67  mTCBurner (),
68  mHostBuffers (),
69  mFrameDataRing (),
70  mTestPatRasters (),
71  mAudioRate (NTV2_AUDIO_192K),
72  mRampSample (0),
73  mBurstIndex (0),
74  mBurstSamples (0),
75  mBurstBuffer (NULL),
76  mBurstSize (0),
77  mBurstOffset (0),
78  mBurstMax (0),
79  mDolbyBuffer (NULL),
80  mDolbySize (0),
81  mDolbyBlocks (0)
82 { }
83 
84 
86 {
87  // Stop my playout and producer threads, then destroy them...
88  Quit ();
89 
91 
92  if (mDolbyBuffer)
93  {
94  delete [] mDolbyBuffer;
95  mDolbyBuffer = NULL;
96  }
97 
98  if (mBurstBuffer)
99  {
100  delete [] mBurstBuffer;
101  mBurstBuffer = NULL;
102  }
103 
104 } // destructor
105 
106 
108 {
109  // Set the global 'quit' flag, and wait for the threads to go inactive...
110  mGlobalQuit = true;
111 
112  while (mProducerThread.Active())
113  AJATime::Sleep(10);
114 
115  while (mConsumerThread.Active())
116  AJATime::Sleep(10);
117 
118  mDevice.SetAudioRate (NTV2_AUDIO_48K, mAudioSystem);
121 
122 #if defined(NTV2_BUFFER_LOCKING)
123  mDevice.DMABufferUnlockAll();
124 #endif // NTV2_BUFFER_LOCKING
125  if (!mConfig.fDoMultiFormat && mDevice.IsOpen())
126  {
128  if (NTV2_IS_VALID_TASK_MODE(mSavedTaskMode))
129  mDevice.SetTaskMode(mSavedTaskMode); // Restore prior task mode
130  }
131 } // Quit
132 
133 
135 {
136  AJAStatus status (AJA_STATUS_SUCCESS);
137 
138  // Open the device...
140  { if (aja::lower(mConfig.fDeviceSpec) != "list" && mConfig.fDeviceSpec != "?")
141  cerr << "## ERROR: Device '" << mConfig.fDeviceSpec << "' not found" << endl;
142  return AJA_STATUS_OPEN;
143  }
144  if (!mDevice.IsDeviceReady(false))
145  {cerr << "## ERROR: Device '" << mDevice.GetDescription() << "' not ready" << endl; return AJA_STATUS_INITIALIZE;}
146  if (!mDevice.features().CanDoPlayback())
147  {cerr << "## ERROR: '" << mDevice.GetDescription() << "' is capture-only" << endl; return AJA_STATUS_FEATURE;}
148  if (!mDevice.features().GetNumHDMIVideoOutputs())
149  {cerr << "## ERROR: '" << mDevice.GetDescription() << "' has no HDMI outputs" << endl; return AJA_STATUS_FEATURE;}
150 
151  const UWord maxNumChannels (mDevice.features().GetNumFrameStores());
152 
153  // Beware -- some older devices (e.g. Corvid1) can only output from FrameStore 2...
154  if ((mConfig.fOutputChannel == NTV2_CHANNEL1) && (!mDevice.features().CanDoFrameStore1Display()))
155  mConfig.fOutputChannel = NTV2_CHANNEL2;
156  if (UWord(mConfig.fOutputChannel) >= maxNumChannels)
157  {
158  cerr << "## ERROR: '" << mDevice.GetDescription() << "' can't use Ch" << DEC(mConfig.fOutputChannel+1)
159  << " -- only supports Ch1" << (maxNumChannels > 1 ? string("-Ch") + string(1, char(maxNumChannels+'0')) : "") << endl;
160  return AJA_STATUS_UNSUPPORTED;
161  }
162 
163  if (!mConfig.fDoMultiFormat)
164  {
165  mDevice.GetTaskMode(mSavedTaskMode); // Save the current task mode
167  return AJA_STATUS_BUSY; // Device is in use by another app -- fail
168  }
169  mDevice.SetTaskMode(NTV2_OEM_TASKS); // Set OEM service level
170 
171  if (mDevice.features().CanDoMultiFormat())
172  mDevice.SetMultiFormatMode(mConfig.fDoMultiFormat);
173  else
174  mConfig.fDoMultiFormat = false;
175 
176  if (!mConfig.fDolbyFilePath.empty())
177  {
178  status = mDolbyFileIO.Open(mConfig.fDolbyFilePath.c_str(), eAJAReadOnly, 0);
179  if (status != AJA_STATUS_SUCCESS)
180  {cerr << "## ERROR: Could not open file: " << mConfig.fDolbyFilePath << endl; return status;}
181  }
182 
183  // Set up the video and audio...
184  status = SetUpVideo();
185  if (AJA_FAILURE(status))
186  return status;
187  status = mConfig.WithAudio() ? SetUpAudio() : AJA_STATUS_SUCCESS;
188  if (AJA_FAILURE(status))
189  return status;
190 
191  // Set up the circular buffers, and the test pattern buffers...
192  status = SetUpHostBuffers();
193  if (AJA_FAILURE(status))
194  return status;
195  status = SetUpTestPatternBuffers();
196  if (AJA_FAILURE(status))
197  return status;
198 
199  // Set up the device signal routing...
200  if (!RouteOutputSignal())
201  return AJA_STATUS_FAIL;
202 
203  // Lastly, prepare my AJATimeCodeBurn instance...
204  if (!mTCBurner.RenderTimeCodeFont (CNTV2DemoCommon::GetAJAPixelFormat(mConfig.fPixelFormat), mFormatDesc.numPixels, mFormatDesc.numLines))
205  {cerr << "## ERROR: RenderTimeCodeFont failed for: " << mFormatDesc << endl; return AJA_STATUS_UNSUPPORTED;}
206 
207  // Ready to go...
208  #if defined(_DEBUG)
209  cerr << mConfig
210  << "Device Description: " << mDevice.GetDescription() << endl
211  << endl;
212  #endif // defined(_DEBUG)
213  return AJA_STATUS_SUCCESS;
214 
215 } // Init
216 
217 
219 {
220  // Configure the device to output the requested video format...
221  if (mConfig.fVideoFormat == NTV2_FORMAT_UNKNOWN)
222  return AJA_STATUS_BAD_PARAM;
223 
224  if (!mDevice.features().CanDoVideoFormat(mConfig.fVideoFormat))
225  { cerr << "## ERROR: '" << mDevice.GetDescription() << "' doesn't support "
226  << ::NTV2VideoFormatToString(mConfig.fVideoFormat) << endl;
227  return AJA_STATUS_UNSUPPORTED;
228  }
229  if (!mDevice.features().CanDoFrameBufferFormat(mConfig.fPixelFormat))
230  { cerr << "## ERROR: '" << mDevice.GetDescription() << "' doesn't support "
231  << ::NTV2FrameBufferFormatString(mConfig.fPixelFormat) << endl;
232  return AJA_STATUS_UNSUPPORTED;
233  }
234 
235  // Keep the raster description handy...
236  mFormatDesc = NTV2FormatDescriptor(mConfig.fVideoFormat, mConfig.fPixelFormat);
237  if (!mFormatDesc.IsValid())
238  return AJA_STATUS_FAIL;
239 
240  // Turn on the FrameStore (to read frame buffer memory and transmit video)...
241  mDevice.EnableChannel(mConfig.fOutputChannel);
242 
243  // This demo assumes VANC is disabled...
244  mDevice.SetVANCMode(NTV2_VANCMODE_OFF, mConfig.fOutputChannel);
246 
247  // Set the FrameStore video format...
248  mDevice.SetVideoFormat (mConfig.fVideoFormat, false, false, mConfig.fOutputChannel);
249 
250  // Set the frame buffer pixel format for the device FrameStore...
251  mDevice.SetFrameBufferFormat (mConfig.fOutputChannel, mConfig.fPixelFormat);
252 
253  // The output interrupt is Enabled by default, but on some platforms, you must subscribe to it
254  // in order to be able to wait on its event/semaphore...
256 
257  // Set output clock reference...
259 
260  return AJA_STATUS_SUCCESS;
261 
262 } // SetUpVideo
263 
264 
266 {
267  mAudioSystem = NTV2_AUDIOSYSTEM_1; // Use NTV2_AUDIOSYSTEM_1...
268  if (mDevice.features().GetNumAudioSystems() > 1) // ...but if the device has more than one audio system...
269  mAudioSystem = ::NTV2ChannelToAudioSystem(mConfig.fOutputChannel); // ...base it on the channel
270  // However, there are a few older devices that have only 1 audio system,
271  // yet 2 frame stores (or must use channel 2 for playout)...
272  if (!mDevice.features().CanDoFrameStore1Display())
273  mAudioSystem = NTV2_AUDIOSYSTEM_1;
274 
275  mDevice.SetNumberAudioChannels (8, mAudioSystem); // This demo uses 8 channels -- no more, no less
276  mDevice.SetAudioRate (mAudioRate, mAudioSystem);
277 
278  // How big should the on-device audio buffer be? 1MB? 2MB? 4MB? 8MB?
279  // For this demo, 4MB will work best across all platforms (Windows, Mac & Linux)...
280  mDevice.SetAudioBufferSize (NTV2_AUDIO_BUFFER_BIG, mAudioSystem);
281 
282  // Set the SDI output audio embedders to embed audio samples from the output of mAudioSystem...
283  mDevice.SetHDMIOutAudioSource2Channel (NTV2_AudioChannel1_2, mAudioSystem);
284 
285  mDevice.SetHDMIOutAudioRate(mAudioRate);
286 
288 
289  // If the last app using the device left it in end-to-end mode (input passthru),
290  // then loopback must be disabled, or else the output will contain whatever audio
291  // is present in whatever signal is feeding the device's SDI input...
292  mDevice.SetAudioLoopBack (NTV2_AUDIO_LOOPBACK_OFF, mAudioSystem);
293 
294  return AJA_STATUS_SUCCESS;
295 
296 } // SetUpAudio
297 
298 
300 {
301  CNTV2DemoCommon::SetDefaultPageSize(); // Set host-specific page size
302 
303  // Let my circular buffer know when it's time to quit...
304  mFrameDataRing.SetAbortFlag (&mGlobalQuit);
305 
306  // Calculate the size of the audio buffer, which mostly depends on the sample rate...
307  const uint32_t AUDIOBYTES_MAX = (mAudioRate == NTV2_AUDIO_192K) ? AUDIOBYTES_MAX_192K : AUDIOBYTES_MAX_48K;
308 
309  // Allocate and add each in-host NTV2FrameData to my circular buffer member variable...
310  mHostBuffers.reserve(CIRCULAR_BUFFER_SIZE);
311  while (mHostBuffers.size() < CIRCULAR_BUFFER_SIZE)
312  {
313  mHostBuffers.push_back(NTV2FrameData()); // Make a new NTV2FrameData...
314  NTV2FrameData & frameData(mHostBuffers.back()); // ...and get a reference to it
315 
316  // Allocate a page-aligned video buffer
317  if (mConfig.WithVideo())
318  if (!frameData.fVideoBuffer.Allocate (mFormatDesc.GetTotalBytes(), BUFFER_PAGE_ALIGNED))
319  {
320  PLFAIL("Failed to allocate " << xHEX0N(mFormatDesc.GetTotalBytes(),8) << "-byte video buffer");
321  return AJA_STATUS_MEMORY;
322  }
323  #ifdef NTV2_BUFFER_LOCKING
324  if (frameData.fVideoBuffer)
325  mDevice.DMABufferLock(frameData.fVideoBuffer, true);
326  #endif
327 
328  // Allocate a page-aligned audio buffer (if transmitting audio)
329  if (mConfig.WithAudio())
330  if (!frameData.fAudioBuffer.Allocate (AUDIOBYTES_MAX, BUFFER_PAGE_ALIGNED))
331  {
332  PLFAIL("Failed to allocate " << xHEX0N(AUDIOBYTES_MAX,8) << "-byte audio buffer");
333  return AJA_STATUS_MEMORY;
334  }
335  #ifdef NTV2_BUFFER_LOCKING
336  if (frameData.fAudioBuffer)
337  mDevice.DMABufferLock(frameData.fAudioBuffer, /*alsoPreLockSGL*/true);
338  #endif
339  mFrameDataRing.Add (&frameData);
340  } // for each NTV2FrameData
341 
342  if (mDolbyFileIO.IsOpen())
343  {
344  // Initialize IEC61937 burst size (32 milliseconds) for HDMI 192 kHz sample rate
345  mBurstSamples = 6144; // 192000 * 0.032 samples
346  mBurstMax = mBurstSamples * 2;
347  mBurstBuffer = new uint16_t [mBurstMax];
348  mDolbyBuffer = new uint16_t [mBurstMax];
349  }
350 
351  return AJA_STATUS_SUCCESS;
352 
353 } // SetUpHostBuffers
354 
356 {
357  vector<NTV2TestPatternSelect> testPatIDs;
358  testPatIDs.push_back(NTV2_TestPatt_ColorBars100);
359  testPatIDs.push_back(NTV2_TestPatt_ColorBars75);
360  testPatIDs.push_back(NTV2_TestPatt_Ramp);
361  testPatIDs.push_back(NTV2_TestPatt_MultiBurst);
362  testPatIDs.push_back(NTV2_TestPatt_LineSweep);
363  testPatIDs.push_back(NTV2_TestPatt_CheckField);
364  testPatIDs.push_back(NTV2_TestPatt_FlatField);
365  testPatIDs.push_back(NTV2_TestPatt_MultiPattern);
366 
367  mTestPatRasters.clear();
368  for (size_t tpNdx(0); tpNdx < testPatIDs.size(); tpNdx++)
369  mTestPatRasters.push_back(NTV2Buffer());
370 
371  if (!mFormatDesc.IsValid())
372  {PLFAIL("Bad format descriptor"); return AJA_STATUS_FAIL;}
373  if (mFormatDesc.IsVANC())
374  {PLFAIL("VANC should have been disabled: " << mFormatDesc); return AJA_STATUS_FAIL;}
375 
376  // Set up one video buffer for each test pattern...
377  for (size_t tpNdx(0); tpNdx < testPatIDs.size(); tpNdx++)
378  {
379  // Allocate the buffer memory...
380  if (!mTestPatRasters.at(tpNdx).Allocate (mFormatDesc.GetTotalBytes(), BUFFER_PAGE_ALIGNED))
381  { PLFAIL("Test pattern buffer " << DEC(tpNdx+1) << " of " << DEC(testPatIDs.size()) << ": "
382  << xHEX0N(mFormatDesc.GetTotalBytes(),8) << "-byte page-aligned alloc failed");
383  return AJA_STATUS_MEMORY;
384  }
385 
386  // Fill the buffer with test pattern...
387  NTV2TestPatternGen testPatternGen;
388  if (!testPatternGen.DrawTestPattern (testPatIDs.at(tpNdx), mFormatDesc, mTestPatRasters.at(tpNdx)))
389  {
390  cerr << "## ERROR: DrawTestPattern " << DEC(tpNdx) << " failed: " << mFormatDesc << endl;
391  return AJA_STATUS_FAIL;
392  }
393 
394  #ifdef NTV2_BUFFER_LOCKING
395  // Try to prelock the memory, including its scatter-gather list...
396  if (!mDevice.DMABufferLock(mTestPatRasters.at(tpNdx), /*alsoLockSegmentMap=*/true))
397  PLWARN("Test pattern buffer " << DEC(tpNdx+1) << " of " << DEC(testPatIDs.size()) << ": failed to pre-lock");
398  #endif
399  } // loop for each predefined pattern
400 
401  return AJA_STATUS_SUCCESS;
402 
403 } // SetUpTestPatternBuffers
404 
405 
407 {
408  const bool isRGB (::IsRGBFormat(mConfig.fPixelFormat));
409  const NTV2OutputXptID fsVidOutXpt (::GetFrameStoreOutputXptFromChannel (mConfig.fOutputChannel, isRGB, false/*is425*/));
410 
411  mDevice.ClearRouting(); // Start with clean slate
412 
413  // Connect HDMI video output...
414  return mDevice.Connect (::GetOutputDestInputXpt(NTV2_OUTPUTDESTINATION_HDMI1), fsVidOutXpt);
415 
416 } // RouteOutputSignal
417 
418 
420 {
421  // Start my consumer and producer threads...
424  return AJA_STATUS_SUCCESS;
425 
426 } // Run
427 
428 
429 
431 // This is where the play thread starts
432 
434 {
435  // Create and start the playout thread...
436  mConsumerThread.Attach (ConsumerThreadStatic, this);
437  mConsumerThread.SetPriority (AJA_ThreadPriority_High);
438  mConsumerThread.Start ();
439 
440 } // StartConsumerThread
441 
442 
443 // The playout thread function
444 void NTV2DolbyPlayer::ConsumerThreadStatic (AJAThread * pThread, void * pContext) // static
445 { (void) pThread;
446  // Grab the NTV2DolbyPlayer instance pointer from the pContext parameter,
447  // then call its ConsumeFrames method...
448  NTV2DolbyPlayer * pApp (reinterpret_cast<NTV2DolbyPlayer*>(pContext));
449  if (pApp)
450  pApp->ConsumeFrames();
451 
452 } // ConsumerThreadStatic
453 
454 
456 {
457  AUTOCIRCULATE_TRANSFER outputXfer;
458  AUTOCIRCULATE_STATUS outputStatus;
459  ULWord goodXfers(0), badXfers(0), starves(0), noRoomWaits(0), startFrm(3);
460 
461  // Stop AutoCirculate, just in case someone else left it running...
462  mDevice.AutoCirculateStop(mConfig.fOutputChannel);
463  mDevice.WaitForOutputVerticalInterrupt(mConfig.fOutputChannel, 4); // Let it stop
464  PLNOTE("Thread started");
465 
466  // Initialize & start AutoCirculate...
467  bool initOK = mDevice.AutoCirculateInitForOutput (mConfig.fOutputChannel, mConfig.fFrames.count(),
468  mAudioSystem, AUTOCIRCULATE_WITH_RP188, /*numChannels*/ 1,
469  mConfig.fFrames.firstFrame(), mConfig.fFrames.lastFrame());
470  if (!initOK)
471  {PLFAIL("AutoCirculateInitForOutput failed"); mGlobalQuit = true;}
472  else if (!mConfig.WithVideo())
473  { // Video suppressed --
474  // Clear device frame buffers being AutoCirculated (prevent garbage output frames)
475  NTV2Buffer tmpFrame (mFormatDesc.GetVideoWriteSize());
476  NTV2TestPatternGen blackPatternGen;
477  blackPatternGen.DrawTestPattern (NTV2_TestPatt_Black, mFormatDesc, tmpFrame);
478  mDevice.AutoCirculateGetStatus (mConfig.fOutputChannel, outputStatus);
479  for (uint16_t frmNum(outputStatus.GetStartFrame()); frmNum <= outputStatus.GetEndFrame(); frmNum++)
480  mDevice.DMAWriteFrame(ULWord(frmNum), tmpFrame, mFormatDesc.GetTotalBytes());
481  } // else if --novideo
482  if (initOK && mDevice.AutoCirculateGetStatus (mConfig.fOutputChannel, outputStatus))
483  { startFrm = outputStatus.GetFrameCount() - 1;
484  if (startFrm > 3)
485  startFrm = 3;
486  }
487 
488  while (!mGlobalQuit)
489  {
490  mDevice.AutoCirculateGetStatus (mConfig.fOutputChannel, outputStatus);
491 
492  // Check if there's room for another frame on the card...
493  if (outputStatus.CanAcceptMoreOutputFrames())
494  {
495  // Device has at least one free frame buffer that can be filled.
496  // Wait for the next frame in our ring to become ready to "consume"...
497  NTV2FrameData * pFrameData (mFrameDataRing.StartConsumeNextBuffer());
498  if (!pFrameData)
499  {starves++; continue;}
500 
501  outputXfer.SetOutputTimeCodes(pFrameData->fTimecodes);
502 
503  if (pFrameData->VideoBuffer()) // Transfer the timecode-burned frame to the device for playout...
504  outputXfer.SetVideoBuffer (pFrameData->VideoBuffer(), pFrameData->VideoBufferSize());
505  if (pFrameData->AudioBuffer()) // If also playing audio...
506  outputXfer.SetAudioBuffer (pFrameData->AudioBuffer(), pFrameData->fNumAudioBytes);
507 
508 
509  // Perform the DMA transfer to the device...
510  if (mDevice.AutoCirculateTransfer (mConfig.fOutputChannel, outputXfer))
511  { if (++goodXfers == startFrm)
512  mDevice.AutoCirculateStart(mConfig.fOutputChannel);
513  }
514  else
515  badXfers++;
516 
517  // Signal that the frame has been "consumed"...
518  mFrameDataRing.EndConsumeNextBuffer();
519  continue; // Back to top of while loop
520 
521  }
522 
523  // Wait for one or more buffers to become available on the device, which should occur at next VBI...
524  noRoomWaits++;
526  } // loop til quit signaled
527 
528  // Stop AutoCirculate...
529  mDevice.AutoCirculateStop(mConfig.fOutputChannel);
530  PLNOTE("Thread completed: " << DEC(goodXfers) << " xfers, " << DEC(badXfers) << " failed, "
531  << DEC(starves) << " starves, " << DEC(noRoomWaits) << " VBI waits");
532 
533 } // ConsumeFrames
534 
535 
536 
538 // This is where the producer thread starts
539 
541 {
542  // Create and start the producer thread...
543  mProducerThread.Attach(ProducerThreadStatic, this);
544  mProducerThread.SetPriority(AJA_ThreadPriority_High);
545  mProducerThread.Start();
546 
547 } // StartProducerThread
548 
549 
550 void NTV2DolbyPlayer::ProducerThreadStatic (AJAThread * pThread, void * pContext) // static
551 {
552  (void) pThread;
553  NTV2DolbyPlayer * pApp (reinterpret_cast <NTV2DolbyPlayer *> (pContext));
554  if (pApp)
555  pApp->ProduceFrames ();
556 
557 } // ProducerThreadStatic
558 
559 
561 {
562  ULWord freqNdx(0), testPatNdx(0), badTally(0);
563  double timeOfLastSwitch (0.0);
564 
567  //const bool isInterlace (!NTV2_VIDEO_FORMAT_HAS_PROGRESSIVE_PICTURE(mConfig.fVideoFormat));
568  //const bool isPAL (NTV2_IS_PAL_VIDEO_FORMAT(mConfig.fVideoFormat));
569  const NTV2FrameRate ntv2FrameRate (::GetNTV2FrameRateFromVideoFormat(mConfig.fVideoFormat));
570  const TimecodeFormat tcFormat (CNTV2DemoCommon::NTV2FrameRate2TimecodeFormat(ntv2FrameRate));
571 
572  PLNOTE("Thread started");
573  while (!mGlobalQuit)
574  {
575  NTV2FrameData * pFrameData (mFrameDataRing.StartProduceNextBuffer());
576  // If no frame is available, wait and try again
577  if (!pFrameData)
578  { badTally++; // No frame available!
579  AJATime::Sleep(10); // Wait a bit for the consumer thread to free one up for me...
580  continue; // ...then try again
581  }
582 
583  // Copy my pre-made test pattern into my video buffer...
584  if (pFrameData->VideoBuffer()) // Copy fresh, unmodified, pre-rendered test pattern into this frame's video buffer...
585  pFrameData->fVideoBuffer.CopyFrom (mTestPatRasters.at(testPatNdx),
586  /*srcOffset*/ 0,
587  /*dstOffset*/ 0,
588  /*byteCount*/ ULWord(pFrameData->fVideoBuffer.GetByteCount()));
589 
590  const CRP188 rp188Info (mCurrentFrame++, 0, 0, 10, tcFormat);
591  NTV2_RP188 tcF1;
592  string tcString;
593 
594  rp188Info.GetRP188Reg (tcF1);
595  rp188Info.GetRP188Str (tcString);
596 
597  if (pFrameData->VideoBuffer()) // Burn current timecode into the video buffer...
598  mTCBurner.BurnTimeCode (pFrameData->VideoBuffer(), tcString.c_str(), 80);
599  TCDBG("F" << DEC0N(mCurrentFrame-1,6) << ": " << tcF1 << ": " << tcString);
600 
601  // If also playing audio...
602  if (pFrameData->AudioBuffer()) // ...then generate audio tone data for this frame...
603  {
604  if (mDolbyFileIO.IsOpen())
605  pFrameData->fNumAudioBytes = AddDolby(*pFrameData);
606  else
607  {
608  if (mConfig.fDoRamp)
609  pFrameData->fNumAudioBytes = AddRamp(*pFrameData);
610  else
611  pFrameData->fNumAudioBytes = AddTone(*pFrameData);
612  }
613  }
614 
615  // Every few seconds, change the test pattern and tone frequency...
616  const double currentTime (timeBase.FramesToSeconds(mCurrentFrame));
617  if (currentTime > timeOfLastSwitch + 4.0)
618  {
619  freqNdx = (freqNdx + 1) % gNumFrequencies;
620  testPatNdx = (testPatNdx + 1) % ULWord(mTestPatRasters.size());
621  mToneFrequency = gFrequencies[freqNdx];
622  timeOfLastSwitch = currentTime;
623  PLINFO("F" << DEC0N(mCurrentFrame,6) << ": " << tcString << ": tone=" << mToneFrequency << "Hz, pattern='" << tpNames.at(testPatNdx) << "'");
624  } // if time to switch test pattern & tone frequency
625 
626  // Signal that I'm done producing this FrameData, making it immediately available for transfer/playout...
627  mFrameDataRing.EndProduceNextBuffer();
628 
629  } // loop til mGlobalQuit goes true
630  PLNOTE("Thread completed: " << DEC(mCurrentFrame) << " frame(s) produced, " << DEC(badTally) << " failed");
631 
632 } // ProduceFrames
633 
635 {
636  mDevice.AutoCirculateGetStatus (mConfig.fOutputChannel, outStatus);
637 }
638 
639 
640 uint32_t NTV2DolbyPlayer::AddTone (NTV2FrameData & inFrameData)
641 {
644  ULWord numChannels (0);
645 
646  mDevice.GetFrameRate (frameRate, mConfig.fOutputChannel);
647  mDevice.GetAudioRate (audioRate, mAudioSystem);
648  mDevice.GetNumberAudioChannels (numChannels, mAudioSystem);
649 
650  // Set per-channel tone frequencies...
651  double pFrequencies [kNumAudioChannelsMax];
652  pFrequencies [0] = (mToneFrequency / 2.0);
653  for (ULWord chan (1); chan < numChannels; chan++)
654  // The 1.154782 value is the 16th root of 10, to ensure that if mToneFrequency is 2000,
655  // that the calculated frequency of audio channel 16 will be 20kHz...
656  pFrequencies [chan] = pFrequencies [chan - 1] * 1.154782;
657 
658  // Because audio on AJA devices use fixed sample rates (typically 48KHz), certain video frame rates will necessarily
659  // result in some frames having more audio samples than others. The GetAudioSamplesPerFrame function
660  // is used to calculate the correct sample count...
661  const ULWord numSamples (::GetAudioSamplesPerFrame (frameRate, audioRate, mCurrentFrame));
662  const double sampleRateHertz (::GetAudioSamplesPerSecond(audioRate));
663 
664  return ::AddAudioTone ( inFrameData.AudioBuffer(), // audio buffer to fill
665  mCurrentSample, // which sample for continuing the waveform
666  numSamples, // number of samples to generate
667  sampleRateHertz, // sample rate [Hz]
668  gAmplitudes, // per-channel amplitudes
669  pFrequencies, // per-channel tone frequencies [Hz]
670  31, // bits per sample
671  false, // don't byte swap
672  numChannels); // number of audio channels to generate
673 } // AddTone
674 
675 uint32_t NTV2DolbyPlayer::AddRamp (NTV2FrameData & inFrameData)
676 {
677  ULWord * audioBuffer (inFrameData.AudioBuffer());
680  ULWord numChannels (0);
681 
682  mDevice.GetFrameRate (frameRate, mConfig.fOutputChannel);
683  mDevice.GetAudioRate (audioRate, mAudioSystem);
684  mDevice.GetNumberAudioChannels (numChannels, mAudioSystem);
685 
686  // Because audio on AJA devices use fixed sample rates (typically 48KHz), certain video frame rates will necessarily
687  // result in some frames having more audio samples than others. The GetAudioSamplesPerFrame function
688  // is used to calculate the correct sample count...
689  const ULWord numSamples (::GetAudioSamplesPerFrame (frameRate, audioRate, mCurrentFrame));
690 
691  for (uint32_t samp(0); samp < numSamples; samp++)
692  {
693  for (uint32_t ch(0); ch < numChannels; ch++)
694  {
695  *audioBuffer = uint32_t(mRampSample) << 16;
696  audioBuffer++;
697  mRampSample++;
698  } // for each channel
699  } // for each sample
700 
701  return numSamples * numChannels * 4;
702 } // AddRamp
703 
704 #if defined(DOLBY_FULL_PARSER)
705 
706 uint32_t NTV2DolbyPlayer::AddDolby (NTV2FrameData & inFrameData)
707 {
708  ULWord* audioBuffer (inFrameData.AudioBuffer());
711  ULWord numChannels (0);
712  ULWord sampleOffset(0);
713  ULWord sampleCount (0);
714  NTV2DolbyBSI bsi;
715 
716  mDevice.GetFrameRate (frameRate, mConfig.fOutputChannel);
717  mDevice.GetAudioRate (audioRate, mAudioSystem);
718  mDevice.GetNumberAudioChannels (numChannels, mAudioSystem);
719  const ULWord numSamples (::GetAudioSamplesPerFrame (frameRate, audioRate, mCurrentFrame));
720 
721  if (!mDolbyFileIO.IsOpen() || !mDolbyBuffer)
722  goto silence;
723 
724  // Generate the samples for this frame
725  while (sampleOffset < numSamples)
726  {
727  if ((mBurstSize != 0) && (mBurstIndex < mBurstSamples))
728  {
729  if(mBurstOffset < mBurstSize)
730  {
731  uint32_t data0 = 0;
732  uint32_t data1 = 0;
733  if (mBurstIndex == 0)
734  {
735  // Add IEC61937 burst preamble
736  data0 = 0xf872; // Sync stuff
737  data1 = 0x4e1f;
738  }
739  else if (mBurstIndex == 1)
740  {
741  // Add more IEC61937 burst preamble
742  data0 = ((bsi.bsmod & 0x7) << 8) | 0x0015; // This is Dolby
743  data1 = mBurstSize * 2; // Data size in bytes
744  }
745  else
746  {
747  // Add sync frame data
748  data0 = (uint32_t)(mBurstBuffer[mBurstOffset]);
749  data0 = ((data0 & 0x00ff) << 8) | ((data0 & 0xff00) >> 8);
750  mBurstOffset++;
751  data1 = (uint32_t)(mBurstBuffer[mBurstOffset]);
752  data1 = ((data1 & 0x00ff) << 8) | ((data1 & 0xff00) >> 8);
753  mBurstOffset++;
754  }
755 
756  // Write data into 16 msbs of all audio channel pairs
757  data0 <<= 16;
758  data1 <<= 16;
759  for (ULWord i = 0; i < numChannels; i += 2)
760  {
761  audioBuffer[sampleOffset * numChannels + i] = data0;
762  audioBuffer[sampleOffset * numChannels + i + 1] = data1;
763  }
764  }
765  else
766  {
767  // Pad samples out to burst size
768  for (ULWord i = 0; i < numChannels; i++)
769  {
770  audioBuffer[sampleOffset * numChannels + i] = 0;
771  }
772  }
773  sampleOffset++;
774  mBurstIndex++;
775  }
776  else
777  {
778  ULWord dolbyOffset = 0;
779  ULWord burstOffset = 0;
780  ULWord numBlocks = 0;
781 
782  mBurstIndex = 0;
783  mBurstOffset = 0;
784 
785  if (mDolbySize == 0)
786  {
787  // Find first Dolby Digital Plus burst frame
788  while (true)
789  {
790  if (!GetDolbyFrame(&mDolbyBuffer[0], sampleCount))
791  {
792  cerr << "## ERROR: Dolby frame not found" << endl;
793  mDolbyFileIO.Close();
794  goto silence;
795  }
796 
797  if (!ParseBSI(&mDolbyBuffer[1], sampleCount - 1, &bsi))
798  continue;
799 
800  if ((bsi.strmtyp == 0) &&
801  (bsi.substreamid == 0) &&
802  (bsi.bsid == 16) &&
803  ((bsi.numblkscod == 3) || (bsi.convsync == 1)))
804  break;
805  }
806 
807  mDolbySize = sampleCount;
808  switch (bsi.numblkscod)
809  {
810  case 0: mDolbyBlocks = 1; break;
811  case 1: mDolbyBlocks = 2; break;
812  case 2: mDolbyBlocks = 3; break;
813  case 3: mDolbyBlocks = 6; break;
814  default: goto silence;
815  }
816  }
817 
818  while (numBlocks <= 6)
819  {
820  // Copy the Dolby frame into the burst buffer
821  while (dolbyOffset < mDolbySize)
822  {
823  // Check for burst size overrun
824  if (burstOffset >= mBurstMax)
825  {
826  cerr << "## ERROR: Dolby burst too large" << endl;
827  mDolbyFileIO.Close();
828  goto silence;
829  }
830 
831  // Copy sample
832  mBurstBuffer[burstOffset] = mDolbyBuffer[dolbyOffset];
833  burstOffset++;
834  dolbyOffset++;
835  }
836 
837  // Get the next Dolby frame
838  if (!GetDolbyFrame(&mDolbyBuffer[0], sampleCount))
839  {
840  // try to loop
841  if (!GetDolbyFrame(&mDolbyBuffer[0], sampleCount))
842  {
843  cerr << "## ERROR: Dolby frame not found" << endl;
844  mDolbyFileIO.Close();
845  goto silence;
846  }
847  }
848 
849  // Parse the Dolby bitstream header
850  if (!ParseBSI(&mDolbyBuffer[1], sampleCount - 1, &bsi))
851  continue;
852 
853  // Only Dolby Digital Plus
854  if (bsi.bsid != 16)
855  {
856  cerr << "## ERROR: Dolby frame bad bsid = " << bsi.bsid << endl;
857  continue;
858  }
859 
860  mDolbySize = sampleCount;
861  dolbyOffset = 0;
862 
863  // Increment block count on first substream
864  if ((bsi.strmtyp == 0) && (bsi.substreamid == 0))
865  {
866  // increment block count
867  numBlocks += mDolbyBlocks;
868 
869  switch (bsi.numblkscod)
870  {
871  case 0: mDolbyBlocks = 1; break;
872  case 1: mDolbyBlocks = 2; break;
873  case 2: mDolbyBlocks = 3; break;
874  case 3: mDolbyBlocks = 6; break;
875  default:
876  cerr << "## ERROR: Dolby frame bad numblkscod = " << bsi.numblkscod << endl;
877  goto silence;
878  }
879  }
880 
881  // Are we done?
882  if (numBlocks >= 6)
883  {
884  // First frame of new burst must have convsync == 1
885  if ((bsi.numblkscod != 3) &&
886  (bsi.convsync != 1))
887  {
888  cerr << "## ERROR: Dolby frame unexpected convsync = " << bsi.convsync << endl;
889  mDolbySize = 0;
890  mDolbyBlocks = 0;
891  }
892 
893  // Keep the burst size
894  mBurstSize = burstOffset;
895  break;
896  }
897  }
898  }
899  }
900 
901  return numSamples * numChannels * 4;
902 
903 silence:
904  // Output silence when done with file
905  memset(&audioBuffer[sampleOffset * numChannels], 0, (numSamples - sampleOffset) * numChannels * 4);
906  return numSamples * numChannels * 4;
907 }
908 
909 
910 bool NTV2DolbyPlayer::GetDolbyFrame (uint16_t * pInDolbyBuffer, uint32_t & numSamples)
911 {
912  uint32_t bytes;
913  bool done = false;
914 
915  while (!done)
916  {
917  bytes = mDolbyFileIO.Read((uint8_t*)(&pInDolbyBuffer[0]), 2);
918  if (bytes != 2)
919  {
920  // Reset file
921  mDolbyFileIO.Seek(0, eAJASeekSet);
922  return false;
923  }
924 
925  // Check sync word
926  if ((mDolbyBuffer[0] == 0x7705) ||
927  (mDolbyBuffer[0] == 0x770b))
928  done = true;
929  }
930 
931  // Read more of the sync frame header
932  bytes = mDolbyFileIO.Read((uint8_t*)(&pInDolbyBuffer[1]), 4);
933  if (bytes != 4)
934  return false;
935 
936  // Get frame size - 16 bit words plus sync word
937  uint32_t size = (uint32_t)mDolbyBuffer[1];
938  size = (((size & 0x00ff) << 8) | ((size & 0xff00) >> 8));
939  size = (size & 0x7ff) + 1;
940 
941  // Read the rest of the sync frame
942  uint32_t len = (size - 3) * 2;
943  bytes = mDolbyFileIO.Read((uint8_t*)(&pInDolbyBuffer[3]), len);
944  if (bytes != len)
945  return false;
946 
947  numSamples = size;
948 
949  return true;
950 }
951 
952 
953 bool NTV2DolbyPlayer::ParseBSI(uint16_t * pInDolbyBuffer, uint32_t numSamples, NTV2DolbyBSI * pBsi)
954 {
955  if ((pInDolbyBuffer == NULL) || (pBsi == NULL))
956  return false;
957 
958  memset(pBsi, 0, sizeof(NTV2DolbyBSI));
959 
960  SetBitBuffer((uint8_t*)pInDolbyBuffer, numSamples * 2);
961 
962  if (!GetBits(pBsi->strmtyp, 2)) return false;
963  if (!GetBits(pBsi->substreamid, 3)) return false;
964  if (!GetBits(pBsi->frmsiz, 11)) return false;
965  if (!GetBits(pBsi->fscod, 2)) return false;
966  if (!GetBits(pBsi->numblkscod, 2)) return false;
967  if (!GetBits(pBsi->acmod, 3)) return false;
968  if (!GetBits(pBsi->lfeon, 1)) return false;
969  if (!GetBits(pBsi->bsid, 5)) return false;
970  if (!GetBits(pBsi->dialnorm, 5)) return false;
971  if (!GetBits(pBsi->compre, 1)) return false;
972  if (pBsi->compre)
973  {
974  if (!GetBits(pBsi->compr, 8)) return false;
975  }
976  if (pBsi->acmod == 0x0) /* if 1+1 mode (dual mono, so some items need a second value) */
977  {
978  if (!GetBits(pBsi->dialnorm2, 5)) return false;
979  if (!GetBits(pBsi->compr2e, 1)) return false;
980  if (pBsi->compr2e)
981  {
982  if (!GetBits(pBsi->compr2, 8)) return false;
983  }
984  }
985  if (pBsi->strmtyp == 0x1) /* if dependent stream */
986  {
987  if (!GetBits(pBsi->chanmape, 1)) return false;
988  if (pBsi->chanmape)
989  {
990  if (!GetBits(pBsi->chanmap, 16)) return false;
991  }
992  }
993  if (!GetBits(pBsi->mixmdate, 1)) return false;
994  if (pBsi->mixmdate) /* mixing metadata */
995  {
996  if (pBsi->acmod > 0x2) /* if more than 2 channels */
997  {
998  if (!GetBits(pBsi->dmixmod, 2)) return false;
999  }
1000  if ((pBsi->acmod & 0x1) && (pBsi->acmod > 0x2)) /* if three front channels exist */
1001  {
1002  if (!GetBits(pBsi->ltrtcmixlev, 3)) return false;
1003  if (!GetBits(pBsi->lorocmixlev, 3)) return false;
1004  }
1005  if (pBsi->acmod & 0x4) /* if a surround channel exists */
1006  {
1007  if (!GetBits(pBsi->ltrtsurmixlev, 3)) return false;
1008  if (!GetBits(pBsi->lorosurmixlev, 3)) return false;
1009  }
1010  if (pBsi->lfeon) /* if the LFE channel exists */
1011  {
1012  if (!GetBits(pBsi->lfemixlevcode, 1)) return false;
1013  if (pBsi->lfemixlevcode)
1014  {
1015  if (!GetBits(pBsi->lfemixlevcod, 5)) return false;
1016  }
1017  }
1018  if (pBsi->strmtyp == 0x0) /* if independent stream */
1019  {
1020  if (!GetBits(pBsi->pgmscle, 1)) return false;
1021  if (pBsi->pgmscle)
1022  {
1023  if (!GetBits(pBsi->pgmscl, 6)) return false;
1024  }
1025  if (pBsi->acmod == 0x0) /* if 1+1 mode (dual mono, so some items need a second value) */
1026  {
1027  if (!GetBits(pBsi->pgmscl2e, 1)) return false;
1028  if (pBsi->pgmscl2e)
1029  {
1030  if (!GetBits(pBsi->pgmscl2, 6)) return false;
1031  }
1032  }
1033  if (!GetBits(pBsi->extpgmscle, 1)) return false;
1034  if (pBsi->extpgmscle)
1035  {
1036  if (!GetBits(pBsi->extpgmscl, 6)) return false;
1037  }
1038  if (!GetBits(pBsi->mixdef, 2)) return false;
1039  if (pBsi->mixdef == 0x1) /* mixing option 2 */
1040  {
1041  if (!GetBits(pBsi->premixcmpsel, 1)) return false;
1042  if (!GetBits(pBsi->drcsrc, 1)) return false;
1043  if (!GetBits(pBsi->premixcmpscl, 3)) return false;
1044  }
1045  else if (pBsi->mixdef == 0x2) /* mixing option 3 */
1046  {
1047  if (!GetBits(pBsi->mixdata, 12)) return false;
1048  }
1049  else if (pBsi->mixdef == 0x3) /* mixing option 4 */
1050  {
1051  if (!GetBits(pBsi->mixdeflen, 5)) return false;
1052  if (!GetBits(pBsi->mixdata2e, 1)) return false;
1053  if (pBsi->mixdata2e)
1054  {
1055  if (!GetBits(pBsi->premixcmpsel, 1)) return false;
1056  if (!GetBits(pBsi->drcsrc, 1)) return false;
1057  if (!GetBits(pBsi->premixcmpscl, 3)) return false;
1058  if (!GetBits(pBsi->extpgmlscle, 1)) return false;
1059  if (pBsi->extpgmlscle)
1060  {
1061  if (!GetBits(pBsi->extpgmlscl, 4)) return false;
1062  }
1063  if (!GetBits(pBsi->extpgmcscle, 1)) return false;
1064  if (pBsi->extpgmcscle)
1065  {
1066  if (!GetBits(pBsi->extpgmcscl, 4)) return false;
1067  }
1068  if (!GetBits(pBsi->extpgmrscle, 1)) return false;
1069  if (pBsi->extpgmrscle)
1070  {
1071  if (!GetBits(pBsi->extpgmrscl, 4)) return false;
1072  }
1073  if (!GetBits(pBsi->extpgmlsscle, 1)) return false;
1074  if (pBsi->extpgmlsscle)
1075  {
1076  if (!GetBits(pBsi->extpgmlsscl, 4)) return false;
1077  }
1078  if (!GetBits(pBsi->extpgmrsscle, 1)) return false;
1079  if (pBsi->extpgmrsscle)
1080  {
1081  if (!GetBits(pBsi->extpgmrsscl, 4)) return false;
1082  }
1083  if (!GetBits(pBsi->extpgmlfescle, 1)) return false;
1084  if (pBsi->extpgmlfescle)
1085  {
1086  if (!GetBits(pBsi->extpgmlfescl, 4)) return false;
1087  }
1088  if (!GetBits(pBsi->dmixscle, 1)) return false;
1089  if (pBsi->dmixscle)
1090  {
1091  if (!GetBits(pBsi->dmixscl, 4)) return false;
1092  }
1093  if (!GetBits(pBsi->addche, 1)) return false;
1094  if (pBsi->addche)
1095  {
1096  if (!GetBits(pBsi->extpgmaux1scle, 1)) return false;
1097  if (pBsi->extpgmaux1scle)
1098  {
1099  if (!GetBits(pBsi->extpgmaux1scl, 4)) return false;
1100  }
1101  if (!GetBits(pBsi->extpgmaux2scle, 1)) return false;
1102  if (pBsi->extpgmaux2scle)
1103  {
1104  if (!GetBits(pBsi->extpgmaux2scl, 4)) return false;
1105  }
1106  }
1107  }
1108  if (!GetBits(pBsi->mixdata3e, 1)) return false;
1109  if (pBsi->mixdata3e)
1110  {
1111  if (!GetBits(pBsi->spchdat, 5)) return false;
1112  if (!GetBits(pBsi->addspchdate, 1)) return false;
1113  if (pBsi->addspchdate)
1114  {
1115  if (!GetBits(pBsi->spchdat1, 5)) return false;
1116  if (!GetBits(pBsi->spchan1att, 2)) return false;
1117  if (!GetBits(pBsi->addspchdat1e, 1)) return false;
1118  if (pBsi->addspdat1e)
1119  {
1120  if (!GetBits(pBsi->spchdat2, 5)) return false;
1121  if (!GetBits(pBsi->spchan2att, 3)) return false;
1122  }
1123  }
1124  }
1125  {
1126  uint32_t data;
1127  uint32_t size = 8 * (pBsi->mixdeflen + 2);
1128  size = (size + 7) / 8 * 8;
1129  uint32_t index = 0;
1130  while (size > 0)
1131  {
1132  if (!GetBits(data, (size > 8)? 8 : size)) return false;
1133  pBsi->mixdatabuffer[index++] = (uint8_t)data;
1134  size = size - 8;
1135  }
1136  }
1137  }
1138  if (pBsi->acmod < 0x2) /* if mono or dual mono source */
1139  {
1140  if (!GetBits(pBsi->paninfoe, 1)) return false;
1141  if (pBsi->paninfoe)
1142  {
1143  if (!GetBits(pBsi->panmean, 8)) return false;
1144  if (!GetBits(pBsi->paninfo, 6)) return false;
1145  }
1146  if (pBsi->acmod == 0x0) /* if 1+1 mode (dual mono - some items need a second value) */
1147  {
1148  if (!GetBits(pBsi->paninfo2e, 1)) return false;
1149  if (pBsi->paninfo2e)
1150  {
1151  if (!GetBits(pBsi->panmean2, 8)) return false;
1152  if (!GetBits(pBsi->paninfo2, 6)) return false;
1153  }
1154  }
1155  }
1156  if (!GetBits(pBsi->frmmixcfginfoe, 1)) return false;
1157  if (pBsi->frmmixcfginfoe) /* mixing configuration information */
1158  {
1159  if (pBsi->numblkscod == 0x0)
1160  {
1161  if (!GetBits(pBsi->blkmixcfginfo[0], 5)) return false;
1162  }
1163  else
1164  {
1165  uint32_t blk;
1166  uint32_t numblk;
1167  if (pBsi->numblkscod == 0x1)
1168  numblk = 2;
1169  else if (pBsi->numblkscod == 0x2)
1170  numblk = 3;
1171  else if (pBsi->numblkscod == 0x3)
1172  numblk = 6;
1173  else
1174  return false;
1175  for(blk = 0; blk < numblk; blk++)
1176  {
1177  if (!GetBits(pBsi->blkmixcfginfoe, 1)) return false;
1178  if (pBsi->blkmixcfginfoe)
1179  {
1180  if (!GetBits(pBsi->blkmixcfginfo[blk], 5)) return false;
1181  }
1182  }
1183  }
1184  }
1185  }
1186  }
1187  if (!GetBits(pBsi->infomdate, 1)) return false;
1188  if (pBsi->infomdate) /* informational metadata */
1189  {
1190  if (!GetBits(pBsi->bsmod, 3)) return false;
1191  if (!GetBits(pBsi->copyrightb, 1)) return false;
1192  if (!GetBits(pBsi->origbs, 1)) return false;
1193  if (pBsi->acmod == 0x2) /* if in 2/0 mode */
1194  {
1195  if (!GetBits(pBsi->dsurmod, 2)) return false;
1196  if (!GetBits(pBsi->dheadphonmod, 2)) return false;
1197  }
1198  if (pBsi->acmod >= 0x6) /* if both surround channels exist */
1199  {
1200  if (!GetBits(pBsi->dsurexmod, 2)) return false;
1201  }
1202  if (!GetBits(pBsi->audprodie, 1)) return false;
1203  if (pBsi->audprodie)
1204  {
1205  if (!GetBits(pBsi->mixlevel, 5)) return false;
1206  if (!GetBits(pBsi->roomtyp, 2)) return false;
1207  if (!GetBits(pBsi->adconvtyp, 1)) return false;
1208  }
1209  if (pBsi->acmod == 0x0) /* if 1+1 mode (dual mono, so some items need a second value) */
1210  {
1211  if (!GetBits(pBsi->audprodi2e, 1)) return false;
1212  if (pBsi->audprodi2e)
1213  {
1214  if (!GetBits(pBsi->mixlevel2, 5)) return false;
1215  if (!GetBits(pBsi->roomtyp2, 2)) return false;
1216  if (!GetBits(pBsi->adconvtyp2, 1)) return false;
1217  }
1218  }
1219  if (pBsi->fscod < 0x3) /* if not half sample rate */
1220  {
1221  if (!GetBits(pBsi->sourcefscod, 1)) return false;
1222  }
1223  }
1224  if ((pBsi->strmtyp == 0x0) && (pBsi->numblkscod != 0x3))
1225  {
1226  if (!GetBits(pBsi->convsync, 1)) return false;
1227  }
1228  if (pBsi->strmtyp == 0x2) /* if bit stream converted from AC-3 */
1229  {
1230  if (pBsi->numblkscod == 0x3) /* 6 blocks per syncframe */
1231  {
1232  pBsi->blkid = 1;
1233  }
1234  else
1235  {
1236  if (!GetBits(pBsi->blkid, 1)) return false;
1237  }
1238  if (pBsi->blkid)
1239  {
1240  if (!GetBits(pBsi->frmsizecod, 6)) return false;
1241  }
1242  }
1243  if (!GetBits(pBsi->addbsie, 1)) return false;
1244  if (pBsi->addbsie)
1245  {
1246  if (!GetBits(pBsi->addbsil, 6)) return false;
1247  {
1248  uint32_t data;
1249  uint32_t size = 8 * (pBsi->addbsil + 1);
1250  uint32_t index = 0;
1251  while (size > 0)
1252  {
1253  if (!GetBits(data, 8)) return false;
1254  pBsi->addbsibuffer[index++] = (uint8_t)data;
1255  size = size - 8;
1256  }
1257  }
1258  }
1259 
1260  return true;
1261 }
1262 
1263 void NTV2DolbyPlayer::SetBitBuffer(uint8_t * pBuffer, uint32_t size)
1264 {
1265  mBitBuffer = pBuffer;
1266  mBitSize = size;
1267  mBitIndex = 8;
1268 }
1269 
1270 bool NTV2DolbyPlayer::GetBits(uint32_t & data, uint32_t bits)
1271 {
1272  uint32_t cb;
1273  static uint8_t bitMask[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
1274 
1275  data = 0;
1276  while (bits > 0)
1277  {
1278  if (mBitSize == 0)
1279  return false;
1280 
1281  if (mBitIndex == 0)
1282  {
1283  mBitBuffer++;
1284  mBitSize--;
1285  mBitIndex = 8;
1286  }
1287 
1288  cb = bits;
1289  if (cb > mBitIndex)
1290  cb = mBitIndex;
1291  bits -= cb;
1292  mBitIndex -= cb;
1293  data |= ((*mBitBuffer >> mBitIndex) & bitMask[cb]) << bits;
1294  }
1295 
1296  return true;
1297 }
1298 
1299 #else // DOLBY_FULL_PARSER
1300 // NOTE: The code under this #else is out of date and not maintaiend
1301 uint32_t NTV2DolbyPlayer::AddDolby (ULWord * pInAudioBuffer)
1302 {
1305  ULWord numChannels (0);
1306  ULWord sampleOffset(0);
1307 
1308  mDevice.GetFrameRate (frameRate, mOutputChannel);
1309  mDevice.GetAudioRate (audioRate, mAudioSystem);
1310  mDevice.GetNumberAudioChannels (numChannels, mAudioSystem);
1311  const ULWord numSamples (::GetAudioSamplesPerFrame (frameRate, audioRate, mCurrentFrame));
1312 
1313  if ((mConfig.fDolbyFile == NULL) || (mDolbyBuffer == NULL))
1314  goto silence;
1315 
1316  // Generate the samples for this frame
1317  while (sampleOffset < numSamples)
1318  {
1319  // Time for a new IEC61937 burst
1320  if (mBurstIndex >= mBurstSamples)
1321  mBurstIndex = 0;
1322 
1323  // Get a new Dolby Digital Plus sync frame
1324  if (mBurstIndex == 0)
1325  {
1326  // Read the sync word (all big endian)
1327  uint32_t bytes = mConfig.fDolbyFile->Read((uint8_t*)(&mDolbyBuffer[0]), 2);
1328  if (bytes != 2)
1329  {
1330  // Try to loop
1331  mConfig.fDolbyFile->Seek(0, eAJASeekSet);
1332  bytes = mConfig.fDolbyFile->Read((uint8_t*)(&mDolbyBuffer[0]), 2);
1333  if (bytes != 2)
1334  goto silence;
1335  }
1336 
1337  // Check sync word
1338  if ((mDolbyBuffer[0] != 0x7705) &&
1339  (mDolbyBuffer[0] != 0x770b))
1340  goto silence;
1341 
1342  // Read more of the sync frame header
1343  bytes = mConfig.fDolbyFile->Read((uint8_t*)(&mDolbyBuffer[1]), 4);
1344  if (bytes != 4)
1345  goto silence;
1346 
1347  // Get frame size - 16 bit words plus sync word
1348  uint32_t size = (uint32_t)mDolbyBuffer[1];
1349  size = (((size & 0x00ff) << 8) | ((size & 0xff00) >> 8)) + 1;
1350 
1351  // Read the rest of the sync frame
1352  uint32_t len = (size - 3) * 2;
1353  bytes = mConfig.fDolbyFile->Read((uint8_t*)(&mDolbyBuffer[3]), len);
1354  if (bytes != len)
1355  goto silence;
1356 
1357  // Good frame
1358  mBurstOffset = 0;
1359  mBurstSize = size;
1360  }
1361 
1362  // Add the Dolby data to the audio stream
1363  if (mBurstOffset < mBurstSize)
1364  {
1365  uint32_t data0 = 0;
1366  uint32_t data1 = 0;
1367  if (mBurstIndex == 0)
1368  {
1369  // Add IEC61937 burst preamble
1370  data0 = 0xf872; // Sync stuff
1371  data1 = 0x4e1f;
1372  }
1373  else if (mBurstIndex == 1)
1374  {
1375  // Add more IEC61937 burst preamble
1376  data0 = 0x0015; // This is Dolby
1377  data1 = mBurstSize * 2; // Data size in bytes
1378  }
1379  else
1380  {
1381  // Add sync frame data
1382  data0 = (uint32_t)(mDolbyBuffer[mBurstOffset]);
1383  data0 = ((data0 & 0x00ff) << 8) | ((data0 & 0xff00) >> 8);
1384  mBurstOffset++;
1385  data1 = (uint32_t)(mDolbyBuffer[mBurstOffset]);
1386  data1 = ((data1 & 0x00ff) << 8) | ((data1 & 0xff00) >> 8);
1387  mBurstOffset++;
1388  }
1389 
1390  // Write data into 16 msbs of all audio channel pairs
1391  data0 <<= 16;
1392  data1 <<= 16;
1393  for (ULWord i = 0; i < numChannels; i += 2)
1394  {
1395  pInAudioBuffer[sampleOffset * numChannels + i] = data0;
1396  pInAudioBuffer[sampleOffset * numChannels + i + 1] = data1;
1397  }
1398  }
1399  else
1400  {
1401  // Pad samples out to burst size
1402  for (ULWord i = 0; i < numChannels; i++)
1403  {
1404  pInAudioBuffer[sampleOffset * numChannels + i] = 0;
1405  }
1406  }
1407 
1408  sampleOffset++;
1409  mBurstIndex++;
1410  }
1411 
1412  return numSamples * numChannels * 4;
1413 
1414 silence:
1415  // Output silence when done with file
1416  memset(&pInAudioBuffer[sampleOffset * numChannels], 0, (numSamples - sampleOffset) * numChannels * 4);
1417  return numSamples * numChannels * 4;
1418 }
1419 #endif // else DOLBY_FULL_PARSER
1420 
1421 AJALabelValuePairs DolbyPlayerConfig::Get (const bool inCompact) const
1422 {
1423  AJALabelValuePairs result (PlayerConfig::Get(inCompact));
1424  AJASystemInfo::append (result, "Dolby Playback File", fDolbyFilePath.empty() ? "---" : fDolbyFilePath);
1425  AJASystemInfo::append (result, "Audio Data Ramp", fDoRamp ? "Yes" : "No");
1426  return result;
1427 }
1428 
1429 std::ostream & operator << (std::ostream & ioStrm, const DolbyPlayerConfig & inObj)
1430 {
1431  ioStrm << AJASystemInfo::ToString(inObj.Get());
1432  return ioStrm;
1433 }
ULWord GetVideoWriteSize(ULWord inPageSize=4096UL) const
bool SetOutputTimeCodes(const NTV2TimeCodes &inValues)
Intended for playout, replaces the contents of my acOutputTimeCodes member.
AJALabelValuePairs Get(const bool inCompact=(0)) const
Renders a human-readable representation of me.
NTV2FrameRate GetNTV2FrameRateFromVideoFormat(const NTV2VideoFormat inVideoFormat)
Definition: ntv2utils.cpp:3630
double FramesToSeconds(int64_t frames) const
Definition: timebase.cpp:205
virtual bool SetTaskMode(const NTV2TaskMode inMode)
Sets the device&#39;s task mode.
virtual bool GetDolbyFrame(uint16_t *pInDolbyBuffer, uint32_t &numSamples)
Get a dolby audio frame from the input file.
static const bool BUFFER_PAGE_ALIGNED((!(0)))
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 NTV2_IS_VALID_TASK_MODE(__m__)
virtual bool SetHDMIOutAudioSource2Channel(const NTV2AudioChannelPair inNewValue, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1, const NTV2Channel inWhichHDMIOut=NTV2_CHANNEL1)
Sets the HDMI output&#39;s 2-channel audio source.
Definition: ntv2audio.cpp:869
virtual bool SetAudioLoopBack(const NTV2AudioLoopBack inMode, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Enables or disables NTV2AudioLoopBack mode for the given NTV2AudioSystem.
Definition: ntv2audio.cpp:301
Specifies the device&#39;s internal clock.
Definition: ntv2enums.h:1464
virtual bool SetReference(const NTV2ReferenceSource inRefSource, const bool inKeepFramePulseSelect=(0))
Sets the device&#39;s clock reference source. See Video Output Clocking & Synchronization for more inform...
virtual bool ReleaseStreamForApplication(ULWord inApplicationType, int32_t inProcessID)
Releases exclusive use of the AJA device for the given process, permitting other processes to acquire...
virtual AJAStatus Run(void)
Runs me.
AJAStatus Add(FrameDataPtr pInFrameData)
Appends a new frame buffer to me, increasing my frame storage capacity by one frame.
The NTV2 test pattern generator.
#define DEC0N(__x__, __n__)
static const double gAmplitudes[]
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 bool IsDeviceReady(const bool inCheckValid=(0))
static uint64_t GetPid()
Definition: process.cpp:35
#define AJA_FAILURE(_status_)
Definition: types.h:373
#define PLINFO(_xpr_)
UWord count(void) const
Definition: ntv2utils.h:997
Declares the NTV2TestPatternGen class.
AJALabelValuePairs Get(const bool inCompact=(0)) const
virtual bool SubscribeOutputVerticalEvent(const NTV2Channel inChannel=NTV2_CHANNEL1)
Causes me to be notified when an output vertical blanking interrupt is generated for the given output...
Definition: ntv2card.h:2763
virtual bool GetAudioRate(NTV2AudioRate &outRate, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Returns the current NTV2AudioRate for the given Audio System.
Definition: ntv2audio.cpp:227
virtual AJAStatus SetUpHostBuffers(void)
Sets up my host video & audio buffers.
virtual bool DMAWriteFrame(const ULWord inFrameNumber, const ULWord *pInFrameBuffer, const ULWord inByteCount)
Transfers a single frame from the host to the AJA device.
Definition: ntv2dma.cpp:65
virtual AJAStatus SetUpAudio(void)
Performs all audio setup.
std::vector< AJALabelValuePair > AJALabelValuePairs
An ordered sequence of label/value pairs.
Definition: info.h:71
virtual AJAStatus SetPriority(AJAThreadPriority priority)
Definition: thread.cpp:133
FrameDataPtr StartConsumeNextBuffer(void)
The thread that&#39;s responsible for processing incoming frames – the consumer – calls this function t...
#define TCDBG(_expr_)
ULWord GetTotalBytes(void) const
virtual AJAStatus SetUpVideo(void)
Performs all video setup.
I am similar to NTV2Player, but I demonstrate how to play/output 8 channels of audio tone (or ramp da...
bool CanAcceptMoreOutputFrames(void) const
UWord firstFrame(void) const
Definition: ntv2utils.h:998
Definition: json.hpp:5362
virtual bool SetAudioRate(const NTV2AudioRate inRate, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Sets the NTV2AudioRate for the given Audio System.
Definition: ntv2audio.cpp:206
virtual AJAStatus Start()
Definition: thread.cpp:91
void EndConsumeNextBuffer(void)
The consumer thread calls this function to signal that it has finished processing the frame it obtain...
Declares common audio macros and structs used in the SDK.
std::string fDeviceSpec
The AJA device to use.
#define false
uint32_t ULWord
Definition: ajatypes.h:236
virtual bool AutoCirculateGetStatus(const NTV2Channel inChannel, AUTOCIRCULATE_STATUS &outStatus)
Returns the current AutoCirculate status for the given channel.
virtual bool SetFrameBufferFormat(NTV2Channel inChannel, NTV2FrameBufferFormat inNewFormat, bool inIsAJARetail=(!(0)), NTV2HDRXferChars inXferChars=NTV2_VPID_TC_SDR_TV, NTV2HDRColorimetry inColorimetry=NTV2_VPID_Color_Rec709, NTV2HDRLuminance inLuminance=NTV2_VPID_Luminance_YCbCr)
Sets the frame buffer format for the given FrameStore on the AJA device.
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.
bool WithAudio(void) const
virtual bool SetHDMIOutAudioRate(const NTV2AudioRate inNewValue, const NTV2Channel inWhichHDMIOut=NTV2_CHANNEL1)
Sets the HDMI output&#39;s audio rate.
Definition: ntv2audio.cpp:1010
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.
static const ULWord gNumFrequencies(sizeof(gFrequencies)/sizeof(double))
virtual std::string GetDescription(void) const
Definition: ntv2card.cpp:139
static TimecodeFormat NTV2FrameRate2TimecodeFormat(const NTV2FrameRate inFrameRate)
NTV2InputXptID GetOutputDestInputXpt(const NTV2OutputDestination inOutputDest, const bool inIsSDI_DS2=false, const UWord inHDMI_Quadrant=99)
virtual bool IsOpen(void) const
virtual void ConsumeFrames(void)
My consumer thread that repeatedly plays frames using AutoCirculate (until quit). ...
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 AutoCirculateTransfer(const NTV2Channel inChannel, AUTOCIRCULATE_TRANSFER &transferInfo)
Transfers all or part of a frame as specified in the given AUTOCIRCULATE_TRANSFER object to/from the ...
virtual bool AcquireStreamForApplication(ULWord inApplicationType, int32_t inProcessID)
Reserves exclusive use of the AJA device for a given process, preventing other processes on the host ...
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
void SetAbortFlag(const bool *pAbortFlag)
Tells me the boolean variable I should monitor such that when it gets set to "true" will cause any th...
virtual void ProduceFrames(void)
My producer thread that repeatedly produces video frames.
virtual uint32_t AddDolby(NTV2FrameData &inFrameData)
Inserts dolby audio into the given NTV2FrameData&#39;s audio buffer.
Describes a video frame for a given video standard or format and pixel format, including the total nu...
AJAStatus Open(const std::string &fileName, const int flags, const int properties)
Definition: file_io.cpp:201
NTV2DolbyPlayer(const DolbyPlayerConfig &inConfigData)
Constructs me using the given configuration settings.
static void Sleep(const int32_t inMilliseconds)
Suspends execution of the current thread for a given number of milliseconds.
Definition: systemtime.cpp:284
This selects audio channels 1 and 2 (Group 1 channels 1 and 2)
Definition: ntv2enums.h:3138
NTV2PixelFormat fPixelFormat
The pixel format to use.
2: OEM (recommended): device configured by client application(s) with some driver involvement...
Configures an NTV2DolbyPlayer instance.
static const uint32_t AUDIOBYTES_MAX_48K(201 *1024)
The maximum number of bytes of 48KHz audio that can be transferred for a single frame. Worst case, assuming 16 channels of audio (max), 4 bytes per sample, and 67 msec per frame (assuming the lowest possible frame rate of 14.98 fps)... 48,000 samples per second requires 3,204 samples x 4 bytes/sample x 16 = 205,056 bytes 201K will suffice, with 768 bytes to spare.
#define PLNOTE(_xpr_)
NTV2VideoFormat fVideoFormat
The video format to use.
std::string NTV2VideoFormatToString(const NTV2VideoFormat inValue, const bool inUseFrameRate=false)
Definition: ntv2utils.cpp:6750
Embeds silence (zeroes) into the data stream.
Definition: ntv2enums.h:2035
virtual bool SetVANCShiftMode(NTV2Channel inChannel, NTV2VANCDataShiftMode inMode)
Enables or disables the "VANC Shift Mode" feature for the given channel.
bool IsOpen()
Definition: file_io.cpp:317
virtual void Quit(void)
Gracefully stops me from running.
virtual uint32_t AddTone(NTV2FrameData &inFrameData)
Inserts audio tone (based on my current tone frequency) into the given NTV2FrameData&#39;s audio buffer...
AJA_EXPORT bool RenderTimeCodeFont(AJA_PixelFormat pixelFormat, uint32_t numPixels, uint32_t numLines)
virtual bool DMABufferUnlockAll()
Unlocks all previously-locked buffers used for DMA transfers.
Definition: ntv2dma.cpp:457
Specifies the PTP source on SFP 1.
Definition: ntv2enums.h:1473
Specifies channel or FrameStore 2 (or the 2nd item).
Definition: ntv2enums.h:1364
virtual void StartProducerThread(void)
Starts my producer thread.
AJAStatus Seek(const int64_t distance, const AJAFileSetFlag flag) const
Definition: file_io.cpp:545
virtual AJAStatus SetUpTestPatternBuffers(void)
Creates my test pattern buffers.
Declares the CNTV2DeviceScanner class.
std::ostream & operator<<(std::ostream &ioStrm, const DolbyPlayerConfig &inObj)
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...
bool AddAudioTone(ULWord &outNumBytesWritten, NTV2Buffer &inAudioBuffer, ULWord &inOutCurrentSample, const ULWord inNumSamples, const double inSampleRate, const double inAmplitude, const double inFrequency, const ULWord inNumBits, const bool inByteSwap, const ULWord inNumChannels)
Fills the given buffer with 32-bit (ULWord) audio tone samples.
Definition: ntv2utils.cpp:4413
Declares the AJAProcess class.
std::string fDolbyFilePath
Optional path to Dolby audio source file.
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 UnsubscribeOutputVerticalEvent(const NTV2Channel inChannel)
Unregisters me so I&#39;m no longer notified when an output VBI is signaled on the given output channel...
Definition: ntv2card.h:2819
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)
uint16_t GetEndFrame(void) const
NTV2Buffer & AudioBuffer(void)
bool IsRGBFormat(const NTV2FrameBufferFormat format)
Definition: ntv2utils.cpp:5414
This object specifies the information that will be transferred to or from the AJA device in the CNTV2...
virtual bool SetAudioBufferSize(const NTV2AudioBufferSize inValue, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Changes the size of the audio buffer that is used for a given Audio System in the AJA device...
Definition: ntv2audio.cpp:250
virtual bool GetNumberAudioChannels(ULWord &outNumChannels, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Returns the current number of audio channels being captured or played by a given Audio System on the ...
Definition: ntv2audio.cpp:181
bool fDoRamp
If true, use audio ramp pattern instead of tone.
Header file for NTV2DolbyPlayer demonstration class.
AJAStatus Close()
Definition: file_io.cpp:281
static AJALabelValuePairs & append(AJALabelValuePairs &inOutTable, const std::string &inLabel, const std::string &inValue=std::string())
A convenience function that appends the given label and value strings to the provided AJALabelValuePa...
Definition: info.h:170
#define DEC(__x__)
void EndProduceNextBuffer(void)
The producer thread calls this function to signal that it has finished populating the frame it obtain...
This identifies the first Audio System.
Definition: ntv2enums.h:3903
virtual bool WaitForOutputVerticalInterrupt(const NTV2Channel inChannel=NTV2_CHANNEL1, UWord inRepeatCount=1)
Efficiently sleeps the calling thread/process until the next one or more field (interlaced video) or ...
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
FrameDataPtr StartProduceNextBuffer(void)
The thread that&#39;s responsible for providing frames – the producer – calls this function to populate...
double GetAudioSamplesPerSecond(const NTV2AudioRate inAudioRate)
Returns the audio sample rate as a number of audio samples per second.
Definition: ntv2utils.cpp:3303
virtual bool ParseBSI(uint16_t *pInDolbyBuffer, uint32_t numSamples, NTV2DolbyBSI *pBsi)
Parse the dolby audio bit stream information block.
virtual void StartConsumerThread(void)
Starts my consumer thread.
mFormatDesc
Definition: ntv2vcam.cpp:942
ULWord GetFrameCount(void) const
This is returned from the CNTV2Card::AutoCirculateGetStatus function.
NTV2OutputXptID GetFrameStoreOutputXptFromChannel(const NTV2Channel inFrameStore, const bool inIsRGB=false, const bool inIs425=false)
virtual bool SetHDMIOutAudioFormat(const NTV2AudioFormat inNewValue, const NTV2Channel inWhichHDMIOut=NTV2_CHANNEL1)
Sets the HDMI output&#39;s audio format.
Definition: ntv2audio.cpp:1032
uint16_t UWord
Definition: ajatypes.h:234
ULWord GetAudioSamplesPerFrame(const NTV2FrameRate inFrameRate, const NTV2AudioRate inAudioRate, ULWord inCadenceFrame=0, bool inIsSMPTE372Enabled=false)
Returns the number of audio samples for a given video frame rate, audio sample rate, and frame number. This is useful since AJA devices use fixed audio sample rates (typically 48KHz), and some video frame rates will necessarily result in some frames having more audio samples than others.
Definition: ntv2utils.cpp:2889
Specifies channel or FrameStore 1 (or the first item).
Definition: ntv2enums.h:1363
virtual bool AutoCirculateStart(const NTV2Channel inChannel, const ULWord64 inStartTime=0)
Starts AutoCirculate streaming for the specified channel that was previously initialized by CNTV2Card...
virtual uint32_t AddRamp(NTV2FrameData &inFrameData)
Inserts audio test ramp into the given NTV2FrameData&#39;s audio buffer.
virtual bool RouteOutputSignal(void)
Performs all widget/signal routing for playout.
bool CanDoFrameBufferFormat(const NTV2PixelFormat inPF)
virtual bool AutoCirculateInitForOutput(const NTV2Channel inChannel, const UWord inFrameCount=7, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_INVALID, const ULWord inOptionFlags=0, const UByte inNumChannels=1, const UWord inStartFrameNumber=0, const UWord inEndFrameNumber=0)
Prepares for subsequent AutoCirculate playback streaming, designating a contiguous block of frame buf...
#define xHEX0N(__x__, __n__)
TimecodeFormat
Definition: ntv2rp188.h:22
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 Init(void)
Initializes me and prepares me to Run.
virtual bool GetFrameRate(NTV2FrameRate &outValue, NTV2Channel inChannel=NTV2_CHANNEL1)
Returns the AJA device&#39;s currently configured frame rate via its "value" parameter.
static AJA_FrameRate GetAJAFrameRate(const NTV2FrameRate inFrameRate)
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.
NTV2AudioSystem NTV2ChannelToAudioSystem(const NTV2Channel inChannel)
Converts the given NTV2Channel value into its equivalent NTV2AudioSystem.
Definition: ntv2utils.cpp:4873
virtual void GetACStatus(AUTOCIRCULATE_STATUS &outStatus)
Provides status information about my output (playout) process.
NTV2ACFrameRange fFrames
AutoCirculate frame count or range.
uint32_t Read(uint8_t *pBuffer, const uint32_t length)
Definition: file_io.cpp:328
bool GetRP188Reg(RP188_STRUCT &outRP188) const
Definition: ntv2rp188.cpp:1241
NTV2AudioRate
Definition: ntv2enums.h:1933
virtual bool GetBits(uint32_t &data, uint32_t inBitCount)
Retreive the specified number of bits from the bitstream buffer.
static size_t SetDefaultPageSize(void)
#define PLWARN(_xpr_)
std::vector< std::string > NTV2StringList
bool CanDoVideoFormat(const NTV2VideoFormat inVF)
UWord lastFrame(void) const
Definition: ntv2utils.h:999
#define AUTOCIRCULATE_WITH_RP188
Use this to AutoCirculate with RP188.
const char * NTV2FrameBufferFormatString(NTV2FrameBufferFormat fmt)
Definition: ntv2debug.cpp:220
bool GetRP188Str(std::string &sRP188) const
Definition: ntv2rp188.cpp:918
static const uint32_t AUDIOBYTES_MAX_192K(824 *1024)
The maximum number of bytes of 192KHz audio that can be transferred for a single frame. Worst case, assuming 8 channels of audio (max), 4 bytes per sample, and 67 msec per frame (assuming the lowest possible frame rate of 14.98 fps)... 96,000 samples per second requires 12,864 samples x 4 bytes/sample x 16 = 823,296 bytes 824K will suffice.
std::string & lower(std::string &str)
Definition: common.cpp:436
bool WithVideo(void) const
bool SetAudioBuffer(ULWord *pInAudioBuffer, const ULWord inAudioByteCount)
Sets my audio buffer for use in a subsequent call to CNTV2Card::AutoCirculateTransfer.
static const double gFrequencies[]
virtual bool SetVANCMode(const NTV2VANCMode inVancMode, const NTV2Channel inChannel=NTV2_CHANNEL1)
Sets the VANC mode for the given FrameStore.
virtual bool SetNumberAudioChannels(const ULWord inNumChannels, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1)
Sets the number of audio channels to be concurrently captured or played for a given Audio System on t...
Definition: ntv2audio.cpp:147
virtual void ToString(std::string &outAllLabelsAndValues) const
Answers with a multi-line string that contains the complete host system info table.
enum NTV2OutputCrosspointID NTV2OutputXptID
uint16_t GetStartFrame(void) const
This identifies the mode in which there are no VANC lines in the frame buffer.
Definition: ntv2enums.h:3805
virtual ~NTV2DolbyPlayer(void)
bool SetVideoBuffer(ULWord *pInVideoBuffer, const ULWord inVideoByteCount)
Sets my video buffer for use in a subsequent call to CNTV2Card::AutoCirculateTransfer.
#define NULL
Definition: ntv2vpid.cpp:18
virtual void SetBitBuffer(uint8_t *pBuffer, uint32_t size)
Set the bitstream buffer for bit retrieval.
virtual bool EnableChannel(const NTV2Channel inChannel)
Enables the given FrameStore.