AJA NTV2 SDK  18.0.0.2122
NTV2 SDK 18.0.0.2122
ancillarydata.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
8 #include "ntv2publicinterface.h"
9 #include "ancillarydata.h"
10 #include "ajabase/system/debug.h" // This makes 'ajaanc' dependent upon 'ajabase'
11 #include "ajabase/system/atomic.h"
12 #include "ajabase/system/lock.h"
13 #if defined(AJA_LINUX)
14  #include <string.h> // For memcpy
15  #include <stdlib.h> // For realloc
16 #endif
17 #include <ios>
18 
19 using namespace std;
20 
21 #define LOGGING_ANCDATA AJADebug::IsActive(AJA_DebugUnit_AJAAncData)
22 #define LOGGING_ANC2110RX AJADebug::IsActive(AJA_DebugUnit_Anc2110Rcv)
23 #define LOGGING_ANC2110TX AJADebug::IsActive(AJA_DebugUnit_Anc2110Xmit)
24 
25 #define LOGMYERROR(__x__) {if (LOGGING_ANCDATA) AJA_sERROR (AJA_DebugUnit_AJAAncData, AJAFUNC << ": " << __x__);}
26 #define LOGMYWARN(__x__) {if (LOGGING_ANCDATA) AJA_sWARNING(AJA_DebugUnit_AJAAncData, AJAFUNC << ": " << __x__);}
27 #define LOGMYNOTE(__x__) {if (LOGGING_ANCDATA) AJA_sNOTICE (AJA_DebugUnit_AJAAncData, AJAFUNC << ": " << __x__);}
28 #define LOGMYINFO(__x__) {if (LOGGING_ANCDATA) AJA_sINFO (AJA_DebugUnit_AJAAncData, AJAFUNC << ": " << __x__);}
29 #define LOGMYDEBUG(__x__) {if (LOGGING_ANCDATA) AJA_sDEBUG (AJA_DebugUnit_AJAAncData, AJAFUNC << ": " << __x__);}
30 
31 #define RCV2110ERR(__x__) {if (LOGGING_ANC2110RX) AJA_sERROR (AJA_DebugUnit_Anc2110Rcv, AJAFUNC << ": " << __x__);}
32 #define RCV2110WARN(__x__) {if (LOGGING_ANC2110RX) AJA_sWARNING(AJA_DebugUnit_Anc2110Rcv, AJAFUNC << ": " << __x__);}
33 #define RCV2110NOTE(__x__) {if (LOGGING_ANC2110RX) AJA_sNOTICE (AJA_DebugUnit_Anc2110Rcv, AJAFUNC << ": " << __x__);}
34 #define RCV2110INFO(__x__) {if (LOGGING_ANC2110RX) AJA_sINFO (AJA_DebugUnit_Anc2110Rcv, AJAFUNC << ": " << __x__);}
35 #define RCV2110DBG(__x__) {if (LOGGING_ANC2110RX) AJA_sDEBUG (AJA_DebugUnit_Anc2110Rcv, AJAFUNC << ": " << __x__);}
36 
37 #define XMT2110ERR(__x__) {if (LOGGING_ANC2110TX) AJA_sERROR (AJA_DebugUnit_Anc2110Xmit, AJAFUNC << ": " << __x__);}
38 #define XMT2110WARN(__x__) {if (LOGGING_ANC2110TX) AJA_sWARNING(AJA_DebugUnit_Anc2110Xmit, AJAFUNC << ": " << __x__);}
39 #define XMT2110NOTE(__x__) {if (LOGGING_ANC2110TX) AJA_sNOTICE (AJA_DebugUnit_Anc2110Xmit, AJAFUNC << ": " << __x__);}
40 #define XMT2110INFO(__x__) {if (LOGGING_ANC2110TX) AJA_sINFO (AJA_DebugUnit_Anc2110Xmit, AJAFUNC << ": " << __x__);}
41 #define XMT2110DBG(__x__) {if (LOGGING_ANC2110TX) AJA_sDEBUG (AJA_DebugUnit_Anc2110Xmit, AJAFUNC << ": " << __x__);}
42 
43 #if defined(AJA_WINDOWS)
44  const size_t sENDL(2); // CRLF
45 #else
46  const size_t sENDL(1); // LF
47 #endif
48 
49 // RCV2110DDBG & XMT2110DDBG are for EXTREMELY detailed debug logging:
50 #if 0 // DetailedDebugging
51  #define RCV2110DDBG(__x__) RCV2110DBG(__x__)
52  #define XMT2110DDBG(__x__) XMT2110DBG(__x__)
53 #else
54  #define RCV2110DDBG(__x__)
55  #define XMT2110DDBG(__x__)
56 #endif
57 
58 #if defined(AJAHostIsBigEndian)
59  // Host is BigEndian (BE)
60  #define AJA_ENDIAN_16NtoH(__val__) (__val__)
61  #define AJA_ENDIAN_16HtoN(__val__) (__val__)
62  #define AJA_ENDIAN_32NtoH(__val__) (__val__)
63  #define AJA_ENDIAN_32HtoN(__val__) (__val__)
64  #define AJA_ENDIAN_64NtoH(__val__) (__val__)
65  #define AJA_ENDIAN_64HtoN(__val__) (__val__)
66 #else
67  // Host is LittleEndian (LE)
68  #define AJA_ENDIAN_16NtoH(__val__) AJA_ENDIAN_SWAP16(__val__)
69  #define AJA_ENDIAN_16HtoN(__val__) AJA_ENDIAN_SWAP16(__val__)
70  #define AJA_ENDIAN_32NtoH(__val__) AJA_ENDIAN_SWAP32(__val__)
71  #define AJA_ENDIAN_32HtoN(__val__) AJA_ENDIAN_SWAP32(__val__)
72  #define AJA_ENDIAN_64NtoH(__val__) AJA_ENDIAN_SWAP64(__val__)
73  #define AJA_ENDIAN_64HtoN(__val__) AJA_ENDIAN_SWAP64(__val__)
74 #endif
75 
76 
77 static inline uint32_t ENDIAN_32NtoH(const uint32_t inValue) {return AJA_ENDIAN_32NtoH(inValue);}
78 static inline uint32_t ENDIAN_32HtoN(const uint32_t inValue) {return AJA_ENDIAN_32HtoN(inValue);}
79 
80 
81 const uint32_t AJAAncillaryDataWrapperSize = 7; // 3 bytes header + DID + SID + DC + Checksum: i.e. everything EXCEPT the payload
82 const uint32_t AJAAuxillaryPacketSize = 32; // HDMI Aux packets are always 32 bytes
83 
84 #if defined(_DEBUG)
85  static uint32_t gConstructCount(0); // Number of constructor calls made
86  static uint32_t gDestructCount(0); // Number of destructor calls made
87 #endif // defined(_DEBUG)
88 
89 
90 
91 
93 {
94 #if defined(_DEBUG)
96 #endif // defined(_DEBUG)
97  Init();
98 }
99 
100 
102 {
103 #if defined(_DEBUG)
105 #endif // defined(_DEBUG)
106  Init();
107  *this = inClone;
108 }
109 
110 
112 {
113 #if defined(_DEBUG)
115 #endif // defined(_DEBUG)
116  Init();
117  if (pClone)
118  *this = *pClone;
119 }
120 
121 
123 {
124 #if defined(_DEBUG)
126 #endif // defined(_DEBUG)
127  FreeDataMemory();
128 }
129 
130 
132 {
133  FreeDataMemory(); // reset all internal data to defaults
134 
135  m_DID = 0x00;
136  m_SID = 0x00;
137  m_checksum = 0;
138  m_frameID = 0;
139  m_userData = 0;
140  m_rcvDataValid = false;
141  m_coding = AJAAncDataCoding_Digital;
142  m_ancType = AJAAncDataType_Unknown;
143  m_bufferFmt = AJAAncBufferFormat_Unknown;
144  // Default location:
145  m_location.SetDataLink(AJAAncDataLink_A) // LinkA
146  .SetDataStream(AJAAncDataStream_1) // DS1
147  .SetDataChannel(AJAAncDataChannel_Y) // Y channel
148 // .SetDataSpace(AJAAncDataSpace_VANC) // VANC
149  .SetHorizontalOffset(AJAAncDataHorizOffset_AnyVanc) // VANC
150  .SetLineNumber(AJAAncDataLineNumber_Unknown); // Unknown line number
151 
152  // HDMI Aux specific
153  m_auxType = 0;
154  m_auxHB1 = 0;
155  m_auxHB2 = 0;
156 }
157 
158 
160 {
161  Init();
162 }
163 
164 
166 {
167  return new AJAAncillaryData (this);
168 }
169 
170 
172 {
173  AJAStatus status;
174  FreeDataMemory();
175  try
176  {
177  m_payload.reserve(numBytes);
178  for (uint32_t ndx(0); ndx < numBytes; ndx++)
179  m_payload.push_back(0);
180  status = AJA_STATUS_SUCCESS;
181  }
182  catch(const bad_alloc &)
183  {
184  m_payload.clear();
185  status = AJA_STATUS_MEMORY;
186  }
187  if (AJA_FAILURE(status))
188  LOGMYERROR(::AJAStatusToString(status) << ": Unable to allocate/reserve " << DEC(numBytes) << " bytes");
189  return status;
190 }
191 
192 
194 {
195  m_payload.clear();
196  return AJA_STATUS_SUCCESS;
197 }
198 
199 
200 AJAStatus AJAAncillaryData::SetDID (const uint8_t inDID)
201 {
202  m_DID = inDID;
203  return AJA_STATUS_SUCCESS;
204 }
205 
206 
207 AJAStatus AJAAncillaryData::SetSID (const uint8_t inSID)
208 {
209  m_SID = inSID;
210  return AJA_STATUS_SUCCESS;
211 }
212 
213 AJAStatus AJAAncillaryData::SetChecksum (const uint8_t inChecksum, const bool inValidate)
214 {
215  m_checksum = inChecksum;
216  if (inValidate)
217  if (inChecksum != Calculate8BitChecksum())
218  return AJA_STATUS_FAIL;
219  return AJA_STATUS_SUCCESS;
220 }
221 
222 
223 uint16_t AJAAncillaryData::GetStreamInfo (void) const
224 {
225  if (IS_VALID_AJAAncDataStream(GetLocationDataStream()))
226  return uint16_t(GetLocationDataStream());
227  else if (IS_VALID_AJAAncDataLink(GetLocationVideoLink()))
228  return uint16_t(GetLocationVideoLink());
229  return 0;
230 }
231 
232 
234 {
235  // NOTE: This is NOT the "real" 9-bit checksum used in SMPTE 291 Ancillary packets,
236  // but it's calculated the same way and should be the same as the LS 8-bits
237  // of the 9-bit checksum...
238  uint8_t sum (m_DID);
239  sum += m_SID;
240  sum += uint8_t(m_payload.size());
241  if (!m_payload.empty())
242  for (ByteVector::size_type ndx(0); ndx < m_payload.size(); ndx++)
243  sum += m_payload[ndx];
244 NTV2_ASSERT(sum == uint8_t(Calculate9BitChecksum()));
245  return sum;
246 }
247 
248 
250 {
251  // SMPTE 291-1:2011: 6.7 Checksum Word
252  uint16_t sum (AddEvenParity(m_DID)); // DID
253  sum += AddEvenParity(m_SID); // + SDID
254  sum += AddEvenParity(UByte(GetDC())); // + DC
255  if (!m_payload.empty()) // + payload:
256  for (ByteVector::size_type ndx(0); ndx < m_payload.size(); ndx++)
257  sum += AddEvenParity(m_payload[ndx]);
258 
259  const bool b8 ((sum & 0x100) != 0);
260  const bool b9 (!b8);
261  return (sum & 0x1FF) | (b9 ? 0x200 : 0x000);
262 }
263 
264 
265 //**********
266 // Set anc data location parameters
267 //
269 {
270  AJAStatus status (SetLocationVideoLink(loc.GetDataLink()));
271  if (AJA_SUCCESS(status))
272  status = SetLocationDataStream(loc.GetDataStream());
273  if (AJA_SUCCESS(status))
274  status = SetLocationDataChannel(loc.GetDataChannel());
275  if (AJA_SUCCESS(status))
276  status = SetLocationHorizOffset(loc.GetHorizontalOffset());
277  if (AJA_SUCCESS(status))
278  status = SetLocationLineNumber(loc.GetLineNumber());
279  return status;
280 }
281 
282 
283 //-------------
284 //
286 {
287  if (!IS_VALID_AJAAncDataLink(inLinkValue))
288  return AJA_STATUS_RANGE;
289 
290  m_location.SetDataLink(inLinkValue);
291  return AJA_STATUS_SUCCESS;
292 }
293 
294 
295 //-------------
296 //
298 {
299  if (!IS_VALID_AJAAncDataStream(inStream))
300  return AJA_STATUS_RANGE;
301 
302  m_location.SetDataStream(inStream);
303  return AJA_STATUS_SUCCESS;
304 }
305 
306 
307 //-------------
308 //
310 {
311  if (!IS_VALID_AJAAncDataChannel(inChannel))
312  return AJA_STATUS_RANGE;
313 
314  m_location.SetDataChannel(inChannel);
315  return AJA_STATUS_SUCCESS;
316 }
317 
318 
319 //-------------
320 //
322 {
323  // No range checking here because we don't know how tall the frame is
324  m_location.SetLineNumber(inLineNum);
325  return AJA_STATUS_SUCCESS;
326 }
327 
328 
329 //-------------
330 //
332 {
333  // No range checking here because we don't know how wide the frame is
334  m_location.SetHorizontalOffset(inOffset);
335  return AJA_STATUS_SUCCESS;
336 }
337 
338 //-------------
339 //
341 {
342  if (m_coding != AJAAncDataCoding_Digital && m_coding != AJAAncDataCoding_Raw)
343  return AJA_STATUS_RANGE;
344 
345  m_coding = inCodingType;
346  return AJA_STATUS_SUCCESS;
347 }
348 
349 
350 //**********
351 // Copy payload data from external source to internal storage. Erases current payload memory
352 // (if any) and allocates new memory
353 
354 AJAStatus AJAAncillaryData::SetPayloadData (const uint8_t * pInData, const uint32_t inNumBytes)
355 {
356  if (pInData == NULL || inNumBytes == 0)
357  return AJA_STATUS_NULL;
358 
359  // [Re]Allocate...
360  AJAStatus status (AllocDataMemory(inNumBytes));
361  if (AJA_FAILURE(status))
362  return status;
363 
364  // Copy payload into memory...
365  ::memcpy (&m_payload[0], pInData, inNumBytes);
366  return AJA_STATUS_SUCCESS;
367 }
368 
369 
370 AJAStatus AJAAncillaryData::SetFromSMPTE334 (const uint16_t * pInData, const uint32_t inNumWords, const AJAAncDataLoc & inLocInfo)
371 {
372  if (!pInData)
373  return AJA_STATUS_NULL;
374  if (inNumWords < 7)
375  return AJA_STATUS_RANGE;
376 
377  const uint32_t payloadByteCount (uint32_t(pInData[5] & 0x00FF));
378  if ((inNumWords - 7) > payloadByteCount)
379  return AJA_STATUS_RANGE;
380 
381  // [Re]Allocate...
382  const AJAStatus status (AllocDataMemory(payloadByteCount));
383  if (AJA_FAILURE(status))
384  return status;
385 
386  // Copy payload into new memory...
387  for (uint32_t numWord (0); numWord < payloadByteCount; numWord++)
388  m_payload[numWord] = UByte(pInData[6+numWord] & 0x00FF);
389 
390  SetDataCoding(AJAAncDataCoding_Digital);
391  SetDataLocation(inLocInfo);
392  SetChecksum(UByte(pInData[6+payloadByteCount] & 0x00FF));
393  SetDID(UByte(pInData[3] & 0x00FF));
394  SetSID(UByte(pInData[4] & 0x00FF));
395 
396  return AJA_STATUS_SUCCESS;
397 }
398 
399 
400 //**********
401 // Append payload data from external source to existing internal storage. Realloc's current
402 // payload memory (if any) or allocates new memory
403 
404 AJAStatus AJAAncillaryData::AppendPayloadData (const uint8_t * pInData, const uint32_t inNumBytes)
405 {
406  if (pInData == NULL || inNumBytes == 0)
407  return AJA_STATUS_NULL;
408 
409  try
410  {
411  for (uint32_t ndx(0); ndx < inNumBytes; ndx++)
412  m_payload.push_back(pInData[ndx]);
413  }
414  catch(const bad_alloc &)
415  {
416  return AJA_STATUS_MEMORY;
417  }
418 
419  return AJA_STATUS_SUCCESS;
420 }
421 
422 
423 //**********
424 // Append payload data from an external AJAAncillaryData object to existing internal storage.
425 
427 {
428  try
429  {
430  const uint8_t * pInData (inAnc.GetPayloadData());
431  const uint32_t numBytes (uint32_t(inAnc.GetPayloadByteCount()));
432  for (uint32_t ndx(0); ndx < numBytes; ndx++)
433  m_payload.push_back(pInData[ndx]);
434  }
435  catch(const bad_alloc &)
436  {
437  return AJA_STATUS_MEMORY;
438  }
439 
440  return AJA_STATUS_SUCCESS;
441 }
442 
443 
444 //**********
445 // Copy payload data from internal storage to external destination.
446 
447 AJAStatus AJAAncillaryData::GetPayloadData (uint8_t * pOutData, const uint32_t inNumBytes) const
448 {
449  if (pOutData == NULL)
450  return AJA_STATUS_NULL;
451 
452  if (ByteVectorIndex(inNumBytes) > m_payload.size())
453  return AJA_STATUS_RANGE;
454 
455  ::memcpy (pOutData, GetPayloadData(), inNumBytes);
456  return AJA_STATUS_SUCCESS;
457 }
458 
459 
460 AJAStatus AJAAncillaryData::GetPayloadData (UWordSequence & outUDWs, const bool inAddParity) const
461 {
462  AJAStatus status (AJA_STATUS_SUCCESS);
463  const UWordSequence::size_type origSize (outUDWs.size());
464  for (ByteVectorConstIter iter(m_payload.begin()); iter != m_payload.end() && AJA_SUCCESS(status); ++iter)
465  {
466  const uint16_t UDW (inAddParity ? AddEvenParity(*iter) : *iter);
467  try
468  {
469  outUDWs.push_back(UDW); // Copy 8-bit data into LS 8 bits, add even parity to bit 8, and ~bit 8 to bit 9
470  }
471  catch(...)
472  {
473  status = AJA_STATUS_MEMORY;
474  }
475  } // for each packet byte
476  if (AJA_FAILURE(status))
477  outUDWs.resize(origSize);
478  return status;
479 }
480 
481 
482 uint8_t AJAAncillaryData::GetPayloadByteAtIndex (const uint32_t inIndex0) const
483 {
484  if (ByteVectorIndex(inIndex0) < m_payload.size())
485  return m_payload[inIndex0];
486  else
487  return 0;
488 }
489 
490 
491 AJAStatus AJAAncillaryData::SetPayloadByteAtIndex (const uint8_t inDataByte, const uint32_t inIndex0)
492 {
493  if (inIndex0 >= GetDC())
494  return AJA_STATUS_RANGE;
495 
496  m_payload[inIndex0] = inDataByte;
497  return AJA_STATUS_SUCCESS;
498 }
499 
500 
502 {
503  // should be overridden by derived classes to parse payload data to local data
504  m_rcvDataValid = false;
505 
506  return AJA_STATUS_SUCCESS;
507 }
508 
509 
510 //**********
511 // [Re]Initializes me from the 8-bit GUMP buffer received from extractor (ingest)
513  const size_t inMaxBytes,
514  const AJAAncDataLoc & inLocationInfo,
515  uint32_t & outPacketByteCount)
516 {
517  AJAStatus status = AJA_STATUS_SUCCESS;
518  outPacketByteCount = 0;
519  Clear();
520 
521  // If all is well, pInData points to the beginning of a "GUMP" packet:
522  //
523  // pInData -> 0: 0xFF // 1st byte is always FF
524  // 1: Hdr data1 // location data byte #1
525  // 2: Hdr data2 // location data byte #2
526  // 3: DID // ancillary packet Data ID
527  // 4: SID // ancillary packet Secondary ID (or DBN)
528  // 5: DC // ancillary packet Data Count (size of payload: 0 - 255)
529  // 6: Payload[0] // 1st byte of payload UDW
530  // 7: Payload[1] // 2nd byte of payload UDW
531  // ... ...
532  // (5 + DC): Payload[DC-1] // last byte of payload UDW
533  // (6 + DC): CS (checksum) // 8-bit sum of (DID + SID + DC + Payload[0] + ... + Payload[DC-1])
534  //
535  // (7 + DC): (start of next packet, if any...) returned in packetSize.
536  //
537  // Note that this is the layout of the data as returned from the Anc Extractor hardware, and
538  // is NOT exactly the same as SMPTE-291.
539  //
540  // The inMaxBytes input gives us an indication of how many "valid" bytes remain in the caller's TOTAL
541  // ANC Data buffer. We use this as a sanity check to make sure we don't try to parse past the end
542  // of the captured data.
543  //
544  // The caller provides an AJAAncDataLoc struct with all of the information filled in
545  // except the line number.
546  //
547  // When we have extracted the useful data from the packet, we return the packet size, in bytes, so the
548  // caller can find the start of the next packet (if any).
549 
550  const uint32_t maxBytes(uint32_t(inMaxBytes+0));
551  if (pInData == AJA_NULL)
552  {
553  LOGMYERROR("AJA_STATUS_NULL: NULL pointer");
554  return AJA_STATUS_NULL;
555  }
556 
557  // The minimum size for a packet (i.e. no payload) is 7 bytes
558  if (maxBytes < AJAAncillaryDataWrapperSize)
559  {
560  outPacketByteCount = maxBytes;
561  LOGMYERROR("AJA_STATUS_RANGE: Buffer size " << maxBytes << " smaller than " << AJAAncillaryDataWrapperSize << " bytes");
562  return AJA_STATUS_RANGE;
563  }
564 
565  // The first byte should be 0xFF. If it's not, then the Anc data stream may be broken...
566  if (pInData[0] != 0xFF)
567  {
568  // Let the caller try to resynchronize...
569  LOGMYDEBUG("No data: First GUMP byte is " << xHEX0N(uint16_t(pInData[0]),2) << ", expected 0xFF");
570  return AJA_STATUS_SUCCESS; // Not necessarily an error (no data)
571  }
572 
573  // There are sufficient bytes for a minimum packet, and the first byte is what we expect.
574  // Check the Data Count in this packet...
575  const uint32_t totalBytes (pInData[5] + AJAAncillaryDataWrapperSize);
576 
577  // Does the reported Data Count extend past the end of the buffer?
578  if (totalBytes > maxBytes)
579  {
580  outPacketByteCount = maxBytes;
581  LOGMYERROR("AJA_STATUS_RANGE: Reported packet size " << totalBytes << " [bytes] extends past end of buffer " << inMaxBytes << " by " << (totalBytes-inMaxBytes) << " byte(s)");
582  return AJA_STATUS_RANGE;
583  }
584 
585  // OK... There's enough data in the buffer to contain the packet, and everything else checks out,
586  // so continue parsing the data...
587  m_DID = pInData[3]; // SMPTE-291 Data ID
588  m_SID = pInData[4]; // SMPTE-291 Secondary ID (or DBN)
589  m_checksum = pInData[totalBytes-1]; // Reported checksum
590 
591  // Caller provides all of the "location" information as a default. If the packet header info is "real", overwrite it...
592  m_location = inLocationInfo;
593 
594  if ((pInData[1] & 0x80) != 0)
595  {
596  m_coding = ((pInData[1] & 0x40) == 0) ? AJAAncDataCoding_Digital : AJAAncDataCoding_Raw; // byte 1, bit 6
597  m_location.SetDataStream(AJAAncDataStream_1); // ??? GUMP doesn't tell us the data stream it came from
598  m_location.SetDataChannel(((pInData[1] & 0x20) == 0) ? AJAAncDataChannel_C : AJAAncDataChannel_Y); // byte 1, bit 5
599  m_location.SetDataSpace(((pInData[1] & 0x10) == 0) ? AJAAncDataSpace_VANC : AJAAncDataSpace_HANC); // byte 1, bit 4
600  m_location.SetLineNumber(uint16_t((pInData[1] & 0x0F) << 7) + uint16_t(pInData[2] & 0x7F)); // byte 1, bits 3:0 + byte 2, bits 6:0
601  SetBufferFormat(AJAAncBufferFormat_SDI);
602  //m_location.SetHorizontalOffset(hOffset); // ??? GUMP doesn't report the horiz offset of where the packet started in the raster line
603  }
604 
605  // Allocate space for the payload and copy it in...
606  const uint32_t payloadSize (pInData[5]); // DC: SMPTE-291 Data Count
607  if (payloadSize)
608  {
609  status = AllocDataMemory(payloadSize); // NOTE: This also sets my "DC" value
610  if (AJA_SUCCESS(status))
611  for (uint32_t ndx(0); ndx < payloadSize; ndx++)
612  m_payload[ndx] = pInData[ndx+6];
613  }
614 
615  outPacketByteCount = totalBytes;
616  LOGMYDEBUG("Set from GUMP buffer OK: " << AsString(32));
617  return status;
618 
619 } // InitWithReceivedData
620 
621 //**********
622 // [Re]Initializes me from the buffer received from extractor (ingest)
624  const size_t inMaxBytes,
625  uint32_t & outPacketByteCount)
626 {
627  AJAStatus status = AJA_STATUS_SUCCESS;
628  Clear();
629 
630  // If all is well, pInData points to the beginning of an HDMI Aux packet:
631  //
632  // pInData -> 0: Packet Type // 1st byte is Packet Type / HB0
633  // 1: Header Data1 // location data byte #1
634  // 2: Header Data2 // location data byte #2
635  // 3-32: Payload
636  // ... ...
637  //
638  // Note that this is the layout of the data as returned from the Aux Extractor hardware, and
639  // is NOT exactly the same as the HDMI Specificaiton. (Error checking bytes are omitted)
640  //
641  // The inMaxBytes input gives us an indication of how many "valid" bytes remain in the caller's TOTAL
642  // ANC Data buffer. We use this as a sanity check to make sure we don't try to parse past the end
643  // of the captured data.
644  //
645  // Once the useful data has been copied from the packet buffer, we return the packet size,
646  // in bytes, so the caller can find the start of the next packet (if any).
647 
648  if (pInData == AJA_NULL)
649  {
650  outPacketByteCount = 0;
651  LOGMYERROR("AJA_STATUS_NULL: NULL pointer");
652  return AJA_STATUS_NULL;
653  }
654 
655  // The first byte should be a recognized Aux Packet type.
656  // If it's not, we will assume we are at the end of the valid data
657  if (!AuxPacketTypeIsValid(pInData[0]))
658  {
659  // Let the caller try to resynchronize...
660  outPacketByteCount = 0;
661  LOGMYDEBUG("No data: First Aux byte " << xHEX0N(uint16_t(pInData[0]),2) << " is not a recognized type");
662  return AJA_STATUS_SUCCESS; // Not necessarily an error (no data)
663  }
664 
665  const uint32_t maxBytes(uint32_t(inMaxBytes+0));
666  // The minimum size for a packet (i.e. no payload) is 7 bytes
667  if (maxBytes < AJAAuxillaryPacketSize)
668  {
669  outPacketByteCount = maxBytes;
670  LOGMYERROR("AJA_STATUS_RANGE: Buffer size " << maxBytes << " smaller than " << AJAAuxillaryPacketSize << " bytes");
671  return AJA_STATUS_RANGE;
672  }
673 
674  // There are enough bytes for a minimum packet!
675 
676  const uint32_t totalBytes (AJAAuxillaryPacketSize);
677  // There's enough data in the buffer to contain the packet, and everything else checks out,
678  // so continue parsing the data...
679  m_auxType = pInData[0]; // HDMI Header Byte 0 / Packet Type
680  m_auxHB1 = pInData[1]; // HDMI Header Byte 1 / Header Data 1
681  m_auxHB2 = pInData[2]; // HDMI Header Byte 2 / Header Data 2
682 
683  // HDMI Aux InfoFrames have a checksum and packet length specifier, while other packet types do not
684  m_checksum = 0;
685  uint32_t payloadSize(28); // HDMI Aux Maximum & Default payload
686  int payloadOffset(3); // Packet payload normally starts at 4th byte
687  if (m_auxType & 0x80) // InfoFrame?
688  { // InfoFrames are special:
689  m_checksum = pInData[3]; // InfoFrame checksum is in 4th byte
690  payloadSize = m_auxHB2 & 0x0000001F; // InfoFrame payload size is in LS 5 bits of 3rd byte (HB2)
691  payloadOffset = 4; // InfoFrame payload starts at 5th byte
692  }
693 
694  m_coding = AJAAncDataCoding_Digital;
695  SetBufferFormat(AJAAncBufferFormat_HDMI);
696 
697  // Allocate space for the payload and copy it in...
698  if (payloadSize)
699  {
700  status = AllocDataMemory(payloadSize); // NOTE: This also sets my "DC" value
701  if (AJA_SUCCESS(status))
702  for (uint32_t ndx(0); ndx < payloadSize; ndx++)
703  m_payload[ndx] = pInData[ndx+payloadOffset];
704  }
705 
706  outPacketByteCount = totalBytes;
707  LOGMYDEBUG("Set from HDMI buffer OK: " << AsString(32));
708  return status;
709 
710 } // InitWithReceivedData
711 
713 {
714  uint32_t pktByteCount(0);
715  if (inData.empty())
716  return AJA_STATUS_NULL;
717  return InitWithReceivedData (&inData[0], uint32_t(inData.size()), inLocationInfo, pktByteCount);
718 }
719 
720 
721 //**********
722 // This returns the number of bytes that will be returned by GenerateTransmitData(). This is usually
723 // called first so the caller can allocate a buffer large enough to hold the results.
724 
725 AJAStatus AJAAncillaryData::GetRawPacketSize (uint32_t & outPacketSize) const
726 {
727  outPacketSize = 0;
728 
729  if (m_coding == AJAAncDataCoding_Digital)
730  {
731  // Normal, "digital" ancillary data (i.e. SMPTE-291 based) will have a total size of
732  // seven bytes (3 bytes header + DID + SID + DC + Checksum) plus the payload size...
733  if (GetDC() <= 255)
734  outPacketSize = GetDC() + AJAAncillaryDataWrapperSize;
735  else
736  {
737  // More than 255 bytes of payload is illegal -- return 255 (truncated) to prevent generating a bad GUMP buffer...
738  LOGMYWARN("Illegal packet size " << DEC(GetDC()) << ", exceeds 255 -- returning truncated value (255): " << AsString(32));
739  outPacketSize = 255 + AJAAncillaryDataWrapperSize;
740  }
741  }
742  else if (m_coding == AJAAncDataCoding_Raw)
743  {
744  // Determine how many "packets" are needed to be generated in order to pass all of the payload data (max 255 bytes per packet)...
745  if (!IsEmpty())
746  {
747  // All "analog" packets will have a 255-byte payload, except for the last one...
748  const uint32_t numPackets ((GetDC() + 254) / 255);
749  const uint32_t lastPacketDC (GetDC() % 255);
750 
751  // Each packet has a 7-byte "wrapper" + the payload size...
752  outPacketSize = ((numPackets - 1) * (255 + AJAAncillaryDataWrapperSize)) // All packets except the last one have a payload of 255 bytes
753  + (lastPacketDC + AJAAncillaryDataWrapperSize); // The last packet carries the remainder
754  }
755  }
756  else // huh? (coding not set)
757  return AJA_STATUS_FAIL;
758 
759  return AJA_STATUS_SUCCESS;
760 }
761 
762 
763 //**********
764 // Writes my payload data into the given 8-bit GUMP buffer (playback)
765 
766 AJAStatus AJAAncillaryData::GenerateTransmitData (uint8_t * pData, const size_t inMaxBytes, uint32_t & outPacketSize)
767 {
768  AJAStatus status (GeneratePayloadData());
769 
770  outPacketSize = 0;
771 
772  // Verify that the caller has allocated enough space to hold what's going to be generated
773  uint32_t myPacketSize(0), maxBytes(uint32_t(inMaxBytes+0));
774  GetRawPacketSize(myPacketSize);
775 
776  if (myPacketSize == 0)
777  {
778  LOGMYERROR("AJA_STATUS_FAIL: nothing to do -- raw packet size is zero: " << AsString(32));
779  return AJA_STATUS_FAIL;
780  }
781  if (myPacketSize > maxBytes)
782  {
783  LOGMYERROR("AJA_STATUS_FAIL: " << maxBytes << "-byte client buffer too small to hold " << myPacketSize << " byte(s): " << AsString(32));
784  return AJA_STATUS_FAIL;
785  }
786  if (!IsDigital() && !IsRaw()) // Coding not set: don't generate anything
787  {
788  LOGMYERROR("AJA_STATUS_FAIL: invalid packet coding (neither Raw nor Digital): " << AsString(32));
789  return AJA_STATUS_FAIL;
790  }
791 
792  if (IsDigital())
793  {
794  pData[0] = GetGUMPHeaderByte1();
795  pData[1] = GetGUMPHeaderByte2();
796  pData[2] = GetGUMPHeaderByte3();
797  pData[3] = m_DID;
798  pData[4] = m_SID;
799 
800  uint8_t payloadSize = uint8_t((GetDC() > 255) ? 255 : GetDC()); // Truncate payload to max 255 bytes
801  pData[5] = payloadSize;
802 
803  // Copy payload data to raw stream...
804  status = GetPayloadData(&pData[6], payloadSize);
805 
806  // NOTE: The hardware automatically recalculates the checksum anyway, so this byte
807  // is ignored. However, if the original source had a checksum, we'll send it back...
808  pData[6+payloadSize] = Calculate8BitChecksum();
809 
810  // Done!
811  outPacketSize = myPacketSize;
812  }
813  else if (IsRaw())
814  {
815  // "Analog" or "raw" ancillary data is special in that it may generate multiple output packets,
816  // depending on the length of the payload data.
817  // NOTE: This code assumes that zero-length payloads have already been screened out (in GetRawPacketSize)!
818  const uint32_t numPackets ((GetDC() + 254) / 255);
819 
820  // all packets will have a 255-byte payload except the last one
821  //Note: Unused -- uint32_t lastPacketDC = m_DC % 255;
822 
823  const uint8_t * payloadPtr = GetPayloadData();
824  uint32_t remainingPayloadData = GetDC();
825 
826  for (uint32_t ndx(0); ndx < numPackets; ndx++)
827  {
828  pData[0] = GetGUMPHeaderByte1();
829  pData[1] = GetGUMPHeaderByte2();
830  pData[2] = GetGUMPHeaderByte3();
831  pData[3] = m_DID;
832  pData[4] = m_SID;
833 
834  uint8_t payloadSize = uint8_t((remainingPayloadData > 255) ? 255 : remainingPayloadData); // Truncate payload to max 255 bytes
835  pData[5] = payloadSize; // DC
836 
837  // Copy payload data into GUMP buffer...
838  ::memcpy(&pData[6], payloadPtr, payloadSize);
839 
840  // NOTE: The hardware automatically recalculates the checksum anyway, so this byte
841  // is ignored. However, if the original source had a checksum we'll send it back...
842  pData[6+payloadSize] = m_checksum;
843 
844  // Advance the payloadPtr to the beginning of the next bunch of payload data...
845  payloadPtr += payloadSize;
846 
847  // Decrease the remaining data count...
848  remainingPayloadData -= payloadSize;
849 
850  // Advance the external data stream pointer to the beginning of the next packet...
851  pData += (payloadSize + AJAAncillaryDataWrapperSize);
852  } // for each raw packet
853 
854  outPacketSize = myPacketSize; // Done!
855  } // else if IsRaw
856  LOGMYDEBUG(outPacketSize << " byte(s) generated: " << AsString(32));
857  return status;
858 
859 } // GenerateTransmitData
860 
861 
863 {
864  uint8_t result (0x80); // LE bit is always active
865 
866  if (m_coding == AJAAncDataCoding_Raw)
867  result |= 0x40; // analog/raw (1) or digital (0) ancillary data
868 
869  if (m_location.IsLumaChannel())
870  result |= 0x20; // carried in Y (1) or C stream
871 
872  if (m_location.IsHanc())
873  result |= 0x10;
874 
875  // ms 4 bits of line number
876  result |= (m_location.GetLineNumber() >> 7) & 0x0F; // ms 4 bits [10:7] of line number
877 
878  return result;
879 }
880 
881 
883 {
884  AJAStatus status (GeneratePayloadData());
885  const UWordSequence::size_type origSize (outRawComponents.size());
886 
887  if (IsDigital())
888  {
889  try
890  {
891  const uint8_t dataCount ((GetDC() > 255) ? 255 : uint8_t(GetDC())); // Truncate payload to max 255 bytes
892  outRawComponents.push_back(0x000); // 000
893  outRawComponents.push_back(0x3FF); // 3FF
894  outRawComponents.push_back(0x3FF); // 3FF
895  outRawComponents.push_back(AddEvenParity(GetDID())); // DID
896  outRawComponents.push_back(AddEvenParity(GetSID())); // SDID
897  outRawComponents.push_back(AddEvenParity(dataCount)); // DC
898  }
899  catch(...)
900  {
901  outRawComponents.resize(origSize);
902  status = AJA_STATUS_MEMORY;
903  }
904  }
905 
906  // Copy payload data into output vector...
907  if (AJA_SUCCESS(status))
908  status = GetPayloadData(outRawComponents, IsDigital() /* Add parity for Digital only */); // UDWs
909 
910  // The hardware automatically recalcs the CS, but still needs to be there...
911  if (AJA_SUCCESS(status) && IsDigital())
912  outRawComponents.push_back(Calculate9BitChecksum()); // CS
913 
914  if (AJA_SUCCESS(status))
915  {LOGMYDEBUG((origSize ? "Appended " : "Generated ") << (outRawComponents.size() - origSize) << " UWords from " << AsString(32) << endl << UWordSequence(outRawComponents));}
916  else
917  LOGMYERROR("Failed: " << ::AJAStatusToString(status) << ": origSize=" << origSize << ", " << AsString(32));
918  return status;
919 }
920 
921 
922 // These tables implement the 16-UDWs-per-20-bytes packing cadence:
923 static const size_t gIndexes[] = { 0,1,2,3, 3,4,5,6, 6,7,8,9, 9,10,11,12, 12,13,14,15 };
924 static const unsigned gShifts[] = { 22,12,2,8, 24,14,4,6, 26,16,6,4, 28,18,8,2, 30,20,10,0 };
925 static const uint32_t gMasks[] = { 0xFFC00000, 0x003FF000, 0x00000FFC, 0x00000003,
926  0xFF000000, 0x00FFC000, 0x00003FF0, 0x0000000F,
927  0xFC000000, 0x03FF0000, 0x0000FFC0, 0x0000003F,
928  0xF0000000, 0x0FFC0000, 0x0003FF00, 0x000000FF,
929  0xC0000000, 0x3FF00000, 0x000FFC00, 0x000003FF };
930 
931 
933 {
934  AJAStatus status (GeneratePayloadData());
935  const ULWordSequence::size_type origSize (outData.size());
936  uint32_t u32 (0); // 32-bit value
937 
938  if (!IsDigital())
939  {XMT2110WARN("Analog/raw packet skipped/ignored: " << AsString(32)); return AJA_STATUS_SUCCESS;}
940  if (GetDC() > 255)
941  {XMT2110ERR("Data count exceeds 255: " << AsString(32)); return AJA_STATUS_RANGE;}
942 
944  // Prepare an array of 10-bit DID/SID/DC/UDWs/CS values...
945  const uint16_t did (AddEvenParity(GetDID()));
946  const uint16_t sid (AddEvenParity(GetSID()));
947  const uint16_t dc (AddEvenParity(uint8_t(GetDC())));
948  const uint16_t cs (Calculate9BitChecksum());
949 
950  UWordSequence UDW16s; // 10-bit even-parity words
951  UDW16s.reserve(GetDC()+4); // Reserve DID + SID + DC + UDWs + CS
952  UDW16s.push_back(did);
953  UDW16s.push_back(sid);
954  UDW16s.push_back(dc);
955 
956  // Append 8-bit payload data, converting into 10-bit values with even parity added...
957  status = GetPayloadData(UDW16s, true); // Append 10-bit even-parity UDWs
958  if (AJA_FAILURE(status))
959  {XMT2110ERR("GetPayloadData failed: " << AsString(32)); return status;}
960  UDW16s.push_back(cs); // Checksum is the caboose
961  // Done -- 10-bit DID/SID/DC/UDWs/CS array is prepared
962  XMT2110DBG("From " << UWordSequence(UDW16s) << " " << AsString(32));
964 
965  // Begin writing into "outData" array.
966  // My first 32-bit longword is the Anc packet header, which contains location info...
967  const AJARTPAncPacketHeader pktHdr (GetDataLocation());
968  const uint32_t pktHdrWord (pktHdr.GetULWord());
969  outData.push_back(pktHdrWord);
970 // XMT2110DDBG("outU32s[" << DEC(outData.size()-1) << "]=" << xHEX0N(ENDIAN_32NtoH(pktHdrWord),8) << " (BigEndian)"); // Byte-Swap it to make BigEndian look right
971 
972  // All subsequent 32-bit longwords come from the array of 10-bit values I built earlier.
973  const size_t numUDWs (UDW16s.size());
974  size_t UDWndx (0);
975  u32 = 0;
976  do
977  {
978  for (unsigned loopNdx(0); loopNdx < sizeof(gIndexes) / sizeof(size_t); loopNdx++)
979  {
980  const bool is4th ((loopNdx & 3) == 3);
981  const size_t ndx (UDWndx + gIndexes[loopNdx]);
982  const bool isPastEnd (ndx >= numUDWs);
983  const uint32_t UDW (isPastEnd ? 0 : uint32_t(UDW16s[ndx]));
984  const unsigned shift (gShifts[loopNdx]);
985  const uint32_t mask (gMasks[loopNdx]);
986 // if (!isPastEnd) XMT2110DDBG("u16s[" << DEC(ndx) << "]=" << xHEX0N(UDW,3));
987  if (is4th)
988  {
989  u32 |= (UDW >> shift) & mask;
990  outData.push_back(ENDIAN_32HtoN(u32));
991 // XMT2110DDBG("outU32s[" << DEC(outData.size()-1) << "]=" << xHEX0N(u32,8) << " (BigEndian)");
992  u32 = 0; // Reset, start over
993  if (isPastEnd)
994  break; // Done, 32-bit longword aligned
995  continue;
996  }
997  // Continue building this 32-bit longword...
998  u32 |= (UDW << shift) & mask;
999  } // inner loop
1000  UDWndx += 16;
1001  } while (UDWndx < numUDWs);
1002 
1003  /* The Pattern: (unrolling the above loop): BitCnt ShiftLeft ShiftRight
1004  u32 = (uint32_t(UDW16s.at( 0)) << 22) & 0xFFC00000; // 0b00000|0x00|00: [ 0] all 10 bits 0+10=10 32-10=22
1005  u32 |= (uint32_t(UDW16s.at( 1)) << 12) & 0x003FF000; // 0b00001|0x01|01: [ 1] all 10 bits 10+10=20 22-10=12
1006  u32 |= (uint32_t(UDW16s.at( 2)) << 2) & 0x00000FFC; // 0b00010|0x02|02: [ 2] all 10 bits 20+10=30 12-10=2
1007  u32 |= (uint32_t(UDW16s.at( 3)) >> 8) & 0x00000003; // 0b00011|0x03|03: [ 3] first (MS 2 bits) 30+2=32 10-2=8
1008  outData.push_back(ENDIAN_32HtoN(u32));
1009  u32 = (uint32_t(UDW16s.at( 3)) << 24) & 0xFF000000; // 0b00100|0x04|04: [ 3] last (LS 8 bits) 0+8=8 32-8=24
1010  u32 |= (uint32_t(UDW16s.at( 4)) << 14) & 0x00FFC000; // 0b00101|0x05|05: [ 4] all 10 bits 8+10=18 24-10=14
1011  u32 |= (uint32_t(UDW16s.at( 5)) << 4) & 0x00003FF0; // 0b00110|0x06|06: [ 5] all 10 bits 18+10=28 14-10=4
1012  u32 |= (uint32_t(UDW16s.at( 6)) >> 6) & 0x0000000F; // 0b00111|0x07|07: [ 6] first (MS 4 bits) 28+4=32 10-4=6
1013  outData.push_back(ENDIAN_32HtoN(u32));
1014  u32 = (uint32_t(UDW16s.at( 6)) << 26) & 0xFC000000; // 0b01000|0x08|08: [ 6] last (LS 6 bits) 0+6=6 32-6=26
1015  u32 |= (uint32_t(UDW16s.at( 7)) << 16) & 0x03FF0000; // 0b01001|0x09|09: [ 7] all 10 bits 6+10=16 26-10=16
1016  u32 |= (uint32_t(UDW16s.at( 8)) << 6) & 0x0000FFC0; // 0b01010|0x0A|10: [ 8] all 10 bits 16+10=26 16-10=6
1017  u32 |= (uint32_t(UDW16s.at( 9)) >> 4) & 0x0000003F; // 0b01011|0x0B|11: [ 9] first (MS 6 bits) 26+6=32 10-6=4
1018  outData.push_back(ENDIAN_32HtoN(u32));
1019  u32 = (uint32_t(UDW16s.at( 9)) << 28) & 0xF0000000; // 0b01100|0x0C|12: [ 9] last (LS 4 bits) 0+4=4 32-4=28
1020  u32 |= (uint32_t(UDW16s.at(10)) << 18) & 0x0FFC0000; // 0b01101|0x0D|13: [10] all 10 bits 4+10=14 28-10=18
1021  u32 |= (uint32_t(UDW16s.at(11)) << 8) & 0x0003FF00; // 0b01110|0x0E|14: [11] all 10 bits 14+10=24 18-10=8
1022  u32 |= (uint32_t(UDW16s.at(12)) >> 2) & 0x000000FF; // 0b01111|0x0F|15: [12] first (MS 8 bits) 24+8=32 10-8=2
1023  outData.push_back(ENDIAN_32HtoN(u32));
1024  u32 = (uint32_t(UDW16s.at(12)) << 30) & 0xC0000000; // 0b10000|0x10|16: [12] last (LS 2 bits) 0+2=2 32-2=30
1025  u32 |= (uint32_t(UDW16s.at(13)) << 20) & 0x3FF00000; // 0b10001|0x11|17: [13] all 10 bits 2+10=12 30-10=20
1026  u32 |= (uint32_t(UDW16s.at(14)) << 10) & 0x000FFC00; // 0b10010|0x12|18: [14] all 10 bits 12+10=22 20-10=10
1027  u32 |= (uint32_t(UDW16s.at(15)) >> 0) & 0x000003FF; // 0b10011|0x13|19: [15] all 10 bits 22+10=32 10-10=0
1028  outData.push_back(ENDIAN_32HtoN(u32)); */
1029 
1030 #if defined(_DEBUG)
1031 {
1032  ostringstream oss;
1033  oss << (origSize ? "Appended " : "Generated ") << (outData.size() - origSize) << " U32s:";
1034  for (size_t ndx(origSize); ndx < outData.size(); ndx++) // outData is in Network Byte Order
1035  oss << " " << HEX0N(ENDIAN_32NtoH(outData[ndx]),8); // so byte-swap to make it look right in the log
1036  oss << " BigEndian from " << AsString(32);
1037  XMT2110DBG(oss.str());
1038 }
1039 #else
1040  XMT2110DBG((origSize ? "Appended " : "Generated ")
1041  << (outData.size() - origSize) << " 32-bit words from " << AsString(32));
1042 #endif
1043  return AJA_STATUS_SUCCESS;
1044 } // GenerateTransmitData
1045 
1046 
1047 AJAStatus AJAAncillaryData::InitWithReceivedData (const ULWordSequence & inU32s, uint16_t & inOutU32Ndx, const bool inIgnoreChecksum)
1048 {
1049  const size_t numU32s (inU32s.size());
1050 
1051  Clear(); // Reset me -- start over
1052 
1053  if (inOutU32Ndx >= numU32s)
1054  {RCV2110ERR("Index error: [" << DEC(inOutU32Ndx) << "] past end of [" << DEC(numU32s) << "] element buffer"); return AJA_STATUS_RANGE;}
1055 
1056  AJARTPAncPacketHeader ancPktHeader;
1057  if (!ancPktHeader.ReadFromULWordVector(inU32s, inOutU32Ndx))
1058  {RCV2110ERR("AJARTPAncPacketHeader::ReadFromULWordVector failed at [" << DEC(inOutU32Ndx) << "]"); return AJA_STATUS_FAIL;}
1059 
1060  const AJAAncDataLoc dataLoc (ancPktHeader.AsDataLocation());
1061  RCV2110DDBG("u32=" << xHEX0N(ENDIAN_32NtoH(inU32s.at(inOutU32Ndx)),8) << " inU32s[" << DEC(inOutU32Ndx) << " of " << DEC(numU32s) << "] AncPktHdr: " << ancPktHeader << " -- AncDataLoc: " << dataLoc);
1062 
1063  if (++inOutU32Ndx >= numU32s)
1064  {RCV2110ERR("Index error: [" << DEC(inOutU32Ndx) << "] past end of [" << DEC(numU32s) << "] element buffer"); return AJA_STATUS_RANGE;}
1065 
1066  // Set location info...
1067  AJAStatus result;
1068  result = SetLocationVideoLink(dataLoc.GetDataLink());
1069  if (AJA_FAILURE(result)) {RCV2110ERR("SetLocationVideoLink failed, dataLoc: " << dataLoc); return result;}
1070 
1071  result = SetLocationDataStream(dataLoc.GetDataStream());
1072  if (AJA_FAILURE(result)) {RCV2110ERR("SetLocationDataStream failed, dataLoc: " << dataLoc); return result;}
1073 
1074  result = SetLocationDataChannel(dataLoc.GetDataChannel());
1075  if (AJA_FAILURE(result)) {RCV2110ERR("SetLocationDataChannel failed, dataLoc: " << dataLoc); return result;}
1076 
1077  result = SetLocationHorizOffset(dataLoc.GetHorizontalOffset());
1078  if (AJA_FAILURE(result)) {RCV2110ERR("SetLocationHorizOffset failed, dataLoc: " << dataLoc); return result;}
1079 
1080  result = SetLocationLineNumber(dataLoc.GetLineNumber());
1081  if (AJA_FAILURE(result)) {RCV2110ERR("SetLocationLineNumber failed, dataLoc: " << dataLoc); return result;}
1082 
1083  // Unpack this anc packet...
1084  UWordSequence u16s; // 10-bit even-parity words
1085  bool gotChecksum (false);
1086  size_t dataCount (0);
1087  uint32_t u32 (ENDIAN_32NtoH(inU32s.at(inOutU32Ndx)));
1088  const size_t startU32Ndx (inOutU32Ndx);
1089  RCV2110DDBG("u32=" << xHEX0N(u32,8) << " inU32s[" << DEC(inOutU32Ndx) << " of " << DEC(numU32s) << "]");
1090  do
1091  {
1092  uint16_t u16 (0);
1093  for (unsigned loopNdx(0); loopNdx < 20 && !gotChecksum; loopNdx++)
1094  {
1095  const bool is4th ((loopNdx & 3) == 3);
1096  const bool is1st ((loopNdx & 3) == 0);
1097  const unsigned shift (gShifts[loopNdx]);
1098  const uint32_t mask (gMasks[loopNdx]);
1099  if (is4th)
1100  {
1101  u16 = uint16_t((u32 & mask) << shift);
1102 
1103  // Grab next u32 value...
1104  if (++inOutU32Ndx >= numU32s)
1105  {
1106  u16s.push_back(u16); // RCV2110DDBG("u16s[" << DEC(u16s.size()-1) << "]=" << xHEX0N(u16,3) << " (Past end)");
1107  break; // Past end
1108  }
1109  u32 = ENDIAN_32NtoH(inU32s.at(inOutU32Ndx));
1110  RCV2110DDBG("u32=" << xHEX0N(u32,8) << " inU32s[" << DEC(inOutU32Ndx) << " of " << DEC(numU32s) << "], u16=" << xHEX0N(u16,3)
1111  << " from " << DEC(loopNdx) << "(" << xHEX0N(inU32s.at(inOutU32Ndx-1),8) << " & " << xHEX0N(mask,8) << ") << " << DEC(shift));
1112  if (shift)
1113  continue; // go around
1114  }
1115  else if (is1st)
1116  {
1117 // RCV2110DDBG("u16s[" << DEC(u16s.size()) << "]=" << xHEX0N(u16,3) << " | " << xHEX0N(uint16_t((u32 & mask) >> shift),3)
1118 // << " = " << xHEX0N(u16 | uint16_t((u32 & mask) >> shift),3));
1119  u16 |= uint16_t((u32 & mask) >> shift);
1120  }
1121  else
1122  {
1123  u16 = uint16_t((u32 & mask) >> shift);
1124 // RCV2110DDBG("u16s[" << DEC(u16s.size()) << "]=" << xHEX0N(u16,3));
1125  }
1126  u16s.push_back(u16); // RCV2110DDBG("u16s[" << DEC(u16s.size()-1) << "]=" << xHEX0N(u16,3));
1127  switch(u16s.size())
1128  {
1129  case 1: SetDID(uint8_t(u16)); break; // Got DID
1130  case 2: SetSID(uint8_t(u16)); break; // Got SID
1131  case 3: dataCount = size_t(u16 & 0x0FF); break; // Got DC
1132  default: if (u16s.size() == (dataCount + 4))
1133  {gotChecksum = true; RCV2110DDBG("Got checksum, DC=" << xHEX0N(dataCount,2) << " CS=" << xHEX0N(u16s.back(),3));} // Got CS
1134  break;
1135  }
1136  } // loop 20 times (or until gotChecksum)
1137  if (gotChecksum)
1138  break;
1139  } while (inOutU32Ndx < numU32s);
1140 
1141  if (u16s.size() < 4)
1142  { ostringstream oss;
1143  if (u16s.size() < 1) oss << " NoDID";
1144  else oss << " DID=" << xHEX0N(UWord(GetDID()),2);
1145  if (u16s.size() < 2) oss << " NoSID";
1146  else oss << " SID=" << xHEX0N(UWord(GetSID()),2);
1147  if (u16s.size() < 3) oss << " NoDC";
1148  else oss << " DC=" << DEC(dataCount);
1149  RCV2110ERR("Incomplete/bad packet:" << oss.str() << " NoCS" << " -- only unpacked " << u16s);
1150  return AJA_STATUS_FAIL;
1151  }
1152  RCV2110DBG("Consumed " << DEC(inOutU32Ndx - startU32Ndx + 1) << " ULWord(s), " << (gotChecksum?"":"NoCS, ") << "DC=" << DEC(dataCount) << ", unpacked " << u16s);
1153  if (inOutU32Ndx < numU32s)
1154  inOutU32Ndx++; // Bump to next Anc packet, if any
1155 
1156  // Did we get the whole packet?
1157  if (dataCount > (u16s.size()-3)) // DC > (u16s.size minus DID, SID, DC)?
1158  { // Uh-oh: too few u16s -- someone's pulling our leg
1159  RCV2110ERR("Incomplete/bad packet: " << DEC(u16s.size()) << " U16s, but missing " << DEC(dataCount - (u16s.size()-3))
1160  << " byte(s), expected DC=" << DEC(dataCount) << " -- DID=" << xHEX0N(UWord(GetDID()),2) << " SID=" << xHEX0N(UWord(GetSID()),2));
1161  return AJA_STATUS_FAIL;
1162  }
1163 
1164  // Copy in the Anc packet data, while stripping off parity...
1165  for (size_t ndx(0); ndx < dataCount; ndx++)
1166  m_payload.push_back(uint8_t(u16s.at(ndx+3)));
1167 
1168  result = SetChecksum(uint8_t(u16s.at(u16s.size()-1)), true /*validate*/);
1169  if (AJA_FAILURE(result))
1170  {
1171  if (inIgnoreChecksum)
1172  {RCV2110WARN("SetChecksum=" << xHEX0N(u16s.at(u16s.size()-1),3) << " failed, calculated=" << xHEX0N(Calculate9BitChecksum(),3)); result = AJA_STATUS_SUCCESS;}
1173  else
1174  {RCV2110ERR("SetChecksum=" << xHEX0N(u16s.at(u16s.size()-1),3) << " failed, calculated=" << xHEX0N(Calculate9BitChecksum(),3)); return result;}
1175  }
1176  SetBufferFormat(AJAAncBufferFormat_RTP);
1177  RCV2110DBG(AsString(64));
1178 
1179  /* The Pattern: (unrolling the above loop):
1180  u32 = ENDIAN_32NtoH(inU32s.at(0));
1181  u16 = uint16_t((u32 & 0xFFC00000) >> 22); // all 10 bits 0
1182  u16s.push_back(u16);
1183  u16 = uint16_t((u32 & 0x003FF000) >> 12); // all 10 bits 1
1184  u16s.push_back(u16);
1185  u16 = uint16_t((u32 & 0x00000FFC) >> 2); // all 10 bits 2
1186  u16s.push_back(u16);
1187  u16 = uint16_t((u32 & 0x00000003) << 8); // first (MS 2 bits) 3
1188 
1189  u32 = ENDIAN_32NtoH(inU32s.at(1));
1190  u16 |= uint16_t((u32 & 0xFF000000) >> 24); // last (LS 8 bits) 4
1191  u16s.push_back(u16);
1192  u16 = uint16_t((u32 & 0x00FFC000) >> 14); // all 10 bits 5
1193  u16s.push_back(u16);
1194  u16 = uint16_t((u32 & 0x00003FF0) >> 4); // all 10 bits 6
1195  u16s.push_back(u16);
1196  u16 = uint16_t((u32 & 0x0000000F) << 6); // first (MS 4 bits) 7
1197 
1198  u32 = ENDIAN_32NtoH(inU32s.at(2));
1199  u16 |= uint16_t((u32 & 0xFC000000) >> 26); // last (LS 6 bits) 8
1200  u16s.push_back(u16);
1201  u16 = uint16_t((u32 & 0x03FF0000) >> 16); // all 10 bits 9
1202  u16s.push_back(u16);
1203  u16 = uint16_t((u32 & 0x0000FFC0) >> 6); // all 10 bits 10
1204  u16s.push_back(u16);
1205  u16 = uint16_t((u32 & 0x0000003F) << 4); // first (MS 6 bits) 11
1206 
1207  u32 = ENDIAN_32NtoH(inU32s.at(3));
1208  u16 |= uint16_t((u32 & 0xF0000000) >> 28); // last (LS 4 bits) 12
1209  u16s.push_back(u16);
1210  u16 = uint16_t((u32 & 0x0FFC0000) >> 18); // all 10 bits 13
1211  u16s.push_back(u16);
1212  u16 = uint16_t((u32 & 0x0003FF00) >> 8); // all 10 bits 14
1213  u16s.push_back(u16);
1214  u16 = uint16_t((u32 & 0x000000FF) << 2); // first (MS 8 bits) 15
1215 
1216  u32 = ENDIAN_32NtoH(inU32s.at(4));
1217  u16 |= uint16_t((u32 & 0xC0000000) >> 30); // last (LS 2 bits) 16
1218  u16s.push_back(u16);
1219  u16 = uint16_t((u32 & 0x3FF00000) >> 20); // all 10 bits 17
1220  u16s.push_back(u16);
1221  u16 = uint16_t((u32 & 0x000FFC00) >> 10); // all 10 bits 18
1222  u16s.push_back(u16);
1223  u16 = uint16_t((u32 & 0x000003FF) >> 0); // all 10 bits 19
1224  u16s.push_back(u16);
1225 */
1226  return result;
1227 } // InitWithReceivedData (const ULWordSequence&,uint16_t&)
1228 
1229 
1230 static const string gEmptyString;
1231 
1232 
1233 const string & AJAAncDataLinkToString (const AJAAncDataLink inValue, const bool inCompact)
1234 {
1235  static const string gAncDataLinkToStr [] = {"A", "B", "?"};
1236  static const string gDAncDataLinkToStr [] = {"AJAAncDataLink_A", "AJAAncDataLink_B", "AJAAncDataLink_Unknown"};
1237 
1238  return IS_VALID_AJAAncDataLink(inValue) ? (inCompact ? gAncDataLinkToStr[inValue] : gDAncDataLinkToStr[inValue]) : gAncDataLinkToStr[2];
1239 }
1240 
1241 
1242 const string & AJAAncDataStreamToString (const AJAAncDataStream inValue, const bool inCompact)
1243 {
1244  static const string gAncDataStreamToStr [] = {"DS1", "DS2", "DS3", "DS4", "?"};
1245  static const string gDAncDataStreamToStr [] = {"AJAAncDataStream_1", "AJAAncDataStream_2",
1246  "AJAAncDataStream_3", "AJAAncDataStream_4", "AJAAncDataStream_Unknown"};
1247 
1248  return IS_VALID_AJAAncDataStream(inValue) ? (inCompact ? gAncDataStreamToStr[inValue] : gDAncDataStreamToStr[inValue]) : gEmptyString;
1249 }
1250 
1251 
1252 const string & AJAAncDataChannelToString (const AJAAncDataChannel inValue, const bool inCompact)
1253 {
1254  static const string gAncDataChannelToStr [] = {"C", "Y", "?"};
1255  static const string gDAncDataChannelToStr [] = {"AJAAncDataChannel_C", "AJAAncDataChannel_Y", "AJAAncDataChannel_Unknown"};
1256 
1257  return IS_VALID_AJAAncDataChannel(inValue) ? (inCompact ? gAncDataChannelToStr[inValue] : gDAncDataChannelToStr[inValue]) : gEmptyString;
1258 }
1259 
1260 
1261 const string & AJAAncDataSpaceToString (const AJAAncDataSpace inValue, const bool inCompact)
1262 {
1263  static const string gAncDataSpaceToStr [] = {"VANC", "HANC", "????"};
1264  static const string gDAncDataSpaceToStr [] = {"AJAAncDataSpace_VANC", "AJAAncDataSpace_HANC", "AJAAncDataSpace_Unknown"};
1265 
1266  return IS_VALID_AJAAncDataSpace(inValue) ? (inCompact ? gAncDataSpaceToStr[inValue] : gDAncDataSpaceToStr[inValue]) : gEmptyString;
1267 }
1268 
1269 
1270 string AJAAncLineNumberToString (const uint16_t inValue)
1271 {
1272  ostringstream oss;
1273  if (inValue == AJAAncDataLineNumber_AnyVanc)
1274  oss << "VANC";
1275  else if (inValue == AJAAncDataLineNumber_Anywhere)
1276  oss << "UNSP"; // Unspecified -- anywhere
1277  else if (inValue == AJAAncDataLineNumber_Future)
1278  oss << "OVFL"; // Overflow
1279  else if (inValue == AJAAncDataLineNumber_Unknown)
1280  oss << "UNKN";
1281  else
1282  oss << "L" << DEC(inValue);
1283  return oss.str();
1284 }
1285 
1286 
1287 string AJAAncHorizOffsetToString (const uint16_t inValue)
1288 {
1289  ostringstream oss;
1290  if (inValue == AJAAncDataHorizOffset_AnyHanc)
1291  oss << "HANC";
1292  else if (inValue == AJAAncDataHorizOffset_AnyVanc)
1293  oss << "VANC";
1294  else if (inValue == AJAAncDataHorizOffset_Anywhere)
1295  oss << "UNSP";
1296  else if (inValue == AJAAncDataHorizOffset_Future)
1297  oss << "OVFL";
1298  else if (inValue == AJAAncDataHorizOffset_Unknown)
1299  oss << "UNKN";
1300  else
1301  oss << "+" << DEC(inValue);
1302  return oss.str();
1303 }
1304 
1305 
1306 ostream & AJAAncDataLoc::Print (ostream & oss, const bool inCompact) const
1307 {
1308  oss << ::AJAAncDataLinkToString(GetDataLink(), inCompact)
1309  << "|" << ::AJAAncDataStreamToString(GetDataStream(), inCompact)
1310  << "|" << ::AJAAncDataChannelToString(GetDataChannel(), inCompact)
1311  << "|" << ::AJAAncLineNumberToString(GetLineNumber())
1312  << "|" << ::AJAAncHorizOffsetToString(GetHorizontalOffset());
1313  return oss;
1314 }
1315 
1317 {
1318  // Everything must match exactly:
1319  if (GetDataLink() != inRHS.GetDataLink())
1320  return AJA_STATUS_FAIL;
1321  if (GetDataStream() != inRHS.GetDataStream())
1322  return AJA_STATUS_FAIL;
1323  if (GetDataChannel() != inRHS.GetDataChannel())
1324  return AJA_STATUS_FAIL;
1325 // if (GetDataSpace() == inRHS.GetDataSpace()) // No longer necessary
1326 // return AJA_STATUS_FAIL;
1327  if (GetLineNumber() != inRHS.GetLineNumber())
1328  return AJA_STATUS_FAIL;
1329  if (GetHorizontalOffset() && inRHS.GetHorizontalOffset())
1330  if (GetHorizontalOffset() != inRHS.GetHorizontalOffset())
1331  return AJA_STATUS_FAIL;
1332  return AJA_STATUS_SUCCESS;
1333 }
1334 
1335 string AJAAncDataLoc::CompareWithInfo (const AJAAncDataLoc & inRHS) const
1336 {
1337  ostringstream oss;
1338  if (GetDataLink() != inRHS.GetDataLink())
1339  oss << ", Link " << ::AJAAncDataLinkToString(GetDataLink()) << " != " << ::AJAAncDataLinkToString(inRHS.GetDataLink());
1340  if (GetDataStream() != inRHS.GetDataStream())
1341  oss << ", " << ::AJAAncDataStreamToString(GetDataStream()) << " != " << ::AJAAncDataStreamToString(inRHS.GetDataStream());
1342  if (GetDataChannel() != inRHS.GetDataChannel())
1343  oss << ", Data Channel " << ::AJAAncDataChannelToString(GetDataChannel()) << " != " << ::AJAAncDataChannelToString(inRHS.GetDataChannel());
1344 // if (GetDataSpace() == inRHS.GetDataSpace()) // No longer necessary
1345 // oss << ", " << ::AJAAncDataSpaceToString(GetDataSpace()) << " != " << ::AJAAncDataSpaceToString(inRHS.GetDataSpace());
1346  if (GetLineNumber() != inRHS.GetLineNumber())
1347  oss << ", " << "Line " << DEC(GetLineNumber()) << " != " << DEC(inRHS.GetLineNumber());
1348  if (GetHorizontalOffset() && inRHS.GetHorizontalOffset())
1349  if (GetHorizontalOffset() != inRHS.GetHorizontalOffset())
1350  oss << ", " << "HOffset " << DEC(GetHorizontalOffset()) << " != " << DEC(inRHS.GetHorizontalOffset());
1351 
1352  if (oss.str().length() > 2)
1353  return oss.str().substr(2, oss.str().length() - 2); // remove first ", "
1354  return string();
1355 }
1356 
1357 
1358 string AJAAncDataLocToString (const AJAAncDataLoc & inValue, const bool inCompact)
1359 {
1360  ostringstream oss;
1361  inValue.Print(oss, inCompact);
1362  return oss.str();
1363 }
1364 
1365 ostream & operator << (ostream & inOutStream, const AJAAncDataLoc & inValue)
1366 {
1367  return inValue.Print(inOutStream, true);
1368 }
1369 
1370 
1371 const string & AJAAncDataCodingToString (const AJAAncDataCoding inValue, const bool inCompact)
1372 {
1373  static const string gAncDataCodingToStr [] = {"Dig", "Ana", "???"};
1374  static const string gDAncDataCodingToStr [] = {"AJAAncDataCoding_Digital", "AJAAncDataCoding_Raw", "AJAAncDataCoding_Unknown"};
1375 
1376  return IS_VALID_AJAAncDataCoding(inValue) ? (inCompact ? gAncDataCodingToStr[inValue] : gDAncDataCodingToStr[inValue]) : gEmptyString;
1377 }
1378 
1379 
1380 const string & AJAAncBufferFormatToString (const AJAAncBufferFormat inValue, const bool inCompact)
1381 {
1382  static const string gAncBufFmtToStr [] = {"UNK", "FBVANC", "SDI", "RTP", "HDMI", ""};
1383  static const string gDAncBufFmtToStr [] = {"AJAAncBufferFormat_Unknown", "AJAAncBufferFormat_FBVANC",
1384  "AJAAncBufferFormat_SDI", "AJAAncBufferFormat_RTP","AJAAncBufferFormat_HDMI", ""};
1385 
1386  return IS_VALID_AJAAncBufferFormat(inValue) ? (inCompact ? gAncBufFmtToStr[inValue] : gDAncBufFmtToStr[inValue]) : gEmptyString;
1387 }
1388 
1389 
1390 const string & AJAAncDataTypeToString (const AJAAncDataType inValue, const bool inCompact)
1391 {
1392  static const string gAncDataTypeToStr [] = { "Unknown", "SMPTE 2016-3 AFD", "SMPTE 12-M RP188", "SMPTE 12-M VITC",
1393  "SMPTE 334 CEA708", "SMPTE 334 CEA608", "CEA608 Line21", "SMPTE 352 VPID",
1394  "SMPTE 2051 2 Frame Marker", "524D Frame Status", "5251 Frame Status",
1395  "HDR SDR", "HDR10", "HDR HLG", "HDMI Aux", "?"};
1396 
1397  static const string gDAncDataTypeToStr [] = { "AJAAncDataType_Unknown", "AJAAncDataType_Smpte2016_3", "AJAAncDataType_Timecode_ATC",
1398  "AJAAncDataType_Timecode_VITC", "AJAAncDataType_Cea708", "AJAAncDataType_Cea608_Vanc",
1399  "AJAAncDataType_Cea608_Line21", "AJAAncDataType_Smpte352", "AJAAncDataType_Smpte2051",
1400  "AJAAncDataType_FrameStatusInfo524D", "AJAAncDataType_FrameStatusInfo5251",
1401  "AJAAncDataType_HDR_SDR", "AJAAncDataType_HDR_HDR10", "AJAAncDataType_HDR_HLG",
1402  "AJAAncDataType_HDMI_Aux", "?"};
1403 
1404  return inValue < AJAAncDataType_Size ? (inCompact ? gAncDataTypeToStr[inValue] : gDAncDataTypeToStr[inValue]) : gEmptyString;
1405 }
1406 
1407 
1408 ostream & AJAAncillaryData::Print (ostream & oss, const bool inDumpPayload) const
1409 {
1410  oss << "Type:\t\t" << IDAsString() << endl;
1411  if (!IsHDMI())
1412  oss << "DID:\t\t" << xHEX0N(uint32_t(GetDID()),2) << endl
1413  << "SID:\t\t" << xHEX0N(uint32_t(GetSID()),2) << endl;
1414  oss << "DC:\t\t" << DEC(GetDC()) << endl;
1415  if (!IsHDMI())
1416  oss << "CS:\t\t" << xHEX0N(uint32_t(m_checksum),2) << endl
1417  << "Loc:\t\t" << GetDataLocation() << endl;
1418  oss << "Coding:\t\t" << ::AJAAncDataCodingToString(m_coding) << endl
1419  << "Frame:\t\t" << xHEX0N(GetFrameID(),8) << endl
1420  << "Format:\t\t" << ::AJAAncBufferFormatToString(GetBufferFormat()) << endl
1421  << "Valid:\t\t" << (GotValidReceiveData() ? "Yes" : "No");
1422  if (inDumpPayload)
1423  {oss << endl; DumpPayload(oss);}
1424  return oss;
1425 }
1426 
1427 string AJAAncillaryData::IDAsString (void) const
1428 {
1429  ostringstream oss;
1430  if (IsRaw())
1431  oss << "Analog/Raw Line " << DEC(GetDataLocation().GetLineNumber()) << " Packet";
1432  else if (IsHDMI())
1433  oss << AuxPacketTypeToString(GetAuxType());
1434  else
1435  oss << DIDSIDToString(GetDID(), GetSID());
1436  return oss.str();
1437 }
1438 
1439 string AJAAncillaryData::AsString (const uint16_t inMaxBytes) const
1440 {
1441  ostringstream oss;
1442  oss << "[" << ::AJAAncDataCodingToString(GetDataCoding());
1443  if (IsHDMI())
1444  oss << "|" << xHEX0N(uint16_t(GetAuxType()),2)
1445  << HEX0N(uint16_t(GetAuxHB1()),2)
1446  << HEX0N(uint16_t(GetAuxHB2()),2);
1447  else
1448  oss << "|" << ::AJAAncDataLocToString(GetDataLocation())
1449  << "|" << GetDIDSIDPair() << "|CS" << HEX0N(uint16_t(GetChecksum()),2);
1450  oss << "|DC=" << DEC(GetDC());
1451  if (m_frameID)
1452  oss << "|FRx" << HEX0N(GetFrameID(),8);
1453  if (IS_KNOWN_AJAAncBufferFormat(m_bufferFmt))
1454  oss << "|" << ::AJAAncBufferFormatToString(GetBufferFormat());
1455  const string typeStr (IsHDMI() ? AuxPacketTypeToString(GetAuxType())
1456  : DIDSIDToString(GetDID(), GetSID()));
1457  if (!typeStr.empty())
1458  oss << "|" << typeStr;
1459  oss << "]";
1460  if (inMaxBytes && GetDC())
1461  {
1462  uint16_t bytesToDump = uint16_t(GetDC());
1463  oss << ": ";
1464  if (inMaxBytes < bytesToDump)
1465  bytesToDump = inMaxBytes;
1466  for (uint16_t ndx(0); ndx < bytesToDump; ndx++)
1467  oss << HEX0N(uint16_t(m_payload[ndx]),2);
1468  if (bytesToDump < uint16_t(GetDC()))
1469  oss << "..."; // Indicate dump was truncated
1470  }
1471  return oss.str();
1472 }
1473 
1474 ostream & operator << (ostream & inOutStream, const AJAAncDIDSIDPair & inData)
1475 {
1476  inOutStream << "x" << HEX0N(uint16_t(inData.first), 2) << "x" << HEX0N(uint16_t(inData.second), 2);
1477  return inOutStream;
1478 }
1479 
1480 ostream & AJAAncillaryData::DumpPayload (ostream & inOutStream) const
1481 {
1482  if (IsEmpty())
1483  inOutStream << "(NULL payload)" << endl;
1484  else
1485  {
1486  const int32_t kBytesPerLine (32);
1487  uint32_t count (GetDC());
1488  const uint8_t * pData (GetPayloadData());
1489 
1490  while (count)
1491  {
1492  const uint32_t numBytes ((count >= kBytesPerLine) ? kBytesPerLine : count);
1493  inOutStream << ((count == GetDC()) ? "Payload: " : " ");
1494  for (uint8_t num(0); num < numBytes; num++)
1495  {
1496  inOutStream << " " << HEX0N(uint32_t(pData[num]),2);
1497  if (num % 4 == 3)
1498  inOutStream << " "; // an extra space every four bytes for readability
1499  }
1500  inOutStream << endl;
1501  pData += numBytes;
1502  count -= numBytes;
1503  } // loop til break
1504  }
1505  return inOutStream;
1506 }
1507 
1508 
1509 AJAStatus AJAAncillaryData::Compare (const AJAAncillaryData & inRHS, const bool inIgnoreLocation, const bool inIgnoreChecksum) const
1510 {
1511  if (GetDID() != inRHS.GetDID())
1512  return AJA_STATUS_FAIL;
1513  if (GetSID() != inRHS.GetSID())
1514  return AJA_STATUS_FAIL;
1515  if (GetDC() != inRHS.GetDC())
1516  return AJA_STATUS_FAIL;
1517 
1518  if (!inIgnoreChecksum)
1519  if (GetChecksum() != inRHS.GetChecksum())
1520  return AJA_STATUS_FAIL;
1521  if (!inIgnoreLocation)
1522  if (AJA_FAILURE(GetDataLocation().Compare(inRHS.GetDataLocation())))
1523  return AJA_STATUS_FAIL;
1524 
1525  if (GetDataCoding() != inRHS.GetDataCoding())
1526  return AJA_STATUS_FAIL;
1527 
1528  if (!IsEmpty())
1529  if (m_payload != inRHS.m_payload)
1530  return AJA_STATUS_FAIL;
1531 
1532  return AJA_STATUS_SUCCESS;
1533 }
1534 
1535 
1536 string AJAAncillaryData::CompareWithInfo (const AJAAncillaryData & inRHS, const bool inIgnoreLocation, const bool inIgnoreChecksum) const
1537 {
1538  ostringstream oss;
1539  if (GetDID() != inRHS.GetDID())
1540  oss << endl << "DID mismatch: " << xHEX0N(uint16_t(GetDID()),2) << " != " << xHEX0N(uint16_t(inRHS.GetDID()),2);
1541  if (GetSID() != inRHS.GetSID())
1542  oss << endl << "SID mismatch: " << xHEX0N(uint16_t(GetSID()),2) << " != " << xHEX0N(uint16_t(inRHS.GetSID()),2);
1543  if (GetDC() != inRHS.GetDC())
1544  oss << endl << "DC mismatch: " << xHEX0N(GetDC(),4) << " != " << xHEX0N(inRHS.GetDC(),4);
1545 
1546  if (!inIgnoreChecksum)
1547  if (GetChecksum() != inRHS.GetChecksum())
1548  oss << endl << "CS mismatch: " << xHEX0N(uint16_t(GetChecksum()),2) << " != " << xHEX0N(uint16_t(inRHS.GetChecksum()),2);
1549  if (!inIgnoreLocation)
1550  { const string info(GetDataLocation().CompareWithInfo(inRHS.GetDataLocation()));
1551  if (!info.empty())
1552  oss << endl << "Location mismatch: " << info;
1553  }
1554 
1555  if (GetDataCoding() != inRHS.GetDataCoding())
1556  oss << endl << "DataCoding mismatch: " << AJAAncDataCodingToString(GetDataCoding()) << " != " << AJAAncDataCodingToString(inRHS.GetDataCoding());
1557 
1558  if (!IsEmpty())
1559  {
1560  const uint8_t *pLHS(GetPayloadData()), *pRHS(inRHS.GetPayloadData());
1561  ULWordSequence diffNdxs;
1562  for (size_t ndx(0); ndx < GetPayloadByteCount(); ndx++)
1563  if (pLHS[ndx] != pRHS[ndx])
1564  diffNdxs.push_back(ULWord(ndx));
1565  if (!diffNdxs.empty())
1566  oss << endl << DEC(diffNdxs.size()) << " of " << DEC(GetDC()) << " (" << fDEC(100.0*double(diffNdxs.size())/double(GetDC()), 5, 2)
1567  << "%) mismatched payload bytes, starting at offset " << DEC(diffNdxs.at(0));
1568  }
1569 
1570  if (oss.str().length() > sENDL)
1571  return oss.str().substr(sENDL, oss.str().length() - sENDL); // remove leading newline
1572  return string();
1573 }
1574 
1576 {
1577  if (this != &inRHS)
1578  {
1579  m_DID = inRHS.m_DID;
1580  m_SID = inRHS.m_SID;
1581  m_checksum = inRHS.m_checksum;
1582  m_location = inRHS.m_location;
1583  m_coding = inRHS.m_coding;
1584  m_payload = inRHS.m_payload;
1585  m_rcvDataValid = inRHS.m_rcvDataValid;
1586  m_ancType = inRHS.m_ancType;
1587  m_bufferFmt = inRHS.m_bufferFmt;
1588  m_frameID = inRHS.m_frameID;
1589  m_userData = inRHS.m_userData;
1590 
1591  // HDMI Aux specific
1592  m_auxType = inRHS.m_auxType;
1593  m_auxHB1 = inRHS.m_auxHB1;
1594  m_auxHB2 = inRHS.m_auxHB2;
1595  }
1596  return *this;
1597 }
1598 
1600 {
1601  return AJA_SUCCESS(Compare(inRHS, false/*ignoreLocations*/, false/*ignoreChecksums*/));
1602 }
1603 
1604 
1605 // Returns the original data byte in bits 7:0, plus even parity in bit 8 and ~bit 8 in bit 9
1606 uint16_t AJAAncillaryData::AddEvenParity (const uint8_t inDataByte)
1607 {
1608  // Parity Table
1609  static const uint16_t gEvenParityTable[256] =
1610  {
1611  /* 0-7 */ 0x200,0x101,0x102,0x203,0x104,0x205,0x206,0x107,
1612  /* 8-15 */ 0x108,0x209,0x20A,0x10B,0x20C,0x10D,0x10E,0x20F,
1613  /* 16-23 */ 0x110,0x211,0x212,0x113,0x214,0x115,0x116,0x217,
1614  /* 24-31 */ 0x218,0x119,0x11A,0x21B,0x11C,0x21D,0x21E,0x11F,
1615  /* 32-39 */ 0x120,0x221,0x222,0x123,0x224,0x125,0x126,0x227,
1616  /* 40-47 */ 0x228,0x129,0x12A,0x22B,0x12C,0x22D,0x22E,0x12F,
1617  /* 48-55 */ 0x230,0x131,0x132,0x233,0x134,0x235,0x236,0x137,
1618  /* 56-63 */ 0x138,0x239,0x23A,0x13B,0x23C,0x13D,0x13E,0x23F,
1619  /* 64-71 */ 0x140,0x241,0x242,0x143,0x244,0x145,0x146,0x247,
1620  /* 72-79 */ 0x248,0x149,0x14A,0x24B,0x14C,0x24D,0x24E,0x14F,
1621  /* 80-87 */ 0x250,0x151,0x152,0x253,0x154,0x255,0x256,0x157,
1622  /* 88-95 */ 0x158,0x259,0x25A,0x15B,0x25C,0x15D,0x15E,0x25F,
1623  /* 96-103 */ 0x260,0x161,0x162,0x263,0x164,0x265,0x266,0x167,
1624  /* 104-111 */ 0x168,0x269,0x26A,0x16B,0x26C,0x16D,0x16E,0x26F,
1625  /* 112-119 */ 0x170,0x271,0x272,0x173,0x274,0x175,0x176,0x277,
1626  /* 120-127 */ 0x278,0x179,0x17A,0x27B,0x17C,0x27D,0x27E,0x17F,
1627  /* 128-135 */ 0x180,0x281,0x282,0x183,0x284,0x185,0x186,0x287,
1628  /* 136-143 */ 0x288,0x189,0x18A,0x28B,0x18C,0x28D,0x28E,0x18F,
1629  /* 144-151 */ 0x290,0x191,0x192,0x293,0x194,0x295,0x296,0x197,
1630  /* 152-159 */ 0x198,0x299,0x29A,0x19B,0x29C,0x19D,0x19E,0x29F,
1631  /* 160-167 */ 0x2A0,0x1A1,0x1A2,0x2A3,0x1A4,0x2A5,0x2A6,0x1A7,
1632  /* 168-175 */ 0x1A8,0x2A9,0x2AA,0x1AB,0x2AC,0x1AD,0x1AE,0x2AF,
1633  /* 176-183 */ 0x1B0,0x2B1,0x2B2,0x1B3,0x2B4,0x1B5,0x1B6,0x2B7,
1634  /* 184-191 */ 0x2B8,0x1B9,0x1BA,0x2BB,0x1BC,0x2BD,0x2BE,0x1BF,
1635  /* 192-199 */ 0x2C0,0x1C1,0x1C2,0x2C3,0x1C4,0x2C5,0x2C6,0x1C7,
1636  /* 200-207 */ 0x1C8,0x2C9,0x2CA,0x1CB,0x2CC,0x1CD,0x1CE,0x2CF,
1637  /* 208-215 */ 0x1D0,0x2D1,0x2D2,0x1D3,0x2D4,0x1D5,0x1D6,0x2D7,
1638  /* 216-223 */ 0x2D8,0x1D9,0x1DA,0x2DB,0x1DC,0x2DD,0x2DE,0x1DF,
1639  /* 224-231 */ 0x1E0,0x2E1,0x2E2,0x1E3,0x2E4,0x1E5,0x1E6,0x2E7,
1640  /* 232-239 */ 0x2E8,0x1E9,0x1EA,0x2EB,0x1EC,0x2ED,0x2EE,0x1EF,
1641  /* 240-247 */ 0x2F0,0x1F1,0x1F2,0x2F3,0x1F4,0x2F5,0x2F6,0x1F7,
1642  /* 248-255 */ 0x1F8,0x2F9,0x2FA,0x1FB,0x2FC,0x1FD,0x1FE,0x2FF
1643  }; // gEvenParityTable
1644  return gEvenParityTable[inDataByte];
1645 }
1646 
1647 
1648 string AncChannelSearchSelectToString (const AncChannelSearchSelect inSelect, const bool inCompact)
1649 {
1650  switch (inSelect)
1651  {
1652  case AncChannelSearch_Y: return inCompact ? "Y" : "AncChannelSearch_Y";
1653  case AncChannelSearch_C: return inCompact ? "C" : "AncChannelSearch_C";
1654  case AncChannelSearch_Both: return inCompact ? "Y+C" : "AncChannelSearch_Both";
1655  default: break;
1656  }
1657  return "";
1658 }
1659 
1660 
1662  const uint16_t inStartIndex,
1663  const uint16_t inTotalCount,
1664  const uint16_t inIncrement = 2)
1665 {
1666  bool bErr (false);
1667  UWord ndx (0);
1668  if (inIncrement == 0 || inIncrement > 2)
1669  return true; // Increment must be 1 or 2
1670 
1671  // Check parity on all words...
1672  for (ndx = 3; ndx < inTotalCount - 1; ndx++) // Skip ANC Data Flags and Checksum
1673  {
1674  const UWord wordValue (inYUV16Line[inStartIndex + ndx * inIncrement]);
1675  if (wordValue != AJAAncillaryData::AddEvenParity(wordValue & 0xFF))
1676  {
1677  LOGMYERROR ("Parity error at word " << ndx << ": got " << xHEX0N(wordValue,2)
1678  << ", expected " << xHEX0N(AJAAncillaryData::AddEvenParity(wordValue & 0xFF),2));
1679  bErr = true;
1680  }
1681  }
1682 
1683  // The checksum word is different: bit 8 is part of the checksum total, and bit 9 should be ~bit 8...
1684  const UWord checksum (inYUV16Line [inStartIndex + (inTotalCount - 1) * inIncrement]);
1685  const bool b8 ((checksum & BIT(8)) != 0);
1686  const bool b9 ((checksum & BIT(9)) != 0);
1687  if (b8 == b9)
1688  {
1689  LOGMYERROR ("Checksum word error: got " << xHEX0N(checksum,2) << ", expected " << xHEX0N(checksum ^ 0x200, 2));
1690  bErr = true;
1691  }
1692 
1693  // Check the checksum math...
1694  UWord sum (0);
1695  for (ndx = 3; ndx < inTotalCount - 1; ndx++)
1696  sum += inYUV16Line [inStartIndex + ndx * inIncrement] & 0x1FF;
1697 
1698  if ((sum & 0x1FF) != (checksum & 0x1FF))
1699  {
1700  LOGMYERROR ("Checksum math error: got " << xHEX0N(checksum & 0x1FF, 2) << ", expected " << xHEX0N(sum & 0x1FF, 2));
1701  bErr = true;
1702  }
1703 
1704  return bErr;
1705 
1706 } // CheckAncParityAndChecksum
1707 
1708 
1710  const AncChannelSearchSelect inChanSelect,
1711  U16Packets & outRawPackets,
1712  UWordSequence & outWordOffsets)
1713 {
1714  const UWord wordCountMax (UWord(inYUV16Line.size ()));
1715 
1716  // If we're only looking at Y samples, start the search 1 word into the line...
1717  const UWord searchOffset (inChanSelect == AncChannelSearch_Y ? 1 : 0);
1718 
1719  // If we're looking in both channels (e.g. SD video), increment search words by 1, else skip at every other word...
1720  const UWord searchIncr (inChanSelect == AncChannelSearch_Both ? 1 : 2);
1721 
1722  outRawPackets.clear();
1723  outWordOffsets.clear();
1724 
1725  if (!IS_VALID_AncChannelSearchSelect(inChanSelect))
1726  {LOGMYERROR("Bad search select value " << DEC(inChanSelect)); return false;} // bad search select
1727  if (wordCountMax < 12)
1728  {LOGMYERROR("UWordSequence size " << DEC(wordCountMax) << " too small"); return false;} // too small
1729 
1730  for (UWord wordNum = searchOffset; wordNum < (wordCountMax - 12); wordNum += searchIncr)
1731  {
1732  const UWord ancHdr0 (inYUV16Line.at (wordNum + (0 * searchIncr))); // 0x000
1733  const UWord ancHdr1 (inYUV16Line.at (wordNum + (1 * searchIncr))); // 0x3ff
1734  const UWord ancHdr2 (inYUV16Line.at (wordNum + (2 * searchIncr))); // 0x3ff
1735  const UWord ancHdr3 (inYUV16Line.at (wordNum + (3 * searchIncr))); // DID
1736  const UWord ancHdr4 (inYUV16Line.at (wordNum + (4 * searchIncr))); // SDID
1737  const UWord ancHdr5 (inYUV16Line.at (wordNum + (5 * searchIncr))); // DC
1738  if (ancHdr0 == 0x000 && ancHdr1 == 0x3ff && ancHdr2 == 0x3ff)
1739  {
1740  // Total words in ANC packet: 6 header words + data count + checksum word...
1741  UWord dataCount (ancHdr5 & 0xFF);
1742  UWord totalCount (6 + dataCount + 1);
1743 
1744  if (totalCount > wordCountMax)
1745  {
1746  totalCount = wordCountMax;
1747  LOGMYERROR ("packet totalCount " << totalCount << " exceeds max " << wordCountMax);
1748  return false;
1749  }
1750 
1751  // Be sure we don't go past the end of the line buffer...
1752  if (ULWord (wordNum + totalCount) >= wordCountMax)
1753  {
1754  LOGMYDEBUG ("past end of line: " << wordNum << " + " << totalCount << " >= " << wordCountMax);
1755  return false; // Past end of line buffer
1756  }
1757 
1758  if (CheckAncParityAndChecksum (inYUV16Line, wordNum, totalCount, searchIncr))
1759  return false; // Parity/Checksum error
1760 
1761  U16Packet packet;
1762  for (unsigned i = 0; i < totalCount; i++)
1763  packet.push_back (inYUV16Line.at (wordNum + (i * searchIncr)));
1764  outRawPackets.push_back (packet);
1765  outWordOffsets.push_back (wordNum);
1766 
1767  LOGMYINFO ("Found ANC packet in " << ::AncChannelSearchSelectToString(inChanSelect)
1768  << ": DID=" << xHEX0N(ancHdr3,4)
1769  << " SDID=" << xHEX0N(ancHdr4,4)
1770  << " word=" << wordNum
1771  << " DC=" << ancHdr5
1772  << " pix=" << (wordNum / searchIncr));
1773  } // if ANC packet found (wildcard or matching DID/SDID)
1774  } // scan the line
1775 
1776  return true;
1777 
1778 } // GetAncPacketsFromVANCLine
1779 
1780 
1782  UWordSequence & outU16YUVLine,
1783  const uint32_t inNumPixels)
1784 {
1785  const UByte * pInYUV8Buffer (reinterpret_cast <const UByte *> (pInYUV8Line));
1786  const ULWord maxOutElements (inNumPixels * 2);
1787 
1788  outU16YUVLine.clear ();
1789  outU16YUVLine.reserve (maxOutElements);
1790  while (outU16YUVLine.size() < size_t(maxOutElements))
1791  outU16YUVLine.push_back(0);
1792 
1793  if (!pInYUV8Buffer)
1794  {LOGMYERROR("NULL/empty YUV8 buffer"); return false;} // NULL pointer
1795  if (inNumPixels < 12)
1796  {LOGMYERROR("width in pixels " << DEC(inNumPixels) << " too small (< 12)"); return false;} // Invalid width
1797  if (inNumPixels % 4) // 6)?
1798  {LOGMYERROR("width in pixels " << DEC(inNumPixels) << " not multiple of 4"); return false;} // Width not evenly divisible by 4
1799 
1800  // Since Y and C may have separate/independent ANC data going on, we're going to split the task and do all
1801  // the even (C) samples first, the come back and repeat it for all of the odd (Y) samples...
1802  for (ULWord comp = 0; comp < 2; comp++)
1803  {
1804  bool bNoMoreAnc (false); // Assume all ANC packets (if any) begin at the first pixel and are contiguous
1805  // (i.e. no gaps between Anc packets). Once a "gap" is seen, this flag is set,
1806  // and the rest of the line turns into a copy.
1807 
1808  ULWord ancCount (0); // Number of bytes to shift and copy (once an ANC packet is found).
1809  // 0 == at the start of a potential new Anc packet.
1810 
1811  ULWord pixNum (0); // The current pixel being inspected (note: NOT the component or sample number!)
1812  UWord checksum (0); // Accumulator for checksum calculations
1813 
1814  while (pixNum < inNumPixels)
1815  {
1816  if (bNoMoreAnc)
1817  { // NoMoreAnc -- there's a gap in the Anc data -- which is assumed to mean there are no more packets on this line.
1818  // Just do a simple 8-bit -> 10-bit expansion with the remaining data on the line...
1819  const ULWord index (2 * pixNum + comp);
1820  const UWord dataValue (UWord(UWord(pInYUV8Buffer[index]) << 2)); // Pad 2 LSBs with zeros
1821 
1822  NTV2_ASSERT (index <= ULWord(outU16YUVLine.size()));
1823  if (index < ULWord(outU16YUVLine.size()))
1824  outU16YUVLine[index] = dataValue;
1825  else
1826  outU16YUVLine.push_back(dataValue);
1827  pixNum++;
1828  }
1829  else
1830  { // Still processing (possible) Anc data...
1831  if (ancCount == 0)
1832  { // AncCount == 0 means we're at the beginning of an Anc packet -- or not...
1833  if ((pixNum + 7) < inNumPixels)
1834  { // An Anc packet has to be at least 7 pixels long to be real...
1835  if ( pInYUV8Buffer [2*(pixNum+0) + comp] == 0x00
1836  && pInYUV8Buffer [2*(pixNum+1) + comp] == 0xFF
1837  && pInYUV8Buffer [2*(pixNum+2) + comp] == 0xFF)
1838  { // "00-FF-FF" means a new Anc packet is being started...
1839  // Stuff "000-3FF-3FF" into the output buffer...
1840  outU16YUVLine [2*pixNum++ + comp] = 0x000;
1841  outU16YUVLine [2*pixNum++ + comp] = 0x3ff;
1842  outU16YUVLine [2*pixNum++ + comp] = 0x3ff;
1843 
1844  ancCount = pInYUV8Buffer[2*(pixNum+2) + comp] + 3 + 1; // Number of data words + DID + SID + DC + checksum
1845  checksum = 0; // Reset checksum accumulator
1846  }
1847  else
1848  bNoMoreAnc = true; // No anc here -- assume there's no more for the rest of the line
1849  }
1850  else
1851  bNoMoreAnc = true; // Not enough room for another anc packet here -- assume no more for the rest of the line
1852  } // if ancCount == 0
1853  else if (ancCount == 1)
1854  { // This is the last byte of an anc packet -- the checksum. Since the original conversion to 8 bits
1855  // wiped out part of the original checksum, we've been recalculating it all along until now...
1856  outU16YUVLine [2*pixNum + comp] = checksum & 0x1ff; // LS 9 bits of checksum
1857  outU16YUVLine [2*pixNum + comp] |= (~checksum & 0x100) << 1; // bit 9 = ~bit 8;
1858 
1859  pixNum++;
1860  ancCount--;
1861  } // else if end of valid Anc packet
1862  else
1863  { // ancCount > 0 means an Anc packet is being processed.
1864  // Copy 8-bit data into LS 8 bits, add even parity to bit 8, and ~bit 8 to bit 9...
1865  const UByte ancByte (pInYUV8Buffer [2*pixNum + comp]);
1866  const UWord ancWord (AddEvenParity (ancByte));
1867 
1868  outU16YUVLine [2*pixNum + comp] = ancWord;
1869 
1870  checksum += (ancWord & 0x1ff); // Add LS 9 bits to checksum
1871 
1872  pixNum++;
1873  ancCount--;
1874  } // else copying actual Anc packet
1875  } // else processing an Anc packet
1876  } // for each pixel in the line
1877  } // for each Y/C component (channel)
1878 
1879  return true;
1880 } // Unpack8BitYCbCrToU16sVANCLine
1881 
1882 
1884  UWordSequence & outU16YUVLine,
1885  const uint32_t inNumPixels)
1886 {
1887  const UByte * pInYUV8Buffer (reinterpret_cast<const UByte*>(pInYUV8Line));
1888  const ULWord maxNumElements(inNumPixels * 2);
1889 
1890  outU16YUVLine.clear ();
1891  outU16YUVLine.reserve (maxNumElements);
1892  while (outU16YUVLine.size() < size_t(maxNumElements))
1893  outU16YUVLine.push_back(0);
1894 
1895  if (!pInYUV8Buffer)
1896  {LOGMYERROR("NULL/empty YUV8 buffer"); return false;} // NULL pointer
1897  if (inNumPixels < 12)
1898  {LOGMYERROR("width in pixels " << DEC(inNumPixels) << " too small (< 12)"); return false;} // Invalid width
1899  if (inNumPixels % 4)
1900  {LOGMYERROR("width in pixels " << DEC(inNumPixels) << " not multiple of 4"); return false;} // Width not evenly divisible by 4
1901 
1902  // In SD, anc data appears in both Y & C...
1903  bool bNoMoreAnc(false); // Assume all ANC packets (if any) begin at the first pixel
1904  // and are contiguous (i.e. no gaps between packets). Once a
1905  // "gap" is seen, this flag is set, and the rest of the line
1906  // is simply copied.
1907  ULWord ancCount(0); // Number of bytes to shift and copy (once an ANC packet is
1908  // found). Zero at the start of a potential new Anc packet.
1909  ULWord ndx(0); // The current pixel being inspected
1910  UWord checksum(0); // Accumulator for checksum calculations
1911 
1912  while (ndx < maxNumElements)
1913  {
1914  if (bNoMoreAnc)
1915  { // NoMoreAnc -- there's a gap in the Anc data -- which is assumed to mean there are
1916  // no more packets on this line. Just do a simple 8-bit -> 10-bit expansion with the
1917  // remaining data on the line...
1918  const UWord dataValue (UWord(UWord(pInYUV8Buffer[ndx]) << 2)); // Pad 2 LSBs with zeros
1919  NTV2_ASSERT (ndx <= ULWord(outU16YUVLine.size()));
1920  if (ndx < ULWord(outU16YUVLine.size()))
1921  outU16YUVLine[ndx] = dataValue;
1922  else
1923  outU16YUVLine.push_back(dataValue);
1924  ndx++;
1925  }
1926  else
1927  { // Still processing (possible) Anc data...
1928  if (ancCount == 0)
1929  { // AncCount == 0 means we're at the beginning of an Anc packet -- or not...
1930  if ((ndx + 7) < maxNumElements)
1931  { // An Anc packet has to be at least 7 pixels long to be real...
1932  if ( pInYUV8Buffer [ndx+0] == 0x00
1933  && pInYUV8Buffer [ndx+1] == 0xFF
1934  && pInYUV8Buffer [ndx+2] == 0xFF)
1935  { // "00-FF-FF" means a new Anc packet is being started...
1936  // Stuff "000-3FF-3FF" into the output buffer...
1937  outU16YUVLine [ndx++] = 0x000;
1938  outU16YUVLine [ndx++] = 0x3ff;
1939  outU16YUVLine [ndx++] = 0x3ff;
1940  ancCount = pInYUV8Buffer[ndx+2] + 3 + 1; // Number of data words + DID + SID + DC + checksum
1941  checksum = 0; // Reset checksum accumulator
1942  }
1943  else
1944  bNoMoreAnc = true; // No anc here -- assume there's no more for the rest of the line
1945  }
1946  else
1947  bNoMoreAnc = true; // Not enough room for another anc packet here -- assume no more for the rest of the line
1948  } // if ancCount == 0
1949  else if (ancCount == 1)
1950  { // This is the last byte of an anc packet -- the checksum. Since the original conversion to 8 bits
1951  // wiped out part of the original checksum, we've been recalculating it all along until now...
1952  outU16YUVLine[ndx] = checksum & 0x1ff; // LS 9 bits of checksum
1953  outU16YUVLine[ndx] |= (~checksum & 0x100) << 1; // bit 9 = ~bit 8;
1954  ndx++;
1955  ancCount--;
1956  } // else if end of valid Anc packet
1957  else
1958  { // ancCount > 0 means an Anc packet is being processed.
1959  // Copy 8-bit data into LS 8 bits, add even parity to bit 8, and ~bit 8 to bit 9...
1960  const UByte ancByte (pInYUV8Buffer[ndx]);
1961  const UWord ancWord (AddEvenParity(ancByte));
1962  outU16YUVLine[ndx] = ancWord;
1963  checksum += (ancWord & 0x1ff); // Add LS 9 bits to checksum
1964  ndx++;
1965  ancCount--;
1966  } // else copying actual Anc packet
1967  } // else processing an Anc packet
1968  } // for each byte in the line
1969  return true;
1970 } // Unpack8BitYCbCrToU16sVANCLineSD
1971 
1972 
1973 void AJAAncillaryData::GetInstanceCounts (uint32_t & outConstructed, uint32_t & outDestructed)
1974 {
1975 #if defined(_DEBUG)
1976  outConstructed = gConstructCount;
1977  outDestructed = gDestructCount;
1978 #else
1979  outConstructed = outDestructed = 0;
1980 #endif
1981 }
1982 
1984 {
1985 #if defined(_DEBUG)
1987 #endif
1988 }
1989 
1991 {
1992 #if defined(_DEBUG)
1994 #else
1995  return 0;
1996 #endif
1997 }
1998 
2000 {
2001 #if defined(_DEBUG)
2002  return gConstructCount;
2003 #else
2004  return 0;
2005 #endif
2006 }
2007 
2009 {
2010 #if defined(_DEBUG)
2011  return gDestructCount;
2012 #else
2013  return 0;
2014 #endif
2015 }
2016 
2017 typedef map<uint8_t, string> DIDToStringMap;
2018 typedef DIDToStringMap::const_iterator DIDToStringMapCI;
2019 typedef pair<uint8_t, string> DIDToStringPair;
2020 typedef map<AJAAncDIDSIDPair, string> DIDSIDToStringMap;
2021 typedef DIDSIDToStringMap::const_iterator DIDSIDToStringMapCI;
2022 typedef pair<AJAAncDIDSIDPair, string> DIDSIDToStringPair;
2026 
2027 string AJAAncillaryData::DIDSIDToString (const uint8_t inDID, const uint8_t inSID)
2028 {
2030  if (sDIDSIDToStringMap.empty())
2031  {
2032  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x08,0x08), "SMPTE-291 Control Packet"));
2033  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x40,0x01), "RP-305 SDTI Header Data"));
2034  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x40,0x02), "RP-348 HD-SDTI Header Data"));
2035  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x40,0x04), "SMPTE-427 Link Encryp Key Msg 1"));
2036  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x40,0x05), "SMPTE-427 Link Encryp Key Msg 2"));
2037  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x40,0x06), "SMPTE-427 Link Encryp MetaD"));
2038  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x41,0x01), "SMPTE-352M Payload ID"));
2039  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x41,0x05), "SMPTE-2016-3 ADF/Bar Data"));
2040  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x41,0x06), "SMPTE-2016-4 Pan & Scan Data"));
2041  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x41,0x07), "SMPTE-2010 ANSI/SCTE 104 Msgs"));
2042  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x41,0x08), "SMPTE-2031 DVB/SCTE VBI Data"));
2043  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x43,0x01), "BT.1685 Inter-Station Ctrl Data"));
2044  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x43,0x02), "RDD08/OP-47 Teletext Subtitling"));
2045  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x43,0x03), "RDD08/OP-47 VANC Multipacket"));
2046  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x43,0x04), "ARIB TR-B29 AV Sig Error Mon MetaD"));
2047  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x43,0x05), "RDD18 Camera Params"));
2048  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x44,0x04), "RP-214 KLV-Encoded MetaData"));
2049  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x44,0x14), "RP-214 KLV-Encoded MetaData"));
2050  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x44,0x44), "RP-223 UMID & Prog ID Label Data"));
2051  for (uint8_t sid(1); sid < 0x0A; sid++)
2052  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x45,sid), "RP-2020 Compr/Dolby Aud MetaD"));
2053  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x50,0x01), "RDD08 WSS Data"));
2054  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x50,0x51), "CineLink-2 Link Encryp MetaD"));
2055  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x51,0x01), "RP-215 Film Transfer Info"));
2056  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x51,0x02), "RDD-18 Cam Param MetaD Set Acq"));
2057  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x5F,0xDF), "ARIB STD-B37 HD Captions"));
2058  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x5F,0xDE), "ARIB STD-B37 SD Captions"));
2059  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x5F,0xDD), "ARIB STD-B37 Analog Captions"));
2060  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x5F,0xDC), "ARIB STD-B37 Mobile Captions"));
2061  for (uint8_t sid(0xD0); sid < 0xE0; sid++)
2062  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x5F,sid), "ARIB STD-B37 ??? Captions"));
2063  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x60,0x60), "SMPTE-12M ATC Timecode"));
2064  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x61,0x01), "SMPTE-334 HD CEA-708 CC"));
2065  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x61,0x02), "SMPTE-334 SD CEA-608 CC"));
2066  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x62,0x01), "RP-207 DTV Program Desc"));
2067  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x62,0x02), "SMPTE-334 Data Broadcast"));
2068  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x62,0x03), "RP-208 VBI Data"));
2069  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x64,0x64), "RP-196 LTC in HANC (Obs)"));
2070  sDIDSIDToStringMap.insert(DIDSIDToStringPair(AJAAncDIDSIDPair(0x64,0x7F), "RP-196 VITC in HANC (Obs)"));
2071  }
2072  if (sDIDToStringMap.empty())
2073  {
2074  sDIDToStringMap.insert(DIDToStringPair(0x00, "SMPTE-291 Control Packet"));
2075  sDIDToStringMap.insert(DIDToStringPair(0x08, "SMPTE-291 Ctrl Pkt"));
2076  sDIDToStringMap.insert(DIDToStringPair(0x40, "RP-305 SDTI / RP-348 HD-SDTI / SMPTE-427 Link Encrypt"));
2077  sDIDToStringMap.insert(DIDToStringPair(0x41, "SMPTE-352M / SMPTE-2016 / SMPTE-2010 / SMPTE-2031"));
2078  sDIDToStringMap.insert(DIDToStringPair(0x43, "BT.1685 / RDD08/OP-47 / ARIB TR-B29 / RDD18"));
2079  sDIDToStringMap.insert(DIDToStringPair(0x44, "RP-214 KLV / RP-223 UMID+ProgramID Labels"));
2080  sDIDToStringMap.insert(DIDToStringPair(0x45, "RP-2020 Compressed/Dolby Audio"));
2081  sDIDToStringMap.insert(DIDToStringPair(0x50, "RDD08 WSS Data / CineLink-2 Link Encryption"));
2082  sDIDToStringMap.insert(DIDToStringPair(0x51, "RP-215 Film Xfer Info / RDD-18 Camera Params"));
2083  sDIDToStringMap.insert(DIDToStringPair(0x5F, "ARIB STD-B37 Captions"));
2084  sDIDToStringMap.insert(DIDToStringPair(0x60, "SMPTE-12M ATC Timecode"));
2085  sDIDToStringMap.insert(DIDToStringPair(0x61, "SMPTE-334 Captions"));
2086  sDIDToStringMap.insert(DIDToStringPair(0x62, "RP-207 DTV Prog / SMPTE-334 Data / RP-208 VBI"));
2087  sDIDToStringMap.insert(DIDToStringPair(0x64, "RP-196 LTC/VITC in HANC"));
2088  sDIDToStringMap.insert(DIDToStringPair(0x80, "SMPTE-291 Ctrl Pkt 'Marked for Deletion'"));
2089  sDIDToStringMap.insert(DIDToStringPair(0x84, "SMPTE-291 Ctrl Pkt 'End Marker'"));
2090  sDIDToStringMap.insert(DIDToStringPair(0x88, "SMPTE-291 Ctrl Pkt 'Start Marker'"));
2091  sDIDToStringMap.insert(DIDToStringPair(0xA0, "SMPTE-299M 3G HD Audio Ctrl Grp8 (Ch 29-32)"));
2092  sDIDToStringMap.insert(DIDToStringPair(0xA1, "SMPTE-299M 3G HD Audio Ctrl Grp7 (Ch 25-28)"));
2093  sDIDToStringMap.insert(DIDToStringPair(0xA2, "SMPTE-299M 3G HD Audio Ctrl Grp6 (Ch 21-24)"));
2094  sDIDToStringMap.insert(DIDToStringPair(0xA3, "SMPTE-299M 3G HD Audio Ctrl Grp5 (Ch 17-20)"));
2095  sDIDToStringMap.insert(DIDToStringPair(0xA4, "SMPTE-299M 3G HD Audio Data Grp8 (Ch 29-32)"));
2096  sDIDToStringMap.insert(DIDToStringPair(0xA5, "SMPTE-299M 3G HD Audio Data Grp7 (Ch 25-28)"));
2097  sDIDToStringMap.insert(DIDToStringPair(0xA6, "SMPTE-299M 3G HD Audio Data Grp6 (Ch 21-24)"));
2098  sDIDToStringMap.insert(DIDToStringPair(0xA7, "SMPTE-299M 3G HD Audio Data Grp5 (Ch 17-20)"));
2099  sDIDToStringMap.insert(DIDToStringPair(0xD1, "AJA QA F1 Test Packet"));
2100  sDIDToStringMap.insert(DIDToStringPair(0xD2, "AJA QA F1 Test Packet"));
2101  sDIDToStringMap.insert(DIDToStringPair(0xD3, "AJA QA F2 Test Packet"));
2102  sDIDToStringMap.insert(DIDToStringPair(0xE0, "SMPTE-299M HD Audio Ctrl Grp4 (Ch 13-16)"));
2103  sDIDToStringMap.insert(DIDToStringPair(0xE1, "SMPTE-299M HD Audio Ctrl Grp3 (Ch 9-12)"));
2104  sDIDToStringMap.insert(DIDToStringPair(0xE2, "SMPTE-299M HD Audio Ctrl Grp2 (Ch 5-8)"));
2105  sDIDToStringMap.insert(DIDToStringPair(0xE3, "SMPTE-299M HD Audio Ctrl Grp1 (Ch 1-4)"));
2106  sDIDToStringMap.insert(DIDToStringPair(0xE4, "SMPTE-299M HD Audio Grp4 (Ch 13-16)"));
2107  sDIDToStringMap.insert(DIDToStringPair(0xE5, "SMPTE-299M HD Audio Grp3 (Ch 9-12)"));
2108  sDIDToStringMap.insert(DIDToStringPair(0xE6, "SMPTE-299M HD Audio Grp2 (Ch 5-8)"));
2109  sDIDToStringMap.insert(DIDToStringPair(0xE7, "SMPTE-299M HD Audio Grp1 (Ch 1-4)"));
2110  sDIDToStringMap.insert(DIDToStringPair(0xEC, "SMPTE-272M SD Audio Ctrl Grp4 (Ch 13-16)"));
2111  sDIDToStringMap.insert(DIDToStringPair(0xED, "SMPTE-272M SD Audio Ctrl Grp3 (Ch 9-12)"));
2112  sDIDToStringMap.insert(DIDToStringPair(0xEE, "SMPTE-272M SD Audio Ctrl Grp2 (Ch 5-8"));
2113  sDIDToStringMap.insert(DIDToStringPair(0xEF, "SMPTE-272M SD Audio Ctrl Grp1 (Ch 1-4)"));
2114  sDIDToStringMap.insert(DIDToStringPair(0xF0, "SMPTE-315 Camera Position"));
2115  sDIDToStringMap.insert(DIDToStringPair(0xF4, "RP-165 Error Detect/Checkwords"));
2116  sDIDToStringMap.insert(DIDToStringPair(0xF8, "SMPTE-272M SD Audio Ext Data Grp4 (Ch 13-16)"));
2117  sDIDToStringMap.insert(DIDToStringPair(0xF9, "SMPTE-272M SD Audio Data Grp4 (Ch 13-16)"));
2118  sDIDToStringMap.insert(DIDToStringPair(0xFA, "SMPTE-272M SD Audio Ext Data Grp3 (Ch 9-12)"));
2119  sDIDToStringMap.insert(DIDToStringPair(0xFB, "SMPTE-272M SD Audio Data Grp3 (Ch 9-12)"));
2120  sDIDToStringMap.insert(DIDToStringPair(0xFC, "SMPTE-272M SD Audio Ext Data Grp2 (Ch 5-8"));
2121  sDIDToStringMap.insert(DIDToStringPair(0xFD, "SMPTE-272M SD Audio Data Grp2 (Ch 5-8"));
2122  sDIDToStringMap.insert(DIDToStringPair(0xFE, "SMPTE-272M SD Audio Ext Data Grp1 (Ch 1-4)"));
2123  sDIDToStringMap.insert(DIDToStringPair(0xFF, "SMPTE-272M SD Audio Data Grp1 (Ch 1-4)"));
2124  }
2125  const AJAAncDIDSIDPair didsid(inDID, inSID);
2126  DIDSIDToStringMapCI it(sDIDSIDToStringMap.find(didsid));
2127  if (it != sDIDSIDToStringMap.end())
2128  return it->second;
2129  DIDToStringMapCI didIt(sDIDToStringMap.find(inDID));
2130  if (didIt != sDIDToStringMap.end())
2131  return didIt->second;
2132  return "";
2133 } // DIDSIDToString
2134 
2135 static const NTV2DIDSet sValidHDMIAuxPacketTypes = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
2136  0x80, 0x81, 0x82, 0x83, 0x84, 0x85}; // <== InfoFrame types
2137 
2138 string AJAAncillaryData::AuxPacketTypeToString (const uint8_t auxPacketType)
2139 {
2140  switch (auxPacketType)
2141  {
2142  case 0x01: return "Audio Clock Regeneration (N/CTS)";
2143  case 0x02: return "Audio Sample (L-PCM & IEC-61937 compressed)";
2144  case 0x03: return "General Control";
2145  case 0x04: return "ACP Packet";
2146  case 0x05: return "ISRC1 Packet";
2147  case 0x06: return "ISRC2 Packet";
2148  case 0x07: return "One Bit Audio Sample Packet";
2149  case 0x08: return "DST Audio Packet";
2150  case 0x09: return "High Bitrate Audio Stream Packet (IEC-61937)";
2151  case 0x0A: return "Gamut Metadata Packet";
2152  case 0x80: return "General InfoFrame Packet"; // May not be valid
2153  case 0x81: return "Vendor-Specific InfoFrame";
2154  case 0x82: return "AVI InfoFrame";
2155  case 0x83: return "Source Product Descriptor InfoFrame";
2156  case 0x84: return "Audio InfoFrame";
2157  case 0x85: return "MPEG Source InfoFrame";
2158  }
2159  return "";
2160 } // AuxPacketTypeToString
2161 
2162 bool AJAAncillaryData::AuxPacketTypeIsValid (const uint8_t inAuxPktType)
2163 {
2164  return sValidHDMIAuxPacketTypes.find(inAuxPktType) != sValidHDMIAuxPacketTypes.end();
2165 }
2166 
2168 // AJARTPAncPayloadHeader
2169 
2170 
2172 {
2173  if (inBuffer.IsNULL())
2174  return false;
2175  // Peek in buffer and see if it starts with an RTP header...
2177  if (!hdr.ReadFromBuffer(inBuffer))
2178  return false;
2179  return hdr.IsValid();
2180 }
2181 
2183  : mVBits (2), // Playout: don't care -- hardware sets this
2184  mPBit (false), // Playout: don't care -- hardware sets this
2185  mXBit (false), // Playout: don't care -- hardware sets this
2186  mMarkerBit (false), // Playout: don't care -- hardware sets this
2187  mCCBits (0), // Playout: don't care -- hardware sets this
2188  mPayloadType (0), // Playout: don't care -- hardware sets this
2189  mSequenceNumber (0), // Playout: don't care -- hardware sets this
2190  mTimeStamp (0), // Playout: don't care -- hardware sets this
2191  mSyncSourceID (0), // Playout: client sets this
2192  mPayloadLength (0), // Playout: WriteIPAncData sets this
2193  mAncCount (0), // Playout: WriteIPAncData sets this
2194  mFieldSignal (0) // Playout: WriteIPAncData sets this
2195 {
2196 }
2197 
2198 bool AJARTPAncPayloadHeader::GetPacketHeaderULWordForIndex (const unsigned inIndex0, uint32_t & outULWord) const
2199 {
2200  switch (inIndex0)
2201  {
2202  case 0:
2203  {
2204  uint32_t u32(uint32_t(mVBits << 30));
2205  u32 |= uint32_t(mPBit ? 1 : 0) << 29;
2206  u32 |= uint32_t(mPBit ? 1 : 0) << 29;
2207  u32 |= uint32_t(mXBit ? 1 : 0) << 28;
2208  u32 |= uint32_t(mCCBits & 0x0000000F) << 24;
2209  u32 |= uint32_t(IsEndOfFieldOrFrame() ? 1 : 0) << 23;
2210  u32 |= uint32_t(GetPayloadType() & 0x0000007F) << 16;
2211  u32 |= uint32_t(GetSequenceNumber() & 0x0000FFFF);
2212  outULWord = ENDIAN_32HtoN(u32);
2213  break;
2214  }
2215 
2216  case 1:
2217  outULWord = ENDIAN_32HtoN(GetTimeStamp());
2218  break;
2219 
2220  case 2:
2221  outULWord = ENDIAN_32HtoN(GetSyncSourceID());
2222  break;
2223 
2224  case 3:
2225  {
2226  const uint32_t u32 ((GetSequenceNumber() & 0xFFFF0000) | (GetPayloadLength()));
2227  outULWord = ENDIAN_32HtoN(u32);
2228  break;
2229  }
2230 
2231  case 4:
2232  {
2233  uint32_t u32(uint32_t(GetAncPacketCount() & 0x000000FF) << 24);
2234  u32 |= uint32_t(GetFieldSignal() & 0x00000003) << 22;
2235  outULWord = ENDIAN_32HtoN(u32);
2236  break;
2237  }
2238 
2239  default:
2240  outULWord = 0;
2241  return false;
2242  }
2243  return true;
2244 }
2245 
2246 bool AJARTPAncPayloadHeader::SetFromPacketHeaderULWordAtIndex(const unsigned inIndex0, const uint32_t inULWord)
2247 {
2248  const uint32_t u32 (ENDIAN_32NtoH(inULWord));
2249  switch (inIndex0)
2250  {
2251  case 0: mVBits = uint8_t(u32 >> 30);
2252  mPBit = (u32 & 0x20000000) ? true : false;
2253  mXBit = (u32 & 0x10000000) ? true : false;
2254  mCCBits = uint8_t((u32 & 0x0F000000) >> 24);
2255  mMarkerBit = (u32 & 0x00800000) ? true : false;
2256  mPayloadType = uint8_t((u32 & 0x007F0000) >> 16);
2257  mSequenceNumber = (mSequenceNumber & 0xFFFF0000) | (u32 & 0x0000FFFF); // Replace LS 16 bits
2258  break;
2259 
2260  case 1: mTimeStamp = u32;
2261  break;
2262 
2263  case 2: mSyncSourceID = u32;
2264  break;
2265 
2266  case 3: mSequenceNumber = (u32 & 0xFFFF0000) | (mSequenceNumber & 0x0000FFFF); // Replace MS 16 bits
2267  mPayloadLength = uint16_t(u32 & 0x0000FFFF);
2268  break;
2269 
2270  case 4: mAncCount = uint8_t((u32 & 0xFF000000) >> 24);
2271  mFieldSignal = uint8_t((u32 & 0x00C00000) >> 22);
2272  break;
2273 
2274  default: return false;
2275  }
2276  return true;
2277 }
2278 
2279 bool AJARTPAncPayloadHeader::WriteToULWordVector (ULWordSequence & outVector, const bool inReset) const
2280 {
2281  if (inReset)
2282  outVector.clear();
2283  while (outVector.size() < 5)
2284  outVector.push_back(0);
2285  for (unsigned ndx(0); ndx < 5; ndx++)
2286  outVector[ndx] = GetPacketHeaderULWordForIndex(ndx);
2287  return true;
2288 }
2289 
2290 bool AJARTPAncPayloadHeader::WriteToBuffer (NTV2Buffer & outBuffer, const ULWord inU32Offset) const
2291 {
2292  const ULWord startingByteOffset (inU32Offset * sizeof(uint32_t));
2293  if ((startingByteOffset + ULWord(GetHeaderByteCount())) > outBuffer.GetByteCount())
2294  return false; // Buffer too small
2295  uint32_t * pU32s (reinterpret_cast<uint32_t*>(outBuffer.GetHostAddress(startingByteOffset)));
2296  for (unsigned ndx(0); ndx < 5; ndx++)
2297  pU32s[ndx] = GetPacketHeaderULWordForIndex(ndx);
2298  return true;
2299 }
2300 
2302 {
2303  // Note: uint32_t's are assumed to be in network byte order
2304  if (inVector.size() < 5)
2305  return false; // Too small
2306  for (unsigned ndx(0); ndx < 5; ndx++)
2307  if (!SetFromPacketHeaderULWordAtIndex(ndx, inVector[ndx]))
2308  return false;
2309  return true;
2310 }
2311 
2313 {
2314  if (inBuffer.GetByteCount() < GetHeaderByteCount())
2315  return false; // Too small
2316  const uint32_t * pU32s (reinterpret_cast <const uint32_t *> (inBuffer.GetHostPointer()));
2317  for (unsigned ndx(0); ndx < 5; ndx++)
2318  if (!SetFromPacketHeaderULWordAtIndex(ndx, pU32s[ndx]))
2319  return false;
2320  return true;
2321 }
2322 
2323 const string & AJARTPAncPayloadHeader::FieldSignalToString (const uint8_t inFBits)
2324 {
2325  static const string sStrs[] = { "p/noF", "BAD", "i/F1", "i/F2" };
2326  return sStrs[inFBits & 0x03];
2327 }
2328 
2330 {
2331  return mVBits == inRHS.mVBits
2332  && mPBit == inRHS.mPBit
2333  && mXBit == inRHS.mXBit
2334  && mCCBits == inRHS.mCCBits
2335  && mMarkerBit == inRHS.mMarkerBit
2336  && mPayloadType == inRHS.mPayloadType
2337  && mSequenceNumber == inRHS.mSequenceNumber
2338  && mTimeStamp == inRHS.mTimeStamp
2339  && mSyncSourceID == inRHS.mSyncSourceID
2340  && mPayloadLength == inRHS.mPayloadLength
2341  && mAncCount == inRHS.mAncCount
2342  && mFieldSignal == inRHS.mFieldSignal;
2343 }
2344 
2345 ostream & AJARTPAncPayloadHeader::Print (ostream & inOutStream) const
2346 { // Translate back to host byte order before printing:
2347  const uint32_t word0 (ENDIAN_32NtoH(GetPacketHeaderULWordForIndex(0)));
2348  inOutStream << xHEX0N(word0,8)
2349 // << "|" << bBIN032(word0)
2350  << ": V=" << DEC(uint16_t(mVBits))
2351  << " P=" << mPBit << " X=" << mXBit << " CC=" << DEC(uint16_t(mCCBits))
2352  << " M=" << (IsEndOfFieldOrFrame()?"EOF":"0") << " PT=" << xHEX0N(uint16_t(GetPayloadType()),2)
2353  << " Seq#=" << xHEX0N(GetSequenceNumber(),8) << " TS=" << xHEX0N(GetTimeStamp(),8)
2354  << " SSRC=" << xHEX0N(GetSyncSourceID(),8) << " PayLen=" << DEC(GetPayloadLength())
2355  << " AncCnt=" << DEC(uint16_t(GetAncPacketCount())) << " F=" << FieldSignalToString(GetFieldSignal())
2356  << (IsValid() ? "" : " (invalid)");
2357  return inOutStream;
2358 }
2359 
2361 { // Return TRUE if all of my fields are zero...
2362  return !(mVBits || mPBit || mXBit || mCCBits || mMarkerBit || mPayloadType || mSequenceNumber || mTimeStamp || mSyncSourceID || mPayloadLength || mAncCount || mFieldSignal);
2363 }
2364 
2366 { // Simple validation -- Check that...
2367  return mVBits == 0x02 // Version == 2
2368  && !IsNULL() // Not NULL
2369  && IsValidFieldSignal(); // Valid field bits
2370 }
2371 
2372 
2374 // AJARTPAncPacketHeader
2375 
2377  : mCBit (false),
2378  mSBit (false),
2379  mLineNum (0),
2380  mHOffset (0),
2381  mStreamNum (0)
2382 {
2383 }
2384 
2386  : mCBit (false),
2387  mSBit (false),
2388  mLineNum (0),
2389  mHOffset (0),
2390  mStreamNum (0)
2391 {
2392  SetFrom(inLoc);
2393 }
2394 
2396 {
2397  // In network byte order:
2398  //
2399  // 0 1 2 3
2400  // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2401  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2402  // |C| Line_Number | Horizontal_Offset |S| StreamNum |
2403  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2404  uint32_t u32(0); // Build little-endian 32-bit ULWord with this
2405  u32 |= (uint32_t(GetLineNumber()) & 0x000007FF) << 20; // 11-bit line number
2406  u32 |= (IsCBitSet() ? 0x80000000 : 0x00000000);
2407  u32 |= (uint32_t(GetHorizOffset()) & 0x00000FFF) << 8; // 12-bit horiz offset
2408  u32 |= IsSBitSet() ? 0x00000080 : 0x00000000; // Data Stream flag
2409  if (IsSBitSet())
2410  u32 |= uint32_t(GetStreamNumber() & 0x7F); // 7-bit StreamNum
2411  return ENDIAN_32HtoN(u32); // Convert to big-endian
2412 }
2413 
2414 bool AJARTPAncPacketHeader::SetFromULWord (const uint32_t inULWord)
2415 {
2416  const uint32_t u32 (ENDIAN_32NtoH(inULWord));
2417  // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2418  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2419  // |C| Line_Number | Horizontal_Offset |S| StreamNum |
2420  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2421  if (u32 & 0x80000000)
2422  SetCChannel();
2423  else
2424  SetYChannel();
2425  SetLineNumber(uint16_t((u32 & 0x7FF00000) >> 20));
2426  SetHorizOffset(uint16_t((u32 & 0x000FFF00) >> 8));
2427  SetStreamNumber(uint8_t(u32 & 0x0000007F));
2428  SetDataStreamFlag(u32 & 0x00000080);
2429  return true;
2430 }
2431 
2432 bool AJARTPAncPacketHeader::WriteToULWordVector (ULWordSequence & outVector, const bool inReset) const
2433 {
2434  if (inReset)
2435  outVector.clear();
2436  outVector.push_back(GetULWord());
2437  return true;
2438 }
2439 
2440 bool AJARTPAncPacketHeader::ReadFromULWordVector (const ULWordSequence & inVector, const unsigned inIndex0)
2441 {
2442  if (inIndex0 >= inVector.size())
2443  return false; // Bad index -- out of range
2444  return SetFromULWord(inVector[inIndex0]);
2445 }
2446 
2448 {
2449  AJAAncDataLoc result;
2453  if (IsSBitSet())
2454  {
2455  // e.g. SMPTE ST 425-3 DL 3Gbps, data streams are numbered 1-4, so DS1/DS2 on linkA, DS3/DS4 on linkB
2458  result.SetDataLink(AJAAncDataLink_B);
2459  }
2460  return result;
2461 }
2462 
2464 {
2465  const AJAAncDataLink lnk (inLoc.GetDataLink());
2466  const AJAAncDataStream ds (inLoc.GetDataStream());
2467  const AJAAncDataChannel dChan (inLoc.GetDataChannel());
2468 
2469  // @bug Dang, the sense of the C bit is opposite of our AJAAncDataChannel enum!
2470  // The C bit should be '1' for AJAAncDataChannel_C (0).
2471  // The C bit should be '0' for AJAAncDataChannel_Y (1).
2472  // The C bit should be '0' for SD, but we use AJAAncDataChannel_Both (0) for this,
2473  // which is indistinguishable from AJAAncDataChannel_C (0).
2474  // @todo This needs to be addressed.
2475  mCBit = IS_VALID_AJAAncDataChannel(dChan) && (dChan != AJAAncDataChannel_Y);
2476 
2477  // Data Stream Flag
2478  // '0': No guidance -- don't know -- don't care
2479  // '1': StreamNum field carries info about source data stream number
2481 
2482  if (IS_VALID_AJAAncDataLink(lnk))
2483  mStreamNum = uint8_t(lnk);
2484  else if (IS_VALID_AJAAncDataStream(ds))
2485  mStreamNum = uint8_t(ds);
2486  else
2487  mStreamNum = 0;
2488 
2489  mLineNum = inLoc.GetLineNumber();
2490  mHOffset = inLoc.GetHorizontalOffset();
2491 
2492  return *this;
2493 }
2494 
2495 ostream & AJARTPAncPacketHeader::Print (ostream & inOutStream) const
2496 {
2497  inOutStream << xHEX0N(GetULWord(),8) << ": C=" << (IsCBitSet() ? "1" : "0")
2498  << " Line=" << DEC(GetLineNumber()) << " HOff=" << DEC(GetHorizOffset())
2499  << " S=" << (IsSBitSet() ? "1" : "0") << " Strm=" << DEC(uint16_t(GetStreamNumber()));
2500  return inOutStream;
2501 }
#define AJAAncDataHorizOffset_Unknown
Unknown.
#define IS_LINKB_AJAAncDataStream(_x_)
#define RCV2110DBG(__x__)
static size_t GetHeaderByteCount(void)
static bool AuxPacketTypeIsValid(const uint8_t inAuxPktType)
#define AJA_ENDIAN_32NtoH(__val__)
virtual bool IsValidFieldSignal(void) const
virtual const uint8_t * GetPayloadData(void) const
virtual uint8_t GetDID(void) const
const string & AJAAncDataSpaceToString(const AJAAncDataSpace inValue, const bool inCompact)
#define AJA_SUCCESS(_status_)
Definition: types.h:372
ostream & operator<<(ostream &inOutStream, const AJAAncDataLoc &inValue)
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 ...
AJAAncillaryData & operator=(const AJAAncillaryData &inRHS)
#define RCV2110WARN(__x__)
static bool CheckAncParityAndChecksum(const AJAAncillaryData::U16Packet &inYUV16Line, const uint16_t inStartIndex, const uint16_t inTotalCount, const uint16_t inIncrement=2)
virtual AJAStatus GetRawPacketSize(uint32_t &outPacketSize) const
Returns the number of "raw" ancillary data bytes that will be generated by AJAAncillaryData::Generate...
virtual AJAStatus Compare(const AJAAncDataLoc &inRHS) const
Compares me with another location.
#define NULL
virtual AJAAncillaryData * Clone(void) const
virtual uint8_t GetSID(void) const
virtual AJAStatus SetSID(const uint8_t inSID)
Sets my Secondary Data ID (SID) - (aka the Data Block Number (DBN) for "Type 1" SMPTE-291 packets)...
AJAAncDataLoc & SetHorizontalOffset(uint16_t inHOffset)
Specifies the horizontal packet position in the raster.
bool IsNULL(void) const
AJAAncDataChannel
Identifies which component of a video stream in which the ancillary data is placed or found...
static uint32_t gConstructCount(0)
#define BIT(_x_)
Definition: ajatypes.h:578
virtual std::string CompareWithInfo(const AJAAncillaryData &inRHS, const bool inIgnoreLocation=true, const bool inIgnoreChecksum=true) const
Compares me with another packet and returns a string that describes what&#39;s different.
virtual AJARTPAncPacketHeader & SetLineNumber(const uint16_t inLineNum)
Sets my line number value to least-significant 11 bits of the given value.
virtual AJAStatus SetDID(const uint8_t inDataID)
Sets my Data ID (DID).
static bool BufferStartsWithRTPHeader(const NTV2Buffer &inBuffer)
virtual bool WriteToBuffer(NTV2Buffer &outBuffer, const ULWord inU32Offset=0) const
Writes an RTP packet header based on my current state into the given buffer. Each 32-bit word will be...
#define AJAAncDataLineNumber_Unknown
Packet line number is unknown.
AJAStatus
Definition: types.h:380
UWordSequence U16Packet
An ordered sequence of 10-bit packet words stored in uint16_t values.
Ancillary data found between SAV and EAV (.
virtual uint8_t GetPayloadType(void) const
Declares the AJADebug class.
static AJALock sDIDToStringLock
AJAAncDataSpace
Identified the raster section of a video stream that contains the ancillary data. Deprecated in favor...
virtual uint32_t GetSequenceNumber(void) const
virtual AJAStatus SetLocationHorizOffset(const uint16_t inOffset)
Sets my ancillary data "location" horizontal offset.
AJAAncDataType m_ancType
One of a known set of ancillary data types (or "Custom" if not identified)
static const size_t gIndexes[]
Only look in luma samples.
Unknown or "don&#39;t care".
#define AJA_FAILURE(_status_)
Definition: types.h:373
virtual const AJAAncDataLoc & GetDataLocation(void) const
AJAAncDataType
Identifies the ancillary data types that are known to this module.
Definition: ancillarydata.h:44
AJARTPAncPacketHeader()
My default constructor.
const uint32_t AJAAuxillaryPacketSize
virtual bool SetFromULWord(const uint32_t inULWord)
Resets my current state by decoding the given 4-byte header value.
std::ostream & Print(std::ostream &ostrm, const bool inCompact=true) const
Writes a human-readable rendition of me into the given output stream.
DIDToStringMap::const_iterator DIDToStringMapCI
#define IS_VALID_AncChannelSearchSelect(_x_)
ULWord GetByteCount(void) const
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 IS_VALID_AJAAncDataLink(_x_)
Definition: ancillarydata.h:89
virtual bool IsEndOfFieldOrFrame(void) const
static const unsigned gShifts[]
AJAAncDataStream GetDataStream(void) const
The ancillary data is in the form of a digitized waveform (e.g. CEA-608 captions, VITC...
#define LOGMYERROR(__x__)
virtual std::string AsString(const uint16_t inDumpMaxBytes=0) const
Definition: lock.h:28
static DIDSIDToStringMap sDIDSIDToStringMap
virtual uint16_t Calculate9BitChecksum(void) const
Generates the official SMPTE 291 9-bit checksum from the DID + SID + DC + payload data...
uint8_t m_auxType
HDMI Aux Header Byte 0 (Packet Type)
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...
Definition: json.hpp:5362
const string & AJAAncDataChannelToString(const AJAAncDataChannel inValue, const bool inCompact)
virtual void Clear(void)
Frees my allocated memory, if any, and resets my members to their default values. ...
map< uint8_t, string > DIDToStringMap
#define false
virtual ~AJAAncillaryData()
My destructor.
uint32_t ULWord
Definition: ajatypes.h:223
string AJAAncDataLocToString(const AJAAncDataLoc &inValue, const bool inCompact)
AJAAncDataLoc & SetDataLink(const AJAAncDataLink inLink)
Sets my data link value to the given value (if valid).
uint8_t m_checksum
My 8-bit checksum: DID + SID + DC + payload (w/o parity) [note: NOT the same as the 9-bit checksum in...
static uint32_t ENDIAN_32NtoH(const uint32_t inValue)
#define AJAAncDataHorizOffset_AnyVanc
VANC – Packet placed/found in any legal area of raster line after SAV, but before EAV...
Ancillary data found between EAV and SAV (.
ByteVector m_payload
My payload data (DC = size)
AJAAncDataCoding m_coding
Analog or digital data.
uint16_t GetLineNumber(void) const
#define AJAAncDataLineNumber_Anywhere
virtual bool SetFromPacketHeaderULWordAtIndex(const unsigned inIndex0, const uint32_t inULWord)
Resets (part of) my state from a given 32-bit word in an existing RTP header.
static uint32_t ENDIAN_32HtoN(const uint32_t inValue)
uint8_t m_auxHB1
HDMI Aux Header Byte 1 (Header Data)
#define AJAAncDataLineNumber_Future
Line number exceeds 11 bits (future).
virtual AJAStatus SetLocationLineNumber(const uint16_t inLineNum)
Sets my ancillary data "location" frame line number.
pair< AJAAncDIDSIDPair, string > DIDSIDToStringPair
#define NTV2_ASSERT(_expr_)
Definition: ajatypes.h:476
Defines where the ancillary data can be found within a video stream.
#define IS_VALID_AJAAncDataCoding(_x_)
AJAStatus FreeDataMemory(void)
string AncChannelSearchSelectToString(const AncChannelSearchSelect inSelect, const bool inCompact)
I represent the header of a SMPTE 2110 compliant RTP Anc network packet.
std::vector< uint8_t > ByteVector
virtual AJARTPAncPacketHeader & SetCChannel(void)
Sets my "C" channel bit setting to &#39;true&#39;.
AJARTPAncPayloadHeader()
My default constructor.
virtual AJARTPAncPacketHeader & SetDataStreamFlag(const bool inFlag)
Sets my data stream flag.
const string & AJAAncDataLinkToString(const AJAAncDataLink inValue, const bool inCompact)
uint64_t m_userData
User data (for client use)
virtual std::ostream & Print(std::ostream &inOutStream, const bool inDetailed=false) const
Streams a human-readable representation of me to the given output stream.
const string & AJAAncDataStreamToString(const AJAAncDataStream inValue, const bool inCompact)
std::vector< U16Packet > U16Packets
An ordered sequence of zero or more U16Packet values.
virtual uint32_t GetULWord(void) const
Includes data that is valid, but we don&#39;t recognize.
Definition: ancillarydata.h:46
virtual uint8_t GetGUMPHeaderByte2(void) const
virtual AJARTPAncPacketHeader & SetHorizOffset(const uint16_t inHOffset)
Sets my horizontal offset value to least-significant 12 bits of the given value.
ByteVector::const_iterator ByteVectorConstIter
#define AJAAncDataHorizOffset_Anywhere
Unspecified – Packet placed/found in any legal area of raster line.
uint8_t m_auxHB2
HDMI Aux Header Byte 2 (Header Data)
virtual uint16_t GetLineNumber(void) const
virtual AJAStatus SetLocationDataStream(const AJAAncDataStream inStream)
Sets my ancillary data "location" data stream value (DS1,DS2...).
AJAAncDataChannel GetDataChannel(void) const
const size_t sENDL(1)
virtual AJAStatus SetLocationVideoLink(const AJAAncDataLink inLink)
Sets my ancillary data "location" within the video stream.
#define AJA_NULL
Definition: ajatypes.h:167
const string & AJAAncBufferFormatToString(const AJAAncBufferFormat inValue, const bool inCompact)
virtual bool GetPacketHeaderULWordForIndex(const unsigned inIndex0, uint32_t &outULWord) const
Answers with the 32-bit RTP packet header value for the given position. The returned value will be in...
static const uint32_t gMasks[]
virtual uint16_t GetHorizOffset(void) const
const string & AJAAncDataCodingToString(const AJAAncDataCoding inValue, const bool inCompact)
AJAAncDataLoc & SetLineNumber(const uint16_t inLineNum)
Sets my anc data line number value.
virtual AJAStatus AppendPayload(const AJAAncillaryData &inAncData)
Appends payload data from another AJAAncillaryData object to my existing payload. ...
The ancillary data is associated with the chrominance (C) channel of the video stream.
#define IS_KNOWN_AJAAncBufferFormat(_x_)
virtual bool operator==(const AJARTPAncPayloadHeader &inRHS) const
const uint32_t AJAAncillaryDataWrapperSize
The ancillary data is associated with the luminance (Y) channel of the video stream.
virtual uint8_t Calculate8BitChecksum(void) const
Generates an 8-bit checksum from the DID + SID + DC + payload data.
#define LOGMYINFO(__x__)
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 ParsePayloadData(void)
Parses (interprets) the "local" ancillary data from my payload data.
static std::string AuxPacketTypeToString(const uint8_t inAuxPktType)
std::vector< uint16_t > UWordSequence
An ordered sequence of UWord (uint16_t) values.
AJAAncDataLink GetDataLink(void) const
virtual bool WriteToULWordVector(ULWordSequence &outVector, const bool inReset=true) const
Writes my 4-byte header value into the given ULWordSequence. The 4-byte value will be in network byte...
virtual std::ostream & Print(std::ostream &inOutStream) const
Writes a human-readable dump of my current state into a given output stream.
virtual AJAStatus SetDataCoding(const AJAAncDataCoding inCodingType)
Sets my ancillary data coding type (e.g. digital or analog/raw waveform).
virtual size_t GetPayloadByteCount(void) const
static uint32_t GetNumDestructed(void)
static int32_t Increment(int32_t volatile *pTarget)
Definition: atomic.cpp:82
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...
static const std::string & FieldSignalToString(const uint8_t inFBits)
AJAAncDataLoc & SetDataStream(const AJAAncDataStream inStream)
Sets my data link value to the given value (if valid).
virtual uint8_t GetFieldSignal(void) const
virtual AJAAncDataLoc AsDataLocation(void) const
virtual AJAStatus SetChecksum(const uint8_t inChecksum8, const bool inValidate=false)
Sets my 8-bit checksum. Note that it is not usually necessary to generate an 8-bit checksum...
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. ...
uint8_t UByte
Definition: ajatypes.h:218
virtual uint32_t GetSyncSourceID(void) const
#define LOGMYWARN(__x__)
virtual AJAStatus SetDataLocation(const AJAAncDataLoc &inLoc)
Sets my ancillary data "location" within the video stream.
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.).
AJAAncDataStream
Identifies which data stream the ancillary data is associated with.
virtual AJARTPAncPacketHeader & SetFrom(const AJAAncDataLoc &inLocation)
Resets me from a given AJAAncDataLoc.
virtual AJAStatus AppendPayloadData(const uint8_t *pInBuffer, const uint32_t inByteCount)
Appends data from an external buffer onto the end of my existing payload.
Declares the AJAAtomic class.
static bool Unpack8BitYCbCrToU16sVANCLineSD(const void *pInYUV8Line, UWordSequence &outU16YUVLine, const uint32_t inNumPixels)
SD version of Unpack8BitYCbCrToU16sVANCLine.
const string & AJAAncDataTypeToString(const AJAAncDataType inValue, const bool inCompact)
AncChannelSearchSelect
Specifies which channel of a video stream in which to look for Anc data.
static void ResetInstanceCounts(void)
AJAAncDataLoc & SetDataChannel(const AJAAncDataChannel inChannel)
Sets my data video stream value to the given value (if valid).
#define XMT2110WARN(__x__)
AJAAncillaryData()
My default constructor.
virtual uint8_t GetAncPacketCount(void) const
virtual AJAStatus SetPayloadByteAtIndex(const uint8_t inDataByte, const uint32_t inIndex0)
virtual uint8_t GetPayloadByteAtIndex(const uint32_t inIndex0) const
#define DEC(__x__)
static void GetInstanceCounts(uint32_t &outConstructed, uint32_t &outDestructed)
virtual uint8_t GetStreamNumber(void) const
uint8_t m_SID
Official SMPTE secondary ID (or DBN - w/o parity)
virtual bool IsSBitSet(void) const
std::pair< uint8_t, uint8_t > AJAAncDIDSIDPair
Definition: ancillarydata.h:27
static std::string DIDSIDToString(const uint8_t inDID, const uint8_t inSDID)
#define IS_VALID_AJAAncDataStream(_x_)
#define AJAAncDataHorizOffset_AnyHanc
HANC – Packet placed/found in any legal area of raster line after EAV.
The ancillary data is associated with Link A of the video stream.
Definition: ancillarydata.h:81
#define LOGMYDEBUG(__x__)
virtual AJARTPAncPacketHeader & SetYChannel(void)
Sets my "C" channel bit setting to &#39;false&#39;.
bool IsRaw(const NTV2FrameBufferFormat format)
Definition: ntv2utils.cpp:5446
#define XMT2110DBG(__x__)
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...
Look both luma and chroma samples (SD only)
uint32_t m_frameID
ID of my originating frame, if known.
ByteVector::size_type ByteVectorIndex
uint16_t UWord
Definition: ajatypes.h:221
virtual AJAAncDataCoding GetDataCoding(void) const
SDI (AJA "GUMP")
virtual AJAStatus SetPayloadData(const uint8_t *pInData, const uint32_t inByteCount)
Copy data from external memory into my local payload memory.
virtual std::ostream & DumpPayload(std::ostream &inOutStream) const
Dumps a human-readable representation of my payload bytes into the given output stream.
virtual uint16_t GetStreamInfo(void) const
#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.
#define IS_VALID_AJAAncDataChannel(_x_)
virtual bool IsValid(void) const
Declares the AJAAncillaryData class.
virtual AJAStatus SetLocationDataChannel(const AJAAncDataChannel inChannel)
Sets my ancillary data "location" data channel value (Y or C).
AJAAncDataCoding
Identifies the ancillary data coding type: digital or non-digital (analog/raw).
pair< uint8_t, string > DIDToStringPair
#define XMT2110ERR(__x__)
AJAAncDataLink
Identifies which link of a video stream the ancillary data is associated with.
Definition: ancillarydata.h:79
DIDSIDToStringMap::const_iterator DIDSIDToStringMapCI
#define fDEC(__x__, __w__, __p__)
std::string AJAStatusToString(const AJAStatus inStatus, const bool inDetailed)
Definition: debug.cpp:981
uint8_t m_DID
Official SMPTE ancillary packet ID (w/o parity)
std::vector< uint32_t > ULWordSequence
An ordered sequence of ULWord (uint32_t) values.
AJAAncDataLoc m_location
Location of the ancillary data in the video stream (Y or C, HANC or VANC, etc.)
virtual bool IsCBitSet(void) const
string AJAAncHorizOffsetToString(const uint16_t inValue)
virtual bool IsNULL(void) const
virtual uint8_t GetChecksum(void) const
virtual uint32_t GetDC(void) const
static uint32_t GetNumActiveInstances(void)
void * GetHostPointer(void) const
string AJAAncLineNumberToString(const uint16_t inValue)
#define IS_VALID_AJAAncBufferFormat(_x_)
static uint32_t GetNumConstructed(void)
virtual std::string IDAsString(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...
map< AJAAncDIDSIDPair, string > DIDSIDToStringMap
bool m_rcvDataValid
This is set true (or not) by ParsePayloadData()
uint16_t GetHorizontalOffset(void) const
#define AJAAncDataLineNumber_AnyVanc
Packet placed/found on any line past RP168 switch line and before SAV.
virtual bool ReadFromULWordVector(const ULWordSequence &inVector, const unsigned inIndex0)
Resets my current state by decoding the 4-byte header value stored in the given ULWordSequence at the...
#define RCV2110ERR(__x__)
virtual AJAStatus Compare(const AJAAncillaryData &inRHS, const bool inIgnoreLocation=true, const bool inIgnoreChecksum=true) const
Compares me with another packet.
void * GetHostAddress(const ULWord inByteOffset, const bool inFromEnd=false) const
static const NTV2DIDSet sValidHDMIAuxPacketTypes
virtual bool operator==(const AJAAncillaryData &inRHS) const
Declares enums and structs used by all platform drivers and the SDK.
#define AJAAncDataHorizOffset_Future
Offset exceeds 12 bits (future).
I represent the 4-byte header of an anc packet that&#39;s inside an RTP packet.
virtual uint16_t GetPayloadLength(void) const
Only look in chroma samples.
virtual std::string CompareWithInfo(const AJAAncDataLoc &inRHS) const
Compares me with another location and returns a string that describes what&#39;s different.
AJAAncBufferFormat m_bufferFmt
My originating buffer format, if known.
static uint16_t AddEvenParity(const uint8_t inDataByte)
The ancillary data is associated with Link B of the video stream.
Definition: ancillarydata.h:82
virtual AJARTPAncPacketHeader & SetStreamNumber(const uint8_t inStreamNum)
Sets my stream number value to least-significant 7 bits of the given value.
static DIDToStringMap sDIDToStringMap
AJAStatus AllocDataMemory(const uint32_t inNumBytes)
#define IS_VALID_AJAAncDataSpace(_x_)
virtual std::ostream & Print(std::ostream &inOutStream) const
Streams a human-readable represetation of my current state to the given output stream.
The ancillary data is associated with DS1 of the video stream (Link A).
virtual AJAStatus SetFromSMPTE334(const uint16_t *pInData, const uint32_t inNumWords, const AJAAncDataLoc &inLocInfo)
Copies payload data from an external 16-bit source into local payload memory.
std::set< UByte > NTV2DIDSet
A set of distinct NTV2DID values.
virtual uint32_t GetTimeStamp(void) const
The ancillary data is in the form of a SMPTE-291 Ancillary Packet.
#define AJA_ENDIAN_32HtoN(__val__)
static const string gEmptyString
#define RCV2110DDBG(__x__)
AJAAncBufferFormat
Identifies the type of anc buffer the packet originated from: GUMP, RTP, VANC, or unknown...
static uint32_t gDestructCount(0)