cuei

package module
v1.1.99 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 15, 2024 License: BSD-3-Clause Imports: 7 Imported by: 0

README

https://goreportcard.com/report/github.com/futzu/cuei

cuei is the fastest SCTE35 parser library on the planet.

  • Parses SCTE-35 Cues from MPEGTS or Bytes or Base64 or Hex or Int or Octal or even Base 36.
  • Parses SCTE-35 Cues spread over multiple MPEGTS packets
  • Supports multi-packet PAT and PMT tables
  • Supports multiple MPEGTS Programs and multiple SCTE-35 streams
  • Encodes Time Signals and Splice Inserts with Descriptors and Upids.

Want to parse an MPEGTS video and print the SCTE-35? 🧮

Do it in ten lines.
⚗️
package main                          // 1

import (                              // 2
        "os"                          // 3    
        "github.com/futzu/cuei"       // 4
)                                     // 5

func main(){                          // 6
        arg := os.Args[1]             // 7
        stream := cuei.NewStream()    // 8
        stream.Decode(arg)            // 9
}                                     // 10  lines

Latest version is One One ninety-nine

  • Super cool custom JSONMarshal stuff
  • Updated to 2023r1 Specification

Install cuei

go get github.com/futzu/cuei@latest

Quick Demo

  • cueidemo.go
package main

import (
        "os"
        "fmt"
        "github.com/futzu/cuei"
)

func main(){

        arg := os.Args[1]

        stream := cuei.NewStream()
        cues := stream.Decode(arg)
        for _,cue := range cues {
        fmt.Printf("Command is a %v\n", cue.Command.Name)
        }

}



build cueidemo
go build cueidemo.go
parse mpegts video for scte35
./cueidemo a_video_with_scte35.ts
output
Next File: mpegts/out.ts

{
    "Name": "Splice Info Section",
    "TableID": "0xfc",
    "SectionSyntaxIndicator": false,
    "Private": false,
    "Reserved": "0x3",
    "SectionLength": 49,
    "ProtocolVersion": 0,
    "EncryptedPacket": false,
    "EncryptionAlgorithm": 0,
    "PtsAdjustment": 0,
    "CwIndex": "0x0",
    "Tier": "0xfff",
    "SpliceCommandLength": 20,
    "SpliceCommandType": 5,
    "DescriptorLoopLength": 12,
    "Command": {
        "Name": "Splice Insert",
        "CommandType": 5,
        "SpliceEventID": "0x5d",
        "OutOfNetworkIndicator": true,
        "ProgramSpliceFlag": true,
        "DurationFlag": true,
        "BreakDuration": 90.023266,
        "TimeSpecifiedFlag": true,
        "PTS": 38113.135577
    },
    "Descriptors": [
        {
            "Tag": 1,
            "Length": 10,
            "Identifier": "CUEI",
            "Name": "DTMF Descriptor",
            "PreRoll": 177,
            "DTMFCount": 4,
            "DTMFChars": 4186542473
        }
    ],
    "Packet": {
        "PacketNumber": 73885,
        "Pid": 515,
        "Program": 51,
        "Pcr": 38104.526277,
        "Pts": 38105.268588
    }
}


  • Use cuei.Stream.DecodeBytes for more fine-grained control of MPEGTS stream parsing.
package main

import (
	"fmt"
	"github.com/futzu/cuei"
	"os"
)

func main() {

	args := os.Args[1:] // Take multiple command line args
	for _, arg := range args {
		var cues []*cuei.Cue
		stream := cuei.NewStream() // New StreamParser for each file
		stream.Quiet = true // suppress printing SCTE-35 messages 
		
		file, err := os.Open(arg)
		if err != nil {
			break
		}
		defer file.Close()

		buffer := make([]byte, cuei.BufSz) // Parse in chunks
		for {
			_, err := file.Read(buffer)
			if err != nil {
				break
			}
			cues = stream.DecodeBytes(buffer)   // StreamParser.Parse returns a [] *cuei.Cue 
			for _,cue := range cues {
			// do stuff with the cues like:
				cue.Show()
			// or
			fmt.Printf("Command is a %v\n", cue.Command.Name)
			}
			
		}
	}
}

