【问题标题】:Go / Cgo - How to access a field of a Cstruct?Go / Cgo - 如何访问 Cstruct 的字段?
【发布时间】:2021-10-17 19:25:32
【问题描述】:

我在 Go 中开发了一个应用程序,用于将音频文件从一种格式转码为另一种格式:

我使用使用 Cgo 的 goav 库来绑定 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

我尝试使用以下方法访问原始AVOutputFormat 的字段audio_codec

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)

正如我在 Cgo 文档中所读到的: 在 Go 文件中,作为 Go 中关键字的 C 结构字段名称可以通过以下划线作为前缀来访问:如果 x 指向具有名为“type”的字段的 C 结构,则 x._type 访问该字段。 Go 结构中无法表达的 C 结构字段,例如位字段或未对齐的数据,在 Go 结构中被省略,替换为适当的填充以到达下一个字段或结构的末尾。

但我不知道我做错了什么。

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

【问题讨论】:

  • 您是如何在代码中导入 avformat 的?
  • import "github.com/giorgisio/goav/avformat" 我的帖子中有链接

标签: go ffmpeg cgo


【解决方案1】:

您在这里遇到了一些 GO/CGO 的特质:

type OutputFormat C.struct_AVOutputFormattype 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 标头以获取 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 包配置和 &lt;libavformat/avformat.h&gt; 导入是否正确,但这适用于我站起来尝试的简单 C 库。

【讨论】:

    猜你喜欢
    • 2015-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-28
    • 1970-01-01
    • 2023-02-24
    相关资源
    最近更新 更多