A guided map of the codebase for maintainers. Covers directory layout, module responsibilities, key data structures, and function entry points.
gstklvplugin/
├── include/
│ └── gstklv/
│ ├── klvencode.h # GstKlvEncode type declaration
│ ├── klvdecode.h # GstKlvDecode type declaration
│ ├── klvframeinject.h # GstKlvFrameInject type declaration
│ ├── tspmtrewrite.h # GstTsPmtRewrite type declaration
│ └── internal/
│ ├── klv_ber.h # BER length encode/decode
│ ├── klv_checksum.h # BCC-16 checksum
│ ├── klv_json.h # Flat JSON parser
│ ├── klv_scaling.h # Range scaling helpers
│ ├── klv_tag_defs.h # Tag registry types and loader
│ ├── klv_ul.h # MISB ST 0601 Universal Label
│ ├── ts_crc32.h # CRC-32/MPEG-2
│ └── ts_psi.h # PAT/PMT structures and parsing
├── src/
│ ├── plugins/
│ │ ├── plugin.c # gst_plugin_desc + element registration
│ │ ├── klvencode.c # klvmetaenc element
│ │ ├── klvdecode.c # klvmetadec element
│ │ ├── klvframeinject.c # klvframeinject element
│ │ └── tspmtrewrite.c # tspmtrewrite element
│ ├── klv/
│ │ ├── klv_ber.c
│ │ ├── klv_checksum.c
│ │ ├── klv_json.c
│ │ ├── klv_scaling.c
│ │ ├── klv_tag_defs.c
│ │ └── klv_ul.c
│ └── ts/
│ ├── ts_crc32.c
│ └── ts_psi.c
├── tests/check/elements/
│ ├── test_klvmetaenc.c
│ ├── test_klvmetadec.c
│ ├── test_klvframeinject.c
│ └── test_tspmtrewrite.c
├── examples/
│ ├── srt-pipelines/python/ # Python SRT sender/receiver
│ ├── srt-pipelines/cpp/ # C++ SRT sender/receiver
│ ├── ts/python/ # Python TS recorder/reader
│ └── ts/cpp/ # C++ TS recorder/reader
├── data/
│ └── stanag4609_tags.ini # Authoritative tag registry
└── tools/
├── capture_ts_from_srt.py
└── verify_ts_klv.py
flowchart TB
A["JSON string<br/>(application/json)"] --> B["klv_json_parse_flat()<br/>parse flat JSON"]
B --> C["klv_encode_tlv()<br/>build TLV per tag"]
C --> D["klv_ber_encode_length()<br/>BER-encode Local Set length"]
D --> E["klv_bcc_16()<br/>compute and append Tag 1"]
E --> F["KLV buffer<br/>(meta/x-klv)"]
Loading
flowchart TB
A["KLV buffer<br/>(meta/x-klv)"] --> B["UL verification"]
B --> C["klv_ber_decode_length()<br/>decode Local Set length"]
C --> D["klv_bcc_16()<br/>verify Tag 1 checksum"]
D --> E["klv_decode_with_range()<br/>inverse scaling per tag"]
E --> F["klv_json_format_number_*()<br/>serialize to JSON"]
F --> G["JSON string<br/>(application/json)"]
Loading
flowchart TB
A["Video buffer<br/>(video/x-h264 or h265)"] --> B["klvframeinject"]
B --> C["parse_json_tags()<br/>GRegex-based JSON parser"]
C --> D["create_klv_buffer()<br/>build KLV from tags or properties"]
D --> E["klv_bcc_16()<br/>compute and append Tag 1"]
B -->|passthrough| F["video_src"]
E -->|metadata| G["klv_src<br/>(meta/x-klv)"]
Loading
flowchart TB
A["MPEG-TS buffer"] --> B["tspmtrewrite<br/>(per 188-byte packet)"]
B --> C["ts_extract_section_from_packet()"]
C --> D["ts_parse_pat_section()<br/>find PMT PID"]
D --> E["ts_parse_pmt_section()<br/>parse PMT entries"]
E --> F["rewrite_pmt_section()<br/>set stream_type 0x06<br/>inject descriptor"]
F --> G["ts_build_pmt_section()<br/>serialize + CRC-32"]
G --> H["rewrite_pmt_packet()<br/>patch CC, write back into buffer"]
H --> I["MPEG-TS buffer<br/>(PMT rewritten)"]
Loading
src/plugins/plugin.c
Registers all four elements with GStreamer:
gst_element_register (plugin , "klvmetaenc" , GST_RANK_NONE , GST_TYPE_KLV_ENCODE );
gst_element_register (plugin , "klvmetadec" , GST_RANK_NONE , GST_TYPE_KLV_DECODE );
gst_element_register (plugin , "klvframeinject" ,GST_RANK_NONE , GST_TYPE_KLV_FRAME_INJECT );
gst_element_register (plugin , "tspmtrewrite" , GST_RANK_NONE , GST_TYPE_TS_PMT_REWRITE );
Element: klvmetaenc (src/plugins/klvencode.c)
Type: GstBaseTransform
Sink: application/json
Source: meta/x-klv
Function
Purpose
gst_klv_encode_transform
Main transform: parse JSON, encode TLVs, write UL + BER + checksum
klv_encode_tlv
Encode a single tag into TLV form (numeric or raw bytes)
get_tag_defs
Lazy-load tag registry via GOnce
klv_encode_with_range
Inverse range scaling: physical value → raw integer
write_be
Write big-endian integer of N bytes
Input JSON must be a flat object with numeric string keys: {"2": ..., "13": ...}.
Tags with range in the INI are numerically scaled; others are treated as raw integers or byte strings.
hex: and base64: prefixes are supported for local set and byte tags.
BCC-16 checksum is computed after the full Local Set is written and patched in-place.
Tag 1 (checksum) is never read from JSON — it is always generated automatically.
Element: klvmetadec (src/plugins/klvdecode.c)
Type: GstBaseTransform
Sink: meta/x-klv
Source: application/json
Function
Purpose
gst_klv_decode_transform
Main transform: verify UL, walk Local Set, emit JSON
klv_build_json
Decode BER length, validate CRC, build JSON string
get_tag_defs
Lazy-load tag registry via GOnce
klv_decode_with_range
Range scaling: raw integer → physical value
klv_sign_extend
Sign extension for signed tags without a range
UL is verified against KLV_MISB_ST0601_UL before parsing.
BCC-16 checksum is validated; mismatch produces a GST_WARNING but does not drop the buffer.
Tag 1 is verified to be the last tag; out-of-position Tag 1 produces a warning.
Tag 1 is excluded from JSON output.
Tags 2 and 72 are decoded as raw uint64 microsecond timestamps.
PTS and DTS are copied from the input KLV buffer to the JSON output buffer.
Element: klvframeinject (src/plugins/klvframeinject.c)
Type: GstElement (custom, not BaseTransform)
Sink: video/x-h264, video/x-h265 (byte-stream, au)
Source video_src: same as sink
Source klv_src: meta/x-klv
Structure
Description
GstKlvFrameInjectPrivate
Pads, tag registry, properties, mutex
JsonTagVal
Intermediate tag representation (numeric, string, bytes)
Function
Purpose
gst_klv_frame_inject_chain
Push video passthrough, emit matching KLV buffer
create_klv_buffer
Build KLV packet from tags-json or fallback properties
parse_json_tags
GRegex-based flat JSON parser (regex compiled once via GOnce)
encode_with_range
Range-scale value to raw integer using INI definitions
init_json_regex
Compile GRegex patterns once at first call
Property
Range / Default
Description
latitude
-90.0 to 90.0 / 0.0
Sensor latitude (Tag 13)
longitude
-180.0 to 180.0 / 0.0
Sensor longitude (Tag 14)
heading
0.0 to 360.0 / 0.0
Platform heading (Tag 5)
altitude
-900.0 to 20000.0 / 1000.0
Sensor altitude (Tag 15)
timestamp
uint64 / 0
Unix timestamp in microseconds (Tag 2)
use-system-time
bool / TRUE
Use system clock if timestamp is 0
tags-json
string / ""
Full tag set as JSON; overrides individual properties
Tag 1 (BCC-16 checksum) is always appended and computed over the full Local Set.
When tags-json is empty, tags 2/5/13/14/15 are populated from individual properties.
GRegex patterns are compiled once via g_once to avoid per-frame overhead.
Pad push is protected by a mutex on the private data.
Element: tspmtrewrite (src/plugins/tspmtrewrite.c)
Type: GstBaseTransform (in-place)
Sink / Source: video/mpegts, systemstream=true, packetsize=188
Function
Purpose
gst_ts_pmt_rewrite_transform_ip
Scan 188-byte TS packets, find and rewrite PMT
rewrite_pmt_section
Insert metadata_descriptor, set stream_type 0x06 for KLVA-tagged KLV
build_metadata_descriptor
Construct metadata_descriptor (0x26) from properties
rewrite_pmt_packet
Serialize rewritten section + CRC, patch continuity counter
Property
Default
Description
metadata-app-format
0xFFFF
metadata_application_format field
metadata-app-identifier
MISB
metadata_application_format_identifier (when app-format == 0xFFFF)
metadata-format
0xFF
metadata_format field
metadata-format-identifier
KLVA
metadata_format_identifier (when format == 0xFF)
metadata-service-id
0x01
metadata_service_id
metadata-flags
0x00
decoder_config_flags
Only rewrites PMT sections that fit in a single 188-byte TS packet; larger PMTs are left unchanged (logged as warning).
Only rewrites ES entries that have a KLVA registration_descriptor.
Current implementation uses stream_type 0x06 instead of 0x15 because the surrounding pipeline emits raw KLV, not MPEG metadata access units.
PMT version is incremented on each rewrite.
Continuity counter (pmt_cc) is seeded from the original packet and incremented modulo 16.
klv_ber — BER Length Encoding (ST 336)
Function
Description
klv_ber_encode_length
Encode length into a buffer; returns bytes written
klv_ber_decode_length
Decode BER length; returns bytes consumed
klv_ber_append_length
Append BER-encoded length to a GByteArray
Function
Description
klv_bcc_16
Sum all bytes modulo 65536, split into hi/lo
klv_json — Flat JSON Parser
Function
Description
klv_json_parse_flat
Parse {"key": value, ...} into KLVJsonTag array
klv_parse_hex_string
Decode hex:AABB... string to bytes
klv_parse_base64_string
Decode base64:... string to bytes
klv_json_format_number_double
Serialize a double with appropriate precision
klv_json_format_number_int64
Serialize a signed 64-bit integer
klv_json_format_number_uint64
Serialize an unsigned 64-bit integer
klv_json_append_escaped
Escape a string for JSON output
klv_scaling — Range Scaling
Function
Description
klv_decode_with_range
Convert raw integer to physical units
klv_encode_with_range
Convert physical value to raw integer
klv_sign_extend
Sign-extend a value from N bits to 64 bits
klv_tag_defs — Tag Registry
Type / Function
Description
KLVTagDef
Tag metadata: ID, name, type, bits, min, max, scale, units
klv_load_tag_defs_from_ini
Load and parse stanag4609_tags.ini into a GHashTable
klv_parse_range_string
Parse range strings like -900..19000 or +/- 20
Constant
Value
KLV_MISB_ST0601_UL
06 0E 2B 34 02 0B 01 01 0E 01 03 01 01 00 00 00
Function
Description
ts_crc32_mpeg2
Compute CRC-32/MPEG-2 over a byte range (polynomial 0x04C11DB7)
Types:
Type
Fields
TsDescriptor
tag (uint8), payload (GByteArray)
TsStreamInfo
stream_type (uint8), pid (uint16), descriptors (GPtrArray of TsDescriptor)
TsPmtInfo
program_number, version_byte, pcr_pid, program_info (GByteArray), streams (GPtrArray of TsStreamInfo)
Functions:
Function
Description
ts_extract_section_from_packet
Extract PSI section payload from a 188-byte TS packet
ts_parse_pat_section
Parse PAT section; extract PMT PID for a given program
ts_parse_pmt_section
Parse PMT section into TsPmtInfo
ts_build_pmt_section
Serialize TsPmtInfo back to bytes with CRC-32
ts_pmt_info_init / ts_pmt_info_clear
Initialize / free TsPmtInfo fields
ts_descriptor_free / ts_stream_info_free
GLib-compatible destructors for GPtrArray
Tag Registry and Scaling Details
The registry is loaded lazily at first use via GOnce in each element that needs it.
KLV_TAGS_INI environment variable overrides the compiled-in default path.
Ranges, signedness, and type are used to select the correct encode/decode path.
Tags declared as uint64 bypass scaling entirely and are serialized as 8-byte big-endian integers.
Timing and Buffer Correlation
klvmetadec copies GST_BUFFER_PTS and GST_BUFFER_DTS from the input KLV buffer to the JSON output buffer, preserving synchronization metadata.
klvframeinject stamps the klv_src buffer with the same PTS/DTS as the incoming video buffer, ensuring frame-level alignment.
Mechanism
How to use
GStreamer debug log
GST_DEBUG=klvmetaenc:5,klvframeinject:5 ./your-pipeline
KLV verbose log
KLV_DEBUG=1 ./your-pipeline
gst-check test output
GST_DEBUG=3 ./build/tests/check/elements_test_klvmetadec
PMT sections must fit within a single 188-byte TS packet to be rewritten. Multi-packet PMTs are not supported and produce a GST_WARNING.
Only payload bytes are left unchanged; only PMT signaling is modified.
The metadata descriptor is inserted immediately after the KLVA registration descriptor in the ES info section.