From: Not Zed Date: Sun, 25 Sep 2022 11:58:32 +0000 (+0930) Subject: Update for OpenJDK 19 java.lang.foreign API. X-Git-Url: https://code.zedzone.au/cvs?a=commitdiff_plain;h=b447302adad2f804089de9a72ef64f3825db7af5;p=jjmpeg Update for OpenJDK 19 java.lang.foreign API. --- diff --git a/README b/README index 95d6c6f..2cd4af0 100644 --- a/README +++ b/README @@ -1,29 +1,23 @@ -Copyright (C) 2017-2019 Michael Zucchi +Copyright (C) 2017-2022 Michael Zucchi See the section LICENSE for details. Introduction ------------ -jjmpeg is a JNI based Java binding for the suite of libraries provided -by FFmpeg. - -The original version of jjmpeg was released sometime in the distant -past and has slowly got further and further behind the current FFmpeg -version. This is a completely new implementation intended as a -project to catch up with the current API. +jjmpeg is a java.lang.foreign based Java binding for the suite of +libraries provided by FFmpeg. Compile ------- -jdk (javac, jar) and native compiler tools (GNU make, cc, cpp, perl) -must be in path. In addition the program cproto must be installed. -JDK 13 is the baseline but JDK 9+ may work. +Requires OpenJDK 19 and a compatible version of the ffmpeg sdk. The prequisitve project notzed.nativez must also have previously been -compiled and will be automatically used if it is present in the -directory above this one (../nativez/). +compiled to the 'sdk' target and will be automatically used if it is +present in the directory above this one (../nativez/), as configured +in config.make. The jdk-foriegn branch must be used with this version. First copy config.make.in to config.make and adjust configuration parameters. @@ -40,7 +34,7 @@ All intermediate and final results are place in `bin/'. `bin//lib/.jar' Modular jar for ide. `bin//lib/*.so' Platform specific -`bin//bin/*.dll' runtime libraries. +`bin//bin/*.dll' runtime libraries `bin//jmods/.jmod' Target specific .jmod. @@ -56,8 +50,9 @@ this will include any droppings. NetBeans -------- -Before the source can be easily edited in NetBeans one must -first run the makefile to generate any auto-generated files. +Before the source can be easily edited in NetBeans one must first run +the makefile to generate any auto-generated files. A full build may +be used but at the least the 'gen' target must be built. $ make gen @@ -67,69 +62,30 @@ files in `src/notzed.jjmpeg/gen' are edited. Development ----------- -Some notes on internals. - -Java Native Interface -- - - - - - - - - - - - -All jj-*.c files are independent of one another, they may only -reference functions and variables from jjmpeg.c. - -The native interface is implemented using the notzed.nativez project. -This allows it to support full garbage collection of all relevant -objects. In some cases this currently requires references to be -manually kept to ensure they survive for the relevant C side objects. -All objects are unique (and keyed) based on their C pointer address. - -If used with care, objects can also be manually released safely. - -Unlike earlier versions of jjmpeg, version 3+ is implemented almost -entirely using hand-rolled Java and macro-assisted C source-code. -Also unlike earlier versions almost all code is written directly in C -with only skeleton Java wrappers of native method signatures. This -requires less work and produces smaller code than previous versions. +This uses notzed.nativez foriegn-abi branch implementation to create a +custom 'object oriented' binding directly from ffmpeg headers. -To further reduce code-size most initialisation is implemented via -tables. +Only a small subset of the API has been converted so far, enough to +build the examples. Enumerations - - - - - - -A set of small(ish) perl scripts are used to extract various -enumeration and #define tables directly from the FFmpeg development -header files. They generate interfaces which are "implemented" to add -the defines to the desired structures. These reside in the scripts -directory. - -All enumerations were converted to final integer values for +All enumerations are converted to final integer values for consistency. Where the corresponding functions exist, static valueOf() and toString() are available for obvious purposes. -The perl scripts generate C code which is then compiled and executed -to create the Java interfaces. - Exceptions -- - - - - - -Exceptions fall into two categories, AVIOException and AVException, -both checked exceptions. The former derives from IOException for -simplicity. +- - - - - -They contain the error code (errno and AVERROR defines) and a -description. - -Where it makes sense other Java checked and unchecked exceptions such -as FileNotFoundException or OutOfMemoryError are also thrown. +These are not implemented (yet?). Error return values need to be +checked and these have not been fully implemented in the high level +interfaces either. Linkage - - - - -All libraries are dynamically linked at runtime. Missing functions -result in an initialisation failure. - -Method signatures are automatically extracted from headers via the -script src/notzed.jjmpeg/jni/extract-proto.pl based on per-file .def -files. This also generates a table for initialising the pointers. +All libraries are dynamically linked via java.lang.foriegn mechanisms. Build System - - - - - - @@ -151,15 +107,7 @@ well as a pair of high-level interfaces JJMediaReader and JJMediaWriter. These have been simplified somewhat from the previous implementation, but it takes less code to use them anyway. -Most functions that should throw exceptions do although that which -they throw may be tweaked. - -Many accessors have been implemented, in some cases they have been -Javaised or NotZedised (e.g. setFlags(mask, value)) for a cleaner -interface. Because of the complexity of the libraries and objects it -is not always clear which members need to be accessed by user code so -some of the choices are arbitrary. Or I just gave up part way -through. They are easy to add. +Exceptions are not implemented at this time. There are two sub-modules notzed.jjmpeg.fx and notzed.jjmpeg.awt which supply the JavaFX and Swing/AWT specific functionality. diff --git a/config.make.in b/config.make.in index a943972..e94f1b5 100644 --- a/config.make.in +++ b/config.make.in @@ -9,7 +9,7 @@ FFMPEG_HOME ?= /usr NATIVEZ_HOME=../nativez/bin/$(TARGET) JAVAMODPATH = $(JAVAFX_HOME)/lib $(NATIVEZ_HOME)/lib -JAVACFLAGS += +JAVACFLAGS += --enable-preview --source 19 JAVAC ?= $(JAVA_HOME)/bin/javac JAR ?= $(JAVA_HOME)/bin/jar diff --git a/nbproject/project.properties b/nbproject/project.properties index 85cea14..80305f8 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -40,7 +40,7 @@ includes=** jar.compress=false javac.classpath= # Space-separated list of extra javac options -javac.compilerargs=-Xlint:unchecked +javac.compilerargs=-Xlint:unchecked --enable-preview javac.deprecation=false javac.external.vm=false javac.modulepath=\ @@ -49,8 +49,8 @@ javac.modulepath=\ javac.processormodulepath= javac.processorpath=\ ${javac.classpath} -javac.source=18 -javac.target=18 +javac.source=19 +javac.target=19 javac.test.classpath=\ ${javac.classpath} javac.test.modulepath=\ @@ -84,7 +84,7 @@ run.classpath= # Space-separated list of JVM arguments used when running the project. # You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. # To set system properties for unit tests define test-sys-prop.name=value: -run.jvmargs=--enable-native-access notzed.nativez,notzed.jjmpeg +run.jvmargs=--enable-native-access notzed.nativez,notzed.jjmpeg --enable-preview run.modulepath=\ ${javac.modulepath}:\ ${build.modules.dir} diff --git a/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/audio/AudioPlay.java b/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/audio/AudioPlay.java index 4dde1ab..7b4daed 100644 --- a/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/audio/AudioPlay.java +++ b/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/audio/AudioPlay.java @@ -23,6 +23,7 @@ import au.notzed.jjmpeg.AVSampleFormat; import au.notzed.jjmpeg.AVSampleReader; import au.notzed.jjmpeg.io.JJMediaReader; import java.io.IOException; +import java.lang.foreign.MemorySession; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; @@ -30,7 +31,6 @@ import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; -import jdk.incubator.foreign.ResourceScope; /** * Plays audio files. @@ -103,7 +103,7 @@ public class AudioPlay { return; } - try (ResourceScope scope = ResourceScope.newConfinedScope(); + try (MemorySession scope = MemorySession.openConfined(); JJMediaReader mr = new JJMediaReader(path, scope)) { JJMediaReader.JJReaderAudio as = mr.openDefaultStream(JJMediaReader.TYPE_AUDIO); diff --git a/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoExport.java b/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoExport.java index 6da1a07..2ebf0b1 100644 --- a/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoExport.java +++ b/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoExport.java @@ -24,9 +24,9 @@ import au.notzed.jjmpeg.io.JJMediaReader; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; +import java.lang.foreign.MemorySession; import java.util.IllegalFormatException; import javax.imageio.ImageIO; -import jdk.incubator.foreign.ResourceScope; /** * Export a video as frames. @@ -75,7 +75,7 @@ public class VideoExport { System.err.println("Unknown extension"); type = format.substring(dot + 1).toLowerCase(); - try (ResourceScope scope = ResourceScope.newConfinedScope(); + try (MemorySession scope = MemorySession.openConfined(); JJMediaReader mr = new JJMediaReader(path, scope)) { int index = 0; JJMediaReader.JJReaderVideo vs = mr.openDefaultStream(JJMediaReader.TYPE_VIDEO); diff --git a/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoPlay.java b/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoPlay.java index 0a7e416..ec4a6fe 100644 --- a/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoPlay.java +++ b/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoPlay.java @@ -26,6 +26,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import static java.lang.Double.min; +import java.lang.foreign.MemorySession; import java.time.Instant; import java.time.LocalTime; import java.time.ZoneId; @@ -57,7 +58,6 @@ import javafx.scene.transform.Translate; import javafx.stage.FileChooser; import javafx.stage.Screen; import javafx.stage.Stage; -import jdk.incubator.foreign.ResourceScope; /** * A simple JavaFX demo which plays a video. @@ -252,7 +252,7 @@ public class VideoPlay extends Application { * @param path */ void reader(String path) { - try (ResourceScope scope = ResourceScope.newConfinedScope(); + try (MemorySession scope = MemorySession.openConfined(); JJMediaReader mr = new JJMediaReader(path, scope)) { JJMediaReader.JJReaderVideo vs = mr.openDefaultStream(JJMediaReader.TYPE_VIDEO); diff --git a/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoScan.java b/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoScan.java index 82e78fe..77186e7 100644 --- a/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoScan.java +++ b/src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoScan.java @@ -21,7 +21,7 @@ package au.notzed.jjmpeg.demo.video; import au.notzed.jjmpeg.AVPixelFormat; import au.notzed.jjmpeg.io.JJMediaReader; import java.io.IOException; -import jdk.incubator.foreign.ResourceScope; +import java.lang.foreign.MemorySession; /** * A simple video scanner. @@ -39,7 +39,7 @@ public class VideoScan { String path = args[0]; - try (ResourceScope scope = ResourceScope.newConfinedScope(); + try (MemorySession scope = MemorySession.openConfined(); JJMediaReader mr = new JJMediaReader(path, scope)) { int count = 0; JJMediaReader.JJReaderVideo vs = mr.openDefaultStream(JJMediaReader.TYPE_VIDEO); diff --git a/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/AVObject.java b/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/AVObject.java index 2984229..44219b3 100644 --- a/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/AVObject.java +++ b/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/AVObject.java @@ -19,8 +19,8 @@ package au.notzed.jjmpeg; import au.notzed.nativez.*; +import java.lang.foreign.MemorySession; import java.util.logging.Logger; -import jdk.incubator.foreign.ResourceScope; /** * @@ -40,7 +40,7 @@ public abstract class AVObject extends Native { System.loadLibrary("avutil"); AVUtil.setLogger(AVUtil.createAVLogger(Logger.getLogger("notzed.jjmpeg")), - ResourceScope.globalScope()); + MemorySession.global()); } /** diff --git a/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/FramePixelReader.java b/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/FramePixelReader.java index 9540555..da920ab 100644 --- a/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/FramePixelReader.java +++ b/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/FramePixelReader.java @@ -19,10 +19,10 @@ package au.notzed.jjmpeg; import java.nio.Buffer; -import java.nio.ByteBuffer; import java.nio.BufferOverflowException; -import jdk.incubator.foreign.*; import au.notzed.nativez.*; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; public class FramePixelReader implements AVPixelReader { @@ -31,7 +31,7 @@ public class FramePixelReader implements AVPixelReader { final int dwidth, dheight, flags; int dfmt = -1; - ResourceScope scope = ResourceScope.newImplicitScope(); + MemorySession scope = MemorySession.openImplicit(); MemorySegment seg; public FramePixelReader(AVFrame frame, int dwidth, int dheight, int flags) { @@ -110,9 +110,9 @@ public class FramePixelReader implements AVPixelReader { public void getPixels(int y, int h, int fmt, T buffer, int scanlineStride) { if (buffer.isDirect()) - getPixels(y, h, fmt, MemorySegment.ofByteBuffer((ByteBuffer)buffer), scanlineStride); + getPixels(y, h, fmt, MemorySegment.ofBuffer(buffer), scanlineStride); else - getPixelsHeap(y, h, fmt, MemorySegment.ofByteBuffer((ByteBuffer)buffer), scanlineStride); + getPixelsHeap(y, h, fmt, MemorySegment.ofBuffer(buffer), scanlineStride); } public void getPixels(int y, int h, int fmt, byte[] buffer, int offset, int scanlineStride) { diff --git a/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/io/JJMediaReader.java b/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/io/JJMediaReader.java index 241c6e7..09b5c4f 100644 --- a/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/io/JJMediaReader.java +++ b/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/io/JJMediaReader.java @@ -37,10 +37,10 @@ import au.notzed.jjmpeg.AVStream; import au.notzed.nativez.Frame; import au.notzed.nativez.HandleArray; import java.io.FileNotFoundException; +import java.lang.foreign.MemorySession; import java.util.AbstractList; import java.util.List; import java.util.logging.Logger; -import jdk.incubator.foreign.ResourceScope; /** * High level interface for scanning audio and video frames. @@ -110,11 +110,11 @@ public class JJMediaReader implements AutoCloseable { * @see #getStreams * @see #readFrame */ - public JJMediaReader(String name, ResourceScope scope) throws AVIOException, FileNotFoundException { + public JJMediaReader(String name, MemorySession scope) throws AVIOException, FileNotFoundException { this(name, null, null, scope); } - public JJMediaReader(String name, AVInputFormat fmt, HandleArray options, ResourceScope scope) throws AVIOException, FileNotFoundException { + public JJMediaReader(String name, AVInputFormat fmt, HandleArray options, MemorySession scope) throws AVIOException, FileNotFoundException { this(AVFormatContext.openInput(name, fmt, options, scope)); } diff --git a/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/io/JJMediaWriter.java b/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/io/JJMediaWriter.java index 30e1667..be16c63 100644 --- a/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/io/JJMediaWriter.java +++ b/src/notzed.jjmpeg/classes/au/notzed/jjmpeg/io/JJMediaWriter.java @@ -44,10 +44,10 @@ import au.notzed.jjmpeg.AVIOException; import au.notzed.jjmpeg.AVMediaType; import au.notzed.jjmpeg.AVSampleFormat; import au.notzed.nativez.Frame; +import java.lang.foreign.MemorySession; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; -import jdk.incubator.foreign.ResourceScope; /** * High level media file writer interface. @@ -72,7 +72,7 @@ public class JJMediaWriter implements AutoCloseable { * * @param filename */ - public JJMediaWriter(String filename, ResourceScope scope) throws AVIOException { + public JJMediaWriter(String filename, MemorySession scope) throws AVIOException { this.filename = filename; oc = AVFormatContext.allocOutputContext(null, null, filename, scope); diff --git a/src/notzed.jjmpeg/gen/ffmpeg.api b/src/notzed.jjmpeg/gen/ffmpeg.api index 86d1a23..e66f72d 100644 --- a/src/notzed.jjmpeg/gen/ffmpeg.api +++ b/src/notzed.jjmpeg/gen/ffmpeg.api @@ -367,7 +367,7 @@ library AVUtil }; } - public static void setLogger(AVLogger log, ResourceScope scope) { + public static void setLogger(AVLogger log, MemorySession scope) { AVUtil.av_log_set_callback(AVLogFunc.upcall((avcl, level, fmt, valist) -> { try (Frame frame = Frame.frame()) { ByteArray line = ByteArray.createArray(1024, frame);