feat: implement component iOS bridge and demo app example

Signed-off-by: Brian Sztamfater <brian@status.im>
This commit is contained in:
Brian Sztamfater 2023-05-04 16:11:22 -03:00
parent c8dab9a4b1
commit 6640e69a81
33 changed files with 18569 additions and 55 deletions

Binary file not shown.

View File

@ -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

234
android/gradlew vendored Executable file
View File

@ -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" "$@"

89
android/gradlew.bat vendored Normal file
View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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
}

View File

@ -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.

533
example/ios/Podfile.lock Normal file
View File

@ -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

View File

@ -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;

View File

@ -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>

View File

@ -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>

View File

@ -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,
},
});

4227
example/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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 }
}

103
ios/AVPlayerView.swift Normal file
View File

@ -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()
}
})
}
}

View File

@ -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);
}
}
}

137
ios/AlphaFrameFilter.swift Normal file
View File

@ -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)
}
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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;
};

View File

@ -2,6 +2,6 @@
@interface RCT_EXTERN_MODULE(TransparentVideoViewManager, RCTViewManager)
RCT_EXPORT_VIEW_PROPERTY(color, NSString)
RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary);
@end

View File

@ -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
}
}
}
}
}

43
ios/VideoSource.swift Normal file
View File

@ -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
}
}

View File

@ -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",

View File

@ -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"

View File

@ -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;

9985
yarn.lock Normal file

File diff suppressed because it is too large Load Diff