【问题标题】:Golang and ffmpeg realtime streaming input/outputGolang 和 ffmpeg 实时流输入/输出
【发布时间】:2017-09-21 22:43:42
【问题描述】:

我是 Go 新手!

我正在做一个简单的测试,从 ffmpeg 读取输出并写入文件。

我知道我可以用不同的方式来做,只需转换,但这是一个项目的开始,我想稍后操作读取的字节,更改它们,然后将它们发送到输出。输入将是 UDP,输出也将是 UDP,也就是说,我将获得 ffmpeg 输出好吧。

通过这个简单的测试,文件的结果不能在 VLC 中运行,我相信我在输出文件中正确写入了字节,但输出文件总是比输入文件少 1MB。

我想要一些帮助来阐明什么是编写我正在做的这个测试的最佳方式,基于我可以离开这个地方。我不知道是不是完全错了,但我的印象是。

输入文件是4K,h264的视频,我相信输出应该是一样的,因为在这个简单的测试中,我只是在读取文件中写入的cmd中的内容。

按照代码进行分析:

package main

import (
    "os/exec"
    "os"
)

func verificaErro(e error) {
    if e != nil {
        panic(e)
    }
}

func main() {
    dir, _ := os.Getwd()

    cmdName := "ffmpeg"
    args := []string{
        "-hide_banner",
        "-re",
        "-i",
        dir + "\\teste-4k.mp4",
        "-preset",
        "superfast",
        "-c:v",
        "h264",
        "-crf",
        "0",
        "-c",
        "copy",
        "-f", "rawvideo", "-",
    }
    cmd := exec.Command(cmdName, args...)

    stdout, err := cmd.StdoutPipe()
    verificaErro(err)
    err2 := cmd.Start()
    verificaErro(err2)

    fileOutput := dir + "/out.raw"
    var _, err3 = os.Stat(fileOutput)

    if os.IsNotExist(err3) {
        var file, err = os.Create(fileOutput)
        verificaErro(err)
        defer file.Close()
    }

    f, err4 := os.OpenFile(dir+"/out.raw", os.O_RDWR|os.O_APPEND, 0666)

    verificaErro(err4)

    bytes := make([]byte, 1024)
    for {
        _, err5 := stdout.Read(bytes)
        if err5 != nil {
            continue
        }
        if len(bytes) > 0 {
            _, err6 := f.Write(bytes)
            verificaErro(err6)
        } else {
            break
        }
    }

    f.Close()
}

【问题讨论】:

    标签: go ffmpeg udp video-streaming


    【解决方案1】:

    您必须检查stdout.Read 的返回值。请注意,读取的字节数(nr)可能小于缓冲区大小,因此您需要对缓冲区进行重新切片以获得有效内容。修改阅读循环如下:

    chunk := make([]byte, 40*1024)
    for {
        nr, err5 := stdout.Read(chunk)
        fmt.Printf("Read %d bytes\n", nr)
    
        //do something with the data
        //e.g. write to file
        if nr > 0 {
            validData := chunk[:nr]
            nw, err6 := f.Write(validData)
            fmt.Printf("Write %d bytes\n", nw)
            verificaErro(err6)
        }
    
        if err5 != nil {
            //Reach end of file (stream), exit from loop
            if err5 == io.EOF {
                break
            }
            fmt.Printf("Error = %v\n", err5)
            continue
        }
    }
    
    if err := cmd.Wait(); err != nil {
        fmt.Printf("Wait command error: %v\n", err)
    }
    

    另一个解决方案是利用io.Copy 将整个输出复制到 golang 缓冲区中。代码 sn-p 将如下所示:

    var buf bytes.Buffer
    
    n, err := io.Copy(&buf, stdout)
    verificaErro(err)
    fmt.Printf("Copied %d bytes\n", n)
    
    err = cmd.Wait()
    fmt.Printf("Wait error %v\n", err)
    
    //do something with the data
    data := buf.Bytes()
    f, err4 := os.OpenFile(dir+"/out.raw", os.O_RDWR|os.O_APPEND, 0666)
    verificaErro(err4)
    defer f.Close()
    nw, err := f.Write(data)
    f.Sync()
    fmt.Printf("Write size %d bytes\n", nw)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-13
      • 2019-01-25
      • 1970-01-01
      • 2013-10-01
      • 2021-10-20
      • 2018-06-03
      • 2016-01-10
      • 2015-10-05
      相关资源
      最近更新 更多