AJA NTV2 SDK  18.1.0.2262
NTV2 SDK 18.1.0.2262
ntv2ccplayer.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
8 #include "ntv2ccplayer.h"
9 #include "ntv2devicefeatures.h"
10 #include "ntv2devicescanner.h"
11 #include "ntv2debug.h"
12 #include "ntv2democommon.h"
13 #include "ntv2rp188.h"
14 #include "ntv2transcode.h"
15 #include "ntv2utils.h"
16 #include "ajabase/common/types.h"
19 #include "ajabase/system/process.h"
20 #include "ntv2testpatterngen.h"
24 #include "ajabase/common/common.h"
28 #include "ntv2captionrenderer.h"
29 #include <sstream>
30 #include <fstream>
31 #include <iostream>
32 #include <iomanip>
33 #include <deque>
34 
35 
36 using namespace std;
37 
38 #define AsSCCSource(__x__) reinterpret_cast<SCCSource&>(__x__)
39 #define AsUBytePtr(__x__) reinterpret_cast<UByte*>(__x__)
40 //#define MEASURE_ACCURACY 1 // Enables a feedback mechanism to precisely generate captions at the desired rate
41 //#define NTV2_ANC_TEST 1
42 
43 static const uint32_t kAppSignature (NTV2_FOURCC('C','C','P','L'));
44 
45 
49 static const string gBuiltInCaptions ("IN CONGRESS, July 4, 1776.\n"
50  "The unanimous Declaration of the thirteen united States of America.\n"
51  "When in the Course of human events, it becomes necessary for one people to dissolve the political bands which have connected them with another, "
52  "and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent "
53  "respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.\n"
54  "We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, "
55  "that among these are Life, Liberty and the pursuit of Happiness. That to secure these rights, Governments are instituted among Men, deriving their "
56  "just powers from the consent of the governed, That whenever any Form of Government becomes destructive of these ends, it is the Right of the People to alter or to abolish it, "
57  "and to institute new Government, laying its foundation on such principles and organizing its powers in such form, as to them shall seem most likely to effect their Safety and "
58  "Happiness. Prudence, indeed, will dictate that Governments long established should not be changed for light and transient causes; and accordingly all experience hath shewn, "
59  "that mankind are more disposed to suffer, while evils are sufferable, than to right themselves by abolishing the forms to which they are accustomed. "
60  "But when a long train of abuses and usurpations, pursuing invariably the same Object evinces a design to reduce them under absolute Despotism, it is their right, "
61  "it is their duty, to throw off such Government, and to provide new Guards for their future security. Such has been the patient sufferance of these Colonies; and such is now "
62  "the necessity which constrains them to alter their former Systems of Government. The history of the present King of Great Britain is a history of repeated injuries and "
63  "usurpations, all having in direct object the establishment of an absolute Tyranny over these States. To prove this, let Facts be submitted to a candid world.\n"
64  "He has refused his Assent to Laws, the most wholesome and necessary for the public good.\n"
65  "He has forbidden his Governors to pass Laws of immediate and pressing importance, unless suspended in their operation till his Assent should be obtained; "
66  "and when so suspended, he has utterly neglected to attend to them.\n"
67  "He has refused to pass other Laws for the accommodation of large districts of people, unless those people would relinquish the right of Representation in the Legislature, "
68  "a right inestimable to them and formidable to tyrants only.\n"
69  "He has called together legislative bodies at places unusual, uncomfortable, and distant from the depository of their public Records, for the sole purpose of fatiguing them "
70  "into compliance with his measures. \n"
71  "He has dissolved Representative Houses repeatedly, for opposing with manly firmness his invasions on the rights of the people.\n"
72  "He has refused for a long time, after such dissolutions, to cause others to be elected; whereby the Legislative powers, incapable of Annihilation, have returned to the People "
73  "at large for their exercise; the State remaining in the mean time exposed to all the dangers of invasion from without, and convulsions within.\n"
74  "He has endeavoured to prevent the population of these States; for that purpose obstructing the Laws for Naturalization of Foreigners; refusing to pass others to encourage "
75  "their migrations hither, and raising the conditions of new Appropriations of Lands.\n"
76  "He has obstructed the Administration of Justice, by refusing his Assent to Laws for establishing Judiciary powers.\n"
77  "He has made Judges dependent on his Will alone, for the tenure of their offices, and the amount and payment of their salaries.\n"
78  "He has erected a multitude of New Offices, and sent hither swarms of Officers to harrass our people, and eat out their substance.\n"
79  "He has kept among us, in times of peace, Standing Armies without the Consent of our legislatures.\n"
80  "He has affected to render the Military independent of and superior to the Civil power.\n"
81  "He has combined with others to subject us to a jurisdiction foreign to our constitution, and unacknowledged by our laws; "
82  "giving his Assent to their Acts of pretended Legislation:\n"
83  "For Quartering large bodies of armed troops among us:\n"
84  "For protecting them, by a mock Trial, from punishment for any Murders which they should commit on the Inhabitants of these States:\n"
85  "For cutting off our Trade with all parts of the world:\n"
86  "For imposing Taxes on us without our Consent:\n"
87  "For depriving us in many cases, of the benefits of Trial by Jury:\n"
88  "For transporting us beyond Seas to be tried for pretended offences.\n"
89  "For abolishing the free System of English Laws in a neighbouring Province, establishing therein an Arbitrary government, and enlarging its Boundaries so as to render it at "
90  "once an example and fit instrument for introducing the same absolute rule into these Colonies:\n"
91  "For taking away our Charters, abolishing our most valuable Laws, and altering fundamentally the Forms of our Governments:\n"
92  "For suspending our own Legislatures, and declaring themselves invested with power to legislate for us in all cases whatsoever.\n"
93  "He has abdicated Government here, by declaring us out of his Protection and waging War against us.\n"
94  "He has plundered our seas, ravaged our Coasts, burnt our towns, and destroyed the lives of our people.\n"
95  "He is at this time transporting large Armies of foreign Mercenaries to compleat the works of death, desolation and tyranny, already begun with circumstances of Cruelty & "
96  "perfidy scarcely paralleled in the most barbarous ages, and totally unworthy the Head of a civilized nation.\n"
97  "He has constrained our fellow Citizens taken Captive on the high Seas to bear Arms against their Country, to become the executioners of their friends and Brethren, "
98  "or to fall themselves by their Hands.\n"
99  "He has excited domestic insurrections amongst us, and has endeavoured to bring on the inhabitants of our frontiers, the merciless Indian Savages, whose known rule of warfare, "
100  "is an undistinguished destruction of all ages, sexes and conditions.\n"
101  "In every stage of these Oppressions We have Petitioned for Redress in the most humble terms: Our repeated Petitions have been answered only by repeated injury. "
102  "A Prince whose character is thus marked by every act which may define a Tyrant, is unfit to be the ruler of a free people.\n"
103  "Nor have We been wanting in attentions to our Brittish brethren. We have warned them from time to time of attempts by their legislature to extend an unwarrantable "
104  "jurisdiction over us. We have reminded them of the circumstances of our emigration and settlement here. We have appealed to their native justice and magnanimity, "
105  "and we have conjured them by the ties of our common kindred to disavow these usurpations, which, would inevitably interrupt our connections and correspondence. "
106  "They too have been deaf to the voice of justice and of consanguinity. We must, therefore, acquiesce in the necessity, which denounces our Separation, and hold them, "
107  "as we hold the rest of mankind, Enemies in War, in Peace Friends.\n"
108  "We, therefore, the Representatives of the united States of America, in General Congress, Assembled, appealing to the Supreme Judge of the world for the rectitude of "
109  "our intentions, do, in the Name, and by Authority of the good People of these Colonies, solemnly publish and declare, That these United Colonies are, and of Right ought "
110  "to be Free and Independent States; that they are Absolved from all Allegiance to the British Crown, and that all political connection between them and the State of Great "
111  "Britain, is and ought to be totally dissolved; and that as Free and Independent States, they have full Power to levy War, conclude Peace, contract Alliances, establish "
112  "Commerce, and to do all other Acts and Things which Independent States may of right do. And for the support of this Declaration, with a firm reliance on the protection of "
113  "divine Providence, we mutually pledge to each other our Lives, our Fortunes and our sacred Honor.");
114 
118 static istringstream gBuiltInStream (gBuiltInCaptions);
119 
120 #if defined (MEASURE_ACCURACY)
121 
126  class Speedometer
127  {
128  public:
134  Speedometer (const size_t inNumSamples = 20)
135  : mMaxNumSamples (inNumSamples),
136  mSampleCallTally (0)
137  {
138  mTimespanSamples.push_back (10); // Initial seed of 10 millisec
139  mWhenLastSampleCall = AJATime::GetSystemMilliseconds ();
140  }
141 
146  virtual void Sample (void)
147  {
148  if (mTimespanSamples.size () >= mMaxNumSamples)
149  mTimespanSamples.pop_front ();
150  const uint64_t now (AJATime::GetSystemMilliseconds ());
151  mTimespanSamples.push_back (now - mWhenLastSampleCall);
152  mWhenLastSampleCall = now;
153  mSampleCallTally++;
154  }
155 
159  virtual double GetAvgMilliSecsBetweenSamples (void) const
160  {
161  uint64_t sum (0.0);
162  for (SampleQueueConstIter iter (mTimespanSamples.begin ()); iter != mTimespanSamples.end (); ++iter)
163  sum += *iter;
164  return double (sum) / double (mTimespanSamples.size ());
165  }
166 
170  virtual double GetAvgSamplesPerSecond (void) const
171  {
172  uint64_t sum (0.0);
173  for (SampleQueueConstIter iter (mTimespanSamples.begin ()); iter != mTimespanSamples.end (); ++iter)
174  sum += *iter;
175  return double (mTimespanSamples.size ()) * 1000.0 / double (sum);
176  }
177 
178  virtual inline double GetAvgSamplesPerMinute (void) const {return GetAvgSamplesPerSecond () * 60.0;}
179  virtual inline size_t GetSampleCount (void) const {return mTimespanSamples.size ();}
180  virtual inline uint64_t GetSampleCountTally (void) const {return mSampleCallTally;}
181 
182  private:
183  typedef std::deque <uint64_t> SampleQueue;
184  typedef SampleQueue::const_iterator SampleQueueConstIter;
185 
186  SampleQueue mTimespanSamples;
187  const size_t mMaxNumSamples;
188  uint64_t mWhenLastSampleCall;
189  uint64_t mSampleCallTally;
190 
191  }; // Speedometer
192 
193 
200  static ostream & operator << (ostream & inOutStr, const Speedometer & inObj)
201  {
202  const double samplesPerSecond (inObj.GetAvgSamplesPerSecond ());
203  const double samplesPerMinute (samplesPerSecond * 60.0);
204  return inOutStr << samplesPerMinute << " per min";
205  }
206 
207  static uint64_t gWhenLastDisplay (0);
208 
209 #endif // MEASURE_ACCURACY
210 
212 {
213  static const string EndActions[] = {"Quit", "Repeat", "Idle", ""};
214  AJALabelValuePairs result;
215  string filesToPlay(aja::join(fFilesToPlay, "\n"));
216  if (filesToPlay.empty()) filesToPlay = "<default>";
217  AJASystemInfo::append(result, "Files to Play", filesToPlay);
218  AJASystemInfo::append(result, "End Action", EndActions[fEndAction]);
219  AJASystemInfo::append(result, "Caption Mode", ::NTV2Line21ModeToStr(fCaptionMode));
220  AJASystemInfo::append(result, "Caption Channel", ::NTV2Line21ChannelToStr(fCaptionChannel));
221  AJASystemInfo::append(result, "Newlines Make New Rows", fNewLinesAreNewRows ? "Y" : "N");
222  AJASystemInfo::append(result, "Chars Per Minute", aja::to_string(fCharsPerMinute));
223  AJASystemInfo::append(result, "Attributes", ::NTV2Line21AttributesToStr(fAttributes));
224  return result;
225 }
226 
227 AJALabelValuePairs CCPlayerConfig::Get (const bool inCompact) const
228 {
229  AJALabelValuePairs result (PlayerConfig::Get (inCompact));
230  AJASystemInfo::append(result, "Background Pattern", fTestPatternName);
231  AJASystemInfo::append(result, "Emit Statistics", fEmitStats ? "Y" : "N");
232  AJASystemInfo::append(result, "Force RTP", fForceRTP ? (fForceRTP&2 ? "MultiPkt" : "UniPkt") : "Normal");
233  AJASystemInfo::append(result, "Suppress Audio", fSuppressAudio ? "Y" : "N");
234  AJASystemInfo::append(result, "Suppress Line21", fSuppressLine21 ? "Y" : "N");
235  AJASystemInfo::append(result, "Suppress 608 Pkt", fSuppress608 ? "Y" : "N");
236  AJASystemInfo::append(result, "Suppress 708 Pkt", fSuppress708 ? "Y" : "N");
237  AJASystemInfo::append(result, "Suppress Timecode", fSuppressTimecode ? "Y" : "N");
238  for (CaptionChanGenMapCIter it(fCapChanGenConfigs.begin()); it != fCapChanGenConfigs.end(); ++it)
239  {
240  AJASystemInfo::append(result, ::NTV2Line21ChannelToStr(it->first, false));
241  AJALabelValuePairs pairs(it->second.Get());
242  for (AJALabelValuePairsConstIter iter(pairs.begin()); iter != pairs.end(); ++iter)
243  result.push_back(*iter);
244  }
245  return result;
246 }
247 
248 std::ostream & operator << (std::ostream & ioStrm, const CCPlayerConfig & inObj)
249 {
250  return ioStrm << AJASystemInfo::ToString(inObj.Get());
251 }
252 
253 
255 // Caption Source
257 
268 
269 
273 typedef deque <CaptionSourcePtr> CaptionSourceList;
274 typedef CaptionSourceList::const_iterator CaptionSourceListConstIter;
275 
276 
278 {
279  // Instance Methods
280  public:
289  explicit CaptionSource (const double inCharsPerMinute, istream * pInInputStream, const string & inFilePath, const bool inDeleteInputStream = false)
290  : mpInputStream (pInInputStream),
291  mInputFilePath (inFilePath),
292  mCharsPerMinute (inCharsPerMinute),
293  mMaxRowCharWidth (32),
294  mFinished (false),
295  mDeleteInputStream (inDeleteInputStream),
296  mIsTextMode (false),
297  mMilliSecsPerChar (0.0),
298  mCaptionChannel (NTV2_CC608_ChannelInvalid)
299  {
300  NTV2_ASSERT(mpInputStream); // Must be non-NULL pointer
301  NTV2_ASSERT(mCharsPerMinute > 0.0); // Must be greater than zero
302  *mpInputStream >> std::noskipws; // Include whitespace when reading from this stream
303  mMilliSecsPerChar = 60000.0 / mCharsPerMinute; // Milliseconds of delay (sleep time) between emitting successive characters
304  }
305 
306 
311  virtual ~CaptionSource ()
312  {
313  if (mDeleteInputStream && mpInputStream)
314  {
315  delete mpInputStream;
316  mpInputStream = AJA_NULL;
317  }
318  #if defined (MEASURE_ACCURACY)
319  PLDBG(::NTV2Line21ChannelToStr(mCaptionChannel) << ": " << mCharSpeed.GetSampleCountTally() << " final chars: " << mCharSpeed);
320  #endif // MEASURE_ACCURACY
321  }
322 
328  virtual string GetNextCaptionCharacter (void)
329  {
330  static double milliSecsPerChar(mMilliSecsPerChar);
331  string resultChar;
332  unsigned char rawBytes[5] = {0, 0, 0, 0, 0};
333 
334  AJATime::Sleep (int32_t(milliSecsPerChar));
335  if (mpInputStream->tellg() == 0 && !mInputFilePath.empty())
336  PLNOTE("Starting caption file '" << mInputFilePath << "'");
337 
338  *mpInputStream >> rawBytes[0];
339  if (mpInputStream->eof())
340  SetFinished();
341 
342  if (rawBytes[0] < 0x80) // 1-byte code
343  {
344  if (rawBytes[0])
345  resultChar = string (1, char(rawBytes[0]));
346  }
347  else if (rawBytes[0] < 0xC0) // invalid
348  PLWARN(::NTV2Line21ChannelToStr(mCaptionChannel) << ": Invalid UTF8 value read from input stream: " << xHEX0N(uint16_t(rawBytes[0]),2));
349  else if (rawBytes[0] < 0xE0) // 2-byte code
350  {
351  if (IsFinished())
352  PLWARN(::NTV2Line21ChannelToStr(mCaptionChannel) << ": EOF on input stream before reading byte 2 of 2-byte UTF8 character");
353  else
354  {
355  resultChar = char(rawBytes[0]);
356  *mpInputStream >> rawBytes[1];
357  if (mpInputStream->eof())
358  SetFinished ();
359  resultChar += char(rawBytes[1]);
360  NTV2_ASSERT(resultChar.length() == 2);
361  }
362  }
363  else if (rawBytes[0] < 0xF0) // 3-byte code
364  {
365  resultChar = char(rawBytes[0]);
366  for (unsigned ndx(1); ndx <= 2; ndx++)
367  {
368  if (IsFinished())
369  {
370  PLWARN(::NTV2Line21ChannelToStr(mCaptionChannel) << ": EOF on input stream before reading byte " << DEC(ndx + 1) << " of 3-byte UTF8 character");
371  resultChar = "";
372  break;
373  }
374  *mpInputStream >> rawBytes[ndx];
375  if (mpInputStream->eof())
376  SetFinished();
377  resultChar += char(rawBytes[ndx]);
378  }
379  if (!IsFinished()) NTV2_ASSERT(resultChar.length() == 3);
380  }
381  else if (rawBytes[0] < 0xF8) // 4-byte code
382  {
383  resultChar = char(rawBytes[0]);
384  for (unsigned ndx(1); ndx <= 3; ndx++)
385  {
386  if (IsFinished())
387  {
388  PLWARN(::NTV2Line21ChannelToStr(mCaptionChannel) << "; EOF on input stream before reading byte " << DEC(ndx + 1) << " of 4-byte UTF8 character");
389  resultChar = "";
390  break;
391  }
392  *mpInputStream >> rawBytes[ndx];
393  if (mpInputStream->eof())
394  SetFinished();
395  resultChar += char(rawBytes[ndx]);
396  }
397  if (!IsFinished()) NTV2_ASSERT(resultChar.length() == 4);
398  }
399  else
400  PLWARN(::NTV2Line21ChannelToStr(mCaptionChannel) << ": UTF8 byte value not handled: " << xHEX0N(uint16_t(rawBytes[0]),2));
401 
402  #if defined (MEASURE_ACCURACY)
403  if (!resultChar.empty ())
404  mCharSpeed.Sample ();
405 
406  if (AJATime::GetSystemMilliseconds () - gWhenLastDisplay > 1000)
407  {
408  // Once per second, see how far off I am from the target character rate, and adjust the sleep time as needed...
409  const double avg (mCharSpeed.GetAvgMilliSecsBetweenSamples ());
410  const double diff (avg - mMilliSecsPerChar);
411  milliSecsPerChar = milliSecsPerChar - diff;
412  if (milliSecsPerChar < 0.0)
413  milliSecsPerChar = mMilliSecsPerChar;
414  PLDBG(mCharSpeed.GetSampleCountTally() << " " << ::NTV2Line21ChannelToStr(mCaptionChannel)
415  << " chars: " << mCharSpeed << " " << milliSecsPerChar << "ms/Char " << avg << "avg - "
416  << mMilliSecsPerChar << " => " << diff << "diff");
417  gWhenLastDisplay = AJATime::GetSystemMilliseconds ();
418  }
419  #endif // MEASURE_ACCURACY
420 
421  return resultChar;
422 
423  } // GetNextCaptionCharacter
424 
425 
433  virtual string GetNextCaptionWord (bool & outLineBreak)
434  {
435  std::locale loc;
436  string resultWord;
437  string nextChar (GetNextCaptionCharacter ());
438 
439  outLineBreak = false;
440  while (!nextChar.empty ())
441  {
442  if (IsSpaceChar (nextChar) || IsControlChar (nextChar))
443  {
444  outLineBreak = (nextChar.at (0) == '\n' || nextChar.at (0) == '\r');
445  break; // Control chars & whitespace break words (HT, LF, CR, etc.) -- but don't include them in the word
446  }
447 
448  resultWord += nextChar;
449  if (IsWordBreakCharacter (nextChar))
450  break; // Some punctuation breaks word -- include in the word, too
451 
452  nextChar = GetNextCaptionCharacter ();
453  } // loop til break
454 
455  return resultWord;
456 
457  } // GetNextCaptionWord
458 
459 
465  virtual string GetNextCaptionRow (const bool inBreakLinesOnNewLineChars = false)
466  {
467  string resultRow;
468 
469  // Build resultRow one word at a time (except Text Mode)...
470  while (true)
471  {
472  if (mIsTextMode)
473  {
474  // Special case for Text Mode...
475  string nextChar (GetNextCaptionCharacter ());
476  while (!nextChar.empty ())
477  {
478  if (nextChar.at (0) == '\n' || nextChar.at (0) == '\r')
479  return resultRow; // LF and CR will break the row -- but don't include LF/CR in the row text
480 
481  resultRow += nextChar;
482  nextChar = GetNextCaptionCharacter ();
483  } // loop til break
484  return resultRow;
485  } // if Text Mode
486 
487 
488  // Any text left over from the last time?
489  if (!mLeftoverRowText.empty ())
490  {
491  // Use whatever text was left over from the last time...
492  if (mLeftoverRowText.length () > mMaxRowCharWidth)
493  {
494  // Not all of it will fit. Use whatever will fit and save the rest for later...
495  resultRow = mLeftoverRowText.substr (0, mMaxRowCharWidth);
496  mLeftoverRowText.erase (0, mMaxRowCharWidth);
497  break; // Done
498  }
499  else
500  {
501  resultRow = mLeftoverRowText;
502  mLeftoverRowText.clear ();
503  }
504  } // if any leftover text
505 
506  if (resultRow.length () == mMaxRowCharWidth) // Completely full?
507  break; // If so, send it!
508 
509  // ResultRow has room for more.
510  // Get the next word from the caption source...
511  bool lineBreak (false);
512  string nextWord (GetNextCaptionWord (lineBreak));
513  if (nextWord.empty () && IsFinished ())
514  break;
515 
516  if (nextWord.empty () && !lineBreak)
517  continue; // Nothing to add at this time
518 
519  // If there's anything to send, and the word is maxRowWidth or longer, send resultRow now, and save the rest...
520  if (!resultRow.empty () && nextWord.length () >= mMaxRowCharWidth)
521  {
522  mLeftoverRowText = nextWord; // Save the word for next time
523  break; // Send resultRow now
524  }
525 
526  // If the word is longer than maxRowWidth...
527  if (nextWord.length () >= mMaxRowCharWidth)
528  {
529  resultRow = nextWord.substr (0, mMaxRowCharWidth); // Send whatever will fit
530  nextWord.erase (0, mMaxRowCharWidth);
531  mLeftoverRowText = nextWord; // Save the rest for next time
532  break; // Send resultRow now
533  }
534 
535  // Add the word only if it will fit...
536  const size_t newLength ((resultRow.length () ? resultRow.length () + 1 : 0) + nextWord.length ());
537  if (newLength > mMaxRowCharWidth)
538  {
539  // Wrap this word onto next line...
540  mLeftoverRowText = nextWord; // Save the word for next time
541  break; // Send resultRow now
542  }
543 
544  if (resultRow.empty ())
545  resultRow = nextWord;
546  else
547  resultRow += " " + nextWord;
548  if (inBreakLinesOnNewLineChars && lineBreak)
549  break;
550  } // loop til I have a row to return
551 
552  return resultRow;
553 
554  } // GetNextCaptionRow
555 
556 
557  virtual inline bool IsPlainTextSource (void) const {return true;}
558  virtual inline bool IsFinished (void) const {return mFinished;}
559  virtual inline void SetFinished (void) {mFinished = true;}
560  virtual inline void SetCaptionChannel (const NTV2Line21Channel inCCChannel) {mCaptionChannel = inCCChannel;}
561  virtual inline NTV2Line21Channel GetCaptionChannel (void) const {return mCaptionChannel;}
562  virtual inline bool IsF1Channel(void) const {return IsField1Line21CaptionChannel(mCaptionChannel);}
563 
564 
570  virtual inline void SetTextMode (const bool inIsTextMode) {mIsTextMode = inIsTextMode;}
571 
572  // Private Instance Methods
573  private:
574  inline CaptionSource (const CaptionSource & inCaptionSource) : mDeleteInputStream (false) {(void) inCaptionSource;} // Hidden
575  virtual inline CaptionSource & operator = (const CaptionSource & inCaptionSource) {(void) inCaptionSource; return *this;} // Hidden
576 
577 
578  // Instance Data
579  private:
580  istream * mpInputStream;
581  string mInputFilePath;
582  double mCharsPerMinute;
583  string mLeftoverRowText;
584  size_t mMaxRowCharWidth;
585  bool mFinished;
586  const bool mDeleteInputStream;
587  bool mIsTextMode;
588  double mMilliSecsPerChar;
589  NTV2Line21Channel mCaptionChannel;
590  #if defined (MEASURE_ACCURACY)
591  Speedometer mCharSpeed;
592  #endif // MEASURE_ACCURACY
593 
594 
595  // Private Class Methods
596  private:
597  static bool IsWordBreakCharacter (const string & inUTF8Char)
598  {
599  static const string wordBreakCharacters ("!#$%&()*+,./:;<=>?@[\\]^_`{|}~. \t");
600  if (inUTF8Char.length () != 1)
601  return false;
602  return wordBreakCharacters.find (inUTF8Char) != string::npos;
603  }
604 
605  static bool IsSpaceChar (const string & inUTF8Char)
606  {
607  // tab, newline, vertical tab, form feed, carriage return, and space
608  if (inUTF8Char.length () != 1)
609  return false;
610  const unsigned char c = UByte(inUTF8Char[0]);
611  if (c == 0x09 || c == 0x0A || c == 0x0B || c == 0x0C || c == 0x0D || c == 0x20)
612  return true;
613  return false;
614  }
615 
616  static bool IsControlChar (const string & inUTF8Char)
617  {
618  // ASCII characters octal codes 000 through 037, and 177 (DEL)
619  if (inUTF8Char.length () != 1)
620  return false;
621  unsigned char c = UByte(inUTF8Char[0]);
622  if ((c > 0x00 && c < ' ') || c == 0x7F)
623  return true;
624  return false;
625  }
626 
627 }; // CaptionSource
628 
629 
630 class SCCSource : public CaptionSource
631 {
632  public: // PUBLIC INSTANCE METHODS
633  explicit SCCSource (const double inCharsPerMinute, istream * pInInputStream, const string & inFilePath, const bool inDeleteInputStream = false);
634  virtual ~SCCSource ()
635  {
636  }
637  virtual bool IsPlainTextSource (void) const {return false;}
638  virtual bool EnqueueCCDataToFrame (CNTV2CaptionEncoder608Ptr inEncoder, const uint32_t inFrameNum);
639  virtual string GetNextCaptionCharacter (void) {return string();}
640  virtual string GetNextCaptionWord (bool & outLineBreak) {(void) outLineBreak; return string();}
641  virtual string GetNextCaptionRow (const bool inBreakLines = false) {(void) inBreakLines; return string();}
642 
643  private: // PRIVATE INSTANCE METHODS
644  virtual inline SCCSource & operator = (const SCCSource & inCaptionSource) {(void) inCaptionSource; return *this;} // Hidden
645 
646  private: // PRIVATE INSTANCE DATA
647  typedef std::vector<uint16_t> UWords;
648  typedef UWords::const_iterator UWordsConstIter;
649  typedef std::map<uint32_t,UWords> CCDataMap; // Mapping: starting frame# to list of CCData words
650  typedef CCDataMap::const_iterator CCDataMapConstIter;
651 
652  CCDataMap mCCDataMap;
653  CCDataMapConstIter mCCDataMapIter;
654  size_t mLastCCDataWordNdx;
655  uint32_t mMaxFrameNum;
656 }; // SCCSource
657 
658 
659 
660 SCCSource::SCCSource (const double inCharsPerMinute, istream * pInInputStream, const string & inFilePath, const bool inDeleteInputStream)
661  : CaptionSource(inCharsPerMinute, pInInputStream, inFilePath, inDeleteInputStream),
662  mLastCCDataWordNdx (0),
663  mMaxFrameNum (0)
664 {
665  NTV2StringList lines;
666  while (!pInInputStream->fail())
667  {
668  string line;
669  std::getline(*pInInputStream, line);
670  aja::strip(line);
671  if (!line.empty())
672  lines.push_back(line);
673  }
674  NTV2StringListConstIter iter(lines.begin());
675  if (iter == lines.end())
676  {PLFAIL("No lines!"); return;}
677  if (iter->find("Scenarist_SCC") == string::npos)
678  {PLFAIL("No 'Scenarist_SCC' heading!"); return;}
679 
680  AJATimeCode tc;
681  const AJATimeBase timeBase (CNTV2DemoCommon::GetAJAFrameRate(NTV2_FRAMERATE_5994)); // For now, since CEA608 focused
682  const bool isDropFrame (true); // For now, since CEA608 focused
683  while (++iter != lines.end())
684  {
685  const string & line(*iter);
686  if (line.empty())
687  continue; // empty line
688  const size_t tabPos(line.find('\t'));
689  if (tabPos == string::npos)
690  continue; // no tab character
691 
692  // Split line at tab
693  const NTV2StringList tabChunks (aja::split(line, '\t'));
694  NTV2_ASSERT(tabChunks.size() > 1);
695 
696  // Parse timecode
697  string timecodeChunk(tabChunks.at(0));
698  aja::strip(timecodeChunk);
699  const NTV2StringList tcPieces(aja::split(timecodeChunk, ':'));
700  if (tcPieces.size() < 4)
701  {PLWARN(tcPieces.size() << " timecode components separated by ':' fewer than 4"); continue;}
702  const uint32_t tcComponents[4] = { uint32_t(aja::stoul(tcPieces[0])), uint32_t(aja::stoul(tcPieces[1])),
703  uint32_t(aja::stoul(tcPieces[2])), uint32_t(aja::stoul(tcPieces[3])) };
704  tc.SetHmsf(tcComponents[0], tcComponents[1], tcComponents[2], tcComponents[3], timeBase, isDropFrame);
705 
706  // Parse UWords
707  UWords ccWords;
708  string ccDataChunk(tabChunks.at(1));
709  aja::strip(ccDataChunk);
710  const NTV2StringList ccDataPieces(aja::split(ccDataChunk, ' '));
711  for (NTV2StringListConstIter it(ccDataPieces.begin()); it != ccDataPieces.end(); ++it)
712  {
713  string ccDataWord(*it);
714  aja::strip(ccDataWord);
715  if (ccDataWord.find("0x") == string::npos && ccDataWord.find("0X") == string::npos)
716  ccDataWord = "0x" + ccDataWord;
717  const uint16_t ccWord(UWord(aja::stoul(ccDataWord, AJA_NULL, 16)));
718  ccWords.push_back(ccWord);
719  }
720 
721  mMaxFrameNum = tc.QueryFrame();
722  CCDataMapConstIter iter(mCCDataMap.find(mMaxFrameNum));
723  if (iter != mCCDataMap.end())
724  PLWARN("Frame " << mMaxFrameNum << " already present, has " << iter->second.size() << " byte pairs");
725  else
726  mCCDataMap[mMaxFrameNum] = ccWords;
727  PLDBG("Frame " << tc.QueryFrame() << " has " << ccWords.size() << " CC byte pairs");
728  mCCDataMapIter = mCCDataMap.begin();
729  mLastCCDataWordNdx = 0;
730  } // for each line
731  if (!mCCDataMap.empty())
732  PLINFO("SCC data frames " << mCCDataMap.begin()->first << " thru " << mMaxFrameNum << ", size=" << mCCDataMap.size());
733 }
734 
735 bool SCCSource::EnqueueCCDataToFrame (CNTV2CaptionEncoder608Ptr inEncoder, const uint32_t inPlayFrame)
736 {
737  bool result(false);
738  uint32_t playFrame(mMaxFrameNum ? inPlayFrame % (mMaxFrameNum + 1) : inPlayFrame);
739  if (!inEncoder)
740  return result;
741  if (mCCDataMapIter != mCCDataMap.end() && mLastCCDataWordNdx < mCCDataMapIter->second.size())
742  {
743  uint32_t CCFrame(mCCDataMapIter->first);
744  if (CCFrame > playFrame) // CCFrame ahead of playout frame?
745  {
746  if (CCFrame == mMaxFrameNum)
747  playFrame = CCFrame; // This prevents "sticking" on last frame -- force last CC bytes out
748  else
749  {
750  const uint32_t delayFrames(CCFrame - playFrame);
751  PLINFO("CCFrame " << DEC(CCFrame) << " > playFrame " << DEC(playFrame) << "|" << DEC(inPlayFrame) << ", delaying " << DEC(delayFrames) << " frames");
752  result = true; // inEncoder->EnqueueDelay(delayFrames, GetCaptionChannel());
753  AJATime::Sleep(delayFrames * 1000 / 30);
754  playFrame += delayFrames;
755  }
756  }
757  if (CCFrame <= playFrame) // If current CCFrame at or behind playFrame...
758  { // ...then enqueue CCFrame's CCBytes
759  PLINFO("CCFrame " << DEC(CCFrame) << " <= playFrame " << DEC(playFrame) << "|" << DEC(inPlayFrame) << ": " << mCCDataMapIter->second);
760  do
761  {
762  const uint16_t ccWord(mCCDataMapIter->second.at(mLastCCDataWordNdx));
763  const UByte cc1(UByte(ccWord >> 8));
764  const UByte cc2(UByte(ccWord & 0x00FF));
765  CaptionData ccData;
766  if (IsF1Channel()) {ccData.f1_char1 = cc1; ccData.f1_char2 = cc2; ccData.bGotField1Data = true;}
767  else {ccData.f2_char1 = cc1; ccData.f2_char2 = cc2; ccData.bGotField2Data = true;}
768 
769  result = inEncoder->EnqueueCaptionData(ccData);
770  if (++mLastCCDataWordNdx >= mCCDataMapIter->second.size())
771  {
772  mLastCCDataWordNdx = 0;
773  ++mCCDataMapIter;
774  if (mCCDataMapIter == mCCDataMap.end())
775  {
776  SetFinished();
777  PLINFO("Finished at playFrame " << DEC(playFrame) << "|" << DEC(inPlayFrame));
778  break; // Exit do/while loop
779  }
780  }
781  } while (mCCDataMapIter->first == CCFrame);
782  } // if CCFrame at or behind playFrame
783  }
784  return result;
785 }
786 
795 static CaptionSourceList GetCaptionSources (const NTV2StringList & inFilesToPlay, const double inCharsPerMinute)
796 {
797  CaptionSourceList result;
798  static istream * pStdIn (&cin);
799  static size_t nFilesToPlay (9999);
800 
801  if (nFilesToPlay == 9999)
802  nFilesToPlay = inFilesToPlay.size();
803 
804  if (nFilesToPlay == 0)
805  {
806  if (gBuiltInStream.eof())
807  {
808  // The built-in caption stream has already been used.
809  // This can happen when running in "loop" mode, so reset it, so it can be used again...
810  gBuiltInStream.clear(); // Clear EOF
811  gBuiltInStream.seekg(0); // Rewind
812  }
813  result.push_back(CaptionSourcePtr(new CaptionSource(inCharsPerMinute, &gBuiltInStream, string())));
814  }
815  else
816  {
817  for (size_t ndx(0); ndx < inFilesToPlay.size(); ndx++)
818  {
819  const string filePath(inFilesToPlay.at(ndx));
820  if (filePath == "-")
821  {
822  if (pStdIn)
823  { // Add stdin once
824  result.push_back(CaptionSourcePtr(new CaptionSource(inCharsPerMinute, pStdIn, string())));
825  pStdIn = AJA_NULL; // Standard input can only be read from once
826  }
827  else
828  cerr << "## WARNING: Standard input ('-') can only be specified once" << endl;
829  } // '-' means "read from standard input"
830  else
831  {
832  ifstream * pFileStream (new ifstream(filePath.c_str()));
833  NTV2_ASSERT(pFileStream);
834  if (pFileStream->is_open())
835  {
836  static const string scc(".scc");
837  const size_t pos (filePath.rfind(scc));
838  if (pos == (filePath.length()-scc.length()))
839  result.push_back(CaptionSourcePtr(new SCCSource(inCharsPerMinute, pFileStream, filePath, true)));
840  else
841  result.push_back(CaptionSourcePtr(new CaptionSource(inCharsPerMinute, pFileStream, filePath, true)));
842  PLINFO("Caption file '" << filePath << "' opened");
843  }
844  else
845  {
846  PLWARN("Cannot open caption file '" << filePath << "'");
847  cerr << "## WARNING: Cannot play '" << filePath << "'" << endl;
848  }
849  } // else not '-'
850  } // for each caption file to play
851  } // else caption file list is not empty
852 
853  return result;
854 
855 } // GetCaptionSources
856 
857 
858 
860  : mConfig (inConfigData),
861  mPlayThread (),
862  mGeneratorThreads (),
863  mSavedTaskMode (NTV2_DISABLE_TASKS),
864  mVideoStandard (NTV2_STANDARD_INVALID),
865  mPlayerQuit (false),
866  mCaptionGeneratorQuit (false),
867  mActiveFrameStores (),
868  mConnections ()
869 {
870  NTV2_ASSERT(!mConfig.fCapChanGenConfigs.empty());
871  mGeneratorThreads.resize(size_t(NTV2_CC608_XDS));
872  while (mGeneratorThreads.size() < size_t(NTV2_CC608_XDS))
873  mGeneratorThreads.push_back(AJAThread());
874 } // constructor
875 
876 
878 {
879  // Stop my playout and producer threads, then destroy them...
880  Quit();
881 
882  mDevice.UnsubscribeOutputVerticalEvent(mActiveFrameStores);
883  if (!mConfig.fDoMultiFormat)
884  {
885  mDevice.SetTaskMode(mSavedTaskMode); // Restore prior service level
886  mDevice.ReleaseStreamForApplication (kAppSignature, int32_t(AJAProcess::GetPid())); // Release the device
887  }
888 
889 } // destructor
890 
891 
892 void NTV2CCPlayer::Quit (const bool inQuitImmediately)
893 {
894  // Kill the caption generators first...
895  mCaptionGeneratorQuit = true;
896  while (!mGeneratorThreads.empty())
897  {
898  while (mGeneratorThreads.back().Active())
899  AJATime::Sleep(10);
900  mGeneratorThreads.pop_back();
901  }
902 
903  if (m608Encoder)
904  {
905  if (inQuitImmediately)
906  {
907  PLDBG("Quit immediate -- flushing");
908  m608Encoder->Flush(); // Immediately flush all queued messages
909  }
910  else
911  {
912  PLDBG("Quit non-immediate -- waiting for queue to drain");
913  while (m608Encoder->GetQueuedByteCount(NTV2_CC608_Field1) || m608Encoder->GetQueuedByteCount(NTV2_CC608_Field2))
914  AJATime::Sleep(10); // Wait for PlayThread encoder's message queues to drain as PlayThread continues
915  // This Sleep isn't necessary, but if not done, the last captions (or Erase) won't get a chance to be seen on downstream
916  // devices (because the AJA device will get released, and the retail services will change the device configuration).
917  AJATime::Sleep(2000);
918  }
919  }
920 
921  mPlayerQuit = true;
922  while (mPlayThread.Active())
923  AJATime::Sleep(10);
924  mDevice.RemoveConnections(mConnections);
925 
926 } // Quit
927 
928 
930 {
931  UWord majorVersion (0), minorVersion (0), pointVersion (0), buildNumber (0);
932  mDevice.GetDriverVersionComponents (majorVersion, minorVersion, pointVersion, buildNumber);
933  // Device Anc extraction requires driver version 12.3 minimum (or 0.0.0.0 for internal development)...
934  if ((majorVersion == 12 && minorVersion >= 3) || (majorVersion >= 13) || (majorVersion == 0 && minorVersion == 0 && pointVersion == 0 && buildNumber == 0))
935  // The device must also support it...
936  if (mDevice.features().CanDoCustomAnc())
937  // And perhaps even do firmware version/date checks??
938  return true;
939  return false;
940 }
941 
942 
944 {
945  AJAStatus status (AJA_STATUS_SUCCESS);
946 
947  // Open the device...
949  { if (aja::lower(mConfig.fDeviceSpec) != "list" && mConfig.fDeviceSpec != "?")
950  cerr << "## ERROR: Device '" << mConfig.fDeviceSpec << "' not found" << endl;
951  return AJA_STATUS_OPEN;
952  }
953  CNTV2DemoCommon::SetDefaultPageSize(); // Set host-specific page size
954  if (!mDevice.IsDeviceReady(false))
955  {cerr << "## ERROR: Device '" << mConfig.fDeviceSpec << "' not ready" << endl; return AJA_STATUS_INITIALIZE;}
956  if (!mDevice.features().CanDoPlayback())
957  {cerr << "## ERROR: '" << mDevice.GetDisplayName() << "' is capture-only" << endl; return AJA_STATUS_FEATURE;}
958 
959  if (!mConfig.fDoMultiFormat)
960  {
962  {
963  cerr << "## ERROR: Cannot acquire '" << mDevice.GetDisplayName() << "' because another app owns it" << endl;
964  return AJA_STATUS_BUSY; // Some other app owns the device
965  }
966  mDevice.GetTaskMode(mSavedTaskMode); // Save the current task mode
967  }
968  mDevice.SetTaskMode(NTV2_OEM_TASKS); // Set OEM service level
969 
970  if (mDevice.features().CanDoMultiFormat() && mConfig.fDoMultiFormat)
971  mDevice.SetMultiFormatMode(true);
972  else if (mDevice.features().CanDoMultiFormat())
973  mDevice.SetMultiFormatMode(false);
974 
975  if (NTV2_IS_VANCMODE_OFF(mConfig.fVancMode)) // if user didn't use --vanc option...
976  if (!DeviceAncExtractorIsAvailable()) // and anc extractor isn't available...
977  mConfig.fVancMode = NTV2_VANCMODE_TALLER; // then enable Vanc anyway
978 
979  // Set up the device video config...
980  status = SetUpOutputVideo();
981  if (AJA_FAILURE(status))
982  return status;
983 
984  // Set up my background pattern buffer...
985  status = SetUpBackgroundPatternBuffer();
986  if (AJA_FAILURE(status))
987  return status;
988 
989  // Set up device signal routing...
990  status = RouteOutputSignal();
991  if (AJA_FAILURE(status))
992  return status;
993 
994  #if defined(_DEBUG)
995  cerr << mConfig
996  << "Device Description: " << mDevice.GetDescription() << endl
997  << endl;
998  #endif // defined(_DEBUG)
999  return AJA_STATUS_SUCCESS;
1000 
1001 } // Init
1002 
1003 
1005 {
1006  // Generate the test pattern...
1007  NTV2TestPatternGen testPatternGen;
1008  const NTV2FormatDescriptor formatDesc (mConfig.fVideoFormat, mConfig.fPixelFormat, mConfig.fVancMode);
1009  testPatternGen.setVANCToLegalBlack(formatDesc.IsVANC()); // Clear the VANC region to legal black if needed
1010 
1011  // Allocate and clear the host video buffer memory...
1012  mVideoBuffer.Allocate(formatDesc.GetVideoWriteSize());
1013 
1014  if (!testPatternGen.DrawTestPattern (mConfig.fTestPatternName, formatDesc, mVideoBuffer))
1015  {
1016  cerr << "## ERROR: DrawTestPattern failed, formatDesc: " << formatDesc << endl;
1017  return AJA_STATUS_FAIL;
1018  }
1019 
1020  // Burn static info into the test pattern...
1021  const string strVideoFormat (CNTV2DemoCommon::StripFormatString (::NTV2VideoFormatToString(mConfig.fVideoFormat)));
1022  { ostringstream oss;
1023  oss << setw(32) << left << string("CCPlayer ") + strVideoFormat + string(formatDesc.IsVANC() ? " VANC" : "");
1024  CNTV2CaptionRenderer::BurnString (oss.str(), NTV2Line21Attributes(NTV2_CC608_White, NTV2_CC608_Cyan), mVideoBuffer, formatDesc, 1, 1); // R1C1
1025  }
1026  { ostringstream oss;
1027  oss << formatDesc.GetRasterWidth() << "Wx" << formatDesc.GetFullRasterHeight() << "H "
1028  << ::NTV2FrameBufferFormatToString(mConfig.fPixelFormat, true) << string(20, ' ');
1029  CNTV2CaptionRenderer::BurnString (oss.str(), NTV2Line21Attributes(NTV2_CC608_White, NTV2_CC608_Cyan), mVideoBuffer, formatDesc, 2, 1); // R2C1
1030  }
1031  return AJA_STATUS_SUCCESS;
1032 
1033 } // SetUpBackgroundPatternBuffer
1034 
1035 
1037 {
1038  // Preflight checks...
1039  if (mDevice.features().GetNumVideoOutputs() < 1)
1040  {cerr << "## ERROR: Device cannot playout" << endl; return AJA_STATUS_UNSUPPORTED;}
1041  if ((mConfig.fOutputChannel == NTV2_CHANNEL1) && !mDevice.features().CanDoFrameStore1Display())
1042  {cerr << "## ERROR: Device cannot playout thru FrameStore 1" << endl; return AJA_STATUS_UNSUPPORTED;}
1043  if (!NTV2_OUTPUT_DEST_IS_SDI(mConfig.fOutputDest))
1044  {
1045  cerr << "## ERROR: CCPlayer uses SDI only, not '" << ::NTV2OutputDestinationToString(mConfig.fOutputDest,true) << "'" << endl;
1046  return AJA_STATUS_UNSUPPORTED;
1047  }
1048  if (!mDevice.features().CanDoOutputDestination(mConfig.fOutputDest))
1049  {
1050  cerr << "## ERROR: No such output connector '" << ::NTV2OutputDestinationToString(mConfig.fOutputDest,true) << "'" << endl;
1051  return AJA_STATUS_UNSUPPORTED;
1052  }
1053  if (NTV2_IS_QUAD_FRAME_FORMAT(mConfig.fVideoFormat) && !mDevice.features().CanDo12gRouting())
1054  {
1055  if (!mConfig.fDoTsiRouting && mConfig.fOutputChannel != NTV2_CHANNEL1 && mConfig.fOutputChannel != NTV2_CHANNEL5)
1056  {
1057  cerr << "## ERROR: Quad-frame format must use Ch1|Ch5, not '" << ::NTV2ChannelToString(mConfig.fOutputChannel, true) << "'" << endl;
1058  return AJA_STATUS_BAD_PARAM;
1059  }
1060  else if (mConfig.fDoTsiRouting && (mConfig.fOutputChannel & 1))
1061  {
1062  cerr << "## ERROR: UHD/4K TSI must use Ch[1|3|5|7], not '" << ::NTV2ChannelToString(mConfig.fOutputChannel, true) << "'" << endl;
1063  return AJA_STATUS_BAD_PARAM;
1064  }
1065  const NTV2Channel sdiChan(::NTV2OutputDestinationToChannel(mConfig.fOutputDest));
1066  if (!mConfig.fDoTsiRouting && sdiChan != NTV2_CHANNEL1 && sdiChan != NTV2_CHANNEL5)
1067  {
1068  cerr << "## ERROR: UHD/4K Squares must use SDIOut[1|5], not '" << ::NTV2ChannelToString(mConfig.fOutputChannel, true) << "'" << endl;
1069  return AJA_STATUS_BAD_PARAM;
1070  }
1071  else if (mConfig.fDoTsiRouting && (sdiChan & 1))
1072  {
1073  cerr << "## ERROR: UHD/4K TSI must use SDIOut[1|3|5|7], not '" << ::NTV2ChannelToString(mConfig.fOutputChannel, true) << "'" << endl;
1074  return AJA_STATUS_BAD_PARAM;
1075  }
1076  }
1077  else
1078  mConfig.fDoTsiRouting = false; // Allows RouteOutputSignal to cheat
1080  {cerr << "## ERROR: CCPlayer doesn't yet support UHD2/8K formats" << endl; return AJA_STATUS_UNSUPPORTED;}
1081  if (NTV2_IS_625_FORMAT(mConfig.fVideoFormat))
1082  cerr << "## WARNING: SD 625/PAL not supported -- but will insert CEA608 caption packets anyway" << endl;
1084  if (NTV2_IS_VANCMODE_ON(mConfig.fVancMode))
1085  {cerr << "## ERROR: Cannot use VANC mode with UHD/4K/UHD2/8K formats" << endl; return AJA_STATUS_UNSUPPORTED;}
1086  if (NTV2_IS_SD_VIDEO_FORMAT(mConfig.fVideoFormat) && !mConfig.fSuppressLine21)
1088  {cerr << "## ERROR: SD/line21 in " << ::NTV2FrameBufferFormatToString(mConfig.fPixelFormat) << "' not '2vuy'|'v210'" << endl; return AJA_STATUS_UNSUPPORTED;}
1089  if (UWord(mConfig.fOutputChannel) >= mDevice.features().GetNumFrameStores())
1090  {cerr << "## ERROR: Device has " << DEC(mDevice.features().GetNumFrameStores()) << " FrameStore(s), no channel " << DEC(mConfig.fOutputChannel+1) << endl; return AJA_STATUS_UNSUPPORTED;}
1091 
1092  const NTV2FrameRate frameRate(::GetNTV2FrameRateFromVideoFormat(mConfig.fVideoFormat));
1093  if (!NTV2_IS_SD_VIDEO_FORMAT(mConfig.fVideoFormat) && !mConfig.fSuppress708)
1094  if (frameRate == NTV2_FRAMERATE_2500 || frameRate == NTV2_FRAMERATE_5000)
1095  {cerr << "## ERROR: CEA708 CDPs can't accommodate CEA608 captions for " << ::NTV2FrameRateToString(frameRate) << endl; return AJA_STATUS_UNSUPPORTED;}
1096 
1097  //
1098  // Enable the required framestore(s)...
1099  //
1101  mActiveFrameStores = ::NTV2MakeChannelSet(mConfig.fOutputChannel, mConfig.fDoTsiRouting ? 2 : 4);
1102  else
1103  mActiveFrameStores.insert(mConfig.fOutputChannel);
1104  mDevice.EnableChannels (mActiveFrameStores,
1105  !mConfig.fDoMultiFormat); // Disable other channels if not MultiFormat mode
1106 
1107  //
1108  // Set video format/standard...
1109  //
1110  if (!mDevice.features().CanDoVideoFormat(mConfig.fVideoFormat))
1111  {cerr << "## ERROR: '" << ::NTV2VideoFormatToString(mConfig.fVideoFormat) << "' not supported" << endl; return AJA_STATUS_UNSUPPORTED;}
1112  mVideoStandard = ::GetNTV2StandardFromVideoFormat(mConfig.fVideoFormat);
1113  mDevice.SetVideoFormat (mActiveFrameStores, mConfig.fVideoFormat, AJA_RETAIL_DEFAULT);
1115  {}
1116  else if (mConfig.fDoTsiRouting)
1117  mDevice.SetTsiFrameEnable(true, mConfig.fOutputChannel);
1118  else
1119  mDevice.Set4kSquaresEnable(true, mConfig.fOutputChannel);
1120 
1121  //
1122  // Set frame buffer pixel format...
1123  //
1124  if (!mDevice.features().CanDoFrameBufferFormat (mConfig.fPixelFormat))
1125  {cerr << "## ERROR: '" << ::NTV2FrameBufferFormatToString(mConfig.fPixelFormat) << "' not supported" << endl; return AJA_STATUS_UNSUPPORTED;}
1126  if (NTV2_IS_VANCMODE_ON(mConfig.fVancMode) && ::IsRGBFormat(mConfig.fPixelFormat) != mConfig.fDoRGBOnWire)
1127  {cerr << "## ERROR: Routing thru CSC may corrupt VANC in frame buffer" << endl; return AJA_STATUS_UNSUPPORTED;}
1128  mDevice.SetFrameBufferFormat (mActiveFrameStores, mConfig.fPixelFormat);
1129  if (NTV2_IS_VANCMODE_OFF(mConfig.fVancMode))
1130  if (mConfig.fOutputChannel != ::NTV2OutputDestinationToChannel(mConfig.fOutputDest))
1131  {
1132  cerr << "## ERROR: FrameStore" << DEC(mConfig.fOutputChannel+1)
1133  << " doesn't correlate with SDIOut" << DEC(::NTV2OutputDestinationToChannel(mConfig.fOutputDest)+1)
1134  << " -- Anc inserter requires both to match, output signal won't have captions" << endl;
1135  return AJA_STATUS_FAIL;
1136  }
1137 
1138  //
1139  // Enable VANC only if device has no Anc inserters, or if --vanc specified...
1140  //
1143  mDevice.SetVANCMode (mActiveFrameStores, mConfig.fVancMode);
1145  if (NTV2_IS_VANCMODE_ON(mConfig.fVancMode))
1146  if (::Is8BitFrameBufferFormat(mConfig.fPixelFormat))
1147  mDevice.SetVANCShiftMode (mConfig.fOutputChannel, NTV2_VANCDATA_8BITSHIFT_ENABLE); // 8-bit FBFs require VANC bit shift
1148 
1149  //
1150  // Create the caption encoders...
1151  //
1152  if (!CNTV2CaptionEncoder608::Create(m608Encoder))
1153  {cerr << "## ERROR: Cannot create 608 encoder" << endl; return AJA_STATUS_MEMORY;}
1154  if (!CNTV2CaptionEncoder708::Create(m708Encoder))
1155  {cerr << "## ERROR: Cannot create 708 encoder" << endl; return AJA_STATUS_MEMORY;}
1156 
1158 
1159  //
1160  // Subscribe to the output interrupt(s)...
1161  //
1162  mDevice.SubscribeOutputVerticalEvent(mActiveFrameStores);
1163 
1164  cerr << "## NOTE: Generating '" << ::NTV2VideoFormatToString(mConfig.fVideoFormat)
1165  << "' using " << (NTV2_IS_VANCMODE_ON(mConfig.fVancMode) ? "VANC" : "device Anc inserter")
1166  << " on '" << mDevice.GetDisplayName() << "' to " << ::NTV2OutputDestinationToString(mConfig.fOutputDest)
1167  << (mConfig.fDoRGBOnWire ? " (DL-RGB)" : "")
1168  << " from FrameStore" << DEC(mConfig.fOutputChannel+1)
1169  << " using " << ::NTV2FrameBufferFormatToString(mConfig.fPixelFormat) << endl;
1170  return AJA_STATUS_SUCCESS;
1171 
1172 } // SetUpOutputVideo
1173 
1174 
1176 {
1177  const bool isRGBFBF (::IsRGBFormat(mConfig.fPixelFormat));
1178  const bool isRGBWire (mConfig.fDoRGBOnWire); // RGB-over-SDI?
1179  const bool isQuadFmt (NTV2_IS_QUAD_FRAME_FORMAT(mConfig.fVideoFormat));
1180  const bool is4KHFR (NTV2_IS_HFR_STANDARD(mVideoStandard));
1181  const NTV2Channel sdiOutput (::NTV2OutputDestinationToChannel(mConfig.fOutputDest));
1182  NTV2ChannelSet sdiOuts (::NTV2MakeChannelSet(sdiOutput, UWord(mActiveFrameStores.size())));
1183  NTV2ChannelList sdiOutputs (::NTV2MakeChannelList(sdiOuts));
1184  NTV2ChannelList frameStores (::NTV2MakeChannelList(mActiveFrameStores));
1185  NTV2ChannelList tsiMuxes, cscs;
1186  mConnections.clear();
1187 
1188  // Does device have RGB conversion capability for the desired channel?
1189  if (isRGBFBF != isRGBWire // if any CSC(s) are needed
1190  && UWord(mConfig.fOutputChannel) > mDevice.features().GetNumCSCs())
1191  {cerr << "## ERROR: No CSC for channel " << (mConfig.fOutputChannel+1) << endl; return AJA_STATUS_UNSUPPORTED;}
1192  //*UNCOMMENT TO SHOW ROUTING PROGRESS WHILE DEBUGGING*/mDevice.ClearRouting();
1193 
1194  mDevice.SetSDITransmitEnable(sdiOuts, true);
1195  if (isRGBFBF && isRGBWire)
1196  {
1197  if (!mConfig.fDoTsiRouting) // RGBFrameStore ==> DLOut ==> SDIOut
1198  for (size_t ndx(0); ndx < sdiOutputs.size(); ndx++)
1199  { NTV2Channel frmSt(frameStores.at(ndx)), sdiOut(sdiOutputs.at(ndx));
1200  mConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut, /*isDS2*/false), ::GetDLOutOutputXptFromChannel(sdiOut, /*isDS2*/false)));
1201  mConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut, /*isDS2*/true), ::GetDLOutOutputXptFromChannel(sdiOut, /*isDS2*/true)));
1202  mConnections.insert(NTV2XptConnection(::GetDLOutInputXptFromChannel(sdiOut), ::GetFrameStoreOutputXptFromChannel(frmSt, true/*isRGB*/, false/*is425*/)));
1203  //*UNCOMMENT TO SHOW ROUTING PROGRESS WHILE DEBUGGING*/mDevice.ApplySignalRoute(mConnections);
1204  // Disable SDI output conversions
1205  mDevice.SetSDIOutLevelAtoLevelBConversion(sdiOut, false);
1206  mDevice.SetSDIOutRGBLevelAConversion(sdiOut, false);
1207  }
1208  else
1209  { // RGBFrameStore ==> 425MUX ==> 2x DLOut ==> 2x SDIOut
1210  sdiOuts = ::NTV2MakeChannelSet(sdiOutput, UWord(2*mActiveFrameStores.size()));
1211  sdiOutputs = ::NTV2MakeChannelList(sdiOuts);
1212  tsiMuxes = CNTV2DemoCommon::GetTSIMuxesForFrameStore(mDevice, frameStores.at(0), UWord(frameStores.size()*2));
1213  mDevice.SetSDITransmitEnable(sdiOuts, true); // Gotta do this again, since sdiOuts changed
1214  for (size_t ndx(0); ndx < sdiOutputs.size(); ndx++)
1215  { NTV2Channel frmSt(frameStores.at(ndx/2)), tsiMux(tsiMuxes.at(ndx/2)), sdiOut(sdiOutputs.at(ndx));
1216  mConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut, /*isDS2*/false), ::GetDLOutOutputXptFromChannel(sdiOut, /*isDS2*/false)));
1217  mConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut, /*isDS2*/true), ::GetDLOutOutputXptFromChannel(sdiOut, /*isDS2*/true)));
1218  mConnections.insert(NTV2XptConnection(::GetDLOutInputXptFromChannel(sdiOut), ::GetTSIMuxOutputXptFromChannel(tsiMux, /*isLinkB*/(ndx & 1) > 0, /*isRGB*/true)));
1219  mConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux,/*linkB?*/false), ::GetFrameStoreOutputXptFromChannel(frmSt, true/*isRGB*/, false/*is425*/)));
1220  mConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux,/*linkB?*/true), ::GetFrameStoreOutputXptFromChannel(frmSt, true/*isRGB*/, true/*is425*/)));
1221  //*UNCOMMENT TO SHOW ROUTING PROGRESS WHILE DEBUGGING*/mDevice.ApplySignalRoute(mConnections);
1222  }
1223  }
1224  }
1225  else if (isRGBFBF && !isRGBWire)
1226  {
1227  if (!mConfig.fDoTsiRouting) // RGBFrameStore ==> CSC ==> SDIOut
1228  for (size_t ndx(0); ndx < sdiOutputs.size(); ndx++)
1229  { NTV2Channel frmSt(frameStores.at(ndx)), sdiOut(sdiOutputs.at(ndx));
1230  mConnections.insert(NTV2XptConnection(::GetCSCInputXptFromChannel(frmSt),
1231  ::GetFrameStoreOutputXptFromChannel(frmSt, /*isRGB*/true, /*is425*/false)));
1232  mConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut),
1233  ::GetCSCOutputXptFromChannel(frmSt)));
1234  //*UNCOMMENT TO SHOW ROUTING PROGRESS WHILE DEBUGGING*/mDevice.ApplySignalRoute(mConnections);
1235  // Disable SDI output conversions
1236  mDevice.SetSDIOutLevelAtoLevelBConversion(sdiOut, false);
1237  mDevice.SetSDIOutRGBLevelAConversion(sdiOut, false);
1238  }
1239  else
1240  { // TSI // RGBFrameStore ==> 425MUX ==> LFR: 2 x CSC ==> 2 x SDIOut HFR: 4 x CSC ==> 4 x SDI
1241  sdiOuts = ::NTV2MakeChannelSet(sdiOutput, is4KHFR ? 4 : UWord(mActiveFrameStores.size()));
1242  sdiOutputs = ::NTV2MakeChannelList(sdiOuts);
1243  tsiMuxes = CNTV2DemoCommon::GetTSIMuxesForFrameStore(mDevice, frameStores.at(0), UWord(frameStores.size()));
1244  cscs = ::NTV2MakeChannelList(mConfig.fOutputChannel > NTV2_CHANNEL4 ? NTV2_CHANNEL5 : NTV2_CHANNEL1, isQuadFmt ? 4 : 2);
1245  //cerr << " FrmSt: " << ::NTV2ChannelListToStr(frameStores) << endl << " TSIMx: " << ::NTV2ChannelListToStr(tsiMuxes) << endl
1246  // << " CSCs: " << ::NTV2ChannelListToStr(cscs) << endl << "SDIOut: " << ::NTV2ChannelListToStr(sdiOutputs) << endl;
1247  mDevice.SetSDITransmitEnable(sdiOuts, true); // Do this again, since sdiOuts changed
1248  for (size_t ndx(0); ndx < cscs.size(); ndx++)
1249  { NTV2Channel frmSt (frameStores.at(ndx/2)), tsiMux (tsiMuxes.at(ndx/2)),
1250  sdiOut (sdiOutputs.at(is4KHFR ? ndx : ndx/2)), csc (cscs.at(ndx));
1251  mConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux,/*linkB?*/ndx & 1),
1252  ::GetFrameStoreOutputXptFromChannel(frmSt, true/*isRGB*/, ndx & 1/*is425*/)));
1253  mConnections.insert(NTV2XptConnection(::GetCSCInputXptFromChannel(csc),
1254  ::GetTSIMuxOutputXptFromChannel(tsiMux, /*isLinkB*/ndx & 1, /*isRGB*/true)));
1255  mConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut, /*isDS2*/is4KHFR ? false : ndx & 1),
1256  ::GetCSCOutputXptFromChannel(cscs.at(ndx))));
1257  //*UNCOMMENT TO SHOW ROUTING PROGRESS WHILE DEBUGGING*/mDevice.ApplySignalRoute(mConnections);
1258  }
1259  }
1260  }
1261  else if (!isRGBFBF && isRGBWire)
1262  {
1263  if (!mConfig.fDoTsiRouting) // YUVFrameStore ==> CSC ==> DLOut ==> SDIOut
1264  for (size_t ndx(0); ndx < sdiOutputs.size(); ndx++)
1265  { NTV2Channel frmSt(frameStores.at(ndx)), sdiOut(sdiOutputs.at(ndx));
1266  mConnections.insert(NTV2XptConnection(::GetCSCInputXptFromChannel(frmSt, /*isKeyInput*/false), ::GetFrameStoreOutputXptFromChannel(frmSt, false/*isRGB*/, false/*is425*/)));
1267  mConnections.insert(NTV2XptConnection(::GetDLOutInputXptFromChannel(sdiOut), ::GetCSCOutputXptFromChannel(frmSt, /*isKey*/false, /*isRGB*/true)));
1268  mConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut, /*isDS2*/false), ::GetDLOutOutputXptFromChannel(sdiOut, /*isDS2*/false)));
1269  mConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut, /*isDS2*/true), ::GetDLOutOutputXptFromChannel(sdiOut, /*isDS2*/true)));
1270  //*UNCOMMENT TO SHOW ROUTING PROGRESS WHILE DEBUGGING*/mDevice.ApplySignalRoute(mConnections);
1271  // Disable SDI output conversions
1272  mDevice.SetSDIOutLevelAtoLevelBConversion(sdiOut, false);
1273  mDevice.SetSDIOutRGBLevelAConversion(sdiOut, false);
1274  }
1275  else
1276  { // YUVFrameStore ==> 425MUX ==> 2x CSC ==> 2x DLOut ==> 2x SDIOut
1277  sdiOuts = ::NTV2MakeChannelSet(sdiOutput, UWord(2*mActiveFrameStores.size()));
1278  sdiOutputs = ::NTV2MakeChannelList(sdiOuts);
1279  tsiMuxes = CNTV2DemoCommon::GetTSIMuxesForFrameStore(mDevice, frameStores.at(0), UWord(frameStores.size()*2));
1280  mDevice.SetSDITransmitEnable(sdiOuts, true); // Gotta do this again, since sdiOuts changed
1281  for (size_t ndx(0); ndx < sdiOutputs.size(); ndx++)
1282  { NTV2Channel frmSt(frameStores.at(ndx/2)), tsiMux(tsiMuxes.at(ndx/2)), sdiOut(sdiOutputs.at(ndx));
1283  mConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux,/*linkB?*/false), ::GetFrameStoreOutputXptFromChannel(frmSt, false/*isRGB*/, false/*is425*/)));
1284  mConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux,/*linkB?*/true), ::GetFrameStoreOutputXptFromChannel(frmSt, false/*isRGB*/, true/*is425*/)));
1285  mConnections.insert(NTV2XptConnection(::GetCSCInputXptFromChannel(sdiOut, /*isKeyInput*/false), ::GetTSIMuxOutputXptFromChannel(tsiMux, /*linkB*/(ndx & 1) > 0,/*isRGB*/false)));
1286  mConnections.insert(NTV2XptConnection(::GetDLOutInputXptFromChannel(sdiOut), ::GetCSCOutputXptFromChannel(NTV2Channel(sdiOut),/*isKey*/false,/*isRGB*/true)));
1287  mConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut, /*isDS2*/false), ::GetDLOutOutputXptFromChannel(sdiOut, /*isDS2*/false)));
1288  mConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut, /*isDS2*/true), ::GetDLOutOutputXptFromChannel(sdiOut, /*isDS2*/true)));
1289  //*UNCOMMENT TO SHOW ROUTING PROGRESS WHILE DEBUGGING*/mDevice.ApplySignalRoute(mConnections);
1290  }
1291  }
1292  }
1293  else // !isRGBFBF && !isRGBWire
1294  {
1295  if (!mConfig.fDoTsiRouting) // YUVFrameStore ==> SDIOut
1296  for (size_t ndx(0); ndx < sdiOutputs.size(); ndx++)
1297  { NTV2Channel frmSt(frameStores.at(ndx)), sdiOut(sdiOutputs.at(ndx));
1298  mConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut),
1300  //*UNCOMMENT TO SHOW ROUTING PROGRESS WHILE DEBUGGING*/mDevice.ApplySignalRoute(mConnections);
1301  // Disable SDI output conversions
1302  mDevice.SetSDIOutLevelAtoLevelBConversion(sdiOut, false);
1303  mDevice.SetSDIOutRGBLevelAConversion(sdiOut, false);
1304  }
1305  else
1306  { // TSI // YUVFrameStore ==> 425MUX ==> SDIOut (LFR: 2 x DS1&DS2, 4KHFR: 4 x DS1)
1307  sdiOuts = ::NTV2MakeChannelSet(sdiOutput, is4KHFR ? 4 : UWord(mActiveFrameStores.size()));
1308  sdiOutputs = ::NTV2MakeChannelList(sdiOuts);
1309  tsiMuxes = CNTV2DemoCommon::GetTSIMuxesForFrameStore(mDevice, frameStores.at(0), UWord(frameStores.size()));
1310  //cerr << "FrameStores: " << ::NTV2ChannelListToStr(frameStores) << endl << "SDIOutputs: " << ::NTV2ChannelListToStr(sdiOutputs) << endl
1311  // << "TSIMuxers: " << ::NTV2ChannelListToStr(tsiMuxes) << endl;
1312  mDevice.SetSDITransmitEnable(sdiOuts, true); // Do this again, since sdiOuts changed
1313  for (size_t ndx(0); ndx < sdiOutputs.size(); ndx++)
1314  { NTV2Channel frmSt(frameStores.at(is4KHFR ? ndx/2 : ndx)),
1315  tsiMux(tsiMuxes.at(is4KHFR ? ndx/2 : ndx)),
1316  sdiOut(sdiOutputs.at(ndx));
1317  mConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut, /*isDS2*/false),
1318  ::GetTSIMuxOutputXptFromChannel(tsiMux, /*linkB?*/is4KHFR && (ndx & 1), /*RGB?*/false)));
1319  if (!is4KHFR)
1320  mConnections.insert(NTV2XptConnection(::GetSDIOutputInputXpt(sdiOut, /*isDS2*/true),
1321  ::GetTSIMuxOutputXptFromChannel(tsiMux, /*linkB?*/true, /*RGB?*/false)));
1322  mConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux,/*linkB?*/is4KHFR && (ndx & 1)),
1323  ::GetFrameStoreOutputXptFromChannel(frmSt, /*RGB?*/false, /*425?*/is4KHFR && (ndx & 1))));
1324  if (!is4KHFR)
1325  mConnections.insert(NTV2XptConnection(::GetTSIMuxInputXptFromChannel(tsiMux,/*linkB?*/true),
1326  ::GetFrameStoreOutputXptFromChannel(frmSt, /*RGB?*/false, /*425?*/true)));
1327  //*UNCOMMENT TO SHOW ROUTING PROGRESS WHILE DEBUGGING*/mDevice.ApplySignalRoute(mConnections);
1328  }
1329  }
1330  }
1331  return mDevice.ApplySignalRoute(mConnections, /*replaceExistingRouting?*/!mConfig.fDoMultiFormat) ? AJA_STATUS_SUCCESS : AJA_STATUS_UNSUPPORTED;
1332 
1333 } // RouteOutputSignal
1334 
1335 
1337 {
1338  // Start the threads...
1341  return AJA_STATUS_SUCCESS;
1342 
1343 } // Run
1344 
1345 
1347 // Caption generator thread
1349 
1351 { public:
1354  uint32_t fSpare;
1355  explicit CapGenStartInfo (NTV2CCPlayer * pPlayer, const NTV2Line21Channel inCapChan)
1356  : fpPlayer(pPlayer), fCapChannel(inCapChan)
1357  {}
1358 };
1359 
1360 
1362 {
1363  // Create and start the caption generator threads, one per caption channel...
1364  for (CaptionChanGenMapCIter it(mConfig.fCapChanGenConfigs.begin()); it != mConfig.fCapChanGenConfigs.end(); ++it)
1365  {
1366  const CCGenConfig & genConfig (it->second);
1367  AJAThread & genThread (mGeneratorThreads.at(size_t(genConfig.fCaptionChannel)));
1368  // The generator thread needs to know the NTV2CCPlayer instance, and the caption channel:
1370  reinterpret_cast<void*>(new CapGenStartInfo(this, genConfig.fCaptionChannel)));
1371  genThread.Start();
1372  }
1373 } // StartCaptionGeneratorThreads
1374 
1375 
1376 void NTV2CCPlayer::CaptionGeneratorThreadStatic (AJAThread * pThread, void * pContext) // STATIC
1377 { (void) pThread;
1378  // Extract all the startup info I need...
1379  const CapGenStartInfo * pStartInfo (reinterpret_cast<CapGenStartInfo*>(pContext));
1380  NTV2_ASSERT(pStartInfo);
1381  NTV2CCPlayer * pApp (pStartInfo->fpPlayer);
1382  NTV2_ASSERT(pApp);
1383  const NTV2Line21Channel captionChannel (pStartInfo->fCapChannel);
1384  NTV2_ASSERT(IsValidLine21Channel(captionChannel));
1385  delete pStartInfo; // Done with it, free it
1386 
1387  // Start generating captions for the given caption channel...
1388  pApp->GenerateCaptions(captionChannel);
1389 
1390 } // CaptionGeneratorThreadStatic
1391 
1392 
1394 {
1395  CaptionChanGenMapCIter iter(mConfig.fCapChanGenConfigs.find(inCCChannel));
1396  NTV2_ASSERT(iter != mConfig.fCapChanGenConfigs.end());
1397 
1398  const CCGenConfig & ccGenConfig (iter->second);
1399  const NTV2Line21Mode captionMode (ccGenConfig.fCaptionMode); // My caption mode (paint-on, pop-on, roll-up, etc.)
1400  const double charsPerMinute (ccGenConfig.fCharsPerMinute); // Desired caption rate (in characters per minute)
1401  const bool newlinesMakeNewRows (ccGenConfig.fNewLinesAreNewRows); // Newline characters cause row breaks?
1402  const AtEndAction endAction (ccGenConfig.fEndAction); // What to do after last file is done playing
1403  NTV2StringList filesToPlay (ccGenConfig.fFilesToPlay); // List of text files to play
1404  UWord linesWanted (3); // Desired number of lines to Enqueue in one shot (min 1, max 4)
1405  bool quitThisGenerator (false); // Set true to exit this function/thread
1406  const UWord paintPopTopRow (9); // PaintOn/PopOn only: top display row
1407  const UWord paintPopMaxNumRows (15 - paintPopTopRow + 1); // PaintOn/PopOn only: number of rows to fill to bottom
1408  UWord lineTally (0); // PaintOn/PopOn only: used to calculate display row
1409  const string ccChannelStr (::NTV2Line21ChannelToStr(inCCChannel));
1410 
1412  static const NTV2Line21Attrs sBluCynItal (NTV2_CC608_Blue, NTV2_CC608_Cyan, NTV2_CC608_Opaque, /*italic*/true);
1413  static const NTV2Line21Attrs sRedBlkFlas (NTV2_CC608_Red, NTV2_CC608_Black, NTV2_CC608_Opaque, /*italic*/false, /*UL*/false, /*flash*/true);
1414  static const NTV2Line21Attrs sBluGrnSemiUL (NTV2_CC608_Blue, NTV2_CC608_Green, NTV2_CC608_SemiTransparent, /*italic*/false, /*UL*/true);
1415  static const NTV2Line21Attrs sMgnCynItal (NTV2_CC608_Magenta,NTV2_CC608_Cyan, NTV2_CC608_SemiTransparent, /*italic*/true);
1416  static const NTV2Line21Attrs sAttrs[] = { NTV2Line21Attrs(), sBlkYelSemi, sBluCynItal, sRedBlkFlas, sBluGrnSemiUL, sMgnCynItal};
1417 
1418  PLNOTE("Started " << ccChannelStr << " generator thread");
1419  if (IsLine21TextChannel(inCCChannel) || !IsLine21RollUpMode(captionMode))
1420  linesWanted = 1;
1421  while (!mCaptionGeneratorQuit)
1422  {
1423  CaptionSourceList captionSources(::GetCaptionSources(filesToPlay, charsPerMinute));
1424  while (!mCaptionGeneratorQuit && !captionSources.empty())
1425  {
1426  CaptionSourcePtr captionSource(captionSources.front());
1427  captionSources.pop_front();
1428 
1429  // Set CaptionSource to Text Mode if caption channel is TX1/TX2/TX3/TX4...
1430  captionSource->SetTextMode(IsLine21TextChannel(inCCChannel));
1431  captionSource->SetCaptionChannel(inCCChannel);
1432 
1433  while (!mCaptionGeneratorQuit && !captionSource->IsFinished())
1434  {
1435  // Enqueue another message only if the encoder has less than 200 messages queued up...
1436  // (This prevents runaway memory consumption)
1437  if (m608Encoder->GetQueuedMessageCount() < 200)
1438  {
1439  if (captionSource->IsPlainTextSource())
1440  {
1441  string str (captionSource->GetNextCaptionRow(newlinesMakeNewRows));
1442 
1443  if (IsLine21CaptionChannel(inCCChannel) && !IsLine21RollUpMode(captionMode) && linesWanted > 1)
1444  for (UWord lines(linesWanted - 1); lines; lines--)
1445  str += "\n" + captionSource->GetNextCaptionRow();
1446 
1447  if (!mConfig.fEmitStats && !str.empty())
1448  cout << str << endl; // Echo caption lines (if not emitting stats)
1449  PLDBG(ccChannelStr << " caption line " << DEC(lineTally+1) << ": '" << str << "'");
1450 
1451  const NTV2Line21Attrs & attrs (sAttrs[lineTally % 6]); // Cycle thru different display attributes
1452 
1453  // For now, only the 608 encoder generates caption data.
1454  // Someday we may generate captions using 708-specific features (e.g., windowing, etc.).
1455 
1456  // Convert the UTF-8 string into a string containing CEA-608 byte codes expected
1457  // by Enqueue*Message functions (except EnqueueTextMessage, which accepts UTF-8)...
1458  if (!IsLine21TextChannel(inCCChannel))
1459  str = CUtf8Helpers::Utf8ToCEA608String(str, inCCChannel);
1460  switch (captionMode)
1461  {
1463  m608Encoder->EnqueuePopOnMessage (str, inCCChannel,
1464  /*row*/lineTally % paintPopMaxNumRows + paintPopTopRow,
1465  /*col*/1,
1466  /*attrs*/attrs);
1467  break;
1471  m608Encoder->EnqueueRollUpMessage (str, captionMode, inCCChannel,
1472  /*row*/0, /*col*/0,
1473  /*attrs*/attrs);
1474  break;
1476  m608Encoder->EnqueuePaintOnMessage (str,
1477  /*eraseFirst*/lineTally % paintPopMaxNumRows == 0,
1478  /*chan*/inCCChannel,
1479  /*row*/lineTally % paintPopMaxNumRows + paintPopTopRow,
1480  /*col*/1,
1481  /*attrs*/attrs);
1482  break;
1483  default:
1484  NTV2_ASSERT (IsLine21TextChannel(inCCChannel));
1485  m608Encoder->EnqueueTextMessage (str, lineTally == 0, inCCChannel);
1486  break;
1487  } // switch on caption mode
1488  lineTally++;
1489  } // if plaintext caption source
1490  else
1491  { // This caption source returns raw CC data byte pairs...
1492  SCCSource & sccSource(AsSCCSource(*captionSource));
1493  sccSource.EnqueueCCDataToFrame(m608Encoder, mACStatus.GetProcessedFrameCount());
1494  }
1495  } // if encoder has < 200 messages queued
1496  else
1497  AJATime::Sleep(1000);
1498  } // loop til captionSource is finished (or mCaptionGeneratorQuit)
1499  captionSource->SetCaptionChannel(NTV2_CC608_ChannelInvalid);
1500  } // for each captionSource
1501 
1502  switch (endAction)
1503  {
1504  case AtEndAction_Quit: PLINFO(ccChannelStr << " generator signaling 'main' to terminate");
1505  filesToPlay.clear(); // Clear to-do list if we loop again
1506  ::SignalHandler(SIG_AJA_STOP); // Signal 'main' to terminate
1507  quitThisGenerator = true; // Instantly terminates me
1508  break;
1509 
1510  case AtEndAction_Repeat: PLINFO(ccChannelStr << " generator repeating");
1511  break;
1512 
1513  case AtEndAction_Idle: PLINFO(ccChannelStr << " generator entering idle mode");
1514  filesToPlay.clear(); // Clear to-do list if we loop again
1515  quitThisGenerator = true; // Instantly terminates me
1516  break;
1517 
1518  default: NTV2_ASSERT (false && "bad end action");
1519  break;
1520  }
1521  if (quitThisGenerator)
1522  break;
1523  } // loop til mCaptionGeneratorQuit
1524 
1525  // Let's be nice, and inject an EDM (Erase Displayed Memory) control message.
1526  // This will prevent frozen, on-screen captions from remaining in/on downstream decoders/monitors...
1527  m608Encoder->Erase (inCCChannel);
1528  PLNOTE(ccChannelStr << " generator thread exit");
1529 
1530 } // GenerateCaptions
1531 
1532 
1534 // Playout thread
1536 
1537 
1539 {
1540  // Create and start the playout thread...
1541  mPlayThread.Attach(PlayThreadStatic, this);
1542  mPlayThread.SetPriority(AJA_ThreadPriority_High);
1543  mPlayThread.Start();
1544 } // StartPlayoutThread
1545 
1546 
1547 // The playout thread function
1548 void NTV2CCPlayer::PlayThreadStatic (AJAThread * pThread, void * pContext) // static
1549 { (void) pThread;
1550  // Grab the NTV2CCPlayer instance pointer from the pContext parameter,
1551  // then call its PlayoutFrames method...
1552  NTV2CCPlayer * pApp (reinterpret_cast<NTV2CCPlayer*>(pContext));
1553  pApp->PlayoutFrames ();
1554 } // PlayThreadStatic
1555 
1556 
1558 {
1561  static const uint32_t AUDIOBYTES_MAX_48K (201 * 1024); // Max audio bytes per frame (16 chls x 4 bytes x 67 msec/fr x 48000 Hz)
1562  static const double gAmplitudes [16] = { 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40,
1563  0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75,
1564  0.80, 0.85};
1565  static const double gFrequencies [16] = { 150.00000000, 200.00000000, 266.66666667, 355.55555556, 474.07407407, 632.09876543,
1566  842.79835391, 1123.73113855, 1498.30818473, 1997.74424630, 2663.65899507, 3551.54532676,
1567  4735.39376902, 6313.85835869, 8418.47781159, 11224.63708211};
1568  // 1080i 720p 525i 625i 1080p 2KFilm 2K1080p 2K1080i UHD 4K UHDHFR 4KHFR
1569  static const uint16_t gF2LineNums608[] = { 573, 0, 273, 323, 0, 1000, 0, 573, 0, 0, 0 }; // Line 10 equivs for F2
1570  static const uint16_t kF1PktLineNumCEA708(9), kF1PktLineNumCEA608(10);
1571  const NTV2SmpteLineNumber smpteLineNumInfo (::GetSmpteLineNumber(mVideoStandard));
1572  const uint16_t kF2PktLineNumCEA608 (gF2LineNums608[mVideoStandard]);
1573  const uint32_t F2StartLine (smpteLineNumInfo.GetLastLine(smpteLineNumInfo.firstFieldTop ? NTV2_FIELD0 : NTV2_FIELD1) + 1); // F2 VBI starts here
1574  static const AJAAncDataLoc kCEA708LocF1 (AJAAncDataLink_A, AJAAncDataChannel_Y, AJAAncDataSpace_VANC, kF1PktLineNumCEA708, AJAAncDataHorizOffset_AnyVanc);
1575  const NTV2FormatDescriptor formatDesc (mConfig.fVideoFormat, mConfig.fPixelFormat, mConfig.fVancMode);
1576  const ULWord bytesPerRow (formatDesc.GetBytesPerRow());
1577  const bool isProgressive (::IsProgressivePicture(mConfig.fVideoFormat));
1578  const bool isInterlaced (!isProgressive);
1579  CNTV2Line21Captioner Line21Encoder; // Used to encode "analog" (line 21) waveform
1580  CaptionData captionData; // Current frame's 608 caption byte pairs (both fields)
1581  ULWord acOptionFlags (0);
1582  ULWord currentSample (0);
1584  ULWord numAudioChannels (0);
1585  Bouncer<UWord> colBouncer (32 - 11 /*upperLimit*/, 0 /*lowerLimit*/, 0 /*startAt*/);
1586  NTV2Buffer audioBuffer;
1587  AUTOCIRCULATE_TRANSFER xferInfo;
1588  ULWord ANCKB (2); // 2 (default)
1589  if (NTV2_IS_VANCMODE_OFF(mConfig.fVancMode))
1590  {
1591 #if defined(NTV2_ANC_TEST)
1592  mDevice.WriteRegister(kVRegCCPlayerBufSizeKB, ANCKB); // Test
1593  PLINFO("Anc buffer size is " << DEC(ANCKB) << "K"); // Test
1594  xferInfo.acANCBuffer.Allocate(ANCKB*1024); // Test
1595  if (isInterlaced) // Test
1596  xferInfo.acANCField2Buffer.Allocate(ANCKB*1024); // Test
1597  mDevice.WriteRegister(kVRegCCPlayerCustomPkt, 0); // Test
1598 #else
1599  xferInfo.acANCBuffer.Allocate(ANCKB*1024);
1600  if (isInterlaced)
1601  xferInfo.acANCField2Buffer.Allocate(ANCKB*1024);
1602 #endif // defined(NTV2_ANC_TEST)
1603  } // if VANC mode is OFF
1604  if (!mConfig.fSuppressAudio)
1605  {
1606  // Audio setup...
1607  audioSystem = (mDevice.features().GetNumAudioSystems() > 1) ? ::NTV2ChannelToAudioSystem(mConfig.fOutputChannel) : NTV2_AUDIOSYSTEM_1;
1608  numAudioChannels = mDevice.features().GetMaxAudioChannels();
1609  if (NTV2_IS_4K_4096_VIDEO_FORMAT(mConfig.fVideoFormat) && numAudioChannels > 8)
1610  numAudioChannels = 8; // 2K/4096-pixel lines have narrower HANC space & can't handle 16 channels
1611  mDevice.SetNumberAudioChannels (numAudioChannels, audioSystem); // Config audio: # channels
1612  mDevice.SetAudioRate (NTV2_AUDIO_48K, audioSystem); // Config audio: 48kHz sample rate
1613  mDevice.SetAudioBufferSize (NTV2_AUDIO_BUFFER_BIG, audioSystem); // Config audio: Use 4MB output buffer
1614  mDevice.SetSDIOutputAudioSystem (mConfig.fOutputChannel, audioSystem); // Set output DS1 audio embedders to use designated audio system
1615  mDevice.SetSDIOutputDS2AudioSystem (mConfig.fOutputChannel, audioSystem); // Set output DS2 audio embedders to use designated audio system
1616  mDevice.SetAudioLoopBack (NTV2_AUDIO_LOOPBACK_OFF, audioSystem); // Config audio: Disable loopback (not E-E)
1617  audioBuffer.Allocate(AUDIOBYTES_MAX_48K); // Allocate audio buffer (large enough for one frame's audio)
1618  if (!mConfig.fDoMultiFormat)
1619  {
1620  for (UWord chan (0); chan < mDevice.features().GetNumVideoOutputs(); chan++)
1621  {
1622  mDevice.SetSDIOutputAudioSystem (NTV2Channel (chan), audioSystem);
1623  mDevice.SetSDIOutputDS2AudioSystem (NTV2Channel (chan), audioSystem);
1624  }
1625  if (mDevice.features().GetNumHDMIAudioOutputChannels() == 8)
1626  {
1628  mDevice.SetHDMIOutAudioSource8Channel (NTV2_AudioChannel1_8, audioSystem);
1629  }
1630  } // if not multiformat
1631  } // if audio not suppressed
1632 
1633  // Set up the transfer buffers...
1634  xferInfo.SetVideoBuffer(reinterpret_cast<ULWord *>(mVideoBuffer.GetHostPointer()), ULWord(mVideoBuffer.GetByteCount()));
1635  if (mConfig.fSuppressTimecode)
1636  xferInfo.acOutputTimeCodes.Set (AJA_NULL, 0);
1637  PLNOTE("Playout thread started: 608F1PktLine=" << DEC(kF1PktLineNumCEA608) << " 608F2PktLine=" << DEC(kF2PktLineNumCEA608)
1638  << " 708F1PktLine=" << DEC(kF1PktLineNumCEA708) << " F2StartLine=" << DEC(F2StartLine));
1639 
1641  mDevice.GetFrameRate(frameRate, mConfig.fOutputChannel);
1643 
1644  // Set up playout AutoCirculate and start it...
1645  if (NTV2_IS_VANCMODE_OFF(mConfig.fVancMode))
1646  acOptionFlags |= AUTOCIRCULATE_WITH_ANC;
1647  if (!mConfig.fSuppressTimecode)
1648  acOptionFlags |= AUTOCIRCULATE_WITH_RP188;
1649  if (!mConfig.fSuppressTimecode && !mConfig.fDoMultiFormat && mDevice.features().GetNumLTCOutputs())
1650  acOptionFlags |= AUTOCIRCULATE_WITH_LTC; // Emit analog LTC if we "own" the device
1651  mDevice.AutoCirculateStop (mConfig.fOutputChannel); // Maybe some other app left this A/C channel running
1652  if (NTV2_IS_SD_VIDEO_FORMAT(mConfig.fVideoFormat) && mConfig.fSuppressLine21 && mConfig.fSuppress608)
1653  cerr << "## WARNING: SD video with '--noline21' option and '--no608' option won't produce captions" << endl;
1654  if (mDevice.AutoCirculateInitForOutput (mConfig.fOutputChannel, mConfig.fFrames, audioSystem, acOptionFlags))
1655  mDevice.AutoCirculateStart (mConfig.fOutputChannel);
1656  else
1657  {cerr << "## ERROR: AutoCirculateInitForOutput failed" << endl; mPlayerQuit = true;}
1658 
1659  // Repeat until time to quit...
1660  while (!mPlayerQuit)
1661  { // Check AutoCirculate status...
1662  mDevice.AutoCirculateGetStatus (mConfig.fOutputChannel, mACStatus);
1663  if (!mACStatus.CanAcceptMoreOutputFrames())
1664  { // Out of room on the device for new frame...
1665  mDevice.WaitForOutputVerticalInterrupt (mConfig.fOutputChannel); // Wait for next VBI
1666  continue; // Try again
1667  }
1668  if (NTV2_IS_VANCMODE_OFF(mConfig.fVancMode))
1669  {xferInfo.acANCBuffer.Fill(ULWord(0)); xferInfo.acANCField2Buffer.Fill(ULWord(0));} // Clear Anc buffers before filling
1670 
1671  AJAAncillaryList packetList; // List of packets to be transmitted
1672  m608Encoder->GetNextCaptionData(captionData); // Pop queued captions from 608 encoder waiting to be transmitted
1673  if (!mConfig.fSuppress608)
1674  {
1676 
1677  pkt608F1.SetLocationLineNumber (kF1PktLineNumCEA608);
1678  pkt608F1.SetCEA608Bytes (captionData.f1_char1, captionData.f1_char2);
1679  pkt608F1.GeneratePayloadData();
1680  packetList.AddAncillaryData(pkt608F1);
1681  if (!NTV2_IS_PROGRESSIVE_STANDARD(mVideoStandard))
1682  { NTV2_ASSERT(kF2PktLineNumCEA608);
1684  pkt608F2.SetLocationLineNumber(kF2PktLineNumCEA608);
1685  pkt608F2.SetCEA608Bytes (captionData.f2_char1, captionData.f2_char2);
1686  pkt608F2.GeneratePayloadData();
1687  packetList.AddAncillaryData(pkt608F2);
1688  }
1689  }
1690 
1692  { // SD Video encodes "analog" waveform into line 21...
1693  if (!mConfig.fSuppressLine21)
1694  { // Overwrite Line21 with encoded CEA608 waveform
1695  ULWord line21RowOffset (0);
1696  UByte * pLine21 (AJA_NULL);
1697  UByte * pEncodedYUV8Line (AJA_NULL);
1698  formatDesc.GetLineOffsetFromSMPTELine (21, line21RowOffset);
1699  pLine21 = reinterpret_cast<UByte*>(formatDesc.GetWriteableRowAddress(mVideoBuffer.GetHostPointer(), line21RowOffset));
1700  if (pLine21)
1701  { // Encode F1 caption bytes into EIA-608-compliant 8-bit YUV waveform...
1702  pEncodedYUV8Line = Line21Encoder.EncodeLine (captionData.f1_char1, captionData.f1_char2);
1703  // Replace F1 line 21 in the frame buffer with the EncodeLine result...
1704  if (mConfig.fPixelFormat == NTV2_FBF_8BIT_YCBCR)
1705  ::memcpy (pLine21, pEncodedYUV8Line, bytesPerRow); // ... just copy the line
1706  else if (mConfig.fPixelFormat == NTV2_FBF_10BIT_YCBCR)
1707  ::ConvertLine_2vuy_to_v210 (pEncodedYUV8Line, reinterpret_cast<ULWord*>(pLine21), 720); // ...with EncodeLine result converted to 10-bit YUV
1708  }
1709  else PLFAIL("GetWriteableRowAddress return NULL for SMPTE line 21, rowOffset=" << xHEX0N(line21RowOffset,8) << " " << formatDesc);
1710 
1711  formatDesc.GetLineOffsetFromSMPTELine (284, line21RowOffset);
1712  pLine21 = reinterpret_cast<UByte*>(formatDesc.GetWriteableRowAddress(mVideoBuffer.GetHostPointer(), line21RowOffset));
1713  if (pLine21)
1714  { // Encode F2 caption bytes into EIA-608-compliant 8-bit YUV waveform...
1715  pEncodedYUV8Line = Line21Encoder.EncodeLine (captionData.f2_char1, captionData.f2_char2);
1716  // Replace F2 line 21 in the frame buffer with the EncodeLine result...
1717  if (mConfig.fPixelFormat == NTV2_FBF_8BIT_YCBCR)
1718  ::memcpy (pLine21, pEncodedYUV8Line, bytesPerRow); // ... just copy the line
1719  else if (mConfig.fPixelFormat == NTV2_FBF_10BIT_YCBCR)
1720  ::ConvertLine_2vuy_to_v210 (pEncodedYUV8Line, reinterpret_cast<ULWord*>(pLine21), 720); // ...with EncodeLine result converted to 10-bit YUV
1721  }
1722  else PLFAIL("GetWriteableRowAddress return NULL for SMPTE line 284, rowOffset=" << xHEX0N(line21RowOffset,8) << " " << formatDesc);
1723  //DEBUG if (captionData.HasData()) mDevice.DMAWriteFrame(33, (ULWord*) mVideoBuffer.GetHostPointer(), mVideoBuffer.GetByteCount());
1724  } // if not suppressing analog line21
1725  } // if SD video
1726  else if (!mConfig.fSuppress708)
1727  { // HD video -- use the 708 encoder to put 608 captions into a single 708 packet:
1728  m708Encoder->Set608CaptionData(captionData); // Set the 708 encoder's 608 caption data (for both F1 and F2)
1729  if (m708Encoder->MakeSMPTE334AncPacket (frameRate, NTV2_CC608_Field1)) // Generate SMPTE-334 Anc data packet
1730  {
1731  AJAAncillaryData_Cea708 pkt708;
1732  pkt708.SetFromSMPTE334 (m708Encoder->GetSMPTE334Data(), uint32_t(m708Encoder->GetSMPTE334Size()), kCEA708LocF1);
1733  packetList.AddAncillaryData(pkt708);
1734  }
1735  } // else HD video
1736 #if defined(NTV2_ANC_TEST) // Test
1737  ULWord val(0); // Test
1738  if (xferInfo.acANCBuffer && mDevice.ReadRegister(kVRegCCPlayerCustomPkt, val) && val) // Test
1739  { // Test
1740  AJAAncData pkt; static const uint8_t sTmp[] = {'T', 'M', 'P', '0'}; // Test
1742  AJAAncDataSpace_VANC, uint16_t(val & 0x0000FFFF))); // Test
1743  pkt.SetDIDSID(AJAAncDIDSIDPair((val >> 24) & 0xFF, (val >> 16) & 0xFF)); // Test
1744  pkt.SetPayloadData (sTmp, 4); // Test
1745  packetList.AddAncillaryData(pkt); // Test
1746  } // Test
1747  PLDBG("Xmit pkts: " << packetList); // DEBUG: Packet list to be transmitted // Test
1748 #endif // defined(NTV2_ANC_TEST) // Test
1749  packetList.SetAllowMultiRTPTransmit(mConfig.fForceRTP & BIT(1));
1750  if (NTV2_IS_VANCMODE_ON(mConfig.fVancMode)) // Write FB VANC lines...
1751  packetList.GetVANCTransmitData (mVideoBuffer, formatDesc);
1752  else if (mConfig.fForceRTP) // Force RTP? Non-IP2110 devices won't understand what's in the Anc buffer...
1753  packetList.GetIPTransmitData(xferInfo.acANCBuffer, xferInfo.acANCField2Buffer, isProgressive, F2StartLine);
1754  else // Else use the Anc inserter firmware:
1755  packetList.GetTransmitData (xferInfo.acANCBuffer, xferInfo.acANCField2Buffer, isProgressive, F2StartLine);
1756 
1757  if (mConfig.fForceRTP && mConfig.fForceRTP & BIT(1) && mDevice.features().CanDo2110())
1758  xferInfo.acTransferStatus.acState = NTV2_AUTOCIRCULATE_INVALID; // Signal MultiPkt RTP to AutoCirculateTransfer/S2110DeviceAncToXferBuffers
1759 
1760  if (!mConfig.fSuppressTimecode)
1761  {
1762  const CRP188 rp188 (mACStatus.GetProcessedFrameCount(), tcFormat);
1763  char tcString[] = {" "};
1764  const UWord colShift (mACStatus.GetProcessedFrameCount() % 10 == 0 ? colBouncer.Next() : colBouncer.Value());
1765  bool tcOK (false);
1766  NTV2_RP188 tc;
1767  rp188.GetRP188Reg (tc);
1768  if (!NTV2_IS_QUAD_FRAME_FORMAT(mConfig.fVideoFormat) && !mConfig.fDoMultiFormat)
1769  // UniFormat and not Quad Frame: i.e. using ALL output spigots:
1770  // AutoCirculateTransfer will automatically set ALL output timecodes to
1771  // the DEFAULT timecode if the DEFAULT timecode is valid...
1772  tcOK = xferInfo.SetOutputTimeCode(tc, NTV2_TCINDEX_DEFAULT);
1773  else
1774  { // MULTI-FORMAT OR QUAD-FRAME:
1775  // Be more selective as to which output spigots get the generated timecode...
1776  NTV2TimeCodes timecodes;
1777  for (int num (0); num < 4; num++)
1778  {
1779  const NTV2Channel chan (NTV2Channel(mConfig.fOutputChannel + num));
1780  timecodes[::NTV2ChannelToTimecodeIndex(chan, /*inEmbeddedLTC*/false)] = tc;
1781  timecodes[::NTV2ChannelToTimecodeIndex(chan, /*inEmbeddedLTC*/true)] = tc;
1782  if (isInterlaced)
1783  timecodes[::NTV2ChannelToTimecodeIndex(chan, /*inEmbeddedLTC*/false, /*inIsF2*/true)] = tc;
1784  if (acOptionFlags & AUTOCIRCULATE_WITH_LTC)
1785  {
1786  timecodes[NTV2_TCINDEX_LTC1] = tc;
1787  if (mDevice.features().GetNumLTCOutputs() > 1)
1788  timecodes[NTV2_TCINDEX_LTC2] = tc;
1789  }
1791  break; // Not Quad Frame: just do the one output
1792  } // for each quad
1793  tcOK = xferInfo.SetOutputTimeCodes(timecodes);
1794  }
1795  ::memcpy (tcString + colShift, rp188.GetRP188CString(), 11);
1796  CNTV2CaptionRenderer::BurnString (tcString, tcOK ? kBlueOnWhite : kRedOnYellow, mVideoBuffer, formatDesc, 3, 1); // R3C1
1797  } // if not suppressing timecode injection
1798 
1799  if (audioBuffer)
1800  xferInfo.SetAudioBuffer (audioBuffer,
1801  ::AddAudioTone (audioBuffer, // audio buffer to fill
1802  currentSample, // sample for continuing the waveform
1803  ::GetAudioSamplesPerFrame(frameRate, NTV2_AUDIO_48K, mACStatus.GetProcessedFrameCount()), // # samples to generate
1804  48000.0, // sample rate [Hz]
1805  gAmplitudes, // per-channel amplitudes
1806  gFrequencies, // per-channel tone frequencies [Hz]
1807  31, // bits per sample
1808  false, // false means "don't byte swap"
1809  numAudioChannels)); // number of audio channels
1810  // Finally ... transfer the frame data to the device...
1811  if (!mDevice.AutoCirculateTransfer (mConfig.fOutputChannel, xferInfo))
1812  PLFAIL("AutoCirculateTransfer failed");
1813 #if defined(NTV2_ANC_TEST) // Test
1814  if (xferInfo.acANCBuffer && mDevice.ReadRegister(kVRegCCPlayerBufSizeKB, val) && val && val != ANCKB) // Test
1815  { // Test
1816  PLINFO("Anc buffer size changed from " << DEC(ANCKB) << "K to " << DEC(val) << "K"); // Test
1817  ANCKB = val; // Test
1818  xferInfo.acANCBuffer.Allocate(ANCKB*1024); // Test
1819  if (isInterlaced) // Test
1820  xferInfo.acANCField2Buffer.Allocate(ANCKB*1024); // Test
1821  } // Test
1822 #endif // defined(NTV2_ANC_TEST) // Test
1823  } // loop til quit signaled
1824 
1825  // Stop AutoCirculate...
1826  mDevice.AutoCirculateStop (mConfig.fOutputChannel);
1827 
1828  // Flush encoder queues (prevent Quit from hanging)...
1829  while(m608Encoder->GetQueuedByteCount(NTV2_CC608_Field1) || m608Encoder->GetQueuedByteCount(NTV2_CC608_Field2))
1830  {m608Encoder->Flush(NTV2_CC608_Field1); m608Encoder->Flush(NTV2_CC608_Field2);}
1831  PLNOTE("Playout thread exit");
1832 
1833 } // PlayoutFrames
1834 
1835 
1836 void NTV2CCPlayer::GetStatus ( size_t & outMessagesQueued, size_t & outBytesQueued,
1837  size_t & outTotMsgsEnq, size_t & outTotBytesEnq,
1838  size_t & outTotMsgsDeq, size_t & outTotBytesDeq,
1839  size_t & outMaxQueDepth, size_t & outDroppedFrames) const
1840 {
1842  if (m608Encoder)
1843  {
1844  outMessagesQueued = m608Encoder->GetQueuedMessageCount();
1845  outBytesQueued = m608Encoder->GetQueuedByteCount();
1846  outTotMsgsEnq = m608Encoder->GetEnqueueMessageTally();
1847  outTotBytesEnq = m608Encoder->GetEnqueueByteTally();
1848  outTotMsgsDeq = m608Encoder->GetDequeueMessageTally();
1849  outTotBytesDeq = m608Encoder->GetDequeueByteTally();
1850  outMaxQueDepth = m608Encoder->GetHighestQueueDepth();
1851  }
1852  else
1853  outMessagesQueued = outBytesQueued = outTotMsgsEnq = outTotBytesEnq = outTotMsgsDeq = outTotBytesDeq = outMaxQueDepth = 0;
1854  outDroppedFrames = size_t(mACStatus.GetDroppedFrameCount());
1855 
1856 } // GetStatus
virtual AJAStatus Init(void)
Initializes me and prepares me to Run.
#define NTV2_IS_SD_VIDEO_FORMAT(__f__)
Definition: ntv2enums.h:746
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.
NTV2Buffer acOutputTimeCodes
Intended for playout, this is an ordered sequence of NTV2_RP188 values to send to the device...
NTV2FrameRate GetNTV2FrameRateFromVideoFormat(const NTV2VideoFormat inVideoFormat)
Definition: ntv2utils.cpp:3630
#define IsLine21RollUpMode(_mode_)
virtual bool SetTaskMode(const NTV2TaskMode inMode)
Sets the device&#39;s task mode.
UByte f2_char1
Caption Byte 1 of Field 2.
virtual bool EnqueueCCDataToFrame(CNTV2CaptionEncoder608Ptr inEncoder, const uint32_t inFrameNum)
Enqueues next-available CC data into the given encoder for the given frame number.
virtual AJAStatus GetTransmitData(NTV2Buffer &F1Buffer, NTV2Buffer &F2Buffer, const bool inIsProgressive=true, const uint32_t inF2StartLine=0)
Encodes my AJAAncillaryData packets into the given buffers in the default SDI Anc Buffer Data Format ...
bool fSuppress608
If true, don&#39;t transmit CEA608 packets; otherwise include 608 packets.
Definition: ntv2ccplayer.h:85
T Next(void)
static void PlayThreadStatic(AJAThread *pThread, void *pContext)
This is the playout thread&#39;s static callback function that gets called when the playout thread runs...
I am an object that can inject text captions into an SDI output of an AJA device in real time...
Definition: ntv2ccplayer.h:125
NTV2AudioSystem
Used to identify an Audio System on an NTV2 device. See Audio System Operation for more information...
Definition: ntv2enums.h:3898
bool setVANCToLegalBlack(void) const
Declares a number of pixel format transcoder functions.
bool fSuppressAudio
If true, suppress audio; otherwise generate & xfer audio tone.
bool Allocate(const size_t inByteCount, const bool inPageAligned=false)
Allocates (or re-allocates) my user-space storage using the given byte count. I assume full responsib...
Declares common types used in the ajabase library.
virtual bool IsF1Channel(void) const
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
bool firstFieldTop
True if the first field on the wire is the top-most field in the raster (field dominance) ...
Definition: ntv2utils.h:882
UByte f1_char2
Caption Byte 2 of Field 1.
Specifies the device&#39;s internal clock.
Definition: ntv2enums.h:1462
virtual bool SetReference(const NTV2ReferenceSource inRefSource, const bool inKeepFramePulseSelect=(0))
Sets the device&#39;s clock reference source. See Video Output Clocking & Synchronization for more inform...
virtual bool ReleaseStreamForApplication(ULWord inApplicationType, int32_t inProcessID)
Releases exclusive use of the AJA device for the given process, permitting other processes to acquire...
bool Is8BitFrameBufferFormat(const NTV2FrameBufferFormat fbFormat)
Definition: ntv2utils.cpp:5455
CaptionChanGenMap::const_iterator CaptionChanGenMapCIter
Definition: ntv2ccplayer.h:73
virtual string GetNextCaptionWord(bool &outLineBreak)
ULWord GetBytesPerRow(const UWord inPlaneIndex0=0) const
The NTV2 test pattern generator.
virtual size_t GetEnqueueByteTally(void) const
Returns the total number of bytes (including command bytes) that have been enqueued onto me since I w...
static const double gAmplitudes[]
virtual void Flush(const NTV2Line21Field inFieldNum=NTV2_CC608_Field1, const bool inAlsoInProgress=true)
Flushes all queued command bytes for the given CC608 field.
#define BIT(_x_)
Definition: ajatypes.h:596
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.
virtual bool Erase(const NTV2Line21Channel inChannel=NTV2_CC608_CC1)
Clears captions on the given channel by emitting ENM (Erase Non-displayed Memory) and EOC (End Of Cap...
enum _AtEndAction_ AtEndAction
These are the actions that can be taken after the last file is "played".
virtual bool Set4kSquaresEnable(const bool inIsEnabled, const NTV2Channel inChannel)
Enables or disables SMPTE 425 "2K quadrants" mode for the given FrameStore bank on the device...
AJAStatus
Definition: types.h:380
Ancillary data found between SAV and EAV (.
virtual void Quit(const bool inQuitImmediately=(0))
Stops me.
NTV2VANCMode fVancMode
VANC mode to use.
See 10-Bit YCbCr Format.
Definition: ntv2enums.h:224
virtual size_t GetQueuedByteCount(const NTV2Line21Field inFieldNum=NTV2_CC608_Field1) const
Answers with the total number of bytes (including command bytes) that are currently queued (for the g...
NTV2Line21Channel fCaptionChannel
The caption channel to use.
Definition: ntv2ccplayer.h:49
UByte f1_char1
Caption Byte 1 of Field 1.
std::string NTV2OutputDestinationToString(const NTV2OutputDestination inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:7065
virtual bool IsDeviceReady(const bool inCheckValid=(0))
bool GetLineOffsetFromSMPTELine(const ULWord inSMPTELine, ULWord &outLineOffset) const
Answers with the equivalent line offset into the raster I describe for the given SMPTE line number...
size_t GetByteCount(void) const
2-row roll-up from bottom
virtual void SetCaptionChannel(const NTV2Line21Channel inCCChannel)
Sets my caption channel.
Used to describe Start of Active Video (SAV) location and field dominance for a given NTV2Standard...
Definition: ntv2utils.h:878
bool ConvertLine_2vuy_to_v210(const UByte *pInSrcLine_2vuy, ULWord *pOutDstLine_v210, const ULWord inNumPixels)
Converts a single 8-bit YCbCr &#39;2vuy&#39; raster line to 10-bit YCbCr &#39;v210&#39; (from NTV2_FBF_8BIT_YCBCR to ...
static uint64_t GetPid()
Definition: process.cpp:35
NTV2StringList::const_iterator NTV2StringListConstIter
#define AJA_FAILURE(_status_)
Definition: types.h:373
#define PLINFO(_xpr_)
Declares the NTV2TestPatternGen class.
static NTV2ChannelList GetTSIMuxesForFrameStore(CNTV2Card &inDevice, const NTV2Channel in1stFrameStore, const UWord inCount)
ULWord GetFullRasterHeight(void) const
Pop-on caption mode.
UByte f2_char2
Caption Byte 2 of Field 2.
std::vector< AJALabelValuePair > AJALabelValuePairs
An ordered sequence of label/value pairs.
Definition: info.h:71
Configures an NTV2CCPlayer instance.
Definition: ntv2ccplayer.h:80
NTV2InputXptID GetDLOutInputXptFromChannel(const NTV2Channel inDLOutWidget)
#define NTV2_IS_4K_VIDEO_FORMAT(__f__)
Definition: ntv2enums.h:785
Declares the AJATime class.
virtual AJAStatus SetPriority(AJAThreadPriority priority)
Definition: thread.cpp:133
Analog LTC 2.
Definition: ntv2enums.h:3964
static uint64_t GetSystemMilliseconds(void)
Returns the current value of the host&#39;s high-resolution clock, in milliseconds.
Definition: systemtime.cpp:206
NTV2OutputXptID GetTSIMuxOutputXptFromChannel(const NTV2Channel inTSIMuxer, const bool inLinkB=false, const bool inIsRGB=false)
virtual bool EnqueueTextMessage(const std::string &inMessageStr, const bool inEraseFirst=false, const NTV2Line21Channel inChannel=NTV2_CC608_Text1)
Enqueues the given message for eventual reception and possible display on a receiver capable of displ...
#define NTV2_FOURCC(_a_, _b_, _c_, _d_)
#define NTV2_IS_VANCMODE_OFF(__v__)
Definition: ntv2enums.h:3812
SCCSource(const double inCharsPerMinute, istream *pInInputStream, const string &inFilePath, const bool inDeleteInputStream=(0))
if(!(riid==IID_IUnknown) &&!(riid==IID_IClassFactory))
Definition: dllentry.cpp:196
virtual AJAStatus GeneratePayloadData(void)
Generate the payload data from my "local" ancillary data.
static void SignalHandler(int inSignal)
Definition: main.cpp:23
I am a reference-counted pointer template class. I am intended to be a proxy for an underlying object...
Definition: ajarefptr.h:89
Declares the AJAAncillaryData_Cea608_Vanc class.
bool CanAcceptMoreOutputFrames(void) const
virtual void StartCaptionGeneratorThreads(void)
Starts my caption generator threads.
The "default" timecode (mostly used by the AJA "Retail" service and Control Panel) ...
Definition: ntv2enums.h:3956
bool SetOutputTimeCode(const NTV2_RP188 &inTimecode, const NTV2TCIndex inTCIndex=NTV2_TCINDEX_SDI1)
Intended for playout, sets one element of my acOutputTimeCodes member.
bool fSuppress708
If true, don&#39;t transmit CEA708 packets; otherwise include 708 packets.
Definition: ntv2ccplayer.h:86
This identifies the mode in which there are some + extra VANC lines in the frame buffer.
Definition: ntv2enums.h:3804
Defines the AJARefPtr template class.
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 RouteOutputSignal(void)
Sets up signal routing for playout.
virtual AJAStatus Start()
Definition: thread.cpp:91
CapGenStartInfo(NTV2CCPlayer *pPlayer, const NTV2Line21Channel inCapChan)
Fractional rate of 60,000 frames per 1,001 seconds.
Definition: ntv2enums.h:419
AJALabelValuePairs::const_iterator AJALabelValuePairsConstIter
Definition: info.h:72
#define NTV2_IS_HFR_STANDARD(__s__)
Definition: ntv2enums.h:215
std::string fDeviceSpec
The AJA device to use.
#define false
std::ostream & operator<<(std::ostream &ioStrm, const CCPlayerConfig &inObj)
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 AJAStatus SetUpOutputVideo(void)
Sets up everything I need to play video.
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.
AJARefPtr< CaptionSource > CaptionSourcePtr
NTV2OutputXptID GetDLOutOutputXptFromChannel(const NTV2Channel inDLOutput, const bool inIsLinkB=false)
NTV2Channel
These enum values are mostly used to identify a specific widget_framestore. They&#39;re also commonly use...
Definition: ntv2enums.h:1359
ULWord GetLastLine(const NTV2FieldID inRasterFieldID=NTV2_FIELD0) const
#define AJAAncDataHorizOffset_AnyVanc
VANC – Packet placed/found in any legal area of raster line after SAV, but before EAV...
static bool Create(CNTV2CaptionEncoder708Ptr &outEncoder)
Creates a new CNTV2CaptionEncoder708 instance.
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 SetHDMIOutAudioChannels(const NTV2HDMIAudioChannels inNewValue, const NTV2Channel inWhichHDMIOut=NTV2_CHANNEL1)
Sets the audio channel count to use for the given HDMI output.
Definition: ntv2audio.cpp:847
bool IsProgressivePicture(const NTV2VideoFormat format)
Definition: ntv2utils.cpp:5394
ULWord GetProcessedFrameCount(void) const
virtual AJAStatus SetLocationLineNumber(const uint16_t inLineNum)
Sets my ancillary data "location" frame line number.
#define NTV2_ASSERT(_expr_)
Definition: ajatypes.h:489
Defines where the ancillary data can be found within a video stream.
Represents an unknown or invalid frame rate.
Definition: ntv2enums.h:416
NTV2AutoCirculateState acState
Current AutoCirculate state after the transfer.
This struct replaces the old RP188_STRUCT.
bool fSuppressLine21
SD output only: if true, do not encode Line 21 waveform; otherwise encode Line 21 waveform...
Definition: ntv2ccplayer.h:84
#define IsLine21CaptionChannel(_chan_)
A handy class that makes it easy to "bounce" an unsigned integer value between a minimum and maximum ...
50 frames per second
Definition: ntv2enums.h:425
NTV2TCIndex NTV2ChannelToTimecodeIndex(const NTV2Channel inChannel, const bool inEmbeddedLTC=false, const bool inIsF2=false)
Converts the given NTV2Channel value into the equivalent NTV2TCIndex value.
Definition: ntv2utils.cpp:4965
unsigned long stoul(const std::string &str, std::size_t *idx, int base)
Definition: common.cpp:143
NTV2ChannelList NTV2MakeChannelList(const NTV2Channel inFirstChannel, const UWord inNumChannels=1)
virtual bool Active()
Definition: thread.cpp:116
virtual size_t GetSMPTE334Size(void) const
bool Fill(const T &inValue)
Fills me with the given scalar value.
virtual bool GetTaskMode(NTV2TaskMode &outMode)
Retrieves the device&#39;s current task mode.
#define SIG_AJA_STOP
Definition: ntv2ccplayer.h:21
const std::string & NTV2Line21ModeToStr(const NTV2Line21Mode inLine21Mode)
Converts the given NTV2Line21Mode value into a human-readable string.
This selects audio channels 1 thru 8.
Definition: ntv2enums.h:3325
NTV2Channel NTV2OutputDestinationToChannel(const NTV2OutputDestination inOutputDest)
Converts a given NTV2OutputDestination to its equivalent NTV2Channel value.
Definition: ntv2utils.cpp:5158
virtual const UWord * GetSMPTE334Data(void) const
Repeat the file list (must Ctrl-C to terminate)
Definition: ntv2ccplayer.h:31
NTV2FrameRate
Identifies a particular video frame rate.
Definition: ntv2enums.h:414
Analog LTC 1.
Definition: ntv2enums.h:3963
static const string gBuiltInCaptions("IN CONGRESS, July 4, 1776.\ "The unanimous Declaration of the thirteen united States of America.\" "When in the Course of human events, it becomes necessary for one people to dissolve the political bands which have connected them with another, " "and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature 's God entitle them, a decent " "respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.\" "We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, " "that among these are Life, Liberty and the pursuit of Happiness. That to secure these rights, Governments are instituted among Men, deriving their " "just powers from the consent of the governed, That whenever any Form of Government becomes destructive of these ends, it is the Right of the People to alter or to abolish it, " "and to institute new Government, laying its foundation on such principles and organizing its powers in such form, as to them shall seem most likely to effect their Safety and " "Happiness. Prudence, indeed, will dictate that Governments long established should not be changed for light and transient causes;and accordingly all experience hath shewn, " "that mankind are more disposed to suffer, while evils are sufferable, than to right themselves by abolishing the forms to which they are accustomed. " "But when a long train of abuses and usurpations, pursuing invariably the same Object evinces a design to reduce them under absolute Despotism, it is their right, " "it is their duty, to throw off such Government, and to provide new Guards for their future security. Such has been the patient sufferance of these Colonies;and such is now " "the necessity which constrains them to alter their former Systems of Government. The history of the present King of Great Britain is a history of repeated injuries and " "usurpations, all having in direct object the establishment of an absolute Tyranny over these States. To prove this, let Facts be submitted to a candid world.\" "He has refused his Assent to Laws, the most wholesome and necessary for the public good.\" "He has forbidden his Governors to pass Laws of immediate and pressing importance, unless suspended in their operation till his Assent should be obtained;" "and when so suspended, he has utterly neglected to attend to them.\" "He has refused to pass other Laws for the accommodation of large districts of people, unless those people would relinquish the right of Representation in the Legislature, " "a right inestimable to them and formidable to tyrants only.\" "He has called together legislative bodies at places unusual, uncomfortable, and distant from the depository of their public Records, for the sole purpose of fatiguing them " "into compliance with his measures. \" "He has dissolved Representative Houses repeatedly, for opposing with manly firmness his invasions on the rights of the people.\" "He has refused for a long time, after such dissolutions, to cause others to be elected;whereby the Legislative powers, incapable of Annihilation, have returned to the People " "at large for their exercise;the State remaining in the mean time exposed to all the dangers of invasion from without, and convulsions within.\" "He has endeavoured to prevent the population of these States;for that purpose obstructing the Laws for Naturalization of Foreigners;refusing to pass others to encourage " "their migrations hither, and raising the conditions of new Appropriations of Lands.\" "He has obstructed the Administration of Justice, by refusing his Assent to Laws for establishing Judiciary powers.\" "He has made Judges dependent on his Will alone, for the tenure of their offices, and the amount and payment of their salaries.\" "He has erected a multitude of New Offices, and sent hither swarms of Officers to harrass our people, and eat out their substance.\" "He has kept among us, in times of peace, Standing Armies without the Consent of our legislatures.\" "He has affected to render the Military independent of and superior to the Civil power.\" "He has combined with others to subject us to a jurisdiction foreign to our constitution, and unacknowledged by our laws;" "giving his Assent to their Acts of pretended Legislation:\" "For Quartering large bodies of armed troops among us:\" "For protecting them, by a mock Trial, from punishment for any Murders which they should commit on the Inhabitants of these States:\" "For cutting off our Trade with all parts of the world:\" "For imposing Taxes on us without our Consent:\" "For depriving us in many cases, of the benefits of Trial by Jury:\" "For transporting us beyond Seas to be tried for pretended offences.\" "For abolishing the free System of English Laws in a neighbouring Province, establishing therein an Arbitrary government, and enlarging its Boundaries so as to render it at " "once an example and fit instrument for introducing the same absolute rule into these Colonies:\" "For taking away our Charters, abolishing our most valuable Laws, and altering fundamentally the Forms of our Governments:\" "For suspending our own Legislatures, and declaring themselves invested with power to legislate for us in all cases whatsoever.\" "He has abdicated Government here, by declaring us out of his Protection and waging War against us.\" "He has plundered our seas, ravaged our Coasts, burnt our towns, and destroyed the lives of our people.\" "He is at this time transporting large Armies of foreign Mercenaries to compleat the works of death, desolation and tyranny, already begun with circumstances of Cruelty &" "perfidy scarcely paralleled in the most barbarous ages, and totally unworthy the Head of a civilized nation.\" "He has constrained our fellow Citizens taken Captive on the high Seas to bear Arms against their Country, to become the executioners of their friends and Brethren, " "or to fall themselves by their Hands.\" "He has excited domestic insurrections amongst us, and has endeavoured to bring on the inhabitants of our frontiers, the merciless Indian Savages, whose known rule of warfare, " "is an undistinguished destruction of all ages, sexes and conditions.\" "In every stage of these Oppressions We have Petitioned for Redress in the most humble terms:Our repeated Petitions have been answered only by repeated injury. " "A Prince whose character is thus marked by every act which may define a Tyrant, is unfit to be the ruler of a free people.\" "Nor have We been wanting in attentions to our Brittish brethren. We have warned them from time to time of attempts by their legislature to extend an unwarrantable " "jurisdiction over us. We have reminded them of the circumstances of our emigration and settlement here. We have appealed to their native justice and magnanimity, " "and we have conjured them by the ties of our common kindred to disavow these usurpations, which, would inevitably interrupt our connections and correspondence. " "They too have been deaf to the voice of justice and of consanguinity. We must, therefore, acquiesce in the necessity, which denounces our Separation, and hold them, " "as we hold the rest of mankind, Enemies in War, in Peace Friends.\" "We, therefore, the Representatives of the united States of America, in General Congress, Assembled, appealing to the Supreme Judge of the world for the rectitude of " "our intentions, do, in the Name, and by Authority of the good People of these Colonies, solemnly publish and declare, That these United Colonies are, and of Right ought " "to be Free and Independent States;that they are Absolved from all Allegiance to the British Crown, and that all political connection between them and the State of Great " "Britain, is and ought to be totally dissolved;and that as Free and Independent States, they have full Power to levy War, conclude Peace, contract Alliances, establish " "Commerce, and to do all other Acts and Things which Independent States may of right do. And for the support of this Declaration, with a firm reliance on the protection of " "divine Providence, we mutually pledge to each other our Lives, our Fortunes and our sacred Honor.")
Some default text to use if standard input isn&#39;t used.
virtual bool DrawTestPattern(const std::string &inTPName, const NTV2FormatDescriptor &inFormatDesc, NTV2Buffer &inBuffer)
Renders the given test pattern or color into a host raster buffer.
virtual bool EnableChannels(const NTV2ChannelSet &inChannels, const bool inDisableOthers=(0))
Enables the given FrameStore(s).
0: Disabled (never recommended): device configured exclusively by client application(s).
virtual std::string GetDescription(void) const
Definition: ntv2card.cpp:139
virtual NTV2Line21Channel GetCaptionChannel(void) const
void * GetWriteableRowAddress(void *pInStartAddress, const ULWord inRowIndex0, const UWord inPlaneIndex0=0) const
bool CanDoOutputDestination(const NTV2OutputDestination inDest)
static TimecodeFormat NTV2FrameRate2TimecodeFormat(const NTV2FrameRate inFrameRate)
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...
std::string to_string(bool val)
Definition: common.cpp:180
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 string GetNextCaptionCharacter(void)
bool bGotField2Data
True if Field 2 bytes have been set; otherwise false.
virtual bool SetSDITransmitEnable(const NTV2Channel inChannel, const bool inEnable)
Sets the specified bidirectional SDI connector to act as an input or an output.
static bool BurnString(const std::string &inString, const NTV2Line21Attrs &inAttribs, NTV2Buffer &inFB, const NTV2FormatDesc &inFBDescriptor, const UWord inRowNum=15, const UWord inColumnNum=1)
Blits the contents of the given UTF-8 encoded string into the given host buffer using the given displ...
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 ...
CEA-608 Character Attributes.
Utility class for timecodes.
Definition: timecode.h:28
Identifies the last (second) field in time for an interlaced video frame.
Definition: ntv2enums.h:1846
void SetHmsf(uint32_t h, uint32_t m, uint32_t s, uint32_t f, const AJATimeBase &timeBase, bool bDropFrame, bool bStdTcForHfr, uint32_t addFrame)
Definition: timecode.cpp:425
#define AJA_NULL
Definition: ajatypes.h:180
virtual std::string GetDisplayName(void)
Answers with this device&#39;s display name.
Definition: ntv2card.cpp:88
Instances of me can encode two ASCII characters into a "line 21" closed-captioning waveform...
Declares the CRP188 class. See SMPTE RP188 standard for details.
NTV2InputXptID GetCSCInputXptFromChannel(const NTV2Channel inCSC, const bool inIsKeyInput=false)
virtual AJAStatus Run(void)
Runs me.
Describes a video frame for a given video standard or format and pixel format, including the total nu...
virtual AJAStatus SetCEA608Bytes(const uint8_t inByte1, const uint8_t inByte2)
Set the CEA608 payload bytes.
static void Sleep(const int32_t inMilliseconds)
Suspends execution of the current thread for a given number of milliseconds.
Definition: systemtime.cpp:284
void split(const std::string &str, const char delim, std::vector< std::string > &elems)
Definition: common.cpp:350
NTV2PixelFormat fPixelFormat
The pixel format to use.
T Value(void) const
NTV2Line21Channel fCapChannel
2: OEM (recommended): device configured by client application(s) with some driver involvement...
#define IsLine21TextChannel(_chan_)
virtual void GetStatus(size_t &outMessagesQueued, size_t &outBytesQueued, size_t &outTotMsgsEnq, size_t &outTotBytesEnq, size_t &outTotMsgsDeq, size_t &outTotBytesDeq, size_t &outMaxQueDepth, size_t &outDroppedFrames) const
Returns status information from my caption encoder.
The ancillary data is associated with the luminance (Y) channel of the video stream.
bool bGotField1Data
True if Field 1 bytes have been set; otherwise false.
virtual bool IsPlainTextSource(void) const
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.
CaptionChanGenMap fCapChanGenConfigs
Caption channel generator configs.
Definition: ntv2ccplayer.h:90
This class handles CEA-708 SMPTE 334 packets.
virtual AJAStatus AddAncillaryData(const AJAAncillaryList &inPackets)
Appends a copy of the given list&#39;s packets to me.
virtual bool ApplySignalRoute(const CNTV2SignalRouter &inRouter, const bool inReplace=(0))
Applies the given routing table to the AJA device.
virtual bool SetSDIOutputAudioSystem(const NTV2Channel inSDIOutputConnector, const NTV2AudioSystem inAudioSystem)
Sets the device&#39;s NTV2AudioSystem that will provide audio for the given SDI output&#39;s audio embedder...
#define PLNOTE(_xpr_)
#define AsSCCSource(__x__)
NTV2VideoFormat fVideoFormat
The video format to use.
std::string NTV2VideoFormatToString(const NTV2VideoFormat inValue, const bool inUseFrameRate=false)
Definition: ntv2utils.cpp:6749
static const uint32_t kAppSignature(((((uint32_t)( 'C'))<< 24)|(((uint32_t)( 'C'))<< 16)|(((uint32_t)( 'P'))<< 8)|(((uint32_t)( 'L'))<< 0)))
static std::string Utf8ToCEA608String(const std::string &inUtf8Str, const NTV2Line21Channel inChannel=NTV2_CC608_CC1)
Converts the given UTF8-encoded string into a string that can be used in the CNTV2CaptionEncoder608&#39;s...
Embeds silence (zeroes) into the data stream.
Definition: ntv2enums.h:2033
virtual bool SetVANCShiftMode(NTV2Channel inChannel, NTV2VANCDataShiftMode inMode)
Enables or disables the "VANC Shift Mode" feature for the given channel.
Declares the CNTV2CaptionRenderer class.
virtual bool GetNextCaptionData(CaptionData &outCaptionData)
This high-level method is used to dequeue caption data for an entire frame.
ULWord GetDroppedFrameCount(void) const
virtual bool SetTsiFrameEnable(const bool inIsEnabled, const NTV2Channel inChannel)
Enables or disables SMPTE 425 two-sample interleave (Tsi) frame mode on the device.
virtual bool RemoveConnections(const NTV2XptConnections &inConnections)
Removes the given widget routing connections from the AJA device.
virtual void SetFinished(void)
Sets my "finished" flag.
virtual void StartPlayoutThread(void)
Starts my playout thread.
virtual bool EnqueueCaptionData(const CaptionData &inCaptionData)
This is a low-level method that enqueues the given CaptionData for eventual transmission.
Specifies the PTP source on SFP 1.
Definition: ntv2enums.h:1471
This class handles VANC-based CEA-608 caption data packets (not "analog" Line 21).
virtual AJAStatus GetVANCTransmitData(NTV2Buffer &inFrameBuffer, const NTV2FormatDescriptor &inFormatDesc)
Writes my AJAAncillaryData objects into the given tall/taller frame buffer having the given raster/fo...
bool fDoRGBOnWire
If true, produce RGB on the wire; otherwise output YUV.
#define AUTOCIRCULATE_WITH_ANC
Use this to AutoCirculate with ancillary data.
virtual string GetNextCaptionCharacter(void)
Returns the next character read from my input stream. If my text input stream has reached EOF...
virtual ~SCCSource()
uint8_t UByte
Definition: ajatypes.h:231
virtual bool Set608CaptionData(const CaptionData &inCC608Data)
Sets the CEA-608 caption data in my private 608 data buffer.
NTV2OutputDest fOutputDest
The desired output connector to use.
virtual string GetNextCaptionRow(const bool inBreakLinesOnNewLineChars=(0))
Returns the next "sentence" read from my input stream. I build the "sentence" by reading "words" usin...
virtual size_t GetEnqueueMessageTally(void) const
Returns the total number of messages that have been enqueued onto me since I was instantiated.
3-row roll-up from bottom
virtual AJAStatus SetDIDSID(const AJAAncDIDSIDPair &inDIDSID)
Sets both my Data ID (DID) and Secondary Data ID (SID).
This class is used to configure a caption generator for a single caption channel. ...
Definition: ntv2ccplayer.h:43
#define NTV2_IS_VANCMODE_ON(__v__)
Definition: ntv2enums.h:3811
Declares the CNTV2DeviceScanner class.
virtual bool ReadRegister(const ULWord inRegNum, ULWord &outValue, const ULWord inMask=0xFFFFFFFF, const ULWord inShift=0)
Reads all or part of the 32-bit contents of a specific register (real or virtual) on the AJA device...
#define NTV2_IS_625_FORMAT(__f__)
Definition: ntv2enums.h:916
#define NTV2_OUTPUT_DEST_IS_SDI(_dest_)
Definition: ntv2enums.h:1348
virtual size_t GetDequeueMessageTally(void) const
Returns the total number of messages that have been dequeued from me since I was instantiated.
virtual AJAStatus SetDataLocation(const AJAAncDataLoc &inLoc)
Sets my ancillary data "location" within the video stream.
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
static CaptionSourceList GetCaptionSources(const NTV2StringList &inFilesToPlay, const double inCharsPerMinute)
Creates and returns a list of CaptionSource instances to play from a given list of paths to text file...
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_)
std::map< NTV2TCIndex, NTV2_RP188 > NTV2TimeCodes
A mapping of NTV2TCIndex enum values to NTV2_RP188 structures.
bool fDoMultiFormat
If true, enable device-sharing; otherwise take exclusive control of device.
bool IsRGBFormat(const NTV2FrameBufferFormat format)
Definition: ntv2utils.cpp:5413
#define IsValidLine21Channel(_chan_)
This object specifies the information that will be transferred to or from the AJA device in the CNTV2...
std::string & strip(std::string &str, const std::string &ws)
Definition: common.cpp:461
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
NTV2CCPlayer * fpPlayer
bool fEmitStats
If true, show stats while playing; otherwise echo caption text being played.
Definition: ntv2ccplayer.h:83
Declares the AJATimeCode class.
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__)
NTV2InputXptID GetTSIMuxInputXptFromChannel(const NTV2Channel inTSIMuxer, const bool inLinkB=false)
virtual ~CaptionSource()
My destructor. If was told at construction time that I was to be responsible for deleting the input s...
bool fDoTsiRouting
If true, enable TSI routing; otherwise route for square division (4K/8K)
CaptionSourceList::const_iterator CaptionSourceListConstIter
NTV2Buffer acANCField2Buffer
The host "Field 2" ancillary data buffer. This field is owned by the client application, and thus is responsible for allocating and/or freeing it. If the pointer is NULL or the size is zero, no "Field 2" ancillary data will be transferred. Use the AUTOCIRCULATE_TRANSFER::SetAncBuffers method to set or reset this field.
std::set< NTV2Channel > NTV2ChannelSet
A set of distinct NTV2Channel values.
This identifies the first Audio System.
Definition: ntv2enums.h:3900
virtual bool EnqueuePaintOnMessage(const std::string &inMessageStr, const bool inEraseFirst=false, const NTV2Line21Channel inChannel=NTV2_CC608_CC1, const UWord inRowNumber=0, const UWord inColumnNumber=0, const NTV2Line21Attrs &inDisplayAttribs=NTV2Line21Attrs())
Enqueues the given message for eventual "paint-on" display.
#define AJA_RETAIL_DEFAULT
Definition: ntv2card.h:592
virtual bool WaitForOutputVerticalInterrupt(const NTV2Channel inChannel=NTV2_CHANNEL1, UWord inRepeatCount=1)
Efficiently sleeps the calling thread/process until the next one or more field (interlaced video) or ...
virtual size_t GetQueuedMessageCount(const NTV2Line21Field inFieldNum=NTV2_CC608_Field1) const
Answers with the current depth of my queue (for the given CC608 field).
virtual UByte * EncodeLine(const UByte inByte1, const UByte inByte2)
Encodes the two given characters as an EIA-608-compliant "line 21" waveform into my private line data...
NTV2SmpteLineNumber GetSmpteLineNumber(const NTV2Standard inStandard)
For the given video standard, returns the SMPTE-designated line numbers for Field 1 and Field 2 that ...
Definition: ntv2utils.h:964
Declares the constants used for sharing debug messages. These structures are used to gather debug mes...
#define NTV2_IS_QUAD_FRAME_FORMAT(__f__)
Definition: ntv2enums.h:814
NTV2Channel fOutputChannel
The device channel to use.
deque< CaptionSourcePtr > CaptionSourceList
I am an ordered sequence of CaptionSources.
Declares numerous NTV2 utility functions.
std::pair< uint8_t, uint8_t > AJAAncDIDSIDPair
Definition: ancillarydata.h:27
static void CaptionGeneratorThreadStatic(AJAThread *pThread, void *pContext)
This is the caption generator thread&#39;s static callback function that gets called when the caption gen...
virtual AJAStatus Attach(AJAThreadFunction *pThreadFunction, void *pUserContext)
Definition: thread.cpp:169
virtual bool DeviceAncExtractorIsAvailable(void)
bool Set(const void *pInUserPointer, const size_t inByteCount)
Sets (or resets) me from a client-supplied address and size.
virtual bool SetSDIOutRGBLevelAConversion(const UWord inOutputSpigot, const bool inEnable)
Enables or disables an RGB-over-3G-level-A conversion at the SDI output widget (assuming the AJA devi...
#define IsField1Line21CaptionChannel(_chan_)
The ancillary data is associated with Link A of the video stream.
Definition: ancillarydata.h:81
static bool Create(CNTV2CaptionEncoder608Ptr &outEncoder)
Creates a new CNTV2CaptionEncoder608 instance.
This structure encapsulates all possible CEA-608 caption data bytes that may be associated with a giv...
#define NTV2_IS_QUAD_QUAD_FORMAT(__f__)
Definition: ntv2enums.h:821
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...
virtual bool SetHDMIOutAudioSource8Channel(const NTV2Audio8ChannelSelect inNewValue, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_1, const NTV2Channel inWhichHDMIOut=NTV2_CHANNEL1)
Changes the HDMI output&#39;s 8-channel audio source.
Definition: ntv2audio.cpp:936
NTV2OutputXptID GetFrameStoreOutputXptFromChannel(const NTV2Channel inFrameStore, const bool inIsRGB=false, const bool inIs425=false)
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
virtual bool WriteRegister(const ULWord inRegNum, const ULWord inValue, const ULWord inMask=0xFFFFFFFF, const ULWord inShift=0)
Updates or replaces all or part of the 32-bit contents of a specific register (real or virtual) on th...
ULWord GetRasterWidth(void) const
virtual AJAStatus SetPayloadData(const uint8_t *pInData, const uint32_t inByteCount)
Copy data from external memory into my local payload memory.
Specifies channel or FrameStore 1 (or the first item).
Definition: ntv2enums.h:1361
virtual bool AutoCirculateStart(const NTV2Channel inChannel, const ULWord64 inStartTime=0)
Starts AutoCirculating the specified channel that was previously initialized by CNTV2Card::AutoCircul...
UWord GetNumHDMIAudioOutputChannels(void)
virtual AJAStatus GetIPTransmitData(NTV2Buffer &F1Buffer, NTV2Buffer &F2Buffer, const bool inIsProgressive=true, const uint32_t inF2StartLine=0)
Explicitly encodes my AJAAncillaryData packets into the given buffers in RTP Anc Buffer Data Format ...
4-row roll-up from bottom
virtual size_t GetDequeueByteTally(void) const
Returns the total number of bytes (including command bytes) that have been dequeued from me since I w...
AUTOCIRCULATE_TRANSFER_STATUS acTransferStatus
Contains status information that&#39;s valid after CNTV2Card::AutoCirculateTransfer returns, including the driver buffer level, number of frames processed or dropped, audio and anc transfer byte counts, and a complete FRAME_STAMP that has even more detailed clocking information.
bool CanDoFrameBufferFormat(const NTV2PixelFormat inPF)
virtual bool SubscribeOutputVerticalEvent(const NTV2Channel inChannel)
Causes me to be notified when an output vertical blanking interrupt is generated for the given output...
virtual bool AutoCirculateInitForOutput(const NTV2Channel inChannel, const UWord inFrameCount=7, const NTV2AudioSystem inAudioSystem=NTV2_AUDIOSYSTEM_INVALID, const ULWord inOptionFlags=0, const UByte inNumChannels=1, const UWord inStartFrameNumber=0, const UWord inEndFrameNumber=0)
Prepares for subsequent AutoCirculate playout, designating a contiguous block of frame buffers on the...
#define xHEX0N(__x__, __n__)
25 frames per second
Definition: ntv2enums.h:422
const std::string & NTV2Line21ChannelToStr(const NTV2Line21Channel inLine21Channel, const bool inCompact=true)
Converts the given NTV2Line21Channel value into a human-readable string.
TimecodeFormat
Definition: ntv2rp188.h:22
CaptionSource(const double inCharsPerMinute, istream *pInInputStream, const string &inFilePath, const bool inDeleteInputStream=(0))
My only constructor.
virtual bool GetFrameRate(NTV2FrameRate &outValue, NTV2Channel inChannel=NTV2_CHANNEL1)
Returns the AJA device&#39;s currently configured frame rate via its "value" parameter.
std::string NTV2FrameBufferFormatToString(const NTV2FrameBufferFormat inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:6939
virtual void PlayoutFrames(void)
Repeatedly plays frames (until time to quit).
static AJA_FrameRate GetAJAFrameRate(const NTV2FrameRate inFrameRate)
virtual size_t GetHighestQueueDepth(void) const
Returns the highest queue depth – i.e., the maximum number of messages I held in either of my queues...
virtual string GetNextCaptionWord(bool &outLineBreak)
Returns the next "word" read from my input stream. If my text input stream has reached EOF...
virtual ~NTV2CCPlayer(void)
bool fSuppressTimecode
If true, suppress timecode; otherwise embed VITC/LTC.
Definition: ntv2ccplayer.h:87
NTV2AudioSystem NTV2ChannelToAudioSystem(const NTV2Channel inChannel)
Converts the given NTV2Channel value into its equivalent NTV2AudioSystem.
Definition: ntv2utils.cpp:4872
Specifies channel or FrameStore 4 (or the 4th item).
Definition: ntv2enums.h:1364
std::string fTestPatternName
The test pattern to use.
Definition: ntv2ccplayer.h:89
std::pair< NTV2InputXptID, NTV2OutputXptID > NTV2XptConnection
NTV2ChannelSet NTV2MakeChannelSet(const NTV2Channel inFirstChannel, const UWord inNumChannels=1)
This file contains some structures, constants, classes and functions that are used in some of the dem...
Specifies channel or FrameStore 5 (or the 5th item).
Definition: ntv2enums.h:1365
NTV2ACFrameRange fFrames
AutoCirculate frame count or range.
Private include file for all ajabase sources.
NTV2Standard GetNTV2StandardFromVideoFormat(const NTV2VideoFormat inVideoFormat)
Definition: ntv2utils.cpp:2375
virtual bool SetSDIOutputDS2AudioSystem(const NTV2Channel inSDIOutputConnector, const NTV2AudioSystem inAudioSystem)
Sets the Audio System that will supply audio for the given SDI output&#39;s audio embedder for Data Strea...
struct NTV2Line21Attributes NTV2Line21Attrs
std::vector< NTV2Channel > NTV2ChannelList
An ordered sequence of NTV2Channel values.
std::string join(const std::vector< std::string > &parts, const std::string &delim)
Definition: common.cpp:468
NTV2Line21Mode
The CEA-608 modes: pop-on, roll-up (2, 3 and 4-line), and paint-on.
virtual bool IsFinished(void) const
void * GetHostPointer(void) const
Identifies the first field in time for an interlaced video frame, or the first and only field in a pr...
Definition: ntv2enums.h:1845
static std::string StripFormatString(const std::string &inStr)
uint32_t QueryFrame(void) const
Definition: timecode.cpp:92
static size_t SetDefaultPageSize(void)
AJALabelValuePairs Get(void) const
static istringstream gBuiltInStream(gBuiltInCaptions)
The global built-in caption data input stream.
#define PLWARN(_xpr_)
8 audio channels
Definition: ntv2enums.h:3673
virtual AJAStatus SetUpBackgroundPatternBuffer(void)
Sets up my gray background field.
std::vector< std::string > NTV2StringList
virtual void GenerateCaptions(const NTV2Line21Channel inCCChannel)
This is the thread function that produces caption messages for a given caption channel.
bool CanDoVideoFormat(const NTV2VideoFormat inVF)
virtual bool MakeSMPTE334AncPacket(const NTV2FrameRate inFrameRate, const NTV2Line21Field inVideoField)
Generates a SMPTE-334 Ancillary data packet.
I am the principal class that stores a single SMPTE-291 SDI ancillary data packet OR the digitized co...
struct NTV2Line21Attributes NTV2Line21Attributes
CEA-608 Character Attributes.
#define AUTOCIRCULATE_WITH_RP188
Use this to AutoCirculate with RP188.
virtual bool IsPlainTextSource(void) const
std::string NTV2ChannelToString(const NTV2Channel inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:5730
std::string & lower(std::string &str)
Definition: common.cpp:436
Declares the AJAAncillaryList class.
NTV2Line21Channel
The CEA-608 caption channels: CC1 thru CC4, TX1 thru TX4, plus XDS.
bool SetAudioBuffer(ULWord *pInAudioBuffer, const ULWord inAudioByteCount)
Sets my audio buffer for use in a subsequent call to CNTV2Card::AutoCirculateTransfer.
Declares the enumeration constants used in the ajabase library.
uint16_t fForceRTP
BIT(0):0=normal,1=forceRTP BIT(1):0=uniPkt,1=multiPkt BIT(2):0=normal,1=patchDeviceID.
Definition: ntv2ccplayer.h:88
NTV2Buffer acANCBuffer
The host ancillary data buffer. This field is owned by the client application, and thus is responsibl...
Paint-on caption mode.
virtual bool EnqueueRollUpMessage(const std::string &inMessageStr, const NTV2Line21Mode inRollMode=NTV2_CC608_CapModeRollUp4, const NTV2Line21Channel inChannel=NTV2_CC608_CC1, const UWord inRowNumber=NTV2_CC608_MaxRow, const UWord inColumnNumber=NTV2_CC608_MinCol, const NTV2Line21Attrs &inDisplayAttribs=NTV2Line21Attrs())
Enqueues the given message for eventual "roll up" display.
virtual void SetTextMode(const bool inIsTextMode)
Sets my text mode. If I&#39;m in text mode, I don&#39;t do any word breaking or line/row truncation.
#define PLDBG(_xpr_)
NTV2InputXptID GetSDIOutputInputXpt(const NTV2Channel inSDIOutput, const bool inIsDS2=false)
static const double gFrequencies[]
Declares the AJAAncillaryData_Cea708 class.
virtual bool SetVANCMode(const NTV2VANCMode inVancMode, const NTV2Channel inChannel=NTV2_CHANNEL1)
Sets the VANC mode for the given FrameStore.
NTV2CCPlayer(const CCPlayerConfig &inConfigData)
Constructs me using the given configuration settings.
virtual bool GetDriverVersionComponents(UWord &outMajor, UWord &outMinor, UWord &outPoint, UWord &outBuild)
Answers with the individual version components of this device&#39;s driver.
Definition: ntv2card.cpp:184
#define NTV2_IS_PROGRESSIVE_STANDARD(__s__)
Definition: ntv2enums.h:191
virtual void SetAllowMultiRTPTransmit(const bool inAllow)
Determines if multiple RTP packets will be encoded for playout (via GetIPTransmitData). The default behavior is to transmit/encode a single RTP packet.
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.
Declares device capability functions.
NTV2OutputXptID GetCSCOutputXptFromChannel(const NTV2Channel inCSC, const bool inIsKey=false, const bool inIsRGB=false)
I am an ordered collection of AJAAncillaryData instances which represent one or more SMPTE 291 data p...
Definition: ancillarylist.h:64
virtual bool EnqueuePopOnMessage(const std::string &inMessageStr, const NTV2Line21Channel inChannel=NTV2_CC608_CC1, const UWord inRowNumber=0, const UWord inColumnNumber=0, const NTV2Line21Attrs &inDisplayAttribs=NTV2Line21Attrs())
Enqueues the given message for eventual "pop-on" display.
virtual AJAStatus SetFromSMPTE334(const uint16_t *pInData, const uint32_t inNumWords, const AJAAncDataLoc &inLocInfo)
Copies payload data from an external 16-bit source into local payload memory.
#define AUTOCIRCULATE_WITH_LTC
Use this to AutoCirculate with analog LTC.
bool SetVideoBuffer(ULWord *pInVideoBuffer, const ULWord inVideoByteCount)
Sets my video buffer for use in a subsequent call to CNTV2Card::AutoCirculateTransfer.
std::string NTV2FrameRateToString(const NTV2FrameRate inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:7011
virtual string GetNextCaptionRow(const bool inBreakLines=(0))
See 8-Bit YCbCr Format.
Definition: ntv2enums.h:225
#define NTV2_IS_4K_4096_VIDEO_FORMAT(__f__)
Definition: ntv2enums.h:835
AJALabelValuePairs Get(const bool inCompact=(0)) const
std::string NTV2Line21AttributesToStr(const NTV2Line21Attributes inLine21Attributes)
Converts the given NTV2Line21Attributes value into a human-readable string.