如何从 Golang 访问 C 指针数组

2024-04-03

我正在使用 FFmpeg 为 Windows 平台编写一个应用程序,它是 golang 包装器 goav,但我无法理解如何使用 C 指针来访问数组。

我试图获取存储在 AVFormatContext 类中的流以在 go 中使用,并最终将帧添加到 OpenGL 中的纹理中,以制作具有炫酷过渡的视频播放器。

我认为了解如何转换和访问 C 数据将使编码变得更加容易。

我已经删除了 C 代码、包装器和我的代码的所有相关部分,如下所示:

C 代码 - libavformat/avformat.h

typedef struct AVFormatContext { 
    unsigned int nb_streams; 
    AVStream **streams; 
}

Golang goav 包装器

package avutil

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

type Context C.struct_AVFormatContext; 

func (ctxt *Context) StreamsGet(i uintptr) *Stream {
    streams := (**Stream)(unsafe.Pointer(ctxt.streams));
    // I think this is where it's going wrong, I'm brand new to this stuff 
    return (*Stream)(unsafe.Pointer(uintptr(unsafe.Pointer(streams)) + i*unsafe.Sizeof(*streams)));
}

我的 Golang 代码

package main

import "github.com/giorgisio/goav/avformat"

func main() {
    ctx := &avformat.Context{} // the actual function to initiate this does an mallocz for the streams

    stream := ctx.StreamsGet(0)

    //do stuff with stream...
}

在C中,看起来我只需要做streams[i],但这在go中不起作用,所以我使用我的问题中的技术向包装器添加了一个函数here https://stackoverflow.com/questions/49931051/cgo-how-do-you-use-pointers-in-golang-to-access-data-from-an-array-in-c。 但是我没有得到数据;看起来我得到了一个指向内存中随机位置的指针。那么,如何从 golang 访问这些元素呢?任何资源也会有帮助;我将在这方面投入相当多的时间。


正如您所注意到的,问题出在以下代码中:

func (ctxt *Context) StreamsGet(i uintptr) *Stream {
    streams := (**Stream)(unsafe.Pointer(ctxt.streams));
    // I think this is where it's going wrong, I'm brand new to this stuff 
    return (*Stream)(unsafe.Pointer(uintptr(unsafe.Pointer(streams)) + i*unsafe.Sizeof(*streams)));
}

代码中,变量streams is 双指针,因此添加偏移量的结果streams也是一个双指针(即类型是**Stream)。但是,在您的片段中,它被转换为*Stream这是不正确的。正确的代码是:

func (ctxt *Context) StreamsGet(i uintptr) *Stream {
    streams := (**Stream)(unsafe.Pointer(ctxt.streams))
    // Add offset i then cast it to **Stream
    ptrPtr := (**Stream)(unsafe.Pointer(uintptr(unsafe.Pointer(streams)) + i*unsafe.Sizeof(*streams)))
    return *ptrPtr
}

附加说明:
如果你想避免指针算术Go一边,你可以定义一个helperC端访问指针元素(即流)的函数如下:

/*
void * ptr_at(void **ptr, int idx) {
    return ptr[idx];
}

struct AVStream * stream_at(struct AVFormatContext *c, int idx) {
    if (i >= 0 && i < c->nb_streams)
        return c->streams[idx];
    return NULL;
}
*/
import "C"
import (
    "unsafe"
)

type Context C.struct_AVFormatContext
type Stream C.struct_AVStream

func (ctx *Context) StreamAt(i int) *Stream {
    p := (*unsafe.Pointer)(unsafe.Pointer(ctx.streams))
    ret := C.ptr_at(p, C.int(i))

    return (*Stream)(ret)
}

func (ctx *Context) StreamAt2(i int) *Stream {
    ret := C.stream_at((*C.struct_AVFormatContext)(ctx), C.int(i))

    return (*Stream)(ret)
}

