Cómo acceder a una matriz de punteros C desde Golang

Estoy escribiendo una aplicación para la plataforma de Windows usando FFmpeg y es Golang wrapper goav, pero tengo problemas para entender cómo usar los punteros C para obtener acceso a una matriz.

Estoy tratando de hacer que las secuencias almacenadas en la clase AVFormatContext se utilicen en go, y eventualmente agregar marcos a una textura en OpenGl para hacer un reproductor de video con transiciones geniales.

Creo que entender cómo emitir y acceder a los datos en C hará que la encoding sea mucho más fácil.

He eliminado todas las partes relevantes del código C, la envoltura y mi código, como se muestra a continuación:

Código C – libavformat / avformat.h

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

Golang envoltura de goav

 package avutil //#cgo pkg-config: libavformat //#include  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))); } 

Mi codigo de 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... } 

En C parece que solo tengo que hacer solo secuencias [i], pero eso no funciona, así que agregué una función al envoltorio usando la técnica de mi pregunta aquí . Sin embargo no estoy obteniendo los datos; Parece que estoy recibiendo un puntero a algún lugar aleatorio en la memoria. Entonces, ¿cómo puedo acceder a estos elementos desde golang? Cualquier recurso sería útil también; Voy a invertir un poco de tiempo en esto.

Como habrás notado, el problema está en el siguiente código:

 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))); } 

En el código, los streams variables son de doble puntero , por lo que el resultado de agregar un desplazamiento a los streams también es un doble puntero (es decir, el tipo es **Stream ). Pero, en tus fragmentos, se convierte a *Stream que es incorrecto. El código correcto es:

 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 } 

Nota adicional:
Si desea evitar la aritmética de punteros en el lado Go , puede definir una función auxiliar para acceder al elemento del puntero (es decir, flujos) en el lado C de la siguiente manera:

 /* 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) } 

Puede elegir la función ptr_at que acepta puntero doble genérico (cualquiera) como argumento, o una función stream_at más específica que solo acepta puntero a AVFormatContext como argumento. El enfoque anterior se puede utilizar para acceder al elemento desde cualquier puntero doble como: AVProgram ** , AVChapter ** , etc. El enfoque posterior es preferible si necesitamos implementar un procesamiento adicional como la verificación de límites.