如何在Go

时间:2019-05-24 11:48:34

标签: go cgo

我想编写一个处理视频的小型go应用程序,并决定使用该库goav,它是go的FFmpeg绑定。但是,它不支持直接从内存读取视频。作为解决方法,我决定直接调用C函数。

我要调用的函数的签名如下。

AVIOContext *avio_alloc_context(
                  unsigned char *buffer,
                  int buffer_size,
                  int write_flag,
                  void *opaque,
                  int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
                  int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
                  int64_t (*seek)(void *opaque, int64_t offset, int whence));

我为此编写的go代码-

package video

// #include<libavformat/avio.h>
import "C"
import (
  "bytes"
  "github.com/giorgisio/goav/avformat"
  "github.com/giorgisio/goav/avutil"
  "unsafe"
)

func DecodeStream(data *bytes.Buffer) {
  bufferSize := 8192
  formatContext := avformat.AvformatAllocContext()
  buffer := (*C.uchar)(avutil.AvMalloc(uintptr(bufferSize)))
  ioContext := C.avio_alloc_context(
    buffer,
    C.int(bufferSize),
    C.int(0),
    unsafe.Pointer(data),
    &[0]byte{},
    &[0]byte{},
    &[0]byte{}, 
  )                                       // <- error in this line
  formatContext.SetPb((*avformat.AvIOContext)(unsafe.Pointer(ioContext)))
  if formatContext.AvformatFindStreamInfo(nil) < 0 {
    panic("Couldn't find stream info")
  }
  println("DURATION: ", formatContext.Duration())
}

但是,我收到此错误runtime error: cgo argument has Go pointer to Go pointer

我也尝试将&[0]byte{}替换为nil。似乎无法摆脱!

1 个答案:

答案 0 :(得分:0)

运行时错误实际上是在抱怨unsafe.Pointer(data)参数。 bytes.Buffer类型具有内部(Go)指针,并且如果这些指针指向包含Go指针本身的Go对象,则cgo不允许将指针传递给C。

以下cgo文档中详细介绍了这些规则:https://golang.org/cmd/cgo/#hdr-Passing_pointers

简短的摘要是,在修改Go指针时,需要注意Go垃圾收集器。 Go编译器确保已编译的代码适当地通知垃圾回收器,但是C编译器不知道这样做。因此,为了防止出现GC问题,cgo根本不允许这样传递指针。