AJA NTV2 SDK  18.1.0.2145
NTV2 SDK 18.1.0.2145
ancillarylist.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
8 #include "ancillarylist.h"
9 #include "ancillarydatafactory.h"
10 #include "ajabase/system/debug.h"
12 #include "ajabase/system/atomic.h"
13 #include "ajabase/system/lock.h"
14 #if defined (AJALinux)
15  #include <string.h> // For memcpy
16 #endif // AJALinux
17 #if defined(AJAANCLISTIMPL_VECTOR)
18  #include <algorithm>
19 #endif
20 #if defined(AJA_USE_CPLUSPLUS11)
21  #include <utility> // For std::move
22 #endif
23 
24 using namespace std;
25 
26 #define LOGGING_ANCLIST AJADebug::IsActive(AJA_DebugUnit_AJAAncList)
27 #define LOGGING_ANC2110RX AJADebug::IsActive(AJA_DebugUnit_Anc2110Rcv)
28 #define LOGGING_ANC2110TX AJADebug::IsActive(AJA_DebugUnit_Anc2110Xmit)
29 
30 #define LOGMYERROR(__x__) {if (LOGGING_ANCLIST) AJA_sERROR (AJA_DebugUnit_AJAAncList, AJAFUNC << ": " << __x__);}
31 #define LOGMYWARN(__x__) {if (LOGGING_ANCLIST) AJA_sWARNING(AJA_DebugUnit_AJAAncList, AJAFUNC << ": " << __x__);}
32 #define LOGMYNOTE(__x__) {if (LOGGING_ANCLIST) AJA_sNOTICE (AJA_DebugUnit_AJAAncList, AJAFUNC << ": " << __x__);}
33 #define LOGMYINFO(__x__) {if (LOGGING_ANCLIST) AJA_sINFO (AJA_DebugUnit_AJAAncList, AJAFUNC << ": " << __x__);}
34 #define LOGMYDEBUG(__x__) {if (LOGGING_ANCLIST) AJA_sDEBUG (AJA_DebugUnit_AJAAncList, AJAFUNC << ": " << __x__);}
35 
36 #define RCVFAIL(__x__) {if (LOGGING_ANC2110RX) AJA_sERROR (AJA_DebugUnit_Anc2110Rcv, AJAFUNC << ": " << __x__);}
37 #define RCVWARN(__x__) {if (LOGGING_ANC2110RX) AJA_sWARNING(AJA_DebugUnit_Anc2110Rcv, AJAFUNC << ": " << __x__);}
38 #define RCVNOTE(__x__) {if (LOGGING_ANC2110RX) AJA_sNOTICE (AJA_DebugUnit_Anc2110Rcv, AJAFUNC << ": " << __x__);}
39 #define RCVINFO(__x__) {if (LOGGING_ANC2110RX) AJA_sINFO (AJA_DebugUnit_Anc2110Rcv, AJAFUNC << ": " << __x__);}
40 #define RCVDBG(__x__) {if (LOGGING_ANC2110RX) AJA_sDEBUG (AJA_DebugUnit_Anc2110Rcv, AJAFUNC << ": " << __x__);}
41 
42 #define XMTFAIL(__x__) {if (LOGGING_ANC2110TX) AJA_sERROR (AJA_DebugUnit_Anc2110Xmit, AJAFUNC << ": " << __x__);}
43 #define XMTWARN(__x__) {if (LOGGING_ANC2110TX) AJA_sWARNING(AJA_DebugUnit_Anc2110Xmit, AJAFUNC << ": " << __x__);}
44 #define XMTNOTE(__x__) {if (LOGGING_ANC2110TX) AJA_sNOTICE (AJA_DebugUnit_Anc2110Xmit, AJAFUNC << ": " << __x__);}
45 #define XMTINFO(__x__) {if (LOGGING_ANC2110TX) AJA_sINFO (AJA_DebugUnit_Anc2110Xmit, AJAFUNC << ": " << __x__);}
46 #define XMTDBG(__x__) {if (LOGGING_ANC2110TX) AJA_sDEBUG (AJA_DebugUnit_Anc2110Xmit, AJAFUNC << ": " << __x__);}
47 
48 #if defined(AJAHostIsBigEndian)
49  // Host is BigEndian (BE)
50  #define AJA_ENDIAN_16NtoH(__val__) (__val__)
51  #define AJA_ENDIAN_16HtoN(__val__) (__val__)
52  #define AJA_ENDIAN_32NtoH(__val__) (__val__)
53  #define AJA_ENDIAN_32HtoN(__val__) (__val__)
54  #define AJA_ENDIAN_64NtoH(__val__) (__val__)
55  #define AJA_ENDIAN_64HtoN(__val__) (__val__)
56 #else
57  // Host is LittleEndian (LE)
58  #define AJA_ENDIAN_16NtoH(__val__) AJA_ENDIAN_SWAP16(__val__)
59  #define AJA_ENDIAN_16HtoN(__val__) AJA_ENDIAN_SWAP16(__val__)
60  #define AJA_ENDIAN_32NtoH(__val__) AJA_ENDIAN_SWAP32(__val__)
61  #define AJA_ENDIAN_32HtoN(__val__) AJA_ENDIAN_SWAP32(__val__)
62  #define AJA_ENDIAN_64NtoH(__val__) AJA_ENDIAN_SWAP64(__val__)
63  #define AJA_ENDIAN_64HtoN(__val__) AJA_ENDIAN_SWAP64(__val__)
64 #endif
65 
66 static inline uint32_t ENDIAN_32NtoH(const uint32_t inValue) {return AJA_ENDIAN_32NtoH(inValue);}
67 //static inline uint32_t ENDIAN_32HtoN(const uint32_t inValue) {return AJA_ENDIAN_32HtoN(inValue);}
68 
69 static ostream & PrintULWordsBE (ostream & inOutStream, const ULWordSequence & inData, const size_t inMaxNum = 32)
70 {
71  unsigned numPrinted (0);
72  inOutStream << DECN(inData.size(),3) << " U32s: ";
73  for (ULWordSequenceConstIter iter(inData.begin()); iter != inData.end(); )
74  {
75  inOutStream << HEX0N(ENDIAN_32NtoH(*iter),8);
76  numPrinted++;
77  if (++iter != inData.end())
78  {
79  if (numPrinted > inMaxNum)
80  {inOutStream << "..."; break;}
81  inOutStream << " ";
82  }
83  }
84  return inOutStream;
85 }
86 
87 static string ULWordSequenceToStringBE (const ULWordSequence & inData, const size_t inMaxNum = 32)
88 {
89  ostringstream oss;
90  ::PrintULWordsBE (oss, inData, inMaxNum);
91  return oss.str();
92 }
93 
94 ostream & operator << (ostream & inOutStream, const AJAU32Pkts & inPkts)
95 {
96  unsigned rtpPktNum(0);
97  for (AJAU32PktsConstIter pktIter(inPkts.begin()); pktIter != inPkts.end(); ++pktIter)
98  { ++rtpPktNum;
99  inOutStream << "RTP PKT " << DEC0N(rtpPktNum,3) << ":";
100  ::PrintULWordsBE(inOutStream, *pktIter);
101  inOutStream << endl;
102  } // for each RTP packet
103  return inOutStream;
104 }
105 
106 ostream & operator << (ostream & inOutStream, const AJAAncPktDIDSIDSet & inSet)
107 {
108  for (AJAAncPktDIDSIDSetConstIter it(inSet.begin()); it != inSet.end(); )
109  { inOutStream << xHEX0N(*it,4);
110  if (++it != inSet.end())
111  inOutStream << " ";
112  } // for each DID/SID pair
113  return inOutStream;
114 }
115 
116 
117 
119 
120 
121 static bool gIncludeZeroLengthPackets (false);
122 static uint32_t gExcludedZeroLengthPackets (0);
124 
126 { AJAAutoLock locker(&gGlobalLock);
128 }
129 
131 { AJAAutoLock locker(&gGlobalLock);
133 }
134 
136 { AJAAutoLock locker(&gGlobalLock);
138 }
139 
140 inline void AJAAncillaryList::SetIncludeZeroLengthPackets (const bool inInclude)
141 { AJAAutoLock locker(&gGlobalLock);
142  gIncludeZeroLengthPackets = inInclude;
143 }
144 
145 static inline void BumpZeroLengthPacketCount (void)
146 {
148 }
149 
150 
152 
153 
155  : m_ancList (),
156  m_rcvMultiRTP (true), // By default, handle receiving multiple RTP packets
157  m_xmitMultiRTP (false), // By default, transmit single RTP packet
158  m_ignoreCS (false)
159 {
160  Clear();
167 }
168 
169 #if defined(AJA_USE_CPLUSPLUS11)
171  : m_ancList (std::move(inRHS.m_ancList)),
172  m_rcvMultiRTP (inRHS.m_rcvMultiRTP), // By default, handle receiving multiple RTP packets
173  m_xmitMultiRTP (inRHS.m_xmitMultiRTP), // By default, transmit single RTP packet
174  m_ignoreCS (inRHS.m_ignoreCS)
175 {
176  // Reset RHS...
177  inRHS.m_rcvMultiRTP = true;
178  inRHS.m_xmitMultiRTP = false;
179  inRHS.m_ignoreCS = false;
180  // inRHS.m_ancList - already moved/reset
181 }
182 #endif // defined(AJA_USE_CPLUSPLUS11)
183 
184 
186 {
187  Clear();
188 }
189 
190 
192 {
193  if (this != &inRHS)
194  {
195  m_xmitMultiRTP = inRHS.m_xmitMultiRTP;
196  m_rcvMultiRTP = inRHS.m_rcvMultiRTP;
197  m_ignoreCS = inRHS.m_ignoreCS;
198  Clear();
199  for (AJAAncDataListConstIter it(inRHS.m_ancList.begin()); it != inRHS.m_ancList.end(); ++it)
200  if (*it)
201  AddAncillaryData(*it);
202  }
203  return *this;
204 }
205 
206 #if defined(AJA_USE_CPLUSPLUS11)
208 {
209  if (this != &inRHS)
210  {
211  m_xmitMultiRTP = inRHS.m_xmitMultiRTP;
212  inRHS.m_xmitMultiRTP = false;
213 
214  m_rcvMultiRTP = inRHS.m_rcvMultiRTP;
215  inRHS.m_rcvMultiRTP = true;
216 
217  m_ignoreCS = inRHS.m_ignoreCS;
218  inRHS.m_ignoreCS = false;
219 
220  Clear(); // Clear down any packets currently being held in 'this'
221  m_ancList = std::move(inRHS.m_ancList);
222  }
223  return *this;
224 }
225 #endif // defined(AJA_USE_CPLUSPLUS11)
226 
228 {
229  AJAAncillaryData * pAncData(AJA_NULL);
230 
231  if (inIndex < m_ancList.size())
232  {
233 #if defined(AJAANCLISTIMPL_VECTOR)
234  pAncData = m_ancList[inIndex]; // Yay! std::vector has random access.
235 #else
236  AJAAncDataListConstIter it (m_ancList.begin());
237 
238  for (uint32_t i(0); i < inIndex; i++) // Dang, std::list has no random access
239  ++it;
240  pAncData = *it;
241 #endif
242  }
243  return pAncData;
244 }
245 
246 
248 {
249  AJAStatus result = AJA_STATUS_SUCCESS;
250 
251  for (AJAAncDataListConstIter it(m_ancList.begin()); it != m_ancList.end(); ++it)
252  {
253  AJAAncillaryData * pAncData = *it;
254  AJAStatus status = pAncData->ParsePayloadData ();
255 
256  // Parse ALL items (even if one fails), but only return success if ALL succeed...
257  if (AJA_FAILURE (status))
258  result = status;
259  }
260  return result;
261 }
262 
263 
265 {
266  uint32_t count = 0;
267 
268  for (AJAAncDataListConstIter it(m_ancList.begin()); it != m_ancList.end(); ++it)
269  {
270  AJAAncillaryData * pAncData (*it);
271  AJAAncDataType ancType (pAncData->GetAncillaryDataType());
272 
273  if (matchType == ancType)
274  count++;
275  }
276  return count;
277 }
278 
279 
280 AJAAncillaryData * AJAAncillaryList::GetAncillaryDataWithType (const AJAAncDataType matchType, const uint32_t index) const
281 {
282  AJAAncillaryData * pResult (AJA_NULL);
283  uint32_t count = 0;
284 
285  for (AJAAncDataListConstIter it(m_ancList.begin()); it != m_ancList.end(); ++it)
286  {
287  AJAAncillaryData * pAncData (*it);
288  AJAAncDataType ancType (pAncData->GetAncillaryDataType());
289 
290  if (matchType == ancType)
291  {
292  if (index == count)
293  {
294  pResult = pAncData;
295  break;
296  }
297  else
298  count++;
299  }
300  }
301  return pResult;
302 }
303 
304 
305 uint32_t AJAAncillaryList::CountAncillaryDataWithID (const uint8_t DID, const uint8_t SID) const
306 {
307  uint32_t count = 0;
308 
309  for (AJAAncDataListConstIter it(m_ancList.begin()); it != m_ancList.end(); ++it)
310  {
311  AJAAncillaryData * pAncData = *it;
312 
313  if (DID == AJAAncillaryDataWildcard_DID || DID == pAncData->GetDID())
314  {
315  if (SID == AJAAncillaryDataWildcard_SID || SID == pAncData->GetSID())
316  count++;
317  }
318  }
319  return count;
320 }
321 
322 
323 AJAAncillaryData * AJAAncillaryList::GetAncillaryDataWithID (const uint8_t inDID, const uint8_t inSID, const uint32_t index) const
324 {
325  AJAAncillaryData * pResult (AJA_NULL);
326  uint32_t count(0);
327 
328  for (AJAAncDataListConstIter it(m_ancList.begin()); it != m_ancList.end(); ++it)
329  {
330  if (inDID == AJAAncillaryDataWildcard_DID || inDID == (*it)->GetDID())
331  {
332  if (inSID == AJAAncillaryDataWildcard_SID || inSID == (*it)->GetSID())
333  {
334  if (index == count)
335  {
336  pResult = *it;
337  break;
338  }
339  count++;
340  }
341  }
342  }
343  return pResult;
344 }
345 
347 {
348  AJAAncPktDIDSIDSet result;
349  for (AJAAncDataListConstIter it(m_ancList.begin()); it != m_ancList.end(); ++it)
350  {
351  const uint16_t pktDIDSID(ToAJAAncPktDIDSID((*it)->GetDID(), (*it)->GetSID()));
352  if (result.find(pktDIDSID) == result.end())
353  result.insert(pktDIDSID);
354  }
355  return result;
356 }
357 
358 
360 {
361  if (&inPackets == this)
362  return AJA_STATUS_BAD_PARAM; // Cannot append from same list!
363  for (AJAAncDataListConstIter it(inPackets.m_ancList.begin()); it != inPackets.m_ancList.end(); ++it)
364  {
365  const AJAAncillaryData * pSrcPkt (*it);
366  if (!pSrcPkt)
367  return AJA_STATUS_FAIL;
368  AJAAncillaryData * pNewPkt (pSrcPkt->Clone());
369  if (!pNewPkt)
370  return AJA_STATUS_FAIL;
371  m_ancList.push_back(pNewPkt);
372  }
373  return AJA_STATUS_SUCCESS;
374 }
375 
376 
378 {
379  if (!pInAncData)
380  return AJA_STATUS_NULL;
381 
382  // Note: this makes a clone of the incoming AJAAncillaryData object and
383  // saves it in the List. The caller is responsible for deleting the original,
384  // and the List owns the clone.
385  const bool wasEmpty (m_ancList.empty());
386  AJAAncillaryData * pData (pInAncData->Clone());
387  if (!pData)
388  return AJA_STATUS_FAIL;
389 
390  // add it to the list
391  if (pData)
392  m_ancList.push_back(pData);
393 
394  LOGMYDEBUG(DEC(m_ancList.size()) << " packet(s) stored" << (wasEmpty ? " from" : " after appending") << " packet " << pData->AsString(32));
395  return AJA_STATUS_SUCCESS;
396 }
397 
398 
400 {
401  uint32_t numDeleted (0);
402  const uint32_t oldSize (uint32_t(m_ancList.size()));
403  for (AJAAncDataListConstIter it (m_ancList.begin()); it != m_ancList.end(); ++it)
404  {
405  AJAAncillaryData * pAncData(*it);
406  if (pAncData)
407  {
408  delete pAncData;
409  numDeleted++;
410  }
411  }
412 
413  m_ancList.clear();
414  if (oldSize || numDeleted)
415  LOGMYDEBUG(numDeleted << " packet(s) deleted -- list emptied");
416  return AJA_STATUS_SUCCESS;
417 }
418 
419 
421 {
422  if (!pAncData)
423  return AJA_STATUS_NULL;
424 
425 #if defined(AJAANCLISTIMPL_VECTOR)
427  for (it = m_ancList.begin(); it != m_ancList.end(); ++it)
428  if (*it == pAncData)
429  break;
430  if (it == m_ancList.end())
431  {LOGMYERROR("failed to remove packet " << pAncData->AsString(32)); return AJA_STATUS_NOT_FOUND;}
432  m_ancList.erase(it);
433 #else
434  m_ancList.remove(pAncData); // note: there's no feedback as to whether one or more elements existed or not
435  // note: pAncData is NOT deleted!
436 #endif
437  LOGMYDEBUG(DEC(m_ancList.size()) << " packet(s) remain after removing packet " << pAncData->AsString(32));
438  return AJA_STATUS_SUCCESS;
439 }
440 
441 
443 {
444  if (!pAncData)
445  return AJA_STATUS_NULL;
446 
447  AJAStatus status (RemoveAncillaryData(pAncData));
448  if (AJA_SUCCESS(status))
449  delete pAncData;
450  return status;
451 }
452 
453 
454 // Sort Predicates
455 
456 static bool SortByDID (AJAAncillaryData * lhs, AJAAncillaryData * rhs)
457 {
458  return lhs->GetDID() < rhs->GetDID();
459 }
460 
461 
462 static bool SortBySID (AJAAncillaryData * lhs, AJAAncillaryData * rhs)
463 {
464  return lhs->GetSID() < rhs->GetSID();
465 }
466 
468 {
469  const AJAAncDataLoc & locLHS (lhs->GetDataLocation());
470  const AJAAncDataLoc & locRHS (rhs->GetDataLocation());
471  return locLHS < locRHS;
472 }
473 
474 
475 // Sort Methods
476 
478 {
479 #if defined(AJAANCLISTIMPL_VECTOR)
480  std::sort(m_ancList.begin(), m_ancList.end(), SortByDID);
481 #else
482  m_ancList.sort (SortByDID);
483 #endif
484  return AJA_STATUS_SUCCESS;
485 }
486 
487 
489 {
490 #if defined(AJAANCLISTIMPL_VECTOR)
491  std::sort(m_ancList.begin(), m_ancList.end(), SortBySID);
492 #else
493  m_ancList.sort (SortBySID);
494 #endif
495  return AJA_STATUS_SUCCESS;
496 }
497 
499 {
500 #if defined(AJAANCLISTIMPL_VECTOR)
501  std::sort(m_ancList.begin(), m_ancList.end(), SortByLocation);
502 #else
503  m_ancList.sort(SortByLocation);
504 #endif
505  return AJA_STATUS_SUCCESS;
506 }
507 
508 
509 AJAStatus AJAAncillaryList::Compare (const AJAAncillaryList & inCompareList, const bool inIgnoreLocation, const bool inIgnoreChecksum) const
510 {
511  if (inCompareList.CountAncillaryData() != CountAncillaryData())
512  return AJA_STATUS_FAIL;
513  for (uint32_t ndx (0); ndx < CountAncillaryData(); ndx++)
514  {
515  AJAAncillaryData * pPktA (inCompareList.GetAncillaryDataAtIndex(ndx));
517  if (AJA_FAILURE(pPktA->Compare(*pPktB, inIgnoreLocation, inIgnoreChecksum)))
518  return AJA_STATUS_FAIL;
519  } // for each packet
520  return AJA_STATUS_SUCCESS;
521 }
522 
523 
524 string AJAAncillaryList::CompareWithInfo (const AJAAncillaryList & inCompareList, const bool inIgnoreLocation, const bool inIgnoreChecksum) const
525 {
526  ostringstream oss;
527  if (inCompareList.CountAncillaryData() != CountAncillaryData())
528  { oss << "Packet count mismatch: " << DEC(CountAncillaryData()) << " vs " << DEC(inCompareList.CountAncillaryData());
529  return oss.str();
530  }
531 
532  for (uint32_t ndx (0); ndx < CountAncillaryData(); ndx++)
533  {
534  AJAAncillaryData * pPktRHS (inCompareList.GetAncillaryDataAtIndex(ndx));
536  const string info (pPkt->CompareWithInfo(*pPktRHS, inIgnoreLocation, inIgnoreChecksum));
537  if (!info.empty())
538  {
539  oss << "Pkt " << DEC(ndx+1) << " of " << DEC(CountAncillaryData()) << ": " << pPkt->AsString() << " != " << pPktRHS->AsString() << ": " << info;
540  return oss.str();
541  }
542  } // for each packet
543  return string();
544 }
545 
546 
547 bool AJAAncillaryList::CompareWithInfo (vector<string> & outDiffInfo, const AJAAncillaryList & inCompareList, const bool inIgnoreLocation, const bool inIgnoreChecksum) const
548 {
549  outDiffInfo.clear();
550  if (inCompareList.CountAncillaryData() != CountAncillaryData())
551  {
552  ostringstream oss;
553  oss << "Packet count mismatch: " << DEC(CountAncillaryData()) << " vs " << DEC(inCompareList.CountAncillaryData());
554  outDiffInfo.push_back(oss.str());
555  return false; // Miscompared
556  }
557 
558  for (uint32_t ndx(0); ndx < CountAncillaryData(); ndx++)
559  {
560  AJAAncillaryData * pPktRHS (inCompareList.GetAncillaryDataAtIndex(ndx));
562  const string info (pPkt->CompareWithInfo(*pPktRHS, inIgnoreLocation, inIgnoreChecksum));
563  if (!info.empty())
564  {
565  ostringstream oss;
566  oss << "Pkt " << DEC(ndx+1) << " of " << DEC(CountAncillaryData()) << ":" << endl
567  << "LHS " << pPkt->AsString(250) << endl
568  << "RHS " << pPktRHS->AsString(250) << endl
569  << info;
570  outDiffInfo.push_back(oss.str());
571  }
572  } // for each packet
573  return outDiffInfo.empty(); // equal if empty list
574 }
575 
576 
580 
581 // Parse a stream of "raw" ancillary data as collected by an AJAAncExtractorWidget.
582 // Break the stream into separate AJAAncillaryData objects and add them to the list.
583 //
584 AJAStatus AJAAncillaryList::AddReceivedAncillaryData (const NTV2Buffer & inReceivedData, const uint32_t inFrameNum)
585 {
586  AJAStatus status (AJA_STATUS_SUCCESS);
587  if (!inReceivedData)
588  return AJA_STATUS_NULL;
589 
590  AJAAncillaryDataList rawPkts; // Accumulate "analog/raw" packets separately
591  AJAAncillaryData newAncData; // Use this as an uninitialized template
593  int32_t remainingSize (int32_t(inReceivedData.GetByteCount()));
594  const uint8_t * pInputData (inReceivedData);
595  bool bMoreData (true);
596 
597  while (bMoreData)
598  {
599  bool bInsertNew (false); // We'll set this 'true' if/when we find a new Anc packet to insert
600  AJAAncDataType newAncType (AJAAncDataType_Unknown); // We'll set this to the proper type once we know it
601  uint32_t packetSize (0); // This is where the AncillaryData object returns the number of bytes that were "consumed" from the input stream
602 
603  // Reset the AncData object, then load itself from the next GUMP packet...
604  newAncData.Clear();
605  status = newAncData.InitWithReceivedData (pInputData, size_t(remainingSize), defaultLoc, packetSize);
606  if (AJA_FAILURE(status))
607  {
608  // TODO: Someday, let's try to recover and process subsequent packets.
609  break; // NOTE: For now, bail on errors in the GUMP stream
610  }
611  else if (packetSize == 0)
612  break; // Nothing to do
613 
614  // Determine what type of anc data we have, and create an object of the appropriate class...
615  if (newAncData.IsDigital())
616  {
617  // Digital anc packets are fairly easy to categorize: you just have to look at their DID/SID.
618  // Also, they are (by definition) independent packets which become independent AJAAncillaryData objects.
619  newAncType = AJAAncillaryDataFactory::GuessAncillaryDataType(&newAncData);
620  bInsertNew = true; // Add it to the list
621  } // digital anc data
622  else if (newAncData.IsRaw())
623  { // "Analog" packets are trickier...
624  // 1) Digitized analog lines are broken into multiple packets by the hardware,
625  // which need to be recombined into a single AJAAncillaryData object.
626  // 2) It is harder to classify the data type, since there is no single easy-to-read
627  // ID. Instead, we rely on the user to tell us what lines are expected to contain
628  // what kind of data (e.g. "expect line 21 to carry 608 captioning...").
629 
630  // This function used to assume that analog packets always were in succession in the buffer.
631  // This isn't true, however, if packet filtering is disabled. Audio packets can be interspersed
632  // between successive analog packets. We now accumulate analog packets separately in "rawPkts",
633  // then add them all to my "m_ancList" member last.
634 
635  // Look for a pkt in "rawPkts" that has the same location...
636  const uint64_t desiredLocation (newAncData.GetDataLocation().OrdinalValue());
637  AJAAncillaryData * pContinuationPkt (AJA_NULL);
638  for (AJAAncDataListConstIter pRaw(rawPkts.begin()); pRaw != rawPkts.end(); ++pRaw)
639  if ((*pRaw)->GetDataLocation().OrdinalValue() == desiredLocation)
640  { // Found one!
641  // "newAncData" must be a continuation of the "pRaw" pkt.
642  // Simply append the new payload data to it...
643  pContinuationPkt = *pRaw;
644  pContinuationPkt->AppendPayload(newAncData);
645  break;
646  }
647 
648  if (!pContinuationPkt)
649  { // If this is NOT a "continuation" packet, then this is a new analog packet.
650  // See if the user has specified an expected Anc data type that matches the
651  // location of the new data...
652  newAncType = GetAnalogAncillaryDataType(newAncData);
653  bInsertNew = true; // Create the new raw pkt, and add it to "rawPkts" queue (below)
654  }
655  } // analog anc data
656 // else
657 // Anc Coding Unknown???? (ignore it)
658 
659  if (bInsertNew)
660  {
661  // Create an AJAAncillaryData object of the appropriate type, and init it with our raw data...
662  AJAAncillaryData * pData (AJAAncillaryDataFactory::Create (newAncType, &newAncData));
663  if (pData)
664  {
666  if (IsIncludingZeroLengthPackets() || pData->GetDC())
667  {
668  try {
669  if (pData->IsRaw())
670  rawPkts.push_back(pData); // New analog pkts go onto my rawPkts queue
671  else
672  m_ancList.push_back(pData); // New digital pkts are immediately appended to my list
673  } catch(...) {status = AJA_STATUS_FAIL;}
674  }
676  if (inFrameNum && !pData->GetFrameID())
677  pData->SetFrameID(inFrameNum);
678  }
679  else
680  status = AJA_STATUS_FAIL;
681  }
682 
683  remainingSize -= packetSize; // Decrease the remaining data size by the amount we just "consumed"
684  pInputData += packetSize; // Advance the input data pointer by the same amount
685  if (remainingSize <= 0) // All of the input data consumed?
686  bMoreData = false;
687  } // while (bMoreData)
688 
689  if (!rawPkts.empty())
690  {
691  if (AJA_FAILURE(status))
692  while (!rawPkts.empty())
693  { // Failed -- delete accumulated analog/raw packets
694  delete rawPkts.at(0);
695  rawPkts.erase(rawPkts.begin());
696  }
697  else while (AJA_SUCCESS(status) && !rawPkts.empty())
698  { // Append accumulated analog/raw packets...
699  try {
700  m_ancList.push_back(rawPkts.back());
701  } catch(...) {status = AJA_STATUS_FAIL;}
702  rawPkts.pop_back();
703  }
704  if (AJA_SUCCESS(status))
705  status = SortListByLocation(); // Re-sort by location
706  } // if any accumulated raw pkts
707 
708  return status;
709 
710 } // AddReceivedAncillaryData
711 
712 // Parse a stream of "raw" ancillary data as collected by an HDMI Aux Extractor.
713 // Break the stream into separate AJAAncillaryData objects and add them to the list.
714 //
716  const uint32_t inFrameNum)
717 {
718  AJAStatus status (AJA_STATUS_SUCCESS);
719  const uint8_t * pRcvData = inReceivedData;
720  const uint32_t dataSize = inReceivedData.GetByteCount();
721  if (!pRcvData || !dataSize)
722  return AJA_STATUS_NULL;
723 
724  // Use this as an uninitialized template...
725  AJAAncillaryData newAncData;
726  int32_t remainingSize (int32_t(dataSize + 0));
727  const uint8_t * pInputData (pRcvData);
728  bool bMoreData (true);
729 
730  while (bMoreData)
731  {
732  uint32_t packetSize (0); // This is where the AncillaryData object returns the number of bytes that were "consumed" from the input stream
733  status = newAncData.InitAuxWithReceivedData (pInputData, size_t(remainingSize), packetSize);
734  if (AJA_FAILURE(status))
735  {
736  // TODO: Someday, try to recover and process subsequent packets.
737  break; // NOTE: For now, bail on errors in the stream
738  }
739  else if (packetSize == 0)
740  break; // Nothing to do
741 
742  // Create an AJAAuxiliaryData object of the appropriate type, and init it with our raw data...
744  if (pData)
745  {
747  if (IsIncludingZeroLengthPackets() || pData->GetDC())
748  {
749  try {m_ancList.push_back(pData);} // Append to my list
750  catch(...) {status = AJA_STATUS_FAIL;}
751  }
753  if (inFrameNum && !pData->GetFrameID())
754  pData->SetFrameID(inFrameNum);
755  }
756  else
757  status = AJA_STATUS_FAIL;
758 
759 
760  remainingSize -= packetSize; // Decrease the remaining data size by the amount we just "consumed"
761  pInputData += packetSize; // Advance the input data pointer by the same amount
762  if (remainingSize <= 0) // All of the input data consumed?
763  bMoreData = false;
764  } // while (bMoreData)
765 
766  return status;
767 
768 } // AddReceivedAncillaryData
769 
770 // Parse a "raw" RTP packet received from hardware (ingest) in network byte order into separate
771 // AJAAncillaryData objects and append them to me. 'inReceivedData' includes the RTP header.
773 {
774  AJAStatus status (AJA_STATUS_SUCCESS);
775  if (inReceivedData.empty())
776  {LOGMYWARN("Empty RTP data vector"); return AJA_STATUS_SUCCESS;}
777 
778 LOGMYDEBUG(::ULWordSequenceToStringBE(inReceivedData) << " (BigEndian)"); // ByteSwap em to make em look right
779 
780  // Crack open the RTP packet header...
781  AJARTPAncPayloadHeader RTPheader;
782  if (!RTPheader.ReadFromULWordVector(inReceivedData))
783  {LOGMYERROR("AJARTPAncPayloadHeader::ReadULWordVector failed, " << DEC(4*inReceivedData.size()) << " header bytes"); return AJA_STATUS_FAIL;}
784  if (RTPheader.IsNULL())
785  {LOGMYWARN("No anc packets added: NULL RTP header: " << RTPheader); return AJA_STATUS_SUCCESS;} // Not an error
786  if (!RTPheader.IsValid())
787  {LOGMYWARN("RTP header invalid: " << RTPheader); return AJA_STATUS_FAIL;}
788 
789  const size_t predictedPayloadSize (RTPheader.GetPayloadLength() / sizeof(uint32_t)); // Payload length (excluding RTP header)
790  const size_t actualPayloadSize (inReceivedData.size() - AJARTPAncPayloadHeader::GetHeaderWordCount());
791  const uint32_t numPackets (RTPheader.GetAncPacketCount());
792  uint32_t pktsAdded (0);
793 
794  // Sanity check the RTP header against inReceivedData...
795  if (actualPayloadSize < predictedPayloadSize)
796  {LOGMYERROR("Expected " << DEC(predictedPayloadSize) << ", but only given " << DEC(actualPayloadSize) << " U32s: " << RTPheader); return AJA_STATUS_BADBUFFERCOUNT;}
797  if (!numPackets)
798  {LOGMYWARN("No Anc packets to append: " << RTPheader); return AJA_STATUS_SUCCESS;}
799  if (!actualPayloadSize)
800  {LOGMYWARN("No payload data yet non-zero packet count: " << RTPheader); return AJA_STATUS_FAIL;}
801 
802 LOGMYDEBUG(RTPheader);
803 
804  // Parse each anc pkt in the RTP pkt...
805  uint16_t u32Ndx (5); // First Anc packet starts at ULWord[5]
806  unsigned pktNum (0);
807  for (; pktNum < numPackets && AJA_SUCCESS(status); pktNum++)
808  {
809  AJAAncillaryData tempPkt;
810  status = tempPkt.InitWithReceivedData(inReceivedData, u32Ndx, IgnoreChecksumErrors());
811  if (AJA_FAILURE(status))
812  continue;
813 
815  AJAAncillaryData * pNewPkt (AJAAncillaryDataFactory::Create (newAncType, tempPkt));
816  if (!pNewPkt)
817  {status = AJA_STATUS_NULL; continue;}
818 
819  pNewPkt->SetBufferFormat(AJAAncBufferFormat_RTP); // Originated in RTP packet
820  pNewPkt->SetFrameID(RTPheader.GetTimeStamp()); // TimeStamp it using RTP timestamp
821  if (IsIncludingZeroLengthPackets() || pNewPkt->GetDC())
822  {
823  try {m_ancList.push_back(pNewPkt); pktsAdded++;} // Append to my list
824  catch(...) {status = AJA_STATUS_FAIL;}
825  }
827  } // for each anc packet
828 
829  if (AJA_FAILURE(status))
830  LOGMYERROR(::AJAStatusToString(status) << ": Failed at pkt[" << DEC(pktNum) << "] of " << DEC(numPackets));
831  if (CountAncillaryData() < numPackets)
832  {LOGMYWARN(DEC(pktsAdded) << " of " << DEC(numPackets) << " anc pkt(s) decoded from RTP pkt");}
833  else
834  LOGMYINFO(DEC(numPackets) << " pkts added from RTP pkt: " << *this);
835  return status;
836 } // AddReceivedAncillaryData
837 
838 
840  const UWordSequence & inPacketWords,
844  0))
845 {
846  AJAStatus status (AJA_STATUS_SUCCESS);
847 
848  if (inPacketWords.size () < 7)
849  return AJA_STATUS_RANGE;
850 // NOTE: Tough call. Decided not to validate the AJAAncDataLoc here:
851 // if (!inLoc.IsValid())
852 // return AJA_STATUS_BAD_PARAM;
853 
854  // Use this as an uninitialized template...
855  UWordSequenceConstIter iter(inPacketWords.begin());
856 
857  // Anc packet must start with 0x000 0x3FF 0x3FF sequence...
858  if (*iter != 0x0000)
859  return AJA_STATUS_FAIL;
860  ++iter;
861  if (*iter != 0x03FF)
862  return AJA_STATUS_FAIL;
863  ++iter;
864  if (*iter != 0x03FF)
865  return AJA_STATUS_FAIL;
866  ++iter; // Now pointing at DID
867 
868  outGumpPkt.reserve (outGumpPkt.size() + inPacketWords.size()); // Expand outGumpPkt's capacity in one step
869  const UByteSequence::size_type dataByte1Ndx (outGumpPkt.size()+1); // Index of byte[1] in outgoing Gump packet
870  outGumpPkt.push_back(0xFF); // [0] First byte always 0xFF
871  outGumpPkt.push_back(0x80); // [1] Location data byte 1: "location valid" bit always set
872  outGumpPkt[dataByte1Ndx] |= (inLoc.GetLineNumber() >> 7) & 0x0F; // [1] Location data byte 1: LS 4 bits == MS 4 bits of 11-bit line number
873  if (inLoc.IsLumaChannel())
874  outGumpPkt[dataByte1Ndx] |= 0x20; // [1] Location data byte 1: set Y/C bit for Y/luma channel
875  if (inLoc.IsHanc())
876  outGumpPkt[dataByte1Ndx] |= 0x10; // [1] Location data byte 1: set H/V bit for HANC
877  outGumpPkt.push_back (inLoc.GetLineNumber() & 0x7F); // [2] Location data byte 2: MSB reserved; LS 7 bits == LS 7 bits of 11-bit line number
878 
879  while (iter != inPacketWords.end())
880  {
881  outGumpPkt.push_back(*iter & 0xFF); // Mask off upper byte
882  ++iter;
883  }
884  return status;
885 }
886 
887 
888 AJAStatus AJAAncillaryList::AddVANCData (const UWordSequence & inPacketWords, const AJAAncDataLoc & inLocation, const uint32_t inFrameNum)
889 {
890  UByteSequence gumpPacketData;
891  AJAStatus status (AppendUWordPacketToGump (gumpPacketData, inPacketWords, inLocation));
892  if (AJA_FAILURE(status))
893  return status;
894 
896  AJAAncillaryData * pData (AJA_NULL);
897  {
898  AJAAncillaryData pkt;
899  status = pkt.InitWithReceivedData (gumpPacketData, inLocation);
900  if (AJA_FAILURE(status))
901  return status;
903 
905  pData = AJAAncillaryDataFactory::Create(newAncType, pkt);
906  if (!pData)
907  return AJA_STATUS_FAIL;
908  }
909 
910  if (IsIncludingZeroLengthPackets() || pData->GetDC())
911  {
912  try {m_ancList.push_back(pData);} // Append to my list, I now own the instance
913  catch(...) {delete pData; return AJA_STATUS_FAIL;}
914 
915  if (inFrameNum && pData->GetDID())
916  pData->SetFrameID(inFrameNum);
917  }
918  else
919  {
921  delete pData; // Don't leak zero-length packets
922  }
923  return AJA_STATUS_SUCCESS;
924 
925 } // AddVANCData
926 
927 
929  const NTV2FormatDesc & inFD,
930  AJAAncillaryList & outPkts,
931  const uint32_t inFrameNum)
932 {
933  outPkts.Clear();
934  if (inFB.IsNULL())
935  {
936  LOGMYERROR("AJA_STATUS_NULL: NULL frame buffer pointer");
937  return AJA_STATUS_NULL;
938  }
939  if (!inFD.IsValid())
940  {
941  LOGMYERROR("AJA_STATUS_BAD_PARAM: bad NTV2FormatDescriptor");
942  return AJA_STATUS_BAD_PARAM;
943  }
944  if (!inFD.IsVANC())
945  {
946  LOGMYERROR("AJA_STATUS_BAD_PARAM: format descriptor has no VANC lines");
947  return AJA_STATUS_BAD_PARAM;
948  }
949 
950  const ULWord vancBytes (inFD.GetTotalRasterBytes() - inFD.GetVisibleRasterBytes());
951  const NTV2PixelFormat fbf (inFD.GetPixelFormat());
952  const bool isSD (NTV2_IS_SD_STANDARD(inFD.GetVideoStandard()));
953  if (inFB.GetByteCount() < vancBytes)
954  {
955  LOGMYERROR("AJA_STATUS_FAIL: " << inFB.GetByteCount() << "-byte frame buffer smaller than " << vancBytes << "-byte VANC region");
956  return AJA_STATUS_FAIL;
957  }
958  if (fbf != NTV2_FBF_10BIT_YCBCR && fbf != NTV2_FBF_8BIT_YCBCR)
959  {
960  LOGMYERROR("AJA_STATUS_UNSUPPORTED: frame buffer format " << ::NTV2FrameBufferFormatToString(fbf) << " not '2vuy' nor 'v210'");
961  return AJA_STATUS_UNSUPPORTED; // Only 'v210' and '2vuy' currently supported
962  }
963 
964  for (ULWord lineOffset (0); lineOffset < inFD.GetFirstActiveLine(); lineOffset++)
965  {
966  UWordSequence uwords;
967  bool isF2 (false);
968  ULWord smpteLineNum (0);
969  unsigned ndx (0);
970  const AJAAncDataLink defaultLink (AJAAncDataLink_A); // This is most common
971 
972  inFD.GetSMPTELineNumber (lineOffset, smpteLineNum, isF2);
973  if (fbf == NTV2_FBF_10BIT_YCBCR)
974  ::UnpackLine_10BitYUVtoUWordSequence (inFD.GetRowAddress(inFB.GetHostAddress(0), lineOffset), inFD, uwords);
975  else if (isSD)
977  uwords, inFD.GetRasterWidth());
978  else
980  uwords, inFD.GetRasterWidth());
981  if (isSD)
982  {
984  UWordSequence ycHOffsets;
985  AJAAncDataLoc loc (defaultLink, AJAAncDataChannel_Both, AJAAncDataSpace_VANC, uint16_t(smpteLineNum));
986 
988  NTV2_ASSERT(ycPackets.size() == ycHOffsets.size());
989 
990  for (AJAAncillaryData::U16Packets::const_iterator it(ycPackets.begin()); it != ycPackets.end(); ++it, ndx++)
991  outPkts.AddVANCData (*it, loc.SetHorizontalOffset(ycHOffsets[ndx]), inFrameNum);
992  }
993  else
994  {
995  AJAAncillaryData::U16Packets yPackets, cPackets;
996  UWordSequence yHOffsets, cHOffsets;
997  AJAAncDataLoc yLoc (defaultLink, AJAAncDataChannel_Y, AJAAncDataSpace_VANC, uint16_t(smpteLineNum));
998  AJAAncDataLoc cLoc (defaultLink, AJAAncDataChannel_C, AJAAncDataSpace_VANC, uint16_t(smpteLineNum));
999  //cerr << endl << "SetFromVANCData: +" << DEC0N(lineOffset,2) << ": "; inFD.PrintSMPTELineNumber(cerr, lineOffset); cerr << ":" << endl << uwords << endl;
1000  AJAAncillaryData::GetAncPacketsFromVANCLine (uwords, AncChannelSearch_Y, yPackets, yHOffsets);
1001  AJAAncillaryData::GetAncPacketsFromVANCLine (uwords, AncChannelSearch_C, cPackets, cHOffsets);
1002  NTV2_ASSERT(yPackets.size() == yHOffsets.size());
1003  NTV2_ASSERT(cPackets.size() == cHOffsets.size());
1004 
1005  unsigned ndxx(0);
1006  for (AJAAncillaryData::U16Packets::const_iterator it(yPackets.begin()); it != yPackets.end(); ++it, ndxx++)
1007  outPkts.AddVANCData (*it, yLoc.SetHorizontalOffset(yHOffsets[ndxx]), inFrameNum);
1008 
1009  ndxx = 0;
1010  for (AJAAncillaryData::U16Packets::const_iterator it(cPackets.begin()); it != cPackets.end(); ++it, ndxx++)
1011  outPkts.AddVANCData (*it, cLoc.SetHorizontalOffset(cHOffsets[ndxx]), inFrameNum);
1012  }
1013  } // for each VANC line
1014  LOGMYDEBUG("returning " << outPkts);
1015  return AJA_STATUS_SUCCESS;
1016 }
1017 
1018 // STATIC
1020  AJAAncillaryList & outPackets,
1021  const uint32_t inFrameNum)
1022 {
1023  uint32_t RTPPacketCount (0); // Number of packets encountered
1024  const uint32_t origPktCount (outPackets.CountAncillaryData());
1025  AJAStatus result (AJA_STATUS_SUCCESS);
1026 
1027  // Try GUMP first...
1028  if (BufferHasGUMPData(inAncBuffer))
1029  { // GUMP GUMP GUMP GUMP GUMP GUMP GUMP GUMP GUMP GUMP GUMP GUMP GUMP GUMP GUMP GUMP GUMP GUMP
1030  result = outPackets.AddReceivedAncillaryData (inAncBuffer, inFrameNum);
1031  if (result == AJA_STATUS_NULL)
1032  result = AJA_STATUS_SUCCESS; // A NULL/empty buffer is not an error
1033  } // if GUMP
1034  else
1035  {
1036  // RTP RTP RTP RTP RTP RTP RTP RTP RTP RTP RTP RTP RTP RTP RTP RTP RTP RTP
1037  NTV2Buffer ancBuffer (inAncBuffer.GetHostPointer(), inAncBuffer.GetByteCount()); // Don't copy
1038  size_t ULWordCount (0); // Size of current RTP packet, including RTP header, in 32-bit words
1039  size_t ULWordOffset (0); // Offset to start of current RTP packet, in 32-bit words
1040  unsigned retries (0); // Retry count
1041  const unsigned MAX_RETRIES (4); // Max number of U32s past the end of an RTP packet to look for another
1042 
1043  while (ancBuffer && retries++ < MAX_RETRIES)
1044  {
1046  {
1047  ULWordSequence U32s;
1048  AJARTPAncPayloadHeader rtpHeader;
1049 
1050  ++RTPPacketCount; // Increment our packet tally
1051 
1052  // Read the RTP packet header to discover the RTP packet's true length...
1053  if (!rtpHeader.ReadFromBuffer(ancBuffer))
1054  {
1055  RCVWARN("On RTP pkt " << DEC(RTPPacketCount) << ", RTP hdr ReadFromBuffer failed at: " << ancBuffer.AsString(40));
1056  break;
1057  }
1058 
1059  ULWordCount = rtpHeader.GetPayloadLength() / sizeof(uint32_t) // payload size
1060  + AJARTPAncPayloadHeader::GetHeaderWordCount(); // plus RTP header size
1061 
1062  // Read ULWordCount x U32s from ancBuffer...
1063  if (!ancBuffer.GetU32s (U32s, /*U32Offset=*/0, /*maxU32sToGet=*/ULWordCount))
1064  {
1065  RCVFAIL("On RTP pkt " << DEC(RTPPacketCount) << ", GetU32s(" << DEC(ULWordCount) << ") at: " << ancBuffer.AsString(40));
1066  return AJA_STATUS_BADBUFFERSIZE; // Ran off the end?
1067  }
1068 
1069  retries = 0; // Reset our retry counter when we get a good header
1070 
1071  // Process the full RTP packet U32s...
1072  result = outPackets.AddReceivedAncillaryData(U32s);
1073  if (AJA_FAILURE(result))
1074  break; // Done -- failed!
1075 
1076  if (!outPackets.AllowMultiRTPReceive())
1077  break; // Only one RTP packet allowed -- done -- success!
1078  } //
1079  else
1080  ULWordCount = 1; // No RTP header found -- move ahead 1 x U32
1081 
1082  // Move "ancBuffer" forward inside "inAncBuffer" to check for another RTP packet...
1083  ULWordOffset += ULWordCount;
1084  ancBuffer.Set (inAncBuffer.GetHostAddress(ULWord(ULWordOffset * sizeof(uint32_t))), // Increment startAddress
1085  inAncBuffer.GetByteCount() - ULWordOffset * sizeof(uint32_t)); // Decrement byteCount
1086  RCVDBG("Moved buffer " << inAncBuffer << " forward by " << DEC(ULWordCount) << " U32s: " << ancBuffer.AsString(20));
1087  } // loop til no more RTP packets found
1088  } // else RTP
1089 
1090  const uint32_t pktsAdded (outPackets.CountAncillaryData() - origPktCount);
1091  if (AJA_SUCCESS(result))
1092  {LOGMYDEBUG("Success: " << DEC(pktsAdded) << " pkts added");}
1093  else
1094  LOGMYERROR(AJAStatusToString(result) << ": " << DEC(pktsAdded) << " pkts added");
1095  return result;
1096 
1097 } // AddFromDeviceAncBuffer
1098 
1099 // STATIC
1101  AJAAncillaryList & outPackets,
1102  const uint32_t inFrameNum)
1103 {
1104  //uint32_t RTPPacketCount (0); // Number of packets encountered
1105  const uint32_t origPktCount (outPackets.CountAncillaryData());
1106  AJAStatus result (AJA_STATUS_SUCCESS);
1107 
1108 
1109  result = outPackets.AddReceivedAuxiliaryData (inAuxBuffer, inFrameNum);
1110  if (result == AJA_STATUS_NULL)
1111  result = AJA_STATUS_SUCCESS; // A NULL/empty buffer is not an error
1112 
1113  const uint32_t pktsAdded (outPackets.CountAncillaryData() - origPktCount);
1114  if (AJA_SUCCESS(result))
1115  {LOGMYDEBUG("Success: " << DEC(pktsAdded) << " pkts added");}
1116  else
1117  LOGMYERROR(AJAStatusToString(result) << ": " << DEC(pktsAdded) << " pkts added");
1118  return result;
1119 
1120 } // AddFromDeviceAuxBuffer
1121 
1122 
1123 // STATIC
1125  const NTV2Buffer & inF2AncBuffer,
1126  AJAAncillaryList & outPackets,
1127  const uint32_t inFrameNum) // STATIC
1128 {
1129  outPackets.Clear();
1130  AJAStatus resultF1(AJA_STATUS_SUCCESS), resultF2(AJA_STATUS_SUCCESS);
1131  if (inF1AncBuffer)
1132  resultF1 = AddFromDeviceAncBuffer(inF1AncBuffer, outPackets, inFrameNum);
1133  if (inF2AncBuffer) //Unnecessary to extract from empty buffer, and prevents 0 Packets debug message.
1134  resultF2 = AddFromDeviceAncBuffer(inF2AncBuffer, outPackets, inFrameNum);
1135  if (AJA_FAILURE(resultF1))
1136  return resultF1;
1137  if (AJA_FAILURE(resultF2))
1138  return resultF2;
1139  return AJA_STATUS_SUCCESS;
1140 }
1141 
1143  const NTV2Buffer & inF2AuxBuffer,
1144  AJAAncillaryList & outPackets,
1145  const uint32_t inFrameNum) // STATIC
1146 {
1147  outPackets.Clear();
1148  AJAStatus resultF1,resultF2;
1149  resultF1 = resultF2 = AJA_STATUS_SUCCESS;
1150  resultF1 = AddFromDeviceAuxBuffer(inF1AuxBuffer, outPackets, inFrameNum);
1151  if (inF2AuxBuffer) //Unnecessary to extract from empty buffer, and prevents 0 Packets debug message.
1152  resultF2 = AddFromDeviceAuxBuffer(inF2AuxBuffer, outPackets, inFrameNum);
1153  if (AJA_FAILURE(resultF1))
1154  return resultF1;
1155  if (AJA_FAILURE(resultF2))
1156  return resultF2;
1157  return AJA_STATUS_SUCCESS;
1158 }
1159 
1160 static const size_t MAX_RTP_PKT_LENGTH_BYTES (0x0000FFFF); // 65535 max
1161 static const size_t MAX_RTP_PKT_LENGTH_WORDS ((MAX_RTP_PKT_LENGTH_BYTES+1) / sizeof(uint32_t) - 1); // 16383 max
1162 static const uint32_t MAX_ANC_PKTS_PER_RTP_PKT (0x000000FF); // 255 max
1163 
1164 
1166  AJAAncPktCounts & outF1AncCounts, AJAAncPktCounts & outF2AncCounts,
1167  const bool inIsProgressive, const uint32_t inF2StartLine)
1168 {
1169  AJAStatus result (AJA_STATUS_SUCCESS);
1170  uint32_t actF1PktCnt (0);
1171  uint32_t actF2PktCnt (0);
1172  uint32_t pktNdx (0);
1173  size_t oldPktLengthWords (0);
1174  unsigned countOverflows (0);
1175  size_t overflowWords (0);
1176 
1177  // Reserve space in AJAU32Pkts vectors...
1178  outF1U32Pkts.reserve(CountAncillaryData()); outF1U32Pkts.clear();
1179  outF2U32Pkts.reserve(CountAncillaryData()); outF2U32Pkts.clear();
1180  outF1AncCounts.clear(); outF2AncCounts.clear();
1181 
1182  ULWordSequence F1U32s, F2U32s;
1183  F1U32s.reserve(MAX_RTP_PKT_LENGTH_WORDS);
1184  if (!inIsProgressive)
1185  F2U32s.reserve(MAX_RTP_PKT_LENGTH_WORDS);
1186  F1U32s.clear(); F2U32s.clear();
1187 
1188  // Generate transmit data for each of my packets...
1189  for (pktNdx = 0; pktNdx < CountAncillaryData(); pktNdx++)
1190  {
1191  AJAAncillaryData * pAncData (GetAncillaryDataAtIndex(pktNdx));
1192  if (!pAncData)
1193  return AJA_STATUS_NULL; // Fail
1194 
1195  AJAAncillaryData & pkt (*pAncData);
1197  {
1198  LOGMYDEBUG("Skipped Pkt " << DEC(pktNdx+1) << " of " << DEC(CountAncillaryData()) << " -- Analog/Raw");
1199  continue; // Skip analog/raw packets
1200  }
1201 
1202  if (inIsProgressive || pkt.GetLocationLineNumber() < inF2StartLine)
1203  {
1204  if (actF1PktCnt >= MAX_ANC_PKTS_PER_RTP_PKT)
1205  {
1206  countOverflows++;
1207  LOGMYDEBUG("Skipped pkt " << DEC(pktNdx+1) << " of " << DEC(CountAncillaryData()) << ", F1 RTP pkt count overflow: " << pkt.AsString(16));
1208  continue;
1209  }
1210  oldPktLengthWords = F1U32s.size();
1211  result = pkt.GenerateTransmitData(F1U32s);
1212  if (AJA_FAILURE(result))
1213  break; // Bail!
1214  if (F1U32s.size() > MAX_RTP_PKT_LENGTH_WORDS)
1215  {
1216  overflowWords += F1U32s.size() - oldPktLengthWords;
1217  LOGMYDEBUG("Skipped pkt " << DEC(pktNdx+1) << " of " << DEC(CountAncillaryData()) << ": F1 RTP pkt length overflow: " << pkt.AsString(16));
1218  while (F1U32s.size() > oldPktLengthWords)
1219  F1U32s.pop_back();
1220  continue;
1221  }
1222  actF1PktCnt++;
1223  if (AllowMultiRTPTransmit())
1224  { // MULTI RTP PKTS
1225  outF1U32Pkts.push_back(F1U32s); // Append it
1226  outF1AncCounts.push_back(1); // One SMPTE Anc packet per RTP packet
1227  XMTDBG("F1 pkt " << DEC(actF1PktCnt) << ": " << ::ULWordSequenceToStringBE(F1U32s) << " (BigEndian)");
1228  F1U32s.clear(); // Start current pkt over
1229  }
1230  }
1231  else
1232  {
1233  if (actF2PktCnt >= MAX_ANC_PKTS_PER_RTP_PKT)
1234  {
1235  countOverflows++;
1236  LOGMYDEBUG("Skipped pkt " << DEC(pktNdx+1) << " of " << DEC(CountAncillaryData()) << ": F2 RTP pkt count overflow: " << pkt.AsString(16));
1237  continue;
1238  }
1239  oldPktLengthWords = F2U32s.size();
1240  result = pkt.GenerateTransmitData(F2U32s);
1241  if (AJA_FAILURE(result))
1242  break; // Bail!
1243  if (AJA_SUCCESS(result) && F2U32s.size() > MAX_RTP_PKT_LENGTH_WORDS)
1244  {
1245  overflowWords += F2U32s.size() - oldPktLengthWords;
1246  LOGMYDEBUG("Skipped pkt " << DEC(pktNdx+1) << " of " << DEC(CountAncillaryData()) << ": F2 RTP pkt length overflow: " << pkt.AsString(16));
1247  while (F2U32s.size() > oldPktLengthWords)
1248  F2U32s.pop_back();
1249  continue;
1250  }
1251  actF2PktCnt++;
1252  if (AllowMultiRTPTransmit())
1253  { // MULTI RTP PKTS
1254  outF2U32Pkts.push_back(F2U32s); // Append it
1255  outF2AncCounts.push_back(1); // One SMPTE Anc packet per RTP packet
1256  XMTDBG("F2 pkt " << DEC(actF2PktCnt) << ": " << ::ULWordSequenceToStringBE(F2U32s) << " (BigEndian)");
1257  F2U32s.clear(); // Start current pkt over
1258  }
1259  }
1260  } // for each SMPTE Anc packet
1261 
1262  if (AJA_FAILURE(result))
1263  {LOGMYERROR(::AJAStatusToString(result) << ": Pkt " << DEC(pktNdx+1) << " of " << DEC(CountAncillaryData()) << " failed in GenerateTransmitData: " << ::AJAStatusToString(result));}
1264  else if (!AllowMultiRTPTransmit())
1265  { // SINGLE RTP PKT
1266  outF1U32Pkts.push_back(F1U32s); // Append all F1
1267  outF1AncCounts.push_back(uint8_t(actF1PktCnt)); // Total F1 SMPTE Anc packets in this one F1 RTP packet
1268  outF2U32Pkts.push_back(F2U32s); // Append all F2
1269  outF2AncCounts.push_back(uint8_t(actF2PktCnt)); // Total F2 SMPTE Anc packets in this one F2 RTP packet
1270  }
1271  if (overflowWords && countOverflows)
1272  {LOGMYWARN("Overflow: " << DEC(countOverflows) << " pkts skipped, " << DEC(overflowWords) << " U32s dropped");}
1273  else if (overflowWords)
1274  {LOGMYWARN("Data overflow: " << DEC(overflowWords) << " U32s dropped");}
1275  else if (countOverflows)
1276  LOGMYWARN("Packet overflow: " << DEC(countOverflows) << " pkts skipped");
1277  XMTDBG("F1 (Content Only): " << outF1U32Pkts);
1278  XMTDBG("F2 (Content Only): " << outF2U32Pkts);
1279  return result;
1280 } // GetRTPPackets
1281 
1282 
1283 
1287 
1288 
1289 AJAStatus AJAAncillaryList::GetAncillaryDataTransmitSize (const bool bProgressive, const uint32_t f2StartLine, uint32_t & ancSizeF1, uint32_t & ancSizeF2)
1290 {
1291  AJAStatus status (AJA_STATUS_SUCCESS);
1292  uint32_t f1Size (0);
1293  uint32_t f2Size (0);
1294 
1295  for (AJAAncDataListConstIter it(m_ancList.begin()); it != m_ancList.end(); ++it)
1296  {
1297  AJAAncillaryData * pAncData (*it);
1298  uint32_t packetSize (0);
1299  status = pAncData->GetRawPacketSize (packetSize);
1300  if (status != AJA_STATUS_SUCCESS)
1301  break;
1302 
1303  if (bProgressive || pAncData->GetLocationLineNumber () < f2StartLine)
1304  f1Size += packetSize;
1305  else
1306  f2Size += packetSize;
1307  }
1308 
1309  ancSizeF1 = f1Size;
1310  ancSizeF2 = f2Size;
1311  return status;
1312 }
1313 
1314 
1315 AJAStatus AJAAncillaryList::GetAncillaryDataTransmitData (const bool bProgressive, const uint32_t f2StartLine, uint8_t * pF1AncData, const uint32_t inMaxF1Data, uint8_t * pF2AncData, const uint32_t inMaxF2Data)
1316 {
1317  NTV2Buffer F1Buffer(pF1AncData, inMaxF1Data), F2Buffer(pF2AncData, inMaxF2Data);
1318  if (!F1Buffer.IsNULL())
1319  NTV2_ASSERT(F1Buffer.IsProvidedByClient());
1320  if (!F2Buffer.IsNULL())
1321  NTV2_ASSERT(F2Buffer.IsProvidedByClient());
1322  return GetTransmitData(F1Buffer, F2Buffer, bProgressive, f2StartLine);
1323 }
1324 
1325 
1327  const bool inIsProgressive, const uint32_t inF2StartLine)
1328 {
1329  AJAStatus status (AJA_STATUS_SUCCESS);
1330  size_t maxF1Data(F1Buffer), maxF2Data(F2Buffer);
1331  uint8_t *pF1AncData(F1Buffer), *pF2AncData(F2Buffer);
1332 
1333  F1Buffer.Fill(uint64_t(0)); F2Buffer.Fill(uint64_t(0));
1334 
1335  // I need to be in ascending line order...
1337 
1338  // Generate transmit data for each of my packets...
1339  for (AJAAncDataListConstIter it(m_ancList.begin()); it != m_ancList.end(); ++it)
1340  {
1341  uint32_t pktSize(0);
1342  AJAAncillaryData * pPkt(*it);
1343  if (!pPkt)
1344  {status = AJA_STATUS_NULL; break;} // Fail
1345 
1346  if (inIsProgressive || pPkt->GetLocationLineNumber() < inF2StartLine)
1347  {
1348  if (pF1AncData && maxF1Data)
1349  {
1350  status = pPkt->GenerateTransmitData(pF1AncData, maxF1Data, pktSize);
1351  if (AJA_FAILURE(status))
1352  break;
1353 
1354  pF1AncData += pktSize;
1355  maxF1Data -= pktSize;
1356  }
1357  }
1358  else if (pF2AncData && maxF2Data)
1359  {
1360  status = pPkt->GenerateTransmitData(pF2AncData, maxF2Data, pktSize);
1361  if (AJA_FAILURE(status))
1362  break;
1363 
1364  pF2AncData += pktSize;
1365  maxF2Data -= pktSize;
1366  }
1367  } // for each of my anc packets
1368  return status;
1369 }
1370 
1371 
1373 {
1374  if (inFrameBuffer.IsNULL())
1375  {
1376  LOGMYERROR("AJA_STATUS_NULL: null frame buffer");
1377  return AJA_STATUS_NULL;
1378  }
1379  if (!inFormatDesc.IsValid())
1380  {
1381  LOGMYERROR("AJA_STATUS_BAD_PARAM: Invalid format descriptor");
1382  return AJA_STATUS_BAD_PARAM;
1383  }
1384  if (!inFormatDesc.IsVANC())
1385  {
1386  LOGMYERROR("AJA_STATUS_BAD_PARAM: Not a VANC geometry");
1387  return AJA_STATUS_BAD_PARAM;
1388  }
1389  if (inFormatDesc.GetPixelFormat() != NTV2_FBF_10BIT_YCBCR && inFormatDesc.GetPixelFormat() != NTV2_FBF_8BIT_YCBCR)
1390  {
1391  LOGMYERROR("AJA_STATUS_UNSUPPORTED: unsupported pixel format: " << inFormatDesc);
1392  return AJA_STATUS_UNSUPPORTED;
1393  }
1394  if (!CountAncillaryData())
1395  {
1396  LOGMYWARN("List is empty");
1397  return AJA_STATUS_SUCCESS;
1398  }
1399 
1400  // I need to be in ascending line order...
1402 
1403  // BRUTE-FORCE METHOD -- NOT VERY EFFICIENT
1404  const bool isSD (inFormatDesc.IsSD());
1405  AJAAncillaryList failures, successes;
1406  set <uint16_t> lineOffsetsWritten;
1407 
1408  // For each VANC line...
1409  for (UWord fbLineOffset(0); fbLineOffset < inFormatDesc.GetFirstActiveLine(); fbLineOffset++)
1410  {
1411  ULWord smpteLine (0); bool isF2 (false);
1412  inFormatDesc.GetSMPTELineNumber (fbLineOffset, smpteLine, isF2);
1413 
1414  // Look for non-HANC packets destined for this line...
1415  for (AJAAncDataListConstIter iter(m_ancList.begin()); (iter != m_ancList.end()) && *iter; ++iter)
1416  {
1417  bool muxedOK (false);
1418  AJAAncillaryData & ancData (**iter);
1419  const AJAAncDataLoc & loc (ancData.GetDataLocation());
1420  UWordSequence u16PktComponents;
1421  if (ancData.GetDataCoding() != AJAAncDataCoding_Digital) // Ignore "Raw" or "Analog" or "Unknown" packets
1422  continue;
1423  if (loc.GetDataSpace() != AJAAncDataSpace_VANC) // Ignore "HANC" or "Unknown" packets
1424  {
1425  //LOGMYWARN("Skipping non-VANC packet " << ancData);
1426  continue;
1427  }
1428  if (loc.GetLineNumber() != smpteLine) // Wrong line number
1429  {
1430  //LOGMYWARN("Skipping packet not destined for line " << DEC(smpteLine) << " " << loc);
1431  continue;
1432  }
1433  if (!IS_VALID_AJAAncDataChannel(loc.GetDataChannel())) // Bad data channel
1434  {
1435  LOGMYWARN("Skipped packet with invalid data channel " << loc);
1436  continue;
1437  }
1438 
1439  // For v210 buffers, generate 10-bit packet data and put into u16 vector...
1440  muxedOK = AJA_SUCCESS(ancData.GenerateTransmitData(u16PktComponents));
1441  if (muxedOK)
1442  {
1443  if (inFormatDesc.GetPixelFormat() == NTV2_FBF_8BIT_YCBCR) // 2vuy buffers are simple -- just copy the data
1444  {
1445  uint8_t * pLine (reinterpret_cast<uint8_t*>(inFormatDesc.GetWriteableRowAddress(inFrameBuffer.GetHostPointer(), fbLineOffset)));
1446  if (isSD)
1447  { // SD overwrites both Y & C channels in the frame buffer:
1448  for (unsigned ndx(0); ndx < u16PktComponents.size(); ndx++)
1449  pLine[ndx] = uint8_t(u16PktComponents[ndx] & 0xFF);
1450  }
1451  else
1452  { // HD overwrites only the Y or C channel data in the frame buffer:
1453  unsigned dstNdx(loc.IsLumaChannel() ? 1 : 0);
1454  for (unsigned srcNdx(0); srcNdx < u16PktComponents.size(); srcNdx++)
1455  pLine[dstNdx + 2*srcNdx] = uint8_t(u16PktComponents[srcNdx] & 0x00FF);
1456  }
1457  } // if 2vuy
1458  else
1459  {
1460  if (isSD)
1461  { // For SD, just pack the u16 components into the buffer...
1462  while (u16PktComponents.size() < 12 || u16PktComponents.size() % 12) // YUVComponentsTo10BitYUVPackedBuffer fails if packing fewer than 12 words
1463  u16PktComponents.push_back(0x040); // SMPTE black
1464  muxedOK = ::YUVComponentsTo10BitYUVPackedBuffer (u16PktComponents, inFrameBuffer, inFormatDesc, fbLineOffset);
1465  }
1466  else
1467  { // HD overwrites only the Y or C channel data:
1468  UWordSequence YUV16Line;
1469  unsigned dstNdx (loc.IsLumaChannel() ? 1 : 0);
1470 
1471  // Read original Y+C components from FB...
1472  muxedOK = UnpackLine_10BitYUVtoU16s (YUV16Line, inFrameBuffer, inFormatDesc, fbLineOffset);
1473  //cerr << "WriteVANCData|orig: +" << DEC0N(fbLineOffset,2) << ": "; inFormatDesc.PrintSMPTELineNumber(cerr, fbLineOffset); cerr << ":" << endl << YUV16Line << endl;
1474 
1475  // Patch the Y or C channel...
1476  if (muxedOK)
1477  for (unsigned srcNdx(0); srcNdx < u16PktComponents.size(); srcNdx++)
1478  YUV16Line[dstNdx + 2*srcNdx] = u16PktComponents[srcNdx] & 0x03FF;
1479  //cerr << "WriteVANCData|modi: +" << DEC0N(fbLineOffset,2) << ": "; inFormatDesc.PrintSMPTELineNumber(cerr, fbLineOffset); cerr << ":" << endl << YUV16Line << endl;
1480 
1481  // Repack the patched YUV16 line back into the FB...
1482  if (muxedOK)
1483  {
1484  while (YUV16Line.size() < 12 || YUV16Line.size() % 12) // YUVComponentsTo10BitYUVPackedBuffer fails if packing fewer than 12 words
1485  YUV16Line.push_back(0x040); // SMPTE black
1486  muxedOK = ::YUVComponentsTo10BitYUVPackedBuffer (YUV16Line, inFrameBuffer, inFormatDesc, fbLineOffset);
1487  }
1488  } // else HD
1489  } // else v210
1490  } // if GenerateTransmitData OK
1491 
1492  // TBD: NEED TO TAKE INTO CONSIDERATION loc.GetHorizontalOffset()
1493 
1494  if (muxedOK)
1495  {
1496  lineOffsetsWritten.insert(uint16_t(fbLineOffset)); // Remember which FB line offsets we overwrote
1497  successes.AddAncillaryData(ancData);
1498  }
1499  else
1500  failures.AddAncillaryData(ancData);
1501  } // for each packet
1502  } // for each VANC line
1503 
1504  // Any analog packets?
1505  for (AJAAncDataListConstIter iter(m_ancList.begin()); (iter != m_ancList.end()) && *iter; ++iter)
1506  {
1507  bool success (inFormatDesc.IsSD());
1508  AJAAncillaryData & ancData (**iter);
1509  const AJAAncDataLoc & loc (ancData.GetDataLocation());
1510  ULWord lineOffset (0);
1511  if (!ancData.IsRaw())
1512  continue; // Ignore "Digital" or "Unknown" packets
1513 
1514  if (success)
1515  success = inFormatDesc.GetLineOffsetFromSMPTELine (loc.GetLineNumber(), lineOffset);
1516  if (success && lineOffsetsWritten.find(uint16_t(lineOffset)) != lineOffsetsWritten.end())
1517  success = false; // Line already written -- "analog" data overwrites entire line
1518  if (success)
1519  {
1520  if (inFormatDesc.GetPixelFormat() == NTV2_FBF_8BIT_YCBCR)
1521  ::memcpy(inFormatDesc.GetWriteableRowAddress(inFrameBuffer.GetHostPointer(), lineOffset), ancData.GetPayloadData(), ancData.GetDC()); // '2vuy' -- straight copy
1522  else
1523  {
1524  UWordSequence pktComponentData;
1525  success = AJA_SUCCESS(ancData.GenerateTransmitData(pktComponentData));
1526  if (success)
1527  success = ::YUVComponentsTo10BitYUVPackedBuffer (pktComponentData, inFrameBuffer, inFormatDesc, UWord(lineOffset));
1528  }
1529  }
1530 
1531  if (success)
1532  {
1533  lineOffsetsWritten.insert(uint16_t(lineOffset)); // Remember which FB line offsets we overwrote
1534  successes.AddAncillaryData(ancData);
1535  }
1536  else
1537  failures.AddAncillaryData(ancData);
1538  } // for each Analog packet
1539 
1540  if (failures.CountAncillaryData())
1541  LOGMYWARN("FAILURES: " << failures);
1542  if (successes.CountAncillaryData())
1543  LOGMYDEBUG("SUCCESSES: " << successes);
1544 
1545  // At least one success is considered SUCCESS.
1546  // Zero successes and one or more failures is considered FAIL...
1547  return successes.CountAncillaryData() == 0 && failures.CountAncillaryData() > 0 ? AJA_STATUS_FAIL : AJA_STATUS_SUCCESS;
1548 } // WriteVANCData
1549 
1550 
1551 // STATIC
1552 AJAStatus AJAAncillaryList::WriteRTPPackets (NTV2Buffer & theBuffer, uint32_t & outBytesWritten,
1553  const AJAU32Pkts & inRTPPkts, const AJAAncPktCounts & inAncCounts,
1554  const bool inIsF2, const bool inIsProgressive)
1555 {
1556  const ULWord totPkts (ULWord(inRTPPkts.size()));
1557  const string sFld (inIsF2 ? " F2" : " F1");
1558  const string sPrg (inIsProgressive ? " Prg" : " Int");
1559  ULWord u32offset(0), pktNum(1);
1560 
1561  outBytesWritten = 0;
1562  if (inRTPPkts.size() != inAncCounts.size())
1563  {LOGMYERROR(DEC(inRTPPkts.size()) << " RTP pkt(s) != " << DEC(inAncCounts.size()) << " anc count(s)"); return AJA_STATUS_BAD_PARAM;}
1564 
1565  // For each RTP Packet...
1566  for (AJAU32PktsConstIter RTPPktIter(inRTPPkts.begin()); RTPPktIter != inRTPPkts.end(); pktNum++)
1567  {
1568  AJARTPAncPayloadHeader RTPHeader; // The RTP packet header to be built
1569  ULWordSequence RTPHeaderU32s; // The RTP packet header expressed as a sequence of 5 x U32s
1570  const ULWordSequence & origRTPPkt(*RTPPktIter); // The original RTP packet data contents, a sequence of U32s
1571  const bool isLastRTPPkt (++RTPPktIter == inRTPPkts.end()); // Last RTP packet?
1572  const size_t totalRTPPktBytes(AJARTPAncPayloadHeader::GetHeaderByteCount() // RTP packet size,
1573  + origRTPPkt.size() * sizeof(uint32_t)); // including header, in bytes
1574  ostringstream pktNumInfo;
1575  pktNumInfo << " for RTP pkt " << DEC(pktNum) << " of " << DEC(totPkts);
1576 
1577  // Set the RTP Packet Header's info...
1578  if (inIsProgressive)
1579  RTPHeader.SetProgressive();
1580  else if (inIsF2)
1581  RTPHeader.SetField2();
1582  else
1583  RTPHeader.SetField1();
1584  RTPHeader.SetEndOfFieldOrFrame(isLastRTPPkt);
1585  RTPHeader.SetAncPacketCount(uint8_t(inAncCounts.at(pktNum-1))); // Use provided Anc count
1586  RTPHeader.SetPayloadLength(uint16_t(origRTPPkt.size() * sizeof(uint32_t)));
1587  // Playout: Firmware looks for full RTP pkt bytecount in LS 16 bits of SequenceNumber in RTP header:
1588  RTPHeader.SetSequenceNumber(uint32_t(totalRTPPktBytes) & 0x0000FFFF);
1589 
1590  // Convert RTP header object into 5 x U32s...
1591  RTPHeader.WriteToULWordVector(RTPHeaderU32s, true);
1592  NTV2_ASSERT(RTPHeaderU32s.size() == AJARTPAncPayloadHeader::GetHeaderWordCount());
1593 
1594  // Write RTP header into theBuffer...
1595  if (theBuffer)
1596  {
1597  if (!theBuffer.PutU32s(RTPHeaderU32s, u32offset))
1598  {LOGMYERROR("RTP hdr WriteBuffer failed for buffer " << theBuffer << " at u32offset=" << DEC(u32offset)
1599  << pktNumInfo.str()); return AJA_STATUS_FAIL;}
1600  }
1601  u32offset += ULWord(RTPHeaderU32s.size()); // Move "write head" to just past end of RTP header
1602 
1603  // Write RTP packet contents into theBuffer...
1604  if (theBuffer)
1605  {
1606  if (!theBuffer.PutU32s(origRTPPkt, u32offset))
1607  {LOGMYERROR("PutU32s failed writing " << DEC(origRTPPkt.size()) << " U32s in buffer " << theBuffer << " at u32offset=" << DEC(u32offset)
1608  << pktNumInfo.str()); return AJA_STATUS_FAIL;}
1609  LOGMYDEBUG("PutU32s OK @u32offset=" << xHEX0N(u32offset,4) << ": " << RTPHeader << pktNumInfo.str());
1610  }
1611 
1612  // Move "write head" to just past where this RTP packet's data ended...
1613  u32offset += ULWord(origRTPPkt.size());
1614 
1615  // JeffL: IP Anc inserters expect subsequent RTP packets to start on a 64-bit/8-byte word boundary.
1616  if (u32offset & 1L) // If it's not even...
1617  u32offset++; // ...then make it even!
1618  } // for each RTP packet
1619 
1620  outBytesWritten = u32offset * ULWord(sizeof(uint32_t));
1621  if (theBuffer)
1622  LOGMYDEBUG(DEC(totPkts) << " RTP pkt(s), " << DEC(u32offset) << " U32s (" << DEC(outBytesWritten)
1623  << " bytes) written for" << sFld << sPrg);
1624  return AJA_STATUS_SUCCESS;
1625 }
1626 
1627 
1629  const bool inIsProgressive, const uint32_t inF2StartLine)
1630 {
1631  AJAStatus result (AJA_STATUS_SUCCESS);
1632  AJAU32Pkts F1U32Pkts, F2U32Pkts; // 32-bit network-byte-order data
1633  AJAAncPktCounts F1AncCounts, F2AncCounts; // Per-RTP packet anc packet counts
1634  uint32_t byteCount(0); // Not used
1635 
1636  // I need to be in ascending line order...
1637  F1Buffer.Fill(uint64_t(0)); F2Buffer.Fill(uint64_t(0));
1639 
1640  // Get F1 & F2 xmit RTP U32 words (and SMPTE anc packet counts for each RTP packet)...
1641  result = GetRTPPackets (F1U32Pkts, F2U32Pkts, F1AncCounts, F2AncCounts, inIsProgressive, inF2StartLine);
1642  if (AJA_FAILURE(result))
1643  return result;
1644 
1645  /*
1646  ostringstream oss; oss << "Anc Counts: F1="; for (size_t ndx(0); ndx < F1AncCounts.size(); ndx++) oss << (ndx?"|":"[") << DEC(uint16_t(F1AncCounts.at(ndx)));
1647  oss << "] F2="; for (size_t ndx(0); ndx < F2AncCounts.size(); ndx++) oss << (ndx?"|":"[") << DEC(uint16_t(F2AncCounts.at(ndx))); oss << "]";
1648  XMTDBG(oss.str());
1649  */
1650 
1651  // Write the F1 buffer...
1652  result = WriteRTPPackets (F1Buffer, byteCount, F1U32Pkts, F1AncCounts, /*isF2*/false, inIsProgressive);
1653  if (AJA_FAILURE(result))
1654  return result;
1655 
1656  // Write the F2 buffer...
1657  if (!inIsProgressive)
1658  result = WriteRTPPackets (F2Buffer, byteCount, F2U32Pkts, F2AncCounts, /*isF2*/true, inIsProgressive);
1659 
1660  return result;
1661 
1662 } // GetIPTransmitData
1663 
1664 
1665 AJAStatus AJAAncillaryList::GetIPTransmitDataLength (uint32_t & outF1ByteCount, uint32_t & outF2ByteCount,
1666  const bool inIsProgressive, const uint32_t inF2StartLine)
1667 {
1668  outF1ByteCount = outF2ByteCount = 0;
1669 
1670  // Get F1 & F2 xmit RTP U32 words...
1671  AJAU32Pkts F1U32Pkts, F2U32Pkts; // U32 network-byte-order data
1672  AJAAncPktCounts F1AncCounts, F2AncCounts; // Per-RTP packet anc packet counts
1673  AJAStatus result (GetRTPPackets (F1U32Pkts, F2U32Pkts, F1AncCounts, F2AncCounts, inIsProgressive, inF2StartLine));
1674  if (AJA_FAILURE(result))
1675  return result;
1676 
1677  NTV2Buffer nullBuffer; // An empty buffer tells WriteRTPPackets to just calculate byteCount...
1678  result = WriteRTPPackets (nullBuffer, outF1ByteCount, F1U32Pkts, F1AncCounts, /*isF2*/false, inIsProgressive);
1679  if (AJA_SUCCESS(result) && !inIsProgressive)
1680  result = WriteRTPPackets (nullBuffer, outF2ByteCount, F2U32Pkts, F2AncCounts, /*isF2*/true, inIsProgressive);
1681 
1682  return result;
1683 }
1684 
1685 
1686 ostream & AJAAncillaryList::Print (ostream & inOutStream, const bool inDumpPayload) const
1687 {
1688  unsigned num (0);
1689  inOutStream << DEC(CountAncillaryData()) << " pkts:" << endl;
1690  for (AJAAncDataListConstIter it(m_ancList.begin()); it != m_ancList.end(); )
1691  {
1692  AJAAncillaryData * pPkt(*it);
1693  inOutStream << "Pkt" << DEC0N(++num,3) << ": " << pPkt->AsString(inDumpPayload ? 16 : 0);
1694  if (++it != m_ancList.end())
1695  inOutStream << endl;
1696  }
1697  return inOutStream;
1698 }
1699 
1700 // Copies GUMP from inSrc to outDst buffers, but removes ATC, VPID, EDH, VITC & analog packets
1702 {
1703  if (!inSrc || !outDst)
1704  return false; // Buffers must be valid
1705  if (inSrc.GetByteCount() > outDst.GetByteCount())
1706  return false; // Target buffer must be at least as large as source buffer
1707 
1708  uint8_t * srcPtr = inSrc;
1709  uint8_t * ptr = srcPtr;
1710  size_t srcBufSize = inSrc;
1711  uint8_t * tgtPtr = outDst;
1712  size_t uncopied = 0;
1713 // size_t numStripped = 0;
1714 // size_t bytesRemoved = 0;
1715  const size_t kGUMPHeaderSize(7);
1716 
1717  for (size_t ndx(0); ndx < srcBufSize; )
1718  {
1719  if (ptr[0] == 0xff && (ndx + kGUMPHeaderSize) < srcBufSize)
1720  {
1721  bool bFiltered{false};
1722  const uint8_t payloadSize(ptr[5]);
1723 
1724  if (ptr[1] & 0x40) // "Analog/raw"
1725  bFiltered = true;
1726  else if (ptr[3] == 0x60 && ptr[4] == 0x60 && payloadSize == 16) // ATC
1727  bFiltered = true;
1728  else if (ptr[3] == 0x41 && ptr[4] == 0x01 && payloadSize == 4) // SMPTE 352 - VPID
1729  bFiltered = true;
1730  else if (ptr[3] == 0xF4 && ptr[4] == 0x00 && payloadSize == 16) // RP165 EDH
1731  bFiltered = true;
1732  else // VITC
1733  {
1734  const uint16_t lineNum (uint16_t((ptr[1] & 0x0F) << 7) + uint16_t(ptr[2] & 0x7F));
1735  bFiltered = (ptr[1] & 0x40) && (lineNum == 14 || lineNum == 277);
1736  }
1737 
1738  if (bFiltered)
1739  { // Copy everything that came before filtered content...
1740  if (uncopied)
1741  ::memcpy(tgtPtr, srcPtr, uncopied);
1742 
1743  // Skip srcPtr past the filtered content...
1744  srcPtr += uncopied + payloadSize + kGUMPHeaderSize;
1745  tgtPtr += uncopied;
1746  ndx += payloadSize + kGUMPHeaderSize;
1747  ptr = srcPtr;
1748  uncopied = 0;
1749 // numStripped++; bytesRemoved += size_t(payloadSize) + kGUMPHeaderSize;
1750  }
1751  else
1752  {
1753  ptr += payloadSize + kGUMPHeaderSize;
1754  ndx += payloadSize + kGUMPHeaderSize;
1755  uncopied += payloadSize + kGUMPHeaderSize;
1756  }
1757  }
1758  else
1759  {ptr++; ndx++; uncopied++;}
1760  } // for each byte in source buffer
1761 
1762  if (uncopied) // Any uncopied remainder?
1763  ::memcpy(tgtPtr, srcPtr, uncopied); // Copy last uncopied bytes
1764  // cout << DEC(numStripped) << " pkts removed, " << DEC(bytesRemoved) << " bytes removed" << endl;
1765  return true;
1766 } // StripNativeInserterPackets
1767 
1768 
1772 
1775 
1776 
1778 {
1780  gAnalogTypeMap.clear();
1781  return AJA_STATUS_SUCCESS;
1782 }
1783 
1784 
1786 {
1788  gAnalogTypeMap = inMap;
1789  return AJA_STATUS_SUCCESS;
1790 }
1791 
1792 
1794 {
1796  outMap = gAnalogTypeMap;
1797  return AJA_STATUS_SUCCESS;
1798 }
1799 
1800 
1802 {
1804  gAnalogTypeMap.erase(inLineNum); // In case someone has already set this line
1805  if (inAncType == AJAAncDataType_Unknown)
1806  return AJA_STATUS_SUCCESS; // A non-entry is the same as AJAAncDataType_Unknown
1807  else if (IS_VALID_AJAAncDataType(inAncType))
1808  gAnalogTypeMap[inLineNum] = inAncType;
1809  else
1810  return AJA_STATUS_BAD_PARAM;
1811  return AJA_STATUS_SUCCESS;
1812 }
1813 
1814 
1816 {
1819  if (!gAnalogTypeMap.empty ())
1820  {
1821  AJAAncillaryAnalogTypeMap::const_iterator it (gAnalogTypeMap.find (inLineNum));
1822  if (it != gAnalogTypeMap.end ())
1823  ancType = it->second;
1824  }
1825  return ancType;
1826 }
static bool SortBySID(AJAAncillaryData *lhs, AJAAncillaryData *rhs)
static size_t GetHeaderByteCount(void)
virtual AJAStatus AddReceivedAuxiliaryData(const NTV2Buffer &inReceivedData, const uint32_t inFrameNum=0)
Parse "raw" HDMI auxillary data bytes received from hardware (ingest) into separate AJAAncillaryData ...
virtual uint8_t GetDID(void) const
std::set< AJAAncPktDIDSID > AJAAncPktDIDSIDSet
Set of distinct packet DID/SIDs (New in SDK 16.0)
Definition: ancillarylist.h:44
#define AJA_SUCCESS(_status_)
Definition: types.h:372
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 ...
virtual AJAStatus AddReceivedAncillaryData(const NTV2Buffer &inReceivedData, const uint32_t inFrameNum=0)
Parse "raw" ancillary data bytes received from hardware (ingest) – see SDI Anc Buffer Data Format –...
virtual AJAStatus GetAncillaryDataTransmitSize(const bool inIsProgressive, const uint32_t inF2StartLine, uint32_t &outF1ByteCount, uint32_t &outF2ByteCount)
Answers with the sizes of the buffers (one for field 1, one for field 2) needed to hold the anc data ...
Declares the AJALock class.
virtual AJAStatus GenerateTransmitData(uint8_t *pBuffer, const size_t inMaxBytes, uint32_t &outPacketSize)
Generates "raw" ancillary data from my internal ancillary data (playback) – see SDI Anc Buffer Data ...
virtual AJAStatus SortListByLocation(void)
Sort the AncillaryDataList by "location", i.e. where in the video (field, line num, HANC/VANC) the data came from or will be inserted to.
virtual uint32_t CountAncillaryData(void) const
Answers with the number of AJAAncillaryData objects I contain (any/all types).
bool YUVComponentsTo10BitYUVPackedBuffer(const std::vector< uint16_t > &inYCbCrLine, NTV2Buffer &inFrameBuffer, const NTV2FormatDescriptor &inDescriptor, const UWord inLineOffset)
Packs up to one raster line of uint16_t YUV components into an NTV2_FBF_10BIT_YCBCR frame buffer...
Definition: ntv2utils.cpp:603
bool UnpackLine_10BitYUVtoUWordSequence(const void *pIn10BitYUVLine, const NTV2FormatDescriptor &inFormatDesc, UWordSequence &out16BitYUVLine)
Unpacks a line of NTV2_FBF_10BIT_YCBCR video into 16-bit-per-component YUV data.
Definition: ntv2utils.cpp:147
virtual AJAStatus GetRawPacketSize(uint32_t &outPacketSize) const
Returns the number of "raw" ancillary data bytes that will be generated by AJAAncillaryData::Generate...
NTV2FrameBufferFormat GetPixelFormat(void) const
#define LOGMYERROR(__x__)
virtual AJAAncillaryData * Clone(void) const
virtual uint8_t GetSID(void) const
virtual AJAAncPktDIDSIDSet GetAncillaryPacketIDs(void) const
static const uint32_t MAX_ANC_PKTS_PER_RTP_PKT(0x000000FF)
AJAAncDataLoc & SetHorizontalOffset(uint16_t inHOffset)
Specifies the horizontal packet position in the raster.
bool IsNULL(void) const
#define DEC0N(__x__, __n__)
NTV2FrameBufferFormat
Identifies a particular video frame buffer pixel format. See Device Frame Buffer Formats for details...
Definition: ntv2enums.h:221
static bool BufferStartsWithRTPHeader(const NTV2Buffer &inBuffer)
AJAStatus
Definition: types.h:380
Ancillary data found between SAV and EAV (.
Declares the AJADebug class.
See 10-Bit YCbCr Format.
Definition: ntv2enums.h:224
virtual AJAAncillaryData * GetAncillaryDataAtIndex(const uint32_t inIndex) const
Answers with the AJAAncillaryData object at the given index.
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
virtual AJAStatus DeleteAncillaryData(AJAAncillaryData *pInAncData)
Removes all copies of the AJAAncillaryData object from me and deletes the object itself.
Only look in luma samples.
#define LOGMYWARN(__x__)
virtual AJAStatus SortListByDID(void)
Sort the AncillaryDataList by DataID (DID) value.
#define AJA_FAILURE(_status_)
Definition: types.h:373
virtual const AJAAncDataLoc & GetDataLocation(void) const
#define LOGMYINFO(__x__)
AJAAncDataType
Identifies the ancillary data types that are known to this module.
Definition: ancillarydata.h:44
ULWordSequence::const_iterator ULWordSequenceConstIter
A handy const iterator for iterating over a ULWordSequence.
static bool gIncludeZeroLengthPackets(false)
ostream & operator<<(ostream &inOutStream, const AJAU32Pkts &inPkts)
virtual bool ReadFromBuffer(const NTV2Buffer &inBuffer)
Resets my current state from the RTP packet header stored in the given buffer. Each 32-bit word in th...
#define ToAJAAncPktDIDSID(_d_, _s_)
Definition: ancillarydata.h:29
struct AJAAncDataLoc AJAAncDataLoc
Defines where the ancillary data can be found within a video stream.
static AJAAncDataType GuessAncillaryDataType(const AJAAncillaryData &inAncData)
Given a generic AJAAncillaryData object, attempts to guess what kind of specific AJAAncillaryData obj...
static AJAStatus GetAnalogAncillaryDataTypeMap(AJAAncillaryAnalogTypeMap &outMap)
Returns a copy of the global Analog Ancillary Data Type map.
virtual std::string AsString(const uint16_t inDumpMaxBytes=0) const
Definition: lock.h:28
uint64_t OrdinalValue(void) const
virtual std::ostream & Print(std::ostream &oss, const bool inDetailed=true) const
Dumps a human-readable description of every packet in my list to the given output stream...
virtual AJAStatus InitAuxWithReceivedData(const uint8_t *pInData, const size_t inMaxBytes, uint32_t &outPacketByteCount)
Initializes me from "raw" ancillary data received from hardware (ingest) – see SDI Anc Buffer Data F...
std::map< uint16_t, AJAAncDataType > AJAAncillaryAnalogTypeMap
Associates certain frame line numbers with specific types of "raw" or "analog" ancillary data...
Definition: ancillarylist.h:36
Definition: json.hpp:5362
static bool SortByDID(AJAAncillaryData *lhs, AJAAncillaryData *rhs)
virtual void Clear(void)
Frees my allocated memory, if any, and resets my members to their default values. ...
virtual AJARTPAncPayloadHeader & SetField2(void)
Sets my Field Signal value to "Field 2".
AJAU32Pkts::const_iterator AJAU32PktsConstIter
Handy const iterator over AJAU32Pkts.
Definition: ancillarylist.h:39
virtual uint32_t GetFrameID(void) const
#define false
ULWord GetVisibleRasterBytes(const UWord inPlaneIndex0=0) const
uint32_t ULWord
Definition: ajatypes.h:236
Frame buffer VANC lines.
static uint32_t ENDIAN_32NtoH(const uint32_t inValue)
const void * GetRowAddress(const void *pInStartAddress, const ULWord inRowIndex0, const UWord inPlaneIndex0=0) const
static bool StripNativeInserterGUMPPackets(const NTV2Buffer &inSrc, NTV2Buffer &outDst)
Copies GUMP from inSrc to outDst buffers, but removes ATC, VPID, VITC, EDH & raw/analog packets...
#define LOGMYDEBUG(__x__)
static AJAStatus AddFromDeviceAuxBuffer(const NTV2Buffer &inAuxBuffer, AJAAncillaryList &outPacketList, const uint32_t inFrameNum=0)
Appends whatever can be decoded from the given device HDIM aux buffer to the AJAAncillaryList.
virtual uint16_t GetLocationLineNumber(void) const
static AJALock gAnalogTypeMapMutex
#define NTV2_ASSERT(_expr_)
Definition: ajatypes.h:489
static uint32_t gExcludedZeroLengthPackets(0)
Defines where the ancillary data can be found within a video stream.
virtual AJAAncDataType GetAncillaryDataType(void) const
virtual AJAAncDataType GetAnalogAncillaryDataType(const AJAAncillaryData &inAncData)
static AJAStatus SetFromDeviceAuxBuffers(const NTV2Buffer &inF1AuxBuffer, const NTV2Buffer &inF2AuxBuffer, AJAAncillaryList &outPackets, const uint32_t inFrameNum=0)
Returns all HDMI Aux data packets found in the given F1 and F2 aux data buffers.
std::vector< uint8_t > UByteSequence
An ordered sequence of UByte (uint8_t) values.
I represent the header of a SMPTE 2110 compliant RTP Anc network packet.
virtual bool AllowMultiRTPTransmit(void) const
Answers true if multiple RTP packets will be transmitted/encoded. The default behavior is to transmit...
bool Fill(const T &inValue)
Fills me with the given scalar value.
virtual AJAAncillaryData & SetFrameID(const uint32_t inFrameID)
Sets my originating frame identifier.
static string ULWordSequenceToStringBE(const ULWordSequence &inData, const size_t inMaxNum=32)
bool UnpackLine_10BitYUVtoU16s(std::vector< uint16_t > &outYCbCrLine, const NTV2Buffer &inFrameBuffer, const NTV2FormatDescriptor &inDescriptor, const UWord inLineOffset)
Unpacks up to one raster line of an NTV2_FBF_10BIT_YCBCR frame buffer into an array of uint16_t value...
Definition: ntv2utils.cpp:646
bool IsProvidedByClient(void) const
std::vector< U16Packet > U16Packets
An ordered sequence of zero or more U16Packet values.
ULWord GetFirstActiveLine(void) const
#define true
AJAAncillaryDataList::iterator AJAAncDataListIter
Handy non-const iterator for iterating over members of an AJAAncillaryDataList.
const uint8_t AJAAncillaryDataWildcard_DID
Definition: ancillarylist.h:27
Includes data that is valid, but we don&#39;t recognize.
Definition: ancillarydata.h:46
static AJAStatus SetFromVANCData(const NTV2Buffer &inFrameBuffer, const NTV2FormatDescriptor &inFormatDesc, AJAAncillaryList &outPackets, const uint32_t inFrameNum=0)
Returns all packets found in the VANC lines of the given NTV2 frame buffer.
#define RCVWARN(__x__)
void * GetWriteableRowAddress(void *pInStartAddress, const ULWord inRowIndex0, const UWord inPlaneIndex0=0) const
virtual AJAStatus Compare(const AJAAncillaryList &inCompareList, const bool inIgnoreLocation=true, const bool inIgnoreChecksum=true) const
Compares me with another list.
virtual uint32_t CountAncillaryDataWithID(const uint8_t inDID, const uint8_t inSID) const
Answers with the number of AncillaryData objects having the given DataID and SecondaryID.
static AJAStatus ClearAnalogAncillaryDataTypeMap(void)
Clears my global Analog Ancillary Data Type map.
static const size_t MAX_RTP_PKT_LENGTH_WORDS((MAX_RTP_PKT_LENGTH_BYTES+1)/sizeof(uint32_t) - 1)
virtual AJAAncillaryData & SetBufferFormat(const AJAAncBufferFormat inFmt)
Sets my originating buffer format.
std::vector< AJAAncillaryData * > AJAAncillaryDataList
#define AJA_NULL
Definition: ajatypes.h:180
static void BumpZeroLengthPacketCount(void)
static const size_t MAX_RTP_PKT_LENGTH_BYTES(0x0000FFFF)
virtual AJAStatus Clear(void)
Removes and frees all of my AJAAncillaryData objects.
virtual AJARTPAncPayloadHeader & SetAncPacketCount(const uint8_t inPktCount)
Sets my RTP Anc Packet Count value.
virtual AJAAncillaryData * GetAncillaryDataWithType(const AJAAncDataType inMatchType, const uint32_t inIndex=0) const
Answers with the AJAAncillaryData object having the given type and index.
Describes a video frame for a given video standard or format and pixel format, including the total nu...
The ancillary data is associated with the chrominance (C) channel of the video stream.
The ancillary data is associated with the luminance (Y) channel of the video stream.
static AJAStatus SetFromDeviceAncBuffers(const NTV2Buffer &inF1AncBuffer, const NTV2Buffer &inF2AncBuffer, AJAAncillaryList &outPackets, const uint32_t inFrameNum=0)
Returns all ancillary data packets found in the given F1 and F2 ancillary data buffers.
virtual bool WriteToULWordVector(ULWordSequence &outVector, const bool inReset=true) const
Writes an RTP packet header based on my current state into the given ULWordSequence. Each 32-bit word will be written in network byte order.
virtual AJAStatus AddAncillaryData(const AJAAncillaryList &inPackets)
Appends a copy of the given list&#39;s packets to me.
virtual AJAStatus ParsePayloadData(void)
Parses (interprets) the "local" ancillary data from my payload data.
std::vector< uint16_t > UWordSequence
An ordered sequence of UWord (uint16_t) values.
virtual bool AllowMultiRTPReceive(void) const
Answers true if multiple RTP packets are allowed for capture/receive. The default behavior is to proc...
AJAAncillaryList()
Instantiate and initialize with a default set of values.
virtual AJAAncillaryList & operator=(const AJAAncillaryList &inRHS)
Assignment operator – replaces my contents with the right-hand-side value.
UWordSequence::const_iterator UWordSequenceConstIter
A handy const iterator for iterating over a UWordSequence.
static int32_t Increment(int32_t volatile *pTarget)
Definition: atomic.cpp:82
static AJAAncDataType GetAnalogAncillaryDataTypeForLine(const uint16_t inLineNum)
Answers with the ancillary data type associated with the designated line.
virtual AJAStatus InitWithReceivedData(const uint8_t *pInData, const size_t inMaxBytes, const AJAAncDataLoc &inLocationInfo, uint32_t &outPacketByteCount)
Initializes me from "raw" ancillary data received from hardware (ingest) – see SDI Anc Buffer Data F...
virtual AJARTPAncPayloadHeader & SetEndOfFieldOrFrame(const bool inIsLast=true)
Sets my RTP Packet End-Of-Field or End-Of-Frame (Marker Bit) value.
virtual AJARTPAncPayloadHeader & SetProgressive(void)
Sets my Field Signal value to "Progressive".
virtual AJAStatus GetVANCTransmitData(NTV2Buffer &inFrameBuffer, const NTV2FormatDescriptor &inFormatDesc)
Writes my AJAAncillaryData objects into the given tall/taller frame buffer having the given raster/fo...
HDMI Auxiliary data.
Definition: ancillarydata.h:60
static bool GetAncPacketsFromVANCLine(const UWordSequence &inYUV16Line, const AncChannelSearchSelect inChanSelect, U16Packets &outRawPackets, U16Packet &outWordOffsets)
Extracts whatever VANC packets are found inside the given 16-bit YUV line buffer. ...
virtual AJAStatus AddVANCData(const UWordSequence &inPacketWords, const AJAAncillaryDataLocation &inLocation, const uint32_t inFrameNum=0)
Adds the packet that originated in the VANC lines of an NTV2 frame buffer to my list.
virtual std::string CompareWithInfo(const AJAAncillaryList &inCompareList, const bool inIgnoreLocation=true, const bool inIgnoreChecksum=true) const
Compares me with another list and returns a std::string that contains a human-readable explanation of...
static bool BufferHasGUMPData(const NTV2Buffer &inBuffer)
virtual AJARTPAncPayloadHeader & SetField1(void)
Sets my Field Signal value to "Field 1".
static uint32_t GetExcludedZeroLengthPacketCount(void)
virtual AJAAncillaryData * GetAncillaryDataWithID(const uint8_t inDID, const uint8_t inSID, const uint32_t inIndex=0) const
Answers with the AJAAncillaryData object having the given DataID and SecondaryID, at the given index...
virtual AJAStatus GetIPTransmitDataLength(uint32_t &outF1ByteCount, uint32_t &outF2ByteCount, const bool inIsProgressive=true, const uint32_t inF2StartLine=0)
Answers with the number of bytes required to store IP/RTP for my AJAAncillaryData packets in RTP Anc ...
#define RCVDBG(__x__)
static ostream & PrintULWordsBE(ostream &inOutStream, const ULWordSequence &inData, const size_t inMaxNum=32)
static AJAStatus SetAnalogAncillaryDataTypeForLine(const uint16_t inLineNum, const AJAAncDataType inType)
Sets (or changes) the map entry for the designated line to the designated type.
std::vector< ULWordSequence > AJAU32Pkts
Ordered sequence of U32 RTP packets (U32s in network byte order)
Definition: ancillarylist.h:38
static void SetIncludeZeroLengthPackets(const bool inExclude)
Sets whether or not zero-length packets are included or not.
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.).
virtual AJAStatus SortListBySID(void)
Sort the AncillaryDataList by Secondary ID (SID) value.
bool GetSMPTELineNumber(const ULWord inLineOffset, ULWord &outSMPTELine, bool &outIsField2) const
Answers with the equivalent SMPTE line number for the given line offset into the frame buffer I descr...
Declares the AJAAtomic class.
static bool Unpack8BitYCbCrToU16sVANCLineSD(const void *pInYUV8Line, UWordSequence &outU16YUVLine, const uint32_t inNumPixels)
SD version of Unpack8BitYCbCrToU16sVANCLine.
bool PutU32s(const ULWordSequence &inU32s, const size_t inU32Offset=0, const bool inByteSwap=false)
Copies a vector of unsigned 32-bit values into me.
#define AJA_ENDIAN_32NtoH(__val__)
virtual AJARTPAncPayloadHeader & SetSequenceNumber(const uint32_t inSeqNumber)
Sets my RTP Packet Sequence Number value.
virtual uint32_t CountAncillaryDataWithType(const AJAAncDataType inMatchType) const
Answers with the number of AJAAncillaryData objects having the given type.
virtual uint8_t GetAncPacketCount(void) const
Declaration of the AJAAncillaryDataFactory class.
#define DEC(__x__)
AJAAncillaryDataList::const_iterator AJAAncDataListConstIter
Handy const iterator for iterating over members of an AJAAncillaryDataList.
#define NTV2_IS_SD_STANDARD(__s__)
Definition: ntv2enums.h:200
Declares numerous NTV2 utility functions.
virtual bool IsDigital(void) const
virtual bool IgnoreChecksumErrors(void) const
Answers if checksum errors are to be ignored or not. The default behavior is to not ignore them...
ULWord GetTotalRasterBytes(const UWord inPlaneIndex0=0) const
static AJALock gGlobalLock
The ancillary data is associated with Link A of the video stream.
Definition: ancillarydata.h:81
#define RCVFAIL(__x__)
virtual AJAStatus RemoveAncillaryData(AJAAncillaryData *pInAncData)
Removes all copies of the AJAAncillaryData object from me.
virtual AJARTPAncPayloadHeader & SetPayloadLength(const uint16_t inByteCount)
Sets my RTP Packet Length value.
virtual AJAStatus ParseAllAncillaryData(void)
Sends a "ParsePayloadData" command to all of my AJAAncillaryData objects.
static bool Unpack8BitYCbCrToU16sVANCLine(const void *pInYUV8Line, U16Packet &outU16YUVLine, const uint32_t inNumPixels)
Converts a single line of NTV2_FBF_8BIT_YCBCR data from the given source buffer into an ordered seque...
virtual AJAStatus GetAncillaryDataTransmitData(const bool inIsProgressive, const uint32_t inF2StartLine, uint8_t *pOutF1AncData, const uint32_t inF1ByteCountMax, uint8_t *pOutF2AncData, const uint32_t inF2ByteCountMax)
Builds one or two ancillary data buffers (one for field 1, one for field 2) with the anc data inserte...
Look both luma and chroma samples (SD only)
uint16_t UWord
Definition: ajatypes.h:234
virtual AJAAncDataCoding GetDataCoding(void) const
SDI (AJA "GUMP")
ULWord GetRasterWidth(void) const
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 ...
NTV2Standard GetVideoStandard(void) const
static AJAAncillaryAnalogTypeMap gAnalogTypeMap
#define xHEX0N(__x__, __n__)
virtual bool ReadFromULWordVector(const ULWordSequence &inVector)
Resets my current state from the RTP packet header stored in the given ULWordSequence. Each 32-bit word in the vector is expected to be in network byte order.
static AJAStatus WriteRTPPackets(NTV2Buffer &theBuffer, uint32_t &outBytesWritten, const AJAU32Pkts &inRTPPkts, const AJAAncPktCounts &inAncCounts, const bool inIsF2, const bool inIsProgressive)
Fills the buffer with the given RTP packets.
#define IS_VALID_AJAAncDataChannel(_x_)
virtual bool IsValid(void) const
std::string NTV2FrameBufferFormatToString(const NTV2FrameBufferFormat inValue, const bool inForRetailDisplay=false)
Definition: ntv2utils.cpp:6938
virtual bool IsRaw(void) const
AJAAncPktDIDSIDSet::const_iterator AJAAncPktDIDSIDSetConstIter
Handy const iterator for AJAAncPktDIDSIDSet (New in SDK 16.0)
Definition: ancillarylist.h:47
static AJAStatus AddFromDeviceAncBuffer(const NTV2Buffer &inAncBuffer, AJAAncillaryList &outPacketList, const uint32_t inFrameNum=0)
Appends whatever can be decoded from the given device Anc buffer to the AJAAncillaryList.
SD ONLY – The ancillary data is associated with both the chroma and luma channels.
AJAAncDataLink
Identifies which link of a video stream the ancillary data is associated with.
Definition: ancillarydata.h:79
const uint8_t AJAAncillaryDataWildcard_SID
Definition: ancillarylist.h:28
virtual AJAStatus GetRTPPackets(AJAU32Pkts &outF1U32Pkts, AJAU32Pkts &outF2U32Pkts, AJAAncPktCounts &outF1AncCounts, AJAAncPktCounts &outF2AncCounts, const bool inIsProgressive, const uint32_t inF2StartLine)
Answers with my F1 & F2 SMPTE anc packets encoded as RTP ULWordSequences. The returned ULWords are al...
static size_t GetHeaderWordCount(void)
std::string AJAStatusToString(const AJAStatus inStatus, const bool inDetailed)
Definition: debug.cpp:981
std::vector< uint32_t > ULWordSequence
An ordered sequence of ULWord (uint32_t) values.
virtual bool IsNULL(void) const
#define XMTDBG(__x__)
virtual uint32_t GetDC(void) const
void * GetHostPointer(void) const
#define HEX0N(__x__, __n__)
Definition: debug.cpp:1175
I am the principal class that stores a single SMPTE-291 SDI ancillary data packet OR the digitized co...
static AJAAncillaryData * Create(const AJAAncDataType inAncType, const AJAAncillaryData &inAncData)
Creates a new particular subtype of AJAAncillaryData object.
Declares the AJAAncillaryList class.
void * GetHostAddress(const ULWord inByteOffset, const bool inFromEnd=false) const
#define DECN(__x__, __n__)
virtual uint16_t GetPayloadLength(void) const
Only look in chroma samples.
static bool IsIncludingZeroLengthPackets(void)
static AJAStatus AppendUWordPacketToGump(UByteSequence &outGumpPkt, const UWordSequence &inPacketWords, const AJAAncDataLoc inLoc=AJAAncDataLoc(AJAAncDataLink_A, AJAAncDataChannel_Y, AJAAncDataSpace_VANC, 0))
CEA608 SD Closed Captioning ("Line 21" waveform)
Definition: ancillarydata.h:52
static bool SortByLocation(AJAAncillaryData *lhs, AJAAncillaryData *rhs)
I am an ordered collection of AJAAncillaryData instances which represent one or more SMPTE 291 data p...
Definition: ancillarylist.h:64
UByteSequence AJAAncPktCounts
Ordered sequence of SMPTE Anc packet counts.
Definition: ancillarylist.h:42
virtual ~AJAAncillaryList()
My destructor.
virtual uint32_t GetTimeStamp(void) const
The ancillary data is in the form of a SMPTE-291 Ancillary Packet.
static AJAStatus SetAnalogAncillaryDataTypeMap(const AJAAncillaryAnalogTypeMap &inMap)
Copies the given map to the global Analog Ancillary Data Type map.
#define IS_VALID_AJAAncDataType(_x_)
Definition: ancillarydata.h:64
See 8-Bit YCbCr Format.
Definition: ntv2enums.h:225
static void ResetExcludedZeroLengthPacketCount(void)
Resets my tally of excluded zero-length packets to zero.