diff --git a/.gitignore b/.gitignore index fe2de4b..996015c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,10 @@ bin +/build /dist +/distribution .classpath .project +*.DS_Store +/.gradle +local.properties +/.idea \ No newline at end of file diff --git a/README.md b/README.md index 203ef25..572c23c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # Processing Video implementation for Android -This library tries to expose the same API endpoints as that of processing-video library for PC. The sketch from processing-video library works for Android. +This library tries to expose the same API endpoints as that of processing-video library for PC. +Any sketches using the processing-video library should work the same when using this library on Android. **Demo:** https://www.youtube.com/watch?v=kjqcWGLH6Q8 -**A primitive example :** +**A simple example :** ``` import in.omerjerk.processing.video.android.*; @@ -26,4 +27,11 @@ void draw() { **Behind the hood :** -The idea is to render camera preview on a `SurfaceTexture` and as soon as the new frame is received, copy the data from this `SurfaceTexture` to a custom texure bound to target `GL_TEXTURE_2D` (Note : We cannot directly render to a texture bound to `GL_TEXTURE_2D` target, because for the preview to happen, the texture must be bound to `GL_TEXTURE_EXTERNAL_OES`). This custom texture is then rendered to a PGraphics object. The backing texture of that PGraphics object is then used as the texture cache for our PImage file which stores the video. +The idea is to render camera preview on a `SurfaceTexture` and as soon as the new frame is received, copy the data from this `SurfaceTexture` to a custom texture bound to target `GL_TEXTURE_2D` +(Note : We cannot directly render to a texture bound to `GL_TEXTURE_2D` target, because for the preview to happen, the texture must be bound to `GL_TEXTURE_EXTERNAL_OES`). +This custom texture is then rendered to a PGraphics object. +The backing texture of that PGraphics object is then used as the texture cache for our PImage file which stores the video. + +## Building the Project + +`gradle dist` will build the project, copy it to the user's Processing sketchbook folder, and prepare a .zip file ready for distribution. \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..f4024d5 --- /dev/null +++ b/build.gradle @@ -0,0 +1,381 @@ +import java.nio.file.Files +import org.zeroturnaround.zip.ZipUtil +import org.apache.commons.io.FileUtils +import java.util.regex.Pattern +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; + +import com.android.build.gradle.internal.dependency.ExtractAarTransform +import com.android.build.gradle.internal.dependency.AarTransform +import com.android.build.gradle.internal.publishing.AndroidArtifacts +import com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactType +import com.google.common.collect.ImmutableList +import org.apache.tools.ant.filters.ReplaceTokens +import org.gradle.api.artifacts.transform.ArtifactTransform +import org.gradle.api.artifacts.type.ArtifactTypeDefinition +import static org.gradle.api.internal.artifacts.ArtifactAttributes.ARTIFACT_FORMAT + +apply plugin: 'java' +apply plugin: 'maven-publish' +apply plugin: 'java-library' + +buildscript { + repositories { + google() + mavenCentral() + maven { + url "https://raw.github.com/processing/processing-android/repository/" + } + } + dependencies { + classpath 'com.android.tools.build:gradle:3.0.1' + classpath group: 'commons-io', name: 'commons-io', version: '2.5' + classpath group: 'org.zeroturnaround', name: 'zt-zip', version: '1.9' + //classpath group: 'io.reactivex.rxjava2', name: 'rxjava', version: '2.2.7' + //classpath group: 'org.tensorflow', name: 'tensorflow-lite', version: '1.12.0' + } +} + +allprojects { + // Getting build properties + Properties buildProperties = new Properties() + buildProperties.load(project.rootProject.file("resources/build.properties").newDataInputStream()) + + ext.javaVersion = buildProperties.getProperty("java.target.version") + ext.libName = buildProperties.getProperty("library.name") + ext.libPackage = buildProperties.getProperty("library.package") + + ext.libVersion = buildProperties.getProperty("library.version") + ext.libPrettyVersion = buildProperties.getProperty("library.prettyVersion") + + ext.projectProperties = buildProperties + + // work around suggested by + // https://youtrack.jetbrains.com/issue/IDEA-276365 + configurations.compileOnly.canBeResolved = true + + project.archivesBaseName = libName + + + ext.userHome = System.getProperty("user.home") + ext.sketchbookLocation = buildProperties.getProperty("sketchbook.location").replace("\${user.home}", userHome) + ext.replaceEnv = { value -> + value = value.replace("\${sketchbook.location}", sketchbookLocation) + value = value.replace("\${user.home}", userHome) + return value + } + + ext.sdkLocation = replaceEnv(buildProperties.getProperty("android_sdk.location")) + ext.sdkAPILevel = buildProperties.getProperty("android_sdk.api_level") + ext.jarDeps = buildProperties.getProperty("dependencies.jar").split(',') + ext.aarDeps = buildProperties.getProperty("dependencies.aar").split(',') + ext.libDeps = replaceEnv(buildProperties.getProperty("dependencies.libraries")).split(',') + ext.copyDeps = buildProperties.getProperty("dependencies.copy_to_library").split(',') + ext.allJarDeps = [] + + ext.compileMode = buildProperties.getProperty("project.compile") + + // Extracting library names from the local library dependencies + ext.libNames = [] + for (lib in libDeps) { + if (lib) libNames.add(lib.split("/")[-1]) + } + + // Putting all remote depndencies (jar and aar) into an array to pass to the pom task + ext.remoteDependencies = [] + ext.addRemoteDepenency = { dep -> + def parts = dep.split(':') + if (parts.length != 3) { + throw new GradleException( + "Malformed Gradle dependency: " + lib + "\n" + + "It needs to have three parts: group, name, and version, separated by colons.") + } + remoteDependencies.add([group:parts[0], name:parts[1], version:parts[2]]) + } + for (dep in jarDeps) addRemoteDepenency(dep) + for (dep in aarDeps) addRemoteDepenency(dep) + + def fn = project.rootProject.file("local.properties") + if (!fn.exists()) { + if (sdkLocation) { + fn.withWriterAppend { w -> + w << "sdk.dir=${sdkLocation}\n" + } + } else if (System.env["ANDROID_SDK"] != null) { + def syspath = System.env["ANDROID_SDK"] + def parts = syspath.split(Pattern.quote(File.separator)) + def path = String.join("/", parts) + fn.withWriterAppend { w -> + w << "sdk.dir=${path}\n" + } + } else { + throw new GradleException( + "No Android SDK path provided in build.properties file, and there is no ANDROID_SDK environmental variable defined in the system.\n" + + "Set the path in local.properties, orefine ANDROID_SDK so it points to the location of the Android SDK.\n" + + "You can also create the local.properties file manully and add the following line to it:\n" + + "sdk.dir=") + } + } + + Properties localProperties = new Properties() + localProperties.load(project.rootProject.file("local.properties").newDataInputStream()) + def sdkDir = localProperties.getProperty("sdk.dir") + ext.androidPlatformPath = "${sdkDir}/platforms/android-${sdkAPILevel}" + + repositories { + google() + maven { + url "https://raw.github.com/processing/processing-android/repository/" + } + flatDir dirs: androidPlatformPath + for (lib in libDeps) { + if (lib) flatDir dirs: lib + "/library" + } + flatDir { + dirs 'lib' + } + } + + sourceCompatibility = javaVersion + targetCompatibility = javaVersion +} + +clean.doFirst { + delete "distribution" +} + +/** + * Custom aar configuration needed to use aar files as dependencies in a pure java + * library project, lifted from the following repo: + * https://github.com/nekocode/Gradle-Import-Aar + */ +configurations { + aarCompileOnly { + attributes { + attribute(ARTIFACT_FORMAT, ArtifactTypeDefinition.JAR_TYPE) + } + + // Add the aar inner jars to the compileClasspath + sourceSets.main.compileClasspath += it + + // Put our custom dependencies onto IDEA's PROVIDED scope + apply plugin: "idea" + idea.module.scopes.PROVIDED.plus += [it] + } +} + +dependencies { + // Transforamtions to extract the classes.jar in the aar package + def explodedAarType = ArtifactType.EXPLODED_AAR.getType() + registerTransform { + from.attribute(ARTIFACT_FORMAT, AndroidArtifacts.TYPE_AAR) + to.attribute(ARTIFACT_FORMAT, explodedAarType) + artifactTransform(ExtractAarTransform) + } + + registerTransform { + from.attribute(ARTIFACT_FORMAT, explodedAarType) + to.attribute(ARTIFACT_FORMAT, "classes.jar") + artifactTransform(AarTransform) { params(ArtifactType.JAR) } + } + + registerTransform { + from.attribute(ARTIFACT_FORMAT, "classes.jar") + to.attribute(ARTIFACT_FORMAT, ArtifactTypeDefinition.JAR_TYPE) + artifactTransform(ClassesJarArtifactTransform) + } + + compileOnly name: "android" + for (dep in jarDeps) compileOnly dep + for (dep in aarDeps) aarCompileOnly dep + for (dep in libNames) compileOnly name: dep + + //add in any files in local folders here, e.g.: + //compile name: "tensorflow-lite-1.12.0" + //compile group: 'org.tensorflow', name: 'tensorflow-lite', version: '1.12.0' + //compile group: 'io.reactivex.rxjava2', name: 'rxjava', version: '2.2.7' +} + +/** + * An ArtifactTransform for renaming the classes.jar + */ +class ClassesJarArtifactTransform extends ArtifactTransform { + @Override + List transform(File file) { + final String[] names = file.getPath().split(Pattern.quote(File.separator)) + final String aarName = names[names.length - 4].replace(".aar", "") + final File renamedJar = new File(getOutputDirectory(), aarName + ".jar") + renamedJar << file.bytes + return ImmutableList.of(renamedJar) + } +} + +project.afterEvaluate { + + ext.copyJarDependency = { fn -> + if (fn.name.lastIndexOf('.jar') != fn.name.size() - 4) return + allJarDeps.add(fn) + copyDeps.each { dep -> + if (dep && -1 < fn.name.indexOf(dep)) { + File libraryFolder = new File(System.getProperty("user.dir"), "library") + libraryFolder.mkdirs(); + final File libraryJar = new File(libraryFolder, fn.getName()) + Files.copy(fn.toPath(), libraryJar.toPath(), REPLACE_EXISTING); + } + } + } + + it.configurations.getByName("compileOnly").forEach { depFile -> copyJarDependency(depFile) } + it.configurations.getByName("aarCompileOnly").forEach { depFile -> copyJarDependency(depFile) } +} + +/* +task createPom { + if (compileMode == "normal") { + pom { + project { + groupId "${libPackage}" + artifactId "${libName}" + version "${libPrettyVersion}" + packaging "jar" + licenses { + license { + name "GNU Lesser General Public License, version 2.1" + url "https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt" + distribution "repo" + } + } + } + }.withXml { + // Add remote dependencies the pom file + def dependenciesNode = asNode().appendNode('dependencies') + remoteDependencies.each { dependency -> + def dependencyNode = dependenciesNode.appendNode('dependency') + dependencyNode.appendNode('groupId', dependency.group) + dependencyNode.appendNode('artifactId', dependency.name) + dependencyNode.appendNode('version', dependency.version) + dependencyNode.appendNode('scope', 'implementation') + } + }.writeTo("distribution/${libName}-${libPrettyVersion}.pom") + } +} +*/ + +sourceSets { + main { + java { + srcDirs = ["src/"] + } + } +} + +task sourcesJar(type: Jar, dependsOn: classes) { + classifier = "sources" + from sourceSets.main.allSource +} + +task javadoc(type: Javadoc, overwrite: true) { + failOnError false + + title = libName + source = sourceSets.main.allJava + + // Adding all dependencies to the classpath. Because files is a lazy collection: + // https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html#files-java.lang.Object...- + // even though it has not been initalized yet it will be evaluated with the correct values. + classpath = sourceSets.main.runtimeClasspath + project.files(allJarDeps) +} + +// Does not work because of Processing-specific tags in source code, such as @webref +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = "javadoc" + from javadoc.destinationDir +} + +artifacts { + archives sourcesJar + if (compileMode == "normal") archives javadocJar +} + +jar.doLast { task -> + ant.checksum file: task.archivePath +} + +clean.doFirst { + delete "distribution/${libName}" + delete "library/jniLibs" + delete fileTree('library') { + include '**/*.jar' + include '**/*.so' + } +} + +build.doLast { + // Create library folder + File libraryFolder = file("library") + libraryFolder.mkdirs(); + + // Copying lib jar to library folder + File libJar = file("library/${libName}.jar") + Files.copy(file("$buildDir/libs/${libName}.jar").toPath(), + libJar.toPath(), REPLACE_EXISTING); + + // Copying 3d party libs to library folder + FileUtils.copyDirectory(file("lib"), + file("library")); + + libJar.mkdirs(); + + if (compileMode == "normal") { + // Copying the files for release on JCentral + File distFolder = file("distribution"); + distFolder.mkdirs(); + Files.copy(file("$buildDir/libs/${libName}.jar").toPath(), + file("distribution/${libName}-${libPrettyVersion}.jar").toPath(), REPLACE_EXISTING); + Files.copy(file("$buildDir/libs/${libName}-sources.jar").toPath(), + file("distribution/${libName}-${libPrettyVersion}-sources.jar").toPath(), REPLACE_EXISTING); + Files.copy(file("$buildDir/libs/${libName}-javadoc.jar").toPath(), + file("distribution/${libName}-${libPrettyVersion}-javadoc.jar").toPath(), REPLACE_EXISTING); + Files.copy(file("$buildDir/libs/${libName}.jar.MD5").toPath(), + file("distribution/${libName}-${libPrettyVersion}.jar.md5").toPath(), REPLACE_EXISTING); + } +} + +task generateLibraryProperties(type: Copy) { + from 'resources' + into "distribution/${libName}/" + include 'library.properties' + filter(ReplaceTokens, beginToken:"##", endToken:"##", tokens: projectProperties) +} + +task dist { + dependsOn build + dependsOn generateLibraryProperties + doLast { + File distFolder = file("distribution/${libName}"); + distFolder.mkdirs(); + + FileUtils.copyDirectory(file("examples"), + file("distribution/${libName}/examples")) + // FileUtils.copyDirectory(file("data"), + // file("distribution/${libName}/data")) + FileUtils.copyDirectory(file("library"), + file("distribution/${libName}/library")) + FileUtils.copyDirectory(file("src"), + file("distribution/${libName}/src")) +// Files.copy(file("resources/library.properties").toPath(), +// file("distribution/${libName}/library.properties").toPath(), REPLACE_EXISTING); + + if (compileMode == "normal") { + // Copy reference + FileUtils.copyDirectory(file("$buildDir/docs/javadoc"), + file("distribution/${libName}/reference")) + Files.copy(file("resources/stylesheet.css").toPath(), + file("distribution/${libName}/reference/stylesheet.css").toPath(), REPLACE_EXISTING); + + ZipUtil.pack(file("distribution/${libName}"), new File("distribution/${libName}-${libVersion}.zip")); + } + + FileUtils.copyDirectory(file("distribution/${libName}"), + file("${sketchbookLocation}/libraries/${libName}")) + } +} diff --git a/build.sh b/build.sh deleted file mode 100755 index ab4c8cc..0000000 --- a/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -rm dist/video_android.zip -ant dist -rm -rf ~/sketchbook/libraries/video_android/ -unzip dist/video_android.zip -d ~/sketchbook/libraries/ \ No newline at end of file diff --git a/build.xml b/build.xml deleted file mode 100644 index e5533c2..0000000 --- a/build.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/Movie/GettingStartedMovie/GettingStartedMovie.pde b/examples/Movie/GettingStartedMovie/GettingStartedMovie.pde index 7d003dc..e96072e 100644 --- a/examples/Movie/GettingStartedMovie/GettingStartedMovie.pde +++ b/examples/Movie/GettingStartedMovie/GettingStartedMovie.pde @@ -4,7 +4,7 @@ Movie movie; void setup() { size(1280, 1280, P2D); - movie = new Movie(this, "transit.mov"); + movie = new Movie(this, "transit.mp4"); movie.loop(); movie.play(); } diff --git a/examples/Movie/GettingStartedMovie/data/transit.mov b/examples/Movie/GettingStartedMovie/data/transit.mov deleted file mode 100644 index 80b2b33..0000000 Binary files a/examples/Movie/GettingStartedMovie/data/transit.mov and /dev/null differ diff --git a/examples/Movie/GettingStartedMovie/data/transit.mp4 b/examples/Movie/GettingStartedMovie/data/transit.mp4 new file mode 100644 index 0000000..2039614 Binary files /dev/null and b/examples/Movie/GettingStartedMovie/data/transit.mp4 differ diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..41d9927 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..41dfb87 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..1b6c787 --- /dev/null +++ b/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..ac1b06f --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 0000000..86d0cb2 --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/library.properties b/library.properties deleted file mode 100644 index ef4c107..0000000 --- a/library.properties +++ /dev/null @@ -1,10 +0,0 @@ -name = Video Library for Processing Android -authorList = Umair Khan -url = http://omerjerk.in -category = Video & Vision -sentence = Implementation of Processing Video APIs for Android. -paragraph = -version = 1 -prettyVersion = 1.0 -minRevision = 228 -maxRevision = 0 \ No newline at end of file diff --git a/library/.gitignore b/library/.gitignore new file mode 100644 index 0000000..86d0cb2 --- /dev/null +++ b/library/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/library/video_android.jar b/library/video_android.jar index dd44c4e..081ebf5 100644 Binary files a/library/video_android.jar and b/library/video_android.jar differ diff --git a/resources/build.properties b/resources/build.properties new file mode 100644 index 0000000..60e9022 --- /dev/null +++ b/resources/build.properties @@ -0,0 +1,156 @@ +# Create libraries for the Android mode (https://android.processing.org/) of +# the Processing open source programming language and environment +# (https://www.processing.org) +# +# Customize the build properties to make the ant-build-process work for your +# environment. How? Please read the comments below. +# +# The default properties are set for OSX, for Windows-settings please refer to +# comments made under (1) and (2). + + + +# (1) +# Where is your Processing sketchbook located? +# If you are not sure, check the sketchbook location in your Processing +# application preferences. +# +# ${user.home} points the compiler to your home directory. +# For windows the default path to your sketchbook would be +# ${user.home}/My Documents/Processing (make adjustments below). + +sketchbook.location=${user.home}/Documents/Processing + + + +# (2) +# Where are the dependencies required for compiling? At the very least, you would need +# need processing-core. +# Provide the dependencies as a Gradle snippet with including package and version. +# Remote dependencies could be either in JAR or AAR format, available on Google or +# JCenter repositories. Put them in the appropriate line and separate multiple +# dependencies by commas. + +dependencies.jar=org.processing.android:processing-core:4.5.0b5 +dependencies.aar=com.android.support:support-v4:26.0.2 + +# Add each installed Processing's library needed to build your library to the +# following line, separated by commas, for example: +# dependencies.libraries=${sketchbook.location}/libraries/super,${sketchbook.location}/libraries/duper +# If you don't need to include any installed libraries, leave this +# blank. + +dependencies.libraries= + +# If some jar files from the Gradle dependencies need to be included in the library's folder, +# please list them next. Don't include the versions. + +dependencies.copy_to_library= + +# Android SDK +# The following path point to the location of the Android SDK required to build +# your project. Leave it empty to use the path in ANDROID_SDK system environment +# variable, if it is defined. +# As of Processing for Android 4.0.4, API level 26 is the minimum version. + +android_sdk.location=${sketchbook.location}/android/sdk +android_sdk.api_level=26 + + + +# (3) +# Set the java version that should be used to compile your library. + +java.target.version=1.7 + + + +# (4) +# Project details. +# Give your library a name and a package (optional). +# project.name will become the folder name for your library, +# so it should not use any special characters or dashes +# (but underscores are ok). + +library.name=video_android +library.prettyName=Processing Video implementation for Android +# library.package=com.yoururl + + +# Use 'normal' or 'fast' as value for project.compile. +# 'fast' will only compile the project into your sketchbook. +# 'normal' will compile the distribution including the javadoc-reference and all +# web-files (the compile process here takes longer). + +project.compile=normal + +# All files compiled with project.compile=normal are stored +# in the distribution folder. + + + +# (5) +# List of authors. Links can be provided using the syntax [author name](url). +# This will appear in the PDE Contribution Manager. + +library.authorList=[Mohammad Umair](https://github.com/omerjerk), [Kate Hollenbach](http://www.katehollenbach.com) + + +# Set the web page for your library. +# This is NOT a direct link to where to download it. + +library.url=https://github.com/kjhollen/processing-video-android + + +# Set the category of your library. This must be one (or many) of the following: +# "3D" "Animation" "Compilations" "Data" +# "Fabrication" "Geometry" "GUI" "Hardware" +# "I/O" "Language" "Math" "Simulation" +# "Sound" "Utilities" "Typography" "Video & Vision" +# If a value other than those listed is used, your library will listed as +# "Other". + +library.category=Video & Vision + + +# A short sentence (or fragment) to summarize the library's function. This will +# be shown from inside the PDE when the library is being installed. Avoid +# repeating the name of your library here. Also, avoid saying anything redundant +# like mentioning that it's a library. This should start with a capitalized +# letter, and end with a period. + +library.sentence=Video player and camera capture implementation for Processing Android. + + +# Additional information suitable for the Processing website. The value of +# 'sentence' always will be prepended, so you should start by writing the +# second sentence here. If your library only works on certain operating systems, +# mention it here. + +library.paragraph= + + +# Set the source code repository for your project. +# Recommendations for storing your source code online are GitHub or Bitbucket. + +source.host=GitHub +source.url=https://github.com/kjhollen/processing-video-android +source.repository=https://github.com/kjhollen/processing-video-android/src + +# The current version of your library. +# This number must be parsable as an int. It increments once with each release. +# This is used to compare different versions of the same library, and check if +# an update is available. + +library.version=2 + + +# The version as the user will see it. +# If blank, the library.version attribute will be used here. + +library.prettyVersion=1.1.0 + +# Include javadoc references into your project's javadocs. + +javadoc.java.href=http://java.sun.com/javase/6/docs/api/ +javadoc.processing.href=http://processing.googlecode.com/svn/trunk/processing/build/javadoc/core/ diff --git a/resources/library.properties b/resources/library.properties new file mode 100644 index 0000000..4bead85 --- /dev/null +++ b/resources/library.properties @@ -0,0 +1,49 @@ +# More on this file here: https://github.com/processing/processing/wiki/Library-Basics +# UTF-8 supported. + +# The name of your library as you want it formatted. This is what +# will appear in the PDE as the name of your library. +name=##library.prettyName## + +# List of authors. Links can be provided using the syntax [author name](url). +authorList=##library.authorList## +# A web page for your library, NOT a direct link to where to download it. +url=##library.url## + +# The category of your library, must be one (or many) of the following: +# "3D" "Animation" "Compilations" "Data" +# "Fabrication" "Geometry" "GUI" "Hardware" +# "I/O" "Language" "Math" "Simulation" +# "Sound" "Utilities" "Typography" "Video & Vision" +# +# If a value other than those listed is used, your library will listed as +# "Other". +category=##library.category## + +# A short sentence (or fragment) to summarize the library's function. This will +# be shown from inside the PDE when the library is being installed. Avoid +# repeating the name of your library here. Also, avoid saying anything redundant +# like mentioning that it's a library. This should start with a capitalized +# letter, and end with a period. +sentence =##library.sentence## + +# Additional information suitable for the Processing website. The value of +# 'sentence' always will be prepended, so you should start by writing the +# second sentence here. If your library only works on certain operating systems, +# mention it here. +paragraph =##library.paragraph## + +# Links in the 'sentence' and 'paragraph' attributes can be inserted using the +# same syntax as for authors. +# That is, [here is a link to Processing](http://processing.org/) + + +# A version number that increments once with each release. This is used to +# compare different versions of the same library, and check if an update is +# available. You should think of it as a counter, counting the total number of +# releases you've had. This must be parse-able as an Int. +version=##library.version## + +# The version as the user will see it. If blank, the version attribute will be +# used here. This is treated as a String. +prettyVersion=##library.prettyVersion## \ No newline at end of file diff --git a/resources/stylesheet.css b/resources/stylesheet.css new file mode 100644 index 0000000..154db1c --- /dev/null +++ b/resources/stylesheet.css @@ -0,0 +1,310 @@ +/* Javadoc style sheet */ +/* Define colors, fonts and other style attributes here to override the defaults */ +/* processingLibs style by andreas schlegel, sojamo */ + + +body { + margin : 0; + padding : 0; + padding-left : 10px; + padding-right : 8px; + background-color : #FFFFFF; + font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size : 100%; + font-size : 0.7em; + font-weight : normal; + line-height : normal; + margin-bottom:30px; +} + + + + +/* Headings */ +h1, h2, h3, h4, h5, th { + font-family :Arial, Helvetica, sans-serif; + font-size:1.2em; +} + + +p { + font-size : 1em; + width:80%; +} + +pre, code { + font-family : "Courier New", Courier, monospace; + font-size : 12px; + line-height : normal; +} + + + +table { + border:0; + margin-bottom:10px; + margin-top:10px; +} + + +tr, td { + border-top: 0px solid; + border-left: 0px solid; + padding-top:8px; + padding-bottom:8px; +} + + + +hr { + border:0; + height:1px; + padding:0; + margin:0; + margin-bottom:4px; + +} + + + +dd, th, td, font { + font-size:1.0em; + line-height:1.0em; +} + + + +dt { + margin-bottom:0px; +} + + + +dd { + margin-top:2px; + margin-bottom:4px; +} + + + +a { + text-decoration: underline; + font-weight: normal; +} + +a:hover, +a:active { + text-decoration: underline; + font-weight: normal; +} + +a:visited, +a:link:visited { + text-decoration: underline; + font-weight: normal; +} + + +img { + border: 0px solid #000000; +} + + + +/* Navigation bar fonts */ +.NavBarCell1 { + border:0; +} + +.NavBarCell1Rev { + border:0; +} + +.NavBarFont1 { + font-family: Arial, Helvetica, sans-serif; + font-size:1.1em; +} + + +.NavBarFont1 b { + font-weight:normal; +} + + + +.NavBarFont1:after, .NavBarFont1Rev:after { + font-weight:normal; + content: " \\"; +} + + +.NavBarFont1Rev { + font-family: Arial, Helvetica, sans-serif; + font-size:1.1em; +} + +.NavBarFont1Rev b { + font-family: Arial, Helvetica, sans-serif; + font-size:1.1em; + font-weight:normal; +} + +.NavBarCell2 { + font-family: Arial, Helvetica, sans-serif; +} + +.NavBarCell3 { + font-family: Arial, Helvetica, sans-serif; +} + + + +font.FrameItemFont { + font-family: Helvetica, Arial, sans-serif; + font-size:1.1em; + line-height:1.1em; +} + +font.FrameHeadingFont { + font-family: Helvetica, Arial, sans-serif; + line-height:32px; +} + +/* Font used in left-hand frame lists */ +.FrameTitleFont { + font-family: Helvetica, Arial, sans-serif +} + + +.toggleList { + padding:0; + margin:0; + margin-top:12px; +} + +.toggleList dt { + font-weight:bold; + font-size:12px; + font-family:arial,sans-serif; + padding:0px; + margin:10px 0px 10px 0px; +} + +.toggleList dt span { + font-family: monospace; + padding:0; + margin:0; +} + + +.toggleList dd { + margin:0; + padding:0; +} + +html.isjs .toggleList dd { + display: none; +} + +.toggleList pre { + padding: 4px 4px 4px 4px; +} + + + + + +/* COLORS */ + +pre, code { + color: #000000; +} + + +body { + color : #333333; + background-color :#FFFFFF; +} + + +h1, h2, h3, h4, h5, h6 { + color:#555; +} + +a, +.toggleList dt { + color: #1a7eb0; +} + +a:hover, +a:active { + color: #1a7eb0; +} + +a:visited, +a:link:visited { + color: #1a7eb0; +} + +td,tr { + border-color: #999999; +} + +hr { + color:#999999; + background:#999999; +} + + +.TableHeadingColor { + background: #dcdcdc; + color: #555; +} + + +.TableSubHeadingColor { + background: #EEEEFF +} + +.TableRowColor { + background: #FFFFFF +} + + +.NavBarCell1 { + background-color:#dcdcdc; + color:#000; +} + +.NavBarCell1 a { + color:#333; +} + + +.NavBarCell1Rev { + background-color:transparent; +} + +.NavBarFont1 { + color:#333; +} + + +.NavBarFont1Rev { + color:#fff; +} + +.NavBarCell2 { + background-color:#999; +} + +.NavBarCell2 a { + color:#fff; +} + + + +.NavBarCell3 { + background-color:#dcdcdc; +} + diff --git a/src/in/omerjerk/processing/video/android/Capture.java b/src/in/omerjerk/processing/video/android/Capture.java index 37be2a6..a0d27d3 100644 --- a/src/in/omerjerk/processing/video/android/Capture.java +++ b/src/in/omerjerk/processing/video/android/Capture.java @@ -252,7 +252,7 @@ public void stopCamera() { @Override public void startPreview() { - if (parent.getSurfaceHolder().getSurface() == null) { + if (parent.getSurface().getSurfaceHolder().getSurface() == null) { // preview surface does not exist return; } diff --git a/src/in/omerjerk/processing/video/android/Movie.java b/src/in/omerjerk/processing/video/android/Movie.java index aa427f7..126d711 100644 --- a/src/in/omerjerk/processing/video/android/Movie.java +++ b/src/in/omerjerk/processing/video/android/Movie.java @@ -16,127 +16,127 @@ import processing.core.PApplet; public class Movie extends VideoBase implements MediaPlayerHandlerCallback { - - private MediaPlayerHandler handler; - private MediaPlayer player; - - private boolean looping = false; - + + private MediaPlayerHandler handler; + private MediaPlayer player; + + private boolean looping = false; + public Movie(PApplet parent, String fileName) { - super(parent); - AssetFileDescriptor afd = null; - try { - afd = activity.getAssets().openFd(fileName); - MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever(); - metaRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); - String height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT); - String width = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH); - if (height == null || width == null) { - showDialog("Error!", "This video format is not supported by the device." - + "Please try a video with another format."); - return; - } - init(Integer.valueOf(width), Integer.valueOf(height), ARGB); - } catch (IOException e) { - e.printStackTrace(); - } - - initalizeFrameBuffer(); - - HandlerThread backgroundThread = new HandlerThread("MediaPlayer"); - backgroundThread.start(); - handler = new MediaPlayerHandler(backgroundThread.getLooper()); - handler.setCallback(this); - handler.sendMessage(handler.obtainMessage(MediaPlayerHandler.MSG_INIT_PLAYER, afd)); + super(parent); + AssetFileDescriptor afd = null; + try { + afd = activity.getAssets().openFd(fileName); + MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever(); + metaRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); + String height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT); + String width = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH); + if (height == null || width == null) { + showDialog("Error!", "This video format is not supported by the device." + + "Please try a video with another format."); + return; + } + init(Integer.valueOf(width), Integer.valueOf(height), ARGB); + } catch (IOException e) { + e.printStackTrace(); + } + + initalizeFrameBuffer(); + + HandlerThread backgroundThread = new HandlerThread("MediaPlayer"); + backgroundThread.start(); + handler = new MediaPlayerHandler(backgroundThread.getLooper()); + handler.setCallback(this); + handler.sendMessage(handler.obtainMessage(MediaPlayerHandler.MSG_INIT_PLAYER, afd)); } - + public void play() { - handler.sendMessage(handler.obtainMessage(MediaPlayerHandler.MSG_START_PLAYER)); + handler.sendMessage(handler.obtainMessage(MediaPlayerHandler.MSG_START_PLAYER)); } - + public void loop() { - looping = true; + looping = true; } - + @Override public void onPause() { } - + @Override public void onResume() { - initalizeFrameBuffer(); + initalizeFrameBuffer(); } - + @Override public String getEventName() { - return "movieEvent"; + return "movieEvent"; } - + private class MediaPlayerHandler extends Handler { - - public static final int MSG_INIT_PLAYER = 0; - public static final int MSG_START_PLAYER = 1; - - MediaPlayerHandlerCallback callback; - - public MediaPlayerHandler(Looper looper) { - super(looper); - } - - public void setCallback (MediaPlayerHandlerCallback cb) { - this.callback = cb; - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_INIT_PLAYER: - AssetFileDescriptor afd = (AssetFileDescriptor) msg.obj; - callback.initPlayer(afd); - break; - case MSG_START_PLAYER: - callback.startPlayer(); - break; - default: - break; - } - } + + public static final int MSG_INIT_PLAYER = 0; + public static final int MSG_START_PLAYER = 1; + + MediaPlayerHandlerCallback callback; + + public MediaPlayerHandler(Looper looper) { + super(looper); + } + + public void setCallback (MediaPlayerHandlerCallback cb) { + this.callback = cb; + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_INIT_PLAYER: + AssetFileDescriptor afd = (AssetFileDescriptor) msg.obj; + callback.initPlayer(afd); + break; + case MSG_START_PLAYER: + callback.startPlayer(); + break; + default: + break; + } + } } - + @Override public void initPlayer(AssetFileDescriptor afd) { - player = new MediaPlayer(); - try { - player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); - System.out.println("texture id = " + mTextureId); - while (mTextureId == 0) { - Thread.sleep(100); - } - player.setSurface(new Surface(mSurfaceTexture)); - player.setLooping(looping); - player.prepare(); - } catch (Exception e) { - e.printStackTrace(); - } + player = new MediaPlayer(); + try { + player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); + System.out.println("texture id = " + mTextureId); + while (mTextureId == 0) { + Thread.sleep(100); + } + player.setSurface(new Surface(mSurfaceTexture)); + player.setLooping(looping); + player.prepare(); + } catch (Exception e) { + e.printStackTrace(); + } } - + @Override public void startPlayer() { - player.start(); + player.start(); } - + private void showDialog(String title, String message) { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity); dialogBuilder.setMessage(message); dialogBuilder.setMessage(title); - + dialogBuilder.setPositiveButton("Okay", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - activity.finish(); - } - }); - + public void onClick(DialogInterface dialog, int id) { + activity.finish(); + } + }); + AlertDialog dialog = dialogBuilder.create(); dialog.show(); } -} +} \ No newline at end of file diff --git a/src/in/omerjerk/processing/video/android/VideoBase.java b/src/in/omerjerk/processing/video/android/VideoBase.java index 8c06c6f..53ccbf5 100644 --- a/src/in/omerjerk/processing/video/android/VideoBase.java +++ b/src/in/omerjerk/processing/video/android/VideoBase.java @@ -67,7 +67,7 @@ public VideoBase(PApplet parent) { setEventHandlerObject(parent); - glView = (GLSurfaceView) parent.getSurfaceView(); + glView = (GLSurfaceView) parent.getSurface().getSurfaceView(); pg = (PGraphicsOpenGL)parent.g; // customTexture = new Texture(pg, width, height); // customTexture.invertedY(true);