Embed CEA-608 Captions in H.264 SEI with FFmpeg

Embedding CEA-608 closed captions directly into H.264 Supplemental Enhancement Information (SEI) NAL units is a standard requirement for broadcast, OTT, and live-streaming workflows such as RTMP and HLS. This guide provides the complete FFmpeg command syntax and parameter details needed to multiplex a video stream and caption source, inject the caption data into the H.264 bitstream using ATSC A/53 SEI messages, and transmit it to a live destination.

The FFmpeg Live Streaming Command

To embed CEA-608 captions into H.264 SEI units during a live stream, use the following command structure:

ffmpeg -re -i input_video.mp4 -i input_captions.scc \
  -c:v libx264 -a53cc 1 \
  -preset veryfast -b:v 4000k -maxrate 4000k -bufsize 8000k \
  -pix_fmt yuv420p -g 60 -keyint_min 60 -sc_threshold 0 \
  -c:a aac -b:a 128k -ar 48000 \
  -f flv rtmp://live.example.com/app/stream_key

Command Breakdown

  • -re: Reads the input at its native frame rate, essential for simulating real-time streaming from file inputs.
  • -i input_video.mp4 and -i input_captions.scc: Specifies the primary video input and the caption track. The caption file can be an SCC (Scenarist Closed Caption) file, an embedded caption stream from an SDI capture card, or a subtitle track.
  • -c:v libx264: Uses the H.264 video encoder, which natively supports SEI caption insertion.
  • -a53cc 1: Instructs libx264 to parse incoming CEA-608/708 caption data and insert it as ATSC A/53 Part 4 User Data into the H.264 SEI NAL units.
  • -preset veryfast: Configures the encoding speed suitable for live streaming workloads to prevent frame drops.
  • -g 60 -keyint_min 60 -sc_threshold 0: Enforces a fixed Group of Pictures (GOP) size (e.g., 2-second keyframe intervals at 30 fps), which is required for predictable HLS/DASH segmentation.
  • -c:a aac -b:a 128k -ar 48000: Encodes audio to standard AAC format suitable for streaming.
  • -f flv rtmp://...: Multiplexes the resulting H.264 video (now containing the embedded SEI captions) and AAC audio into the RTMP protocol. For MPEG-TS/SRT workflows, change the format to -f mpegts srt://....

If capturing directly from an SDI capture card with pre-existing CEA-608 data (VANC line 21) or from an existing MPEG-TS containing embedded captions, explicit mapping is required:

ffmpeg -f decklink -i "DeckLink Studio 4K" \
  -c:v libx264 -a53cc 1 \
  -c:a aac -f flv rtmp://live.example.com/app/stream_key

When passing an existing stream that already contains CEA-608 subtitles in a distinct subtitle stream, ensure the subtitle stream is mapped to the encoder:

ffmpeg -re -i input.ts \
  -map 0:v:0 -map 0:a:0 -map 0:s? \
  -c:v libx264 -a53cc 1 \
  -c:a copy \
  -f flv rtmp://live.example.com/app/stream_key

Verification

To verify that the CEA-608 captions are correctly placed within the H.264 SEI payloads, inspect the output using ffprobe:

ffprobe -show_entries frame=pict_type,interlaced_frame -show_data -read_intervals "%+5" -f live_flv rtmp://live.example.com/app/stream_key

Look for side_data_type=A/53 Closed Captions within the frame metadata to confirm the captions are being transmitted as intended.