AJA NTV2 SDK  18.0.0.2122
NTV2 SDK 18.0.0.2122
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  resultF1 = AddFromDeviceAncBuffer(inF1AncBuffer, outPackets, inFrameNum);
1132  if (inF2AncBuffer) //Unnecessary to extract from empty buffer, and prevents 0 Packets debug message.
1133  resultF2 = AddFromDeviceAncBuffer(inF2AncBuffer, outPackets, inFrameNum);
1134  if (AJA_FAILURE(resultF1))
1135  return resultF1;
1136  if (AJA_FAILURE(resultF2))
1137  return resultF2;
1138  return AJA_STATUS_SUCCESS;
1139 }
1140 
1142  const NTV2Buffer & inF2AuxBuffer,
1143  AJAAncillaryList & outPackets,
1144  const uint32_t inFrameNum) // STATIC
1145 {
1146  outPackets.Clear();
1147  AJAStatus resultF1,resultF2;
1148  resultF1 = resultF2 = AJA_STATUS_SUCCESS;
1149  resultF1 = AddFromDeviceAuxBuffer(inF1AuxBuffer, outPackets, inFrameNum);
1150  if (inF2AuxBuffer) //Unnecessary to extract from empty buffer, and prevents 0 Packets debug message.
1151  resultF2 = AddFromDeviceAuxBuffer(inF2AuxBuffer, outPackets, inFrameNum);
1152  if (AJA_FAILURE(resultF1))
1153  return resultF1;
1154  if (AJA_FAILURE(resultF2))
1155  return resultF2;
1156  return AJA_STATUS_SUCCESS;
1157 }
1158 
1159 static const size_t MAX_RTP_PKT_LENGTH_BYTES (0x0000FFFF); // 65535 max
1160 static const size_t MAX_RTP_PKT_LENGTH_WORDS ((MAX_RTP_PKT_LENGTH_BYTES+1) / sizeof(uint32_t) - 1); // 16383 max
1161 static const uint32_t MAX_ANC_PKTS_PER_RTP_PKT (0x000000FF); // 255 max
1162 
1163 
1165  AJAAncPktCounts & outF1AncCounts, AJAAncPktCounts & outF2AncCounts,
1166  const bool inIsProgressive, const uint32_t inF2StartLine)
1167 {
1168  AJAStatus result (AJA_STATUS_SUCCESS);
1169  uint32_t actF1PktCnt (0);
1170  uint32_t actF2PktCnt (0);
1171  uint32_t pktNdx (0);
1172  size_t oldPktLengthWords (0);
1173  unsigned countOverflows (0);
1174  size_t overflowWords (0);
1175 
1176  // Reserve space in AJAU32Pkts vectors...
1177  outF1U32Pkts.reserve(CountAncillaryData()); outF1U32Pkts.clear();
1178  outF2U32Pkts.reserve(CountAncillaryData()); outF2U32Pkts.clear();
1179  outF1AncCounts.clear(); outF2AncCounts.clear();
1180 
1181  ULWordSequence F1U32s, F2U32s;
1182  F1U32s.reserve(MAX_RTP_PKT_LENGTH_WORDS);
1183  if (!inIsProgressive)
1184  F2U32s.reserve(MAX_RTP_PKT_LENGTH_WORDS);
1185  F1U32s.clear(); F2U32s.clear();
1186 
1187  // Generate transmit data for each of my packets...
1188  for (pktNdx = 0; pktNdx < CountAncillaryData(); pktNdx++)
1189  {
1190  AJAAncillaryData * pAncData (GetAncillaryDataAtIndex(pktNdx));
1191  if (!pAncData)
1192  return AJA_STATUS_NULL; // Fail
1193 
1194  AJAAncillaryData & pkt (*pAncData);
1196  {
1197  LOGMYDEBUG("Skipped Pkt " << DEC(pktNdx+1) << " of " << DEC(CountAncillaryData()) << " -- Analog/Raw");
1198  continue; // Skip analog/raw packets
1199  }
1200 
1201  if (inIsProgressive || pkt.GetLocationLineNumber() < inF2StartLine)
1202  {
1203  if (actF1PktCnt >= MAX_ANC_PKTS_PER_RTP_PKT)
1204  {
1205  countOverflows++;
1206  LOGMYDEBUG("Skipped pkt " << DEC(pktNdx+1) << " of " << DEC(CountAncillaryData()) << ", F1 RTP pkt count overflow: " << pkt.AsString(16));
1207  continue;
1208  }
1209  oldPktLengthWords = F1U32s.size();
1210  result = pkt.GenerateTransmitData(F1U32s);
1211  if (AJA_FAILURE(result))
1212  break; // Bail!
1213  if (F1U32s.size() > MAX_RTP_PKT_LENGTH_WORDS)
1214  {
1215  overflowWords += F1U32s.size() - oldPktLengthWords;
1216  LOGMYDEBUG("Skipped pkt " << DEC(pktNdx+1) << " of " << DEC(CountAncillaryData()) << ": F1 RTP pkt length overflow: " << pkt.AsString(16));
1217  while (F1U32s.size() > oldPktLengthWords)
1218  F1U32s.pop_back();
1219  continue;
1220  }
1221  actF1PktCnt++;
1222  if (AllowMultiRTPTransmit())
1223  { // MULTI RTP PKTS
1224  outF1U32Pkts.push_back(F1U32s); // Append it
1225  outF1AncCounts.push_back(1); // One SMPTE Anc packet per RTP packet
1226  XMTDBG("F1 pkt " << DEC(actF1PktCnt) << ": " << ::ULWordSequenceToStringBE(F1U32s) << " (BigEndian)");
1227  F1U32s.clear(); // Start current pkt over
1228  }
1229  }
1230  else
1231  {
1232  if (actF2PktCnt >= MAX_ANC_PKTS_PER_RTP_PKT)
1233  {
1234  countOverflows++;
1235  LOGMYDEBUG("Skipped pkt " << DEC(pktNdx+1) << " of " << DEC(CountAncillaryData()) << ": F2 RTP pkt count overflow: " << pkt.AsString(16));
1236  continue;
1237  }
1238  oldPktLengthWords = F2U32s.size();
1239  result = pkt.GenerateTransmitData(F2U32s);
1240  if (AJA_FAILURE(result))
1241  break; // Bail!
1242  if (AJA_SUCCESS(result) && F2U32s.size() > MAX_RTP_PKT_LENGTH_WORDS)
1243  {
1244  overflowWords += F2U32s.size() - oldPktLengthWords;
1245  LOGMYDEBUG("Skipped pkt " << DEC(pktNdx+1) << " of " << DEC(CountAncillaryData()) << ": F2 RTP pkt length overflow: " << pkt.AsString(16));
1246  while (F2U32s.size() > oldPktLengthWords)
1247  F2U32s.pop_back();
1248  continue;
1249  }
1250  actF2PktCnt++;
1251  if (AllowMultiRTPTransmit())
1252  { // MULTI RTP PKTS
1253  outF2U32Pkts.push_back(F2U32s); // Append it
1254  outF2AncCounts.push_back(1); // One SMPTE Anc packet per RTP packet
1255  XMTDBG("F2 pkt " << DEC(actF2PktCnt) << ": " << ::ULWordSequenceToStringBE(F2U32s) << " (BigEndian)");
1256  F2U32s.clear(); // Start current pkt over
1257  }
1258  }
1259  } // for each SMPTE Anc packet
1260 
1261  if (AJA_FAILURE(result))
1262  {LOGMYERROR(::AJAStatusToString(result) << ": Pkt " << DEC(pktNdx+1) << " of " << DEC(CountAncillaryData()) << " failed in GenerateTransmitData: " << ::AJAStatusToString(result));}
1263  else if (!AllowMultiRTPTransmit())
1264  { // SINGLE RTP PKT
1265  outF1U32Pkts.push_back(F1U32s); // Append all F1
1266  outF1AncCounts.push_back(uint8_t(actF1PktCnt)); // Total F1 SMPTE Anc packets in this one F1 RTP packet
1267  outF2U32Pkts.push_back(F2U32s); // Append all F2
1268  outF2AncCounts.push_back(uint8_t(actF2PktCnt)); // Total F2 SMPTE Anc packets in this one F2 RTP packet
1269  }
1270  if (overflowWords && countOverflows)
1271  {LOGMYWARN("Overflow: " << DEC(countOverflows) << " pkts skipped, " << DEC(overflowWords) << " U32s dropped");}
1272  else if (overflowWords)
1273  {LOGMYWARN("Data overflow: " << DEC(overflowWords) << " U32s dropped");}
1274  else if (countOverflows)
1275  LOGMYWARN("Packet overflow: " << DEC(countOverflows) << " pkts skipped");
1276  XMTDBG("F1 (Content Only): " << outF1U32Pkts);
1277  XMTDBG("F2 (Content Only): " << outF2U32Pkts);
1278  return result;
1279 } // GetRTPPackets
1280 
1281 
1282 
1286 
1287 
1288 AJAStatus AJAAncillaryList::GetAncillaryDataTransmitSize (const bool bProgressive, const uint32_t f2StartLine, uint32_t & ancSizeF1, uint32_t & ancSizeF2)
1289 {
1290  AJAStatus status (AJA_STATUS_SUCCESS);
1291  uint32_t f1Size (0);
1292  uint32_t f2Size (0);
1293 
1294  for (AJAAncDataListConstIter it(m_ancList.begin()); it != m_ancList.end(); ++it)
1295  {
1296  AJAAncillaryData * pAncData (*it);
1297  uint32_t packetSize (0);
1298  status = pAncData->GetRawPacketSize (packetSize);
1299  if (status != AJA_STATUS_SUCCESS)
1300  break;
1301 
1302  if (bProgressive || pAncData->GetLocationLineNumber () < f2StartLine)
1303  f1Size += packetSize;
1304  else
1305  f2Size += packetSize;
1306  }
1307 
1308  ancSizeF1 = f1Size;
1309  ancSizeF2 = f2Size;
1310  return status;
1311 }
1312 
1313 
1314 AJAStatus AJAAncillaryList::GetAncillaryDataTransmitData (const bool bProgressive, const uint32_t f2StartLine, uint8_t * pF1AncData, const uint32_t inMaxF1Data, uint8_t * pF2AncData, const uint32_t inMaxF2Data)
1315 {
1316  NTV2Buffer F1Buffer(pF1AncData, inMaxF1Data), F2Buffer(pF2AncData, inMaxF2Data);
1317  if (!F1Buffer.IsNULL())
1318  NTV2_ASSERT(F1Buffer.IsProvidedByClient());
1319  if (!F2Buffer.IsNULL())
1320  NTV2_ASSERT(F2Buffer.IsProvidedByClient());
1321  return GetTransmitData(F1Buffer, F2Buffer, bProgressive, f2StartLine);
1322 }
1323 
1324 
1326  const bool inIsProgressive, const uint32_t inF2StartLine)
1327 {
1328  AJAStatus status (AJA_STATUS_SUCCESS);
1329  size_t maxF1Data(F1Buffer), maxF2Data(F2Buffer);
1330  uint8_t *pF1AncData(F1Buffer), *pF2AncData(F2Buffer);
1331 
1332  F1Buffer.Fill(uint64_t(0)); F2Buffer.Fill(uint64_t(0));
1333 
1334  // I need to be in ascending line order...
1336 
1337  // Generate transmit data for each of my packets...
1338  for (AJAAncDataListConstIter it(m_ancList.begin()); it != m_ancList.end(); ++it)
1339  {
1340  uint32_t pktSize(0);
1341  AJAAncillaryData * pPkt(*it);
1342  if (!pPkt)
1343  {status = AJA_STATUS_NULL; break;} // Fail
1344 
1345  if (inIsProgressive || pPkt->GetLocationLineNumber() < inF2StartLine)
1346  {
1347  if (pF1AncData && maxF1Data)
1348  {
1349  status = pPkt->GenerateTransmitData(pF1AncData, maxF1Data, pktSize);
1350  if (AJA_FAILURE(status))
1351  break;
1352 
1353  pF1AncData += pktSize;
1354  maxF1Data -= pktSize;
1355  }
1356  }
1357  else if (pF2AncData && maxF2Data)
1358  {
1359  status = pPkt->GenerateTransmitData(pF2AncData, maxF2Data, pktSize);
1360  if (AJA_FAILURE(status))
1361  break;
1362 
1363  pF2AncData += pktSize;
1364  maxF2Data -= pktSize;
1365  }
1366  } // for each of my anc packets
1367  return status;
1368 }
1369 
1370 
1372 {
1373  if (inFrameBuffer.IsNULL())
1374  {
1375  LOGMYERROR("AJA_STATUS_NULL: null frame buffer");
1376  return AJA_STATUS_NULL;
1377  }
1378  if (!inFormatDesc.IsValid())
1379  {
1380  LOGMYERROR("AJA_STATUS_BAD_PARAM: Invalid format descriptor");
1381  return AJA_STATUS_BAD_PARAM;
1382  }
1383  if (!inFormatDesc.IsVANC())
1384  {
1385  LOGMYERROR("AJA_STATUS_BAD_PARAM: Not a VANC geometry");
1386  return AJA_STATUS_BAD_PARAM;
1387  }
1388  if (inFormatDesc.GetPixelFormat() != NTV2_FBF_10BIT_YCBCR && inFormatDesc.GetPixelFormat() != NTV2_FBF_8BIT_YCBCR)
1389  {
1390  LOGMYERROR("AJA_STATUS_UNSUPPORTED: unsupported pixel format: " << inFormatDesc);
1391  return AJA_STATUS_UNSUPPORTED;
1392  }
1393  if (!CountAncillaryData())
1394  {
1395  LOGMYWARN("List is empty");
1396  return AJA_STATUS_SUCCESS;
1397  }
1398 
1399  // I need to be in ascending line order...
1401 
1402  // BRUTE-FORCE METHOD -- NOT VERY EFFICIENT
1403  const bool isSD (inFormatDesc.IsSD());
1404  AJAAncillaryList failures, successes;
1405  set <uint16_t> lineOffsetsWritten;
1406 
1407  // For each VANC line...
1408  for (UWord fbLineOffset(0); fbLineOffset < inFormatDesc.GetFirstActiveLine(); fbLineOffset++)
1409  {
1410  ULWord smpteLine (0); bool isF2 (false);
1411  inFormatDesc.GetSMPTELineNumber (fbLineOffset, smpteLine, isF2);
1412 
1413  // Look for non-HANC packets destined for this line...
1414  for (AJAAncDataListConstIter iter(m_ancList.begin()); (iter != m_ancList.end()) && *iter; ++iter)
1415  {
1416  bool muxedOK (false);
1417  AJAAncillaryData & ancData (**iter);
1418  const AJAAncDataLoc & loc (ancData.GetDataLocation());
1419  UWordSequence u16PktComponents;
1420  if (ancData.GetDataCoding() != AJAAncDataCoding_Digital) // Ignore "Raw" or "Analog" or "Unknown" packets
1421  continue;
1422  if (loc.GetDataSpace() != AJAAncDataSpace_VANC) // Ignore "HANC" or "Unknown" packets
1423  {
1424  //LOGMYWARN("Skipping non-VANC packet " << ancData);
1425  continue;
1426  }
1427  if (loc.GetLineNumber() != smpteLine) // Wrong line number
1428  {
1429  //LOGMYWARN("Skipping packet not destined for line " << DEC(smpteLine) << " " << loc);
1430  continue;
1431  }
1432  if (!IS_VALID_AJAAncDataChannel(loc.GetDataChannel())) // Bad data channel
1433  {
1434  LOGMYWARN("Skipped packet with invalid data channel " << loc);
1435  continue;
1436  }
1437 
1438  // For v210 buffers, generate 10-bit packet data and put into u16 vector...
1439  muxedOK = AJA_SUCCESS(ancData.GenerateTransmitData(u16PktComponents));
1440  if (muxedOK)
1441  {
1442  if (inFormatDesc.GetPixelFormat() == NTV2_FBF_8BIT_YCBCR) // 2vuy buffers are simple -- just copy the data
1443  {
1444  uint8_t * pLine (reinterpret_cast<uint8_t*>(inFormatDesc.GetWriteableRowAddress(inFrameBuffer.GetHostPointer(), fbLineOffset)));
1445  if (isSD)
1446  { // SD overwrites both Y & C channels in the frame buffer:
1447  for (unsigned ndx(0); ndx < u16PktComponents.size(); ndx++)
1448  pLine[ndx] = uint8_t(u16PktComponents[ndx] & 0xFF);
1449  }
1450  else
1451  { // HD overwrites only the Y or C channel data in the frame buffer:
1452  unsigned dstNdx(loc.IsLumaChannel() ? 1 : 0);
1453  for (unsigned srcNdx(0); srcNdx < u16PktComponents.size(); srcNdx++)
1454  pLine[dstNdx + 2*srcNdx] = uint8_t(u16PktComponents[srcNdx] & 0x00FF);
1455  }
1456  } // if 2vuy
1457  else
1458  {
1459  if (isSD)
1460  { // For SD, just pack the u16 components into the buffer...
1461  while (u16PktComponents.size() < 12 || u16PktComponents.size() % 12) // YUVComponentsTo10BitYUVPackedBuffer fails if packing fewer than 12 words
1462  u16PktComponents.push_back(0x040); // SMPTE black
1463  muxedOK = ::YUVComponentsTo10BitYUVPackedBuffer (u16PktComponents, inFrameBuffer, inFormatDesc, fbLineOffset);
1464  }
1465  else
1466  { // HD overwrites only the Y or C channel data:
1467  UWordSequence YUV16Line;
1468  unsigned dstNdx (loc.IsLumaChannel() ? 1 : 0);
1469 
1470  // Read original Y+C components from FB...
1471  muxedOK = UnpackLine_10BitYUVtoU16s (YUV16Line, inFrameBuffer, inFormatDesc, fbLineOffset);
1472  //cerr << "WriteVANCData|orig: +" << DEC0N(fbLineOffset,2) << ": "; inFormatDesc.PrintSMPTELineNumber(cerr, fbLineOffset); cerr << ":" << endl << YUV16Line << endl;
1473 
1474  // Patch the Y or C channel...
1475  if (muxedOK)
1476  for (unsigned srcNdx(0); srcNdx < u16PktComponents.size(); srcNdx++)
1477  YUV16Line[dstNdx + 2*srcNdx] = u16PktComponents[srcNdx] & 0x03FF;
1478  //cerr << "WriteVANCData|modi: +" << DEC0N(fbLineOffset,2) << ": "; inFormatDesc.PrintSMPTELineNumber(cerr, fbLineOffset); cerr << ":" << endl << YUV16Line << endl;
1479 
1480  // Repack the patched YUV16 line back into the FB...
1481  if (muxedOK)
1482  {
1483  while (YUV16Line.size() < 12 || YUV16Line.size() % 12) // YUVComponentsTo10BitYUVPackedBuffer fails if packing fewer than 12 words
1484  YUV16Line.push_back(0x040); // SMPTE black
1485  muxedOK = ::YUVComponentsTo10BitYUVPackedBuffer (YUV16Line, inFrameBuffer, inFormatDesc, fbLineOffset);
1486  }
1487  } // else HD
1488  } // else v210
1489  } // if GenerateTransmitData OK
1490 
1491  // TBD: NEED TO TAKE INTO CONSIDERATION loc.GetHorizontalOffset()
1492 
1493  if (muxedOK)
1494  {
1495  lineOffsetsWritten.insert(uint16_t(fbLineOffset)); // Remember which FB line offsets we overwrote
1496  successes.AddAncillaryData(ancData);
1497  }
1498  else
1499  failures.AddAncillaryData(ancData);
1500  } // for each packet
1501  } // for each VANC line
1502 
1503  // Any analog packets?
1504  for (AJAAncDataListConstIter iter(m_ancList.begin()); (iter != m_ancList.end()) && *iter; ++iter)
1505  {
1506  bool success (inFormatDesc.IsSD());
1507  AJAAncillaryData & ancData (**iter);
1508  const AJAAncDataLoc & loc (ancData.GetDataLocation());
1509  ULWord lineOffset (0);
1510  if (!ancData.IsRaw())
1511  continue; // Ignore "Digital" or "Unknown" packets
1512 
1513  if (success)
1514  success = inFormatDesc.GetLineOffsetFromSMPTELine (loc.GetLineNumber(), lineOffset);
1515  if (success && lineOffsetsWritten.find(uint16_t(lineOffset)) != lineOffsetsWritten.end())
1516  success = false; // Line already written -- "analog" data overwrites entire line
1517  if (success)
1518  {
1519  if (inFormatDesc.GetPixelFormat() == NTV2_FBF_8BIT_YCBCR)
1520  ::memcpy(inFormatDesc.GetWriteableRowAddress(inFrameBuffer.GetHostPointer(), lineOffset), ancData.GetPayloadData(), ancData.GetDC()); // '2vuy' -- straight copy
1521  else
1522  {
1523  UWordSequence pktComponentData;
1524  success = AJA_SUCCESS(ancData.GenerateTransmitData(pktComponentData));
1525  if (success)
1526  success = ::YUVComponentsTo10BitYUVPackedBuffer (pktComponentData, inFrameBuffer, inFormatDesc, UWord(lineOffset));
1527  }
1528  }
1529 
1530  if (success)
1531  {
1532  lineOffsetsWritten.insert(uint16_t(lineOffset)); // Remember which FB line offsets we overwrote
1533  successes.AddAncillaryData(ancData);
1534  }
1535  else
1536  failures.AddAncillaryData(ancData);
1537  } // for each Analog packet
1538 
1539  if (failures.CountAncillaryData())
1540  LOGMYWARN("FAILURES: " << failures);
1541  if (successes.CountAncillaryData())
1542  LOGMYDEBUG("SUCCESSES: " << successes);
1543 
1544  // At least one success is considered SUCCESS.
1545  // Zero successes and one or more failures is considered FAIL...
1546  return successes.CountAncillaryData() == 0 && failures.CountAncillaryData() > 0 ? AJA_STATUS_FAIL : AJA_STATUS_SUCCESS;
1547 } // WriteVANCData
1548 
1549 
1550 // STATIC
1551 AJAStatus AJAAncillaryList::WriteRTPPackets (NTV2Buffer & theBuffer, uint32_t & outBytesWritten,
1552  const AJAU32Pkts & inRTPPkts, const AJAAncPktCounts & inAncCounts,
1553  const bool inIsF2, const bool inIsProgressive)
1554 {
1555  const ULWord totPkts (ULWord(inRTPPkts.size()));
1556  const string sFld (inIsF2 ? " F2" : " F1");
1557  const string sPrg (inIsProgressive ? " Prg" : " Int");
1558  ULWord u32offset(0), pktNum(1);
1559 
1560  outBytesWritten = 0;
1561  if (inRTPPkts.size() != inAncCounts.size())
1562  {LOGMYERROR(DEC(inRTPPkts.size()) << " RTP pkt(s) != " << DEC(inAncCounts.size()) << " anc count(s)"); return AJA_STATUS_BAD_PARAM;}
1563 
1564  // For each RTP Packet...
1565  for (AJAU32PktsConstIter RTPPktIter(inRTPPkts.begin()); RTPPktIter != inRTPPkts.end(); pktNum++)
1566  {
1567  AJARTPAncPayloadHeader RTPHeader; // The RTP packet header to be built
1568  ULWordSequence RTPHeaderU32s; // The RTP packet header expressed as a sequence of 5 x U32s
1569  const ULWordSequence & origRTPPkt(*RTPPktIter); // The original RTP packet data contents, a sequence of U32s
1570  const bool isLastRTPPkt (++RTPPktIter == inRTPPkts.end()); // Last RTP packet?
1571  const size_t totalRTPPktBytes(AJARTPAncPayloadHeader::GetHeaderByteCount() // RTP packet size,
1572  + origRTPPkt.size() * sizeof(uint32_t)); // including header, in bytes
1573  ostringstream pktNumInfo;
1574  pktNumInfo << " for RTP pkt " << DEC(pktNum) << " of " << DEC(totPkts);
1575 
1576  // Set the RTP Packet Header's info...
1577  if (inIsProgressive)
1578  RTPHeader.SetProgressive();
1579  else if (inIsF2)
1580  RTPHeader.SetField2();
1581  else
1582  RTPHeader.SetField1();
1583  RTPHeader.SetEndOfFieldOrFrame(isLastRTPPkt);
1584  RTPHeader.SetAncPacketCount(uint8_t(inAncCounts.at(pktNum-1))); // Use provided Anc count
1585  RTPHeader.SetPayloadLength(uint16_t(origRTPPkt.size() * sizeof(uint32_t)));
1586  // Playout: Firmware looks for full RTP pkt bytecount in LS 16 bits of SequenceNumber in RTP header:
1587  RTPHeader.SetSequenceNumber(uint32_t(totalRTPPktBytes) & 0x0000FFFF);
1588 
1589  // Convert RTP header object into 5 x U32s...
1590  RTPHeader.WriteToULWordVector(RTPHeaderU32s, true);
1591  NTV2_ASSERT(RTPHeaderU32s.size() == AJARTPAncPayloadHeader::GetHeaderWordCount());
1592 
1593  // Write RTP header into theBuffer...
1594  if (theBuffer)
1595  {
1596  if (!theBuffer.PutU32s(RTPHeaderU32s, u32offset))
1597  {LOGMYERROR("RTP hdr WriteBuffer failed for buffer " << theBuffer << " at u32offset=" << DEC(u32offset)
1598  << pktNumInfo.str()); return AJA_STATUS_FAIL;}
1599  }
1600  u32offset += ULWord(RTPHeaderU32s.size()); // Move "write head" to just past end of RTP header
1601 
1602  // Write RTP packet contents into theBuffer...
1603  if (theBuffer)
1604  {
1605  if (!theBuffer.PutU32s(origRTPPkt, u32offset))
1606  {LOGMYERROR("PutU32s failed writing " << DEC(origRTPPkt.size()) << " U32s in buffer " << theBuffer << " at u32offset=" << DEC(u32offset)
1607  << pktNumInfo.str()); return AJA_STATUS_FAIL;}
1608  LOGMYDEBUG("PutU32s OK @u32offset=" << xHEX0N(u32offset,4) << ": " << RTPHeader << pktNumInfo.str());
1609  }
1610 
1611  // Move "write head" to just past where this RTP packet's data ended...
1612  u32offset += ULWord(origRTPPkt.size());
1613 
1614  // JeffL: IP Anc inserters expect subsequent RTP packets to start on a 64-bit/8-byte word boundary.
1615  if (u32offset & 1L) // If it's not even...
1616  u32offset++; // ...then make it even!
1617  } // for each RTP packet
1618 
1619  outBytesWritten = u32offset * ULWord(sizeof(uint32_t));
1620  if (theBuffer)
1621  LOGMYDEBUG(DEC(totPkts) << " RTP pkt(s), " << DEC(u32offset) << " U32s (" << DEC(outBytesWritten)
1622  << " bytes) written for" << sFld << sPrg);
1623  return AJA_STATUS_SUCCESS;
1624 }
1625 
1626 
1628  const bool inIsProgressive, const uint32_t inF2StartLine)
1629 {
1630  AJAStatus result (AJA_STATUS_SUCCESS);
1631  AJAU32Pkts F1U32Pkts, F2U32Pkts; // 32-bit network-byte-order data
1632  AJAAncPktCounts F1AncCounts, F2AncCounts; // Per-RTP packet anc packet counts
1633  uint32_t byteCount(0); // Not used
1634 
1635  // I need to be in ascending line order...
1636  F1Buffer.Fill(uint64_t(0)); F2Buffer.Fill(uint64_t(0));
1638 
1639  // Get F1 & F2 xmit RTP U32 words (and SMPTE anc packet counts for each RTP packet)...
1640  result = GetRTPPackets (F1U32Pkts, F2U32Pkts, F1AncCounts, F2AncCounts, inIsProgressive, inF2StartLine);
1641  if (AJA_FAILURE(result))
1642  return result;
1643 
1644  /*
1645  ostringstream oss; oss << "Anc Counts: F1="; for (size_t ndx(0); ndx < F1AncCounts.size(); ndx++) oss << (ndx?"|":"[") << DEC(uint16_t(F1AncCounts.at(ndx)));
1646  oss << "] F2="; for (size_t ndx(0); ndx < F2AncCounts.size(); ndx++) oss << (ndx?"|":"[") << DEC(uint16_t(F2AncCounts.at(ndx))); oss << "]";
1647  XMTDBG(oss.str());
1648  */
1649 
1650  // Write the F1 buffer...
1651  result = WriteRTPPackets (F1Buffer, byteCount, F1U32Pkts, F1AncCounts, /*isF2*/false, inIsProgressive);
1652  if (AJA_FAILURE(result))
1653  return result;
1654 
1655  // Write the F2 buffer...
1656  if (!inIsProgressive)
1657  result = WriteRTPPackets (F2Buffer, byteCount, F2U32Pkts, F2AncCounts, /*isF2*/true, inIsProgressive);
1658 
1659  return result;
1660 
1661 } // GetIPTransmitData
1662 
1663 
1664 AJAStatus AJAAncillaryList::GetIPTransmitDataLength (uint32_t & outF1ByteCount, uint32_t & outF2ByteCount,
1665  const bool inIsProgressive, const uint32_t inF2StartLine)
1666 {
1667  outF1ByteCount = outF2ByteCount = 0;
1668 
1669  // Get F1 & F2 xmit RTP U32 words...
1670  AJAU32Pkts F1U32Pkts, F2U32Pkts; // U32 network-byte-order data
1671  AJAAncPktCounts F1AncCounts, F2AncCounts; // Per-RTP packet anc packet counts
1672  AJAStatus result (GetRTPPackets (F1U32Pkts, F2U32Pkts, F1AncCounts, F2AncCounts, inIsProgressive, inF2StartLine));
1673  if (AJA_FAILURE(result))
1674  return result;
1675 
1676  NTV2Buffer nullBuffer; // An empty buffer tells WriteRTPPackets to just calculate byteCount...
1677  result = WriteRTPPackets (nullBuffer, outF1ByteCount, F1U32Pkts, F1AncCounts, /*isF2*/false, inIsProgressive);
1678  if (AJA_SUCCESS(result) && !inIsProgressive)
1679  result = WriteRTPPackets (nullBuffer, outF2ByteCount, F2U32Pkts, F2AncCounts, /*isF2*/true, inIsProgressive);
1680 
1681  return result;
1682 }
1683 
1684 
1685 ostream & AJAAncillaryList::Print (ostream & inOutStream, const bool inDumpPayload) const
1686 {
1687  unsigned num (0);
1688  inOutStream << DEC(CountAncillaryData()) << " pkts:" << endl;
1689  for (AJAAncDataListConstIter it(m_ancList.begin()); it != m_ancList.end(); )
1690  {
1691  AJAAncillaryData * pPkt(*it);
1692  inOutStream << "Pkt" << DEC0N(++num,3) << ": " << pPkt->AsString(inDumpPayload ? 16 : 0);
1693  if (++it != m_ancList.end())
1694  inOutStream << endl;
1695  }
1696  return inOutStream;
1697 }
1698 
1699 // Copies GUMP from inSrc to outDst buffers, but removes ATC, VPID, EDH, VITC & analog packets
1701 {
1702  if (!inSrc || !outDst)
1703  return false; // Buffers must be valid
1704  if (inSrc.GetByteCount() > outDst.GetByteCount())
1705  return false; // Target buffer must be at least as large as source buffer
1706 
1707  uint8_t * srcPtr = inSrc;
1708  uint8_t * ptr = srcPtr;
1709  size_t srcBufSize = inSrc;
1710  uint8_t * tgtPtr = outDst;
1711  size_t uncopied = 0;
1712 // size_t numStripped = 0;
1713 // size_t bytesRemoved = 0;
1714  const size_t kGUMPHeaderSize(7);
1715 
1716  for (size_t ndx(0); ndx < srcBufSize; )
1717  {
1718  if (ptr[0] == 0xff && (ndx + kGUMPHeaderSize) < srcBufSize)
1719  {
1720  bool bFiltered{false};
1721  const uint8_t payloadSize(ptr[5]);
1722 
1723  if (ptr[1] & 0x40) // "Analog/raw"
1724  bFiltered = true;
1725  else if (ptr[3] == 0x60 && ptr[4] == 0x60 && payloadSize == 16) // ATC
1726  bFiltered = true;
1727  else if (ptr[3] == 0x41 && ptr[4] == 0x01 && payloadSize == 4) // SMPTE 352 - VPID
1728  bFiltered = true;
1729  else if (ptr[3] == 0xF4 && ptr[4] == 0x00 && payloadSize == 16) // RP165 EDH
1730  bFiltered = true;
1731  else // VITC
1732  {
1733  const uint16_t lineNum (uint16_t((ptr[1] & 0x0F) << 7) + uint16_t(ptr[2] & 0x7F));
1734  bFiltered = (ptr[1] & 0x40) && (lineNum == 14 || lineNum == 277);
1735  }
1736 
1737  if (bFiltered)
1738  { // Copy everything that came before filtered content...
1739  if (uncopied)
1740  ::memcpy(tgtPtr, srcPtr, uncopied);
1741 
1742  // Skip srcPtr past the filtered content...
1743  srcPtr += uncopied + payloadSize + kGUMPHeaderSize;
1744  tgtPtr += uncopied;
1745  ndx += payloadSize + kGUMPHeaderSize;
1746  ptr = srcPtr;
1747  uncopied = 0;
1748 // numStripped++; bytesRemoved += size_t(payloadSize) + kGUMPHeaderSize;
1749  }
1750  else
1751  {
1752  ptr += payloadSize + kGUMPHeaderSize;
1753  ndx += payloadSize + kGUMPHeaderSize;
1754  uncopied += payloadSize + kGUMPHeaderSize;
1755  }
1756  }
1757  else
1758  {ptr++; ndx++; uncopied++;}
1759  } // for each byte in source buffer
1760 
1761  if (uncopied) // Any uncopied remainder?
1762  ::memcpy(tgtPtr, srcPtr, uncopied); // Copy last uncopied bytes
1763  // cout << DEC(numStripped) << " pkts removed, " << DEC(bytesRemoved) << " bytes removed" << endl;
1764  return true;
1765 } // StripNativeInserterPackets
1766 
1767 
1771 
1774 
1775 
1777 {
1779  gAnalogTypeMap.clear();
1780  return AJA_STATUS_SUCCESS;
1781 }
1782 
1783 
1785 {
1787  gAnalogTypeMap = inMap;
1788  return AJA_STATUS_SUCCESS;
1789 }
1790 
1791 
1793 {
1795  outMap = gAnalogTypeMap;
1796  return AJA_STATUS_SUCCESS;
1797 }
1798 
1799 
1801 {
1803  gAnalogTypeMap.erase(inLineNum); // In case someone has already set this line
1804  if (inAncType == AJAAncDataType_Unknown)
1805  return AJA_STATUS_SUCCESS; // A non-entry is the same as AJAAncDataType_Unknown
1806  else if (IS_VALID_AJAAncDataType(inAncType))
1807  gAnalogTypeMap[inLineNum] = inAncType;
1808  else
1809  return AJA_STATUS_BAD_PARAM;
1810  return AJA_STATUS_SUCCESS;
1811 }
1812 
1813 
1815 {
1818  if (!gAnalogTypeMap.empty ())
1819  {
1820  AJAAncillaryAnalogTypeMap::const_iterator it (gAnalogTypeMap.find (inLineNum));
1821  if (it != gAnalogTypeMap.end ())
1822  ancType = it->second;
1823  }
1824  return ancType;
1825 }
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:219
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:222
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...
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)
ULWord GetByteCount(void) const
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:223
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:476
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:167
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:198
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:221
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:6936
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:223
static void ResetExcludedZeroLengthPacketCount(void)
Resets my tally of excluded zero-length packets to zero.