重新包装C类型会导致Go中的类型转换错误

I'm trying to repackage some go code that integrates with an existing C library.

The following works perfectly.

File 1:

package avcodec

type Codec C.struct_AVCodec

File 2:

package avformat

//#cgo pkg-config: libavformat libavcodec
//#include <libavformat/avformat.h>
//#include <libavcodec/avcodec.h>
import "C" 
import (    
"unsafe" 
) 

type Codec C.struct_AVCodec

func (s *FormatContext) AvFormatGetVideoCodec() *Codec {    
  result := C.av_format_get_video_codec((*C.struct_AVFormatContext)(s))
  return (*Codec)(result) // <- This works. Codec is defined in this package.
}

If I try to reference or move Codec from File 2 into a separate package (eg. File 1) I get the error:

cannot convert (func literal)((*C.struct_AVFormatContext)(s)) (type *C.struct_AVCodec) to type *Codec

For example, this fails:

package avformat

//#cgo pkg-config: libavformat libavcodec
//#include <libavformat/avformat.h>
//#include <libavcodec/avcodec.h>
import "C" 
import (    
"avcodec"
"unsafe" 
) 

func (s *FormatContext) AvFormatGetVideoCodec() *avcodec.Codec {    
 result := C.av_format_get_video_codec((*C.struct_AVFormatContext)(s))      
 return (*avcodec.Codec)(result) // <- This fails. Codec defined in avcodec.
}

This also fails:

package avformat

//#cgo pkg-config: libavformat libavcodec
//#include <libavformat/avformat.h>
//#include <libavcodec/avcodec.h>    
import "C" 
import ( 
"avcodec"   
"unsafe" 
) 

type Codec avcodec.Codec

func (s *FormatContext) AvFormatGetVideoCodec() *Codec {    
  result := C.av_format_get_video_codec((*C.struct_AVFormatContext)(s))
  return (*Codec)(result) // <- This also fails. Codec is based on avcodec.Codec.
}

I'd like to:

  1. Understand why it fails, and
  2. Identify how I can change the packaging so that the function uses the Codec type that is defined in the avcodec package.

Thanks in advance.

This was failing due to how Go represents types.

For instance, given:

//Ex1
package avformat 
//.. deleted for simplicity

type Codec C.struct_AVCodec

...and

//Ex2
package avcode 
//.. deleted for simplicity

type Codec C.struct_AVCodec

In the code above, the C.struct_AVCodec in ex1 is different from the C.struct_AVCodec in ex2, even though the same are lexically the same.

Specifically, the fully qualified type in ex1 is avformat._Ctype_struct_AVCodec, while ex2 is avcodec._Ctype_struct_AVCodec

This explains why the functions in the package avformat that were trying to cast anything from an external type (in this case from package avcodec) to the local C.struct_AVCodec were failing.

Solution

To get this to work, I relied on type assertions.

package avformat

func (s *FormatContext) AvformatNewStream(c avcodec.ICodec) *Stream {
  v, _ := c.(*C.struct_AVCodec)
  return (*Stream)(C.avformat_new_stream((*C.struct_AVFormatContext)(s), (*C.struct_AVCodec)(v)))
}

...and

package avcodec

type ICodec interface{}