cuei

package module
v1.0.8 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2023 License: BSD-3-Clause Imports: 8 Imported by: 0

README

cuei is a SCTE35 parser library in Go.

  • 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

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

This section is empty.

Types

type Command

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

Command

These Splice Command types are consolidated into Command.

     0x0: Splice Null,
     0x5: Splice Insert,
     0x6: Time Signal,
     0x7: Bandwidth Reservation,
     0xff: Private,

func (*Command) Decode

func (cmd *Command) Decode(cmdtype uint8, bd *bitDecoder)

Decode a Splice Command

func (*Command) Encode

func (cmd *Command) Encode() []byte

Encode a Splice Command and return the bytes mostly used by cuei.Cue

func (*Command) Json

func (cmd *Command) Json() string

Return Command as JSON

func (*Command) Show

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
   	0 or 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

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

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)
	cue.Show()
	// Change cue.InfoSection.PtsAdjustment and re-encode cue to bytes
	cue.AdjustPts(33.333)
	cue.Show()
	fmt.Println("Was", data)
	fmt.Println("Is", cue.Encode2B64())
}
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 (
	"github.com/futzu/cuei"
)

func main() {
	data := "/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q=="
	cue := cuei.NewCue()
	cue.Decode(data)
	cue.Show()
}
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

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

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()
}
Output:

func (*Cue) Show

func (cue *Cue) Show()

Show display SCTE-35 data as JSON.

func (*Cue) Six2Five

func (cue *Cue) Six2Five() string

Convert Cue.Command from a Time Signal to a Splice Insert and return a base64 string

type Descriptor

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

func (*Descriptor) Decode

func (dscptr *Descriptor) Decode(bd *bitDecoder, tag uint8, length uint8)

* Decode returns a Splice Descriptor by tag.

The following Splice Descriptors are recognized.

    0x0: Avail Descriptor,
    0x1: DTMF Descriptor,
    0x2: Segmentation Descriptor,
    0x3: Time Descriptor,
    0x4: Audio Descrioptor,

*

func (*Descriptor) Encode

func (dscptr *Descriptor) Encode(be *bitEncoder)

func (*Descriptor) Json

func (dscptr *Descriptor) Json() string

Return Descriptor as JSON

func (*Descriptor) Show

func (dscptr *Descriptor) Show()

Print Descriptor as JSON

type InfoSection

type InfoSection struct {
	Name                   string
	TableID                string
	SectionSyntaxIndicator bool
	Private                bool
	Reserved               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) Decode

func (infosec *InfoSection) Decode(bd *bitDecoder) bool

Decode Splice Info Section values.

func (*InfoSection) Encode

func (infosec *InfoSection) Encode() []byte

Encode Splice Info Section Encodes the InfoSection variables to bytes.

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

func NewStream() *Stream

initialize and return a *Stream

func (*Stream) Decode

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

Decode fname (a file name) for SCTE-35

func (*Stream) DecodeBytes

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

DecodeBytes Parses a chunk of mpegts bytes for SCTE-35

type Upid

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.

func (*Upid) Decode

func (upid *Upid) Decode(bd *bitDecoder, upidType uint8, upidlen uint8)

Decode Upids

func (*Upid) Encode

func (upid *Upid) Encode(be *bitEncoder, upidType uint8)

Encode Upids

Jump to

Keyboard shortcuts

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