astiencoder

package module
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Mar 6, 2020 License: MIT Imports: 14 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 4.1.1.

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:

  • understand how the video encoding process work
  • integrate your video encoder in a GO ecosystem
  • visualize your encoding workflow and statuses/stats of nodes in real time
  • communicate with the encoder through an HTTP API + websocket to tweak behaviours in real time
  • use native GO subtitle libraries like astisub
  • 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 a Workflow Pool that can manage several Workflows.

At this point, Workflows are made of Nodes that can start/pause/continue/stop any kind of work.

The Workflow Pool can serve both an HTTP API and WebSocket events to interact with Workflows and Nodes.

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

Whatever mode you're in, you can open the Web UI in order to either interact with your workflows or see their stats.

By default it's accessible at http://127.0.0.1:4000 but you can change it using the encoder configuration.

screenshot-1

Pause/continue a workflow

On the left-hand side, you'll see the names of all your workflows. Click once the slider on the right of its name to pause the workflow:

screenshot-4

You can also start/pause/continue nodes individually by clicking on them:

screenshot-6

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 4.1.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
  • mosaic
  • audio resampling
  • 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

Variables

View Source
var (
	EventNameError             = "astiencoder.error"
	EventNameNodeContinued     = "astiencoder.node.continued"
	EventNameNodePaused        = "astiencoder.node.paused"
	EventNameNodeStarted       = "astiencoder.node.started"
	EventNameNodeStats         = "astiencoder.node.stats"
	EventNameNodeStopped       = "astiencoder.node.stopped"
	EventNameWorkflowContinued = "astiencoder.workflow.continued"
	EventNameWorkflowPaused    = "astiencoder.workflow.paused"
	EventNameWorkflowStarted   = "astiencoder.workflow.started"
	EventNameWorkflowStats     = "astiencoder.workflow.stats"
	EventNameWorkflowStopped   = "astiencoder.workflow.stopped"
	EventTypeContinued         = "continued"
	EventTypePaused            = "paused"
	EventTypeStarted           = "started"
	EventTypeStats             = "stats"
	EventTypeStopped           = "stopped"
)

Default event names

View Source
var (
	ErrWorkflowNotFound = errors.New("astiencoder: workflow.not.found")
)

Errors

Functions

func ConnectNodes

func ConnectNodes(parent, child Node)

ConnectNodes connects 2 nodes

func DisconnectNodes

func DisconnectNodes(parent, child Node)

DisconnectNodes disconnects 2 nodes

func LoggerEventHandlerAdapter

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

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

func WriteJSONError

func WriteJSONError(l astikit.SeverityLogger, rw http.ResponseWriter, code int, err error)

WriteJSONError writes a JSON error

Types

type BaseNode

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

BaseNode represents a base node

func NewBaseNode

func NewBaseNode(o NodeOptions, eg EventGenerator, eh *EventHandler) (n *BaseNode)

NewBaseNode creates a new base node

func (*BaseNode) AddChild

func (n *BaseNode) AddChild(i Node)

AddChild implements the NodeParent interface

func (*BaseNode) AddParent

func (n *BaseNode) AddParent(i Node)

AddParent implements the NodeChild interface

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) 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) HandlePause

func (n *BaseNode) HandlePause()

HandlePause handles the pause

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) Stater

func (n *BaseNode) Stater() *astikit.Stater

Stater returns the node stater

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 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 EventGenerator

type EventGenerator interface {
	Event(eventType string, payload interface{}) Event
}

EventGenerator represents an object capable of generating an event based on its type

type EventGeneratorNode

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

EventGeneratorNode represents a node event generator

func NewEventGeneratorNode

func NewEventGeneratorNode(n Node) *EventGeneratorNode

NewEventGeneratorNode creates a new node event generator

func (EventGeneratorNode) Event

func (g EventGeneratorNode) Event(eventType string, payload interface{}) Event

Event implements the EventGenerator interface

type EventGeneratorWorkflow

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

EventGeneratorWorkflow represents a workflow event generator

func NewEventGeneratorWorkflow

func NewEventGeneratorWorkflow(w *Workflow) *EventGeneratorWorkflow

NewEventGeneratorWorkflow creates a new workflow event generator

func (EventGeneratorWorkflow) Event

func (g EventGeneratorWorkflow) Event(eventType string, payload interface{}) Event

Event implements the EventGenerator interface

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
	Unit        string
	Value       interface{}
}

EventStat represents a stat event

type ExposedError

type ExposedError struct {
	Message string `json:"message"`
}

ExposedError represents an exposed error.

type ExposedReferences

type ExposedReferences struct {
	WsPingPeriod time.Duration `json:"ws_ping_period"`
}

ExposedReferences represents the exposed references.

type ExposedStat

type ExposedStat struct {
	Description string      `json:"description"`
	Label       string      `json:"label"`
	Unit        string      `json:"unit"`
	Value       interface{} `json:"value"`
}

ExposedStat represents an exposed stat

type ExposedStatMetadata

type ExposedStatMetadata struct {
	Description string `json:"description"`
	Label       string `json:"label"`
	Unit        string `json:"unit"`
}

ExposedStatMetadata represents exposed stat metadata

type ExposedStats

type ExposedStats struct {
	Name  string        `json:"name"`
	Stats []ExposedStat `json:"stats"`
}

ExposedStats represents exposed stats

type ExposedWorkflow

type ExposedWorkflow struct {
	ExposedWorkflowBase
	Edges []ExposedWorkflowEdge `json:"edges"`
	Nodes []ExposedWorkflowNode `json:"nodes"`
}

ExposedWorkflow represents an exposed workflow

type ExposedWorkflowBase

type ExposedWorkflowBase struct {
	Name   string `json:"name"`
	Status string `json:"status"`
}

ExposedWorkflowBase represents a base exposed encoder workflow

type ExposedWorkflowEdge

type ExposedWorkflowEdge struct {
	From string `json:"from"`
	To   string `json:"to"`
}

ExposedWorkflowEdge represents an exposed workflow edge

type ExposedWorkflowNode

type ExposedWorkflowNode struct {
	Description string                `json:"description"`
	Label       string                `json:"label"`
	Name        string                `json:"name"`
	Stats       []ExposedStatMetadata `json:"stats"`
	Status      string                `json:"status"`
}

ExposedWorkflowNode represents an exposed workflow node

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
}

NodeMetadata represents node metadata

func (NodeMetadata) Extend

func (m NodeMetadata) Extend(name, label, description 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 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 interface {
	Stater() *astikit.Stater
}

Stater represents an object that can return its stater

type Workflow

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

Workflow represents a workflow

func NewWorkflow

func NewWorkflow(ctx context.Context, name string, e *EventHandler, tf CreateTaskFunc, c *astikit.Closer) (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) 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 WorkflowPool

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

WorkflowPool represents a workflow pool

func NewWorkflowPool

func NewWorkflowPool() *WorkflowPool

NewWorkflowPool creates a new workflow pool

func (*WorkflowPool) AddWorkflow

func (wp *WorkflowPool) AddWorkflow(w *Workflow)

AddWorkflow adds a new workflow

func (*WorkflowPool) Serve

func (wp *WorkflowPool) Serve(eh *EventHandler, pathWeb string, l astikit.StdLogger, fn func(http.Handler)) (err error)

Serve spawns the workflow pool server

func (*WorkflowPool) Workflow

func (wp *WorkflowPool) Workflow(name string) (w *Workflow, err error)

Workflow retrieves a workflow from the pool

func (*WorkflowPool) Workflows

func (wp *WorkflowPool) Workflows() (ws []*Workflow)

Workflows returns all the workflows

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

Jump to

Keyboard shortcuts

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