您可以选择ptr_at接受通用(任何)双指针作为其参数的函数,或更具体stream_at只接受指向的函数AVFormatContext作为其论点。前一种方法可用于从任何双指针访问元素,例如:AVProgram **, AVChapter **等等。如果我们需要实现边界检查等额外处理,则后一种方法是更好的选择。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从 Golang 访问 C 指针数组 的相关文章

  • SSH 主机密钥指纹与模式 C# WinSCP 不匹配

    我尝试通过 WinSCP 使用 C 连接到 FTPS 服务器 但收到此错误 SSH 主机密钥指纹 与模式不匹配 经过大量研究 我相信这与密钥的长度有关 当使用 服务器和协议信息 下的界面进行连接时 我从 WinSCP 获得的密钥是xx xx
  • 如何在我的应用程序中使用 Windows Key

    Like Windows Key E Opens a new Explorer Window And Windows Key R Displays the Run command 如何在应用程序的 KeyDown 事件中使用 Windows
  • 跨多个控件共享事件处理程序

    在我用 C 编写的 Windows 窗体应用程序中 我有一堆按钮 当用户的鼠标悬停在按钮上时 我希望按钮的边框发生变化 目前我有以下多个实例 每个按钮一个副本 private void btnStopServer MouseEnter ob
  • C# 中可空类型是什么?

    当我们必须使用nullable输入 C net 任何人都可以举例说明 可空类型 何时使用可空类型 https web archive org web http broadcast oreilly com 2010 11 understand
  • 使用 C# 在 WinRT 中获取可用磁盘空间

    DllImport kernel32 dll SetLastError true static extern bool GetDiskFreeSpaceEx string lpDirectoryName out ulong lpFreeBy
  • c 中的错误:声明隐藏了全局范围内的变量

    当我尝试编译以下代码时 我收到此错误消息 错误 声明隐藏了全局范围内的变量 无效迭代器 节点 根 我不明白我到底在哪里隐藏或隐藏了之前声明的全局变量 我怎样才能解决这个问题 typedef node typedef struct node
  • C# 用数组封送结构体

    假设我有一个类似于 public struct MyStruct public float a 我想用一些自定义数组大小实例化一个这样的结构 在本例中假设为 2 然后我将其封送到字节数组中 MyStruct s new MyStruct s
  • 当 Cortex-M3 出现硬故障时如何保留堆栈跟踪?

    使用以下设置 基于 Cortex M3 的 C gcc arm 交叉工具链 https launchpad net gcc arm embedded 使用 C 和 C FreeRtos 7 5 3 日食月神 Segger Jlink 与 J
  • 为什么模板不能位于外部“C”块内?

    这是一个后续问题一个答案 https stackoverflow com questions 4866433 is it possible to typedef a pointer to extern c function type wit
  • 线程、进程和 Application.Exit()

    我的应用程序由主消息循环 GUI 和线程 Task Factory 组成 在线程中我调用一些第三方应用程序var p new Process 但是当我调用Application Exit 在消息循环中 我可以看到在线程中启动的进程仍在内存中
  • .NET 选项将视频文件流式传输为网络摄像头图像

    我有兴趣开发一个应用程序 它允许我从 xml 构建视频列表 包含视频标题 持续时间等 并将该列表作为我的网络摄像头流播放 这意味着 如果我要访问 ustream tv 或在实时通讯软件上激活我的网络摄像头 我的视频播放列表将注册为我的活动网
  • 用 C 实现 Unix shell:检查文件是否可执行

    我正在努力用 C 语言实现 Unix shell 目前正在处理相对路径的问题 特别是在输入命令时 现在 我每次都必须输入可执行文件的完整路径 而我宁愿简单地输入 ls 或 cat 我已经设法获取 PATH 环境变量 我的想法是在 字符处拆分
  • C 中的位移位

    如果与有符号整数对应的位模式右移 则 1 vacant bit will be filled by the sign bit 2 vacant bit will be filled by 0 3 The outcome is impleme
  • EPPlus Excel 更改单元格颜色

    我正在尝试将给定单元格的颜色设置为另一个单元格的颜色 该单元格已在模板中着色 但worksheet Cells row col Style Fill BackgroundColor似乎没有get财产 是否可以做到这一点 或者我是否必须在互联
  • 在 ASP.NET 中将事件冒泡为父级

    我已经说过 ASP NET 中的层次结构 page user control 1 user control 2 control 3 我想要做的是 当控件 3 它可以是任何类型的控件 我一般都想这样做 让用户用它做一些触发回发的事情时 它会向
  • 更改显示的 DPI 缩放大小使 Qt 应用程序的字体大小渲染得更大

    我使用 Qt 创建了一些 GUI 应用程序 我的 GUI 应用程序包含按钮和单选按钮等控件 当我运行应用程序时 按钮内的按钮和字体看起来正常 当我将显示器的 DPI 缩放大小从 100 更改为 150 或 200 时 无论分辨率如何 控件的
  • C++ 成员函数中的“if (!this)”有多糟糕?

    如果我遇到旧代码if this return 在应用程序中 这种风险有多严重 它是一个危险的定时炸弹 需要立即在应用程序范围内进行搜索和销毁工作 还是更像是一种可以悄悄留在原处的代码气味 我不打算writing当然 执行此操作的代码 相反
  • 为什么 strtok 会导致分段错误?

    为什么下面的代码给出了Seg 最后一行有问题吗 char m ReadName printf nRead String s n m Writes OK char token token strtok m 如前所述 读取字符串打印没有问题 但
  • 将输入数据发送到node.js中的子进程

    我正在编写代码以在 Node js 环境中创建在线 C 编译器 使用spawn函数我创建了一个子进程 它将编译代码并执行它并将输出发送回用户 但我需要将输入发送到正在运行的 C 程序 我用了child stdin write data 用于
  • 将新行添加到表后如何更新 datagridview 的行列表

    我有一个 datagridview 在表单的加载事件上填充了表集合 我还有一个由用户填写的表单 并将新行添加到表 onclick 事件 我想在向该表添加新行后更新 datagridview表 我使用绑定到绑定数据源的 sqladapter

随机推荐