CGO: Как вы используете указатели в Golang для доступа к данным из массива в C

Я пишу приложение для платформы Windows, используя FFmpeg и его goav-оболочку golang, но у меня возникли проблемы с пониманием того, как использовать указатели C для получения доступа к массиву данных, на который они указывают.

Я пытаюсь получить данные, хранящиеся в классе AVFrame, и использовать Go, чтобы записать их в файл, и, в конечном итоге, текстуру в OpenGl, чтобы сделать видеоплеер с классными переходами.

Я думаю, что понимание того, как преобразовать и получить доступ к данным C, значительно упростит кодирование.

Я удалил все соответствующие части кода C, оболочки и моего кода, как показано ниже:

Код C — libavutil/frame.h

#include <stdint.h>

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

Goav-оболочка Golang - я действительно не знаю, что здесь происходит с unsafe.Pointers и кастингом, но это дает мне доступ к базовому коду C

package avutil

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

type Frame C.struct_AVFrame

func AvFrameAlloc() *Frame {
    return (*Frame)(unsafe.Pointer(C.av_frame_alloc()))
}

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

Мой код Голанга

package main

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

func main() {
    videoFrame := avutil.AvFrameAlloc()

    data := avutil.Data(videoFrame)

    fmt.Println(data) // here i want the values from data[0] to data[7], but how?
}

person nevernew    schedule 19.04.2018    source источник


Ответы (1)


Поскольку автор библиотеки не создал для вас заголовок среза, с которым вы могли бы работать, вместо этого вам нужно будет преобразовать возвращаемое значение в unsafe.Pointer, а затем в uintptr, это позволит вам выполнить над ним арифметические действия с указателем, чтобы позже получить элементы в памяти. .

Вот пример кода, который должен работать как есть на игровой площадке go.

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    nums := []uint8{1, 2, 3, 4, 5, 6, 7, 8}

    val := &nums[0] // val is the equivalent of the *uint8 the Data function returns

    ptr := unsafe.Pointer(val)

    sixthVal := (*uint8)(unsafe.Pointer(uintptr(ptr) + 5*unsafe.Sizeof(*val)))

    fmt.Println("Sixth element:", *sixthVal)
}

Конечно, вам нужно быть очень уверенным, что вы знаете, сколько там элементов, чтобы не получить доступ к недопустимой памяти.

person Thomas    schedule 21.04.2018
comment
О, круто, хорошо выглядит! У меня есть другой тип списка в C typedef struct AVFormatContext { unsigned int nb_streams; AVStream **streams; } В C это похоже на просто streams[i], но это не будет работать в go, поэтому я добавил функцию, используя ваш метод: type Context C.struct_AVFormatContext; func (ctxt *Context) StreamsGet(i uintptr) *Stream { streams := (**Stream)(unsafe.Pointer(ctxt.streams)); return (*Stream)(unsafe.Pointer(uintptr(unsafe.Pointer(streams)) + i*unsafe.Sizeof(*streams))); } Однако я не получаю данные. Вы знаете, как я могу получить доступ к этим элементам? - person nevernew; 23.04.2018
comment
Продолжение вопроса: stackoverflow.com/questions/49987098/ - person nevernew; 23.04.2018