Skip to content

Commit

Permalink
Updated DVB decoding transport stream
Browse files Browse the repository at this point in the history
  • Loading branch information
djthorpe committed Jan 27, 2021
1 parent a35063f commit 71a8b09
Show file tree
Hide file tree
Showing 16 changed files with 870 additions and 20 deletions.
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ ifneq ($strip $(FT)),)
$(eval TAGS += ffmpeg)
endif

# DVB bindings
dvb:
@echo "Targetting dvb"
$(eval TAGS += dvb)

# Chromaprint bindings
chromaprint: darwin
$(eval FT = $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --silence-errors --modversion libchromaprint))
Expand Down Expand Up @@ -191,6 +196,9 @@ googlecast: builddir protogen
mediakit: builddir ffmpeg chromaprint
PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" $(GO) build -o ${BUILDDIR}/mediakit -tags "$(TAGS)" ${GOFLAGS} ./cmd/mediakit

dvbkit: builddir dvb
PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" $(GO) build -o ${BUILDDIR}/dvbkit -tags "$(TAGS)" ${GOFLAGS} ./cmd/dvbkit

gx: builddir rpi egl drm gbm
PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" $(GO) build -o ${BUILDDIR}/gx -tags "$(TAGS)" ${GOFLAGS} ./cmd/gx

Expand Down
90 changes: 90 additions & 0 deletions cmd/dvbkit/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package main

import (
"context"
"fmt"
"os"
"time"

"github.com/djthorpe/gopi/v3"
)

////////////////////////////////////////////////////////////////////////////////
// TYPES

type app struct {
gopi.Unit
gopi.Logger
gopi.DVBManager
gopi.DVBTuner

timeout *time.Duration
tuner *uint
params []gopi.DVBTunerParams
}

////////////////////////////////////////////////////////////////////////////////
// LIFECYCLE

func (this *app) Define(cfg gopi.Config) error {
this.timeout = cfg.FlagDuration("timeout", 2*time.Second, "Tune timeout")
this.tuner = cfg.FlagUint("tuner", 0, "Tuner identifier")
return nil
}

func (this *app) New(cfg gopi.Config) error {
this.Require(this.Logger, this.DVBManager)

args := cfg.Args()
if len(args) != 1 {
return gopi.ErrBadParameter.WithPrefix("file")
}

// Set the tuner
tuners := this.DVBManager.Tuners()
for _, tuner := range tuners {
if tuner.Id() == *this.tuner {
this.DVBTuner = tuner
}
}
if this.DVBTuner == nil {
return gopi.ErrNotFound.WithPrefix("Tuner")
}

// Parse tuner params
if fh, err := os.Open(args[0]); err != nil {
return err
} else if params, err := this.DVBManager.ParseTunerParams(fh); err != nil {
return err
} else {
this.params = params
}

// Return success
return nil
}

func (this *app) Run(ctx context.Context) error {

// Tune all channels
for _, param := range this.params {
fmt.Println("Tune:", this.DVBTuner, param.Name())
tunectx, cancel := context.WithTimeout(ctx, *this.timeout)
defer cancel()

if err := this.Tune(tunectx, this.DVBTuner, param); err != nil {
fmt.Println(" Error:", err)
} else if tunectx.Err() == nil {
fmt.Println(" SCAN")
this.ScanNIT(this.DVBTuner)
<-tunectx.Done()

}
}

// Wait for interrupt
fmt.Println("Press CTRL+C to end")
<-ctx.Done()

return ctx.Err()
}
11 changes: 11 additions & 0 deletions cmd/dvbkit/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

import (
"os"

tool "github.com/djthorpe/gopi/v3/pkg/tool"
)

func main() {
os.Exit(tool.CommandLine("dvbkit", os.Args[1:], new(app)))
}
7 changes: 7 additions & 0 deletions cmd/dvbkit/units.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

import (
_ "github.com/djthorpe/gopi/v3/pkg/event"
_ "github.com/djthorpe/gopi/v3/pkg/file"
_ "github.com/djthorpe/gopi/v3/pkg/media/dvb"
)
3 changes: 3 additions & 0 deletions media.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ type DVBManager interface {

// Tune to parameters with timeout
Tune(context.Context, DVBTuner, DVBTunerParams) error

// Temporary methods
ScanNIT(DVBTuner) error
}

// DVBTunerParams represents tune parameters
Expand Down
2 changes: 0 additions & 2 deletions pkg/file/filepoll_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,6 @@ func (this *filepoll) call(fd uintptr, flags gopi.FilePollFlags) {
}
} else if handler, exists := this.funcs[fd]; exists {
handler(fd, flags)
} else {
this.Print("Filepoll: Unable to handle fd=", fd, " flags=", flags)
}
}

Expand Down
234 changes: 234 additions & 0 deletions pkg/media/dvb/filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
// +build dvb

package dvb

import (
"fmt"
"os"
"strconv"
"sync"

gopi "github.com/djthorpe/gopi/v3"
ts "github.com/djthorpe/gopi/v3/pkg/media/internal/ts"
dvb "github.com/djthorpe/gopi/v3/pkg/sys/dvb"
multierror "github.com/hashicorp/go-multierror"
)

////////////////////////////////////////////////////////////////////////////////
// TYPES

type Filter struct {
sync.RWMutex
dev *os.File
}

type SectionFilter struct {
Filter
*dvb.DMXSectionFilter
}