Parse base64 encoded SCTE-35

package main

import (
	"fmt"
	"github.com/futzu/cuei"
)

func main(){

	cue := cuei.NewCue()
	data := "/DA7AAAAAAAAAP/wFAUAAAABf+/+AItfZn4AKTLgAAEAAAAWAhRDVUVJAAAAAX//AAApMuABACIBAIoXZrM="
        cue.Decode(data) 
        fmt.Println("Cue as Json")
        cue.Show()
}

Shadow a Cue struct method

package main

import (
	"fmt"
	"github.com/futzu/cuei"
)

type Cue2 struct {
    cuei.Cue               		// Embed cuei.Cue
}
func (cue2 *Cue2) Show() {        	// Override Show
	fmt.Printf("%+v",cue2.Command)
}

func main(){

	var cue2 Cue2
	data := "/DA7AAAAAAAAAP/wFAUAAAABf+/+AItfZn4AKTLgAAEAAAAWAhRDVUVJAAAAAX//AAApMuABACIBAIoXZrM="
        cue2.Decode(data) 
        cue2.Show()
	
}

Call a shadowed method

package main

import (
	"fmt"
	"github.com/futzu/cuei"
)

type Cue2 struct {
    cuei.Cue               		// Embed cuei.Cue
}
func (cue2 *Cue2) Show() {        	// Override Show

	fmt.Println("Cue2.Show()")
	fmt.Printf("%+v",cue2.Command) 
	
	fmt.Println("\n\ncuei.Cue.Show() from cue2.Show()")
	
	cue2.Cue.Show()			// Call the Show method from embedded cuei.Cue
}

func main(){

	var cue2 Cue2
	data := "/DA7AAAAAAAAAP/wFAUAAAABf+/+AItfZn4AKTLgAAEAAAAWAhRDVUVJAAAAAX//AAApMuABACIBAIoXZrM="
        cue2.Decode(data) 
        cue2.Show()
	
}


Use Dot notation to access SCTE-35 Cue values


/**
Show  the packet PTS time and Splice Command Name of SCTE-35 Cues
in a MPEGTS stream.
**/
package main

import (
	"os"
	"fmt"
	"github.com/futzu/cuei"
)

func main() {

	arg := os.Args[1]
	stream := cuei.NewStream()
	cues :=	stream.Decode(arg)
	for _,c := range cues {
		fmt.Printf("PTS: %v, Splice Command: %v\n",c.PacketData.Pts, c.Command.Name )
	}
}

Load JSON and Encode

  • cuei can accept SCTE-35 data as JSON and encode it to Base64, Bytes, or Hex string.
package main

import (
	"fmt"
	"github.com/futzu/cuei"
)

func main() {

	js := `{
    "InfoSection": {
        "Name": "Splice Info Section",
        "TableID": "0xfc",
        "SectionSyntaxIndicator": false,
        "Private": false,
        "Reserved": "0x3",
        "SectionLength": 42,
        "ProtocolVersion": 0,
        "EncryptedPacket": false,
        "EncryptionAlgorithm": 0,
        "PtsAdjustment": 0,
        "CwIndex": "0xff",
        "Tier": "0xfff",
        "CommandLength": 15,
        "CommandType": 5
    },
    "Command": {
        "Name": "Splice Insert",
        "CommandType": 5,
        "SpliceEventID": 5690,
        "OutOfNetworkIndicator": true,
        "ProgramSpliceFlag": true,
        "TimeSpecifiedFlag": true,
        "PTS": 23683.480033
    },
    "DescriptorLoopLength": 10,
    "Descriptors": [
        {
            "Length": 8,
            "Identifier": "CUEI",
            "Name": "Avail Descriptor"
        }
    ],
    "Crc32": 3608566905
}
`
	cue :=  cuei.Json2Cue(js)
	
	cue.AdjustPts(28.0)   	 // Apply pts adjustment
	
	fmt.Println("\nBytes:\n\t", cue.Encode())	// Bytes
	
	fmt.Println("\nBase64:\n\t",cue.Encode2B64())  	// Base64
	
	fmt.Println("\nHex:\n\t",cue.Encode2Hex()) 	// Hex

}


  • Output
