AJA NTV2 SDK  17.5.0.1242
NTV2 SDK 17.5.0.1242
“libajacc” Closed-Caption Library

The AJA Closed-Caption Library (AJACCLib) is a suite of classes and data types which allow end-users to easily encode or decode CEA-608 or CEA-708 closed-caption data using nearly any NTV2-compatible AJA device using the C++ programming language. The code operates on Windows/VisualStudio, MacOS/Xcode and Linux/gcc.

The purpose of the AJACCLib library is to enable third-parties to easily access and/or control the caption data entering or leaving an AJA NTV2 device.

Note
The library currently is very focused on CEA-608. It does not support “full/native” CEA-708, Teletext, OP-42/47, ARIB STD-B37, etc.

As this library is AJA proprietary, source code is not provided.

Demonstration Applications
Principal Classes
Object Lifespan

Caption library class instances are provided using type-safe “smart” pointers (see AJARefPtr), which helps to simplify memory management, and eliminate leaks and double-free’s. Client programs need not micromanage the lifespans of these objects.

Client programs instantiate library objects using a Create class method, which always return a valid smart pointer if the function result is true, an invalid one if the result is false (i.e. std::bad_alloc should never be thrown).

Decoding CEA-608 Captions

The CNTV2CaptionDecoder608 class is a full-featured CEA-608 caption decoder that can decode message or control bytes found in line 21 of an SD frame buffer, parse it to the appropriate channel (CC1, CC2, etc.), where the current state and buffer status is maintained. The class handles parsing for captioning channels CC1-CC4, TX1-TX4, and XDS in parallel — i.e., it decodes them all simultaneously.

For display purposes, the class provides CNTV2CaptionDecoder608::SetDisplayChannel to select the current displayed channel of interest. However, since all channels are decoded simultaneously in parallel, the decoder’s “display” channel can be changed at any time, with the state of the newly-selected channel immediately seen without having to wait for the channel to receive enough new data to get back in-sync.

To implement a basic decoder, create an instance (using the CNTV2CaptionDecoder608::Create method), then call CNTV2CaptionDecoder608::SetDisplayChannel to select the current displayed channel of interest (if any). Clients should then call CNTV2CaptionDecoder608::ProcessNew608FrameData with the four bytes of CEA-608 CaptionData that arrive every frame. If interlaced video is being decoded, 2 bytes of data are often arriving with each field. The best thing to do is wait until the end of the frame and package both fields’ data into the one call.

CNTV2CaptionDecoder608::ProcessNew608FrameData should be called every frame, even if the captioning data for that frame is all zeroes. CEA-608 caption rules call for certain commands to be sent twice on adjacent frames. This means that there is a difference between command|command and command|NULL|command, and if the decoder never sees the intervening NULL frames, it may mistakenly think two commands came from adjacent frames and misinterpret them.

To display the caption data, call CNTV2CaptionDecoder608::SetDisplayChannel to select which captioning channel to display, then call CNTV2CaptionDecoder608::BurnCaptions with a pointer to the frame buffer holding the video. Clients may also iteratively call CNTV2CaptionDecoder608::GetOnAirCharacter to get the character at each “cell” of the frame buffer, and implement your own burn-in. When using the burn-in feature, CNTV2CaptionDecoder608::IdleFrame should be called once per frame to properly cause characters having the “blink” display attribute to flash.

The decoder also has a simple notification callback mechanism that notifies a client program of caption changes in the channel of interest. Call CNTV2CaptionDecoder608::SubscribeChangeNotification to install the client callback, and CNTV2CaptionDecoder608::UnsubscribeChangeNotification to remove it. As changes to the caption channel occur — e.g., the character to be displayed at a given row/column, or its attributes (color, italics, etc.) — the client callback function is called. This permits an event-driven caption display model, as opposed to a polled model. (Note that this mechanism cannot “blink” characters that have the “flash” display attribute.)

Encoding CEA-608 Captions

The CNTV2CaptionEncoder608 class is used to encode CEA-608 compliant caption messages into a valid “Line 21” waveform for copying into an SD frame buffer. It supports the three principal caption types — “pop-on”, “paint-on”, and “roll-up” — with optional character display attributes (color, italics, etc.).

