feat: implement component iOS bridge and demo app example
Signed-off-by: Brian Sztamfater <brian@status.im>
This commit is contained in:
parent
c8dab9a4b1
commit
6640e69a81
Binary file not shown.
|
@ -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
|
|
@ -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" "$@"
|
|
@ -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
|
|
@ -0,0 +1,566 @@
|
|||
/*
|
||||
* Copyright 2017 Pavel Semak
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package com.transparentvideo;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.content.res.TypedArray;
|
||||
import android.media.MediaDataSource;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
public class AlphaMovieView extends GLTextureView {
|
||||
|
||||
private static final int GL_CONTEXT_VERSION = 2;
|
||||
|
||||
private static final int NOT_DEFINED = -1;
|
||||
private static final int NOT_DEFINED_COLOR = 0;
|
||||
private static final int TIME_DETECTION_INTERVAL_MS = 50;
|
||||
|
||||
private static final String TAG = "VideoSurfaceView";
|
||||
|
||||
private static final float VIEW_ASPECT_RATIO = 4f / 3f;
|
||||
private float videoAspectRatio = VIEW_ASPECT_RATIO;
|
||||
|
||||
VideoRenderer renderer;
|
||||
private MediaPlayer mediaPlayer;
|
||||
|
||||
private OnVideoStartedListener onVideoStartedListener;
|
||||
private OnVideoEndedListener onVideoEndedListener;
|
||||
|
||||
private boolean isSurfaceCreated;
|
||||
private boolean isDataSourceSet;
|
||||
|
||||
private float accuracy;
|
||||
private int alphaColor;
|
||||
private boolean isPacked;
|
||||
// When loopStartMs >= 0 and loopEndMs == -1, the video will jump back to loopStartMs
|
||||
// once it reaches the end of the video.
|
||||
private long loopStartMs; // -1 means no specific loop points will be set
|
||||
private long loopEndMs; //numeros largos
|
||||
// This should be populated with a MediaPlayer.SEEK_* constant
|
||||
// Only for API 26 and above
|
||||
private int loopSeekingMethod = 0; //numeros
|
||||
private String shader; //letras y numeros
|
||||
|
||||
private boolean autoPlayAfterResume;//si o no
|
||||
private boolean playAfterResume;
|
||||
|
||||
private PlayerState state = PlayerState.NOT_PREPARED;
|
||||
|
||||
final Handler handler = new Handler();
|
||||
final Runnable timeDetector = new Runnable() {
|
||||
public void run() {
|
||||
if (getRootView() == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
int currentTimeMs = mediaPlayer.getCurrentPosition();
|
||||
if (state == PlayerState.STARTED) {
|
||||
startTimeDetector();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (loopStartMs >= 0 && loopEndMs >= 0 && currentTimeMs >= loopEndMs) {
|
||||
// Handle looping when both loop start and end points are defined
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mediaPlayer.seekTo(loopStartMs, loopSeekingMethod);
|
||||
} else {
|
||||
mediaPlayer.seekTo((int) loopStartMs);
|
||||
}
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
Log.e("AlphaMovieView", "Time detector error. Did you forget to call AlphaMovieView's onPause in the containing fragment/activity? | " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public AlphaMovieView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
if (!isInEditMode()) {
|
||||
init(attrs);
|
||||
}
|
||||
}
|
||||
|
||||
private void init(AttributeSet attrs) {
|
||||
setEGLContextClientVersion(GL_CONTEXT_VERSION);
|
||||
setEGLConfigChooser(8, 8, 8, 8, 16, 0);
|
||||
|
||||
initMediaPlayer();
|
||||
|
||||
renderer = new VideoRenderer();
|
||||
|
||||
obtainRendererOptions(attrs);
|
||||
|
||||
this.addOnSurfacePrepareListener();
|
||||
setRenderer(renderer);
|
||||
|
||||
bringToFront();
|
||||
setPreserveEGLContextOnPause(true);
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
private void initMediaPlayer() {
|
||||
mediaPlayer = new MediaPlayer();
|
||||
setScreenOnWhilePlaying(true);
|
||||
setLooping(true);
|
||||
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
|
||||
@Override
|
||||
public void onCompletion(MediaPlayer mp) {
|
||||
if (onVideoEndedListener != null) {
|
||||
onVideoEndedListener.onVideoEnded();
|
||||
}
|
||||
if (loopStartMs >= 0 && loopEndMs == -1) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mediaPlayer.seekTo(loopStartMs, loopSeekingMethod);
|
||||
} else {
|
||||
mediaPlayer.seekTo((int) loopStartMs);
|
||||
}
|
||||
mediaPlayer.start();
|
||||
return;
|
||||
}
|
||||
state = PlayerState.PAUSED;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void obtainRendererOptions(AttributeSet attrs) {
|
||||
if (attrs != null) {
|
||||
TypedArray arr = getContext().obtainStyledAttributes(attrs, R.styleable.AlphaMovieView);
|
||||
this.accuracy = arr.getFloat(R.styleable.AlphaMovieView_accuracy, NOT_DEFINED);
|
||||
this.alphaColor = arr.getColor(R.styleable.AlphaMovieView_alphaColor, NOT_DEFINED_COLOR);
|
||||
this.autoPlayAfterResume = arr.getBoolean(R.styleable.AlphaMovieView_autoPlayAfterResume, false);
|
||||
this.isPacked = arr.getBoolean(R.styleable.AlphaMovieView_packed, false);
|
||||
this.loopStartMs = arr.getInteger(R.styleable.AlphaMovieView_loopStartMs, -1);
|
||||
this.loopEndMs = arr.getInteger(R.styleable.AlphaMovieView_loopEndMs, -1);
|
||||
updateMediaPlayerLoopSetting();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
this.loopSeekingMethod = arr.getInteger(R.styleable.AlphaMovieView_loopSeekingMethod, MediaPlayer.SEEK_CLOSEST_SYNC);
|
||||
} else {
|
||||
this.loopSeekingMethod = 0;
|
||||
}
|
||||
this.shader = arr.getString(R.styleable.AlphaMovieView_shader);
|
||||
arr.recycle();
|
||||
updateRendererOptions();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateRendererOptions() {
|
||||
renderer.setPacked(isPacked);
|
||||
if (alphaColor != NOT_DEFINED_COLOR) {
|
||||
renderer.setAlphaColor(alphaColor);
|
||||
}
|
||||
if (shader != null) {
|
||||
renderer.setCustomShader(shader);
|
||||
}
|
||||
if (accuracy != NOT_DEFINED) {
|
||||
renderer.setAccuracy(accuracy);
|
||||
}
|
||||
}
|
||||
|
||||
private void addOnSurfacePrepareListener() {
|
||||
if (renderer != null) {
|
||||
renderer.setOnSurfacePrepareListener(new VideoRenderer.OnSurfacePrepareListener() {
|
||||
@Override
|
||||
public void surfacePrepared(Surface surface) {
|
||||
isSurfaceCreated = true;
|
||||
mediaPlayer.setSurface(surface);
|
||||
surface.release();
|
||||
if (isDataSourceSet) {
|
||||
prepareAndStartMediaPlayer();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareAndStartMediaPlayer() {
|
||||
prepareAsync(new MediaPlayer.OnPreparedListener() {
|
||||
@Override
|
||||
public void onPrepared(MediaPlayer mp) {
|
||||
start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void calculateVideoAspectRatio(int videoWidth, int videoHeight) {
|
||||
if (videoWidth > 0 && videoHeight > 0) {
|
||||
videoAspectRatio = (float) videoWidth / videoHeight;
|
||||
}
|
||||
|
||||
requestLayout();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int widthMode = View.MeasureSpec.getMode(widthMeasureSpec);
|
||||
int heightMode = View.MeasureSpec.getMode(heightMeasureSpec);
|
||||
int widthSize = View.MeasureSpec.getSize(widthMeasureSpec);
|
||||
int heightSize = View.MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
double currentAspectRatio = (double) widthSize / heightSize;
|
||||
if (currentAspectRatio > videoAspectRatio) {
|
||||
widthSize = (int) (heightSize * videoAspectRatio);
|
||||
} else {
|
||||
heightSize = (int) (widthSize / videoAspectRatio);
|
||||
}
|
||||
|
||||
super.onMeasure(View.MeasureSpec.makeMeasureSpec(widthSize, widthMode),
|
||||
View.MeasureSpec.makeMeasureSpec(heightSize, heightMode));
|
||||
}
|
||||
|
||||
private void onDataSourceSet(MediaMetadataRetriever retriever) {
|
||||
int videoWidth = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
|
||||
int videoHeight = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
|
||||
if (isPacked) {
|
||||
// Packed videos are assumed to be contain the alpha channel on the right side of the
|
||||
// original video, so the actual video width is half of the whole video
|
||||
videoHeight /= 2.0f;
|
||||
}
|
||||
|
||||
calculateVideoAspectRatio(videoWidth, videoHeight);
|
||||
isDataSourceSet = true;
|
||||
|
||||
if (isSurfaceCreated) {
|
||||
prepareAndStartMediaPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
public void setAutoPlayAfterResume(boolean autoPlayAfterResume) {
|
||||
this.autoPlayAfterResume = autoPlayAfterResume;
|
||||
}
|
||||
|
||||
public void setPacked(boolean isPacked) {
|
||||
this.isPacked = isPacked;
|
||||
renderer.setPacked(isPacked);
|
||||
updateRendererOptions();
|
||||
renderer.refreshShader();
|
||||
}
|
||||
|
||||
private void updateMediaPlayerLoopSetting() {
|
||||
if (loopStartMs >= 0 || loopEndMs >= 0) {
|
||||
// Disable MediaPlayer's built in looping if manual loop section is specified
|
||||
setLooping(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the start point of a loop. If >= 0, will override any setting set via mediaPlayer.setLooping
|
||||
public void setLoopStartMs(long startMs) {
|
||||
this.loopStartMs = startMs;
|
||||
updateMediaPlayerLoopSetting();
|
||||
}
|
||||
|
||||
// Sets the end point of a loop. If >= 0, will override any setting set via mediaPlayer.setLooping
|
||||
public void setLoopEndMs(long endMs) {
|
||||
this.loopEndMs = endMs;
|
||||
updateMediaPlayerLoopSetting();
|
||||
}
|
||||
|
||||
public void setVideoFromAssets(String assetsFileName) {
|
||||
reset();
|
||||
|
||||
try {
|
||||
AssetFileDescriptor assetFileDescriptor = getContext().getAssets().openFd(assetsFileName);
|
||||
mediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(), assetFileDescriptor.getStartOffset(), assetFileDescriptor.getLength());
|
||||
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
retriever.setDataSource(assetFileDescriptor.getFileDescriptor(), assetFileDescriptor.getStartOffset(), assetFileDescriptor.getLength());
|
||||
|
||||
onDataSourceSet(retriever);
|
||||
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVideoFromAssets(String assetsFileName, boolean isPacked) {
|
||||
setPacked(isPacked);
|
||||
setVideoFromAssets(assetsFileName);
|
||||
}
|
||||
|
||||
public void setVideoByUrl(String url) {
|
||||
reset();
|
||||
|
||||
try {
|
||||
mediaPlayer.setDataSource(url);
|
||||
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
retriever.setDataSource(url, new HashMap<String, String>());
|
||||
|
||||
onDataSourceSet(retriever);
|
||||
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVideoFromFile(FileDescriptor fileDescriptor) {
|
||||
reset();
|
||||
|
||||
try {
|
||||
mediaPlayer.setDataSource(fileDescriptor);
|
||||
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
retriever.setDataSource(fileDescriptor);
|
||||
|
||||
onDataSourceSet(retriever);
|
||||
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVideoFromFile(FileDescriptor fileDescriptor, int startOffset, int endOffset) {
|
||||
reset();
|
||||
|
||||
try {
|
||||
mediaPlayer.setDataSource(fileDescriptor, startOffset, endOffset);
|
||||
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
retriever.setDataSource(fileDescriptor, startOffset, endOffset);
|
||||
|
||||
onDataSourceSet(retriever);
|
||||
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(23)
|
||||
public void setVideoFromMediaDataSource(MediaDataSource mediaDataSource) {
|
||||
reset();
|
||||
|
||||
mediaPlayer.setDataSource(mediaDataSource);
|
||||
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
retriever.setDataSource(mediaDataSource);
|
||||
|
||||
onDataSourceSet(retriever);
|
||||
}
|
||||
|
||||
public void setVideoFromUri(Context context, Uri uri) {
|
||||
reset();
|
||||
|
||||
try {
|
||||
mediaPlayer.setDataSource(context, uri);
|
||||
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
retriever.setDataSource(context, uri);
|
||||
|
||||
onDataSourceSet(retriever);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (autoPlayAfterResume && playAfterResume) {
|
||||
playAfterResume = false;
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
handler.removeCallbacks(timeDetector);
|
||||
if (isPlaying() && autoPlayAfterResume) {
|
||||
playAfterResume = true;
|
||||
}
|
||||
pause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
release();
|
||||
}
|
||||
|
||||
private void prepareAsync(final MediaPlayer.OnPreparedListener onPreparedListener) {
|
||||
if (mediaPlayer != null && state == PlayerState.NOT_PREPARED
|
||||
|| state == PlayerState.STOPPED) {
|
||||
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
|
||||
@Override
|
||||
public void onPrepared(MediaPlayer mp) {
|
||||
state = PlayerState.PREPARED;
|
||||
onPreparedListener.onPrepared(mp);
|
||||
}
|
||||
});
|
||||
mediaPlayer.prepareAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private void startTimeDetector() {
|
||||
handler.postDelayed(timeDetector, TIME_DETECTION_INTERVAL_MS);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (mediaPlayer != null) {
|
||||
switch (state) {
|
||||
case PREPARED:
|
||||
mediaPlayer.start();
|
||||
startTimeDetector();
|
||||
state = PlayerState.STARTED;
|
||||
if (onVideoStartedListener != null) {
|
||||
onVideoStartedListener.onVideoStarted();
|
||||
}
|
||||
break;
|
||||
case PAUSED:
|
||||
mediaPlayer.start();
|
||||
startTimeDetector();
|
||||
state = PlayerState.STARTED;
|
||||
break;
|
||||
case STOPPED:
|
||||
prepareAsync(new MediaPlayer.OnPreparedListener() {
|
||||
@Override
|
||||
public void onPrepared(MediaPlayer mp) {
|
||||
mediaPlayer.start();
|
||||
startTimeDetector();
|
||||
state = PlayerState.STARTED;
|
||||
if (onVideoStartedListener != null) {
|
||||
onVideoStartedListener.onVideoStarted();
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
if (mediaPlayer != null && state == PlayerState.STARTED) {
|
||||
mediaPlayer.pause();
|
||||
state = PlayerState.PAUSED;
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (mediaPlayer != null && (state == PlayerState.STARTED || state == PlayerState.PAUSED)) {
|
||||
mediaPlayer.stop();
|
||||
state = PlayerState.STOPPED;
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
if (mediaPlayer != null && (state == PlayerState.STARTED || state == PlayerState.PAUSED ||
|
||||
state == PlayerState.STOPPED)) {
|
||||
mediaPlayer.reset();
|
||||
state = PlayerState.NOT_PREPARED;
|
||||
}
|
||||
}
|
||||
|
||||
public void release() {
|
||||
if (mediaPlayer != null) {
|
||||
mediaPlayer.release();
|
||||
state = PlayerState.RELEASE;
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public boolean isPlaying() {
|
||||
return state == PlayerState.STARTED;
|
||||
}
|
||||
|
||||
public boolean isPaused() {
|
||||
return state == PlayerState.PAUSED;
|
||||
}
|
||||
|
||||
public boolean isStopped() {
|
||||
return state == PlayerState.STOPPED;
|
||||
}
|
||||
|
||||
public boolean isReleased() {
|
||||
return state == PlayerState.RELEASE;
|
||||
}
|
||||
|
||||
public void seekTo(int msec) {
|
||||
mediaPlayer.seekTo(msec);
|
||||
}
|
||||
|
||||
public void setLooping(boolean looping) {
|
||||
mediaPlayer.setLooping(looping);
|
||||
}
|
||||
|
||||
public int getCurrentPosition() {
|
||||
return mediaPlayer.getCurrentPosition();
|
||||
}
|
||||
|
||||
public void setScreenOnWhilePlaying(boolean screenOn) {
|
||||
mediaPlayer.setScreenOnWhilePlaying(screenOn);
|
||||
}
|
||||
|
||||
public void setOnErrorListener(MediaPlayer.OnErrorListener onErrorListener){
|
||||
mediaPlayer.setOnErrorListener(onErrorListener);
|
||||
}
|
||||
|
||||
public void setOnVideoStartedListener(OnVideoStartedListener onVideoStartedListener) {
|
||||
this.onVideoStartedListener = onVideoStartedListener;
|
||||
}
|
||||
|
||||
public void setOnVideoEndedListener(OnVideoEndedListener onVideoEndedListener) {
|
||||
this.onVideoEndedListener = onVideoEndedListener;
|
||||
}
|
||||
|
||||
public void setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener onSeekCompleteListener) {
|
||||
mediaPlayer.setOnSeekCompleteListener(onSeekCompleteListener);
|
||||
}
|
||||
|
||||
public void setLoopSeekingMethod(int loopSeekingMethod) {
|
||||
this.loopSeekingMethod = loopSeekingMethod;
|
||||
}
|
||||
|
||||
public int getLoopSeekingMethod() {
|
||||
return this.loopSeekingMethod;
|
||||
}
|
||||
|
||||
public MediaPlayer getMediaPlayer() {
|
||||
return mediaPlayer;
|
||||
}
|
||||
|
||||
public interface OnVideoStartedListener {
|
||||
void onVideoStarted();
|
||||
}
|
||||
|
||||
public interface OnVideoEndedListener {
|
||||
void onVideoEnded();
|
||||
}
|
||||
|
||||
private enum PlayerState {
|
||||
NOT_PREPARED, PREPARED, STARTED, PAUSED, STOPPED, RELEASE
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -8,6 +8,9 @@ import androidx.annotation.NonNull;
|
|||
import com.facebook.react.uimanager.SimpleViewManager;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
|
||||
import java.util.Dictionary;
|
||||
|
||||
public class TransparentVideoViewManager extends SimpleViewManager<View> {
|
||||
public static final String REACT_CLASS = "TransparentVideoView";
|
||||
|
@ -24,8 +27,8 @@ public class TransparentVideoViewManager extends SimpleViewManager<View> {
|
|||
return new View(reactContext);
|
||||
}
|
||||
|
||||
@ReactProp(name = "color")
|
||||
public void setColor(View view, String color) {
|
||||
view.setBackgroundColor(Color.parseColor(color));
|
||||
@ReactProp(name = "src")
|
||||
public void setSrc(View view, ReadableMap src) {
|
||||
view.setBackgroundColor(Color.BLUE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,360 @@
|
|||
/*
|
||||
* Copyright 2017 Pavel Semak
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
package com.transparentvideo;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.Matrix;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
class VideoRenderer implements GLTextureView.Renderer, SurfaceTexture.OnFrameAvailableListener {
|
||||
private static String TAG = "VideoRender";
|
||||
|
||||
private static final int COLOR_MAX_VALUE = 255;
|
||||
|
||||
private static final int FLOAT_SIZE_BYTES = 4;
|
||||
private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
|
||||
private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
|
||||
private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
|
||||
private final float[] triangleVerticesData = {
|
||||
// X, Y, Z, U, V
|
||||
-1.0f, -1.0f, 0, 0.f, 0.f,
|
||||
1.0f, -1.0f, 0, 1.f, 0.f,
|
||||
-1.0f, 1.0f, 0, 0.f, 1.f,
|
||||
1.0f, 1.0f, 0, 1.f, 1.f,
|
||||
};
|
||||
|
||||
private FloatBuffer triangleVertices;
|
||||
|
||||
private final String vertexShader =
|
||||
"uniform mat4 uMVPMatrix;\n" +
|
||||
"uniform mat4 uSTMatrix;\n" +
|
||||
"attribute vec4 aPosition;\n" +
|
||||
"attribute vec4 aTextureCoord;\n" +
|
||||
"varying vec2 vTextureCoord;\n" +
|
||||
"void main() {\n" +
|
||||
" gl_Position = uMVPMatrix * aPosition;\n" +
|
||||
" vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
|
||||
"}\n";
|
||||
|
||||
private final String alphaShader = "#extension GL_OES_EGL_image_external : require\n"
|
||||
+ "precision mediump float;\n"
|
||||
+ "varying vec2 vTextureCoord;\n"
|
||||
+ "uniform samplerExternalOES sTexture;\n"
|
||||
+ "varying mediump float text_alpha_out;\n"
|
||||
+ "void main() {\n"
|
||||
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n"
|
||||
+ " float red = %f;\n"
|
||||
+ " float green = %f;\n"
|
||||
+ " float blue = %f;\n"
|
||||
+ " float accuracy = %f;\n"
|
||||
+ " if (abs(color.r - red) <= accuracy && abs(color.g - green) <= accuracy && abs(color.b - blue) <= accuracy) {\n"
|
||||
+ " gl_FragColor = vec4(color.r, color.g, color.b, 0.0);\n"
|
||||
+ " } else {\n"
|
||||
+ " gl_FragColor = vec4(color.r, color.g, color.b, 1.0);\n"
|
||||
+ " }\n"
|
||||
+ "}\n";
|
||||
|
||||
private final String alphaPackedShader = "#extension GL_OES_EGL_image_external : require\n"
|
||||
+ "precision mediump float;\n"
|
||||
+ "varying vec2 vTextureCoord;\n"
|
||||
+ "uniform samplerExternalOES sTexture;\n"
|
||||
+ "varying mediump float text_alpha_out;\n"
|
||||
+ "void main() {\n"
|
||||
+ " vec4 color = texture2D(sTexture, vec2(vTextureCoord.x, vTextureCoord.y / 2.0));\n"
|
||||
+ " float alpha = texture2D(sTexture, vec2(vTextureCoord.x, 0.5 + vTextureCoord.y / 2.0)).r;\n"
|
||||
+ " gl_FragColor = vec4(color.rgb, alpha);\n"
|
||||
+ "}\n";
|
||||
|
||||
private double accuracy = 0.95;
|
||||
|
||||
private String shader = alphaShader;
|
||||
|
||||
private float[] mVPMatrix = new float[16];
|
||||
private float[] sTMatrix = new float[16];
|
||||
|
||||
private int program;
|
||||
private int textureID;
|
||||
private int uMVPMatrixHandle;
|
||||
private int uSTMatrixHandle;
|
||||
private int aPositionHandle;
|
||||
private int aTextureHandle;
|
||||
|
||||
private SurfaceTexture surface;
|
||||
private boolean updateSurface = false;
|
||||
private boolean updateShader = false;
|
||||
|
||||
private static int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
|
||||
|
||||
private OnSurfacePrepareListener onSurfacePrepareListener;
|
||||
|
||||
private boolean isCustom;
|
||||
|
||||
/**
|
||||
* True if the video is an alpha packed video with the left half containing the color data
|
||||
* and right half containing the alpha data
|
||||
*/
|
||||
private boolean isPacked;
|
||||
|
||||
private float redParam = 0.0f;
|
||||
private float greenParam = 1.0f;
|
||||
private float blueParam = 0.0f;
|
||||
|
||||
VideoRenderer() {
|
||||
triangleVertices = ByteBuffer.allocateDirect(
|
||||
triangleVerticesData.length * FLOAT_SIZE_BYTES)
|
||||
.order(ByteOrder.nativeOrder()).asFloatBuffer();
|
||||
triangleVertices.put(triangleVerticesData).position(0);
|
||||
|
||||
Matrix.setIdentityM(sTMatrix, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawFrame(GL10 glUnused) {
|
||||
synchronized (this) {
|
||||
if (updateSurface) {
|
||||
surface.updateTexImage();
|
||||
surface.getTransformMatrix(sTMatrix);
|
||||
updateSurface = false;
|
||||
}
|
||||
if (updateShader) {
|
||||
initializeShader();
|
||||
updateShader = false;
|
||||
}
|
||||
}
|
||||
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
GLES20.glEnable(GLES20.GL_BLEND);
|
||||
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
GLES20.glUseProgram(program);
|
||||
checkGlError("glUseProgram");
|
||||
|
||||
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
|
||||
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureID);
|
||||
|
||||
triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
|
||||
GLES20.glVertexAttribPointer(aPositionHandle, 3, GLES20.GL_FLOAT, false,
|
||||
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
|
||||
checkGlError("glVertexAttribPointer maPosition");
|
||||
GLES20.glEnableVertexAttribArray(aPositionHandle);
|
||||
checkGlError("glEnableVertexAttribArray aPositionHandle");
|
||||
|
||||
triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
|
||||
GLES20.glVertexAttribPointer(aTextureHandle, 3, GLES20.GL_FLOAT, false,
|
||||
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
|
||||
checkGlError("glVertexAttribPointer aTextureHandle");
|
||||
GLES20.glEnableVertexAttribArray(aTextureHandle);
|
||||
checkGlError("glEnableVertexAttribArray aTextureHandle");
|
||||
|
||||
Matrix.setIdentityM(mVPMatrix, 0);
|
||||
GLES20.glUniformMatrix4fv(uMVPMatrixHandle, 1, false, mVPMatrix, 0);
|
||||
GLES20.glUniformMatrix4fv(uSTMatrixHandle, 1, false, sTMatrix, 0);
|
||||
|
||||
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
|
||||
checkGlError("glDrawArrays");
|
||||
|
||||
GLES20.glFinish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceDestroyed(GL10 gl) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
|
||||
GLES20.glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
|
||||
if (!initializeShader()) {
|
||||
return;
|
||||
}
|
||||
prepareSurface();
|
||||
}
|
||||
|
||||
public boolean initializeShader() {
|
||||
program = createProgram(vertexShader, this.resolveShader());
|
||||
if (program == 0) {
|
||||
return false;
|
||||
}
|
||||
aPositionHandle = GLES20.glGetAttribLocation(program, "aPosition");
|
||||
checkGlError("glGetAttribLocation aPosition");
|
||||
if (aPositionHandle == -1) {
|
||||
throw new RuntimeException("Could not get attrib location for aPosition");
|
||||
}
|
||||
aTextureHandle = GLES20.glGetAttribLocation(program, "aTextureCoord");
|
||||
checkGlError("glGetAttribLocation aTextureCoord");
|
||||
if (aTextureHandle == -1) {
|
||||
throw new RuntimeException("Could not get attrib location for aTextureCoord");
|
||||
}
|
||||
|
||||
uMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
|
||||
checkGlError("glGetUniformLocation uMVPMatrix");
|
||||
if (uMVPMatrixHandle == -1) {
|
||||
throw new RuntimeException("Could not get attrib location for uMVPMatrix");
|
||||
}
|
||||
|
||||
uSTMatrixHandle = GLES20.glGetUniformLocation(program, "uSTMatrix");
|
||||
checkGlError("glGetUniformLocation uSTMatrix");
|
||||
if (uSTMatrixHandle == -1) {
|
||||
throw new RuntimeException("Could not get attrib location for uSTMatrix");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void prepareSurface() {
|
||||
int[] textures = new int[1];
|
||||
GLES20.glGenTextures(1, textures, 0);
|
||||
|
||||
textureID = textures[0];
|
||||
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureID);
|
||||
checkGlError("glBindTexture textureID");
|
||||
|
||||
GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
|
||||
GLES20.GL_NEAREST);
|
||||
GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
|
||||
GLES20.GL_LINEAR);
|
||||
|
||||
surface = new SurfaceTexture(textureID);
|
||||
surface.setOnFrameAvailableListener(this);
|
||||
|
||||
Surface surface = new Surface(this.surface);
|
||||
onSurfacePrepareListener.surfacePrepared(surface);
|
||||
|
||||
synchronized (this) {
|
||||
updateSurface = false;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized public void onFrameAvailable(SurfaceTexture surface) {
|
||||
updateSurface = true;
|
||||
}
|
||||
|
||||
synchronized public void refreshShader() {
|
||||
updateShader = true;
|
||||
}
|
||||
|
||||
private int loadShader(int shaderType, String source) {
|
||||
int shader = GLES20.glCreateShader(shaderType);
|
||||
if (shader != 0) {
|
||||
GLES20.glShaderSource(shader, source);
|
||||
GLES20.glCompileShader(shader);
|
||||
int[] compiled = new int[1];
|
||||
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
|
||||
if (compiled[0] == 0) {
|
||||
Log.e(TAG, "Could not compile shader " + shaderType + ":");
|
||||
Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
|
||||
GLES20.glDeleteShader(shader);
|
||||
shader = 0;
|
||||
}
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
private int createProgram(String vertexSource, String fragmentSource) {
|
||||
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
|
||||
if (vertexShader == 0) {
|
||||
return 0;
|
||||
}
|
||||
int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
|
||||
if (pixelShader == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int program = GLES20.glCreateProgram();
|
||||
if (program != 0) {
|
||||
GLES20.glAttachShader(program, vertexShader);
|
||||
checkGlError("glAttachShader");
|
||||
GLES20.glAttachShader(program, pixelShader);
|
||||
checkGlError("glAttachShader");
|
||||
GLES20.glLinkProgram(program);
|
||||
int[] linkStatus = new int[1];
|
||||
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
|
||||
if (linkStatus[0] != GLES20.GL_TRUE) {
|
||||
Log.e(TAG, "Could not link program: ");
|
||||
Log.e(TAG, GLES20.glGetProgramInfoLog(program));
|
||||
GLES20.glDeleteProgram(program);
|
||||
program = 0;
|
||||
}
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
void setAlphaColor(int color) {
|
||||
redParam = (float) Color.red(color) / COLOR_MAX_VALUE;
|
||||
greenParam = (float) Color.green(color) / COLOR_MAX_VALUE;
|
||||
blueParam = (float) Color.blue(color) / COLOR_MAX_VALUE;
|
||||
}
|
||||
|
||||
void setCustomShader(String customShader) {
|
||||
isCustom = true;
|
||||
shader = customShader;
|
||||
}
|
||||
|
||||
void setPacked(boolean isPacked) {
|
||||
this.isPacked = isPacked;
|
||||
}
|
||||
|
||||
void setAccuracy(double accuracy) {
|
||||
if (accuracy > 1.0) {
|
||||
accuracy = 1.0;
|
||||
} else if (accuracy < 0.0) {
|
||||
accuracy = 0.0;
|
||||
}
|
||||
this.accuracy = accuracy;
|
||||
}
|
||||
|
||||
public double getAccuracy() {
|
||||
return accuracy;
|
||||
}
|
||||
|
||||
private String resolveShader() {
|
||||
return isCustom ? shader : isPacked ?
|
||||
alphaPackedShader : String.format(Locale.ENGLISH, alphaShader,
|
||||
redParam, greenParam, blueParam, 1 - accuracy);
|
||||
}
|
||||
|
||||
private void checkGlError(String op) {
|
||||
int error;
|
||||
if ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
|
||||
Log.e(TAG, op + ": glError " + error);
|
||||
throw new RuntimeException(op + ": glError " + error);
|
||||
}
|
||||
}
|
||||
|
||||
void setOnSurfacePrepareListener(OnSurfacePrepareListener onSurfacePrepareListener) {
|
||||
this.onSurfacePrepareListener = onSurfacePrepareListener;
|
||||
}
|
||||
|
||||
interface OnSurfacePrepareListener {
|
||||
void surfacePrepared(Surface surface);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<declare-styleable name="AlphaMovieView">
|
||||
<attr name="alphaColor" format="color" />
|
||||
<attr name="autoPlayAfterResume" format="boolean" />
|
||||
<attr name="loopStartMs" format="integer" />
|
||||
<attr name="loopEndMs" format="integer" />
|
||||
<attr name="loopSeekingMethod" format="integer" />
|
||||
<attr name="packed" format="boolean" />
|
||||
<attr name="shader" format="string" />
|
||||
<attr name="accuracy" format="float" />
|
||||
</declare-styleable>
|
||||
</resources>
|
|
@ -13,7 +13,7 @@ buildscript {
|
|||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:4.2.2")
|
||||
classpath('com.android.tools.build:gradle:7.4.2')
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#Thu May 04 15:26:04 ART 2023
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,533 @@
|
|||
PODS:
|
||||
- boost (1.76.0)
|
||||
- CocoaAsyncSocket (7.6.5)
|
||||
- DoubleConversion (1.1.6)
|
||||
- FBLazyVector (0.67.5)
|
||||
- FBReactNativeSpec (0.67.5):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTRequired (= 0.67.5)
|
||||
- RCTTypeSafety (= 0.67.5)
|
||||
- React-Core (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- ReactCommon/turbomodule/core (= 0.67.5)
|
||||
- Flipper (0.99.0):
|
||||
- Flipper-Folly (~> 2.6)
|
||||
- Flipper-RSocket (~> 1.4)
|
||||
- Flipper-Boost-iOSX (1.76.0.1.11)
|
||||
- Flipper-DoubleConversion (3.1.7)
|
||||
- Flipper-Fmt (7.1.7)
|
||||
- Flipper-Folly (2.6.7):
|
||||
- Flipper-Boost-iOSX
|
||||
- Flipper-DoubleConversion
|
||||
- Flipper-Fmt (= 7.1.7)
|
||||
- Flipper-Glog
|
||||
- libevent (~> 2.1.12)
|
||||
- OpenSSL-Universal (= 1.1.180)
|
||||
- Flipper-Glog (0.3.6)
|
||||
- Flipper-PeerTalk (0.0.4)
|
||||
- Flipper-RSocket (1.4.3):
|
||||
- Flipper-Folly (~> 2.6)
|
||||
- FlipperKit (0.99.0):
|
||||
- FlipperKit/Core (= 0.99.0)
|
||||
- FlipperKit/Core (0.99.0):
|
||||
- Flipper (~> 0.99.0)
|
||||
- FlipperKit/CppBridge
|
||||
- FlipperKit/FBCxxFollyDynamicConvert
|
||||
- FlipperKit/FBDefines
|
||||
- FlipperKit/FKPortForwarding
|
||||
- FlipperKit/CppBridge (0.99.0):
|
||||
- Flipper (~> 0.99.0)
|
||||
- FlipperKit/FBCxxFollyDynamicConvert (0.99.0):
|
||||
- Flipper-Folly (~> 2.6)
|
||||
- FlipperKit/FBDefines (0.99.0)
|
||||
- FlipperKit/FKPortForwarding (0.99.0):
|
||||
- CocoaAsyncSocket (~> 7.6)
|
||||
- Flipper-PeerTalk (~> 0.0.4)
|
||||
- FlipperKit/FlipperKitHighlightOverlay (0.99.0)
|
||||
- FlipperKit/FlipperKitLayoutHelpers (0.99.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitHighlightOverlay
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable
|
||||
- FlipperKit/FlipperKitLayoutIOSDescriptors (0.99.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitHighlightOverlay
|
||||
- FlipperKit/FlipperKitLayoutHelpers
|
||||
- YogaKit (~> 1.18)
|
||||
- FlipperKit/FlipperKitLayoutPlugin (0.99.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitHighlightOverlay
|
||||
- FlipperKit/FlipperKitLayoutHelpers
|
||||
- FlipperKit/FlipperKitLayoutIOSDescriptors
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable
|
||||
- YogaKit (~> 1.18)
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable (0.99.0)
|
||||
- FlipperKit/FlipperKitNetworkPlugin (0.99.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitReactPlugin (0.99.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitUserDefaultsPlugin (0.99.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/SKIOSNetworkPlugin (0.99.0):
|
||||
- FlipperKit/Core
|
||||
- FlipperKit/FlipperKitNetworkPlugin
|
||||
- fmt (6.2.1)
|
||||
- glog (0.3.5)
|
||||
- libevent (2.1.12)
|
||||
- OpenSSL-Universal (1.1.180)
|
||||
- RCT-Folly (2021.06.28.00-v2):
|
||||
- boost
|
||||
- DoubleConversion
|
||||
- fmt (~> 6.2.1)
|
||||
- glog
|
||||
- RCT-Folly/Default (= 2021.06.28.00-v2)
|
||||
- RCT-Folly/Default (2021.06.28.00-v2):
|
||||
- boost
|
||||
- DoubleConversion
|
||||
- fmt (~> 6.2.1)
|
||||
- glog
|
||||
- RCTRequired (0.67.5)
|
||||
- RCTTypeSafety (0.67.5):
|
||||
- FBLazyVector (= 0.67.5)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTRequired (= 0.67.5)
|
||||
- React-Core (= 0.67.5)
|
||||
- React (0.67.5):
|
||||
- React-Core (= 0.67.5)
|
||||
- React-Core/DevSupport (= 0.67.5)
|
||||
- React-Core/RCTWebSocket (= 0.67.5)
|
||||
- React-RCTActionSheet (= 0.67.5)
|
||||
- React-RCTAnimation (= 0.67.5)
|
||||
- React-RCTBlob (= 0.67.5)
|
||||
- React-RCTImage (= 0.67.5)
|
||||
- React-RCTLinking (= 0.67.5)
|
||||
- React-RCTNetwork (= 0.67.5)
|
||||
- React-RCTSettings (= 0.67.5)
|
||||
- React-RCTText (= 0.67.5)
|
||||
- React-RCTVibration (= 0.67.5)
|
||||
- React-callinvoker (0.67.5)
|
||||
- React-Core (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.67.5)
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-Core/CoreModulesHeaders (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-Core/Default (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-Core/DevSupport (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.67.5)
|
||||
- React-Core/RCTWebSocket (= 0.67.5)
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-jsinspector (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-Core/RCTActionSheetHeaders (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-Core/RCTAnimationHeaders (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-Core/RCTBlobHeaders (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-Core/RCTImageHeaders (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-Core/RCTLinkingHeaders (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-Core/RCTNetworkHeaders (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-Core/RCTSettingsHeaders (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-Core/RCTTextHeaders (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-Core/RCTVibrationHeaders (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-Core/RCTWebSocket (0.67.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.67.5)
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsiexecutor (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga
|
||||
- React-CoreModules (0.67.5):
|
||||
- FBReactNativeSpec (= 0.67.5)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.67.5)
|
||||
- React-Core/CoreModulesHeaders (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-RCTImage (= 0.67.5)
|
||||
- ReactCommon/turbomodule/core (= 0.67.5)
|
||||
- React-cxxreact (0.67.5):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-callinvoker (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-jsinspector (= 0.67.5)
|
||||
- React-logger (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- React-runtimeexecutor (= 0.67.5)
|
||||
- React-jsi (0.67.5):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-jsi/Default (= 0.67.5)
|
||||
- React-jsi/Default (0.67.5):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-jsiexecutor (0.67.5):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- React-jsinspector (0.67.5)
|
||||
- React-logger (0.67.5):
|
||||
- glog
|
||||
- react-native-transparent-video (0.1.0):
|
||||
- React-Core
|
||||
- React-perflogger (0.67.5)
|
||||
- React-RCTActionSheet (0.67.5):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.67.5)
|
||||
- React-RCTAnimation (0.67.5):
|
||||
- FBReactNativeSpec (= 0.67.5)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.67.5)
|
||||
- React-Core/RCTAnimationHeaders (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- ReactCommon/turbomodule/core (= 0.67.5)
|
||||
- React-RCTBlob (0.67.5):
|
||||
- FBReactNativeSpec (= 0.67.5)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/RCTBlobHeaders (= 0.67.5)
|
||||
- React-Core/RCTWebSocket (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-RCTNetwork (= 0.67.5)
|
||||
- ReactCommon/turbomodule/core (= 0.67.5)
|
||||
- React-RCTImage (0.67.5):
|
||||
- FBReactNativeSpec (= 0.67.5)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.67.5)
|
||||
- React-Core/RCTImageHeaders (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-RCTNetwork (= 0.67.5)
|
||||
- ReactCommon/turbomodule/core (= 0.67.5)
|
||||
- React-RCTLinking (0.67.5):
|
||||
- FBReactNativeSpec (= 0.67.5)
|
||||
- React-Core/RCTLinkingHeaders (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- ReactCommon/turbomodule/core (= 0.67.5)
|
||||
- React-RCTNetwork (0.67.5):
|
||||
- FBReactNativeSpec (= 0.67.5)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.67.5)
|
||||
- React-Core/RCTNetworkHeaders (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- ReactCommon/turbomodule/core (= 0.67.5)
|
||||
- React-RCTSettings (0.67.5):
|
||||
- FBReactNativeSpec (= 0.67.5)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.67.5)
|
||||
- React-Core/RCTSettingsHeaders (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- ReactCommon/turbomodule/core (= 0.67.5)
|
||||
- React-RCTText (0.67.5):
|
||||
- React-Core/RCTTextHeaders (= 0.67.5)
|
||||
- React-RCTVibration (0.67.5):
|
||||
- FBReactNativeSpec (= 0.67.5)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/RCTVibrationHeaders (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- ReactCommon/turbomodule/core (= 0.67.5)
|
||||
- React-runtimeexecutor (0.67.5):
|
||||
- React-jsi (= 0.67.5)
|
||||
- ReactCommon/turbomodule/core (0.67.5):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-callinvoker (= 0.67.5)
|
||||
- React-Core (= 0.67.5)
|
||||
- React-cxxreact (= 0.67.5)
|
||||
- React-jsi (= 0.67.5)
|
||||
- React-logger (= 0.67.5)
|
||||
- React-perflogger (= 0.67.5)
|
||||
- Yoga (1.14.0)
|
||||
- YogaKit (1.18.1):
|
||||
- Yoga (~> 1.14)
|
||||
|
||||
DEPENDENCIES:
|
||||
- boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
|
||||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
|
||||
- FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`)
|
||||
- Flipper (= 0.99.0)
|
||||
- Flipper-Boost-iOSX (= 1.76.0.1.11)
|
||||
- Flipper-DoubleConversion (= 3.1.7)
|
||||
- Flipper-Fmt (= 7.1.7)
|
||||
- Flipper-Folly (= 2.6.7)
|
||||
- Flipper-Glog (= 0.3.6)
|
||||
- Flipper-PeerTalk (= 0.0.4)
|
||||
- Flipper-RSocket (= 1.4.3)
|
||||
- FlipperKit (= 0.99.0)
|
||||
- FlipperKit/Core (= 0.99.0)
|
||||
- FlipperKit/CppBridge (= 0.99.0)
|
||||
- FlipperKit/FBCxxFollyDynamicConvert (= 0.99.0)
|
||||
- FlipperKit/FBDefines (= 0.99.0)
|
||||
- FlipperKit/FKPortForwarding (= 0.99.0)
|
||||
- FlipperKit/FlipperKitHighlightOverlay (= 0.99.0)
|
||||
- FlipperKit/FlipperKitLayoutPlugin (= 0.99.0)
|
||||
- FlipperKit/FlipperKitLayoutTextSearchable (= 0.99.0)
|
||||
- FlipperKit/FlipperKitNetworkPlugin (= 0.99.0)
|
||||
- FlipperKit/FlipperKitReactPlugin (= 0.99.0)
|
||||
- FlipperKit/FlipperKitUserDefaultsPlugin (= 0.99.0)
|
||||
- FlipperKit/SKIOSNetworkPlugin (= 0.99.0)
|
||||
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
- OpenSSL-Universal (= 1.1.180)
|
||||
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
|
||||
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
|
||||
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
|
||||
- React (from `../node_modules/react-native/`)
|
||||
- React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
|
||||
- React-Core (from `../node_modules/react-native/`)
|
||||
- React-Core/DevSupport (from `../node_modules/react-native/`)
|
||||
- React-Core/RCTWebSocket (from `../node_modules/react-native/`)
|
||||
- React-CoreModules (from `../node_modules/react-native/React/CoreModules`)
|
||||
- React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
|
||||
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
|
||||
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
|
||||
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
|
||||
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
|
||||
- react-native-transparent-video (from `../..`)
|
||||
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
|
||||
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
|
||||
- React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
|
||||
- React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
|
||||
- React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
|
||||
- React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
|
||||
- React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
|
||||
- React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
|
||||
- React-RCTText (from `../node_modules/react-native/Libraries/Text`)
|
||||
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
|
||||
- React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`)
|
||||
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
|
||||
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- CocoaAsyncSocket
|
||||
- Flipper
|
||||
- Flipper-Boost-iOSX
|
||||
- Flipper-DoubleConversion
|
||||
- Flipper-Fmt
|
||||
- Flipper-Folly
|
||||
- Flipper-Glog
|
||||
- Flipper-PeerTalk
|
||||
- Flipper-RSocket
|
||||
- FlipperKit
|
||||
- fmt
|
||||
- libevent
|
||||
- OpenSSL-Universal
|
||||
- YogaKit
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
boost:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec"
|
||||
DoubleConversion:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
|
||||
FBLazyVector:
|
||||
:path: "../node_modules/react-native/Libraries/FBLazyVector"
|
||||
FBReactNativeSpec:
|
||||
:path: "../node_modules/react-native/React/FBReactNativeSpec"
|
||||
glog:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
|
||||
RCT-Folly:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
|
||||
RCTRequired:
|
||||
:path: "../node_modules/react-native/Libraries/RCTRequired"
|
||||
RCTTypeSafety:
|
||||
:path: "../node_modules/react-native/Libraries/TypeSafety"
|
||||
React:
|
||||
:path: "../node_modules/react-native/"
|
||||
React-callinvoker:
|
||||
:path: "../node_modules/react-native/ReactCommon/callinvoker"
|
||||
React-Core:
|
||||
:path: "../node_modules/react-native/"
|
||||
React-CoreModules:
|
||||
:path: "../node_modules/react-native/React/CoreModules"
|
||||
React-cxxreact:
|
||||
:path: "../node_modules/react-native/ReactCommon/cxxreact"
|
||||
React-jsi:
|
||||
:path: "../node_modules/react-native/ReactCommon/jsi"
|
||||
React-jsiexecutor:
|
||||
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
|
||||
React-jsinspector:
|
||||
:path: "../node_modules/react-native/ReactCommon/jsinspector"
|
||||
React-logger:
|
||||
:path: "../node_modules/react-native/ReactCommon/logger"
|
||||
react-native-transparent-video:
|
||||
:path: "../.."
|
||||
React-perflogger:
|
||||
:path: "../node_modules/react-native/ReactCommon/reactperflogger"
|
||||
React-RCTActionSheet:
|
||||
:path: "../node_modules/react-native/Libraries/ActionSheetIOS"
|
||||
React-RCTAnimation:
|
||||
:path: "../node_modules/react-native/Libraries/NativeAnimation"
|
||||
React-RCTBlob:
|
||||
:path: "../node_modules/react-native/Libraries/Blob"
|
||||
React-RCTImage:
|
||||
:path: "../node_modules/react-native/Libraries/Image"
|
||||
React-RCTLinking:
|
||||
:path: "../node_modules/react-native/Libraries/LinkingIOS"
|
||||
React-RCTNetwork:
|
||||
:path: "../node_modules/react-native/Libraries/Network"
|
||||
React-RCTSettings:
|
||||
:path: "../node_modules/react-native/Libraries/Settings"
|
||||
React-RCTText:
|
||||
:path: "../node_modules/react-native/Libraries/Text"
|
||||
React-RCTVibration:
|
||||
:path: "../node_modules/react-native/Libraries/Vibration"
|
||||
React-runtimeexecutor:
|
||||
:path: "../node_modules/react-native/ReactCommon/runtimeexecutor"
|
||||
ReactCommon:
|
||||
:path: "../node_modules/react-native/ReactCommon"
|
||||
Yoga:
|
||||
:path: "../node_modules/react-native/ReactCommon/yoga"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
||||
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
|
||||
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
|
||||
FBLazyVector: d2db9d00883282819d03bbd401b2ad4360d47580
|
||||
FBReactNativeSpec: 94da4d84ba3b1acf459103320882daa481a2b62d
|
||||
Flipper: 30e8eeeed6abdc98edaf32af0cda2f198be4b733
|
||||
Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c
|
||||
Flipper-DoubleConversion: 57ffbe81ef95306cc9e69c4aa3aeeeeb58a6a28c
|
||||
Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b
|
||||
Flipper-Folly: 83af37379faa69497529e414bd43fbfc7cae259a
|
||||
Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6
|
||||
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
|
||||
Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541
|
||||
FlipperKit: d8d346844eca5d9120c17d441a2f38596e8ed2b9
|
||||
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
||||
glog: 85ecdd10ee8d8ec362ef519a6a45ff9aa27b2e85
|
||||
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
||||
OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
|
||||
RCT-Folly: 803a9cfd78114b2ec0f140cfa6fa2a6bafb2d685
|
||||
RCTRequired: 412e994c1e570cf35378a32c18fd46e50634938b
|
||||
RCTTypeSafety: ef27340c728e6d673af345ed69e479a010c8a2d8
|
||||
React: 36b9f5116572e5b80f01e562bb1f1451e8848e47
|
||||
React-callinvoker: 91e62870884d3db3a0db33bbb1ba4e53fa5210ca
|
||||
React-Core: 765ccc3861be1b93c7d5ca37f6b06e2efd6e7999
|
||||
React-CoreModules: da2ddff50a92576b6d58fbfc80a62ba3f81d8a4e
|
||||
React-cxxreact: b54cffd4feb550c3213cd38db4a2a4bdd896f715
|
||||
React-jsi: 103674913e4159a07df20ef214c6b563e90e7b2e
|
||||
React-jsiexecutor: e9895ccae253323ca70f693945fecbba091f0abd
|
||||
React-jsinspector: ec4fe4f65ccf9d67c8429dda955d3412db8a25ef
|
||||
React-logger: 85f4ef06b9723714b2dfa5b0e5502b673b271b58
|
||||
react-native-transparent-video: 54d0f657780b0a79a9113167342520cc28954ee0
|
||||
React-perflogger: d32ee13196f4ae2e4098fb7f8e7ed4f864c6fb0f
|
||||
React-RCTActionSheet: 81779c09e34a6a3d6b15783407ba9016a774f535
|
||||
React-RCTAnimation: b778eaaa42a884abcc5719035a7a0b2f54672658
|
||||
React-RCTBlob: 8edfc04c117decb0e7d4e6ab32bec91707e63ecb
|
||||
React-RCTImage: 2022097f1291bfebd0003e477318c72b07853578
|
||||
React-RCTLinking: bd8d889c65695181342541ce4420e9419845084c
|
||||
React-RCTNetwork: eae64b805d967bf3ece2cec3ad09218eeb32cb74
|
||||
React-RCTSettings: 0645af8aec5f40726e98d434a07ff58e75a81aa9
|
||||
React-RCTText: e55de507cda263ff58404c3e7d75bf76c2b80813
|
||||
React-RCTVibration: c3b8a3245267a3849b0c7cb91a37606bf5f3aa65
|
||||
React-runtimeexecutor: 434efc9e5b6d0f14f49867f130b39376c971c1aa
|
||||
ReactCommon: a30c2448e5a88bae6fcb0e3da124c14ae493dac1
|
||||
Yoga: 099a946cbf84c9b32ffdc4278d72db26710ecf92
|
||||
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
||||
|
||||
PODFILE CHECKSUM: 6d7615f1df282ca37c2aeda28a0509a54fa74246
|
||||
|
||||
COCOAPODS: 1.10.1
|
|
@ -11,7 +11,9 @@
|
|||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
26021728828441A991FCFAF3 /* libPods-TransparentVideoExample-TransparentVideoExampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D055D162686D462C72ADDC5 /* libPods-TransparentVideoExample-TransparentVideoExampleTests.a */; };
|
||||
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
|
||||
E28B5FB23A188DF377686BE7 /* libPods-TransparentVideoExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0267F842782FED148A4077C1 /* libPods-TransparentVideoExample.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -28,14 +30,20 @@
|
|||
00E356EE1AD99517003FC87E /* TransparentVideoExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TransparentVideoExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
00E356F21AD99517003FC87E /* TransparentVideoExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TransparentVideoExampleTests.m; sourceTree = "<group>"; };
|
||||
0267F842782FED148A4077C1 /* libPods-TransparentVideoExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-TransparentVideoExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07F961A680F5B00A75B9A /* TransparentVideoExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TransparentVideoExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = TransparentVideoExample/AppDelegate.h; sourceTree = "<group>"; };
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = TransparentVideoExample/AppDelegate.m; sourceTree = "<group>"; };
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = TransparentVideoExample/Images.xcassets; sourceTree = "<group>"; };
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = TransparentVideoExample/Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = TransparentVideoExample/main.m; sourceTree = "<group>"; };
|
||||
2A14A34D05389C0ADABA2876 /* Pods-TransparentVideoExample-TransparentVideoExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TransparentVideoExample-TransparentVideoExampleTests.release.xcconfig"; path = "Target Support Files/Pods-TransparentVideoExample-TransparentVideoExampleTests/Pods-TransparentVideoExample-TransparentVideoExampleTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
7D055D162686D462C72ADDC5 /* libPods-TransparentVideoExample-TransparentVideoExampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-TransparentVideoExample-TransparentVideoExampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = TransparentVideoExample/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
8FF5F75A1315DCD7F71FC708 /* Pods-TransparentVideoExample-TransparentVideoExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TransparentVideoExample-TransparentVideoExampleTests.debug.xcconfig"; path = "Target Support Files/Pods-TransparentVideoExample-TransparentVideoExampleTests/Pods-TransparentVideoExample-TransparentVideoExampleTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
B8C21317940F3C5C4CC04B40 /* Pods-TransparentVideoExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TransparentVideoExample.release.xcconfig"; path = "Target Support Files/Pods-TransparentVideoExample/Pods-TransparentVideoExample.release.xcconfig"; sourceTree = "<group>"; };
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||
EFA15796DEC98130A0A508D8 /* Pods-TransparentVideoExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TransparentVideoExample.debug.xcconfig"; path = "Target Support Files/Pods-TransparentVideoExample/Pods-TransparentVideoExample.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -43,6 +51,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
26021728828441A991FCFAF3 /* libPods-TransparentVideoExample-TransparentVideoExampleTests.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -50,6 +59,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E28B5FB23A188DF377686BE7 /* libPods-TransparentVideoExample.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -90,6 +100,8 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
|
||||
0267F842782FED148A4077C1 /* libPods-TransparentVideoExample.a */,
|
||||
7D055D162686D462C72ADDC5 /* libPods-TransparentVideoExample-TransparentVideoExampleTests.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
|
@ -109,6 +121,7 @@
|
|||
00E356EF1AD99517003FC87E /* TransparentVideoExampleTests */,
|
||||
83CBBA001A601CBA00E9B192 /* Products */,
|
||||
2D16E6871FA4F8E400B85C8A /* Frameworks */,
|
||||
A4F8B528F73DCA183806A23F /* Pods */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
|
@ -124,6 +137,18 @@
|
|||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A4F8B528F73DCA183806A23F /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EFA15796DEC98130A0A508D8 /* Pods-TransparentVideoExample.debug.xcconfig */,
|
||||
B8C21317940F3C5C4CC04B40 /* Pods-TransparentVideoExample.release.xcconfig */,
|
||||
8FF5F75A1315DCD7F71FC708 /* Pods-TransparentVideoExample-TransparentVideoExampleTests.debug.xcconfig */,
|
||||
2A14A34D05389C0ADABA2876 /* Pods-TransparentVideoExample-TransparentVideoExampleTests.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
|
@ -131,9 +156,12 @@
|
|||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "TransparentVideoExampleTests" */;
|
||||
buildPhases = (
|
||||
FCA46571122E4A63384E26E1 /* [CP] Check Pods Manifest.lock */,
|
||||
00E356EA1AD99517003FC87E /* Sources */,
|
||||
00E356EB1AD99517003FC87E /* Frameworks */,
|
||||
00E356EC1AD99517003FC87E /* Resources */,
|
||||
B254C78279E1703AC198B6F9 /* [CP] Embed Pods Frameworks */,
|
||||
5AAA60A676534D0A39309A17 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -149,11 +177,14 @@
|
|||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "TransparentVideoExample" */;
|
||||
buildPhases = (
|
||||
1D7003AAD3B26D08AB23B64A /* [CP] Check Pods Manifest.lock */,
|
||||
FD10A7F022414F080027D42C /* Start Packager */,
|
||||
13B07F871A680F5B00A75B9A /* Sources */,
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */,
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||
BB55B3945FAE5B08746CC796 /* [CP] Embed Pods Frameworks */,
|
||||
A209273306B44872997D8079 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -234,6 +265,118 @@
|
|||
shellPath = /bin/sh;
|
||||
shellScript = "set -e\n\nexport NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
|
||||
};
|
||||
1D7003AAD3B26D08AB23B64A /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-TransparentVideoExample-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
5AAA60A676534D0A39309A17 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-TransparentVideoExample-TransparentVideoExampleTests/Pods-TransparentVideoExample-TransparentVideoExampleTests-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-TransparentVideoExample-TransparentVideoExampleTests/Pods-TransparentVideoExample-TransparentVideoExampleTests-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TransparentVideoExample-TransparentVideoExampleTests/Pods-TransparentVideoExample-TransparentVideoExampleTests-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
A209273306B44872997D8079 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-TransparentVideoExample/Pods-TransparentVideoExample-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-TransparentVideoExample/Pods-TransparentVideoExample-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TransparentVideoExample/Pods-TransparentVideoExample-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
B254C78279E1703AC198B6F9 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-TransparentVideoExample-TransparentVideoExampleTests/Pods-TransparentVideoExample-TransparentVideoExampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-TransparentVideoExample-TransparentVideoExampleTests/Pods-TransparentVideoExample-TransparentVideoExampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TransparentVideoExample-TransparentVideoExampleTests/Pods-TransparentVideoExample-TransparentVideoExampleTests-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
BB55B3945FAE5B08746CC796 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-TransparentVideoExample/Pods-TransparentVideoExample-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-TransparentVideoExample/Pods-TransparentVideoExample-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TransparentVideoExample/Pods-TransparentVideoExample-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
FCA46571122E4A63384E26E1 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-TransparentVideoExample-TransparentVideoExampleTests-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
FD10A7F022414F080027D42C /* Start Packager */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -286,6 +429,7 @@
|
|||
/* Begin XCBuildConfiguration section */
|
||||
00E356F61AD99517003FC87E /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 8FF5F75A1315DCD7F71FC708 /* Pods-TransparentVideoExample-TransparentVideoExampleTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
|
@ -312,6 +456,7 @@
|
|||
};
|
||||
00E356F71AD99517003FC87E /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 2A14A34D05389C0ADABA2876 /* Pods-TransparentVideoExample-TransparentVideoExampleTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
|
@ -335,6 +480,7 @@
|
|||
};
|
||||
13B07F941A680F5B00A75B9A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = EFA15796DEC98130A0A508D8 /* Pods-TransparentVideoExample.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
|
@ -360,6 +506,7 @@
|
|||
};
|
||||
13B07F951A680F5B00A75B9A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = B8C21317940F3C5C4CC04B40 /* Pods-TransparentVideoExample.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
|
@ -414,6 +561,7 @@
|
|||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
|
@ -478,6 +626,7 @@
|
|||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:TransparentVideoExample.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,25 +1,59 @@
|
|||
import * as React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { TransparentVideoView } from 'react-native-transparent-video';
|
||||
import TransparentVideo from 'react-native-transparent-video';
|
||||
|
||||
const video1 = require('../assets/videos/background.mp4');
|
||||
const video2 = require('../assets/videos/playdoh-bat.mp4');
|
||||
|
||||
export default () => {
|
||||
const [background, setBackground] = useState('blue');
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
if (background === 'blue') {
|
||||
setBackground('green');
|
||||
} else if (background === 'green') {
|
||||
setBackground('red');
|
||||
} else if (background === 'red') {
|
||||
setBackground('yellow');
|
||||
} else if (background === 'yellow') {
|
||||
setBackground('darkblue');
|
||||
} else if (background === 'darkblue') {
|
||||
setBackground('gray');
|
||||
} else if (background === 'gray') {
|
||||
setBackground('blue');
|
||||
}
|
||||
}, 1000);
|
||||
}, [background]);
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<TransparentVideoView color="#32a852" style={styles.box} />
|
||||
<View style={{ ...styles.container, ...{ backgroundColor: background } }}>
|
||||
<TransparentVideo source={video1} style={styles.video1} />
|
||||
<TransparentVideo source={video2} style={styles.video2} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
box: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
marginVertical: 20,
|
||||
video1: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
zIndex: 0,
|
||||
},
|
||||
video2: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
zIndex: 1,
|
||||
},
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
// AVAsset+VideoSize.swift
|
||||
// MyTransparentVideoExample
|
||||
//
|
||||
// Created by Quentin Fasquel on 22/03/2020.
|
||||
// Copyright © 2020 Quentin Fasquel. All rights reserved.
|
||||
//
|
||||
|
||||
import AVFoundation
|
||||
|
||||
extension AVAsset {
|
||||
var videoSize: CGSize { tracks(withMediaType: .video).first?.naturalSize ?? .zero }
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
//
|
||||
// AVPlayerView.swift
|
||||
// MyTransparentVideoExample
|
||||
//
|
||||
// Created by Quentin on 27/10/2017.
|
||||
// Copyright © 2017 Quentin Fasquel. All rights reserved.
|
||||
//
|
||||
|
||||
import AVFoundation
|
||||
import UIKit
|
||||
|
||||
public class AVPlayerView: UIView {
|
||||
|
||||
deinit {
|
||||
playerItem = nil
|
||||
}
|
||||
|
||||
public override class var layerClass: AnyClass {
|
||||
return AVPlayerLayer.self
|
||||
}
|
||||
|
||||
public var playerLayer: AVPlayerLayer {
|
||||
return layer as! AVPlayerLayer
|
||||
}
|
||||
|
||||
public private(set) var player: AVPlayer? {
|
||||
set { playerLayer.player = newValue }
|
||||
get { return playerLayer.player }
|
||||
}
|
||||
|
||||
private var playerItemStatusObserver: NSKeyValueObservation?
|
||||
|
||||
private(set) var playerItem: AVPlayerItem? = nil {
|
||||
didSet {
|
||||
// If `isLoopingEnabled` is called before the AVPlayer was set
|
||||
setupLooping()
|
||||
}
|
||||
}
|
||||
|
||||
public func loadPlayerItem(_ playerItem: AVPlayerItem, onReady: ((Result<AVPlayer, Error>) -> Void)? = nil) {
|
||||
let player = AVPlayer(playerItem: playerItem)
|
||||
|
||||
self.player = player
|
||||
self.playerItem = playerItem
|
||||
|
||||
guard let completion = onReady else {
|
||||
playerItemStatusObserver = nil
|
||||
return
|
||||
}
|
||||
|
||||
playerItemStatusObserver = playerItem.observe(\.status) { [weak self] item, _ in
|
||||
switch item.status {
|
||||
case .failed:
|
||||
completion(.failure(item.error!))
|
||||
case .readyToPlay:
|
||||
completion(.success(player))
|
||||
// Stop observing
|
||||
self?.playerItemStatusObserver = nil
|
||||
case .unknown:
|
||||
break
|
||||
@unknown default:
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Looping Handler
|
||||
|
||||
/// When set to `true`, the player view automatically adds an observer on its AVPlayer,
|
||||
/// and it will play again from start every time playback ends.
|
||||
/// * Warning: This will not result in a smooth video loop.
|
||||
public var isLoopingEnabled: Bool = false {
|
||||
didSet { setupLooping() }
|
||||
}
|
||||
|
||||
private var didPlayToEndTimeObsever: NSObjectProtocol? = nil {
|
||||
willSet(newObserver) {
|
||||
// When updating didPlayToEndTimeObserver,
|
||||
// automatically remove its previous value from the Notification Center
|
||||
if let observer = didPlayToEndTimeObsever, didPlayToEndTimeObsever !== newObserver {
|
||||
NotificationCenter.default.removeObserver(observer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func setupLooping() {
|
||||
guard let playerItem = self.playerItem, let player = self.player else {
|
||||
return
|
||||
}
|
||||
|
||||
guard isLoopingEnabled else {
|
||||
didPlayToEndTimeObsever = nil
|
||||
return
|
||||
}
|
||||
|
||||
didPlayToEndTimeObsever = NotificationCenter.default.addObserver(
|
||||
forName: .AVPlayerItemDidPlayToEndTime, object: playerItem, queue: nil, using: { _ in
|
||||
player.seek(to: CMTime.zero) { _ in
|
||||
player.play()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// AlphaFrameFilter.metal
|
||||
// MyTransparentVideoExample
|
||||
//
|
||||
// Created by Quentin Fasquel on 22/03/2020.
|
||||
// Copyright © 2020 Quentin Fasquel. All rights reserved.
|
||||
//
|
||||
|
||||
#include <metal_stdlib>
|
||||
#include <CoreImage/CoreImage.h> // includes CIKernelMetalLib.h
|
||||
|
||||
extern "C" {
|
||||
namespace coreimage {
|
||||
float4 alphaFrame(sampler source, sampler mask) {
|
||||
float4 color = source.sample(source.coord());
|
||||
float opacity = mask.sample(mask.coord()).r;
|
||||
return float4(color.rgb, opacity);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
//
|
||||
// ChromaKeyFilter.swift
|
||||
// MyTransparentVideoExample
|
||||
//
|
||||
// Created by Quentin on 27/10/2017.
|
||||
// Copyright © 2017 Quentin Fasquel. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreImage
|
||||
|
||||
typealias AlphaFrameFilterError = AlphaFrameFilter.Error
|
||||
|
||||
final class AlphaFrameFilter: CIFilter {
|
||||
|
||||
enum Error: Swift.Error {
|
||||
/// This error is thrown when using renderingMode `builtInFilter` and the filter named *CIBlendWithMask* was not found
|
||||
case buildInFilterNotFound
|
||||
/// This error is thrown when `inputImage` and `maskImage` have different **extents**
|
||||
case incompatibleExtents
|
||||
/// This error is thrown when a kernel couldn't be initialized,
|
||||
/// which may happen when using renderingMode `colorKernel` or `metalKernel`
|
||||
case invalidKernel
|
||||
/// This error is thrown when `inputImage` or `maskImage` is missing
|
||||
case invalidParameters
|
||||
/// This error would be thrown when output image is `nil` in any other case, it typically should not happen
|
||||
case unknown
|
||||
}
|
||||
|
||||
private(set) var inputImage: CIImage?
|
||||
private(set) var maskImage: CIImage?
|
||||
private(set) var outputError: Swift.Error?
|
||||
|
||||
private let renderingMode: RenderingMode
|
||||
|
||||
required init(renderingMode: RenderingMode) {
|
||||
self.renderingMode = renderingMode
|
||||
super.init()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override var outputImage: CIImage? {
|
||||
// Output is nil if an input image and a mask image aren't provided
|
||||
guard let inputImage = inputImage, let maskImage = maskImage else {
|
||||
outputError = Error.invalidParameters
|
||||
return nil
|
||||
}
|
||||
|
||||
// Input image & mask image should have the same extent
|
||||
guard inputImage.extent == maskImage.extent else {
|
||||
outputError = Error.incompatibleExtents
|
||||
return nil
|
||||
}
|
||||
|
||||
outputError = nil
|
||||
|
||||
return render(using: renderingMode, inputImage: inputImage, maskImage: maskImage)
|
||||
}
|
||||
|
||||
func process(_ inputImage: CIImage, mask maskImage: CIImage) throws -> CIImage {
|
||||
self.inputImage = inputImage
|
||||
self.maskImage = maskImage
|
||||
|
||||
guard let outputImage = self.outputImage else {
|
||||
throw outputError ?? Error.unknown
|
||||
}
|
||||
|
||||
return outputImage
|
||||
}
|
||||
|
||||
// MARK: - Rendering
|
||||
|
||||
enum RenderingMode {
|
||||
case builtInFilter
|
||||
case colorKernel
|
||||
case metalKernel
|
||||
}
|
||||
|
||||
private static var colorKernel: CIColorKernel? = {
|
||||
// `init(source:)` was deprecated in iOS 12.0: Core Image Kernel Language API deprecated.
|
||||
// This warning is silent because of preprocessor macro `CI_SILENCE_GL_DEPRECATION`
|
||||
return CIColorKernel(source: """
|
||||
kernel vec4 alphaFrame(__sample s, __sample m) {
|
||||
return vec4( s.rgb, m.r );
|
||||
}
|
||||
""")
|
||||
}()
|
||||
|
||||
private static var metalKernelError: Swift.Error?
|
||||
private static var metalKernel: CIKernel? = {
|
||||
do { return try CIKernel(functionName: "alphaFrame") }
|
||||
catch { metalKernelError = error; return nil }
|
||||
}()
|
||||
|
||||
private func render(using renderingMode: RenderingMode, inputImage: CIImage, maskImage: CIImage) -> CIImage? {
|
||||
switch renderingMode {
|
||||
|
||||
case .builtInFilter:
|
||||
guard let filter = CIFilter(name: "CIBlendWithMask") else {
|
||||
outputError = Error.buildInFilterNotFound
|
||||
return nil
|
||||
}
|
||||
|
||||
let outputExtent = inputImage.extent
|
||||
let backgroundImage = CIImage(color: .clear).cropped(to: outputExtent)
|
||||
filter.setValue(backgroundImage, forKey: kCIInputBackgroundImageKey)
|
||||
filter.setValue(inputImage, forKey: kCIInputImageKey)
|
||||
filter.setValue(maskImage, forKey: kCIInputMaskImageKey)
|
||||
return filter.outputImage
|
||||
|
||||
case .colorKernel:
|
||||
// Force a fatal error if our kernel source isn't correct
|
||||
guard let colorKernel = Self.colorKernel else {
|
||||
outputError = Error.invalidKernel
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply our color kernel with the proper parameters
|
||||
let outputExtent = inputImage.extent
|
||||
let arguments = [inputImage, maskImage]
|
||||
return colorKernel.apply(extent: outputExtent, arguments: arguments)
|
||||
|
||||
case .metalKernel:
|
||||
guard let metalKernel = Self.metalKernel else {
|
||||
outputError = Self.metalKernelError ?? Error.invalidKernel
|
||||
return nil
|
||||
}
|
||||
|
||||
let outputExtent = inputImage.extent
|
||||
let roiCallback: CIKernelROICallback = { _, rect in rect }
|
||||
let arguments = [inputImage, maskImage]
|
||||
return metalKernel.apply(extent: outputExtent, roiCallback: roiCallback, arguments: arguments)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// CIImage+Split.swift
|
||||
// MyTransparentVideoExample
|
||||
//
|
||||
// Created by Quentin Fasquel on 27/03/2020.
|
||||
// Copyright © 2020 Quentin Fasquel. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreImage
|
||||
|
||||
extension CIImage {
|
||||
|
||||
typealias VerticalSplit = (topImage: CIImage, bottomImage: CIImage)
|
||||
|
||||
func verticalSplit() -> VerticalSplit {
|
||||
let outputExtent = self.extent.applying(CGAffineTransform(scaleX: 1.0, y: 0.5))
|
||||
|
||||
// Get the top region according to Core Image coordinate system, (0,0) being bottom left
|
||||
let translate = CGAffineTransform(translationX: 0, y: outputExtent.height)
|
||||
let topRegion = outputExtent.applying(translate)
|
||||
var topImage = self.cropped(to: topRegion)
|
||||
// Translate topImage back to origin
|
||||
topImage = topImage.transformed(by: translate.inverted())
|
||||
|
||||
let bottomRegion = outputExtent
|
||||
let bottomImage = self.cropped(to: bottomRegion)
|
||||
|
||||
return (topImage, bottomImage)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// CIKernelExtension.swift
|
||||
// MyTransparentVideoExample
|
||||
//
|
||||
// Created by Quentin Fasquel on 22/03/2020.
|
||||
// Copyright © 2020 Quentin Fasquel. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreImage
|
||||
import Metal
|
||||
|
||||
private func defaultMetalLibrary() throws -> Data {
|
||||
let url = Bundle.main.url(forResource: "default", withExtension: "metallib")!
|
||||
return try Data(contentsOf: url)
|
||||
}
|
||||
|
||||
extension CIKernel {
|
||||
/// Init CI kernel with just a `functionName` directly from default metal library
|
||||
convenience init(functionName: String) throws {
|
||||
let metalLibrary = try defaultMetalLibrary()
|
||||
try self.init(functionName: functionName, fromMetalLibraryData: metalLibrary)
|
||||
}
|
||||
}
|
|
@ -7,8 +7,8 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
5E555C0D2413F4C50049A1A2 /* TransparentVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* TransparentVideo.m */; };
|
||||
F4FF95D7245B92E800C19C63 /* TransparentVideo.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* TransparentVideo.swift */; };
|
||||
C12B19DF2A020CC0001F03AB /* TransparentVideoViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C12B19DD2A020CC0001F03AB /* TransparentVideoViewManager.m */; };
|
||||
C12B19E02A020CC0001F03AB /* TransparentVideoViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12B19DE2A020CC0001F03AB /* TransparentVideoViewManager.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
|
@ -25,9 +25,9 @@
|
|||
|
||||
/* Begin PBXFileReference section */
|
||||
134814201AA4EA6300B7C361 /* libTransparentVideo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTransparentVideo.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B3E7B5891CC2AC0600A0062D /* TransparentVideo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TransparentVideo.m; sourceTree = "<group>"; };
|
||||
C12B19DD2A020CC0001F03AB /* TransparentVideoViewManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TransparentVideoViewManager.m; sourceTree = "<group>"; };
|
||||
C12B19DE2A020CC0001F03AB /* TransparentVideoViewManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransparentVideoViewManager.swift; sourceTree = "<group>"; };
|
||||
F4FF95D5245B92E700C19C63 /* TransparentVideo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TransparentVideo-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
F4FF95D6245B92E800C19C63 /* TransparentVideo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransparentVideo.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -52,8 +52,8 @@
|
|||
58B511D21A9E6C8500147676 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F4FF95D6245B92E800C19C63 /* TransparentVideo.swift */,
|
||||
B3E7B5891CC2AC0600A0062D /* TransparentVideo.m */,
|
||||
C12B19DD2A020CC0001F03AB /* TransparentVideoViewManager.m */,
|
||||
C12B19DE2A020CC0001F03AB /* TransparentVideoViewManager.swift */,
|
||||
F4FF95D5245B92E700C19C63 /* TransparentVideo-Bridging-Header.h */,
|
||||
134814211AA4EA7D00B7C361 /* Products */,
|
||||
);
|
||||
|
@ -116,8 +116,8 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F4FF95D7245B92E800C19C63 /* TransparentVideo.swift in Sources */,
|
||||
B3E7B58A1CC2AC0600A0062D /* TransparentVideo.m in Sources */,
|
||||
C12B19DF2A020CC0001F03AB /* TransparentVideoViewManager.m in Sources */,
|
||||
C12B19E02A020CC0001F03AB /* TransparentVideoViewManager.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
@interface RCT_EXTERN_MODULE(TransparentVideoViewManager, RCTViewManager)
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(color, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary);
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import AVFoundation
|
||||
import os.log
|
||||
|
||||
@objc(TransparentVideoViewManager)
|
||||
class TransparentVideoViewManager: RCTViewManager {
|
||||
|
||||
|
@ -12,25 +15,108 @@ class TransparentVideoViewManager: RCTViewManager {
|
|||
|
||||
class TransparentVideoView : UIView {
|
||||
|
||||
@objc var color: String = "" {
|
||||
private var source: VideoSource?
|
||||
private var playerView: AVPlayerView?
|
||||
|
||||
@objc var src: NSDictionary = NSDictionary() {
|
||||
didSet {
|
||||
self.backgroundColor = hexStringToUIColor(hexColor: color)
|
||||
self.source = VideoSource(src)
|
||||
let itemUrl = URL(string: self.source!.uri!)!
|
||||
loadVideoPlayer(itemUrl: itemUrl)
|
||||
}
|
||||
}
|
||||
|
||||
func hexStringToUIColor(hexColor: String) -> UIColor {
|
||||
let stringScanner = Scanner(string: hexColor)
|
||||
func loadVideoPlayer(itemUrl: URL) {
|
||||
if (self.playerView == nil) {
|
||||
let playerView = AVPlayerView(frame: CGRect(origin: .zero, size: .zero))
|
||||
addSubview(playerView)
|
||||
|
||||
if(hexColor.hasPrefix("#")) {
|
||||
stringScanner.scanLocation = 1
|
||||
// Use Auto Layout anchors to center our playerView
|
||||
playerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
playerView.topAnchor.constraint(equalTo: self.topAnchor),
|
||||
playerView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
|
||||
playerView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
|
||||
playerView.trailingAnchor.constraint(equalTo: self.trailingAnchor)
|
||||
])
|
||||
|
||||
// Setup our playerLayer to hold a pixel buffer format with "alpha"
|
||||
let playerLayer: AVPlayerLayer = playerView.playerLayer
|
||||
playerLayer.pixelBufferAttributes = [
|
||||
(kCVPixelBufferPixelFormatTypeKey as String): kCVPixelFormatType_32BGRA]
|
||||
|
||||
// Setup looping on our video
|
||||
playerView.isLoopingEnabled = true
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(appEnteredBackgound), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(appEnteredForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
|
||||
|
||||
self.playerView = playerView
|
||||
}
|
||||
var color: UInt32 = 0
|
||||
stringScanner.scanHexInt32(&color)
|
||||
|
||||
let r = CGFloat(Int(color >> 16) & 0x000000FF)
|
||||
let g = CGFloat(Int(color >> 8) & 0x000000FF)
|
||||
let b = CGFloat(Int(color) & 0x000000FF)
|
||||
// Load our player item
|
||||
let playerItem = createTransparentItem(url: itemUrl)
|
||||
|
||||
return UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: 1)
|
||||
self.playerView!.loadPlayerItem(playerItem) { result in
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
return print("Something went wrong when loading our video", error)
|
||||
|
||||
case .success(let player):
|
||||
// Finally, we can start playing
|
||||
player.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Player Item Configuration
|
||||
|
||||
func createTransparentItem(url: URL) -> AVPlayerItem {
|
||||
let asset = AVAsset(url: url)
|
||||
let playerItem = AVPlayerItem(asset: asset)
|
||||
// Set the video so that seeking also renders with transparency
|
||||
playerItem.seekingWaitsForVideoCompositionRendering = true
|
||||
// Apply a video composition (which applies our custom filter)
|
||||
playerItem.videoComposition = createVideoComposition(for: asset)
|
||||
return playerItem
|
||||
}
|
||||
|
||||
func createVideoComposition(for asset: AVAsset) -> AVVideoComposition {
|
||||
let filter = AlphaFrameFilter(renderingMode: .builtInFilter)
|
||||
let composition = AVMutableVideoComposition(asset: asset, applyingCIFiltersWithHandler: { request in
|
||||
do {
|
||||
let (inputImage, maskImage) = request.sourceImage.verticalSplit()
|
||||
let outputImage = try filter.process(inputImage, mask: maskImage)
|
||||
return request.finish(with: outputImage, context: nil)
|
||||
} catch {
|
||||
os_log("Video composition error: %s", String(describing: error))
|
||||
return request.finish(with: error)
|
||||
}
|
||||
})
|
||||
|
||||
composition.renderSize = asset.videoSize.applying(CGAffineTransform(scaleX: 1.0, y: 0.5))
|
||||
return composition
|
||||
}
|
||||
|
||||
// MARK: - Lifecycle callbacks
|
||||
|
||||
@objc func appEnteredBackgound() {
|
||||
if let tracks = self.playerView?.player?.currentItem?.tracks {
|
||||
for track in tracks {
|
||||
if (track.assetTrack?.hasMediaCharacteristic(AVMediaCharacteristic.visual))! {
|
||||
track.isEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func appEnteredForeground() {
|
||||
if let tracks = self.playerView?.player?.currentItem?.tracks {
|
||||
for track in tracks {
|
||||
if (track.assetTrack?.hasMediaCharacteristic(AVMediaCharacteristic.visual))! {
|
||||
track.isEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// VideoSource.swift
|
||||
// react-native-transparent-video
|
||||
//
|
||||
// Created by Brian Sztamfater on 03/05/2023.
|
||||
//
|
||||
|
||||
struct VideoSource {
|
||||
let type: String?
|
||||
let uri: String?
|
||||
let isNetwork: Bool
|
||||
let isAsset: Bool
|
||||
let shouldCache: Bool
|
||||
let requestHeaders: Dictionary<String,Any>?
|
||||
let startTime: Int64?
|
||||
let endTime: Int64?
|
||||
|
||||
let json: NSDictionary?
|
||||
|
||||
init(_ json: NSDictionary!) {
|
||||
guard json != nil else {
|
||||
self.json = nil
|
||||
self.type = nil
|
||||
self.uri = nil
|
||||
self.isNetwork = false
|
||||
self.isAsset = false
|
||||
self.shouldCache = false
|
||||
self.requestHeaders = nil
|
||||
self.startTime = nil
|
||||
self.endTime = nil
|
||||
return
|
||||
}
|
||||
self.json = json
|
||||
self.type = json["type"] as? String
|
||||
self.uri = json["uri"] as? String
|
||||
self.isNetwork = json["isNetwork"] as? Bool ?? false
|
||||
self.isAsset = json["isAsset"] as? Bool ?? false
|
||||
self.shouldCache = json["shouldCache"] as? Bool ?? false
|
||||
self.requestHeaders = json["requestHeaders"] as? Dictionary<String,Any>
|
||||
self.startTime = json["startTime"] as? Int64
|
||||
self.endTime = json["endTime"] as? Int64
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "react-native-transparent-video",
|
||||
"version": "0.1.0",
|
||||
"description": "test",
|
||||
"description": "React Native video player with alpha channel (alpha-packing) support.",
|
||||
"main": "lib/commonjs/index",
|
||||
"module": "lib/module/index",
|
||||
"types": "lib/typescript/index.d.ts",
|
||||
|
|
|
@ -18,6 +18,10 @@ Pod::Spec.new do |s|
|
|||
|
||||
s.dependency "React-Core"
|
||||
|
||||
# s.ios.user_target_xcconfig = {
|
||||
# 'OTHER_LDFLAGS' => '-fcikernel',
|
||||
# }
|
||||
|
||||
# Don't install the dependencies when we run `pod install` in the old architecture.
|
||||
if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
|
||||
s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
|
||||
|
|
|
@ -1,26 +1,39 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
requireNativeComponent,
|
||||
UIManager,
|
||||
Platform,
|
||||
ViewStyle,
|
||||
} from 'react-native';
|
||||
|
||||
const LINKING_ERROR =
|
||||
`The package 'react-native-transparent-video' doesn't seem to be linked. Make sure: \n\n` +
|
||||
Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
|
||||
'- You rebuilt the app after installing the package\n' +
|
||||
'- You are not using Expo Go\n';
|
||||
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
|
||||
|
||||
type TransparentVideoProps = {
|
||||
color: string;
|
||||
style: ViewStyle;
|
||||
source?: any;
|
||||
};
|
||||
|
||||
const ComponentName = 'TransparentVideoView';
|
||||
|
||||
export const TransparentVideoView =
|
||||
UIManager.getViewManagerConfig(ComponentName) != null
|
||||
? requireNativeComponent<TransparentVideoProps>(ComponentName)
|
||||
: () => {
|
||||
throw new Error(LINKING_ERROR);
|
||||
};
|
||||
const TransparentVideoView = requireNativeComponent(ComponentName);
|
||||
|
||||
class TransparentVideo extends React.PureComponent<TransparentVideoProps> {
|
||||
render() {
|
||||
const source = resolveAssetSource(this.props.source) || {};
|
||||
let uri = source.uri || '';
|
||||
if (uri && uri.match(/^\//)) {
|
||||
uri = `file://${uri}`;
|
||||
}
|
||||
|
||||
const nativeProps = Object.assign({}, this.props);
|
||||
Object.assign(nativeProps, {
|
||||
style: nativeProps.style,
|
||||
src: {
|
||||
uri,
|
||||
type: source.type || '',
|
||||
},
|
||||
});
|
||||
|
||||
return <TransparentVideoView {...nativeProps} />;
|
||||
}
|
||||
}
|
||||
|
||||
export default TransparentVideo;
|
||||
|
|
Loading…
Reference in New Issue