Bytes:
	[252 48 42 0 0 0 38 115 192 255 255 240 15 5 0 0 22 58 127 207 254 127 12 79 115
	0 0 0 0 0 10 0 8 67 85 69 73 0 0 0 0 236 139 53 78]

Base64:
	 /DAqAAAAJnPA///wDwUAABY6f8/+fwxPcwAAAAAACgAIQ1VFSQAAAADsizVO

Hex:
	 0xfc302a0000002673c0fffff00f050000163a7fcffe7f0c4f7300000000000a00084355454900000000ec8b354e


Cuei is the FourCC / identifier for SCTE-35

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func MkCrc32 added in v1.1.81

func MkCrc32(data []byte) uint32

MkCrc32 generate a 32 bit Crc

Types

type Command

type Command struct {
	Name                       string
	CommandType                uint8
	PrivateBytes               []byte
	Identifier                 uint32
	SpliceEventID              uint32
	SpliceEventCancelIndicator bool
	EventIDComplianceFlag      bool
	OutOfNetworkIndicator      bool
	ProgramSpliceFlag          bool
	DurationFlag               bool
	BreakAutoReturn            bool
	BreakDuration              float64
	SpliceImmediateFlag        bool
	UniqueProgramID            uint16
	AvailNum                   uint8
	AvailExpected              uint8
	TimeSpecifiedFlag          bool
	PTS                        float64
}

func (*Command) Json added in v1.1.81

func (cmd *Command) Json() string

Return Command as JSON

func (*Command) MarshalJSON added in v1.1.91

func (cmd *Command) MarshalJSON() ([]byte, error)

func (*Command) Show added in v1.1.81

func (cmd *Command) Show()

Print Command as JSON

type Cue

type Cue struct {
	InfoSection *InfoSection
	Command     *Command
	Dll         uint16       `json:"DescriptorLoopLength"`
	Descriptors []Descriptor `json:",omitempty"`
	PacketData  *packetData  `json:",omitempty"`
	Crc32       uint32
}

* Cue is a SCTE35 cue.

A Cue contains:

	1 InfoSection
   	1 Command
   	1 Dll  Descriptor loop length
   	0 or more Splice Descriptors
   	1 Crc32
   	1 packetData (if parsed from MPEGTS)

*

func Json2Cue

func Json2Cue(s string) *Cue

Take a JSON string and return a *Cue

Example
package main

import (
	"github.com/futzu/cuei"
)

func main() {

	js := `{
    "InfoSection": {
        "Name": "Splice Info Section",
        "TableID": "0xfc",
        "SectionSyntaxIndicator": false,
        "Private": false,
        "Reserved": "0x3",
        "SectionLength": 42,
        "ProtocolVersion": 0,
        "EncryptedPacket": false,
        "EncryptionAlgorithm": 0,
        "PtsAdjustment": 0,
        "CwIndex": "0xff",
        "Tier": "0xfff",
        "CommandLength": 15,
        "CommandType": 5
    },
    "Command": {
        "Name": "Splice Insert",
        "CommandType": 5,
        "SpliceEventID": 5690,
        "OutOfNetworkIndicator": true,
        "ProgramSpliceFlag": true,
        "TimeSpecifiedFlag": true,
        "PTS": 23683.480033
    },
    "DescriptorLoopLength": 10,
    "Descriptors": [
        {
            "Length": 8,
            "Identifier": "CUEI",
            "Name": "Avail Descriptor"
        }
    ],
    "Crc32": 3608566905
}
`
	cue := cuei.Json2Cue(js)
	cue.Encode()
	cue.Show()
}
Output:

func NewCue added in v1.1.51

func NewCue() *Cue

initialize and return a *Cue

Example
package main

import (
	"github.com/futzu/cuei"
)

func main() {
	data := "/DCtAAAAAAAAAP/wBQb+Tq9DwQCXAixDVUVJCUvhcH+fAR1QQ1IxXzEyMTYyMTE0MDBXQUJDUkFDSEFFTFJBWSEBAQIsQ1VFSQlL4W9/nwEdUENSMV8xMjE2MjExNDAwV0FCQ1JBQ0hBRUxSQVkRAQECGUNVRUkJTBwVf58BClRLUlIxNjA4NEEQAQECHkNVRUkJTBwWf98AA3clYAEKVEtSUjE2MDg0QSABAdHBXYA="

	cue := cuei.NewCue()
	cue.Decode(data)
	cue.Show()
}
Output:

