3

I'm trying to use the Foreign Function & Memory API in Java 22 to call into FFmpeg's libavformat. First, I used jextract to generate a binding:

jextract --target-package org.ffmpeg.avformat \    --output /path/to/src/main/java \    -I <base include dir> libavformat/avformat.h

My initial goal is to open a video file and get its dimensions. Many FFmpeg functions make use of a struct called AVFormatContext, which is a main context struct that refers to other structs, which refer to other structs, etc. So I need to walk through a few different structs to get the width & height:

struct AVFormatContext {    unsigned int nb_streams;    AVStream **streams;    // etc.}struct AVStream {    AVCodecParameters *codecpar;    // etc.}struct AVCodecParameters {    int width;    int height;    // etc.}

In C, this would involve something like:

int width  = formatCtx->streams[i]->codecpar->width;int height = formatCtx->streams[i]->codecpar->height;

Here is my attempt in Java:

try (Arena arena = Arena.ofConfined()) {    ///////////////////// begin setup ////////////////////////    MemorySegment formatCtxPtr  = arena.allocate(C_POINTER);    MemorySegment inputFormat   = MemorySegment.NULL;    MemorySegment formatDictPtr = MemorySegment.NULL;    MemorySegment url = arena.allocateFrom("file:/path/to/video.mp4");    int result = avformat_open_input(formatCtxPtr, url, inputFormat, formatDictPtr);    if (result != 0) {        throw new IOException("Couldn't open file");    }    MemorySegment formatCtx = formatCtxPtr.get(C_POINTER, 0);    // Verify the AVFormatContext    av_dump_format(formatCtx, 0, url, 0);    ///////////////////// end setup ////////////////////////    StructLayout formatCtxLayout = (StructLayout) AVFormatContext.layout();    VarHandle streamsHandle  = formatCtxLayout.varHandle(            MemoryLayout.PathElement.groupElement("streams"));    MemorySegment streamsPtr = (MemorySegment) streamsHandle.get(formatCtx, 0);    MemorySegment stream     = streamsPtr.getAtIndex(C_POINTER, 0);    StructLayout avStreamLayout  = (StructLayout) AVStream.layout();    VarHandle codecParamsHandle  = avStreamLayout.varHandle(            MemoryLayout.PathElement.groupElement("codecpar"));    MemorySegment codecParamsPtr = (MemorySegment) codecParamsHandle.get(stream, 0);    MemorySegment codecParams    = codecParamsPtr.get(C_POINTER, 0);    StructLayout codecParamsLayout = (StructLayout) AVCodecParameters.layout();    VarHandle widthHandle          = codecParamsLayout.varHandle(            MemoryLayout.PathElement.groupElement("width"));    int width                      = (int) widthHandle.get(codecParams, 0);}

Sadly that last call towidthHandle.get() causes:java.lang.InternalError: a fault occurred in an unsafe memory access operation

DuncG's user avatar
DuncG
16.3k3 gold badges31 silver badges44 bronze badges
askedMay 23, 2024 at 13:42
alexantd's user avatar
1
  • 2
    I'm not familiar with libavformat but jextract should have generated getter (and indexed) getter calls to retrieve each member field of each of those structures, avoiding you need to use Layout/VarHandle. eg see if you haveAVFormatContext.streams(formatCtx) etcCommentedMay 23, 2024 at 14:37

1 Answer1

1

It looks like you have one too many dereferences:

MemorySegment codecParams    = codecParamsPtr.get(C_POINTER, 0);

ThecodecParamsPtr is aAVCodecParameters*, which you then try to load a pointer from. That will however just read the first 8 bytes of the struct as a pointer.

Also, like @DuncG says in the comments, you can just use the getters that jextract generates. This should work:

// AVStream**MemorySegment streams = AVFormatContext.streams(formatCtx);// AVStream*MemorySegment stream = streams.getAtIndex(C_POINTER, 0);// AVCodecParameters*MemorySegment codecParams = AVStream.codecpar(stream);int width = AVCodecParameters.width(codecParams);
answeredMay 23, 2024 at 15:42
Jorn Vernee's user avatar
Sign up to request clarification or add additional context in comments.

1 Comment

Works like magic! Thanks!

Your Answer

Sign up orlog in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

By clicking “Post Your Answer”, you agree to ourterms of service and acknowledge you have read ourprivacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.