gpt4 book ai didi

c - 如何使用指向 C 数据的指针写入 Golang 中的文件?

转载 作者:行者123 更新时间:2023-12-01 19:53:19 26 4
gpt4 key购买 nike

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

我正在尝试将 C 的 uint8 指针指向的帧数据写入 golang 中的 .ppm 文件。

完成此操作后,为了证明 FFmpeg 正在做我期望的事情,我想将帧设置为 OpenGl 中的纹理,以制作具有炫酷过渡的视频播放器;任何能有效地做到这一点的建议都会非常有帮助!我猜我需要编写一些着色器代码来将 ppm 绘制为纹理...

PPM file structure看起来很简单只是标题,然后是帧中从左上到右下每个像素的每个红色、绿色和蓝色值的一个字节数据

我开始理解如何在 C 和 Go 类型之间转换指针,但我如何访问数据并将其写入 Go 并获得与 C 相同的结果?在 C 中,我只需为数据设置指针偏移量并说明要写入的数据量:

for (y = 0; y < height; y++) {
fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
}

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

C 代码 - libavutil/frame.h

#include <stdint.h>

typedef struct AVFrame {
#define AV_NUM_DATA_POINTERS 8
uint8_t *data[AV_NUM_DATA_POINTERS];
int linesize[AV_NUM_DATA_POINTERS];
}

Golang goav 包装器

package avutil

/*
#cgo pkg-config: libavutil
#include <libavutil/frame.h>
#include <stdlib.h>
*/
import "C"
import (
"unsafe"
)

type Frame C.struct_AVFrame

func Data(f *Frame) *uint8 {
return (*uint8)(unsafe.Pointer((*C.uint8_t)(unsafe.Pointer(&f.data))))
}
func Linesize(f *Frame) int {
return int(*(*C.int)(unsafe.Pointer(&f.linesize)))
}

我的 Golang 代码

package main

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

func saveFrame(videoFrame *avutil.Frame, width int, height int, iFrame int) {
var szFilename string
var y int
var file *os.File
var err error

szFilename = ""

// Open file
szFilename = fmt.Sprintf("frame%d.ppm", iFrame)

if file, err = os.Create(szFilename); err != nil {
log.Println("Error Reading")
}

// Write header
fh := []byte(fmt.Sprintf("P6\n%d %d\n255\n", width, height))
file.Write(fh)
var b byte = 0
// Write pixel data
for y = 0; y < height; y++ {
d := avutil.Data(videoFrame) // d should be a pointer to the first byte of data
l := avutil.Linesize(videoFrame)

// I'm basically lost trying to figure out how to correctly write
// this to a file, the file is created, but when I open it in GIMP
// the image is mostly black with glitchy fuzz - so it's not being
// written properly; the header seems to be ok, it knows the height
// and width at least.

data := make([]byte, l*3)

ptr := unsafe.Pointer(d)
for i := 0; i < l; i++ {
datum := (*uint8)(unsafe.Pointer(uintptr(ptr) + (uintptr(i)+(uintptr(y)*uintptr(l)))*unsafe.Sizeof(*d)))
data = append(data, *datum)
//fmt.Println(*datum)
}

n, err := file.Write(data)
if err != nil {
log.Println("Error Writing:", szFilename, "-", n)
}
}

file.Close()
}

那么,我如何使用指向数据的指针写入文件,就像您在 C 中所做的那样,并获得相同的结果?

第一帧应该是黑色的,所以全是 0,但我遇到了毛刺,所以它一定是在访问一些随机数据

更新:我使用 C 函数保存的修复:

package avutil

/*
#cgo pkg-config: libavutil
#include <libavutil/frame.h>
#include <stdlib.h>
#include <stdio.h>

void SaveFrame(const char* location, AVFrame *pFrame, int width, int height) {
FILE *pFile;
int y;

// Open file
pFile=fopen(location, "wb");
if(pFile==NULL)
return;

// Write header
fprintf(pFile, "P6\n%d %d\n255\n", width, height);

// Write pixel data
for(y=0; y<height; y++)
fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);

// Close file
fclose(pFile);
}
uint8_t* GetData(AVFrame *pFrame) {
return pFrame->data[0];
}
*/
import "C"

我更新了 avutil 文件,在 goav 包装器包中,在顶部使用这个保存函数,然后将帧上下文传递给它,以便它可以从中获取数据指针。我还将此 Go 函数添加到该 avutil 文件中以调用 C 函数

func SaveFrame(location string, f *Frame, width int, height int) {
csLoc := C.CString(location)
C.SaveFrame(csLoc, (*C.struct_AVFrame)(unsafe.Pointer(f)), C.int(width), C.int(height))
C.free(unsafe.Pointer(csLoc))
}

最佳答案

我遇到了同样的问题:一个 C 函数分配空间并给出一个指向该空间的指针和要读取的大小。我通过这样做解决了它:

buffer := *(*[]byte)(unsafe.Pointer(&content))

这会将指针转换为内容地址处的 Golang 字节数组。buffer 填充来自 os.Read 的数据,C 函数处理数据。

关于c - 如何使用指向 C 数据的指针写入 Golang 中的文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50010555/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com