You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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.

Accessing AVFormatContext Streams in goav

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.Ctx gives you direct access to the underlying *C.AVFormatContext pointer (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.Pointer for 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() for AVFormatContext)—use these when available instead of directly accessing Ctx fields, 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:

  1. Decode packets from the video stream into AVFrames using goav’s avcodec package.
  2. Convert the YUV frame data (FFmpeg’s default) to RGBA with FFmpeg’s swscale library:
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
}
  1. 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 Free methods (like AvFrameFree and SwsFreeContext) to prevent memory leaks.
  • Format conversion is non-negotiable: FFmpeg outputs YUV frames by default, and OpenGL expects RGB/RGBA—swscale is the most efficient way to handle this.

内容的提问来源于stack exchange,提问作者nevernew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:12:44