func (*Cue) AdjustPts added in v1.1.71

func (cue *Cue) AdjustPts(seconds float64)

AdjustPts adds seconds to cue.InfoSection.PtsAdjustment

Example
package main

import (
	"fmt"
	"github.com/futzu/cuei"
)

func main() {
	data := "/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q=="
	cue := cuei.NewCue()
	cue.Decode(data)
	fmt.Println("Before calling Cue.AdjustPts")
	fmt.Println(data)
	cue.InfoSection.Show()
	fmt.Println()
	// Change cue.InfoSection.PtsAdjustment and re-encode cue to bytes
	cue.AdjustPts(33.333)
	fmt.Println("After calling Cue.AdjustPts")
	fmt.Println(cue.Encode2B64())
	cue.InfoSection.Show()

}
Output:

func (*Cue) Decode

func (cue *Cue) Decode(i interface{}) bool

Decode takes Cue data as []byte, base64 or hex string.

Example
package main

import (
	"fmt"
	"github.com/futzu/cuei"
)

func main() {
	data := "/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q=="
	cue := cuei.NewCue()
	cue.Decode(data)
	fmt.Println("Cue.Decode() parses data and populate the fields in the Cue.")
	cue.Show()
	fmt.Println("\n\nCue values can be accessed via dot notiation,")
	cue.Command.PTS = 987.654321
	fmt.Printf("cue.Command.PTS = %v\n", cue.Command.PTS)

}
Output:

func (*Cue) Encode

func (cue *Cue) Encode() []byte

Encode Cue currently works for Splice Inserts and Time Signals

Example
package main

import (
	"fmt"
	"github.com/futzu/cuei"
)

func main() {
	data := "/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q=="
	cue := cuei.NewCue()
	cue.Decode(data)
	fmt.Println(cue.Encode())
}
Output:

func (*Cue) Encode2B64 added in v1.1.75

func (cue *Cue) Encode2B64() string

Encode2B64 Encodes cue and returns Base64 string

Example
package main

import (
	"fmt"
	"github.com/futzu/cuei"
)

func main() {
	data := "/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q=="
	cue := cuei.NewCue()
	cue.Decode(data)
	fmt.Println(cue.Encode2B64())
}
Output:

func (*Cue) Encode2Hex added in v1.1.75

func (cue *Cue) Encode2Hex() string

Encode2Hex encodes cue and returns as a hex string

Example
package main

import (
	"fmt"
	"github.com/futzu/cuei"
)

func main() {
	data := "/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q=="
	cue := cuei.NewCue()
	cue.Decode(data)
	fmt.Println(cue.Encode2Hex())
	cue.Decode(cue.Encode2Hex())
	cue.Show()
	cue.Command.Show()
}
Output:

func (*Cue) Show

func (cue *Cue) Show()

Show display SCTE-35 data as JSON.

Example
package main

import (
	"github.com/futzu/cuei"
)

func main() {
	data := "/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q=="
	cue := cuei.NewCue()
	cue.Decode(data)
	cue.Show()
}
Output:

func (*Cue) Six2Five

func (cue *Cue) Six2Five() string

*

	Convert  Cue.Command  from a  Time Signal
	to a Splice Insert and return a base64 string
 	SegmentationTypeIds to trigger CUE-OUTs : 0x22, 0x30, 0x32, 0x34, 0x36, 0x44, 0x46
	SegmentationTypeIds to trigger CUE-INs:  0x23, 0x31, 0x33, 0x35, 0x37, 0x45, 0x47

*

type Descriptor

