Go/Cgo - 如何访问 Cstruct 的字段?

标签 go ffmpeg cgo

我在 Go 中开发了一个应用程序,用于将音频文件从一种格式转码为另一种格式:
我使用使用 Cgo 的 goav 库来绑定(bind) FFmpeg C-libs:
https://github.com/giorgisio/goav/

goav 图书馆; package avformat有一个 typedef 可以转换原始的 FFmpeg lib C-Struct AVOutputFormat:

type ( 
   OutputFormat               C.struct_AVOutputFormat
)
在我的代码中,我有一个名为 outputF 的变量OutputFormat 类型的那是一个 C.struct_AVOutputFormat .C真实 AVOutputFormat结构有字段:
name, long_name, mime_type, extensions, audio_codec, video_codec, subtitle_codec,..
以及更多领域。
见:https://ffmpeg.org/doxygen/2.6/structAVOutputFormat.html

我通过 fmt.Println(outputF) 验证了情况并达到:
{0x7ffff7f23383 0x7ffff7f23907 0x7ffff7f13c33 0x7ffff7f23383 86017 61 0 128 <nil> 0x7ffff7f8cfa0 <nil> 3344 0x7ffff7e3ec10 0x7ffff7e3f410 0x7ffff7e3ecc0 <nil> 0x7ffff7e3dfc0 <nil> <nil> <nil> <nil> <nil> <nil> 0 0x7ffff7e3e070 0x7ffff7e3e020 <nil>}
音频编解码器字段位于位置 5并包含 86017我使用包 reflect 验证了字段名称:
val := reflect.Indirect(reflect.ValueOf(outputF))
fmt.Println(val)
fmt.Println("Fieldname: ", val.Type().Field(4).Name)

Output:
Fieldname:  audio_codec

我尝试访问该字段 audio_codec原文AVOutputFormat使用:
fmt.Println(outputF.audio_codec)
ERROR: outputF.audio_codec undefined (cannot refer to unexported field or method audio_codec)


fmt.Println(outputF._audio_codec)
ERROR: outputF._audio_codec undefined (type *avformat.OutputFormat has no field or method _audio_codec)

As i read in the Cgo documentation: Within the Go file, C's struct field names that are keywords in Go can be accessed by prefixing them with an underscore: if x points at a C struct with a field named "type", x._type accesses the field. C struct fields that cannot be expressed in Go, such as bit fields or misaligned data, are omitted in the Go struct, replaced by appropriate padding to reach the next field or the end of the struct.


但我不知道我做错了什么。
编辑:
可以肯定不需要下划线,因为 audio_codec 不是 Go 中的关键字。这我现在明白了。但仍然存在为什么我无法访问 CStruct 字段“audio_codec”的问题。

最佳答案

您在这里遇到的 GO/CGO 有一些特质:type OutputFormat C.struct_AVOutputFormat去吧type declaration ,而不是别名。将其视为一个瘦包装器而不是别名可能会有所帮助。因此OutputFormat != C.struct_AVOutputFormat并且 C.struct_AVOutputFormat 的字段没有被导出,这就是你得到 ERROR: outputF.audio_codec undefined (cannot refer to unexported field or method audio_codec) 的原因
如果该字段被称为 Audio_codec,它将符合 go 对 exported identifier 的定义。我们可以访问它,但它不是。
有一种方法可以解决这个问题,但我建议在继续之前三思而后行,因为它使用不安全的指针,并且存在您的程序可能在运行时失去可移植性和/或稳定性的风险。 This is a good intro to unsafe pointers如果您想了解更多信息。
现在,如果您确实确定要这样做,解决方案是将指针转换为 OutputFormat转换为不安全的指针,然后将其转换为指向 C.struct_AVOutputFormat 的指针.请注意,这需要您加载 FFMPEG header 以获取 C.struct_AVOutputFormat 的定义。

//#cgo pkg-config: libavformat
//#include <libavformat/avformat.h>
import "C"
import (
    "fmt"
    "unsafe"
    "github.com/giorgisio/goav/avformat"
)

func getOutput() *avformat.OutputFormat {
  // calls out to avformat and gets an OutputFormat back
}

func main() {
    outputF := getOutput()
    coutput := *(*C.struct_AVOutputFormat)(unsafe.Pointer(outputF))

    fmt.Println(coutput.audio_codec) // This should now work
}
警告:我没有测试过 cgo 包配置和 <libavformat/avformat.h>导入是正确的,但这适用于我站起来尝试的一个简单的 C 库。

关于Go/Cgo - 如何访问 Cstruct 的字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68791044/

相关文章:

go - 为什么CGO无法在C中直接调用函数指针?

cgo 如何设置 C union 值

c++ - 是否可以将复杂的 Go 结构导出/包装到 C?

Go atomic store 后跟 atomic load 在整个例程中表现不正常

utf-8 - 在 Go 中解码 ISO-8859-1 XML 输入

javascript - HTML 5 如何记录过滤的 Canvas

video - 如何将文本流(字幕)添加到 .mp4 或 .m4v

concurrency - 计算/显示事件 goroutine 的数量

debugging - Go语言中常见的陷阱有哪些?

linux - youtube-dl 有时会挂起并显示 "[ffmpeg] Correcting container"