Как передать указатель функции на C-код в Go - PullRequest
1 голос
/ 24 мая 2019

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

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

AVIOContext *avio_alloc_context(
                  unsigned char *buffer,
                  int buffer_size,
                  int write_flag,
                  void *opaque,
                  int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
                  int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
                  int64_t (*seek)(void *opaque, int64_t offset, int whence));

Код go, который я написал, чтобы назвать это -

package video

// #include<libavformat/avio.h>
import "C"
import (
  "bytes"
  "github.com/giorgisio/goav/avformat"
  "github.com/giorgisio/goav/avutil"
  "unsafe"
)

func DecodeStream(data *bytes.Buffer) {
  bufferSize := 8192
  formatContext := avformat.AvformatAllocContext()
  buffer := (*C.uchar)(avutil.AvMalloc(uintptr(bufferSize)))
  ioContext := C.avio_alloc_context(
    buffer,
    C.int(bufferSize),
    C.int(0),
    unsafe.Pointer(data),
    &[0]byte{},
    &[0]byte{},
    &[0]byte{}, 
  )                                       // <- error in this line
  formatContext.SetPb((*avformat.AvIOContext)(unsafe.Pointer(ioContext)))
  if formatContext.AvformatFindStreamInfo(nil) < 0 {
    panic("Couldn't find stream info")
  }
  println("DURATION: ", formatContext.Duration())
}

Однако я получаю эту ошибку runtime error: cgo argument has Go pointer to Go pointer.

Я тоже пытался заменить &[0]byte{} на nil. Кажется, не может уйти!

1 Ответ

0 голосов
/ 26 мая 2019

Ошибка времени выполнения на самом деле жалуется на аргумент unsafe.Pointer(data). Тип bytes.Buffer имеет внутренние (Go) указатели, и cgo не позволяет передавать указатели на C, если эти указатели указывают на объекты Go, которые сами содержат указатели Go.

Эти правила подробно описаны в документации cgo здесь: https://golang.org/cmd/cgo/#hdr-Passing_pointers

Краткая сводка заключается в том, что сборщик мусора Go должен знать, когда изменяются указатели Go. Компиляторы Go следят за тем, чтобы скомпилированный код надлежащим образом информировал сборщик мусора, но компиляторы C не знают, как это сделать. Поэтому, чтобы предотвратить проблемы с сборщиком мусора, cgo просто не разрешает передавать указатели вроде этого.

...