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_keyCommand Breakdown
-re: Reads the input at its native frame rate, essential for simulating real-time streaming from file inputs.-i input_video.mp4and-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: Instructslibx264to 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://....
Live Ingest from DeckLink or Existing Streams
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_keyWhen 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_keyVerification
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_keyLook for side_data_type=A/53 Closed Captions within the
frame metadata to confirm the captions are being transmitted as
intended.