type Descriptor struct {
	Tag                                    uint8
	Length                                 uint8
	Identifier                             string
	Name                                   string
	ProviderAvailID                        uint32
	AudioComponents                        []audioCmpt
	PreRoll                                uint8
	DTMFCount                              uint8
	DTMFChars                              uint64
	TAISeconds                             uint64
	TAINano                                uint32
	UTCOffset                              uint16
	SegmentationEventID                    string
	SegmentationEventCancelIndicator       bool
	SegmentationEventIDComplianceIndicator bool
	ProgramSegmentationFlag                bool
	SegmentationDurationFlag               bool
	DeliveryNotRestrictedFlag              bool
	WebDeliveryAllowedFlag                 bool
	NoRegionalBlackoutFlag                 bool
	ArchiveAllowedFlag                     bool
	DeviceRestrictions                     string
	SegmentationDuration                   float64
	SegmentationMessage                    string
	SegmentationUpidType                   uint8
	SegmentationUpidLength                 uint8
	SegmentationUpid                       *Upid
	SegmentationTypeID                     uint8
	SegmentNum                             uint8
	SegmentsExpected                       uint8
	SubSegmentNum                          uint8
	SubSegmentsExpected                    uint8
}

*

Descriptor is the combination of all the descriptors
this is to maintain dot notation in the Cue struct.

*

func (*Descriptor) Json added in v1.1.81

func (dscptr *Descriptor) Json() string

Return Descriptor as JSON

func (*Descriptor) MarshalJSON added in v1.1.91

func (dscptr *Descriptor) MarshalJSON() ([]byte, error)
 *
    Custom MarshalJSON
        Marshal a Descriptor into

        0x0: AvailDescriptor,
	    0x1: DTMFDescriptor,
	    0x2: SegmentationDescriptor

        or just return the Descriptor

*

func (*Descriptor) Show added in v1.1.81

func (dscptr *Descriptor) Show()

Print Descriptor as JSON

type InfoSection

type InfoSection struct {
	Name                   string
	TableID                string
	SectionSyntaxIndicator bool
	Private                bool
	SapType                uint8
	SapDetails             string
	SectionLength          uint16
	ProtocolVersion        uint8
	EncryptedPacket        bool
	EncryptionAlgorithm    uint8
	PtsAdjustment          float64
	CwIndex                string
	Tier                   string
	CommandLength          uint16
	CommandType            uint8
}

InfoSection is the splice info section of the SCTE 35 cue.

func (*InfoSection) Json added in v1.1.83

func (infosec *InfoSection) Json() string

Return InfoSection as JSON

func (*InfoSection) Show added in v1.1.83

func (infosec *InfoSection) Show()

Print InfoSection as JSON

type Pids

type Pids struct {
	PmtPids    []uint16
	PcrPids    []uint16
	Scte35Pids []uint16
}

Pids holds collections of pids by type for cuei.Stream.

type Stream

type Stream struct {
	Cues     []*Cue
	Pids     *Pids
	Pid2Prgm map[uint16]uint16 // pid to program map
	Pid2Type map[uint16]uint8  // pid to stream type map
	Programs []uint16
	Prgm2Pcr map[uint16]uint64 // program to pcr map
	Prgm2Pts map[uint16]uint64 // program to pts map

	Quiet bool // Don't call Cue.Show() when a Cue is found.
	// contains filtered or unexported fields
}

Stream for parsing MPEGTS for SCTE-35

func NewStream added in v1.1.51

func NewStream() *Stream

initialize and return a *Stream

func (*Stream) Decode added in v1.1.51

func (stream *Stream) Decode(fname string) []*Cue

Decode fname (a file name) for SCTE-35

func (*Stream) DecodeBytes added in v1.1.51

func (stream *Stream) DecodeBytes(bites []byte) []*Cue

DecodeBytes Parses a chunk of mpegts bytes for SCTE-35

type Upid added in v1.1.53

type Upid struct {
	Name             string `json:",omitempty"`
	UpidType         uint8  `json:",omitempty"`
	Value            string `json:",omitempty"`
	TSID             uint16 `json:",omitempty"`
	Reserved         uint8  `json:",omitempty"`
	EndOfDay         uint8  `json:",omitempty"`
	UniqueFor        uint16 `json:",omitempty"`
	ContentID        []byte `json:",omitempty"`
	Upids            []Upid `json:",omitempty"`
	FormatIdentifier string `json:",omitempty"`
	PrivateData      []byte `json:",omitempty"`
}

Upid is the Struct for Segmentation Upids

Non-standard UPID types are returned as bytes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL