ffmpeg-go

repository·master·Indexed 25 days ago

https://github.com/u2takey/ffmpeg-go

A Go wrapper for the FFmpeg multimedia framework that provides a fluent API for building complex command chains. It supports transcoding, filtering, stream manipulation, and resource limiting. The library utilizes a Directed Acyclic Graph (DAG) to manage command structures and supports features such as S3 uploads, progress monitoring via Unix sockets, and stream splitting.

Tokens
7.1K
Snippets
12
Records
47
Agent score
81%

What's inside ffmpeg-go

  1. Install ffmpeg-go

    master

    Install the ffmpeg-go package using Go modules:

    go get -u github.com/u2takey/ffmpeg-go

    Prerequisite: Install FFmpeg ffmpeg-go is a pure-Go wrapper and does not install the FFmpeg binary itself. You must install FFmpeg on your system and ensure it is available in your $PATH.

    You can verify the installation by running:

    ffmpeg

    If you see ffmpeg: command not found, you must install it via your OS package manager (e.g., brew install ffmpeg on macOS or sudo apt install ffmpeg on Ubuntu).

    go get -u github.com/u2takey/ffmpeg-go
  2. How nodes and streams form a processing pipeline

    master

    The library builds a Directed Acyclic Graph (DAG) of media processing.

    1. Nodes (*Node) represent operations (inputs, filters, or outputs).
    2. Streams (*Stream) represent the connections between nodes. A node's streamSpec defines which streams it expects as inputs.
    3. Selectors and Labels: When connecting nodes, you use Label and Selector to specify which exact track (e.g., video vs audio) is being passed from one node to another.

    To retrieve a specific stream from a node, use the Get(a string) method. The string format a can be a simple label (e.g., "v") or a label with a selector separated by a colon (e.g., "v:0").

  3. Define a command execution graph with Graph and GraphNode

    master

    The ffmpeg-go library uses a graph-based model to represent complex FFmpeg command chains.

    • Graph: The top-level structure representing the entire execution plan. It contains a list of Nodes and global GraphOptions.
    • GraphNode: Represents a single unit of work (like an input, a filter, or an output) within the graph. It defines which input streams it consumes, which output streams it produces, and the specific Args and KwArgs required for that step.
    • GraphOptions: Configuration for the execution of the graph, such as Timeout and OverWriteOutput.
  4. Understand the DagNode interface for FFmpeg command graphs

    master

    The DagNode interface represents a node within a Directed Acyclic Graph (DAG) used to manage FFmpeg command structures. Nodes are immutable and must be hashable to allow for graph traversal and comparison.

    Key characteristics of a DagNode:

    • Immutability: Once created, a node's hash and string representations must remain constant. To change a node, you must create a new one.
    • Connectivity: Nodes primarily track their incoming edges. The full graph structure is inferred by traversing from downstream nodes back to upstream nodes.
    • Edges: An edge connects an upstream_node to a downstream_node. Each side of the connection can have a unique Label (string or integer) and a Selector.
    • Equality: Two nodes are considered equivalent if they share the same Hash() value.
    type DagNode interface {
    	Hash() int
    	// Compare two nodes
    	Equal(other DagNode) bool
    	// Return a full string representation of the node.
    	String() string
    	// Return a partial/concise representation of the node
    	ShortRepr() string
    	// Provides information about all incoming edges that connect to this node.
    	IncomingEdgeMap() map[Label]NodeInfo
    }
  5. Set CPU limits for FFmpeg processes

    master

    You can control the resource usage of an FFmpeg process using .RunWithResource(cpuLimit, memLimit). This allows you to restrict the amount of CPU cores or memory the process can consume.

    e := ComplexFilterExample("./sample_data/in1.mp4", "./sample_data/overlay.png", "./sample_data/out2.mp4")
    err := e.RunWithResource(0.1, 0.5)
    if err != nil {
    	assert.Nil(t, err)
    }
  6. Extract a single frame as a JPEG

    master

    You can extract a specific frame from a video and pipe it to an io.Reader (like a buffer) by using the select filter to pick the frame number and setting the output format to image2 with vcodec as mjpeg.

    func ExampleReadFrameAsJpeg(inFileName string, frameNum int) io.Reader {
    	buf := bytes.NewBuffer(nil)
    	err := ffmpeg.Input(inFileName).
    		Filter("select", ffmpeg.Args{fmt.Sprintf("gte(n,%d)", frameNum)}).
    		Output("pipe:", ffmpeg.KwArgs{"vframes": 1, "format": "image2", "vcodec": "mjpeg"}).
    		WithOutput(buf, os.Stdout).
    		Run()
    	if err != nil {
    		panic(err)
    	}
    	return buf
    }
  7. Add a watermark to a video

    master

    To overlay an image onto a video, use the ffmpeg.Filter function. You can scale the overlay image first using .Filter("scale", ...) and then apply the overlay filter to the stream set. Use ffmpeg.KwArgs to enable the overlay at specific timestamps (e.g., enable: gte(t,1)).

    // show watermark with size 64:-1 in the top left corner after seconds 1
    overlay := ffmpeg.Input("./sample_data/overlay.png").Filter("scale", ffmpeg.Args{"64:-1"})
    err := ffmpeg.Filter(
        []*ffmpeg.Stream{
            ffmpeg.Input("./sample_data/in1.mp4"),
            overlay,
        }, "overlay", ffmpeg.Args{"10:10"}, ffmpeg.KwArgs{"enable": "gte(t,1)"}).
        Output("./sample_data/out1.mp4").OverWriteOutput().ErrorToStdOut().Run()
  8. Transcode video to a different codec

    master

    Use ffmpeg.Input and ffmpeg.Output combined with ffmpeg.KwArgs to specify codec changes. For example, to transcode an MP4 file to H.265 (libx265), pass the codec option in KwArgs.

    err := ffmpeg.Input("./sample_data/in1.mp4").
    		Output("./sample_data/out1.mp4", ffmpeg.KwArgs{"c:v": "libx265"}).
    		OverWriteOutput().ErrorToStdOut().Run()
  9. Cut video by timestamp

    master

    To extract a specific segment of a video, use the ss (start time) and t (duration) parameters within ffmpeg.KwArgs in both the Input and Output calls.

    err := ffmpeg.Input("./sample_data/in1.mp4", ffmpeg.KwArgs{"ss": 1}).
        Output("./sample_data/out1.mp4", ffmpeg.KwArgs{"t": 1}).OverWriteOutput().Run()
  10. Monitor FFmpeg progress

    master

    To track progress, use ffmpeg.Probe to get the total duration of the file. Then, use .GlobalArgs("-progress", "unix://...") to instruct FFmpeg to write progress data to a Unix socket.

    func ExampleShowProgress(inFileName, outFileName string) {
    	a, err := ffmpeg.Probe(inFileName)
    	if err != nil {
    		panic(err)
    	}
    	totalDuration := gjson.Get(a, "format.duration").Float()
    
    	err = ffmpeg.Input(inFileName).
    		Output(outFileName, ffmpeg.KwArgs{"c:v": "libx264", "preset": "veryslow"}).
    		GlobalArgs("-progress", "unix://"+TempSock(totalDuration)).
    		OverWriteOutput().
    		Run()
    	if err != nil {
    		panic(err)
    	}
    }
  11. Generate multiple outputs from one input

    master

    To create multiple different versions of a video (e.g., different resolutions or bitrates) from a single source, use .Split() on the input stream. This creates multiple identical streams that can be processed independently. Use ffmpeg.MergeOutputs to execute all output commands in a single run.

    // get multiple output with different size/bitrate
    input := ffmpeg.Input("./sample_data/in1.mp4").Split()
    out1 := input.Get("0").Filter("scale", ffmpeg.Args{"1920:-1"}).
    	Output("./sample_data/1920.mp4", ffmpeg.KwArgs{"b:v": "5000k"})
    out2 := input.Get("1").Filter("scale", ffmpeg.Args{"1280:-1"}).
    	Output("./sample_data/1280.mp4", ffmpeg.KwArgs{"b:v": "2800k"})
    
    err := ffmpeg.MergeOutputs(out1, out2).OverWriteOutput().ErrorToStdOut().Run()
  12. Draw a box on a video stream

    master

    The DrawBox method draws a colored rectangle on the video stream.

    • x, y, w, h: The rectangle dimensions and position.
    • color: The color string (e.g., "red").
    • thickness: The thickness of the border. If 0, it is omitted from the arguments.
    • kwargs: Additional FFmpeg drawbox parameters.

    Returns a *Stream.