astiencoder

package module
v0.24.0 Latest Latest
Warning

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

Go to latest
Published: Mar 22, 2022 License: MIT Imports: 20 Imported by: 0

README

astiencoder is an open source video encoder written in GO and based on ffmpeg C bindings

Right now this project has only been tested on FFMpeg n4.4.1

You need GO >= 1.13

screenshot-1

Why use this project when I can use ffmpeg binary?

In most cases you won't need this project as the ffmpeg binary is pretty awesome.

However, this project could be useful to you if you're looking to:

  1. understand how the video encoding process work
  2. integrate your video encoder in a GO ecosystem
  3. visualize in real time, record or replay your encoding workflow and nodes statuses and stats
  4. use native GO subtitle libraries like astisub
  5. build your own video encoder and take control of its workflow

How is this project structured?

The encoder framework

At the root of the project, package astiencoder provides the framework to build Workflows. Workflows are made of Nodes. Nodes can start/pause/continue/stop any kind of work.

It also provides a Server that exposes the UI.

All internal Events can be handled with the proper EventHandler.

The libav wrapper

In folder libav, package astilibav provides the proper nodes to use the ffmpeg C bindings with the encoder:

At this point the way you connect those nodes is up to you since they implement 2 main interfaces:

type PktHandler interface {
	HandlePkt(p *PktHandlerPayload)
}

type FrameHandler interface {
	HandleFrame(p *FrameHandlerPayload)
}

The out-of-the-box encoder

In folder astiencoder, package main provides an out-of-the-box encoder using both packages astiencoder and astilibav.

It creates workflows based on Jobs.

It's a good place to start digging if you're looking to implement your own workflow builder.

How do I install this project?

FFMpeg

In order to use the ffmpeg C bindings, you need to install ffmpeg. To do so, run the following command:

$ make install-ffmpeg

In some cases, you'll need to enable/disable libs explicitly. To do so, use the configure placeholder. For instance this will install the libx264 as well:

$ make install-ffmpeg configure="--enable-libx264 --enable-gpl"

Astiencoder

Simply run the following command:

$ go get github.com/asticode/go-astiencoder/...

Test everything is working fine

Simply run the following command:

$ make version

It should print something like:

avcodec: 3805796
avdevice: 3801956
avfilter: 462948
avutil: 3673700
resample: GPL version 2 or later
swscale: 328036

How can I run the out-of-the-box encoder?

Modes

The out-of-the-box encoder has 2 modes:

  • by default it will spawn the server and wait for a new workflow to be added manually
  • when provided with the -j flag, it will open the provided json-formatted job, transform it into a workflow, execute it and exit once everything is done

To run the default mode, simply run the following command:

$ make server

Web UI

If you set up the server correctly, you can open the Web UI in order to see your node's stats.

What do those stats mean?

Nodes use the same stats:

  • Incoming rate: the number of incoming object received per second. This is either packets per second (pps) or frames per second (fps).
  • Listen ratio: the percentage of time spent waiting for a new incoming object
  • Dispatch ratio: the percentage of time spent waiting for all children to be available to process the output object.
  • Work ratio: the percentage of time spent doing some actual work

That way you can monitor the efficiency of your workflow and see which node needs work.

How can I run examples?

Examples are located in the examples folder and consists of json-formatted jobs.

If you want to run a specific example, run the following command:

$ make example=<name of the example>

File outputs will be written in the examples/tmp folder.

WARNING: for the following examples you will need specific ffmpeg libs enabled. Again, in order to do so, use the configure placeholder as mentioned here:

  • encode: --enable-libx264 --enable-gpl

How can I build my own workflow?

I'd recommend to get inspiration from the out-of-the-box encoder's workflow builder.

Which ffmpeg C bindings is this project using and why?

Right now this project is using these bindings.

Here's why:

  1. the base project is not maintained anymore
  2. this project is a hard fork of #1 but has gone a very different route
  3. this project is a fork of #1 but I'm experiencing lots of panics
  4. this project is the best fork of #1 even though the last commit is not recent
  5. this project is a fork of #4 with interesting additional commits
  6. this project is a fork of #4 with interesting additional commits
  7. this project has a very nice set of examples

Therefore I've forked #4, added useful commits from other forks and removed deprecated functions so that it works properly in FFMpeg n4.4.1.

I'm not familiar with CGO, which flags am I supposed to provide?

If you're using make, you're not supposed to add CGO flags manually, it will do it for you.

Otherwise you need to provide the proper CGO_CFLAGS, CGO_LDFLAGS and PKG_CONFIG_PATH environment variables when running your GO code.

Let say the absolute path to your current dir is /path/to, here are their respective values:

  • CGO_CFLAGS: -I/path/to/vendor_c/include
  • CGO_LDFLAGS: -L/path/to/vendor_c/lib
  • PKG_CONFIG_PATH: /path/to/vendor_c/lib/pkgconfig

Features and roadmap

  • copy (remux)
  • mjpeg (thumbnails)
  • basic encode (h264 + aac)
  • stats
  • web ui
  • proper tests
  • packaging (dash + hls + smooth)
  • add plugin in snickers
  • many others :D

Contribute

Contributions are more than welcome! Simply fork this project, make changes in a specific branch such as patch-1 for instance and submit a PR.

Documentation

Index

Constants

View Source
const (
	StatusPaused  = "paused"
	StatusRunning = "running"
	StatusStopped = "stopped"
)

Statuses

View Source
const (
	StatNameHostUsage = "astiencoder.host.usage"
)

Variables

View Source
var (
	EventNameError             = "astiencoder.error"
	EventNameNodeClosed        = "astiencoder.node.closed"
	EventNameNodeContinued     = "astiencoder.node.continued"
	EventNameNodePaused        = "astiencoder.node.paused"
	EventNameNodeStarted       = "astiencoder.node.started"
	EventNameNodeStopped       = "astiencoder.node.stopped"
	EventNameStats             = "astiencoder.stats"
	EventNameWorkflowClosed    = "astiencoder.workflow.closed"
	EventNameWorkflowContinued = "astiencoder.workflow.continued"
	EventNameWorkflowPaused    = "astiencoder.workflow.paused"
	EventNameWorkflowStarted   = "astiencoder.workflow.started"
	EventNameWorkflowStopped   = "astiencoder.workflow.stopped"
	EventTypeClosed            = "closed"
	EventTypeContinued         = "continued"
	EventTypePaused            = "paused"
	EventTypeStarted           = "started"
	EventTypeStopped           = "stopped"
)

Default event names

Functions

func ConnectNodes

func ConnectNodes(parent, child Node)

ConnectNodes connects 2 nodes

func DisconnectNodes

func DisconnectNodes(parent, child Node)

DisconnectNodes disconnects 2 nodes

func EventTypeToNodeEventName added in v0.12.0

func EventTypeToNodeEventName(eventType string) string

EventTypeToNodeEventName is the node EventTypeTransformer

func EventTypeToWorkflowEventName added in v0.12.0

func EventTypeToWorkflowEventName(eventType string) string

EventTypeToWorkflowEventName is the workflow EventTypeTransformer

func LoggerEventHandlerAdapter

func LoggerEventHandlerAdapter(i astikit.StdLogger, h *EventHandler)

LoggerEventHandlerAdapter adapts the event handler so that it logs the events properly

Types

type BaseNode

type BaseNode struct {
	// contains filtered or unexported fields
}

BaseNode represents a base node

func NewBaseNode

func NewBaseNode(o NodeOptions, c *astikit.Closer, eh *EventHandler, s *Stater, target interface{}, et EventTypeTransformer) (n *BaseNode)

NewBaseNode creates a new base node

func (*BaseNode) AddChild

func (n *BaseNode) AddChild(i Node)

AddChild implements the NodeParent interface

func (*BaseNode) AddClose added in v0.23.0

func (n *BaseNode) AddClose(fn astikit.CloseFunc)

func (*BaseNode) AddCloseWithError added in v0.23.0

func (n *BaseNode) AddCloseWithError(fn astikit.CloseFuncWithError)

func (*BaseNode) AddParent

func (n *BaseNode) AddParent(i Node)

AddParent implements the NodeChild interface

func (*BaseNode) AddStats added in v0.12.0

func (n *BaseNode) AddStats(ss ...astikit.StatOptions)

AddStats adds stats

func (*BaseNode) ChildIsStarted

func (n *BaseNode) ChildIsStarted(m NodeMetadata)

ChildIsStarted implements the NodeParent interface

func (*BaseNode) ChildIsStopped

func (n *BaseNode) ChildIsStopped(m NodeMetadata)

ChildIsStopped implements the NodeParent interface

func (*BaseNode) Children

func (n *BaseNode) Children() (ns []Node)

Children implements the NodeParent interface

func (*BaseNode) Close added in v0.19.0

func (n *BaseNode) Close() error

func (*BaseNode) Context

func (n *BaseNode) Context() context.Context

Context returns the node context

func (*BaseNode) Continue

func (n *BaseNode) Continue()

Continue implements the Starter interface

func (*BaseNode) DelChild

func (n *BaseNode) DelChild(i Node)

DelChild implements the NodeParent interface

func (*BaseNode) DelParent

func (n *BaseNode) DelParent(i Node)

DelParent implements the NodeChild interface

func (*BaseNode) DoWhenUnclosed added in v0.19.0

func (n *BaseNode) DoWhenUnclosed(fn func())

func (*BaseNode) HandlePause

func (n *BaseNode) HandlePause()

HandlePause handles the pause

func (*BaseNode) IsClosed added in v0.19.0

func (n *BaseNode) IsClosed() bool

func (*BaseNode) Metadata

func (n *BaseNode) Metadata() NodeMetadata

Metadata implements the Node interface

func (*BaseNode) ParentIsStarted

func (n *BaseNode) ParentIsStarted(m NodeMetadata)

ParentIsStarted implements the NodeChild interface

func (*BaseNode) ParentIsStopped

func (n *BaseNode) ParentIsStopped(m NodeMetadata)

ParentIsStopped implements the NodeChild interface

func (*BaseNode) Parents

func (n *BaseNode) Parents() (ns []Node)

Parents implements the NodeChild interface

func (*BaseNode) Pause

func (n *BaseNode) Pause()

Pause implements the Starter interface

func (*BaseNode) Start

func (n *BaseNode) Start(ctx context.Context, tc CreateTaskFunc, execFunc BaseNodeExecFunc)

Start starts the node

func (*BaseNode) Status

func (n *BaseNode) Status() string

Status implements the Starter interface

func (*BaseNode) Stop

func (n *BaseNode) Stop()

Stop stops the node

type BaseNodeExecFunc

type BaseNodeExecFunc func(t *astikit.Task)

BaseNodeExecFunc represents a node exec func

type BaseNodeStartFunc

type BaseNodeStartFunc func()

BaseNodeStartFunc represents a node start func

type Closer added in v0.19.0

type Closer interface {
	AddClose(astikit.CloseFunc)
	AddCloseWithError(astikit.CloseFuncWithError)
	Close() error
	DoWhenUnclosed(func())
	IsClosed() bool
}

type CreateTaskFunc

type CreateTaskFunc func() *astikit.Task

CreateTaskFunc is a method that can create a task

type Event

type Event struct {
	Name    string
	Payload interface{}
	Target  interface{}
}

Event is an event coming out of the encoder

func EventError

func EventError(target interface{}, err error) Event

EventError returns an error event

type EventCallback

type EventCallback func(e Event) (deleteListener bool)

EventCallback represents an event callback

type EventHandler

type EventHandler struct {
	// contains filtered or unexported fields
}

EventHandler represents an event handler

func NewEventHandler

func NewEventHandler() *EventHandler

NewEventHandler creates a new event handler

func (*EventHandler) Add

func (h *EventHandler) Add(target interface{}, eventName string, c EventCallback)

Add adds a new callback for a specific target and event name

func (*EventHandler) AddForAll

func (h *EventHandler) AddForAll(c EventCallback)

AddForAll adds a new callback for all events

func (*EventHandler) AddForEventName

func (h *EventHandler) AddForEventName(eventName string, c EventCallback)

AddForEventName adds a new callback for a specific event name

func (*EventHandler) AddForTarget

func (h *EventHandler) AddForTarget(target interface{}, c EventCallback)

AddForTarget adds a new callback for a specific target

func (*EventHandler) Emit

func (h *EventHandler) Emit(e Event)

Emit emits an event

type EventStat

type EventStat struct {
	Description string
	Label       string
	Name        string
	Target      interface{}
	Unit        string
	Value       interface{}
}

EventStat represents a stat event

type EventTypeTransformer added in v0.12.0

type EventTypeTransformer func(eventType string) string

EventTypeTransformer represents a function capable of transforming an event type to an event name

type Node

Node represents a node

type NodeChild

type NodeChild interface {
	NodeChildMapper
	ParentIsStarted(m NodeMetadata)
	ParentIsStopped(m NodeMetadata)
}

NodeChild represents an object with parent nodes

type NodeChildMapper

type NodeChildMapper interface {
	AddParent(n Node)
	DelParent(n Node)
	Parents() []Node
}

NodeChildMapper represents an object that can play with its parents map

type NodeDescriptor

type NodeDescriptor interface {
	Metadata() NodeMetadata
}

NodeDescriptor represents an object that can describe a node

type NodeMetadata

type NodeMetadata struct {
	Description string
	Label       string
	Name        string
	Tags        []string
}

NodeMetadata represents node metadata

func (NodeMetadata) Extend

func (m NodeMetadata) Extend(name, label, description string, tags ...string) NodeMetadata

Extend extends the node metadata

type NodeOptions

type NodeOptions struct {
	Metadata       NodeMetadata
	NoIndirectStop bool
}

NodeOptions represents node options

type NodeParent

type NodeParent interface {
	NodeParentMapper
	ChildIsStarted(m NodeMetadata)
	ChildIsStopped(m NodeMetadata)
}

NodeParent represents an object with child nodes

type NodeParentMapper

type NodeParentMapper interface {
	AddChild(n Node)
	Children() []Node
	DelChild(n Node)
}

NodeParentMapper represents an object that can play with its children map

type Server added in v0.9.0

type Server struct {
	// contains filtered or unexported fields
}

func NewServer added in v0.9.0

func NewServer(o ServerOptions) *Server

func (*Server) EventHandlerAdapter added in v0.9.0

func (s *Server) EventHandlerAdapter(eh *EventHandler)

func (*Server) Handler added in v0.9.0

func (s *Server) Handler() http.Handler

func (*Server) SetWorkflow added in v0.9.0

func (s *Server) SetWorkflow(w *Workflow)

type ServerNode added in v0.9.0

type ServerNode struct {
	Children    []string `json:"children"`
	Closed      bool     `json:"closed"`
	Description string   `json:"description"`
	Label       string   `json:"label"`
	Name        string   `json:"name"`
	Parents     []string `json:"parents"`
	Status      string   `json:"status"`
	Tags        []string `json:"tags"`
}

type ServerOptions added in v0.9.0

type ServerOptions struct {
	Logger astikit.StdLogger
}

type ServerStat added in v0.9.0

type ServerStat struct {
	Description string      `json:"description"`
	Label       string      `json:"label"`
	Name        string      `json:"name"`
	Target      string      `json:"target"`
	Unit        string      `json:"unit"`
	Value       interface{} `json:"value"`
}

type ServerWelcome added in v0.9.0

type ServerWelcome struct {
	Workflow *ServerWorkflow `json:"workflow,omitempty"`
}

type ServerWorkflow added in v0.9.0

type ServerWorkflow struct {
	Name   string       `json:"name"`
	Nodes  []ServerNode `json:"nodes"`
	Status string       `json:"status"`
}

type Starter

type Starter interface {
	Continue()
	Pause()
	Start(ctx context.Context, t CreateTaskFunc)
	Status() string
	Stop()
}

Starter represents an object that can start/pause/continue/stop

type Stater

type Stater struct {
	// contains filtered or unexported fields
}

Stater represents an object that can compute and handle stats

func NewStater added in v0.12.0

func NewStater(period time.Duration, eh *EventHandler) (s *Stater)

NewStater creates a new stater

func (*Stater) AddStats added in v0.12.0

func (s *Stater) AddStats(target interface{}, os ...astikit.StatOptions)

AddStats adds stats

func (*Stater) DelStats added in v0.12.0

func (s *Stater) DelStats(target interface{}, os ...astikit.StatOptions)

DelStats deletes stats

func (*Stater) Start added in v0.12.0

func (s *Stater) Start(ctx context.Context)

Start starts the stater

func (*Stater) Stop added in v0.12.0

func (s *Stater) Stop()

Stop stops the stater

type Workflow

type Workflow struct {
	// contains filtered or unexported fields
}

Workflow represents a workflow

func NewWorkflow

func NewWorkflow(ctx context.Context, name string, eh *EventHandler, tf CreateTaskFunc, c *astikit.Closer, s *Stater) (w *Workflow)

NewWorkflow creates a new workflow

func (*Workflow) AddChild

func (w *Workflow) AddChild(n Node)

AddChild adds a child to the workflow

func (*Workflow) Children

func (w *Workflow) Children() []Node

Children returns the workflow children

func (*Workflow) Continue

func (w *Workflow) Continue()

Continue continues the workflow

func (*Workflow) DelChild

func (w *Workflow) DelChild(n Node)

DelChild deletes a child from the workflow

func (*Workflow) Name

func (w *Workflow) Name() string

Name returns the workflow name

func (*Workflow) NewRecording added in v0.9.0

func (w *Workflow) NewRecording(o WorkflowRecordingOptions) (r *WorkflowRecording)

func (*Workflow) Pause

func (w *Workflow) Pause()

Pause pauses the workflow

func (*Workflow) Start

func (w *Workflow) Start()

Start starts the workflow

func (*Workflow) StartNodes

func (w *Workflow) StartNodes(ns ...Node)

StartNodes starts nodes

func (*Workflow) StartNodesInSubTask

func (w *Workflow) StartNodesInSubTask(ns ...Node) (t *astikit.Task)

StartNodesInSubTask starts nodes in a new sub task

func (*Workflow) StartWithOptions

func (w *Workflow) StartWithOptions(o WorkflowStartOptions)

StartWithOptions starts the workflow with options

func (*Workflow) Status

func (w *Workflow) Status() string

Status returns the workflow status

func (*Workflow) Stop

func (w *Workflow) Stop()

Stop stops the workflow

type WorkflowRecording added in v0.9.0

type WorkflowRecording struct {
	// contains filtered or unexported fields
}

func (*WorkflowRecording) Start added in v0.9.0

func (r *WorkflowRecording) Start(ctx context.Context) (err error)

func (*WorkflowRecording) Stop added in v0.9.0

func (r *WorkflowRecording) Stop()

type WorkflowRecordingOptions added in v0.9.0

type WorkflowRecordingOptions struct {
	Dst    string
	Logger astikit.StdLogger
}

type WorkflowStartGroup

type WorkflowStartGroup struct {
	Callback func(t *astikit.Task)
	Nodes    []Node
}

WorkflowStartGroup represents a workflow start group

type WorkflowStartOptions

type WorkflowStartOptions struct {
	Groups []WorkflowStartGroup
}

WorkflowStartOptions represents workflow start options

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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