Call CNTV2CaptionEncoder608::Create to instantiate a new instance.

There are three instance methods for enqueueing messages for each display method:

There are three instance methods for dequeueing messages, from lowest (least abstract) to highest (most abstract) level:

Note
The encoder’s dequeueing methods currently give priority to display messages (CC1-CC4) over non-display messages (TX1-TX4), sending TXn messages only when there are no CCn messages waiting to go. Because of CEA-608’s slow 4-byte-per-frame data rate, it’s easy to “saturate the pipeline” with display messages, causing non-display messages to never get sent. Client programs must take care to regulate the rate at which display messages are enqueued.

There are two methods for reporting the queue status:

Finally, there are five methods for reporting usage statistics — i.e., querying the total bytes or messages ever enqueued or dequeued, plus querying the highest queue depth.

The queues used in this class are thread-safe, so it’s okay to use one thread to enqueue messages, and another thread to dequeue them and encode them into your host frame buffer.

Encoding and Decoding SD “Line 21” Waveforms

The CNTV2Line21Captioner class is used to encode or decode EIA-608 compliant raw data bytes to/from line 21 of an SD frame buffer.

The CNTV2Line21Captioner::DecodeLine (static) class method decodes line 21 into raw caption bytes.

The CNTV2Line21Captioner::EncodeLine instance method encodes raw caption bytes into a line 21 waveform.

Decoding CEA-708 Captions

The CNTV2CaptionDecoder708 class is a CEA-708 caption decoder that can decode “service level 1” caption data found in SMPTE-334-compliant ancillary data packets. This is useful for extracting CEA-608 caption bytes from an HD video stream.

There are two ways to feed a decoder instance the requisite ancillary data it needs to decode captions:

  1. Manually — If the ancillary data is already available in a buffer, use the CNTV2CaptionDecoder708::SetSMPTE334AncData method, passing it a pointer to the buffer, and a byte count.
  2. Host Frame Buffer — If a video frame exists in host memory that includes VANC data, use the CNTV2CaptionDecoder708::FindSMPTE334AncPacketInVideoFrame method to have the decoder parse it.

Once the decoder has the ancillary data, call its CNTV2CaptionDecoder708::ParseSMPTE334AncPacket method to have it parsed.

To obtain any embedded 608-style captions it was able to decode, call its CNTV2CaptionDecoder708::GetCC608CaptionData method, then pass them into the CNTV2CaptionDecoder608 instance’s CNTV2CaptionDecoder608::ProcessNew608FrameData function.

Note
This decoder does not currently decode “native” CEA-708 captions — i.e., service levels 2 and up, that make use of windows of varying dimensions and transparency, fonts of varying sizes and styles, characters of varying colors and opacity, etc.

Encoding CEA-708 Captions

The CNTV2CaptionEncoder708 class is a CEA-708 caption encoder that encodes caption data into SMPTE-334-compliant ancillary data packets.

There are two principal sets of methods:

To output SMPTE-334 ancillary data into a host frame buffer for eventual transfer to an AJA device, call CNTV2CaptionEncoder708::InsertSMPTE334AncPacketInVideoFrame.

Note
This encoder implementation is capable of encoding what is necessary for translating CEA-608 captions into “708-compliant” captions suitable for transmission into HD video streams.

Rendering Captions

The CNTV2CaptionRenderer class renders CEA-608-compliant characters and/or strings into NTV2 frame buffers. It currently only supports the following frame buffer formats:

  • NTV2_FBF_10BIT_YCBCR
  • NTV2_FBF_8BIT_YCBCR
  • NTV2_FBF_ABGR
  • NTV2_FBF_RGBA
  • NTV2_FBF_ARGB
  • NTV2_FBF_10BIT_DPX
  • NTV2_FBF_10BIT_RGB

It’s easiest to use its class methods, which automatically take care of creating, opening and initializing the specific renderer instance for a given frame buffer format and frame geometry.

If more control is needed over when (and which) renderer instances get allocated or freed, use these class methods: