GithubHelp home page GithubHelp logo

comcast / scte35-go Goto Github PK

View Code? Open in Web Editor NEW
29.0 10.0 14.0 3.39 MB

Golang implementation of ANSI/SCTE-35

License: Apache License 2.0

Go 100.00%
scte-35 golang mpeg-ts video signaling decoder encoder go

scte35-go's Introduction

scte35-go: ANSI/SCTE 35 Decoder/Encoder

scte35-go is a Go library to supports creating, decorating, and analyzing binary Digital Program Insertion Cueing Messages.

This library is fully compliant and compatible with all versions of the ANSI/SCTE 35 specification up to and including ANSI/SCTE 35 2022b.

This project uses Semantic Versioning and is published as a Go Module.

Build Status PkgGoDev

Getting Started

Get the module:

$ go get github.com/Comcast/scte35-go
go get: added github.com/Comcast/scte35-go v1.2.1

Code Examples

Additional examples can be found in examples.

Decode Signal

Binary signals can be quickly and easily decoded from base-64 or hexadecimal strings.

The results can be output as a:

decode.go

package main

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"os"

	"github.com/Comcast/scte35-go/pkg/scte35"
)

func main() {
	sis, _ := scte35.DecodeBase64("/DA8AAAAAAAAAP///wb+06ACpQAmAiRDVUVJAACcHX//AACky4AMEERJU0NZTVdGMDQ1MjAwMEgxAQEMm4c0")

	// details
	_, _ = fmt.Fprintf(os.Stdout, "\nDetails: \n%s\n", sis)

	// xml
	b, _ := xml.MarshalIndent(sis, "", "\t")
	_, _ = fmt.Fprintf(os.Stdout, "\nXML: \n%s\n", b)

	// json
	b, _ = json.MarshalIndent(sis, "", "\t")
	_, _ = fmt.Fprintf(os.Stdout, "\nJSON: \n%s\n", b)
}
$ go run ./examples/decode.go

Details:
splice_info_section() {
    table_id: 0xfc
    section_syntax_indicator: false
    private_indicator: false
    sap_type: Not Specified
    section_length: 60 bytes
}
protocol_version: 0
encrypted_packet: false
encryption_algorithm: No encryption
pts_adjustment: 0 ticks (0s)
cw_index: 0
tier: 4095
splice_command_length: 5 bytes
splice_command_type: 0x06
time_signal() {
    time_specified_flag: true
    pts_time: 3550479013 ticks (10h57m29.766811111s)
}
descriptor_loop_length: 38 bytes
avail_descriptor() {
    splice_descriptor_tag: 0x02
    descriptor_length: 36 bytes
    identifier: CUEI
    segmentation_event_id: 39965
    segmentation_event_cancel_indicator: false
    program_segmentation_flag: true
    segmentation_duration_flag: true
    delivery_not_restricted_flag: true
    segmentation_duration: 10800000 ticks (2m0s)
    segmentation_upid_length: 16 bytes
    segmentation_upid {
        segmentation_upid_type: MPU() (0x0c)
        format_identifer: DISC
        segmentation_upid: 0x44495343594d57463034353230303048
    }
    segmentation_type_id: Provider Advertisement End (0x31)
    segment_num: 1
    segments_expected: 1
}

XML:
<SpliceInfoSection xmlns="http://www.scte.org/schemas/35" sapType="3" ptsAdjustment="0" protocolVersion="0" tier="4095">
  <TimeSignal xmlns="http://www.scte.org/schemas/35">
    <SpliceTime xmlns="http://www.scte.org/schemas/35" ptsTime="3550479013"></SpliceTime>
  </TimeSignal>
  <SegmentationDescriptor xmlns="http://www.scte.org/schemas/35" segmentationEventId="39965" segmentationEventCancelIndicator="false" segmentationDuration="10800000" segmentationTypeId="49" segmentNum="1" segmentsExpected="1">
    <SegmentationUpid xmlns="http://www.scte.org/schemas/35" segmentationUpidType="12" formatIdentifier="1145656131" format="base-64">WU1XRjA0NTIwMDBI</SegmentationUpid>
  </SegmentationDescriptor>
</SpliceInfoSection>

JSON:
{
  "protocolVersion": 0,
  "ptsAdjustment": 0,
  "sapType": 3,
  "spliceCommand": {
    "type": 6,
    "spliceTime": {
      "ptsTime": 3550479013
    }
  },
  "spliceDescriptors": [
    {
      "type": 2,
      "deliveryRestrictions": null,
      "segmentationUpids": [
        {
          "segmentationUpidType": 12,
          "formatIdentifier": 1145656131,
          "format": "base-64",
          "value": "WU1XRjA0NTIwMDBI"
        }
      ],
      "components": null,
      "segmentationEventId": 39965,
      "segmentationEventCancelIndicator": false,
      "segmentationDuration": 10800000,
      "segmentationTypeId": 49,
      "segmentNum": 1,
      "segmentsExpected": 1,
      "subSegmentNum": null,
      "subSegmentsExpected": null
    }
  ],
  "tier": 4095
}

Encode Signal

Encoding signals is equally simple. You can start from scratch and build a scte35.SpliceInfoSection or decode an existing signal and modify it to suit your needs.

encode.go

package main

import (
	"fmt"
	"os"

	"github.com/Comcast/scte35-go/pkg/scte35"
)

func main() {
	// start with a signal
	sis := scte35.SpliceInfoSection{
		SpliceCommand: scte35.NewTimeSignal(0x072bd0050),
		SpliceDescriptors: []scte35.SpliceDescriptor{
			&scte35.SegmentationDescriptor{
				DeliveryRestrictions: &scte35.DeliveryRestrictions{
					NoRegionalBlackoutFlag: true,
					ArchiveAllowedFlag:     true,
					DeviceRestrictions:     scte35.DeviceRestrictionsNone,
				},
				SegmentationEventID: uint32(0x4800008e),
				SegmentationTypeID:  scte35.SegmentationTypeProviderPOStart,
				SegmentationUPIDs: []scte35.SegmentationUPID{
					scte35.NewSegmentationUPID(scte35.SegmentationUPIDTypeTI, []byte("78511452")),
				},
				SegmentNum: 2,
			},
		},
		EncryptedPacket: scte35.EncryptedPacket{CWIndex: 255},
		Tier:            4095,
		SAPType:         3,
	}

	// encode it
	_, _ = fmt.Fprintf(os.Stdout, "Original:\n")
	_, _ = fmt.Fprintf(os.Stdout, "base-64: %s\n", sis.Base64())
	_, _ = fmt.Fprintf(os.Stdout, "hex    : %s\n", sis.Hex())

	// add a segmentation descriptor
	sis.SpliceDescriptors = append(
		sis.SpliceDescriptors,
		&scte35.DTMFDescriptor{
			DTMFChars: "ABC*",
		},
	)

	// encode it again
	_, _ = fmt.Fprintf(os.Stdout, "\nModified:\n")
	_, _ = fmt.Fprintf(os.Stdout, "base-64: %s\n", sis.Base64())
	_, _ = fmt.Fprintf(os.Stdout, "hex    : %s\n", sis.Hex())
}
$ go run ./examples/encode.go
Original:
base-64: /DAvAAAAAAAA///wBQb+cr0AUAAZAhdDVUVJSAAAjn+PCAg3ODUxMTQ1MjQCADhqB9E=
hex    : fc302f000000000000fffff00506fe72bd005000190217435545494800008e7f8f08083738353131343532340200386a07d1

Modified:
base-64: /DA7AAAAAAAA///wBQb+cr0AUAAlAhdDVUVJSAAAjn+PCAg3ODUxMTQ1MjQCAAEKQ1VFSQCfQUJDKqtwQlQ=
hex    : fc303b000000000000fffff00506fe72bd005000250217435545494800008e7f8f08083738353131343532340200010a43554549009f4142432aab704254

Decoding Non-Compliant Signals

The SCTE 35 decoder will always return a non-nil SpliceInfoSection, even when an error occurs. This is done to help better identify the specific cause of the decoding failure.

bad-signal

package main

import (
	"fmt"
	"os"

	"code.comcast.com/jbaile223/scte35/pkg/scte35"
)

func main() {
	sis, err := scte35.DecodeBase64("FkC1lwP3uTQD0VvxHwVBEH89G6B7VjzaZ9eNuyUF9q8pYAIXsRM9ZpDCczBeDbytQhXkssQstGJVGcvjZ3tiIMULiA4BpRHlzLGFa0q6aVMtzk8ZRUeLcxtKibgVOKBBnkCbOQyhSflFiDkrAAIp+Fk+VRsByTSkPN3RvyK+lWcjHElhwa9hNFcAy4dm3DdeRXnrD3I2mISNc7DkgS0ReotPyp94FV77xMHT4D7SYL48XU20UM4bgg==")
	if err != nil {
		fmt.Fprintf(os.Stdout, "Error: %s\n", err)
	}
	// splice info section contains best-effort decoding
	fmt.Fprintf(os.Stdout, "Signal: %s", sis)
}

As we can see from the output below, the signal has a corrupted component_count, causing the decoder to return a scte.ErrBufferOverflow:

$ go run ./examples/bad_signal.go
Error: splice_insert: buffer overflow
Signal: splice_info_section() {
    table_id: 0xfc
    section_syntax_indicator: false
    private_indicator: false
    sap_type: Type 1
    section_length: 343 bytes
}
protocol_version: 151
encrypted_packet: false
encryption_algorithm: No encryption
pts_adjustment: 8451077123 ticks (26h5m0.856922222s)
cw_index: 209
tier: 1471
splice_command_length: 326 bytes
splice_command_type: 0x05
splice_insert() {
    splice_event_id: 1091600189
    splice_event_cancel_indicator: false
    out_of_network_indicator: true
    program_splice_flag: false
    duration_flag: true
    splice_immediate_flag: false
    component_count: 123
    component[0] {
        component_tag: 86
        time_specified_flag: false
    }

    ... additional components removed

    component[122] {
        component_tag: 0
        time_specified_flag: false
    }
    auto_return: false
    duration: 0 ticks (0s)
    unique_program_id: 0
    avail_num: 0
    avails_expected: 0  
}

