diff --git a/.gitignore b/.gitignore
index ae18b21..acee6fc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,4 +7,6 @@ bin
/library/windows*
/library/linux*
+/library/video.jar
+
local.properties
diff --git a/build.xml b/build.xml
index f874f23..1a6517e 100755
--- a/build.xml
+++ b/build.xml
@@ -63,7 +63,7 @@ ${line.separator}with the path to where you have the code for Processing 4 check
-
+
Code signing will only work if you have a $99/yr Apple developer ID.
@@ -76,7 +76,7 @@ ${line.separator}with the path to where you have the code for Processing 4 check
-
+
@@ -91,11 +91,11 @@ ${line.separator}with the path to where you have the code for Processing 4 check
-
+
-
+
@@ -133,7 +133,7 @@ ${line.separator}with the path to where you have the code for Processing 4 check
-
+
@@ -149,7 +149,7 @@ ${line.separator}with the path to where you have the code for Processing 4 check
Check on notarization status with:
- xcrun altool -u $VIDEO_APPLE_ID -p $VIDEO_LIB_PASSWORD --notarization-info [the RequestUUID above]
+ xcrun altool -u $APPLE_ID -p $VIDEO_LIB_PASSWORD --notarization-info [the RequestUUID above]
@@ -159,9 +159,10 @@ ${line.separator}with the path to where you have the code for Processing 4 check
-
-
-
+
+
+
+
@@ -178,7 +179,7 @@ ${line.separator}with the path to where you have the code for Processing 4 check
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+ Creating zip package...
+
+
+
+
+
+
+
+
+
+
+
+ Done!
+
diff --git a/examples/Capture/AsciiVideo/AsciiVideo.pde b/examples/Capture/AsciiVideo/AsciiVideo.pde
index 5936428..aadc30c 100644
--- a/examples/Capture/AsciiVideo/AsciiVideo.pde
+++ b/examples/Capture/AsciiVideo/AsciiVideo.pde
@@ -1,11 +1,11 @@
/**
* ASCII Video
- * by Ben Fry.
+ * by Ben Fry.
+ *
*
- *
* Text characters have been used to represent images since the earliest computers.
* This sketch is a simple homage that re-interprets live video as ASCII text.
- * See the keyPressed function for more options, like changing the font size.
+ * See the keyPressed() function for more options, like changing the font size.
*/
import processing.video.*;
@@ -13,14 +13,13 @@ import processing.video.*;
Capture video;
boolean cheatScreen;
-// All ASCII characters, sorted according to their visual density
+// Characters sorted according to their visual density
String letterOrder =
" .`-_':,;^=+/\"|)\\<>)iv%xclrs{*}I?!][1taeo7zjLu" +
"nT#JCwfy325Fp6mqSghVd4EgXPGZbYkOA&8U$@KHDBWNMR0Q";
char[] letters;
float[] bright;
-char[] chars;
PFont font;
float fontSize = 1.5;
@@ -29,13 +28,13 @@ float fontSize = 1.5;
void setup() {
size(640, 480);
- // This the default video input, see the GettingStartedCapture
+ // This the default video input, see the GettingStartedCapture
// example if it creates an error
video = new Capture(this, 160, 120);
-
+
// Start capturing the images from the camera
- video.start();
-
+ video.start();
+
int count = video.width * video.height;
//println(count);
@@ -49,9 +48,6 @@ void setup() {
letters[i] = letterOrder.charAt(index);
}
- // current characters for each position in the video
- chars = new char[count];
-
// current brightness for each point
bright = new float[count];
for (int i = 0; i < count; i++) {
@@ -87,7 +83,7 @@ void draw() {
pushMatrix();
for (int x = 0; x < video.width; x++) {
int pixelColor = video.pixels[index];
- // Faster method of calculating r, g, b than red(), green(), blue()
+ // Faster method of calculating r, g, b than red(), green(), blue()
int r = (pixelColor >> 16) & 0xff;
int g = (pixelColor >> 8) & 0xff;
int b = pixelColor & 0xff;
@@ -105,7 +101,7 @@ void draw() {
fill(pixelColor);
int num = int(bright[index]);
text(letters[num], 0, 0);
-
+
// Move to the next pixel
index++;
diff --git a/examples/Capture/GettingStartedCapture/GettingStartedCapture.pde b/examples/Capture/GettingStartedCapture/GettingStartedCapture.pde
index af86a5a..29f1d3a 100644
--- a/examples/Capture/GettingStartedCapture/GettingStartedCapture.pde
+++ b/examples/Capture/GettingStartedCapture/GettingStartedCapture.pde
@@ -26,12 +26,14 @@ void setup() {
// The camera can be initialized directly using an element
// from the array returned by list():
cam = new Capture(this, cameras[0]);
- // Or, the settings can be defined based on the text in the list
- //cam = new Capture(this, 640, 480, "Built-in iSight", 30);
-
- // Start capturing the images from the camera
- cam.start();
+
+ // Or, the camera name can be retrieved from the list (you need
+ // to enter valid a width, height, and frame rate for the camera).
+ //cam = new Capture(this, 640, 480, "FaceTime HD Camera (Built-in)", 30);
}
+
+ // Start capturing the images from the camera
+ cam.start();
}
void draw() {
diff --git a/library.properties b/library.properties
index cb25752..fe32250 100644
--- a/library.properties
+++ b/library.properties
@@ -4,7 +4,7 @@ url = http://processing.org/reference/libraries/video/index.html
category = Video & Vision
sentence = GStreamer-based video library for Processing.
paragraph =
-version = 9
-prettyVersion = 2.1
+version = 12
+prettyVersion = 2.2.2
minRevision = 1281
maxRevision = 0
diff --git a/library/.gitignore b/library/.gitignore
deleted file mode 100644
index 374cc6c..0000000
--- a/library/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-video.jar
diff --git a/library/jna.jar b/library/jna.jar
old mode 100755
new mode 100644
index af5dd08..77f8c7a
Binary files a/library/jna.jar and b/library/jna.jar differ
diff --git a/scripts/macosx_gstreamer_install.sh b/scripts/macosx_gstreamer_install.sh
index a4c9ec5..7d137bd 100755
--- a/scripts/macosx_gstreamer_install.sh
+++ b/scripts/macosx_gstreamer_install.sh
@@ -1,55 +1,22 @@
#!/bin/bash
-# This script downloads the GStreamer image with separate package to install
-# only those needed by Processing:
-# https://gstreamer.freedesktop.org/documentation/deploying/mac-osx.html?gi-language=c#deploy-only-necessary-packages-using-the-provided-ones
+# This script downloads the latest GStreamer universal runtime package
-GST_VERSION=${1:-1.18.0}
-INSTALL_PACKAGES=0 # version 1.16.0 does not yet have a package image
+GST_VERSION=${1:-1.20.3}
GST_PKG_URL="https://gstreamer.freedesktop.org/data/pkg/osx"
DOWNLOAD_PATH="."
TARGET_PATH="/"
CURRENT_PATH=`pwd`
-if [ $INSTALL_PACKAGES -eq 1 ]
-then
- echo "PACKAGES INSTALL..."
+echo "FULL INSTALL..."
- SRC_FILE="$GST_PKG_URL/$GST_VERSION/gstreamer-1.0-$GST_VERSION-x86_64-packages.dmg"
- DEST_FILE="$DOWNLOAD_PATH/gstreamer-1.0-$GST_VERSION-x86_64-packages.dmg"
+SRC_FILE="$GST_PKG_URL/$GST_VERSION/gstreamer-1.0-$GST_VERSION-universal.pkg"
+DEST_FILE="$DOWNLOAD_PATH/gstreamer-1.0-$GST_VERSION-universal.pkg"
- curl $SRC_FILE --output $DEST_FILE
+curl $SRC_FILE --output $DEST_FILE
- sudo hdiutil attach $DOWNLOAD_PATH/gstreamer-1.0-$GST_VERSION-x86_64-packages.dmg
- cd /Volumes/hdidir
+sudo installer -pkg $DOWNLOAD_PATH/gstreamer-1.0-$GST_VERSION-universal.pkg -target $TARGET_PATH
- sudo installer -pkg base-system-1.0-${GST_VERSION}-x86_64.pkg -target $TARGET_PATH
- sudo installer -pkg base-crypto-${GST_VERSION}-x86_64.pkg -target $TARGET_PATH
- sudo installer -pkg gstreamer-1.0-system-${GST_VERSION}-x86_64.pkg -target $TARGET_PATH
- sudo installer -pkg gstreamer-1.0-core-${GST_VERSION}-x86_64.pkg -target $TARGET_PATH
- sudo installer -pkg gstreamer-1.0-playback-${GST_VERSION}-x86_64.pkg -target $TARGET_PATH
- sudo installer -pkg gstreamer-1.0-capture-${GST_VERSION}-x86_64.pkg -target $TARGET_PATH
- sudo installer -pkg gstreamer-1.0-codecs-${GST_VERSION}-x86_64.pkg -target $TARGET_PATH
- sudo installer -pkg gstreamer-1.0-libav-${GST_VERSION}-x86_64.pkg -target $TARGET_PATH
- sudo installer -pkg gstreamer-1.0-net-${GST_VERSION}-x86_64.pkg -target $TARGET_PATH
- sudo installer -pkg gstreamer-1.0-editing-${GST_VERSION}-x86_64.pkg -target $TARGET_PATH
+rm $DOWNLOAD_PATH/gstreamer-1.0-$GST_VERSION-universal.pkg
- cd $CURRENT_PATH
- hdiutil detach /Volumes/hdidir
- rm $DOWNLOAD_PATH/gstreamer-1.0-$GST_VERSION-x86_64-packages.dmg
-
- echo "DONE..."
-else
- echo "FULL INSTALL..."
-
- SRC_FILE="$GST_PKG_URL/$GST_VERSION/gstreamer-1.0-$GST_VERSION-x86_64.pkg"
- DEST_FILE="$DOWNLOAD_PATH/gstreamer-1.0-$GST_VERSION-x86_64.pkg"
-
- curl $SRC_FILE --output $DEST_FILE
-
- sudo installer -pkg $DOWNLOAD_PATH/gstreamer-1.0-$GST_VERSION-x86_64.pkg -target $TARGET_PATH
-
- rm $DOWNLOAD_PATH/gstreamer-1.0-$GST_VERSION-x86_64.pkg
-
- echo "DONE..."
-fi
\ No newline at end of file
+echo "DONE..."
\ No newline at end of file
diff --git a/scripts/macosx_remove_extra_libs.py b/scripts/macosx_remove_extra_libs.py
index 73474b8..640c7ea 100755
--- a/scripts/macosx_remove_extra_libs.py
+++ b/scripts/macosx_remove_extra_libs.py
@@ -12,7 +12,7 @@
import subprocess
import re
-lib_folder = '../library/macosx'
+lib_folder = '../library/macos-universal'
# First, remove libraries from packages we don't bundle with the video library:
# gstreamer-1.0-codecs-gpl
diff --git a/scripts/pack_linux_libs.sh b/scripts/pack_linux_libs.sh
new file mode 100755
index 0000000..e19a4d8
--- /dev/null
+++ b/scripts/pack_linux_libs.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Set the appropriate build dist folder in this env variable
+meson_build_folder=/home/andres/code/gstreamer/build-1.20/lib/x86_64-linux-gnu
+
+# Copy the build to the native library folder for linux
+mkdir ../library/linux-amd64
+cp -a ${meson_build_folder}/* ../library/linux-amd64
+
+# Remove static .a libs
+rm -r ../library/linux-amd64/*.a
+
+# Remove unncessary folders
+rm -r ../library/linux-amd64/cairo
+rm -r ../library/linux-amd64/cmake
+rm -r ../library/linux-amd64/gio
+rm -r ../library/linux-amd64/glib-2.0
+rm -r ../library/linux-amd64/gst-validate-launcher
+rm -r ../library/linux-amd64/pkgconfig
+rm -r ../library/linux-amd64/gstreamer-1.0/validate
\ No newline at end of file
diff --git a/scripts/pack_macosx_libs.sh b/scripts/pack_macosx_libs.sh
index 8d34ffb..3b2c997 100755
--- a/scripts/pack_macosx_libs.sh
+++ b/scripts/pack_macosx_libs.sh
@@ -19,25 +19,54 @@ else
fi
gst_folder=/Library/Frameworks/GStreamer.framework/Versions/1.0/lib
-lib_folder=../library/macosx
+lib_folder_univ=../library/macos-universal
+lib_folder_x86_64=../library/macos-x86_64
+lib_folder_aarch64=../library/macos-aarch64
echo "Copying base gstreamer libs..."
-mkdir -p ${lib_folder}
-cp ${gst_folder}/*.dylib ${lib_folder}
+mkdir -p ${lib_folder_univ}
+cp ${gst_folder}/*.dylib ${lib_folder_univ}
echo "Relocating dependencies in base libs..."
-./macosx_relocator.py ${lib_folder} ${dep_path} "@loader_path/"
+./macosx_relocator.py ${lib_folder_univ} ${dep_path} "@loader_path/"
echo "Copying gstreamer plugins..."
-mkdir -p ${lib_folder}/gstreamer-1.0
-cp ${gst_folder}/gstreamer-1.0/* ${lib_folder}/gstreamer-1.0
+mkdir -p ${lib_folder_univ}/gstreamer-1.0
+cp ${gst_folder}/gstreamer-1.0/* ${lib_folder_univ}/gstreamer-1.0
-# Silence runtime error from these plugins
-rm -f ${lib_folder}/gstreamer-1.0/libgsthls.so
-rm -f ${lib_folder}/gstreamer-1.0/libgstopenjpeg.so
+# Remove plugins that give runtime errors:
+rm -f ${lib_folder_univ}/gstreamer-1.0/libgstsrt.dylib
+rm -f ${lib_folder_univ}/gstreamer-1.0/libgstsrtp.dylib
+
+# These seem okay now (with GStreamer 1.20.x)
+# rm -f ${lib_folder_univ}/gstreamer-1.0/libgsthls.so
+# rm -f ${lib_folder_univ}/gstreamer-1.0/libgstopenjpeg.so
echo "Relocating dependencies in gstreamer plugins..."
-./macosx_relocator.py ${lib_folder}/gstreamer-1.0 ${dep_path} "@loader_path/../"
+./macosx_relocator.py ${lib_folder_univ}/gstreamer-1.0 ${dep_path} "@loader_path/../"
echo "Removing unused dependencies..."
-./macosx_remove_extra_libs.py
\ No newline at end of file
+./macosx_remove_extra_libs.py
+
+echo "Extracting x86_64 and aarch64 native libraries..."
+
+mkdir -p ${lib_folder_x86_64}
+mkdir -p ${lib_folder_aarch64}
+for file in ${lib_folder_univ}/*.dylib; do
+ fn="$(basename ${file})"
+ lipo ${file} -thin x86_64 -output ${lib_folder_x86_64}/${fn};
+ lipo ${file} -thin arm64 -output ${lib_folder_aarch64}/${fn};
+done
+
+mkdir -p ${lib_folder_x86_64}/gstreamer-1.0
+mkdir -p ${lib_folder_aarch64}/gstreamer-1.0
+for file in ${lib_folder_univ}/gstreamer-1.0/*.dylib; do
+ fn="$(basename ${file})"
+ lipo ${file} -thin x86_64 -output ${lib_folder_x86_64}/gstreamer-1.0/${fn};
+ lipo ${file} -thin arm64 -output ${lib_folder_aarch64}/gstreamer-1.0/${fn};
+done
+
+echo "Removing universal native libraries..."
+rm -rf ${lib_folder_univ}
+
+echo "Done."
\ No newline at end of file
diff --git a/scripts/pack_windows_libs.bat b/scripts/pack_windows_libs.bat
old mode 100644
new mode 100755
index 063a09c..0844b4c
--- a/scripts/pack_windows_libs.bat
+++ b/scripts/pack_windows_libs.bat
@@ -1,46 +1,11 @@
-SET gst_folder=C:\gstreamer
-SET gst_toolchain=
-SET lib_folder=..\library
-
-echo "Copying base gstreamer libs..."
-md %lib_folder%\windows64 %lib_folder%\windows32
-copy %gst_folder%\1.0\%gst_toolchain%x86_64\bin\*.dll %lib_folder%\windows64
-copy %gst_folder%\1.0\%gst_toolchain%x86\bin\*.dll %lib_folder%\windows32
-
-echo "Copying gstreamer plugins..."
-md %lib_folder%\windows64\gstreamer-1.0 %lib_folder%\windows32\gstreamer-1.0
-copy %gst_folder%\1.0\%gst_toolchain%x86_64\lib\gstreamer-1.0\*.dll %lib_folder%\windows64\gstreamer-1.0
-copy %gst_folder%\1.0\%gst_toolchain%x86\lib\gstreamer-1.0\*.dll %lib_folder%\windows32\gstreamer-1.0
-
-echo "Remove broken plugins..."
-del %lib_folder%\windows64\gstreamer-1.0\libgsta52dec.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstamrnb.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstamrwbdec.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstassrender.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstdtsdec.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstdvdread.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstges.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstlibvisual.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstmms.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstresindvd.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstrtmp.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstsoundtouch.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstvoaacenc.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstwebrtcdsp.dll /f
-del %lib_folder%\windows64\gstreamer-1.0\libgstx264.dll /f
-
-del %lib_folder%\windows32\gstreamer-1.0\libgsta52dec.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstamrnb.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstamrwbdec.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstassrender.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstdtsdec.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstdvdread.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstges.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstlibvisual.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstmms.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstresindvd.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstrtmp.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstsoundtouch.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstvoaacenc.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstwebrtcdsp.dll /f
-del %lib_folder%\windows32\gstreamer-1.0\libgstx264.dll /f
\ No newline at end of file
+SET gst_folder=C:\gstreamer
+SET gst_toolchain=msvc
+SET lib_folder=..\library
+
+echo "Copying base gstreamer libs..."
+md %lib_folder%\windows-amd64
+copy %gst_folder%\1.0\%gst_toolchain%_x86_64\bin\*.dll %lib_folder%\windows-amd64
+
+echo "Copying gstreamer plugins..."
+md %lib_folder%\windows-amd64\gstreamer-1.0
+copy %gst_folder%\1.0\%gst_toolchain%_x86_64\lib\gstreamer-1.0\*.dll %lib_folder%\windows-amd64\gstreamer-1.0
diff --git a/src/processing/video/Capture.java b/src/processing/video/Capture.java
index a302227..844e87b 100755
--- a/src/processing/video/Capture.java
+++ b/src/processing/video/Capture.java
@@ -30,6 +30,7 @@
import processing.core.*;
import java.nio.*;
+import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -104,7 +105,7 @@ public class Capture extends PImage implements PConstants {
*/
public Capture(PApplet parent) {
// Attempt to use a default resolution
- this(parent, 640, 480, null, 0);
+ this(parent, 640, 480, null, 30);
}
@@ -116,7 +117,7 @@ public Capture(PApplet parent) {
*/
public Capture(PApplet parent, String device) {
// Attempt to use a default resolution
- this(parent, 640, 480, device, 0);
+ this(parent, 640, 480, device, 30);
}
@@ -126,7 +127,7 @@ public Capture(PApplet parent, String device) {
* @param height height in pixels
*/
public Capture(PApplet parent, int width, int height) {
- this(parent, width, height, null, 0);
+ this(parent, width, height, null, 30);
}
@@ -144,7 +145,16 @@ public Capture(PApplet parent, int width, int height, float fps) {
* @see Capture#list()
*/
public Capture(PApplet parent, int width, int height, String device) {
- this(parent, width, height, device, 0);
+ this(parent, width, height, device, 30);
+ }
+
+
+ /**
+ * Open a specific capture device with a given framerate
+ * @see Capture#list()
+ */
+ public Capture(PApplet parent, String device, float fps) {
+ this(parent, 640, 480, device, fps);
}
@@ -177,9 +187,11 @@ public void dispose() {
pixels = null;
- rgbSink.disconnect(newSampleListener);
- rgbSink.disconnect(newPrerollListener);
- rgbSink.dispose();
+ if (rgbSink != null) {
+ rgbSink.disconnect(newSampleListener);
+ rgbSink.disconnect(newPrerollListener);
+ rgbSink.dispose();
+ }
pipeline.setState(org.freedesktop.gstreamer.State.NULL);
pipeline.getState();
pipeline.getBus().dispose();
@@ -492,9 +504,8 @@ protected void initDevicePipeline() {
}
for (int i=0; i < devices.size(); i++) {
- String deviceName = assignDisplayName(devices.get(i), i);
+ String deviceName = assignDisplayName(devices.get(i), i);
if (devices.get(i).getDisplayName().equals(device) || devices.get(i).getName().equals(device) || deviceName.equals(device)) {
- // Found device
srcElement = devices.get(i).createElement(null);
break;
}
@@ -516,14 +527,24 @@ protected void initDevicePipeline() {
if (frameRate != 0.0) {
frameRateString = ", framerate=" + fpsToFramerate(frameRate);
} else {
- frameRateString = "";
+ System.err.println("The capture framerate cannot be zero!");
+ return;
}
+
capsfilter.set("caps", Caps.fromString("video/x-raw, width=" + width + ", height=" + height + frameRateString));
initSink();
- pipeline.addMany(srcElement, videoscale, videoconvert, capsfilter, rgbSink);
- Element.linkMany(srcElement, videoscale, videoconvert, capsfilter, rgbSink);
+ pipeline.add(srcElement);
+ pipeline.add(videoscale);
+ pipeline.add(videoconvert);
+ pipeline.add(capsfilter);
+ pipeline.add(rgbSink);
+
+ srcElement.link(videoscale);
+ videoscale.link(videoconvert);
+ videoconvert.link(capsfilter);
+ capsfilter.link(rgbSink);
makeBusConnections(pipeline.getBus());
}
@@ -717,24 +738,117 @@ public synchronized void post() {
* Multiple devices can have identical display names, appending ' #n' to devices
* with duplicate display names.
* @return array of device names
+ * @webref capture
+ * @webBrief Get a list of all capture device names
*/
static public String[] list() {
- Video.init();
+ Video.init();
+
+ String[] out;
+
+ DeviceMonitor monitor = new DeviceMonitor();
+ monitor.addFilter("Video/Source", null);
+ devices = monitor.getDevices();
+ monitor.close();
+
+ out = new String[devices.size()];
+ for (int i = 0; i < devices.size(); i++) {
+ Device dev = devices.get(i);
+ out[i] = checkCameraDuplicates(dev) > 1 ? assignDisplayName(dev, i) : dev.getDisplayName();
+ }
+
+ return out;
+ }
+
+ // This is a temporary addition until it's decided how to bring back resolution/framerate caps to the official API.
+ // The old way of doing things is still listed in the video tutorial:
+ // https://processing.org/tutorials/video
+ static public String[] getCapabilities(String device) {
+ for (int i=0; i < devices.size(); i++) {
+ String deviceName = assignDisplayName(devices.get(i), i);
+ if (devices.get(i).getDisplayName().equals(device) || devices.get(i).getName().equals(device) || deviceName.equals(device)) {
+ return parseCaps(devices.get(i));
+ }
+ }
+ return new String[]{};
+ }
+
+ static private String[] parseCaps(Device dev) {
+ String[] caps = dev.getCaps().toString().split(";");
+ ArrayList devCaps = new ArrayList();
- String[] out;
+ for (String cap: caps) {
+ if (cap.indexOf("video/x-raw,") == -1) continue; // Looking for raw caps (excluding GLMemory stuff)
- DeviceMonitor monitor = new DeviceMonitor();
- monitor.addFilter("Video/Source", null);
- devices = monitor.getDevices();
- monitor.close();
+ int indexWidth = cap.indexOf("width");
+ int indexHeight = cap.indexOf("height");
+ int indexFramerate = cap.indexOf("framerate");
- out = new String[devices.size()];
- for (int i = 0; i < devices.size(); i++) {
- Device dev = devices.get(i);
- out[i] = checkCameraDuplicates(dev) > 1 ? assignDisplayName(dev, i) : dev.getDisplayName();
- }
+ String stringWidth = "";
+ String stringHeight = "";
+ String stringFramerate = "";
- return out;
+ if (0 < indexWidth && 0 < indexHeight && 0 < indexFramerate) {
+ stringWidth = cap.substring(indexWidth, cap.indexOf(',', indexWidth));
+ stringHeight = cap.substring(indexHeight, cap.indexOf(", format", indexHeight));
+ stringFramerate = cap.substring(indexFramerate, cap.indexOf(']', indexFramerate));
+ }
+// PApplet.println("=======>", cap);
+ if (0 < stringHeight.indexOf("{")) {
+ // A list of heights... something like "height=(int){ 448, 600 }
+ stringHeight = stringHeight.substring(13, stringHeight.length() - 1);
+ String[] values = stringHeight.split(",");
+ for (String value: values) {
+ stringHeight = "height=(int)" + value.trim();
+ addCapStringsToList(stringWidth, stringHeight, stringFramerate, devCaps);
+ }
+ } else {
+ addCapStringsToList(stringWidth, stringHeight, stringFramerate, devCaps);
+ }
+ }
+
+ String[] out = new String[0];
+ return devCaps.toArray(out);
+ }
+
+ static private void addCapStringsToList(String stringWidth, String stringHeight, String stringFramerate, ArrayList devCaps) {
+ if (0 < stringWidth.split("=").length) { // Expecting a string of the form "width=(int)1600"
+ stringWidth = stringWidth.substring(11);
+ try {
+ Integer.parseInt(stringWidth);
+ } catch (NumberFormatException ex) {
+ stringHeight = "";
+ }
+ }
+ if (0 < stringHeight.split("=").length) { // Expecting a string of the form "height=(int)896"
+ stringHeight = stringHeight.substring(12);
+ try {
+ Integer.parseInt(stringHeight);
+ } catch (NumberFormatException ex) {
+ stringHeight = "";
+ }
+ }
+ if (0 < stringFramerate.split("=,").length) { // Expecting a string of the form "framerate=(fraction)[ 5/1, 10000000/333333"
+ stringFramerate = stringFramerate.substring(stringFramerate.indexOf("="));
+ String[] fpsParts = stringFramerate.split(",");
+ if (1 < fpsParts.length) {
+ stringFramerate = fpsParts[1].trim();
+ fpsParts = stringFramerate.split("/");
+ if (fpsParts.length == 2) {
+ try {
+ int fpsNumerator = Integer.parseInt(fpsParts[0]);
+ int fpsDenominator = Integer.parseInt(fpsParts[1]);
+ int fps = fpsNumerator / fpsDenominator;
+ stringFramerate = String.valueOf(fps);
+ } catch (NumberFormatException ex) {
+ stringFramerate = "";
+ }
+ }
+ }
+ }
+ if (!stringWidth.equals("") && !stringHeight.equals("") && !stringFramerate.equals("")) {
+ devCaps.add("size=" + stringWidth + "x" + stringHeight + ",fps=" + stringFramerate);
+ }
}
static private String assignDisplayName(Device d, int pos) {
diff --git a/src/processing/video/LibraryLoader.java b/src/processing/video/LibraryLoader.java
index 9f89310..62649db 100755
--- a/src/processing/video/LibraryLoader.java
+++ b/src/processing/video/LibraryLoader.java
@@ -1,351 +1,527 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2012-22 The Processing Foundation
- Copyright (c) 2011-12 Ben Fry and Casey Reas
- GStreamer implementation ported from GSVideo library by Andres Colubri
- Library loader based on code by Tal Shalif
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General
- Public License along with this library; if not, write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- Boston, MA 02111-1307 USA
-*/
-
-package processing.video;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import com.sun.jna.Library;
-import com.sun.jna.Native;
-import com.sun.jna.Platform;
-
-/**
- * This class loads the gstreamer native libraries.
- *
- */
-public class LibraryLoader {
-
- public interface DummyLibrary extends Library {
- }
-
- private static LibraryLoader instance;
-
- static final Object[][] WINDOWS_DEPENDENCIES = {
- // Core GStreamer libraries
- { "libgstadaptivedemux-1.0-0", new String[] {}, false },
- { "libgstallocators-1.0-0", new String[] {}, false },
- { "libgstapp-1.0-0", new String[] {}, false },
- { "libgstaudio-1.0-0", new String[] {}, false },
- { "libgstbadaudio-1.0-0", new String[] {}, false },
- { "libgstbase-1.0-0", new String[] {}, false },
- { "libgstbasecamerabinsrc-1.0-0", new String[] {}, false },
- { "libgstcheck-1.0-0", new String[] {}, false },
- { "libgstcodecparsers-1.0-0", new String[] {}, false },
- { "libgstcontroller-1.0-0", new String[] {}, false },
- { "libgstfft-1.0-0", new String[] {}, false },
- { "libgstgl-1.0-0", new String[] {}, false },
- { "libgstinsertbin-1.0-0", new String[] {}, false },
- { "libgstisoff-1.0-0", new String[] {}, false },
- { "libgstmpegts-1.0-0", new String[] {}, false },
- { "libgstnet-1.0-0", new String[] {}, false },
- { "libgstpbutils-1.0-0", new String[] {}, false },
- { "libgstphotography-1.0-0", new String[] {}, false },
- { "libgstplayer-1.0-0", new String[] {}, false },
- { "libgstreamer-1.0-0", new String[] {}, false },
- { "libgstriff-1.0-0", new String[] {}, false },
- { "libgstrtp-1.0-0", new String[] {}, false },
- { "libgstrtsp-1.0-0", new String[] {}, false },
- { "libgstrtspserver-1.0-0", new String[] {}, false },
- { "libgstsctp-1.0-0", new String[] {}, false },
- { "libgstsdp-1.0-0", new String[] {}, false },
- { "libgsttag-1.0-0", new String[] {}, false },
- { "libgsturidownloader-1.0-0", new String[] {}, false },
- { "libgstvideo-1.0-0", new String[] {}, false },
- { "libgstwebrtc-1.0-0", new String[] {}, false },
-
- // External libraries
- { "libbz2", new String[] {}, false },
- { "libcairo-2", new String[] {}, false },
- { "libcairo-gobject-2", new String[] {}, false },
- { "libcairo-script-interpreter-2", new String[] {}, false },
- { "libcroco-0.6-3", new String[] {}, false },
- { "libcrypto-1_1-x64", new String[] {}, false },
- { "libdv-4", new String[] {}, false },
- { "libexpat-1", new String[] {}, false },
- { "libffi-7", new String[] {}, false },
- { "libFLAC-8", new String[] {}, false },
- { "libfontconfig-1", new String[] {}, false },
- { "libfreetype-6", new String[] {}, false },
- { "libfribidi-0", new String[] {}, false },
- { "libgcc_s_sjlj-1", new String[] {}, false },
- { "libgdk_pixbuf-2.0-0", new String[] {}, false },
- { "libgio-2.0-0", new String[] {}, false },
- { "libglib-2.0-0", new String[] {}, false },
- { "libgmodule-2.0-0", new String[] {}, false },
- { "libgmp-10", new String[] {}, false },
- { "libgnutls-30", new String[] {}, false },
- { "libgnutlsxx-28", new String[] {}, false },
- { "libgobject-2.0-0", new String[] {}, false },
- { "libgomp-1", new String[] {}, false },
- { "libgraphene-1.0-0", new String[] {}, false },
- { "libgthread-2.0-0", new String[] {}, false },
- { "libharfbuzz-0", new String[] {}, false },
- { "libhogweed-4", new String[] {}, false },
- { "libintl-8", new String[] {}, false },
- { "libjpeg-8", new String[] {}, false },
- { "libjson-glib-1.0-0", new String[] {}, false },
- { "libkate-1", new String[] {}, false },
- { "libmp3lame-0", new String[] {}, false },
- { "libmpg123-0", new String[] {}, false },
- { "libnettle-6", new String[] {}, false },
- { "libnice-10", new String[] {}, false },
- { "libogg-0", new String[] {}, false },
- { "liboggkate-1", new String[] {}, false },
- { "libopenh264", new String[] {}, false },
- { "libopenjp2", new String[] {}, false },
- { "libopus-0", new String[] {}, false },
- { "liborc-0.4-0", new String[] {}, false },
- { "liborc-test-0.4-0", new String[] {}, false },
- { "libpango-1.0-0", new String[] {}, false },
- { "libpangocairo-1.0-0", new String[] {}, false },
- { "libpangoft2-1.0-0", new String[] {}, false },
- { "libpangowin32-1.0-0", new String[] {}, false },
- { "libpixman-1-0", new String[] {}, false },
- { "libpng16-16", new String[] {}, false },
- { "librsvg-2-2", new String[] {}, false },
- { "libsbc-1", new String[] {}, false },
- { "libsoup-2.4-1", new String[] {}, false },
- { "libspandsp-2", new String[] {}, false },
- { "libspeex-1", new String[] {}, false },
- { "libsrt", new String[] {}, false },
- { "libsrtp", new String[] {}, false },
- { "libssl-1_1-x64", new String[] {}, false },
- { "libstdc++-6", new String[] {}, false },
- { "libtag", new String[] {}, false },
- { "libtasn1-6", new String[] {}, false },
- { "libtheora-0", new String[] {}, false },
- { "libtheoradec-1", new String[] {}, false },
- { "libtheoraenc-1", new String[] {}, false },
- { "libtiff-5", new String[] {}, false },
- { "libturbojpeg-0", new String[] {}, false },
- { "libusrsctp-1", new String[] {}, false },
- { "libvorbis-0", new String[] {}, false },
- { "libvorbisenc-2", new String[] {}, false },
- { "libvorbisfile-3", new String[] {}, false },
- { "libwavpack-1", new String[] {}, false },
- { "libwinpthread-1", new String[] {}, false },
- { "libxml2-2", new String[] {}, false },
- { "libz-1", new String[] {}, false },
- { "avcodec-58", new String[] {}, false },
- { "avfilter-7", new String[] {}, false },
- { "avformat-58", new String[] {}, false },
- { "avutil-56", new String[] {}, false },
- { "swresample-3", new String[] {}, false }
- };
-
- static final Object[][] LINUX_DEPENDENCIES = {
- // GLib libraries
- { "glib-2.0", new String[] {}, false },
- { "gobject-2.0", new String[] {}, false },
- { "gio-2.0", new String[] {}, false },
- { "gmodule-2.0", new String[] {}, false },
- { "gthread-2.0", new String[] {}, false },
-
- // Core GStreamer libraries
- { "gstreamer-1.0", new String[] {}, false },
- { "gstbase-1.0", new String[] {}, false },
- { "gsturidownloader-1.0", new String[] {}, false },
- { "gstadaptivedemux-1.0", new String[] {}, false },
- { "gstapp-1.0", new String[] {}, false },
- { "gsttag-1.0", new String[] {}, false },
- { "gstvideo-1.0", new String[] {}, false },
- { "gstaudio-1.0", new String[] {}, false },
- { "gstpbutils-1.0", new String[] {}, false },
- { "gstplayer-1.0", new String[] {}, false },
- { "gstbadaudio-1.0", new String[] {}, false },
- { "gstbasecamerabinsrc-1.0", new String[] {}, false },
- { "gstcheck-1.0", new String[] {}, false },
- { "gstcodecparsers-1.0", new String[] {}, false },
- { "gstcontroller-1.0", new String[] {}, false },
- { "gstfft-1.0", new String[] {}, false },
- { "gstinsertbin-1.0", new String[] {}, false },
- { "gstisoff-1.0", new String[] {}, false },
- { "gstmpegts-1.0", new String[] {}, false },
- { "gstnet-1.0", new String[] {}, false },
- { "gstphotography-1.0", new String[] {}, false },
- { "gstallocators-1.0", new String[] {}, false },
- { "gstriff-1.0", new String[] {}, false },
- { "gstrtp-1.0", new String[] {}, false },
- { "gstrtsp-1.0", new String[] {}, false },
- { "gstsdp-1.0", new String[] {}, false },
- { "gstsctp-1.0", new String[] {}, false },
- { "gstrtspserver-1.0", new String[] {}, false },
- { "gstvalidate-1.0", new String[] {}, false },
- { "gstvalidate-default-overrides-1.0", new String[] {}, false },
- { "gstwebrtc-1.0", new String[] {}, false },
-
- // External libraries
- { "avutil", new String[] {}, false },
- { "swresample", new String[] {}, false },
- { "swscale", new String[] {}, false },
- { "avcodec", new String[] {}, false },
- { "avformat", new String[] {}, false },
- { "avresample", new String[] {}, false },
- { "avfilter", new String[] {}, false },
- { "avdevice", new String[] {}, false },
- { "ges-1.0", new String[] {}, false },
- { "json-glib-1.0", new String[] {}, false },
- { "nice", new String[] {}, false },
- { "x264", new String[] {}, false },
- { "openh264", new String[] {}, false },
- { "orc-0.4", new String[] {}, false },
- { "orc-test-0.4", new String[] {}, false },
- { "postproc", new String[] {}, false }
- };
-
- static final Object[][] MACOS_DEPENDENCIES = { };
-
- static final Object[][] DEFAULT_DEPENDENCIES = { };
-
- static final Object[][] dependencies =
- Platform.isWindows() ? WINDOWS_DEPENDENCIES :
- Platform.isLinux() ? LINUX_DEPENDENCIES :
- Platform.isMac() ? MACOS_DEPENDENCIES : DEFAULT_DEPENDENCIES;
-
-
- private static final Map loadedMap =
- new HashMap<>();
-
-
- private static final int RECURSIVE_LOAD_MAX_DEPTH = 5;
-
-
- private LibraryLoader() {
- }
-
-
- private void preLoadLibs() {
- for (Object[] a : dependencies) {
- load(a[0].toString(), DummyLibrary.class, true, 0, (Boolean) a[2]);
- }
- }
-
-
- static private String[] findDeps(String name) {
-
- for (Object[] a : dependencies) {
- if (name.equals(a[0])) {
-
- return (String[]) a[1];
- }
- }
-
- // library dependency load chain unspecified - probably client call
- return new String[] { };
- }
-
-
- public Object load(String name, Class> clazz, boolean reqLib) {
- return load(name, clazz, true, 0, reqLib);
- }
-
-
- private Object load(String name, Class> clazz, boolean forceReload,
- int depth, boolean reqLib) {
-
- assert depth < RECURSIVE_LOAD_MAX_DEPTH : String.format(
- "recursive max load depth %s has been exceeded", depth);
-
- Object library = loadedMap.get(name);
-
- if (null == library || forceReload) {
-
- // Logger.getAnonymousLogger().info(String.format("%" + ((depth + 1) * 2)
- // + "sloading %s", "->", name));
-
- try {
- String[] deps = findDeps(name);
-
- for (String lib : deps) {
- load(lib, DummyLibrary.class, false, depth + 1, reqLib);
- }
-
- library = loadLibrary(name, clazz, reqLib);
-
- if (library != null) {
- loadedMap.put(name, library);
- }
- } catch (Exception e) {
- if (reqLib)
- throw new RuntimeException(String.format(
- "can not load required library %s", name, e));
- else
- System.out.println(String.format("can not load library %s", name, e));
- }
- }
-
- return library;
- }
-
-
- private static Object loadLibrary(String name, Class> clazz,
- boolean reqLib) {
-
- // Logger.getAnonymousLogger().info(String.format("loading %s", name));
-
- String[] nameFormats;
- nameFormats = Platform.isWindows() ? new String[] { "lib%s", "lib%s-0",
- "%s" } : new String[] { "%s-0", "%s" };
-
- UnsatisfiedLinkError linkError = null;
-
- for (String fmt : nameFormats) {
- try {
- String s = String.format(fmt, name);
- //System.out.println("Trying to load library file " + s);
- Object obj = Native.loadLibrary(s, clazz);
- //System.out.println("Loaded library " + s + " successfully!");
- return obj;
- } catch (UnsatisfiedLinkError ex) {
- linkError = ex;
- }
- }
-
- if (reqLib)
- throw new UnsatisfiedLinkError(
- String.format(
- "can't load library %s (%1$s|lib%1$s|lib%1$s-0) with " +
- "-Djna.library.path=%s. Last error:%s",
- name, System.getProperty("jna.library.path"), linkError));
- else {
- System.out.println(String.format(
- "can't load library %s (%1$s|lib%1$s|lib%1$s-0) with " +
- "-Djna.library.path=%s. Last error:%s",
- name, System.getProperty("jna.library.path"), linkError));
- return null;
- }
- }
-
-
- public static synchronized LibraryLoader getInstance() {
- if (null == instance) {
- instance = new LibraryLoader();
- instance.preLoadLibs();
- }
- return instance;
- }
-}
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2012-22 The Processing Foundation
+ Copyright (c) 2011-12 Ben Fry and Casey Reas
+ GStreamer implementation ported from GSVideo library by Andres Colubri
+ Library loader based on code by Tal Shalif
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ Boston, MA 02111-1307 USA
+*/
+
+package processing.video;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.sun.jna.Library;
+import com.sun.jna.Native;
+import com.sun.jna.Platform;
+
+/**
+ * This class loads the gstreamer native libraries.
+ *
+ */
+public class LibraryLoader {
+
+ public interface DummyLibrary extends Library {
+ }
+
+ private static LibraryLoader instance;
+
+ static final Object[][] WINDOWS_MINGW_DEPENDENCIES = {
+ // Base GStreamer native libraries for a COMPLETE MINGW installation
+ { "avcodec-58", new String[] {}, false },
+ { "avfilter-7", new String[] {}, false },
+ { "avformat-58", new String[] {}, false },
+ { "avutil-56", new String[] {}, false },
+ { "libass-9", new String[] {}, false },
+ { "libbz2", new String[] {}, false },
+ { "libcairo-2", new String[] {}, false },
+ { "libcairo-gobject-2", new String[] {}, false },
+ { "libcairo-script-interpreter-2", new String[] {}, false },
+ { "libcharset-1", new String[] {}, false },
+ { "libcroco-0.6-3", new String[] {}, false },
+ { "libcrypto-1_1-x64", new String[] {}, false },
+ { "libdca-0", new String[] {}, false },
+ { "libdv-4", new String[] {}, false },
+ { "libexpat-1", new String[] {}, false },
+ { "libffi-7", new String[] {}, false },
+ { "libFLAC-8", new String[] {}, false },
+ { "libfontconfig-1", new String[] {}, false },
+ { "libfreetype-6", new String[] {}, false },
+ { "libfribidi-0", new String[] {}, false },
+ { "libgcc_s_seh-1", new String[] {}, false },
+ { "libgdk_pixbuf-2.0-0", new String[] {}, false },
+ { "libges-1.0-0", new String[] {}, false },
+ { "libgio-2.0-0", new String[] {}, false },
+ { "libglib-2.0-0", new String[] {}, false },
+ { "libgmodule-2.0-0", new String[] {}, false },
+ { "libgobject-2.0-0", new String[] {}, false },
+ { "libgraphene-1.0-0", new String[] {}, false },
+ { "libgstadaptivedemux-1.0-0", new String[] {}, false },
+ { "libgstallocators-1.0-0", new String[] {}, false },
+ { "libgstapp-1.0-0", new String[] {}, false },
+ { "libgstaudio-1.0-0", new String[] {}, false },
+ { "libgstbadaudio-1.0-0", new String[] {}, false },
+ { "libgstbase-1.0-0", new String[] {}, false },
+ { "libgstbasecamerabinsrc-1.0-0", new String[] {}, false },
+ { "libgstcheck-1.0-0", new String[] {}, false },
+ { "libgstcodecparsers-1.0-0", new String[] {}, false },
+ { "libgstcodecs-1.0-0", new String[] {}, false },
+ { "libgstcontroller-1.0-0", new String[] {}, false },
+ { "libgstd3d11-1.0-0", new String[] {}, false },
+ { "libgstfft-1.0-0", new String[] {}, false },
+ { "libgstgl-1.0-0", new String[] {}, false },
+ { "libgstinsertbin-1.0-0", new String[] {}, false },
+ { "libgstisoff-1.0-0", new String[] {}, false },
+ { "libgstmpegts-1.0-0", new String[] {}, false },
+ { "libgstnet-1.0-0", new String[] {}, false },
+ { "libgstpbutils-1.0-0", new String[] {}, false },
+ { "libgstphotography-1.0-0", new String[] {}, false },
+ { "libgstplay-1.0-0", new String[] {}, false },
+ { "libgstplayer-1.0-0", new String[] {}, false },
+ { "libgstreamer-1.0-0", new String[] {}, false },
+ { "libgstriff-1.0-0", new String[] {}, false },
+ { "libgstrtp-1.0-0", new String[] {}, false },
+ { "libgstrtsp-1.0-0", new String[] {}, false },
+ { "libgstrtspserver-1.0-0", new String[] {}, false },
+ { "libgstsctp-1.0-0", new String[] {}, false },
+ { "libgstsdp-1.0-0", new String[] {}, false },
+ { "libgsttag-1.0-0", new String[] {}, false },
+ { "libgsttranscoder-1.0-0", new String[] {}, false },
+ { "libgsturidownloader-1.0-0", new String[] {}, false },
+ { "libgstvalidate-1.0-0", new String[] {}, false },
+ { "libgstvideo-1.0-0", new String[] {}, false },
+ { "libgstwebrtc-1.0-0", new String[] {}, false },
+ { "libgthread-2.0-0", new String[] {}, false },
+ { "libharfbuzz-0", new String[] {}, false },
+ { "libiconv-2", new String[] {}, false },
+ { "libintl-8", new String[] {}, false },
+ { "libjpeg-8", new String[] {}, false },
+ { "libjson-glib-1.0-0", new String[] {}, false },
+ { "libkate-1", new String[] {}, false },
+ { "libmp3lame-0", new String[] {}, false },
+ { "libmpg123-0", new String[] {}, false },
+ { "libnice-10", new String[] {}, false },
+ { "libogg-0", new String[] {}, false },
+ { "liboggkate-1", new String[] {}, false },
+ { "libopencore-amrnb-0", new String[] {}, false },
+ { "libopencore-amrwb-0", new String[] {}, false },
+ { "libopenh264-6", new String[] {}, false },
+ { "libopenjp2", new String[] {}, false },
+ { "libopus-0", new String[] {}, false },
+ { "liborc-0.4-0", new String[] {}, false },
+ { "liborc-test-0.4-0", new String[] {}, false },
+ { "libpango-1.0-0", new String[] {}, false },
+ { "libpangocairo-1.0-0", new String[] {}, false },
+ { "libpangoft2-1.0-0", new String[] {}, false },
+ { "libpangowin32-1.0-0", new String[] {}, false },
+ { "libpixman-1-0", new String[] {}, false },
+ { "libpng16-16", new String[] {}, false },
+ { "libpsl-5", new String[] {}, false },
+ { "librsvg-2-2", new String[] {}, false },
+ { "librtmp-1", new String[] {}, false },
+ { "libsbc-1", new String[] {}, false },
+ { "libSoundTouch-1", new String[] {}, false },
+ { "libsoup-2.4-1", new String[] {}, false },
+ { "libspandsp-2", new String[] {}, false },
+ { "libspeex-1", new String[] {}, false },
+ { "libsqlite3-0", new String[] {}, false },
+ { "libsrt", new String[] {}, false },
+ { "libsrtp2-1", new String[] {}, false },
+ { "libssl-1_1-x64", new String[] {}, false },
+ { "libstdc++-6", new String[] {}, false },
+ { "libtag", new String[] {}, false },
+ { "libtheora-0", new String[] {}, false },
+ { "libtheoradec-1", new String[] {}, false },
+ { "libtheoraenc-1", new String[] {}, false },
+ { "libtiff-5", new String[] {}, false },
+ { "libturbojpeg-0", new String[] {}, false },
+ { "libvo-aacenc-0", new String[] {}, false },
+ { "libvorbis-0", new String[] {}, false },
+ { "libvorbisenc-2", new String[] {}, false },
+ { "libvorbisfile-3", new String[] {}, false },
+ { "libwavpack", new String[] {}, false },
+ { "libwebrtc_audio_processing-0", new String[] {}, false },
+ { "libwinpthread-1", new String[] {}, false },
+ { "libx264-157", new String[] {}, false },
+ { "libxml2-2", new String[] {}, false },
+ { "libz-1", new String[] {}, false },
+ { "libzbar-0", new String[] {}, false },
+ { "swresample-3", new String[] {}, false }
+ };
+
+ static final Object[][] WINDOWS_MSVC_DEPENDENCIES = {
+ // Base GStreamer native libraries for a COMPLETE MSVC installation
+ { "avcodec-58", new String[] {}, false },
+ { "avfilter-7", new String[] {}, false },
+ { "avformat-58", new String[] {}, false },
+ { "avutil-56", new String[] {}, false },
+ { "bz2", new String[] {}, false },
+ { "cairo-2", new String[] {}, false },
+ { "cairo-gobject-2", new String[] {}, false },
+ { "cairo-script-interpreter-2", new String[] {}, false },
+ { "dv-4", new String[] {}, false },
+ { "ffi-7", new String[] {}, false },
+ { "fontconfig-1", new String[] {}, false },
+ { "fribidi-0", new String[] {}, false },
+ { "gdk_pixbuf-2.0-0", new String[] {}, false },
+ { "ges-1.0-0", new String[] {}, false },
+ { "gio-2.0-0", new String[] {}, false },
+ { "glib-2.0-0", new String[] {}, false },
+ { "gmodule-2.0-0", new String[] {}, false },
+ { "gobject-2.0-0", new String[] {}, false },
+ { "graphene-1.0-0", new String[] {}, false },
+ { "gstadaptivedemux-1.0-0", new String[] {}, false },
+ { "gstallocators-1.0-0", new String[] {}, false },
+ { "gstapp-1.0-0", new String[] {}, false },
+ { "gstaudio-1.0-0", new String[] {}, false },
+ { "gstbadaudio-1.0-0", new String[] {}, false },
+ { "gstbase-1.0-0", new String[] {}, false },
+ { "gstbasecamerabinsrc-1.0-0", new String[] {}, false },
+ { "gstcheck-1.0-0", new String[] {}, false },
+ { "gstcodecparsers-1.0-0", new String[] {}, false },
+ { "gstcodecs-1.0-0", new String[] {}, false },
+ { "gstcontroller-1.0-0", new String[] {}, false },
+ { "gstd3d11-1.0-0", new String[] {}, false },
+ { "gstfft-1.0-0", new String[] {}, false },
+ { "gstgl-1.0-0", new String[] {}, false },
+ { "gstinsertbin-1.0-0", new String[] {}, false },
+ { "gstisoff-1.0-0", new String[] {}, false },
+ { "gstmpegts-1.0-0", new String[] {}, false },
+ { "gstnet-1.0-0", new String[] {}, false },
+ { "gstpbutils-1.0-0", new String[] {}, false },
+ { "gstphotography-1.0-0", new String[] {}, false },
+ { "gstplay-1.0-0", new String[] {}, false },
+ { "gstplayer-1.0-0", new String[] {}, false },
+ { "gstreamer-1.0-0", new String[] {}, false },
+ { "gstriff-1.0-0", new String[] {}, false },
+ { "gstrtp-1.0-0", new String[] {}, false },
+ { "gstrtsp-1.0-0", new String[] {}, false },
+ { "gstrtspserver-1.0-0", new String[] {}, false },
+ { "gstsctp-1.0-0", new String[] {}, false },
+ { "gstsdp-1.0-0", new String[] {}, false },
+ { "gsttag-1.0-0", new String[] {}, false },
+ { "gsttranscoder-1.0-0", new String[] {}, false },
+ { "gsturidownloader-1.0-0", new String[] {}, false },
+ { "gstvalidate-1.0-0", new String[] {}, false },
+ { "gstvideo-1.0-0", new String[] {}, false },
+ { "gstwebrtc-1.0-0", new String[] {}, false },
+ { "gstwinrt-1.0-0", new String[] {}, false },
+ { "gthread-2.0-0", new String[] {}, false },
+ { "harfbuzz", new String[] {}, false },
+ { "intl-8", new String[] {}, false },
+ { "json-glib-1.0-0", new String[] {}, false },
+ { "libass-9", new String[] {}, false },
+ { "libcharset-1", new String[] {}, false },
+ { "libcroco-0.6-3", new String[] {}, false },
+ { "libcrypto-1_1-x64", new String[] {}, false },
+ { "libdca-0", new String[] {}, false },
+ { "libexpat-1", new String[] {}, false },
+ { "libFLAC-8", new String[] {}, false },
+ { "libfreetype-6", new String[] {}, false },
+ { "libgcc_s_seh-1", new String[] {}, false },
+ { "libiconv-2", new String[] {}, false },
+ { "libjpeg-8", new String[] {}, false },
+ { "libkate-1", new String[] {}, false },
+ { "libmp3lame-0", new String[] {}, false },
+ { "libmpg123-0", new String[] {}, false },
+ { "libogg-0", new String[] {}, false },
+ { "liboggkate-1", new String[] {}, false },
+ { "libopencore-amrnb-0", new String[] {}, false },
+ { "libopencore-amrwb-0", new String[] {}, false },
+ { "libpng16-16", new String[] {}, false },
+ { "librsvg-2-2", new String[] {}, false },
+ { "librtmp-1", new String[] {}, false },
+ { "libsbc-1", new String[] {}, false },
+ { "libspandsp-2", new String[] {}, false },
+ { "libspeex-1", new String[] {}, false },
+ { "libsrt", new String[] {}, false },
+ { "libssl-1_1-x64", new String[] {}, false },
+ { "libstdc++-6", new String[] {}, false },
+ { "libtheora-0", new String[] {}, false },
+ { "libtheoradec-1", new String[] {}, false },
+ { "libtheoraenc-1", new String[] {}, false },
+ { "libtiff-5", new String[] {}, false },
+ { "libturbojpeg-0", new String[] {}, false },
+ { "libvo-aacenc-0", new String[] {}, false },
+ { "libvorbis-0", new String[] {}, false },
+ { "libvorbisenc-2", new String[] {}, false },
+ { "libvorbisfile-3", new String[] {}, false },
+ { "libwinpthread-1", new String[] {}, false },
+ { "libx264-157", new String[] {}, false },
+ { "libxml2-2", new String[] {}, false },
+ { "libzbar-0", new String[] {}, false },
+ { "nice-10", new String[] {}, false },
+ { "openh264-6", new String[] {}, false },
+ { "openjp2", new String[] {}, false },
+ { "opus-0", new String[] {}, false },
+ { "orc-0.4-0", new String[] {}, false },
+ { "orc-test-0.4-0", new String[] {}, false },
+ { "pango-1.0-0", new String[] {}, false },
+ { "pangocairo-1.0-0", new String[] {}, false },
+ { "pangoft2-1.0-0", new String[] {}, false },
+ { "pangowin32-1.0-0", new String[] {}, false },
+ { "pixman-1-0", new String[] {}, false },
+ { "psl-5", new String[] {}, false },
+ { "soup-2.4-1", new String[] {}, false },
+ { "sqlite3-0", new String[] {}, false },
+ { "srtp2-1", new String[] {}, false },
+ { "swresample-3", new String[] {}, false },
+ { "wavpack", new String[] {}, false },
+ { "z-1", new String[] {}, false }
+ };
+
+ static final Object[][] LINUX_DEPENDENCIES = {
+ // Base GStreamer native libraries from a meson build
+
+ // GLib libraries
+ { "glib-2.0", new String[] {}, false },
+ { "gobject-2.0", new String[] {}, false },
+ { "gio-2.0", new String[] {}, false },
+ { "gmodule-2.0", new String[] {}, false },
+ { "gthread-2.0", new String[] {}, false },
+
+ // Core GStreamer libraries... the order of these libraries is important (while it does
+ // not seem to matter for Windows. For example, if gstbase comes before gstreamer, then
+ // plugin scanning crashes with "cannot register existing type 'GstObject'" error
+ { "gstreamer-1.0", new String[] {}, false },
+ { "gstbase-1.0", new String[] {}, false },
+ { "gsturidownloader-1.0", new String[] {}, false },
+ { "gstadaptivedemux-1.0", new String[] {}, false },
+ { "gstapp-1.0", new String[] {}, false },
+ { "gsttag-1.0", new String[] {}, false },
+ { "gstvideo-1.0", new String[] {}, false },
+ { "gstaudio-1.0", new String[] {}, false },
+ { "gstpbutils-1.0", new String[] {}, false },
+ { "gstplay-1.0", new String[] {}, false },
+ { "gstplayer-1.0", new String[] {}, false },
+ { "gstbadaudio-1.0", new String[] {}, false },
+ { "gstbasecamerabinsrc-1.0", new String[] {}, false },
+ { "gstcheck-1.0", new String[] {}, false },
+ { "gstcodecparsers-1.0", new String[] {}, false },
+ { "gstcontroller-1.0", new String[] {}, false },
+ { "gstfft-1.0", new String[] {}, false },
+ { "gstinsertbin-1.0", new String[] {}, false },
+ { "gstisoff-1.0", new String[] {}, false },
+ { "gstmpegts-1.0", new String[] {}, false },
+ { "gstnet-1.0", new String[] {}, false },
+ { "gstphotography-1.0", new String[] {}, false },
+ { "gstallocators-1.0", new String[] {}, false },
+ { "libgstcodecs-1.0", new String[] {}, false },
+ { "gstriff-1.0", new String[] {}, false },
+ { "gstrtp-1.0", new String[] {}, false },
+ { "gstrtsp-1.0", new String[] {}, false },
+ { "gstsdp-1.0", new String[] {}, false },
+ { "gstsctp-1.0", new String[] {}, false },
+ { "gstrtspserver-1.0", new String[] {}, false },
+ { "gstvalidate-1.0", new String[] {}, false },
+ { "gstvalidate-default-overrides-1.0", new String[] {}, false },
+ { "gstwebrtc-1.0", new String[] {}, false },
+ { "gsttranscoder-1.0", new String[] {}, false },
+
+ // External libraries
+ { "xml2", new String[] {}, false },
+ { "avutil", new String[] {}, false },
+ { "swresample", new String[] {}, false },
+ { "swscale", new String[] {}, false },
+ { "avcodec", new String[] {}, false },
+ { "avformat", new String[] {}, false },
+ { "avresample", new String[] {}, false },
+ { "avfilter", new String[] {}, false },
+ { "avdevice", new String[] {}, false },
+ { "avtp", new String[] {}, false },
+ { "cairo-gobject", new String[] {}, false },
+ { "cairo-script-interpreter", new String[] {}, false },
+ { "cairo", new String[] {}, false },
+ { "dv", new String[] {}, false },
+ { "fdk_aac", new String[] {}, false },
+ { "fontconfig", new String[] {}, false },
+ { "freetype", new String[] {}, false },
+ { "fribidi", new String[] {}, false },
+ { "ges-1.0", new String[] {}, false },
+ { "harfbuzz-gobject", new String[] {}, false },
+ { "harfbuzz", new String[] {}, false },
+ { "harfbuzz-subset", new String[] {}, false },
+ { "jpeg", new String[] {}, false },
+ { "json-glib-1.0", new String[] {}, false },
+ { "microdns", new String[] {}, false },
+ { "mp3lame", new String[] {}, false },
+ { "nice", new String[] {}, false },
+ { "ogg", new String[] {}, false },
+ { "openh264", new String[] {}, false },
+ { "openjp2", new String[] {}, false },
+ { "opus", new String[] {}, false },
+ { "orc-0.4", new String[] {}, false },
+ { "orc-test-0.4", new String[] {}, false },
+ { "pango-1.0", new String[] {}, false },
+ // { "pangocairo-1.0", new String[] {}, false }, // Seems broken in 1.20.3
+ { "pangoft2-1.0", new String[] {}, false },
+ { "pixman-1", new String[] {}, false },
+ { "png16", new String[] {}, false },
+ { "postproc", new String[] {}, false },
+ { "psl", new String[] {}, false },
+ { "soup-2.4", new String[] {}, false },
+ { "soup-gnome-2.4", new String[] {}, false },
+ { "sqlite3", new String[] {}, false },
+ { "vorbisenc", new String[] {}, false },
+ { "vorbisfile", new String[] {}, false },
+ { "vorbis", new String[] {}, false }
+};
+
+ static Object[][] dependencies;
+
+
+ private static final Map loadedMap =
+ new HashMap<>();
+
+
+ private static final int RECURSIVE_LOAD_MAX_DEPTH = 5;
+
+
+ private LibraryLoader() {
+ }
+
+
+ private void preLoadLibs(int winBuildType) {
+ if (Platform.isWindows()) {
+ if (winBuildType == 0) {
+ System.err.println("Seems like you are trying to use GStreamer native libraries older than 1.20, which are not supported.");
+ return;
+ } else if (winBuildType == 1) {
+ dependencies = WINDOWS_MINGW_DEPENDENCIES;
+ } else if (winBuildType == 2) {
+ dependencies = WINDOWS_MSVC_DEPENDENCIES;
+ }
+
+ } else if (Platform.isLinux()) {
+ dependencies = LINUX_DEPENDENCIES;
+ } else {
+ // No need for dependencies pre-loading on MacOS
+ return;
+ }
+
+ for (Object[] a : dependencies) {
+ load(a[0].toString(), DummyLibrary.class, true, 0, (Boolean) a[2]);
+ }
+ }
+
+
+ static private String[] findDeps(String name) {
+ for (Object[] a : dependencies) {
+ if (name.equals(a[0])) {
+ return (String[]) a[1];
+ }
+ }
+
+ // library dependency load chain unspecified - probably client call
+ return new String[] { };
+ }
+
+
+ public Object load(String name, Class> clazz, boolean reqLib) {
+ return load(name, clazz, true, 0, reqLib);
+ }
+
+
+ private Object load(String name, Class> clazz, boolean forceReload,
+ int depth, boolean reqLib) {
+
+ assert depth < RECURSIVE_LOAD_MAX_DEPTH : String.format(
+ "recursive max load depth %s has been exceeded", depth);
+
+ Object library = loadedMap.get(name);
+
+ if (null == library || forceReload) {
+
+ // Logger.getAnonymousLogger().info(String.format("%" + ((depth + 1) * 2)
+ // + "sloading %s", "->", name));
+
+ try {
+ String[] deps = findDeps(name);
+
+ for (String lib : deps) {
+ load(lib, DummyLibrary.class, false, depth + 1, reqLib);
+ }
+
+ library = loadLibrary(name, clazz, reqLib);
+
+ if (library != null) {
+ loadedMap.put(name, library);
+ }
+ } catch (Exception e) {
+ if (reqLib)
+ throw new RuntimeException(String.format(
+ "can not load required library %s", name, e));
+ else
+ System.out.println(String.format("can not load library %s", name, e));
+ }
+ }
+
+ return library;
+ }
+
+
+ private static Object loadLibrary(String name, Class> clazz,
+ boolean reqLib) {
+
+ // Logger.getAnonymousLogger().info(String.format("loading %s", name));
+
+ String[] nameFormats;
+ nameFormats = Platform.isWindows() ? new String[] { "lib%s", "lib%s-0",
+ "%s" } : new String[] { "%s-0", "%s" };
+
+ UnsatisfiedLinkError linkError = null;
+
+ for (String fmt : nameFormats) {
+ try {
+ String s = String.format(fmt, name);
+ //System.out.println("Trying to load library file " + s);
+ Object obj = Native.loadLibrary(s, clazz);
+ //System.out.println("Loaded library " + s + " successfully!");
+ return obj;
+ } catch (UnsatisfiedLinkError ex) {
+ linkError = ex;
+ }
+ }
+
+ if (reqLib)
+ throw new UnsatisfiedLinkError(
+ String.format(
+ "can't load library %s (%1$s|lib%1$s|lib%1$s-0) with " +
+ "-Djna.library.path=%s. Last error:%s",
+ name, System.getProperty("jna.library.path"), linkError));
+ else {
+ System.out.println(String.format(
+ "can't load library %s (%1$s|lib%1$s|lib%1$s-0) with " +
+ "-Djna.library.path=%s. Last error:%s",
+ name, System.getProperty("jna.library.path"), linkError));
+ return null;
+ }
+ }
+
+
+ public static synchronized LibraryLoader getInstance(int winBuildType) {
+ if (null == instance) {
+ instance = new LibraryLoader();
+ instance.preLoadLibs(winBuildType);
+ }
+ return instance;
+ }
+}
diff --git a/src/processing/video/Movie.java b/src/processing/video/Movie.java
index 644b905..4ace469 100755
--- a/src/processing/video/Movie.java
+++ b/src/processing/video/Movie.java
@@ -53,7 +53,7 @@
* @usage application
*/
public class Movie extends PImage implements PConstants {
- public static String[] supportedProtocols = { "http" };
+ public static String[] supportedProtocols = { "http", "https" };
public String filename;
public PlayBin playbin;
diff --git a/src/processing/video/Video.java b/src/processing/video/Video.java
index 4918de3..fd138b3 100755
--- a/src/processing/video/Video.java
+++ b/src/processing/video/Video.java
@@ -1,398 +1,424 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2012-22 The Processing Foundation
- Copyright (c) 2011-12 Ben Fry and Casey Reas
- GStreamer implementation ported from GSVideo library by Andres Colubri
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General
- Public License along with this library; if not, write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- Boston, MA 02111-1307 USA
-*/
-
-package processing.video;
-
-import org.freedesktop.gstreamer.*;
-import processing.core.PApplet;
-import processing.core.PConstants;
-
-import java.io.File;
-import java.nio.ByteOrder;
-import java.nio.file.Paths;
-import java.util.List;
-
-/**
- * This class contains some basic functions used by the rest of the classes in
- * this library.
- */
-public class Video implements PConstants {
- // Allows to set the amount of desired debug output from GStreamer, according to the following table:
- // https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html?gi-language=c#printing-debug-information
- public static int DEBUG_LEVEL = 1;
-
- // Path that the video library will use to load the GStreamer base libraries
- // and plugins from. They can be passed from the application using the
- // gstreamer.library.path and gstreamer.plugin.path system variables (see
- // comments in initImpl() below).
- public static String gstreamerLibPath = "";
- public static String gstreamerPluginPath = "";
-
- protected static boolean usingGStreamerSystemInstall = false;
-
- // OpenGL texture used as buffer sink by default, when the renderer is
- // GL-based. This can improve performance significantly, since the video
- // frames are automatically copied into the texture without passing through
- // the pixels arrays, as well as having the color conversion into RGBA handled
- // natively by GStreamer.
- protected static boolean useGLBufferSink = true;
-
- protected static boolean defaultGLibContext = false;
-
- protected static long INSTANCES_COUNT = 0;
-
- protected static int bitsJVM;
- static {
- bitsJVM = PApplet.parseInt(System.getProperty("sun.arch.data.model"));
- }
-
-
- static protected void init() {
- if (INSTANCES_COUNT == 0) {
- initImpl();
- }
- INSTANCES_COUNT++;
- }
-
-
- static protected void restart() {
- removePlugins();
- Gst.deinit();
- initImpl();
- }
-
-
- static protected void initImpl() {
- // The video library loads the GStreamer libraries according to the following
- // priority:
- // 1) If the VM argument "gstreamer.library.path" exists, it will use it as the
- // root location of the libraries. This is typically the case when running
- // the library from Eclipse.
- // 2) If the environmental variable is GSTREAMER_1_0_ROOT_X86(_64) is defined then
- // will try to use its contents as the root path of the system install of GStreamer.
- // 3) The bundled version of GStreamer will be used, if present.
- // 4) If none of the above works, then will try to use default install locations of GStreamer
- // on Windows and Mac, if they exist.
- // In this way, priority is given to the system installation of GStreamer only if set in the
- // environmental variables, otherwise will try to load the bundled GStreamer, and if it does not
- // exist it will look for GStreamer in the system-wide locations. This gives the user the option
- // to remove the bundled GStreamer libs to default to the system-wide installation.
- String libPath = System.getProperty("gstreamer.library.path");
- if (libPath != null) {
- gstreamerLibPath = libPath;
-
- // If the GStreamer installation referred by gstreamer.library.path is not
- // a system installation, then the path containing the plugins needs to be
- // specified separately, otherwise the plugins will be automatically
- // loaded from the default location. The system property for the plugin
- // path is "gstreamer.plugin.path"
- String pluginPath = System.getProperty("gstreamer.plugin.path");
- if (pluginPath != null) {
- gstreamerPluginPath = pluginPath;
- }
-
- usingGStreamerSystemInstall = false;
- } else {
- String rootPath = "";
- if (bitsJVM == 64 && System.getenv("GSTREAMER_1_0_ROOT_X86_64") != null) {
- // Get 64-bit root of GStreamer install
- rootPath = System.getenv("GSTREAMER_1_0_ROOT_X86_64");
- } else if (bitsJVM == 32 && System.getenv("GSTREAMER_1_0_ROOT_X86") != null) {
- // Get 32-bit root of GStreamer install
- rootPath = System.getenv("GSTREAMER_1_0_ROOT_X86");
- }
-
- if (!rootPath.equals("")) {
- if (PApplet.platform == MACOS) {
- gstreamerLibPath = Paths.get(rootPath, "lib").toString();
- } else {
- gstreamerLibPath = Paths.get(rootPath, "bin").toString();
- }
- File path = new File(gstreamerLibPath);
- if (path.exists()) {
- // We have a system install of GStreamer
- usingGStreamerSystemInstall = true;
- buildSystemPaths(rootPath);
- } else {
- // The environmental variables contain invalid paths...
- gstreamerLibPath = "";
- }
- }
- }
-
- if (libPath == null && !usingGStreamerSystemInstall) {
- // No GStreamer path in the VM arguments, and not system-wide install in environmental variables,
- // will try searching for the bundled GStreamer libs.
- buildBundldedPaths();
- }
-
- if (gstreamerLibPath.equals("")) {
- // Finally, no environmental variables defined and did not find bundled gstreamer,
- // will try some default system-wide locations.
- String rootPath = "";
- if (PApplet.platform == MACOS) {
- rootPath = "/Library/Frameworks/GStreamer.framework/Versions/1.0";
- gstreamerLibPath = Paths.get(rootPath, "lib").toString();
- } else if (PApplet.platform == WINDOWS) {
- if (bitsJVM == 64) {
- rootPath = "C:\\gstreamer\\1.0\\x86_64";
- } else {
- rootPath = "C:\\gstreamer\\1.0\\x86";
- }
- gstreamerLibPath = Paths.get(rootPath, "bin").toString();
- } else if (PApplet.platform == LINUX) {
- if (bitsJVM == 64) {
- rootPath = "/lib/x86_64-linux-gnu";
- } else {
- rootPath = "/lib/x86-linux-gnu";
- }
- File gstlib = new File(rootPath, "libgstreamer-1.0.so.0");
- if (gstlib.exists()) {
- gstreamerLibPath = Paths.get(rootPath).toString();
- }
- }
-
- File path = new File(gstreamerLibPath);
- if (path.exists()) {
- // We have a system install of GStreamer
- if (bitsJVM == 64) {
- Environment.libc.setenv("GSTREAMER_1_0_ROOT_X86_64", gstreamerLibPath, true);
- } else {
- Environment.libc.setenv("GSTREAMER_1_0_ROOT_X86", gstreamerLibPath, true);
- }
- buildSystemPaths(rootPath);
- } else {
- System.err.println("We could not find a system-wide or bundled installation of GStreamer, but video might still work if GStreamer was placed somewhere else");
- }
- usingGStreamerSystemInstall = true;
- }
-
- if (!gstreamerLibPath.equals("")) {
- // Should be safe because this is setting the jna.library.path,
- // not java.library.path, and JNA is being provided by the video library.
- // This will need to change if JNA is ever moved into more of a shared
- // location (i.e. part of core) because this would overwrite the prop.
- System.setProperty("jna.library.path", gstreamerLibPath);
- }
-
- Environment.libc.setenv("GST_DEBUG", String.valueOf(DEBUG_LEVEL), true);
-
- if (!usingGStreamerSystemInstall) {
- // Disable the use of gst-plugin-scanner on environments where we're
- // not using the host system's installation of GStreamer
- // the problem with gst-plugin-scanner is that the library expects it
- // to exist at a specific location determined at build time
- Environment.libc.setenv("GST_REGISTRY_FORK", "no", true);
-
- // Prevent globally installed libraries from being used on platforms
- // where we ship GStreamer
- if (!gstreamerPluginPath.equals("")) {
- Environment.libc.setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", true);
- }
- }
-
- if (!usingGStreamerSystemInstall && (PApplet.platform == WINDOWS || PApplet.platform == LINUX)) {
- // Pre-loading base GStreamer libraries on Windows and Linux,
- // otherwise dynamic dependencies cannot be resolved.
- LibraryLoader loader = LibraryLoader.getInstance();
- if (loader == null) {
- System.err.println("Cannot load GStreamer libraries.");
- }
- }
-
- String[] args = { "" };
- Gst.setUseDefaultContext(defaultGLibContext);
- Gst.init("Processing core video", args);
-
- if (!usingGStreamerSystemInstall) {
- // Plugins are scanned explicitly from the bindings if using the
- // local GStreamer
- addPlugins();
- }
-
- // output GStreamer version, lib path, plugin path
- // and whether a system install is being used
- printGStreamerInfo();
- }
-
- static protected void printGStreamerInfo() {
- String locInfo = "";
- if (usingGStreamerSystemInstall) locInfo = "system-wide";
- else locInfo = "bundled";
- System.out.println("Processing video library using " + locInfo + " GStreamer " + Gst.getVersion());
- }
-
-
- static protected void addPlugins() {
- if (!gstreamerPluginPath.equals("")) {
- Registry reg = Registry.get();
- boolean res;
- res = reg.scanPath(gstreamerPluginPath);
- if (!res) {
- System.err.println("Cannot load GStreamer plugins from " + gstreamerPluginPath);
- }
- }
- }
-
-
- static protected void removePlugins() {
- Registry reg = Registry.get();
- List list = reg.getPluginList();
- for (Plugin plg : list) {
- reg.removePlugin(plg);
- }
- }
-
-
- /**
- * Search for an item by checking folders listed in java.library.path
- * for a specific name.
- */
- @SuppressWarnings("SameParameterValue")
- static private String searchLibraryPath(String what) {
- String libraryPath = System.getProperty("java.library.path");
- // Should not be null, but cannot assume
- if (libraryPath != null) {
- String[] folders = PApplet.split(libraryPath, File.pathSeparatorChar);
- // Usually, the most relevant paths will be at the front of the list,
- // so hopefully this will not walk several entries.
- for (String folder : folders) {
- // Skip /lib and /usr/lib folders because they contain the system-wide GStreamer on Linux
- // and they are on the Java library path.
- if (folder.startsWith("/lib/") || folder.startsWith("/usr/lib/")) continue;
- File file = new File(folder, what);
- if (file.exists()) {
- return file.getAbsolutePath();
- }
- }
- }
- return null;
- }
-
-
- /**
- * Search for an item by checking folders listed in java.class.path
- * for a specific name.
- */
- @SuppressWarnings("SameParameterValue")
- static private String searchClassPath(String what) {
- String classPath = System.getProperty("java.class.path");
- // Should not be null, but cannot assume
- if (classPath != null) {
- String[] entries = PApplet.split(classPath, File.pathSeparatorChar);
- // Usually, the most relevant paths will be at the front of the list,
- // so hopefully this will not walk several entries.
- for (String entry : entries) {
- File dir = new File(entry);
- // If it's a .jar file, get its parent folder. This will lead to some
- // double-checking of the same folder, but probably almost as expensive
- // to keep track of folders we've already seen.
- if (dir.isFile()) {
- dir = dir.getParentFile();
- }
- File file = new File(dir, what);
- if (file.exists()) {
- return file.getAbsolutePath();
- }
- }
- }
- return null;
- }
-
- static protected void buildSystemPaths(String rootPath) {
- if (System.getenv("GST_PLUGIN_SYSTEM_PATH") != null) {
- gstreamerPluginPath = System.getenv("GST_PLUGIN_SYSTEM_PATH");
- } else {
- if (PApplet.platform == WINDOWS) {
- gstreamerPluginPath = Paths.get(rootPath, "lib", "gstreamer-1.0").toString();
- } else {
- gstreamerPluginPath = Paths.get(gstreamerLibPath, "gstreamer-1.0").toString(); }
- }
- File path = new File(gstreamerPluginPath);
- if (!path.exists()) {
- gstreamerPluginPath = "";
- }
- }
-
- static protected void buildBundldedPaths() {
- // look for the gstreamer-1.0 folder in the native library path
- // (there are natives adjacent to it, so this will work)
- gstreamerPluginPath = searchLibraryPath("gstreamer-1.0");
- if (gstreamerPluginPath == null) {
- gstreamerPluginPath = searchClassPath("gstreamer-1.0");
- }
-
- if (gstreamerPluginPath == null) {
- gstreamerPluginPath = "";
- gstreamerLibPath = "";
- usingGStreamerSystemInstall = true;
- } else {
- File gstreamerLibDir = new File(gstreamerPluginPath).getParentFile();
- gstreamerLibPath = gstreamerLibDir.getAbsolutePath();
- }
- }
-
-
- static protected float nanoSecToSecFrac(long nanosec) {
- return (float)(nanosec / 1E9);
- }
-
-
- static protected long secToNanoLong(float sec) {
- Double f = Double.valueOf(sec * 1E9);
- return f.longValue();
- }
-
-
- /**
- * Reorders an OpenGL pixel array (RGBA) into ARGB. The array must be
- * of size width * height.
- * @param pixels int[]
- */
- static protected void convertToARGB(int[] pixels, int width, int height) {
- int t = 0;
- int p = 0;
- if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
- // RGBA to ARGB conversion: shifting RGB 8 bits to the right,
- // and placing A 24 bits to the left.
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- int pixel = pixels[p++];
- pixels[t++] = (pixel >>> 8) | ((pixel << 24) & 0xFF000000);
- }
- }
- } else {
- // We have to convert ABGR into ARGB, so R and B must be swapped,
- // A and G just brought back in.
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- int pixel = pixels[p++];
- pixels[t++] = ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) |
- (pixel & 0xFF00FF00);
- }
- }
- }
- }
-}
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2012-22 The Processing Foundation
+ Copyright (c) 2011-12 Ben Fry and Casey Reas
+ GStreamer implementation ported from GSVideo library by Andres Colubri
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ Boston, MA 02111-1307 USA
+*/
+
+package processing.video;
+
+import org.freedesktop.gstreamer.*;
+import processing.core.PApplet;
+import processing.core.PConstants;
+
+import java.io.File;
+import java.nio.ByteOrder;
+import java.nio.file.Paths;
+import java.util.List;
+
+/**
+ * This class contains some basic functions used by the rest of the classes in
+ * this library.
+ */
+public class Video implements PConstants {
+ // Allows to set the amount of desired debug output from GStreamer, according to the following table:
+ // https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html?gi-language=c#printing-debug-information
+ public static int DEBUG_LEVEL = 1;
+
+ // Path that the video library will use to load the GStreamer base libraries
+ // and plugins from. They can be passed from the application using the
+ // gstreamer.library.path and gstreamer.plugin.path system variables (see
+ // comments in initImpl() below).
+ public static String gstreamerLibPath = "";
+ public static String gstreamerPluginPath = "";
+
+ protected static boolean usingGStreamerSystemInstall = false;
+
+ // OpenGL texture used as buffer sink by default, when the renderer is
+ // GL-based. This can improve performance significantly, since the video
+ // frames are automatically copied into the texture without passing through
+ // the pixels arrays, as well as having the color conversion into RGBA handled
+ // natively by GStreamer.
+ protected static boolean useGLBufferSink = true;
+
+ protected static boolean defaultGLibContext = false;
+
+ protected static long INSTANCES_COUNT = 0;
+
+ protected static int bitsJVM;
+ static {
+ bitsJVM = PApplet.parseInt(System.getProperty("sun.arch.data.model"));
+ }
+
+
+ static protected void init() {
+ if (INSTANCES_COUNT == 0) {
+ initImpl();
+ }
+ INSTANCES_COUNT++;
+ }
+
+
+ static protected void restart() {
+ removePlugins();
+ Gst.deinit();
+ initImpl();
+ }
+
+
+ static protected void initImpl() {
+ // The video library loads the GStreamer libraries according to the following
+ // priority:
+ // 1) If the VM argument "gstreamer.library.path" exists, it will use it as the
+ // root location of the libraries. This is typically the case when running
+ // the library from Eclipse.
+ // 2) If the environmental variable is GSTREAMER_1_0_ROOT_(MINGW/MSVC)_64 is defined then
+ // will try to use its contents as the root path of the system install of GStreamer.
+ // 3) The bundled version of GStreamer will be used, if present.
+ // 4) If none of the above works, then will try to use default install locations of GStreamer
+ // on Windows and Mac, if they exist.
+ // In this way, priority is given to the system installation of GStreamer only if set in the
+ // environmental variables, otherwise will try to load the bundled GStreamer, and if it does not
+ // exist it will look for GStreamer in the system-wide locations. This gives the user the option
+ // to remove the bundled GStreamer libs to default to the system-wide installation.
+ String libPath = System.getProperty("gstreamer.library.path");
+ int winBuildType = 0; // 0: default build, 1: mingw, 2: msvc
+ if (libPath != null) {
+ gstreamerLibPath = libPath;
+
+ // If the GStreamer installation referred by gstreamer.library.path is not
+ // a system installation, then the path containing the plugins needs to be
+ // specified separately, otherwise the plugins will be automatically
+ // loaded from the default location. The system property for the plugin
+ // path is "gstreamer.plugin.path"
+ String pluginPath = System.getProperty("gstreamer.plugin.path");
+ if (pluginPath != null) {
+ gstreamerPluginPath = pluginPath;
+ }
+
+ usingGStreamerSystemInstall = false;
+ } else {
+ String rootPath = "";
+ if (bitsJVM == 64) {
+ // Get 64-bit root of GStreamer install
+ if (System.getenv("GSTREAMER_1_0_ROOT_X86_64") != null) {
+ winBuildType = 0;
+ rootPath = System.getenv("GSTREAMER_1_0_ROOT_X86_64");
+ } else if (System.getenv("GSTREAMER_1_0_ROOT_MINGW_X86_64") != null) {
+ winBuildType = 1;
+ rootPath = System.getenv("GSTREAMER_1_0_ROOT_MINGW_X86_64");
+ } else if (System.getenv("GSTREAMER_1_0_ROOT_MSVC_X86_64") != null) {
+ winBuildType = 2;
+ rootPath = System.getenv("GSTREAMER_1_0_ROOT_MSVC_X86_64");
+ }
+ }
+
+ if (!rootPath.equals("")) {
+ if (PApplet.platform == MACOS) {
+ gstreamerLibPath = Paths.get(rootPath, "lib").toString();
+ } else {
+ gstreamerLibPath = Paths.get(rootPath, "bin").toString();
+ }
+ File path = new File(gstreamerLibPath);
+ if (path.exists()) {
+ // We have a system install of GStreamer
+ usingGStreamerSystemInstall = true;
+ buildSystemPaths(rootPath);
+ } else {
+ // The environmental variables contain invalid paths...
+ gstreamerLibPath = "";
+ }
+ }
+ }
+
+ if (libPath == null && !usingGStreamerSystemInstall) {
+ // No GStreamer path in the VM arguments, and not system-wide install in environmental variables,
+ // will try searching for the bundled GStreamer libs.
+ if (buildBundldedPaths()) {
+ // Found bundled GStreamer libs, which in version 2.2 of the library are MSVC-built:
+ winBuildType = 2;
+ }
+ }
+
+ if (gstreamerLibPath.equals("")) {
+ // Finally, no environmental variables defined and did not find bundled gstreamer,
+ // will try some default system-wide locations.
+ String rootPath = "";
+ if (PApplet.platform == MACOS) {
+ rootPath = "/Library/Frameworks/GStreamer.framework/Versions/1.0";
+ gstreamerLibPath = Paths.get(rootPath, "lib").toString();
+ } else if (PApplet.platform == WINDOWS) {
+ if (bitsJVM == 64) {
+ if (new File("C:\\gstreamer\\1.0\\x86_64").exists()) {
+ winBuildType = 0;
+ rootPath = "C:\\gstreamer\\1.0\\x86_64";
+ } else if (new File("C:\\gstreamer\\1.0\\mingw_x86_64").exists()) {
+ winBuildType = 1;
+ rootPath = "C:\\gstreamer\\1.0\\mingw_x86_64";
+ } else if (new File("C:\\gstreamer\\1.0\\msvc_x86_64").exists()) {
+ winBuildType = 2;
+ rootPath = "C:\\gstreamer\\1.0\\msvc_x86_64";
+ }
+ gstreamerLibPath = Paths.get(rootPath, "bin").toString();
+ }
+ } else if (PApplet.platform == LINUX) {
+ if (bitsJVM == 64) {
+ rootPath = "/lib/x86_64-linux-gnu";
+ } else {
+ rootPath = "/lib/x86-linux-gnu";
+ }
+ File gstlib = new File(rootPath, "libgstreamer-1.0.so.0");
+ if (gstlib.exists()) {
+ gstreamerLibPath = Paths.get(rootPath).toString();
+ }
+ }
+
+ File path = new File(gstreamerLibPath);
+ if (path.exists()) {
+ // We have a system install of GStreamer
+ if (bitsJVM == 64) {
+ if (winBuildType == 0) {
+ Environment.libc.setenv("GSTREAMER_1_0_ROOT_X86_64", gstreamerLibPath, true);
+ } else if (winBuildType == 1) {
+ Environment.libc.setenv("GSTREAMER_1_0_ROOT_MINGW_X86_64", gstreamerLibPath, true);
+ } else if (winBuildType == 2) {
+ Environment.libc.setenv("GSTREAMER_1_0_ROOT_MSVC_X86_64", gstreamerLibPath, true);
+ }
+ }
+ buildSystemPaths(rootPath);
+ } else {
+ System.err.println("We could not find a system-wide or bundled installation of GStreamer, but video might still work if GStreamer was placed somewhere else");
+ }
+ usingGStreamerSystemInstall = true;
+ }
+
+ if (!gstreamerLibPath.equals("")) {
+ // Should be safe because this is setting the jna.library.path,
+ // not java.library.path, and JNA is being provided by the video library.
+ // This will need to change if JNA is ever moved into more of a shared
+ // location (i.e. part of core) because this would overwrite the prop.
+ System.setProperty("jna.library.path", gstreamerLibPath);
+ }
+
+ Environment.libc.setenv("GST_DEBUG", String.valueOf(DEBUG_LEVEL), true);
+
+ if (!usingGStreamerSystemInstall) {
+ // Disable the use of gst-plugin-scanner on environments where we're
+ // not using the host system's installation of GStreamer
+ // the problem with gst-plugin-scanner is that the library expects it
+ // to exist at a specific location determined at build time
+ Environment.libc.setenv("GST_REGISTRY_FORK", "no", true);
+
+ // Prevent globally installed libraries from being used on platforms
+ // where we ship GStreamer
+ if (!gstreamerPluginPath.equals("")) {
+ Environment.libc.setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", true);
+ }
+ }
+
+ if (PApplet.platform == WINDOWS || (!usingGStreamerSystemInstall && PApplet.platform == LINUX)) {
+ // Pre-loading base GStreamer libraries on Windows and Linux,
+ // otherwise dynamic dependencies cannot be resolved.
+ LibraryLoader loader = LibraryLoader.getInstance(winBuildType);
+ if (loader == null) {
+ System.err.println("Cannot load GStreamer libraries.");
+ }
+ }
+
+ String[] args = { "" };
+ Gst.setUseDefaultContext(defaultGLibContext);
+ Gst.init("Processing core video", args);
+
+ // Output GStreamer version, lib path, plugin path
+ // and whether a system install is being used
+ printGStreamerInfo();
+
+ if (!usingGStreamerSystemInstall) {
+ // Plugins are scanned explicitly from the bindings if using the
+ // local GStreamer
+ scanPlugins();
+ }
+ }
+
+ static protected void printGStreamerInfo() {
+ String locInfo = "";
+ if (usingGStreamerSystemInstall) locInfo = "system-wide";
+ else locInfo = "bundled";
+ System.out.println("Processing video library using " + locInfo + " GStreamer " + Gst.getVersion());
+ }
+
+
+ static protected void scanPlugins() {
+ if (!gstreamerPluginPath.equals("")) {
+ Registry reg = Registry.get();
+ boolean res;
+ System.out.print("Scanning GStreamer plugins...");
+ res = reg.scanPath(gstreamerPluginPath);
+ if (res) {
+ System.out.println(" Done.");
+ } else {
+ System.err.println("Cannot load GStreamer plugins from " + gstreamerPluginPath);
+ }
+ }
+ }
+
+
+ static protected void removePlugins() {
+ Registry reg = Registry.get();
+ List list = reg.getPluginList();
+ for (Plugin plg : list) {
+ reg.removePlugin(plg);
+ }
+ }
+
+
+ /**
+ * Search for an item by checking folders listed in java.library.path
+ * for a specific name.
+ */
+ @SuppressWarnings("SameParameterValue")
+ static private String searchLibraryPath(String what) {
+ String libraryPath = System.getProperty("java.library.path");
+ // Should not be null, but cannot assume
+ if (libraryPath != null) {
+ String[] folders = PApplet.split(libraryPath, File.pathSeparatorChar);
+ // Usually, the most relevant paths will be at the front of the list,
+ // so hopefully this will not walk several entries.
+ for (String folder : folders) {
+ // Skip /lib and /usr/lib folders because they contain the system-wide GStreamer on Linux
+ // and they are on the Java library path.
+ if (folder.startsWith("/lib/") || folder.startsWith("/usr/lib/")) continue;
+ File file = new File(folder, what);
+ if (file.exists()) {
+ return file.getAbsolutePath();
+ }
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Search for an item by checking folders listed in java.class.path
+ * for a specific name.
+ */
+ @SuppressWarnings("SameParameterValue")
+ static private String searchClassPath(String what) {
+ String classPath = System.getProperty("java.class.path");
+ // Should not be null, but cannot assume
+ if (classPath != null) {
+ String[] entries = PApplet.split(classPath, File.pathSeparatorChar);
+ // Usually, the most relevant paths will be at the front of the list,
+ // so hopefully this will not walk several entries.
+ for (String entry : entries) {
+ File dir = new File(entry);
+ // If it's a .jar file, get its parent folder. This will lead to some
+ // double-checking of the same folder, but probably almost as expensive
+ // to keep track of folders we've already seen.
+ if (dir.isFile()) {
+ dir = dir.getParentFile();
+ }
+ File file = new File(dir, what);
+ if (file.exists()) {
+ return file.getAbsolutePath();
+ }
+ }
+ }
+ return null;
+ }
+
+ static protected void buildSystemPaths(String rootPath) {
+ if (System.getenv("GST_PLUGIN_SYSTEM_PATH") != null) {
+ gstreamerPluginPath = System.getenv("GST_PLUGIN_SYSTEM_PATH");
+ } else {
+ if (PApplet.platform == WINDOWS) {
+ gstreamerPluginPath = Paths.get(rootPath, "lib", "gstreamer-1.0").toString();
+ } else {
+ gstreamerPluginPath = Paths.get(gstreamerLibPath, "gstreamer-1.0").toString(); }
+ }
+ File path = new File(gstreamerPluginPath);
+ if (!path.exists()) {
+ gstreamerPluginPath = "";
+ }
+ }
+
+ static protected boolean buildBundldedPaths() {
+ // look for the gstreamer-1.0 folder in the native library path
+ // (there are natives adjacent to it, so this will work)
+ gstreamerPluginPath = searchLibraryPath("gstreamer-1.0");
+ if (gstreamerPluginPath == null) {
+ gstreamerPluginPath = searchClassPath("gstreamer-1.0");
+ }
+
+ if (gstreamerPluginPath == null) {
+ gstreamerPluginPath = "";
+ gstreamerLibPath = "";
+ usingGStreamerSystemInstall = true;
+ return false;
+ } else {
+ File gstreamerLibDir = new File(gstreamerPluginPath).getParentFile();
+ gstreamerLibPath = gstreamerLibDir.getAbsolutePath();
+ return true;
+ }
+ }
+
+
+ static protected float nanoSecToSecFrac(long nanosec) {
+ return (float)(nanosec / 1E9);
+ }
+
+
+ static protected long secToNanoLong(float sec) {
+ Double f = Double.valueOf(sec * 1E9);
+ return f.longValue();
+ }
+
+
+ /**
+ * Reorders an OpenGL pixel array (RGBA) into ARGB. The array must be
+ * of size width * height.
+ * @param pixels int[]
+ */
+ static protected void convertToARGB(int[] pixels, int width, int height) {
+ int t = 0;
+ int p = 0;
+ if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
+ // RGBA to ARGB conversion: shifting RGB 8 bits to the right,
+ // and placing A 24 bits to the left.
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int pixel = pixels[p++];
+ pixels[t++] = (pixel >>> 8) | ((pixel << 24) & 0xFF000000);
+ }
+ }
+ } else {
+ // We have to convert ABGR into ARGB, so R and B must be swapped,
+ // A and G just brought back in.
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int pixel = pixels[p++];
+ pixels[t++] = ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) |
+ (pixel & 0xFF00FF00);
+ }
+ }
+ }
+ }
+}