Update for OpenJDK 19 java.lang.foreign API.
authorNot Zed <notzed@gmail.com>
Sun, 25 Sep 2022 11:58:32 +0000 (21:28 +0930)
committerNot Zed <notzed@gmail.com>
Sun, 25 Sep 2022 11:58:32 +0000 (21:28 +0930)
12 files changed:
README
config.make.in
nbproject/project.properties
src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/audio/AudioPlay.java
src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoExport.java
src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoPlay.java
src/notzed.jjmpeg.demo/classes/au/notzed/jjmpeg/demo/video/VideoScan.java
src/notzed.jjmpeg/classes/au/notzed/jjmpeg/AVObject.java
src/notzed.jjmpeg/classes/au/notzed/jjmpeg/FramePixelReader.java
src/notzed.jjmpeg/classes/au/notzed/jjmpeg/io/JJMediaReader.java
src/notzed.jjmpeg/classes/au/notzed/jjmpeg/io/JJMediaWriter.java
src/notzed.jjmpeg/gen/ffmpeg.api

diff --git a/README b/README
index 95d6c6f..2cd4af0 100644 (file)
--- 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/<target>/lib/<module>.jar'    Modular jar for ide.
 `bin/<target>/lib/*.so'            Platform specific
-`bin/<target>/bin/*.dll'            runtime libraries.
+`bin/<target>/bin/*.dll'            runtime libraries
 
 `bin/<target>/jmods/<module>.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.
index a943972..e94f1b5 100644 (file)
@@ -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
index 85cea14..80305f8 100644 (file)
@@ -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}
index 4dde1ab..7b4daed 100644 (file)
@@ -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);
 
index 6da1a07..2ebf0b1 100644 (file)
@@ -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);
index 0a7e416..ec4a6fe 100644 (file)
@@ -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);
 
index 82e78fe..77186e7 100644 (file)
@@ -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);
index 2984229..44219b3 100644 (file)
@@ -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());
        }
 
        /**
index 9540555..da920ab 100644 (file)
 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 <T extends Buffer> 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) {
index 241c6e7..09b5c4f 100644 (file)
@@ -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<AVDictionary> options, ResourceScope scope) throws AVIOException, FileNotFoundException {
+       public JJMediaReader(String name, AVInputFormat fmt, HandleArray<AVDictionary> options, MemorySession scope) throws AVIOException, FileNotFoundException {
                this(AVFormatContext.openInput(name, fmt, options, scope));
        }
 
index 30e1667..be16c63 100644 (file)
@@ -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);
index 86d1a23..e66f72d 100644 (file)
@@ -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);