go - 如何在 Go 中将函数指针传递给 C 代码

标签 go cgo

我想编写一个用于处理视频的小型 go 应用程序,并决定使用这个库 goav这是 go 的 FFmpeg 绑定(bind)。但是,它不支持直接从内存中读取视频。作为解决方法,我决定直接调用 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

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

最佳答案

运行时错误实际上是在提示 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 根本不允许这样传递指针。

关于go - 如何在 Go 中将函数指针传递给 C 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56292071/

相关文章:

string - 是否可以将 Golang 字符串的内存 "safely"归零?

go - 将结构和结构数组从 Go 传递给 C 函数

go - 访问字符串的原始字节

select - 我可以在不等待 goroutine 返回的情况下强制终止它吗?

go - 在 Golang 中推回 vector 导致程序崩溃

ssl - Artifactory jfrog cli 无法进行身份验证

http - 如何使用 http 而不是 https 在 Heroku 上提供 Golang 应用程序?

android - 在 Mac for Android 上交叉编译 "Hello World"

go - 编码无法从 Go 访问的 C 对象

pointers - go-ini 的 mapTo 函数的正确使用方法是什么?