type StreamFilter struct {
Filter
*dvb.DMXStreamFilter
}

////////////////////////////////////////////////////////////////////////////////
// LIFECYCLE

func NewSectionFilter(tuner *Tuner, pid uint16, tids ...ts.TableType) (*SectionFilter, error) {
this := new(SectionFilter)

// Check incoming parameters
if tuner == nil {
return nil, gopi.ErrBadParameter.WithPrefix("NewSectionFilter")
}
if len(tids) == 0 {
return nil, gopi.ErrBadParameter.WithPrefix("NewSectionFilter")
}

// Open device
if dev, err := tuner.DMXOpen(); err != nil {
return nil, err
} else {
this.dev = dev
}

// Create filter with 0ms timeout (no timeout)
this.DMXSectionFilter = dvb.NewSectionFilter(pid, 0, dvb.DMX_NONE)
for i, tid := range tids {
this.DMXSectionFilter.Set(i, uint8(tid), 0xFF, 0x00)
}

// Set filter
if err := dvb.DMXSetSectionFilter(this.dev.Fd(), this.DMXSectionFilter); err != nil {
this.dev.Close()
return nil, err
}

// Return success
return this, nil
}

func NewStreamFilter(tuner *Tuner, pid uint16, in dvb.DMXInput, out dvb.DMXOutput, stream dvb.DMXStreamType) (*StreamFilter, error) {
this := new(StreamFilter)

// Check incoming parameters
if tuner == nil {
return nil, gopi.ErrBadParameter.WithPrefix("NewStreamFilter")
}

// Open device
if dev, err := tuner.DMXOpen(); err != nil {
return nil, err
} else {
this.dev = dev
}

// Create filter
this.DMXStreamFilter = dvb.NewStreamFilter(pid, in, out, stream, dvb.DMX_NONE)

// Set filter
if err := dvb.DMXSetStreamFilter(this.dev.Fd(), this.DMXStreamFilter); err != nil {
this.dev.Close()
return nil, err
}

// Return success
return this, nil
}

func (this *Filter) Dispose() error {
this.RWMutex.Lock()
defer this.RWMutex.Unlock()

var result error
if this.dev != nil {
if err := this.dev.Close(); err != nil {
result = multierror.Append(result, err)
}
}

// Release resources
this.dev = nil

// Return success
return result
}

////////////////////////////////////////////////////////////////////////////////
// PROPERTIES

func (this *Filter) Fd() uintptr {
this.RWMutex.RLock()
defer this.RWMutex.RUnlock()

if this.dev == nil {
return 0
} else {
return this.dev.Fd()
}
}

////////////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS

func (this *Filter) Start() error {
this.RWMutex.Lock()
defer this.RWMutex.Unlock()

if this.dev == nil {
return gopi.ErrOutOfOrder.WithPrefix("Start")
}

return dvb.DMXStart(this.dev.Fd())
}

func (this *Filter) Stop() error {
this.RWMutex.Lock()
defer this.RWMutex.Unlock()

if this.dev == nil {
return gopi.ErrOutOfOrder.WithPrefix("Stop")
}

return dvb.DMXStop(this.dev.Fd())
}

func (this *Filter) AddPid(pid uint16) error {
this.RWMutex.Lock()
defer this.RWMutex.Unlock()

if this.dev == nil {
return gopi.ErrOutOfOrder.WithPrefix("AddPid")
}

return dvb.DMXAddPid(this.dev.Fd(), pid)
}

func (this *Filter) AddPids(pids []uint16) error {
this.RWMutex.Lock()
defer this.RWMutex.Unlock()

if this.dev == nil {
return gopi.ErrOutOfOrder.WithPrefix("AddPids")
}

var result error
for _, pid := range pids {
if err := dvb.DMXAddPid(this.dev.Fd(), pid); err != nil {
result = multierror.Append(result, err)
}
}

// Success
return result
}

func (this *Filter) SetBufferSize(size uint32) error {
this.RWMutex.Lock()
defer this.RWMutex.Unlock()

if this.dev == nil {
return gopi.ErrOutOfOrder.WithPrefix("SetBufferSize")
}

return dvb.DMXSetBufferSize(this.dev.Fd(), size)
}

func (this *Filter) RemovePid(pid uint16) error {
this.RWMutex.Lock()
defer this.RWMutex.Unlock()

if this.dev == nil {
return gopi.ErrOutOfOrder.WithPrefix("RemovePid")
}

return dvb.DMXRemovePid(this.dev.Fd(), pid)
}

////////////////////////////////////////////////////////////////////////////////
// STRINGIFY

func (this *SectionFilter) String() string {
this.RWMutex.RLock()
defer this.RWMutex.RUnlock()

str := "<dvb.sectionfilter"
if this.dev != nil {
str += " dev=" + strconv.Quote(this.dev.Name())
str += " filter=" + fmt.Sprint(this.DMXSectionFilter)
}
return str + ">"
}

func (this *StreamFilter) String() string {
this.RWMutex.RLock()
defer this.RWMutex.RUnlock()

str := "<dvb.streamfilter"
if this.dev != nil {
str += " dev=" + strconv.Quote(this.dev.Name())
str += " filter=" + fmt.Sprint(this.DMXStreamFilter)
}
return str + ">"
}
Loading

0 comments on commit 71a8b09

Please sign in to comment.