dongwo1914 2017-04-25 04:49
浏览 677
已采纳

Golang和ffmpeg实时流输入/输出

I'm new to Go!

I'm doing a simple test that is reading the output from ffmpeg and writing to a file.

I know I can do it in a different way, simply convert, but this is the beginning of a project where I want to later manipulate the bytes read, changing them and then sending them to the output. And the input will be UDP and output will be UDP too, that is, I will get the ffmpeg output I will treat the bytes as I wish to do and then I will throw these bytes as input into another ffmpeg process which output is UDP as well.

With this simple test the result of the file does not run in VLC, I believe I'm writing the bytes in the output file correctly, but the output file always has 1MB less than the input file.

I would like some help to elucidate what would be the best way to write this test that I am doing, based on that I can get out of the place. I do not know if it's exactly wrong, but I have the impression that it is.

The input file is a video in 4K, h264, I believe the output should be the same, because in this simple test I am simply reading what goes out in the cmd writing in the file.

Follow the code for analysis:

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()
}
  • 写回答

1条回答 默认 最新

  • douyou7797 2017-04-25 05:52
    关注

    You must check return values of stdout.Read. Please note that the number of bytes read (nr) may be smaller than the buffer size, so you need to re-slice the buffer to get a valid content. Modify reading loop as follows:

    chunk := make([]byte, 40*1024)
    for {
        nr, err5 := stdout.Read(chunk)
        fmt.Printf("Read %d bytes
    ", 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
    ", nw)
            verificaErro(err6)
        }
    
        if err5 != nil {
            //Reach end of file (stream), exit from loop
            if err5 == io.EOF {
                break
            }
            fmt.Printf("Error = %v
    ", err5)
            continue
        }
    }
    
    if err := cmd.Wait(); err != nil {
        fmt.Printf("Wait command error: %v
    ", err)
    }
    

    Another solution is utilizing io.Copy to copy the whole output into golang buffer. The code snippet will look like:

    var buf bytes.Buffer
    
    n, err := io.Copy(&buf, stdout)
    verificaErro(err)
    fmt.Printf("Copied %d bytes
    ", n)
    
    err = cmd.Wait()
    fmt.Printf("Wait error %v
    ", 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
    ", nw)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 MATLAB动图问题
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名