如何使用指向C数据的指针写入Golang中的文件? [英] How do I write to a file in Golang using a pointer to the C data?

查看:57
本文介绍了如何使用指向C数据的指针写入Golang中的文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用FFmpeg为Windows平台编写一个应用程序,它是golang包装器goav,但是我在理解如何使用C指针获取对数组的访问方面遇到了麻烦.

I'm writing an app for the windows platform using FFmpeg and it's golang wrapper goav, but I'm having trouble understanding how to use the C pointers to gain access to an array.

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

I'm trying to write the frame data, pointed to by a uint8 pointer from C, to a .ppm file in golang.

完成此操作后,为了证明FFmpeg可以达到预期效果,我想将帧设置为OpenGl中的纹理,以使视频播放器具有出色的过渡效果;任何出色而有效地做到这一点的指针都将非常有帮助!我猜我需要编写一些着色器代码以将ppm绘制为纹理...

PPM文件结构看起来很简单,只是标头然后是字节从左上到右下的帧中每个像素的红色,绿色和蓝色值的数据

The PPM file structure looks pretty simple just the header and then a byte of data for each red, green and blue value of each pixel in the frame from top left to bottom right

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

I'm starting to understanding how to cast the pointers between C and Go types, but how can I access the data and write it in Go with the same result as C? In C I just have to set the pointer offset for the data and state how much of it to write:

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

我已经剥离了C代码的所有相关部分,包装程序和我的代码,如下所示:

I've stripped out all the relevant parts of the C code, the wrapper and my code, shown below:

C代码-libavutil/frame.h

C code - 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包装器

Golang goav wrapper

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语言一样使用指向数据的指针写入文件,并获得相同的结果?

So, how can I write to a file using a pointer to the data, like you can do in C, and get the same result?

第一帧应该是黑色的,所以全0,但是我得到了一个毛刺的模糊感,因此它必须访问一些随机数据

The first frame should be black so all 0's but I'm getting a glitchy fuzz, so it must be accessing some random data

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

Update: My fix using a C function to save:

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"

我在goav包装程序包中更新了avutil文件,并在顶部使用了此保存功能,然后将其传递给框架上下文,以便它可以从中获取数据指针.我还将此Go函数添加到了该avutil文件中以调用C函数

I updated the avutil file, in the goav wrapper package, with this save function at the top, then pass it the frame context so it can get the data pointer from it. I also added this Go function to that avutil file to call the C function

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函数分配了空间,并提供了指向该空间的指针以及要读取的大小.我通过以下方法解决了这个问题:

I had the same issue: A C function allocated space and gave a pointer to that space and the size to read. I solved it by doing:

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

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

this transforms the pointer to a Golang byte array at the address of content. buffer gets filled with data from os.Read and the C function handles the data.

这篇关于如何使用指向C数据的指针写入Golang中的文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