如何在Golang中访问C指针数组?基于goav与FFmpeg的Windows开发场景
Hey there! I’ve worked with goav and FFmpeg on Windows before, so I totally get the confusion around C pointer/array access when dealing with AVFormatContext’s streams. Let’s walk through this step by step—mastering this will absolutely smooth out your path to getting frames into OpenGL textures for those cool transitions you’re building.
First, let’s recall that in raw FFmpeg C code, AVFormatContext->streams is an AVStream** (a pointer to an array of pointers). goav wraps these C structures, but you’ll need to use Go’s unsafe package to bridge the gap between C’s pointer arrays and Go’s usable types.
Step 1: Extract the Streams Array
Assuming you’ve already opened a media file and have an *avformat.AVFormatContext instance, here’s how to safely iterate over its streams:
import ( "unsafe" "github.com/giorgisio/goav/avformat" ) func extractStreams(fmtCtx *avformat.AVFormatContext) []*avformat.AVStream { var streams []*avformat.AVStream // Get the number of streams from the underlying C structure nbStreams := int(fmtCtx.Ctx.nb_streams) // Cast the C stream pointer array to a Go-accessible form cStreamArray := (**C.AVStream)(unsafe.Pointer(fmtCtx.Ctx.streams)) // Iterate over each stream pointer in the array for i := 0; i < nbStreams; i++ { // Use a large dummy array size (1<<30) to safely index the C array streamPtr := (*[1 << 30]*C.AVStream)(unsafe.Pointer(cStreamArray))[i] // Wrap the C pointer in goav's AVStream type streams = append(streams, (*avformat.AVStream)(unsafe.Pointer(streamPtr))) } return streams }
Why this works:
fmtCtx.Ctxgives you direct access to the underlying*C.AVFormatContextpointer (goav exposes this for low-level operations).- We cast the
AVStream**to a pointer of a huge dummy array—this lets us use Go’s array indexing syntax to access individual stream pointers without triggering undefined behavior (since video streams will never hit 1<<30 in count).
Step 2: Critical C/Go Type Conversion Tips
- Always use
unsafe.Pointerfor cross-language type casts: This is the only Go-approved way to interact with C memory directly. Avoid any type casts without it. - Match C array lengths: Never iterate beyond
nb_streams—this will cause memory access errors. Always use the C structure’s length field to bound your loops. - Leverage goav’s helpers: Some goav structs have wrapper methods (like
NbStreams()forAVFormatContext)—use these when available instead of directly accessingCtxfields, but know the direct access is there when you need it.
Step 3: Prepping Frames for OpenGL Textures
Once you have your video stream, the next big step is getting decoded frames into a format OpenGL can use (usually RGBA). Here’s a quick breakdown with code:
- Decode packets from the video stream into
AVFrames using goav’savcodecpackage. - Convert the YUV frame data (FFmpeg’s default) to RGBA with FFmpeg’s
swscalelibrary:
import ( "unsafe" "github.com/giorgisio/goav/avutil" "github.com/giorgisio/goav/swscale" ) func yuvToRGBA(frame *avutil.AVFrame, width, height int) []byte { // Create a scale context for format conversion swsCtx := swscale.SwsGetContext( width, height, avutil.AV_PIX_FMT_YUV420P, width, height, avutil.AV_PIX_FMT_RGBA, swscale.SWS_BILINEAR, nil, nil, nil, ) defer swscale.SwsFreeContext(swsCtx) // Allocate memory for the RGBA frame rgbaFrame := avutil.AvFrameAlloc() defer avutil.AvFrameFree(&rgbaFrame) rgbaFrame.SetFormat(avutil.AV_PIX_FMT_RGBA) rgbaFrame.SetWidth(width) rgbaFrame.SetHeight(height) avutil.AvFrameGetBuffer(rgbaFrame, 32) // Perform the format conversion swscale.SwsScale(swsCtx, frame.Data(), frame.Linesize(), 0, height, rgbaFrame.Data(), rgbaFrame.Linesize()) // Copy the RGBA data into a Go slice (safe for OpenGL use) rgbaData := make([]byte, width*height*4) copy(rgbaData, unsafe.Slice((*byte)(rgbaFrame.Data()[0]), width*height*4)) return rgbaData }
- Use OpenGL’s
glTexSubImage2D(or similar) to upload the RGBA slice into your texture.
Key Takeaways
- Treat C pointer arrays as "opaque" until you cast them with
unsafe.Pointer—this avoids Go’s type safety checks, but is necessary for FFmpeg interop. - Always clean up C resources with goav’s
Freemethods (likeAvFrameFreeandSwsFreeContext) to prevent memory leaks. - Format conversion is non-negotiable: FFmpeg outputs YUV frames by default, and OpenGL expects RGB/RGBA—
swscaleis the most efficient way to handle this.
内容的提问来源于stack exchange,提问作者nevernew

