Expand description
§SCTE-35 Library
A Rust library for creating and parsing SCTE-35 (Society of Cable Telecommunications Engineers) messages with built-in CRC validation. SCTE-35 is a standard for inserting cue messages into video streams, commonly used for ad insertion points in broadcast television.
§Features
- Builder Pattern API - Type-safe builder pattern for creating SCTE-35 messages from scratch with validation
- Serde support - Serialize/deserialize SCTE-35 messages to/from JSON and other formats (enabled by default)
- CRC validation - Built-in CRC-32 validation using MPEG-2 algorithm (enabled by default)
- Human-readable UPID parsing - Full support for 18 standard UPID types with intelligent formatting
- Human-readable segmentation types - Complete set of 48 standard segmentation types with descriptive names
- Segmentation descriptor parsing - Complete parsing of segmentation descriptors including UPID data
- Minimal dependencies - Only the
crc
crate for validation (optional) andserde
for serialization (optional) - Full SCTE-35 parsing - Supports all major SCTE-35 command types
- Bit-level precision - Accurate parsing of bit-packed SCTE-35 messages
- Optional CLI tool - Command-line interface for parsing base64-encoded messages with text and JSON output formats
- Type-safe - Strongly typed representations of all SCTE-35 structures
- Data integrity - Detects corrupted or tampered SCTE-35 messages
§Installation
§With All Features (Default)
Add this to your Cargo.toml
:
[dependencies]
scte35 = "0.2.0"
This includes both CRC validation and serde support.
§Without Serde Support
If you don’t need JSON serialization:
[dependencies]
scte35 = { version = "0.2.0", default-features = false, features = ["crc-validation"] }
§Minimal (No CRC or Serde)
For a minimal library without CRC validation or serde:
[dependencies]
scte35 = { version = "0.2.0", default-features = false }
§With CLI Tool (Automatically includes CRC validation)
To include the command-line tool, enable the cli
feature:
[dependencies]
scte35 = { version = "0.2.0", features = ["cli"] }
Or install the CLI tool directly:
cargo install scte35 --features cli
Note: The CLI feature automatically enables CRC validation to provide complete message diagnostics.
§Usage
§Library Usage
use scte35::{parse_splice_info_section, SpliceCommand, SpliceDescriptor};
use std::time::Duration;
// Your SCTE-35 message as bytes (example message)
let scte35_bytes = vec![
0xFC, 0x30, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF0, 0x05, 0x06, 0xFE,
0x42, 0x3A, 0x35, 0xBD, 0x00, 0x00, 0xBB, 0x0C, 0x73, 0xF4
];
match parse_splice_info_section(&scte35_bytes) {
Ok(section) => {
println!("Table ID: {}", section.table_id);
println!("Command Type: {}", section.splice_command_type);
match section.splice_command {
SpliceCommand::SpliceInsert(insert) => {
println!("Splice Event ID: 0x{:08x}", insert.splice_event_id);
// Convert break duration to std::time::Duration
if let Some(break_duration) = &insert.break_duration {
let duration: Duration = break_duration.into();
println!("Break Duration: {:?}", duration);
println!("Break Duration: {:.3} seconds", duration.as_secs_f64());
}
// Convert splice time to Duration
if let Some(duration) = insert.splice_time.as_ref()
.and_then(|st| st.to_duration()) {
println!("Splice Time: {:?}", duration);
}
}
SpliceCommand::TimeSignal(signal) => {
if let Some(duration) = signal.splice_time.to_duration() {
println!("Time Signal: {:?}", duration);
}
}
_ => println!("Other command type"),
}
// Parse segmentation descriptors with UPID information
for descriptor in §ion.splice_descriptors {
if let SpliceDescriptor::Segmentation(seg_desc) = descriptor {
println!("Segmentation Event ID: 0x{:08x}", seg_desc.segmentation_event_id);
println!("UPID Type: {}", seg_desc.upid_type_description());
println!("Segmentation Type: {}", seg_desc.segmentation_type_description());
if let Some(upid_str) = seg_desc.upid_as_string() {
println!("UPID: {}", upid_str);
}
}
}
}
Err(e) => eprintln!("Error parsing SCTE-35: {}", e),
}
§CRC Validation
By default, the library validates CRC-32 checksums in SCTE-35 messages to ensure data integrity:
use scte35::{parse_splice_info_section, validate_scte35_crc, CrcValidatable};
// Example SCTE-35 message bytes
let scte35_bytes = vec![
0xFC, 0x30, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF0, 0x05, 0x06, 0xFE,
0x42, 0x3A, 0x35, 0xBD, 0x00, 0x00, 0xBB, 0x0C, 0x73, 0xF4
];
// Parse with automatic CRC validation (default behavior)
match parse_splice_info_section(&scte35_bytes) {
Ok(section) => {
println!("Valid SCTE-35 message parsed successfully");
println!("CRC-32: 0x{:08X}", section.get_crc());
}
Err(e) => {
if e.to_string().contains("CRC validation failed") {
eprintln!("Message corrupted or tampered: {}", e);
} else {
eprintln!("Parse error: {}", e);
}
}
}
// Validate CRC independently
match validate_scte35_crc(&scte35_bytes) {
Ok(true) => println!("CRC validation passed"),
Ok(false) => println!("CRC validation failed or not available"),
Err(e) => eprintln!("Validation error: {}", e),
}
// Validate using the parsed section
if let Ok(section) = parse_splice_info_section(&scte35_bytes) {
match section.validate_crc(&scte35_bytes) {
Ok(true) => println!("Message integrity verified"),
Ok(false) => println!("Message integrity check failed"),
Err(e) => eprintln!("Validation error: {}", e),
}
}
§Duration Conversion
SCTE-35 time values are represented as 90kHz clock ticks. This library provides convenient conversion to Rust’s std::time::Duration
:
use scte35::BreakDuration;
use std::time::Duration;
// Create a break duration of 30 seconds (30 * 90000 ticks)
let break_duration = BreakDuration {
auto_return: 1,
reserved: 0,
duration: 2_700_000,
};
// Convert using Into trait
let duration: Duration = (&break_duration).into();
assert_eq!(duration.as_secs(), 30);
// Or use the method directly
let duration2 = break_duration.to_duration();
assert_eq!(duration2.as_secs(), 30);
§Serde Support (JSON Serialization)
The library includes built-in serde support for serializing/deserializing SCTE-35 messages:
use scte35::parse_splice_info_section;
use serde_json;
// Parse SCTE-35 message
let scte35_bytes = vec![
0xFC, 0x30, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF0, 0x05, 0x06, 0xFE,
0x42, 0x3A, 0x35, 0xBD, 0x00, 0x00, 0xBB, 0x0C, 0x73, 0xF4
];
if let Ok(section) = parse_splice_info_section(&scte35_bytes) {
// Serialize to JSON
let json = serde_json::to_string_pretty(§ion).unwrap();
println!("{}", json);
// Deserialize from JSON
let deserialized: scte35::SpliceInfoSection =
serde_json::from_str(&json).unwrap();
assert_eq!(section, deserialized);
}
The serde implementation includes:
- Binary data as base64: All raw bytes (private commands, UPID data, alignment bits) are encoded as base64 strings
- Human-readable enums: Segmentation types and UPID types include both numeric values and descriptions
- Time duration info: PTS times and durations include both raw ticks and human-readable formats
- Computed fields: Segmentation descriptors include parsed UPID strings when available
Example JSON output:
{
"table_id": 252,
"section_syntax_indicator": 0,
"private_indicator": 0,
"section_length": 22,
"protocol_version": 0,
"encrypted_packet": 0,
"encryption_algorithm": 0,
"pts_adjustment": 0,
"cw_index": 255,
"tier": 4095,
"splice_command_length": 5,
"splice_command_type": 6,
"splice_command": {
"type": "TimeSignal",
"splice_time": {
"time_specified_flag": 1,
"pts_time": 900000,
"duration_info": {
"ticks": 900000,
"seconds": 10.0,
"human_readable": "10.0s"
}
}
},
"descriptor_loop_length": 0,
"splice_descriptors": [],
"alignment_stuffing_bits": "",
"e_crc_32": null,
"crc_32": 0
}
§Segmentation Types
The library provides human-readable segmentation types that correspond to the numeric IDs in SCTE-35 messages:
use scte35::{SegmentationType, parse_splice_info_section, SpliceDescriptor};
// Work with segmentation types directly
let seg_type = SegmentationType::ProviderAdvertisementStart;
println!("Type: {} (ID: 0x{:02X})", seg_type, seg_type.id());
// Convert from numeric ID (useful when parsing)
let seg_type = SegmentationType::from_id(0x30);
assert_eq!(seg_type, SegmentationType::ProviderAdvertisementStart);
assert_eq!(seg_type.to_string(), "Provider Advertisement Start");
// Example: Parse a message and check segmentation descriptors
let scte35_bytes = vec![
0xFC, 0x30, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF0, 0x05, 0x06, 0xFE,
0x42, 0x3A, 0x35, 0xBD, 0x00, 0x00, 0xBB, 0x0C, 0x73, 0xF4
];
if let Ok(section) = parse_splice_info_section(&scte35_bytes) {
// Segmentation descriptors automatically populate both fields
// The numeric ID and human-readable type are always consistent
for descriptor in §ion.splice_descriptors {
if let SpliceDescriptor::Segmentation(seg_desc) = descriptor {
println!("Segmentation Type ID: 0x{:02X}", seg_desc.segmentation_type_id);
println!("Segmentation Type: {:?}", seg_desc.segmentation_type);
println!("Description: {}", seg_desc.segmentation_type_description());
}
}
}
§Supported Segmentation Types
The library supports all standard SCTE-35 segmentation types including:
Program Boundaries:
- Program Start/End
- Program Early Termination
- Program Breakaway/Resumption
- Program Runover (Planned/Unplanned)
- Program Overlap Start
- Program Blackout Override
- Program Join
Content Segments:
- Chapter Start/End
- Break Start/End
- Content Identification
Advertisement Opportunities:
- Provider/Distributor Advertisement Start/End
- Provider/Distributor Placement Opportunity Start/End
- Provider/Distributor Overlay Placement Opportunity Start/End
- Provider/Distributor Promo Start/End
- Provider/Distributor Ad Block Start/End
Special Events:
- Unscheduled Event Start/End
- Alternate Content Opportunity Start/End
- Network Start/End
§Builder Pattern API (Creating SCTE-35 Messages)
The library includes a comprehensive builder pattern API for creating SCTE-35 messages from scratch with type safety and validation:
// Example 1: Creating a 30-second ad break starting at 20 seconds
let splice_insert = SpliceInsertBuilder::new(12345)
.at_pts(Duration::from_secs(20))?
.duration(Duration::from_secs(30))
.unique_program_id(0x1234)
.avail(1, 4) // First of 4 avails
.build()?;
let section = SpliceInfoSectionBuilder::new()
.pts_adjustment(0)
.splice_insert(splice_insert)
.build()?;
println!("Created SCTE-35 message with {} byte payload", section.section_length);
§Creating Time Signals with Segmentation Descriptors
// Example 2: Program start boundary with UPID
let segmentation = SegmentationDescriptorBuilder::new(
5678,
SegmentationType::ProgramStart
)
.upid(Upid::AdId("ABC123456789".to_string()))?
.duration(Duration::from_secs(1800))? // 30-minute program
.build()?;
let section = SpliceInfoSectionBuilder::new()
.time_signal(TimeSignalBuilder::new().immediate().build()?)
.add_segmentation_descriptor(segmentation)
.build()?;
§Component-Level Splice Operations
// Example 3: Component-level splice for specific audio/video streams
let splice_insert = SpliceInsertBuilder::new(3333)
.component_splice(vec![
(0x01, Some(Duration::from_secs(10))), // Video component
(0x02, Some(Duration::from_secs(10))), // Audio component 1
(0x03, Some(Duration::from_secs(10))), // Audio component 2
])?
.duration(Duration::from_secs(15))
.build()?;
§Advanced Segmentation with Delivery Restrictions
// Example 4: Complex segmentation with delivery restrictions
let restrictions = DeliveryRestrictions {
web_delivery_allowed: false,
no_regional_blackout: false,
archive_allowed: true,
device_restrictions: DeviceRestrictions::RestrictGroup1,
};
let uuid_bytes = [0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0];
let segmentation = SegmentationDescriptorBuilder::new(
7777,
SegmentationType::DistributorAdvertisementStart
)
.delivery_restrictions(restrictions)
.upid(Upid::Uuid(uuid_bytes))?
.segment(2, 6) // 2nd of 6 segments
.build()?;
§Comprehensive UPID Support
The builder API supports all SCTE-35 UPID types with validation:
// Ad ID (12 ASCII characters)
builder = builder.upid(Upid::AdId("ABC123456789".to_string()))?;
// UUID (16 bytes)
let uuid_bytes = [0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0];
builder = builder.upid(Upid::Uuid(uuid_bytes))?;
// URI (variable length)
builder = builder.upid(Upid::Uri("https://example.com/content/123".to_string()))?;
// ISAN (12 bytes)
let isan_bytes = [0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23];
builder = builder.upid(Upid::Isan(isan_bytes))?;
// And many more: UMID, EIDR, TID, AiringID, etc.
§Error Handling and Validation
The builder API provides comprehensive validation with clear error messages:
// Invalid UPID length
let result = SegmentationDescriptorBuilder::new(1234, SegmentationType::ProgramStart)
.upid(Upid::AdId("TOO_SHORT".to_string()));
match result {
Err(BuilderError::InvalidUpidLength { expected, actual }) => {
println!("UPID validation failed: expected {} chars, got {}", expected, actual);
}
_ => {}
}
// Duration too large for 33-bit PTS
let result = SpliceInsertBuilder::new(1234)
.at_pts(Duration::from_secs(u64::MAX / 90_000 + 1))?
.build();
match result {
Err(BuilderError::DurationTooLarge { field, duration }) => {
println!("Duration {} is too large for field {}", duration.as_secs(), field);
}
_ => {}
}
§Builder Features
- Type Safety: Compile-time prevention of invalid message states
- Validation: Runtime validation with descriptive error messages
- Ergonomic API: Fluent interface with sensible defaults
- Spec Compliance: Automatic handling of reserved fields and constraints
- Complete Coverage: Builders for all major SCTE-35 structures
See the builder_demo example for more comprehensive usage examples.
§CLI Usage
When built with the cli
feature, you can parse base64-encoded SCTE-35 messages with multiple output formats:
# Text output (default)
cargo run --features cli -- "/DAvAAAAAAAA///wFAVIAACPf+/+c2nALv4AUsz1AAAAAAAKAAhDVUVJAAABNWLbowo="
# JSON output
cargo run --features cli -- -o json "/DAvAAAAAAAA///wFAVIAACPf+/+c2nALv4AUsz1AAAAAAAKAAhDVUVJAAABNWLbowo="
# Or with long flag
cargo run --features cli -- --output json "/DAvAAAAAAAA///wFAVIAACPf+/+c2nALv4AUsz1AAAAAAAKAAhDVUVJAAABNWLbowo="
# Get help
cargo run --features cli -- --help
Example output with splice insert command and break duration:
Successfully parsed SpliceInfoSection:
Table ID: 252
Section Length: 47
Protocol Version: 0
Splice Command Type: 5
Splice Command Length: 20
Splice Command: SpliceInsert
Splice Event ID: 0x4800008f
Splice Event Cancel: 0
Out of Network: 1
Program Splice Flag: 1
Duration Flag: 1
Splice Immediate Flag: 0
Splice Time PTS: 0x07369c02e
Splice Time: 21514.559089 seconds
Break Duration:
Auto Return: 1
Duration: 0x00052ccf5 (60.293567 seconds)
Unique Program ID: 0
Avail Num: 0
Avails Expected: 0
Descriptor Loop Length: 10
Number of Descriptors: 1
Unknown Descriptor:
Tag: 0x00
Length: 8
Content: "CUEI 5"
CRC-32: 0x62DBA30A ✓ (Valid)
§CLI Output Formats
The CLI supports two output formats:
- Text format (default): Human-readable format with detailed field descriptions
- JSON format: Structured JSON output for programmatic use
JSON output includes the complete parsed structure with CRC validation results:
cargo run --features cli -- -o json "/DAvAAAAAAAA///wFAVIAACPf+/+c2nALv4AUsz1AAAAAAAKAAhDVUVJAAABNWLbowo="
{
"status": "success",
"data": {
"table_id": 252,
"section_length": 47,
"protocol_version": 0,
"splice_command_type": 5,
"splice_command_length": 20,
"splice_command": {
"type": "SpliceInsert",
"splice_event_id": 1207959695,
"splice_event_cancel_indicator": 0,
"out_of_network_indicator": 1,
"program_splice_flag": 1,
"duration_flag": 1,
"splice_immediate_flag": 0,
"splice_time": {
"time_specified_flag": 1,
"pts_time": 1936310318,
"duration_info": {
"ticks": 1936310318,
"seconds": 21514.559088888887,
"human_readable": "5h 58m 34.6s"
}
},
"break_duration": {
"auto_return": 1,
"duration": 5426421,
"duration_info": {
"ticks": 5426421,
"seconds": 60.29356666666666,
"human_readable": "1m 0.3s"
}
},
"unique_program_id": 0,
"avail_num": 0,
"avails_expected": 0
},
"descriptor_loop_length": 10,
"splice_descriptors": [
{
"descriptor_type": "Unknown",
"tag": 0,
"length": 8,
"data": "Q1VFSQAAATU="
}
],
"crc_32": 1658561290
},
"crc_validation": {
"valid": true,
"error": null
}
}
§Supported SCTE-35 Commands
- SpliceNull - Null command
- SpliceSchedule - Scheduled splice events
- SpliceInsert - Immediate or scheduled ad insertion points
- TimeSignal - Time synchronization signals
- BandwidthReservation - Bandwidth allocation commands
- PrivateCommand - Private/custom commands
§CRC Validation
By default, the library validates CRC-32 checksums in SCTE-35 messages to ensure data integrity. This feature can be disabled if needed:
§With CRC Validation (Default)
[dependencies]
scte35 = "0.2.0"
§Without CRC Validation (Library only)
[dependencies]
scte35 = { version = "0.2.0", default-features = false }
§With CLI Tool (Automatically includes CRC validation)
[dependencies]
scte35 = { version = "0.2.0", features = ["cli"] }
Note: The CLI feature automatically enables CRC validation to provide complete message diagnostics.
§Benefits of CRC Validation
- Data Integrity: Ensures SCTE-35 messages haven’t been corrupted during transmission
- Security: Helps detect tampered messages
- Debugging: Identifies parsing issues vs. data corruption
- Standards Compliance: Follows SCTE-35 specification requirements
- Flexibility: Optional feature allows users to choose performance vs. validation trade-offs
§API Documentation
Full API documentation is available at docs.rs or can be generated locally:
cargo doc --no-deps --open
§Main Functions
§parse_splice_info_section(buffer: &[u8]) -> Result<SpliceInfoSection, io::Error>
Parses a complete SCTE-35 splice information section from a byte buffer. Automatically validates CRC-32 when the crc-validation
feature is enabled.
§validate_scte35_crc(buffer: &[u8]) -> Result<bool, io::Error>
Validates the CRC-32 checksum of an SCTE-35 message independently. Returns Ok(true)
if valid, Ok(false)
if invalid or CRC validation is disabled.
§Data Structures
§SpliceInfoSection
The top-level structure containing all SCTE-35 message fields:
table_id
: Table identifier (should be 0xFC for SCTE-35)section_length
: Length of the sectionprotocol_version
: SCTE-35 protocol versionsplice_command_type
: Type of splice commandsplice_command
: The actual command data (enum)descriptor_loop_length
: Length of descriptorssplice_descriptors
: List of splice descriptorscrc_32
: CRC32 checksum
§SpliceCommand
An enum representing different SCTE-35 command types:
SpliceNull
SpliceSchedule(SpliceSchedule)
SpliceInsert(SpliceInsert)
TimeSignal(TimeSignal)
BandwidthReservation(BandwidthReservation)
PrivateCommand(PrivateCommand)
Unknown
§Building from Source
§Build Library Only
git clone https://github.com/yourusername/scte35
cd scte35
cargo build --release
§Build with CLI Tool
cargo build --release --features cli
§Run Tests
cargo test
§License
This project is licensed under the MIT License - see the LICENSE file for details.
§Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
§References
Re-exports§
pub use crc::CrcValidatable;
pub use crc::validate_message_crc;
pub use parser::parse_splice_info_section;
pub use types::BandwidthReservation;
pub use types::ComponentSplice;
pub use types::PrivateCommand;
pub use types::SegmentationType;
pub use types::SpliceCommand;
pub use types::SpliceInfoSection;
pub use types::SpliceInsert;
pub use types::SpliceInsertComponent;
pub use types::SpliceNull;
pub use types::SpliceSchedule;
pub use types::TimeSignal;
pub use time::BreakDuration;
pub use time::SpliceTime;
pub use upid::SegmentationUpidType;
pub use descriptors::SegmentationDescriptor;
pub use descriptors::SpliceDescriptor;
Modules§
- builders
- Builder pattern API for creating SCTE-35 messages from scratch. Builder pattern API for creating SCTE-35 messages from scratch.
- crc
- CRC validation module for SCTE-35 messages.
- descriptors
- SCTE-35 descriptor types and parsing.
- encoding
- Binary encoding support for SCTE-35 messages. Binary encoding support for SCTE-35 messages.
- parser
- Main parsing functions for SCTE-35 messages.
- serde
- Serde serialization support for SCTE-35 types.
- time
- Time-related structures and utilities for SCTE-35 messages.
- types
- Core SCTE-35 data structures and types.
- upid
- UPID (Unique Program Identifier) types and formatting utilities.
Functions§
- validate_
scte35_ crc - Validates the CRC-32 checksum of an SCTE-35 message.