CRC_32 Validation

The SCTE 35 decoder performs automatic CRC_32 validation. The returned error can be explicitly ignored if desired.

sis, err := scte35.DecodeBase64("/DA4AAAAAAAAAP/wFAUABDEAf+//mWEhzP4Azf5gAQAAAAATAhFDVUVJAAAAAX+/AQIwNAEAAKeYO3Q=")
if err != nil && !errors.Is(err, scte35.ErrCRC32Invalid) {
  return err
}

Logging

Additional diagnostics can be enabled by redirecting the output of scte35.Logger

scte35.Logger.SetOutput(os.Stderr)

Command Line Interface

This package also provides a simple command line interface that supports encoding and decoding signals from the command line.

$ ./scte35-go --help
SCTE-35 CLI

Usage:
  scte35-go [command]

Available Commands:
  decode      Decode a splice_info_section from binary
  encode      Encode a splice_info_section to binary
  help        Help about any command

Flags:
  -h, --help   help for scte35-go

License

scte35-go is licensed under Apache License 2.0.

Code of Conduct

We take our code of conduct very seriously. Please abide by it.

Contributing

Please read our contributing guide for details on how to contribute to our project.

Releases

scte35-go's People

Contributors

blahspam avatar blahspambot avatar dugwill avatar marc-ostrow avatar reluxa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

scte35-go's Issues

SpliceInfoSection.SAPType defaults to SAPType1

The SCTE 35 2022b spec lists the SAPType field as:

@sapType [Optional; xsd:unsignedShort; default=3]

However, if you encode a SCTE 35 XML document that does not specify an sapType attribute for the SpliceInfoSection, then decode the resulting binary, the sapType specified in the decoded XML shows an sapType of '0', specifying Type 1 stream access point (Closed GOP with no leading pictures).

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Repository problems

Renovate tried to run on this repository, but found these problems.

  • WARN: Found renovate config warnings

Other Branches

These updates are pending. To force PRs open, click the checkbox below.

  • chore(deps): update actions/checkout action to v3.6.0
  • chore(deps): update actions/checkout action to v4
  • chore(deps): update actions/setup-go action to v5
  • chore(deps): update renovatebot/github-action action to v40

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/check.yml
  • actions/checkout v3
  • actions/setup-go v4
.github/workflows/renovate.yaml
  • actions/checkout v3.5.2
  • renovatebot/github-action v36.1.1
gomod
go.mod
  • go 1.18
  • github.com/bamiaux/iobit v0.0.0-20170418073505-498159a04883@498159a04883
  • github.com/spf13/cobra v1.8.0
  • github.com/stretchr/testify v1.9.0
  • golang.org/x/text v0.14.0
pre-commit
.pre-commit-config.yaml
  • pre-commit/pre-commit-hooks v4.5.0
  • tekwizely/pre-commit-golang v1.0.0-rc.1
  • adrienverge/yamllint v1.35.1
  • zricethezav/gitleaks v8.18.2
  • compilerla/conventional-pre-commit v2.4.0

SegmentationUpid.ASCIIValue() has issue in v1.4.3

The ASCIIValue() method in release scte35-go v1.4.3 panics with

panic: runtime error: index out of range [0] with length 0

from [email protected]/pkg/scte35/segmentation_upid.go:176

This worked without issue in version 1.4.2.

This is a quick program to reproduce:

package main

import (
	"fmt"

	"github.com/Comcast/scte35-go/pkg/scte35"
)

func main() {
	upid := scte35.SegmentationUPID{
		Type:  0x09,
		Value: "SIGNAL:z1sFOMjCnV4AAAAAAAABAQ==",
	}
	fmt.Printf("%+v\n", upid)
	fmt.Printf("%+v\n", upid.ASCIIValue()) // <- panics with index out of range in scte35.go v1.4.3. Was OK in v1.4.2.
}

Encode of Decode with alignment stuffing returns iobit.ErrOverflow

Here are two such examples of splice info sections that Decode having alignment stuffing, but an Encode of that decoded SpliceInfoSection fails with iobit.ErrOverflow.

  • /DA0AABS2+YAAACgFAUALJGCf+/+MSwPcX4AUmXAAAAAAAAMAQpDVUVJRp8xMjEq3pnIPCi6lw==
  • /DAvAABS2+YAAACgDwUALJGEf0/+MX7z3AAAAAAADAEKQ1VFSQCfMTIxI6SMuQkzWQI=

SpliceInfoSection.Decode is able to parse the sections, each having 3 bytes of alignment stuffing. When encoding, a buffer is allocated based on SpliceInfoSection.length which in turn is based on SpliceInfoSection.sectionLength which currently only includes alignment stuffing when the section is encrypted.

The fix is to move line splice_info_section.go#L371 out from (and placed above) the encryption check.

NOTE: These are SpliceInserts from the wild, you can't make this stuff up! ;-)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.