我想编写一个用于处理视频的小型 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/