Commit 9e10c7aa5fabbf623b092facdf6300f0a2afa800
0 parents
新建推流SDKdemo
Showing
96 changed files
with
3203 additions
and
0 deletions
.gitignore
0 → 100644
.idea/compiler.xml
0 → 100644
| 1 | +++ a/.idea/compiler.xml | |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<project version="4"> | |
| 3 | + <component name="CompilerConfiguration"> | |
| 4 | + <resourceExtensions /> | |
| 5 | + <wildcardResourcePatterns> | |
| 6 | + <entry name="!?*.java" /> | |
| 7 | + <entry name="!?*.form" /> | |
| 8 | + <entry name="!?*.class" /> | |
| 9 | + <entry name="!?*.groovy" /> | |
| 10 | + <entry name="!?*.scala" /> | |
| 11 | + <entry name="!?*.flex" /> | |
| 12 | + <entry name="!?*.kt" /> | |
| 13 | + <entry name="!?*.clj" /> | |
| 14 | + <entry name="!?*.aj" /> | |
| 15 | + </wildcardResourcePatterns> | |
| 16 | + <annotationProcessing> | |
| 17 | + <profile default="true" name="Default" enabled="false"> | |
| 18 | + <processorPath useClasspath="true" /> | |
| 19 | + </profile> | |
| 20 | + </annotationProcessing> | |
| 21 | + </component> | |
| 22 | +</project> | |
| 0 | 23 | \ No newline at end of file | ... | ... |
.idea/copyright/profiles_settings.xml
0 → 100644
.idea/gradle.xml
0 → 100644
| 1 | +++ a/.idea/gradle.xml | |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<project version="4"> | |
| 3 | + <component name="GradleSettings"> | |
| 4 | + <option name="linkedExternalProjectsSettings"> | |
| 5 | + <GradleProjectSettings> | |
| 6 | + <option name="distributionType" value="LOCAL" /> | |
| 7 | + <option name="externalProjectPath" value="$PROJECT_DIR$" /> | |
| 8 | + <option name="gradleHome" value="C:\Program Files\Android\Android Studio\gradle\gradle-2.14.1" /> | |
| 9 | + <option name="modules"> | |
| 10 | + <set> | |
| 11 | + <option value="$PROJECT_DIR$" /> | |
| 12 | + <option value="$PROJECT_DIR$/app" /> | |
| 13 | + </set> | |
| 14 | + </option> | |
| 15 | + <option name="resolveModulePerSourceSet" value="false" /> | |
| 16 | + </GradleProjectSettings> | |
| 17 | + </option> | |
| 18 | + </component> | |
| 19 | +</project> | |
| 0 | 20 | \ No newline at end of file | ... | ... |
.idea/misc.xml
0 → 100644
| 1 | +++ a/.idea/misc.xml | |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<project version="4"> | |
| 3 | + <component name="EntryPointsManager"> | |
| 4 | + <entry_points version="2.0" /> | |
| 5 | + </component> | |
| 6 | + <component name="NullableNotNullManager"> | |
| 7 | + <option name="myDefaultNullable" value="android.support.annotation.Nullable" /> | |
| 8 | + <option name="myDefaultNotNull" value="android.support.annotation.NonNull" /> | |
| 9 | + <option name="myNullables"> | |
| 10 | + <value> | |
| 11 | + <list size="4"> | |
| 12 | + <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" /> | |
| 13 | + <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" /> | |
| 14 | + <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" /> | |
| 15 | + <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" /> | |
| 16 | + </list> | |
| 17 | + </value> | |
| 18 | + </option> | |
| 19 | + <option name="myNotNulls"> | |
| 20 | + <value> | |
| 21 | + <list size="4"> | |
| 22 | + <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" /> | |
| 23 | + <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" /> | |
| 24 | + <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" /> | |
| 25 | + <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" /> | |
| 26 | + </list> | |
| 27 | + </value> | |
| 28 | + </option> | |
| 29 | + </component> | |
| 30 | + <component name="ProjectLevelVcsManager" settingsEditedManually="false"> | |
| 31 | + <OptionsSetting value="true" id="Add" /> | |
| 32 | + <OptionsSetting value="true" id="Remove" /> | |
| 33 | + <OptionsSetting value="true" id="Checkout" /> | |
| 34 | + <OptionsSetting value="true" id="Update" /> | |
| 35 | + <OptionsSetting value="true" id="Status" /> | |
| 36 | + <OptionsSetting value="true" id="Edit" /> | |
| 37 | + <ConfirmationsSetting value="0" id="Add" /> | |
| 38 | + <ConfirmationsSetting value="0" id="Remove" /> | |
| 39 | + </component> | |
| 40 | + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> | |
| 41 | + <output url="file://$PROJECT_DIR$/build/classes" /> | |
| 42 | + </component> | |
| 43 | + <component name="ProjectType"> | |
| 44 | + <option name="id" value="Android" /> | |
| 45 | + </component> | |
| 46 | +</project> | |
| 0 | 47 | \ No newline at end of file | ... | ... |
.idea/modules.xml
0 → 100644
| 1 | +++ a/.idea/modules.xml | |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<project version="4"> | |
| 3 | + <component name="ProjectModuleManager"> | |
| 4 | + <modules> | |
| 5 | + <module fileurl="file://$PROJECT_DIR$/QNStreamerDemo.iml" filepath="$PROJECT_DIR$/QNStreamerDemo.iml" /> | |
| 6 | + <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" /> | |
| 7 | + </modules> | |
| 8 | + </component> | |
| 9 | +</project> | |
| 0 | 10 | \ No newline at end of file | ... | ... |
.idea/runConfigurations.xml
0 → 100644
| 1 | +++ a/.idea/runConfigurations.xml | |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<project version="4"> | |
| 3 | + <component name="RunConfigurationProducerService"> | |
| 4 | + <option name="ignoredProducers"> | |
| 5 | + <set> | |
| 6 | + <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" /> | |
| 7 | + <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" /> | |
| 8 | + <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" /> | |
| 9 | + </set> | |
| 10 | + </option> | |
| 11 | + </component> | |
| 12 | +</project> | |
| 0 | 13 | \ No newline at end of file | ... | ... |
.idea/vcs.xml
0 → 100644
app/.gitignore
0 → 100644
app/build.gradle
0 → 100644
| 1 | +++ a/app/build.gradle | |
| 1 | +apply plugin: 'com.android.application' | |
| 2 | + | |
| 3 | +android { | |
| 4 | + compileSdkVersion 24 | |
| 5 | + buildToolsVersion "24.0.3" | |
| 6 | + defaultConfig { | |
| 7 | + applicationId "com.cnlive.demo.stream" | |
| 8 | + minSdkVersion 16 | |
| 9 | + targetSdkVersion 24 | |
| 10 | + versionCode 1 | |
| 11 | + versionName "1.0" | |
| 12 | + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" | |
| 13 | + } | |
| 14 | + buildTypes { | |
| 15 | + release { | |
| 16 | + minifyEnabled false | |
| 17 | + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | |
| 18 | + } | |
| 19 | + } | |
| 20 | +} | |
| 21 | + | |
| 22 | +dependencies { | |
| 23 | + compile fileTree(include: ['*.jar'], dir: 'libs') | |
| 24 | + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { | |
| 25 | + exclude group: 'com.android.support', module: 'support-annotations' | |
| 26 | + }) | |
| 27 | + compile 'com.android.support:appcompat-v7:24.2.1' | |
| 28 | + testCompile 'junit:junit:4.12' | |
| 29 | + compile files('libs/libcnliveutilplus.jar') | |
| 30 | +} | ... | ... |
app/libs/libcnlivestream.jar
0 → 100644
No preview for this file type
app/libs/libcnliveutilplus.jar
0 → 100644
No preview for this file type
app/proguard-rules.pro
0 → 100644
| 1 | +++ a/app/proguard-rules.pro | |
| 1 | +# Add project specific ProGuard rules here. | |
| 2 | +# By default, the flags in this file are appended to flags specified | |
| 3 | +# in D:\android_sdk/tools/proguard/proguard-android.txt | |
| 4 | +# You can edit the include path and order by changing the proguardFiles | |
| 5 | +# directive in build.gradle. | |
| 6 | +# | |
| 7 | +# For more details, see | |
| 8 | +# http://developer.android.com/guide/developing/tools/proguard.html | |
| 9 | + | |
| 10 | +# Add any project specific keep options here: | |
| 11 | + | |
| 12 | +# If your project uses WebView with JS, uncomment the following | |
| 13 | +# and specify the fully qualified class name to the JavaScript interface | |
| 14 | +# class: | |
| 15 | +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | |
| 16 | +# public *; | |
| 17 | +#} | ... | ... |
app/src/androidTest/java/com/cnlive/demo/stream/ExampleInstrumentedTest.java
0 → 100644
| 1 | +++ a/app/src/androidTest/java/com/cnlive/demo/stream/ExampleInstrumentedTest.java | |
| 1 | +package com.cnlive.demo.stream; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.support.test.InstrumentationRegistry; | |
| 5 | +import android.support.test.runner.AndroidJUnit4; | |
| 6 | + | |
| 7 | +import org.junit.Test; | |
| 8 | +import org.junit.runner.RunWith; | |
| 9 | + | |
| 10 | +import static org.junit.Assert.*; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * Instrumentation test, which will execute on an Android device. | |
| 14 | + * | |
| 15 | + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | |
| 16 | + */ | |
| 17 | +@RunWith(AndroidJUnit4.class) | |
| 18 | +public class ExampleInstrumentedTest { | |
| 19 | + @Test | |
| 20 | + public void useAppContext() throws Exception { | |
| 21 | + // Context of the app under test. | |
| 22 | + Context appContext = InstrumentationRegistry.getTargetContext(); | |
| 23 | + | |
| 24 | + assertEquals("com.cnlive.demo.stream", appContext.getPackageName()); | |
| 25 | + } | |
| 26 | +} | ... | ... |
app/src/main/AndroidManifest.xml
0 → 100644
| 1 | +++ a/app/src/main/AndroidManifest.xml | |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + package="com.cnlive.demo.stream"> | |
| 4 | + | |
| 5 | + <uses-permission android:name="android.permission.INTERNET" /> | |
| 6 | + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | |
| 7 | + <uses-permission android:name="android.permission.RECORD_AUDIO" /> | |
| 8 | + <uses-permission android:name="android.permission.CAMERA" /> | |
| 9 | + <uses-permission android:name="android.permission.WAKE_LOCK" /> | |
| 10 | + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | |
| 11 | + <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> | |
| 12 | + | |
| 13 | + <uses-feature android:name="android.hardware.camera.autofocus" /> | |
| 14 | + <uses-feature android:glEsVersion="0x00020000" android:required="true" /> | |
| 15 | + | |
| 16 | + <application | |
| 17 | + android:name=".CNStreamApplication" | |
| 18 | + android:allowBackup="true" | |
| 19 | + android:icon="@mipmap/ic_launcher" | |
| 20 | + android:label="@string/app_name" | |
| 21 | + android:supportsRtl="true" | |
| 22 | + android:theme="@style/AppTheme"> | |
| 23 | + <activity android:name=".MainActivity"> | |
| 24 | + <intent-filter> | |
| 25 | + <action android:name="android.intent.action.MAIN" /> | |
| 26 | + | |
| 27 | + <category android:name="android.intent.category.LAUNCHER" /> | |
| 28 | + </intent-filter> | |
| 29 | + </activity> | |
| 30 | + <activity android:name=".BaseStreamActivity" | |
| 31 | + android:configChanges="orientation|screenSize"></activity> | |
| 32 | + </application> | |
| 33 | + | |
| 34 | +</manifest> | |
| 0 | 35 | \ No newline at end of file | ... | ... |
app/src/main/java/com/cnlive/demo/stream/BaseStreamActivity.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/BaseStreamActivity.java | |
| 1 | +package com.cnlive.demo.stream; | |
| 2 | + | |
| 3 | +import android.app.Activity; | |
| 4 | +import android.app.AlertDialog; | |
| 5 | +import android.content.DialogInterface; | |
| 6 | +import android.content.Intent; | |
| 7 | +import android.content.pm.ActivityInfo; | |
| 8 | +import android.graphics.Bitmap; | |
| 9 | +import android.hardware.Camera; | |
| 10 | +import android.os.Build; | |
| 11 | +import android.os.Bundle; | |
| 12 | +import android.os.Environment; | |
| 13 | +import android.os.Handler; | |
| 14 | +import android.util.Log; | |
| 15 | +import android.view.KeyEvent; | |
| 16 | +import android.view.MotionEvent; | |
| 17 | +import android.view.View; | |
| 18 | +import android.view.Window; | |
| 19 | +import android.view.WindowManager; | |
| 20 | +import android.widget.Button; | |
| 21 | +import android.widget.ImageView; | |
| 22 | +import android.widget.SeekBar; | |
| 23 | +import android.widget.Toast; | |
| 24 | + | |
| 25 | +import com.cnlive.demo.stream.gles.FBO; | |
| 26 | +import com.cnlive.demo.stream.ui.CameraPreviewFrameView; | |
| 27 | +import com.cnlive.demo.stream.ui.RotateLayout; | |
| 28 | + | |
| 29 | +import com.cnlive.libs.lib_cnstream.CNCameraSetting; | |
| 30 | +import com.cnlive.libs.lib_cnstream.CNMicrophoneSetting; | |
| 31 | +import com.cnlive.libs.lib_cnstream.CNStreamManager; | |
| 32 | +import com.cnlive.libs.lib_cnstream.CNStreamProfile; | |
| 33 | +import com.cnlive.libs.lib_cnstream.CNWatermarkSetting; | |
| 34 | +import com.cnlive.libs.lib_cnstream.base.CNAspectFrameLayout; | |
| 35 | +import com.cnlive.libs.lib_cnstream.base.CNPLFourCC; | |
| 36 | +import com.cnlive.libs.lib_cnstream.base.EncodeType; | |
| 37 | +import com.cnlive.libs.lib_cnstream.base.ICNCameraSetting; | |
| 38 | +import com.cnlive.libs.lib_cnstream.base.ICNStreamManager; | |
| 39 | +import com.cnlive.libs.lib_cnstream.base.ICNStreamProfile; | |
| 40 | +import com.cnlive.libs.lib_cnstream.base.ICNWatermarkSetting; | |
| 41 | +import com.cnlive.libs.lib_cnstream.callback.CNAudioSourceCallback; | |
| 42 | +import com.cnlive.libs.lib_cnstream.callback.CNFrameCapturedCallback; | |
| 43 | +import com.cnlive.libs.lib_cnstream.callback.CNStreamStatusCallback; | |
| 44 | +import com.cnlive.libs.lib_cnstream.callback.CNStreamingPreviewCallback; | |
| 45 | +import com.cnlive.libs.lib_cnstream.callback.CNStreamingSessionListener; | |
| 46 | +import com.cnlive.libs.lib_cnstream.callback.CNStreamingStateChangedListener; | |
| 47 | +import com.cnlive.libs.lib_cnstream.callback.CNSurfaceTextureCallback; | |
| 48 | +import com.cnlive.libs.lib_cnstream.model.ActivityConfig; | |
| 49 | +import com.cnlive.libs.lib_util.dns.CNAndroidDnsServer; | |
| 50 | +import com.cnlive.libs.lib_util.dns.CNDnsManager; | |
| 51 | +import com.cnlive.libs.lib_util.dns.CNDnspodFree; | |
| 52 | +import com.cnlive.libs.lib_util.dns.CNIResolver; | |
| 53 | +import com.cnlive.libs.lib_util.dns.CNNetworkInfo; | |
| 54 | +import com.cnlive.libs.lib_util.dns.CNResolver; | |
| 55 | +import com.qiniu.pili.droid.streaming.StreamingEnv; | |
| 56 | + | |
| 57 | +import java.io.BufferedOutputStream; | |
| 58 | +import java.io.File; | |
| 59 | +import java.io.FileOutputStream; | |
| 60 | +import java.io.IOException; | |
| 61 | +import java.net.InetAddress; | |
| 62 | +import java.nio.ByteBuffer; | |
| 63 | +import java.util.List; | |
| 64 | + | |
| 65 | +import static android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK; | |
| 66 | + | |
| 67 | +/** | |
| 68 | + * Created by Administrator on 2016/11/16. | |
| 69 | + */ | |
| 70 | + | |
| 71 | +public class BaseStreamActivity extends Activity implements View.OnClickListener, | |
| 72 | + View.OnLayoutChangeListener, | |
| 73 | + CNStreamStatusCallback, | |
| 74 | + CNStreamingPreviewCallback, | |
| 75 | + CNSurfaceTextureCallback, | |
| 76 | + CNAudioSourceCallback, | |
| 77 | + CameraPreviewFrameView.Listener, | |
| 78 | + CNStreamingSessionListener, | |
| 79 | + CNStreamingStateChangedListener, | |
| 80 | + ICNStreamManager.OnInfoListener, | |
| 81 | + ICNStreamManager.OnErrorListener { | |
| 82 | + private static final String TAG = "StreamingBaseActivity"; | |
| 83 | + | |
| 84 | + private String activityId; | |
| 85 | + private String channelId; | |
| 86 | + | |
| 87 | + private ImageView flashBtn; | |
| 88 | + private ImageView flipBtn; | |
| 89 | + private ImageView closeBtn; | |
| 90 | + private ImageView beautyBtn; | |
| 91 | + private SeekBar beautyLevel; | |
| 92 | + | |
| 93 | + private Button orientationBtn; | |
| 94 | + protected Button startStreamBtn; | |
| 95 | + private Button muteBtn; | |
| 96 | + private Button captureBtn; | |
| 97 | + private CameraPreviewFrameView cameraPreviewFrameView; | |
| 98 | + | |
| 99 | + private Screenshooter screenshooter = new Screenshooter(); | |
| 100 | + private boolean isFlashOpened = false; | |
| 101 | + private boolean mIsNeedFB = false; | |
| 102 | + private boolean mIsNeedMute = false; | |
| 103 | + protected boolean mIsRecording = false; | |
| 104 | + | |
| 105 | + private RotateLayout mRotateLayout; | |
| 106 | + private boolean isEncOrientationPort = true; | |
| 107 | + protected String mLogContent = "\n"; | |
| 108 | + | |
| 109 | + protected CNStreamManager mMediaManager; | |
| 110 | + protected CNCameraSetting mCameraSetting; | |
| 111 | + protected CNMicrophoneSetting mMicrophoneSetting; | |
| 112 | + protected CNStreamProfile mProfile; | |
| 113 | + private CNWatermarkSetting watermarksetting; | |
| 114 | + private CNAspectFrameLayout afl; | |
| 115 | + | |
| 116 | + private int orientation = 1; | |
| 117 | + | |
| 118 | + | |
| 119 | + private boolean mOrientationChanged = false; | |
| 120 | + | |
| 121 | + protected boolean mIsReady = false; | |
| 122 | + | |
| 123 | + private int mCurrentZoom = 0; | |
| 124 | + private int mMaxZoom = 0; | |
| 125 | + | |
| 126 | + private FBO mFBO = new FBO(); | |
| 127 | + | |
| 128 | + @Override | |
| 129 | + protected void onCreate(Bundle savedInstanceState) { | |
| 130 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { | |
| 131 | + requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); | |
| 132 | + } else { | |
| 133 | + requestWindowFeature(Window.FEATURE_NO_TITLE); | |
| 134 | + } | |
| 135 | + | |
| 136 | + super.onCreate(savedInstanceState); | |
| 137 | + StreamingEnv.init(getApplicationContext()); | |
| 138 | + | |
| 139 | + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); | |
| 140 | + | |
| 141 | + if (Config.SCREEN_ORIENTATION == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) { | |
| 142 | + isEncOrientationPort = true; | |
| 143 | + } else if (Config.SCREEN_ORIENTATION == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { | |
| 144 | + isEncOrientationPort = false; | |
| 145 | + } | |
| 146 | + setRequestedOrientation(Config.SCREEN_ORIENTATION); | |
| 147 | + setContentView(R.layout.activity_stream); | |
| 148 | + | |
| 149 | + CNStreamProfile.AudioProfile aProfile = new CNStreamProfile.AudioProfile(44100, 96 * 1024); | |
| 150 | + CNStreamProfile.VideoProfile vProfile = new CNStreamProfile.VideoProfile(30, 1000 * 1024, 48); | |
| 151 | + CNStreamProfile.AVProfile avProfile = new CNStreamProfile.AVProfile(vProfile, aProfile); | |
| 152 | + | |
| 153 | + initStreamProfile(); | |
| 154 | + | |
| 155 | + initCameraSetting(); | |
| 156 | + mIsNeedFB = true; | |
| 157 | + initWatermark(); | |
| 158 | + | |
| 159 | + initMicrophoneSetting(); | |
| 160 | + initView(); | |
| 161 | + initData(); | |
| 162 | + setUpMediaManager(); | |
| 163 | + setFocusAreaIndicator(); | |
| 164 | + } | |
| 165 | + | |
| 166 | + //推流参数配置 | |
| 167 | + private void initStreamProfile() { | |
| 168 | + mProfile = new CNStreamProfile(); | |
| 169 | + mProfile.setVideoQuality(ICNStreamProfile.VIDEO_QUALITY_MEDIUM2); | |
| 170 | + mProfile.setAudioQuality(ICNStreamProfile.AUDIO_QUALITY_MEDIUM2); | |
| 171 | + mProfile.setEncodingSizeLevel(ICNStreamProfile.VIDEO_ENCODING_HEIGHT_480); | |
| 172 | + mProfile.setEncoderRCMode(ICNStreamProfile.BITRATE_PRIORITY); | |
| 173 | + mProfile.setDnsManager(getMyDnsManager()); | |
| 174 | + mProfile.setAdaptiveBitrateEnable(true); | |
| 175 | + mProfile.setFpsControllerEnable(true); | |
| 176 | + mProfile.setStreamStatusConfig(new CNStreamProfile.StreamStatusConfig(3)); | |
| 177 | + mProfile.setSendingBufferProfile(new CNStreamProfile.SendingBufferProfile(0.2f, 0.8f, 3.0f, 20 * 1000)); | |
| 178 | + } | |
| 179 | + | |
| 180 | + //摄像头参数配置 | |
| 181 | + private void initCameraSetting() { | |
| 182 | + mCameraSetting = new CNCameraSetting(); | |
| 183 | + mCameraSetting.setCameraId(CAMERA_FACING_BACK); | |
| 184 | + mCameraSetting.setContinuousFocusModeEnabled(true); | |
| 185 | + mCameraSetting.setRecordingHint(false); | |
| 186 | + mCameraSetting.setCameraFacingId(ICNCameraSetting.CAMERA_FACING_FRONT); | |
| 187 | + mCameraSetting.setBuiltInFaceBeautyEnabled(true); | |
| 188 | + mCameraSetting.setResetTouchFocusDelayInMs(3000); | |
| 189 | + mCameraSetting.setCameraPrvSizeLevel(ICNCameraSetting.SMALL); | |
| 190 | + mCameraSetting.setCameraPrvSizeRatio(ICNCameraSetting.RATIO_16_9); | |
| 191 | + mCameraSetting.setFaceBeautySetting(new CNCameraSetting.FaceBeautySetting(1.0f, 1.0f, 0.8f)); | |
| 192 | + } | |
| 193 | + | |
| 194 | + //麦克风参数配置 | |
| 195 | + private void initMicrophoneSetting() { | |
| 196 | + mMicrophoneSetting = new CNMicrophoneSetting(); | |
| 197 | + mMicrophoneSetting.setBluetoothSCOEnabled(false); | |
| 198 | + } | |
| 199 | + | |
| 200 | + //水印参数配置 | |
| 201 | + private void initWatermark() { | |
| 202 | + watermarksetting = new CNWatermarkSetting(this); | |
| 203 | + watermarksetting.setResourceId(R.drawable.cnlive_logo); | |
| 204 | + watermarksetting.setAlpha(100); | |
| 205 | + watermarksetting.setSize(ICNWatermarkSetting.SMALL); | |
| 206 | + watermarksetting.setCustomPosition(0.5f, 0.5f); | |
| 207 | + } | |
| 208 | + | |
| 209 | + //初始化推流所需参数 | |
| 210 | + private void initData() { | |
| 211 | + Intent intent = getIntent(); | |
| 212 | + activityId = intent.getStringExtra("activityId"); | |
| 213 | + channelId = intent.getStringExtra("channelId"); | |
| 214 | + } | |
| 215 | + | |
| 216 | + //配置推流核心类 | |
| 217 | + private void setUpMediaManager() { | |
| 218 | + mMediaManager = new CNStreamManager(this, afl, cameraPreviewFrameView, EncodeType.SW_VIDEO_WITH_SW_AUDIO_CODEC); // sw codec | |
| 219 | + | |
| 220 | + mMediaManager.prepare(mCameraSetting, mMicrophoneSetting, watermarksetting, mProfile); | |
| 221 | + | |
| 222 | + mMediaManager.setStreamingStateListener(this); | |
| 223 | + mMediaManager.setSurfaceTextureCallback(this); | |
| 224 | + mMediaManager.setStreamingSessionListener(this); | |
| 225 | + mMediaManager.setStreamStatusCallback(this); | |
| 226 | + mMediaManager.setStreamingPreviewCallback(this); | |
| 227 | + mMediaManager.setAudioSourceCallback(this); | |
| 228 | + mMediaManager.setOnErrorListener(this); | |
| 229 | + mMediaManager.setOnInfoListener(this); | |
| 230 | + } | |
| 231 | + | |
| 232 | + @Override | |
| 233 | + public void onResume() { | |
| 234 | + super.onResume(); | |
| 235 | + mMediaManager.resume(); | |
| 236 | + } | |
| 237 | + | |
| 238 | + public void onPause() { | |
| 239 | + super.onPause(); | |
| 240 | + mIsReady = false; | |
| 241 | + mMediaManager.pause(); | |
| 242 | + } | |
| 243 | + | |
| 244 | + @Override | |
| 245 | + public void onDestroy() { | |
| 246 | + super.onDestroy(); | |
| 247 | + mMediaManager.destroy(); | |
| 248 | + } | |
| 249 | + | |
| 250 | + //开始推流 | |
| 251 | + protected void startStreaming() { | |
| 252 | + mMediaManager.startStream(activityConfig); | |
| 253 | + startStreamBtn.setText("结束推流"); | |
| 254 | + startStreamBtn.postInvalidate(); | |
| 255 | + mIsRecording = true; | |
| 256 | + } | |
| 257 | + | |
| 258 | + //结束推流 | |
| 259 | + protected void stopStreaming() { | |
| 260 | + mMediaManager.stopStream(); | |
| 261 | + startStreamBtn.setText("开始推流"); | |
| 262 | + startStreamBtn.postInvalidate(); | |
| 263 | + mIsRecording = false; | |
| 264 | + } | |
| 265 | + | |
| 266 | + //返回按钮 | |
| 267 | + protected void onBackoffClick() { | |
| 268 | + new AlertDialog.Builder(BaseStreamActivity.this).setCancelable(true) | |
| 269 | + .setTitle("结束直播?") | |
| 270 | + .setNegativeButton("取消", new DialogInterface.OnClickListener() { | |
| 271 | + | |
| 272 | + @Override | |
| 273 | + public void onClick(DialogInterface arg0, int arg1) { | |
| 274 | + | |
| 275 | + } | |
| 276 | + }) | |
| 277 | + .setPositiveButton("确定", new DialogInterface.OnClickListener() { | |
| 278 | + @Override | |
| 279 | + public void onClick(DialogInterface arg0, int arg1) { | |
| 280 | + mMediaManager.stopStream(); | |
| 281 | + mIsRecording = false; | |
| 282 | + new Handler().postDelayed(new Runnable() { | |
| 283 | + public void run() { | |
| 284 | + //execute the task | |
| 285 | + BaseStreamActivity.this.finish(); | |
| 286 | + | |
| 287 | + } | |
| 288 | + }, 1000); | |
| 289 | + } | |
| 290 | + }).show(); | |
| 291 | + } | |
| 292 | + | |
| 293 | + @Override | |
| 294 | + public boolean onKeyDown(int keyCode, KeyEvent event) { | |
| 295 | + switch (keyCode) { | |
| 296 | + case KeyEvent.KEYCODE_BACK: | |
| 297 | + onBackoffClick(); | |
| 298 | + break; | |
| 299 | + default: | |
| 300 | + break; | |
| 301 | + } | |
| 302 | + return true; | |
| 303 | + } | |
| 304 | + | |
| 305 | + @Override | |
| 306 | + public boolean onRecordAudioFailedHandled(int err) { | |
| 307 | + return false; | |
| 308 | + } | |
| 309 | + | |
| 310 | + @Override | |
| 311 | + public boolean onRestartStreamingHandled(int err) { | |
| 312 | + Log.i(TAG, "onRestartStreamingHandled"); | |
| 313 | + return mMediaManager.startStreaming(); | |
| 314 | + } | |
| 315 | + | |
| 316 | + @Override | |
| 317 | + public Camera.Size onPreviewSizeSelected(List<Camera.Size> list) { | |
| 318 | + Camera.Size size = null; | |
| 319 | + if (list != null) { | |
| 320 | + for (Camera.Size s : list) { | |
| 321 | + if (s.height >= 480) { | |
| 322 | + size = s; | |
| 323 | + break; | |
| 324 | + } | |
| 325 | + } | |
| 326 | + } | |
| 327 | + return size; | |
| 328 | + } | |
| 329 | + | |
| 330 | + //对焦 | |
| 331 | + @Override | |
| 332 | + public boolean onSingleTapUp(MotionEvent e) { | |
| 333 | + Log.i(TAG, "onSingleTapUp X:" + e.getX() + ",Y:" + e.getY()); | |
| 334 | + | |
| 335 | + if (mIsReady) { | |
| 336 | + setFocusAreaIndicator(); | |
| 337 | + mMediaManager.doSingleTapUp((int) e.getX(), (int) e.getY()); | |
| 338 | + return true; | |
| 339 | + } | |
| 340 | + return false; | |
| 341 | + } | |
| 342 | + | |
| 343 | + //变焦 | |
| 344 | + @Override | |
| 345 | + public boolean onZoomValueChanged(float factor) { | |
| 346 | + if (mIsReady && mMediaManager.isZoomSupported()) { | |
| 347 | + mCurrentZoom = (int) (mMaxZoom * factor); | |
| 348 | + mCurrentZoom = Math.min(mCurrentZoom, mMaxZoom); | |
| 349 | + mCurrentZoom = Math.max(0, mCurrentZoom); | |
| 350 | + | |
| 351 | + Log.d(TAG, "zoom ongoing, scale: " + mCurrentZoom + ",factor:" + factor + ",maxZoom:" + mMaxZoom); | |
| 352 | + mMediaManager.setZoomValue(mCurrentZoom); | |
| 353 | + } | |
| 354 | + return false; | |
| 355 | + } | |
| 356 | + | |
| 357 | + @Override | |
| 358 | + public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { | |
| 359 | + Log.i(TAG, "view!!!!:" + v); | |
| 360 | + } | |
| 361 | + | |
| 362 | + @Override | |
| 363 | + public boolean onPreviewFrame(byte[] bytes, int width, int height, int rotation, int fmt, long tsInNanoTime) { | |
| 364 | + Log.i(TAG, "onPreviewFrame " + width + "x" + height + ",fmt:" + (fmt == CNPLFourCC.FOURCC_I420 ? "I420" : "NV21") + ",ts:" + tsInNanoTime + ",rotation:" + rotation); | |
| 365 | + return true; | |
| 366 | + } | |
| 367 | + | |
| 368 | + @Override | |
| 369 | + public void onSurfaceCreated() { | |
| 370 | + Log.i(TAG, "onSurfaceCreated"); | |
| 371 | + mFBO.initialize(this); | |
| 372 | + } | |
| 373 | + | |
| 374 | + @Override | |
| 375 | + public void onSurfaceChanged(int width, int height) { | |
| 376 | + Log.i(TAG, "onSurfaceChanged width:" + width + ",height:" + height); | |
| 377 | + mFBO.updateSurfaceSize(width, height); | |
| 378 | + } | |
| 379 | + | |
| 380 | + @Override | |
| 381 | + public void onSurfaceDestroyed() { | |
| 382 | + Log.i(TAG, "onSurfaceDestroyed"); | |
| 383 | + mFBO.release(); | |
| 384 | + } | |
| 385 | + | |
| 386 | + @Override | |
| 387 | + public int onDrawFrame(int texId, int texWidth, int texHeight, float[] transformMatrix) { | |
| 388 | + int newTexId = mFBO.drawFrame(texId, texWidth, texHeight); | |
| 389 | + return newTexId; | |
| 390 | + } | |
| 391 | + | |
| 392 | + @Override | |
| 393 | + public void onAudioSourceAvailable(ByteBuffer byteBuffer, int size, long tsInNanoTime, boolean eof) { | |
| 394 | + } | |
| 395 | + | |
| 396 | + @Override | |
| 397 | + public void notifyStreamStatusChanged(final CNStreamProfile.StreamStatus streamStatus) { | |
| 398 | + } | |
| 399 | + | |
| 400 | + //推流过程中的状态改变监听 | |
| 401 | + @Override | |
| 402 | + public void onStateChanged(com.cnlive.libs.lib_cnstream.base.StreamingState streamingState, Object extra) { | |
| 403 | + Log.i(TAG, "StreamingState streamingState:" + streamingState + ",extra:" + extra); | |
| 404 | + | |
| 405 | + switch (streamingState) { | |
| 406 | + case PREPARING: | |
| 407 | + break; | |
| 408 | + case READY: | |
| 409 | + mIsReady = true; | |
| 410 | + mMaxZoom = mMediaManager.getMaxZoom(); | |
| 411 | + break; | |
| 412 | + case CONNECTING: | |
| 413 | + break; | |
| 414 | + case STREAMING: | |
| 415 | + break; | |
| 416 | + case SHUTDOWN: | |
| 417 | + break; | |
| 418 | + case IOERROR: | |
| 419 | + break; | |
| 420 | + case UNKNOWN: | |
| 421 | + break; | |
| 422 | + case SENDING_BUFFER_EMPTY: | |
| 423 | + break; | |
| 424 | + case SENDING_BUFFER_FULL: | |
| 425 | + break; | |
| 426 | + case AUDIO_RECORDING_FAIL: | |
| 427 | + break; | |
| 428 | + case OPEN_CAMERA_FAIL: | |
| 429 | + Log.e(TAG, "Open Camera Fail. id:" + extra); | |
| 430 | + break; | |
| 431 | + case DISCONNECTED: | |
| 432 | + mLogContent += "DISCONNECTED\n"; | |
| 433 | + break; | |
| 434 | + case INVALID_STREAMING_URL: | |
| 435 | + Log.e(TAG, "Invalid streaming url:" + extra); | |
| 436 | + break; | |
| 437 | + case UNAUTHORIZED_STREAMING_URL: | |
| 438 | + Log.e(TAG, "Unauthorized streaming url:" + extra); | |
| 439 | + mLogContent += "Unauthorized Url\n"; | |
| 440 | + break; | |
| 441 | + case TORCH_INFO: | |
| 442 | + if (extra != null) { | |
| 443 | + final boolean isSupportedTorch = (Boolean) extra; | |
| 444 | + Log.i(TAG, "isSupportedTorch=" + isSupportedTorch); | |
| 445 | + } | |
| 446 | + break; | |
| 447 | + } | |
| 448 | + Log.e(TAG, streamingState.toString()); | |
| 449 | + } | |
| 450 | + | |
| 451 | + //初始化view | |
| 452 | + private void initView() { | |
| 453 | + afl = (CNAspectFrameLayout) findViewById(R.id.cameraPreview_afl); | |
| 454 | + afl.setShowMode(CNAspectFrameLayout.SHOW_MODE.FULL); | |
| 455 | + cameraPreviewFrameView = (CameraPreviewFrameView) findViewById(R.id.cameraPreview_surfaceView); | |
| 456 | + cameraPreviewFrameView.setListener(this); | |
| 457 | + flashBtn = (ImageView) findViewById(R.id.flashBtn); | |
| 458 | + flashBtn.setOnClickListener(this); | |
| 459 | + flipBtn = (ImageView) findViewById(R.id.flipBtn); | |
| 460 | + flipBtn.setOnClickListener(this); | |
| 461 | + closeBtn = (ImageView) findViewById(R.id.closeBtn); | |
| 462 | + closeBtn.setOnClickListener(this); | |
| 463 | + beautyBtn = (ImageView) findViewById(R.id.beautyBtn); | |
| 464 | + beautyBtn.setOnClickListener(this); | |
| 465 | + | |
| 466 | + orientationBtn = (Button) findViewById(R.id.orientationBtn); | |
| 467 | + orientationBtn.setOnClickListener(this); | |
| 468 | + startStreamBtn = (Button) findViewById(R.id.startStreamBtn); | |
| 469 | + startStreamBtn.setOnClickListener(this); | |
| 470 | + muteBtn = (Button) findViewById(R.id.muteBtn); | |
| 471 | + muteBtn.setOnClickListener(this); | |
| 472 | + captureBtn = (Button) findViewById(R.id.captureBtn); | |
| 473 | + captureBtn.setOnClickListener(this); | |
| 474 | + | |
| 475 | + beautyLevel = (SeekBar) findViewById(R.id.beautyLevel_seekBar); | |
| 476 | + beautyLevel.setOnSeekBarChangeListener(beautyLevelListener); | |
| 477 | + } | |
| 478 | + | |
| 479 | + @Override | |
| 480 | + public void onClick(View view) { | |
| 481 | + switch (view.getId()) { | |
| 482 | + case R.id.flashBtn: | |
| 483 | + if (isFlashOpened) { | |
| 484 | + mMediaManager.turnLightOff(); | |
| 485 | + isFlashOpened = false; | |
| 486 | + } else { | |
| 487 | + mMediaManager.turnLightOn(); | |
| 488 | + isFlashOpened = true; | |
| 489 | + } | |
| 490 | + break; | |
| 491 | + case R.id.flipBtn: | |
| 492 | + mMediaManager.switchCamera(); | |
| 493 | + break; | |
| 494 | + case R.id.beautyBtn: | |
| 495 | + mIsNeedFB = !mIsNeedFB; | |
| 496 | + mMediaManager.setVideoFilterType(mIsNeedFB ? ICNCameraSetting.VIDEO_FILTER_BEAUTY | |
| 497 | + : ICNCameraSetting.VIDEO_FILTER_NONE); | |
| 498 | + beautyBtn.setBackgroundResource(mIsNeedFB ? R.drawable.icon_record_meiyan_on : R.drawable.icon_record_meiyan_off); | |
| 499 | + break; | |
| 500 | + case R.id.closeBtn: | |
| 501 | + onBackoffClick(); | |
| 502 | + break; | |
| 503 | + case R.id.orientationBtn: | |
| 504 | + mOrientationChanged = !mOrientationChanged; | |
| 505 | + isEncOrientationPort = !isEncOrientationPort; | |
| 506 | + mProfile.setEncodingOrientation(isEncOrientationPort ? ICNStreamProfile.PORT : ICNStreamProfile.LAND); | |
| 507 | + orientation = isEncOrientationPort ? 0 : 1; | |
| 508 | + mMediaManager.setStreamingProfile(mProfile); | |
| 509 | + setRequestedOrientation(isEncOrientationPort ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); | |
| 510 | + mMediaManager.notifyActivityOrientationChanged(); | |
| 511 | + orientationBtn.setText(isEncOrientationPort ? "横屏" : "竖屏"); | |
| 512 | + break; | |
| 513 | + case R.id.startStreamBtn: | |
| 514 | + if (mIsRecording) { | |
| 515 | + stopStreaming(); | |
| 516 | + } else { | |
| 517 | + startStreaming(); | |
| 518 | + } | |
| 519 | + break; | |
| 520 | + case R.id.muteBtn: | |
| 521 | + mIsNeedMute = !mIsNeedMute; | |
| 522 | + mMediaManager.mute(mIsNeedMute); | |
| 523 | + muteBtn.setText(mIsNeedMute ? "恢复" : "静音"); | |
| 524 | + break; | |
| 525 | + case R.id.captureBtn: | |
| 526 | + new Handler().postDelayed(screenshooter, 100); | |
| 527 | + break; | |
| 528 | + } | |
| 529 | + } | |
| 530 | + | |
| 531 | + //美颜seekbar监听 | |
| 532 | + SeekBar.OnSeekBarChangeListener beautyLevelListener = new SeekBar.OnSeekBarChangeListener() { | |
| 533 | + @Override | |
| 534 | + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { | |
| 535 | + CNCameraSetting.FaceBeautySetting faceBeautySetting = mCameraSetting.getFaceBeautySetting(); | |
| 536 | + faceBeautySetting.beautyLevel = progress / 100.0f; | |
| 537 | + faceBeautySetting.whiten = progress / 100.0f; | |
| 538 | + faceBeautySetting.redden = progress / 100.0f; | |
| 539 | + | |
| 540 | + mMediaManager.updateFaceBeautySetting(faceBeautySetting); | |
| 541 | + } | |
| 542 | + | |
| 543 | + @Override | |
| 544 | + public void onStartTrackingTouch(SeekBar seekBar) { | |
| 545 | + } | |
| 546 | + | |
| 547 | + @Override | |
| 548 | + public void onStopTrackingTouch(SeekBar seekBar) { | |
| 549 | + } | |
| 550 | + }; | |
| 551 | + | |
| 552 | + protected void setFocusAreaIndicator() { | |
| 553 | + if (mRotateLayout == null) { | |
| 554 | + mRotateLayout = (RotateLayout) findViewById(R.id.focus_indicator_rotate_layout); | |
| 555 | + mMediaManager.setFocusAreaIndicator(mRotateLayout, mRotateLayout.findViewById(R.id.focus_indicator)); | |
| 556 | + } | |
| 557 | + } | |
| 558 | + | |
| 559 | + private static CNDnsManager getMyDnsManager() { | |
| 560 | + CNIResolver r0 = new CNDnspodFree(); | |
| 561 | + CNIResolver r1 = CNAndroidDnsServer.defaultResolver(); | |
| 562 | + CNIResolver r2 = null; | |
| 563 | + try { | |
| 564 | + r2 = new CNResolver(InetAddress.getByName("119.29.29.29")); | |
| 565 | + } catch (IOException ex) { | |
| 566 | + ex.printStackTrace(); | |
| 567 | + } | |
| 568 | + return new CNDnsManager(CNNetworkInfo.normal, new CNIResolver[]{r0, r1, r2}); | |
| 569 | + } | |
| 570 | + | |
| 571 | + //传入推流所需参数 | |
| 572 | + ActivityConfig activityConfig = new ActivityConfig() { | |
| 573 | + @Override | |
| 574 | + public String getActivityID() { | |
| 575 | + return activityId; | |
| 576 | + } | |
| 577 | + | |
| 578 | + @Override | |
| 579 | + public String getActivityName() { | |
| 580 | + return " "; | |
| 581 | + } | |
| 582 | + | |
| 583 | + @Override | |
| 584 | + public int getActivityStatus() { | |
| 585 | + return 0; | |
| 586 | + } | |
| 587 | + | |
| 588 | + @Override | |
| 589 | + public int getIsHorizontalScreen() { | |
| 590 | + return orientation; | |
| 591 | + } | |
| 592 | + | |
| 593 | + @Override | |
| 594 | + public String getChannelID() { | |
| 595 | + return channelId; | |
| 596 | + } | |
| 597 | + | |
| 598 | + @Override | |
| 599 | + public String getStartTime() { | |
| 600 | + return " "; | |
| 601 | + } | |
| 602 | + | |
| 603 | + @Override | |
| 604 | + public String getEndTime() { | |
| 605 | + return " "; | |
| 606 | + } | |
| 607 | + | |
| 608 | + @Override | |
| 609 | + public String getCoverImgUrl() { | |
| 610 | + return " "; | |
| 611 | + } | |
| 612 | + | |
| 613 | + @Override | |
| 614 | + public String getActivityCategory() { | |
| 615 | + return " "; | |
| 616 | + } | |
| 617 | + | |
| 618 | + @Override | |
| 619 | + public String getExtensions() { | |
| 620 | + return " "; | |
| 621 | + } | |
| 622 | + | |
| 623 | + @Override | |
| 624 | + public String getUuid() { | |
| 625 | + return " "; | |
| 626 | + } | |
| 627 | + | |
| 628 | + @Override | |
| 629 | + public String getCallbackAcitvityStatushttpPostUrl() { | |
| 630 | + return " "; | |
| 631 | + } | |
| 632 | + }; | |
| 633 | + | |
| 634 | + //推流过程中的错误监听 | |
| 635 | + @Override | |
| 636 | + public void onError(int what, String extra) { | |
| 637 | + stopStreaming(); | |
| 638 | + Log.e(TAG, what + " " + extra); | |
| 639 | + } | |
| 640 | + | |
| 641 | + //推流过程中返回的信息 | |
| 642 | + @Override | |
| 643 | + public void onInfo(int what, String extra) { | |
| 644 | + Log.e(TAG, what + " " + extra); | |
| 645 | + } | |
| 646 | + | |
| 647 | + private class Screenshooter implements Runnable { | |
| 648 | + @Override | |
| 649 | + public void run() { | |
| 650 | + final String fileName = "PLStreaming_" + System.currentTimeMillis() + ".jpg"; | |
| 651 | + mMediaManager.captureFrame(100, 100, new CNFrameCapturedCallback() { | |
| 652 | + private Bitmap bitmap; | |
| 653 | + | |
| 654 | + @Override | |
| 655 | + public void onFrameCaptured(Bitmap bmp) { | |
| 656 | + if (bmp == null) { | |
| 657 | + return; | |
| 658 | + } | |
| 659 | + bitmap = bmp; | |
| 660 | + new Thread(new Runnable() { | |
| 661 | + @Override | |
| 662 | + public void run() { | |
| 663 | + try { | |
| 664 | + saveToSDCard(fileName, bitmap); | |
| 665 | + } catch (IOException e) { | |
| 666 | + e.printStackTrace(); | |
| 667 | + } finally { | |
| 668 | + if (bitmap != null) { | |
| 669 | + bitmap.recycle(); | |
| 670 | + bitmap = null; | |
| 671 | + } | |
| 672 | + } | |
| 673 | + } | |
| 674 | + }).start(); | |
| 675 | + } | |
| 676 | + }); | |
| 677 | + } | |
| 678 | + } | |
| 679 | + | |
| 680 | + private void saveToSDCard(String filename, Bitmap bmp) throws IOException { | |
| 681 | + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { | |
| 682 | + File file = new File(Environment.getExternalStorageDirectory(), filename); | |
| 683 | + BufferedOutputStream bos = null; | |
| 684 | + try { | |
| 685 | + bos = new BufferedOutputStream(new FileOutputStream(file)); | |
| 686 | + bmp.compress(Bitmap.CompressFormat.PNG, 90, bos); | |
| 687 | + bmp.recycle(); | |
| 688 | + bmp = null; | |
| 689 | + } finally { | |
| 690 | + if (bos != null) bos.close(); | |
| 691 | + } | |
| 692 | + | |
| 693 | + final String info = "Save frame to:" + Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + filename; | |
| 694 | + runOnUiThread(new Runnable() { | |
| 695 | + @Override | |
| 696 | + public void run() { | |
| 697 | + Toast.makeText(BaseStreamActivity.this, info, Toast.LENGTH_LONG).show(); | |
| 698 | + } | |
| 699 | + }); | |
| 700 | + } | |
| 701 | + } | |
| 702 | +} | ... | ... |
app/src/main/java/com/cnlive/demo/stream/CNStreamApplication.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/CNStreamApplication.java | |
| 1 | +package com.cnlive.demo.stream; | |
| 2 | + | |
| 3 | +import android.app.Application; | |
| 4 | + | |
| 5 | +import com.cnlive.libs.util.Config; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Created by Administrator on 2016/11/16. | |
| 9 | + */ | |
| 10 | + | |
| 11 | +public class CNStreamApplication extends Application { | |
| 12 | + @Override | |
| 13 | + public void onCreate() { | |
| 14 | + super.onCreate(); | |
| 15 | + Config.init(this, "60_irn9gh9d49", "f7b6db55616d207fd5c07e2b580b5650c690aff58fb36d"); | |
| 16 | + } | |
| 17 | +} | ... | ... |
app/src/main/java/com/cnlive/demo/stream/Config.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/Config.java | |
| 1 | +package com.cnlive.demo.stream; | |
| 2 | + | |
| 3 | +import android.content.pm.ActivityInfo; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * Created by jerikc on 15/12/8. | |
| 7 | + */ | |
| 8 | +public class Config { | |
| 9 | + public static final boolean FILTER_ENABLED = false; | |
| 10 | + public static final int SCREEN_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; | |
| 11 | +} | ... | ... |
app/src/main/java/com/cnlive/demo/stream/MainActivity.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/MainActivity.java | |
| 1 | +package com.cnlive.demo.stream; | |
| 2 | + | |
| 3 | +import android.app.Activity; | |
| 4 | +import android.content.Intent; | |
| 5 | +import android.os.Bundle; | |
| 6 | +import android.view.View; | |
| 7 | +import android.widget.Button; | |
| 8 | +import android.widget.EditText; | |
| 9 | +import android.widget.Toast; | |
| 10 | + | |
| 11 | +public class MainActivity extends Activity implements View.OnClickListener { | |
| 12 | + public static final String TAG = "MainActivity"; | |
| 13 | + private Button connectBtn; | |
| 14 | + private EditText activityId; | |
| 15 | + private EditText channelId; | |
| 16 | + | |
| 17 | + @Override | |
| 18 | + protected void onCreate(Bundle savedInstanceState) { | |
| 19 | + super.onCreate(savedInstanceState); | |
| 20 | + setContentView(R.layout.activity_main); | |
| 21 | + initView(); | |
| 22 | + } | |
| 23 | + | |
| 24 | + private void initView() { | |
| 25 | + connectBtn = (Button) findViewById(R.id.connectBtn); | |
| 26 | + connectBtn.setOnClickListener(this); | |
| 27 | + activityId = (EditText) findViewById(R.id.activityId); | |
| 28 | + channelId = (EditText) findViewById(R.id.channelId); | |
| 29 | + } | |
| 30 | + | |
| 31 | + @Override | |
| 32 | + public void onClick(View v) { | |
| 33 | + switch (v.getId()) { | |
| 34 | + case R.id.connectBtn: | |
| 35 | + Intent intent = new Intent(this, BaseStreamActivity.class); | |
| 36 | + intent.putExtra("activityId", activityId.getText().toString()); | |
| 37 | + intent.putExtra("channelId", channelId.getText().toString()); | |
| 38 | + if (activityId.getText().toString().isEmpty() || channelId.getText().toString().isEmpty()) { | |
| 39 | + Toast.makeText(this, "activityID或channelId不能为空哦", Toast.LENGTH_SHORT).show(); | |
| 40 | + } else { | |
| 41 | + startActivity(intent); | |
| 42 | + } | |
| 43 | + break; | |
| 44 | + } | |
| 45 | + } | |
| 46 | +} | ... | ... |
app/src/main/java/com/cnlive/demo/stream/filter/AbstractFilter.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/filter/AbstractFilter.java | |
| 1 | +package com.cnlive.demo.stream.filter; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | + | |
| 5 | +import java.nio.FloatBuffer; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Created by jerikc on 16/2/23. | |
| 9 | + */ | |
| 10 | +public abstract class AbstractFilter { | |
| 11 | + protected abstract int createProgram(Context context); | |
| 12 | + | |
| 13 | + protected abstract void getGLSLValues(); | |
| 14 | + | |
| 15 | + protected abstract void useProgram(); | |
| 16 | + | |
| 17 | + protected abstract void bindTexture(int textureId); | |
| 18 | + | |
| 19 | + protected abstract void bindGLSLValues(float[] mvpMatrix, FloatBuffer vertexBuffer, | |
| 20 | + int coordsPerVertex, int vertexStride, FloatBuffer texBuffer, | |
| 21 | + int texStride); | |
| 22 | + | |
| 23 | + protected abstract void drawArrays(int firstVertex, int vertexCount); | |
| 24 | + | |
| 25 | + protected abstract void unbindGLSLValues(); | |
| 26 | + | |
| 27 | + protected abstract void unbindTexture(); | |
| 28 | + | |
| 29 | + protected abstract void disuseProgram(); | |
| 30 | +} | ... | ... |
app/src/main/java/com/cnlive/demo/stream/filter/CameraFilter.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/filter/CameraFilter.java | |
| 1 | +package com.cnlive.demo.stream.filter; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.opengl.GLES11Ext; | |
| 5 | +import android.opengl.GLES20; | |
| 6 | + | |
| 7 | +import com.cnlive.demo.stream.R; | |
| 8 | +import com.cnlive.demo.stream.gles.GlUtil; | |
| 9 | + | |
| 10 | +import java.nio.FloatBuffer; | |
| 11 | + | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * Created by jerikc on 16/2/23. | |
| 15 | + */ | |
| 16 | +public class CameraFilter extends AbstractFilter implements IFilter { | |
| 17 | + protected int mProgramHandle; | |
| 18 | + private int maPositionLoc; | |
| 19 | + private int muMVPMatrixLoc; | |
| 20 | + private int maTextureCoordLoc; | |
| 21 | + private int mTextureLoc; | |
| 22 | + | |
| 23 | + protected int mIncomingWidth, mIncomingHeight; | |
| 24 | + | |
| 25 | + public CameraFilter(Context applicationContext) { | |
| 26 | + mProgramHandle = createProgram(applicationContext); | |
| 27 | + if (mProgramHandle == 0) { | |
| 28 | + throw new RuntimeException("Unable to create program"); | |
| 29 | + } | |
| 30 | + getGLSLValues(); | |
| 31 | + } | |
| 32 | + | |
| 33 | + @Override | |
| 34 | + public int getTextureTarget() { | |
| 35 | + return GLES11Ext.GL_TEXTURE_EXTERNAL_OES; | |
| 36 | + } | |
| 37 | + | |
| 38 | + @Override | |
| 39 | + public void setTextureSize(int width, int height) { | |
| 40 | + if (width == 0 || height == 0) { | |
| 41 | + return; | |
| 42 | + } | |
| 43 | + if (width == mIncomingWidth && height == mIncomingHeight) { | |
| 44 | + return; | |
| 45 | + } | |
| 46 | + mIncomingWidth = width; | |
| 47 | + mIncomingHeight = height; | |
| 48 | + } | |
| 49 | + | |
| 50 | + @Override | |
| 51 | + protected int createProgram(Context applicationContext) { | |
| 52 | + return GlUtil.createProgram(applicationContext, R.raw.vertex_shader, | |
| 53 | + R.raw.fragment_shader_no_filter); | |
| 54 | + } | |
| 55 | + | |
| 56 | + @Override | |
| 57 | + protected void getGLSLValues() { | |
| 58 | + mTextureLoc = GLES20.glGetUniformLocation(mProgramHandle, "uTexture"); | |
| 59 | + maPositionLoc = GLES20.glGetAttribLocation(mProgramHandle, "aPosition"); | |
| 60 | + muMVPMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle, "uMVPMatrix"); | |
| 61 | + maTextureCoordLoc = GLES20.glGetAttribLocation(mProgramHandle, "aTextureCoord"); | |
| 62 | + } | |
| 63 | + | |
| 64 | + @Override | |
| 65 | + public void onDraw(float[] mvpMatrix, FloatBuffer vertexBuffer, int firstVertex, | |
| 66 | + int vertexCount, int coordsPerVertex, int vertexStride, | |
| 67 | + FloatBuffer texBuffer, int textureId, int texStride) { | |
| 68 | + | |
| 69 | + GlUtil.checkGlError("draw start"); | |
| 70 | + | |
| 71 | + useProgram(); | |
| 72 | + | |
| 73 | + bindTexture(textureId); | |
| 74 | + | |
| 75 | + bindGLSLValues(mvpMatrix, vertexBuffer, coordsPerVertex, vertexStride, texBuffer, | |
| 76 | + texStride); | |
| 77 | + | |
| 78 | + drawArrays(firstVertex, vertexCount); | |
| 79 | + | |
| 80 | + unbindGLSLValues(); | |
| 81 | + | |
| 82 | + unbindTexture(); | |
| 83 | + | |
| 84 | + disuseProgram(); | |
| 85 | + } | |
| 86 | + | |
| 87 | + @Override | |
| 88 | + protected void useProgram() { | |
| 89 | + GLES20.glUseProgram(mProgramHandle); | |
| 90 | + //GlUtil.checkGlError("glUseProgram"); | |
| 91 | + } | |
| 92 | + | |
| 93 | + @Override | |
| 94 | + protected void bindTexture(int textureId) { | |
| 95 | + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); | |
| 96 | + GLES20.glBindTexture(getTextureTarget(), textureId); | |
| 97 | + GLES20.glUniform1i(mTextureLoc, 0); | |
| 98 | + } | |
| 99 | + | |
| 100 | + @Override | |
| 101 | + protected void bindGLSLValues(float[] mvpMatrix, FloatBuffer vertexBuffer, int coordsPerVertex, | |
| 102 | + int vertexStride, FloatBuffer texBuffer, int texStride) { | |
| 103 | + | |
| 104 | + GLES20.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mvpMatrix, 0); | |
| 105 | + GLES20.glEnableVertexAttribArray(maPositionLoc); | |
| 106 | + GLES20.glVertexAttribPointer(maPositionLoc, coordsPerVertex, GLES20.GL_FLOAT, false, | |
| 107 | + vertexStride, vertexBuffer); | |
| 108 | + GLES20.glEnableVertexAttribArray(maTextureCoordLoc); | |
| 109 | + GLES20.glVertexAttribPointer(maTextureCoordLoc, 2, GLES20.GL_FLOAT, false, texStride, | |
| 110 | + texBuffer); | |
| 111 | + } | |
| 112 | + | |
| 113 | + @Override | |
| 114 | + protected void drawArrays(int firstVertex, int vertexCount) { | |
| 115 | + GLES20.glClearColor(0f, 0f, 0f, 1f); | |
| 116 | + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); | |
| 117 | + GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, firstVertex, vertexCount); | |
| 118 | + } | |
| 119 | + | |
| 120 | + @Override | |
| 121 | + protected void unbindGLSLValues() { | |
| 122 | + GLES20.glDisableVertexAttribArray(maPositionLoc); | |
| 123 | + GLES20.glDisableVertexAttribArray(maTextureCoordLoc); | |
| 124 | + } | |
| 125 | + | |
| 126 | + @Override | |
| 127 | + protected void unbindTexture() { | |
| 128 | + GLES20.glBindTexture(getTextureTarget(), 0); | |
| 129 | + } | |
| 130 | + | |
| 131 | + @Override | |
| 132 | + protected void disuseProgram() { | |
| 133 | + GLES20.glUseProgram(0); | |
| 134 | + } | |
| 135 | + | |
| 136 | + @Override | |
| 137 | + public void releaseProgram() { | |
| 138 | + GLES20.glDeleteProgram(mProgramHandle); | |
| 139 | + mProgramHandle = -1; | |
| 140 | + } | |
| 141 | +} | ... | ... |
app/src/main/java/com/cnlive/demo/stream/filter/CameraFilterBeauty.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/filter/CameraFilterBeauty.java | |
| 1 | +package com.cnlive.demo.stream.filter; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.opengl.GLES20; | |
| 5 | + | |
| 6 | +import com.cnlive.demo.stream.R; | |
| 7 | +import com.cnlive.demo.stream.gles.GlUtil; | |
| 8 | + | |
| 9 | +import java.nio.FloatBuffer; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * Created by shengwenhui on 16/3/3. | |
| 13 | + */ | |
| 14 | +public class CameraFilterBeauty extends CameraFilter { | |
| 15 | + private int singleStepOffset; | |
| 16 | + | |
| 17 | + private static final float offset_array[] = { | |
| 18 | + 2, 2, | |
| 19 | + }; | |
| 20 | + | |
| 21 | + public CameraFilterBeauty(Context context) { | |
| 22 | + super(context); | |
| 23 | + offset_array[0] = offset_array[0] / 90; | |
| 24 | + offset_array[1] = offset_array[1] / 160; | |
| 25 | + } | |
| 26 | + | |
| 27 | + @Override | |
| 28 | + protected int createProgram(Context applicationContext) { | |
| 29 | + return GlUtil.createProgram(applicationContext, R.raw.vertex_shader, | |
| 30 | + R.raw.fragment_shader_beauty); | |
| 31 | + } | |
| 32 | + | |
| 33 | + @Override | |
| 34 | + protected void getGLSLValues() { | |
| 35 | + super.getGLSLValues(); | |
| 36 | + | |
| 37 | + singleStepOffset = GLES20.glGetUniformLocation(mProgramHandle, "singleStepOffset"); | |
| 38 | + } | |
| 39 | + | |
| 40 | + @Override | |
| 41 | + protected void bindGLSLValues(float[] mvpMatrix, FloatBuffer vertexBuffer, int coordsPerVertex, | |
| 42 | + int vertexStride, FloatBuffer texBuffer, int texStride) { | |
| 43 | + super.bindGLSLValues(mvpMatrix, vertexBuffer, coordsPerVertex, vertexStride, | |
| 44 | + texBuffer, texStride); | |
| 45 | + | |
| 46 | + GLES20.glUniform2fv(singleStepOffset, 1, offset_array, 0); | |
| 47 | + } | |
| 48 | +} | |
| 49 | + | ... | ... |
app/src/main/java/com/cnlive/demo/stream/filter/CameraFilterMosaic.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/filter/CameraFilterMosaic.java | |
| 1 | +package com.cnlive.demo.stream.filter; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.opengl.GLES20; | |
| 5 | + | |
| 6 | +import com.cnlive.demo.stream.R; | |
| 7 | +import com.cnlive.demo.stream.gles.GlUtil; | |
| 8 | + | |
| 9 | +import java.nio.FloatBuffer; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * Created by shengwenhui on 16/3/3. | |
| 13 | + */ | |
| 14 | +public class CameraFilterMosaic extends CameraFilter { | |
| 15 | + private int muTexsizeLoc; | |
| 16 | + | |
| 17 | + private static final float Texsize_array[] = { | |
| 18 | + 255, 255, | |
| 19 | + }; | |
| 20 | + | |
| 21 | + public CameraFilterMosaic(Context context) { | |
| 22 | + super(context); | |
| 23 | + } | |
| 24 | + | |
| 25 | + @Override | |
| 26 | + protected int createProgram(Context applicationContext) { | |
| 27 | + return GlUtil.createProgram(applicationContext, R.raw.vertex_shader, | |
| 28 | + R.raw.fragment_shader_mosaic); | |
| 29 | + } | |
| 30 | + | |
| 31 | + @Override | |
| 32 | + protected void getGLSLValues() { | |
| 33 | + super.getGLSLValues(); | |
| 34 | + | |
| 35 | + muTexsizeLoc = GLES20.glGetUniformLocation(mProgramHandle, "TexSize"); | |
| 36 | + } | |
| 37 | + | |
| 38 | + @Override | |
| 39 | + protected void bindGLSLValues(float[] mvpMatrix, FloatBuffer vertexBuffer, int coordsPerVertex, | |
| 40 | + int vertexStride, FloatBuffer texBuffer, int texStride) { | |
| 41 | + super.bindGLSLValues(mvpMatrix, vertexBuffer, coordsPerVertex, vertexStride, | |
| 42 | + texBuffer, texStride); | |
| 43 | + | |
| 44 | + GLES20.glUniform2fv(muTexsizeLoc, 1, Texsize_array, 0); | |
| 45 | + } | |
| 46 | +} | |
| 0 | 47 | \ No newline at end of file | ... | ... |
app/src/main/java/com/cnlive/demo/stream/filter/CameraFilterToneCurve.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/filter/CameraFilterToneCurve.java | |
| 1 | +package com.cnlive.demo.stream.filter; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.graphics.Point; | |
| 5 | +import android.graphics.PointF; | |
| 6 | +import android.opengl.GLES20; | |
| 7 | + | |
| 8 | +import com.cnlive.demo.stream.R; | |
| 9 | +import com.cnlive.demo.stream.gles.GlUtil; | |
| 10 | + | |
| 11 | +import java.io.IOException; | |
| 12 | +import java.io.InputStream; | |
| 13 | +import java.nio.ByteBuffer; | |
| 14 | +import java.nio.FloatBuffer; | |
| 15 | +import java.util.ArrayList; | |
| 16 | +import java.util.Arrays; | |
| 17 | +import java.util.Comparator; | |
| 18 | + | |
| 19 | +/** | |
| 20 | + * Created by jerikc on 16/2/23. | |
| 21 | + */ | |
| 22 | +public class CameraFilterToneCurve extends CameraFilter { | |
| 23 | + | |
| 24 | + private final int mToneCurveTextureId; | |
| 25 | + protected int muToneCurveTextureLoc; | |
| 26 | + | |
| 27 | + private PointF[] mRgbCompositeControlPoints; | |
| 28 | + private PointF[] mRedControlPoints; | |
| 29 | + private PointF[] mGreenControlPoints; | |
| 30 | + private PointF[] mBlueControlPoints; | |
| 31 | + | |
| 32 | + private ArrayList<Float> mRgbCompositeCurve; | |
| 33 | + private ArrayList<Float> mRedCurve; | |
| 34 | + private ArrayList<Float> mGreenCurve; | |
| 35 | + private ArrayList<Float> mBlueCurve; | |
| 36 | + | |
| 37 | + public CameraFilterToneCurve(Context context, InputStream inputStream) { | |
| 38 | + super(context); | |
| 39 | + setFromCurveFileInputStream(inputStream); | |
| 40 | + setRgbCompositeControlPoints(mRgbCompositeControlPoints); | |
| 41 | + setRedControlPoints(mRedControlPoints); | |
| 42 | + setGreenControlPoints(mGreenControlPoints); | |
| 43 | + setBlueControlPoints(mBlueControlPoints); | |
| 44 | + | |
| 45 | + mToneCurveTextureId = GlUtil.createTexture(GLES20.GL_TEXTURE_2D); | |
| 46 | + } | |
| 47 | + | |
| 48 | + @Override | |
| 49 | + protected int createProgram(Context applicationContext) { | |
| 50 | + return GlUtil.createProgram(applicationContext, R.raw.vertex_shader, | |
| 51 | + R.raw.fragment_shader_ext_tone_curve); | |
| 52 | + } | |
| 53 | + | |
| 54 | + @Override | |
| 55 | + protected void getGLSLValues() { | |
| 56 | + super.getGLSLValues(); | |
| 57 | + | |
| 58 | + muToneCurveTextureLoc = GLES20.glGetUniformLocation(mProgramHandle, "toneCurveTexture"); | |
| 59 | + } | |
| 60 | + | |
| 61 | + @Override | |
| 62 | + protected void bindTexture(int textureId) { | |
| 63 | + | |
| 64 | + super.bindTexture(textureId); | |
| 65 | + | |
| 66 | + GLES20.glActiveTexture(GLES20.GL_TEXTURE1); | |
| 67 | + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTextureId); | |
| 68 | + GLES20.glUniform1i(muToneCurveTextureLoc, 1); | |
| 69 | + | |
| 70 | + if ((mRedCurve.size() >= 256) | |
| 71 | + && (mGreenCurve.size() >= 256) | |
| 72 | + && (mBlueCurve.size() >= 256) | |
| 73 | + && (mRgbCompositeCurve.size() >= 256)) { | |
| 74 | + byte[] toneCurveByteArray = new byte[256 * 4]; | |
| 75 | + for (int currentCurveIndex = 0; currentCurveIndex < 256; currentCurveIndex++) { | |
| 76 | + // BGRA for upload to texture | |
| 77 | + toneCurveByteArray[currentCurveIndex * 4 + 2] = (byte) ((int) Math.min(Math.max( | |
| 78 | + currentCurveIndex | |
| 79 | + + mBlueCurve.get(currentCurveIndex) | |
| 80 | + + mRgbCompositeCurve.get(currentCurveIndex), 0), 255) & 0xff); | |
| 81 | + toneCurveByteArray[currentCurveIndex * 4 + 1] = (byte) ((int) Math.min(Math.max( | |
| 82 | + currentCurveIndex | |
| 83 | + + mGreenCurve.get(currentCurveIndex) | |
| 84 | + + mRgbCompositeCurve.get(currentCurveIndex), 0), 255) & 0xff); | |
| 85 | + toneCurveByteArray[currentCurveIndex * 4] = (byte) ((int) Math.min(Math.max( | |
| 86 | + currentCurveIndex | |
| 87 | + + mRedCurve.get(currentCurveIndex) | |
| 88 | + + mRgbCompositeCurve.get(currentCurveIndex), 0), 255) & 0xff); | |
| 89 | + toneCurveByteArray[currentCurveIndex * 4 + 3] = (byte) (255 & 0xff); | |
| 90 | + } | |
| 91 | + | |
| 92 | + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256 /*width*/, | |
| 93 | + 1 /*height*/, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, | |
| 94 | + ByteBuffer.wrap(toneCurveByteArray)); | |
| 95 | + } | |
| 96 | + } | |
| 97 | + | |
| 98 | + @Override | |
| 99 | + protected void bindGLSLValues(float[] mvpMatrix, FloatBuffer vertexBuffer, int coordsPerVertex, | |
| 100 | + int vertexStride, FloatBuffer texBuffer, int texStride) { | |
| 101 | + super.bindGLSLValues(mvpMatrix, vertexBuffer, coordsPerVertex, vertexStride, | |
| 102 | + texBuffer, texStride); | |
| 103 | + //GLES20.glEnableVertexAttribArray(maExtraTextureCoordLoc); | |
| 104 | + //GLES20.glVertexAttribPointer(maExtraTextureCoordLoc, 2, GLES20.GL_FLOAT, false, texStride, | |
| 105 | + // texBuffer); | |
| 106 | + } | |
| 107 | + | |
| 108 | + @Override | |
| 109 | + protected void unbindGLSLValues() { | |
| 110 | + super.unbindGLSLValues(); | |
| 111 | + //GLES20.glDisableVertexAttribArray(maExtraTextureCoordLoc); | |
| 112 | + } | |
| 113 | + | |
| 114 | + @Override | |
| 115 | + protected void unbindTexture() { | |
| 116 | + super.unbindTexture(); | |
| 117 | + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); | |
| 118 | + } | |
| 119 | + | |
| 120 | + /////////////////////// | |
| 121 | + | |
| 122 | + private short readShort(InputStream input) throws IOException { | |
| 123 | + return (short) (input.read() << 8 | input.read()); | |
| 124 | + } | |
| 125 | + | |
| 126 | + private void setFromCurveFileInputStream(InputStream input) { | |
| 127 | + try { | |
| 128 | + int version = readShort(input); | |
| 129 | + int totalCurves = readShort(input); | |
| 130 | + | |
| 131 | + ArrayList<PointF[]> curves = new ArrayList<PointF[]>(totalCurves); | |
| 132 | + float pointRate = 1.0f / 255; | |
| 133 | + | |
| 134 | + for (int i = 0; i < totalCurves; i++) { | |
| 135 | + // 2 bytes, Count of points in the curve (short integer from 2...19) | |
| 136 | + short pointCount = readShort(input); | |
| 137 | + PointF[] points = new PointF[pointCount]; | |
| 138 | + // point count * 4 | |
| 139 | + // Curve points. Each curve point is a pair of short integers where | |
| 140 | + // the first number is the output value (vertical coordinate on the | |
| 141 | + // Curves dialog graph) and the second is the input value. All coordinates have range 0 to 255. | |
| 142 | + for (int j = 0; j < pointCount; j++) { | |
| 143 | + short y = readShort(input); | |
| 144 | + short x = readShort(input); | |
| 145 | + | |
| 146 | + points[j] = new PointF(x * pointRate, y * pointRate); | |
| 147 | + } | |
| 148 | + | |
| 149 | + curves.add(points); | |
| 150 | + } | |
| 151 | + input.close(); | |
| 152 | + | |
| 153 | + mRgbCompositeControlPoints = curves.get(0); | |
| 154 | + mRedControlPoints = curves.get(1); | |
| 155 | + mGreenControlPoints = curves.get(2); | |
| 156 | + mBlueControlPoints = curves.get(3); | |
| 157 | + } catch (IOException e) { | |
| 158 | + e.printStackTrace(); | |
| 159 | + } | |
| 160 | + } | |
| 161 | + | |
| 162 | + public void setRgbCompositeControlPoints(PointF[] points) { | |
| 163 | + mRgbCompositeControlPoints = points; | |
| 164 | + mRgbCompositeCurve = createSplineCurve(mRgbCompositeControlPoints); | |
| 165 | + //updateToneCurveTexture(); | |
| 166 | + } | |
| 167 | + | |
| 168 | + public void setRedControlPoints(PointF[] points) { | |
| 169 | + mRedControlPoints = points; | |
| 170 | + mRedCurve = createSplineCurve(mRedControlPoints); | |
| 171 | + //updateToneCurveTexture(); | |
| 172 | + } | |
| 173 | + | |
| 174 | + public void setGreenControlPoints(PointF[] points) { | |
| 175 | + mGreenControlPoints = points; | |
| 176 | + mGreenCurve = createSplineCurve(mGreenControlPoints); | |
| 177 | + //updateToneCurveTexture(); | |
| 178 | + } | |
| 179 | + | |
| 180 | + public void setBlueControlPoints(PointF[] points) { | |
| 181 | + mBlueControlPoints = points; | |
| 182 | + mBlueCurve = createSplineCurve(mBlueControlPoints); | |
| 183 | + //updateToneCurveTexture(); | |
| 184 | + } | |
| 185 | + | |
| 186 | + private ArrayList<Float> createSplineCurve(PointF[] points) { | |
| 187 | + if (points == null || points.length <= 0) { | |
| 188 | + return null; | |
| 189 | + } | |
| 190 | + | |
| 191 | + // Sort the array | |
| 192 | + PointF[] pointsSorted = points.clone(); | |
| 193 | + Arrays.sort(pointsSorted, new Comparator<PointF>() { | |
| 194 | + @Override | |
| 195 | + public int compare(PointF point1, PointF point2) { | |
| 196 | + if (point1.x < point2.x) { | |
| 197 | + return -1; | |
| 198 | + } else if (point1.x > point2.x) { | |
| 199 | + return 1; | |
| 200 | + } else { | |
| 201 | + return 0; | |
| 202 | + } | |
| 203 | + } | |
| 204 | + }); | |
| 205 | + | |
| 206 | + // Convert from (0, 1) to (0, 255). | |
| 207 | + Point[] convertedPoints = new Point[pointsSorted.length]; | |
| 208 | + for (int i = 0; i < points.length; i++) { | |
| 209 | + PointF point = pointsSorted[i]; | |
| 210 | + convertedPoints[i] = new Point((int) (point.x * 255), (int) (point.y * 255)); | |
| 211 | + } | |
| 212 | + | |
| 213 | + ArrayList<Point> splinePoints = createSplineCurve2(convertedPoints); | |
| 214 | + | |
| 215 | + // If we have a first point like (0.3, 0) we'll be missing some points at the beginning | |
| 216 | + // that should be 0. | |
| 217 | + Point firstSplinePoint = splinePoints.get(0); | |
| 218 | + if (firstSplinePoint.x > 0) { | |
| 219 | + for (int i = firstSplinePoint.x; i >= 0; i--) { | |
| 220 | + splinePoints.add(0, new Point(i, 0)); | |
| 221 | + } | |
| 222 | + } | |
| 223 | + | |
| 224 | + // Insert points similarly at the end, if necessary. | |
| 225 | + Point lastSplinePoint = splinePoints.get(splinePoints.size() - 1); | |
| 226 | + if (lastSplinePoint.x < 255) { | |
| 227 | + for (int i = lastSplinePoint.x + 1; i <= 255; i++) { | |
| 228 | + splinePoints.add(new Point(i, 255)); | |
| 229 | + } | |
| 230 | + } | |
| 231 | + | |
| 232 | + // Prepare the spline points. | |
| 233 | + ArrayList<Float> preparedSplinePoints = new ArrayList<Float>(splinePoints.size()); | |
| 234 | + for (Point newPoint : splinePoints) { | |
| 235 | + Point origPoint = new Point(newPoint.x, newPoint.x); | |
| 236 | + | |
| 237 | + float distance = (float) Math.sqrt( | |
| 238 | + Math.pow((origPoint.x - newPoint.x), 2.0) + Math.pow((origPoint.y - newPoint.y), | |
| 239 | + 2.0)); | |
| 240 | + | |
| 241 | + if (origPoint.y > newPoint.y) { | |
| 242 | + distance = -distance; | |
| 243 | + } | |
| 244 | + | |
| 245 | + preparedSplinePoints.add(distance); | |
| 246 | + } | |
| 247 | + | |
| 248 | + return preparedSplinePoints; | |
| 249 | + } | |
| 250 | + | |
| 251 | + private ArrayList<Point> createSplineCurve2(Point[] points) { | |
| 252 | + ArrayList<Double> sdA = createSecondDerivative(points); | |
| 253 | + | |
| 254 | + // Is [points count] equal to [sdA count]? | |
| 255 | + // int n = [points count]; | |
| 256 | + int n = sdA.size(); | |
| 257 | + if (n < 1) { | |
| 258 | + return null; | |
| 259 | + } | |
| 260 | + double sd[] = new double[n]; | |
| 261 | + | |
| 262 | + // From NSMutableArray to sd[n]; | |
| 263 | + for (int i = 0; i < n; i++) { | |
| 264 | + sd[i] = sdA.get(i); | |
| 265 | + } | |
| 266 | + | |
| 267 | + ArrayList<Point> output = new ArrayList<Point>(n + 1); | |
| 268 | + | |
| 269 | + for (int i = 0; i < n - 1; i++) { | |
| 270 | + Point cur = points[i]; | |
| 271 | + Point next = points[i + 1]; | |
| 272 | + | |
| 273 | + for (int x = cur.x; x < next.x; x++) { | |
| 274 | + double t = (double) (x - cur.x) / (next.x - cur.x); | |
| 275 | + | |
| 276 | + double a = 1 - t; | |
| 277 | + double b = t; | |
| 278 | + double h = next.x - cur.x; | |
| 279 | + | |
| 280 | + double y = a * cur.y + b * next.y + (h * h / 6) * ((a * a * a - a) * sd[i] | |
| 281 | + + (b * b * b - b) * sd[i + 1]); | |
| 282 | + | |
| 283 | + if (y > 255.0) { | |
| 284 | + y = 255.0; | |
| 285 | + } else if (y < 0.0) { | |
| 286 | + y = 0.0; | |
| 287 | + } | |
| 288 | + | |
| 289 | + output.add(new Point(x, (int) Math.round(y))); | |
| 290 | + } | |
| 291 | + } | |
| 292 | + | |
| 293 | + // If the last point is (255, 255) it doesn't get added. | |
| 294 | + if (output.size() == 255) { | |
| 295 | + output.add(points[points.length - 1]); | |
| 296 | + } | |
| 297 | + return output; | |
| 298 | + } | |
| 299 | + | |
| 300 | + private ArrayList<Double> createSecondDerivative(Point[] points) { | |
| 301 | + int n = points.length; | |
| 302 | + if (n <= 1) { | |
| 303 | + return null; | |
| 304 | + } | |
| 305 | + | |
| 306 | + double matrix[][] = new double[n][3]; | |
| 307 | + double result[] = new double[n]; | |
| 308 | + matrix[0][1] = 1; | |
| 309 | + // What about matrix[0][1] and matrix[0][0]? Assuming 0 for now (Brad L.) | |
| 310 | + matrix[0][0] = 0; | |
| 311 | + matrix[0][2] = 0; | |
| 312 | + | |
| 313 | + for (int i = 1; i < n - 1; i++) { | |
| 314 | + Point P1 = points[i - 1]; | |
| 315 | + Point P2 = points[i]; | |
| 316 | + Point P3 = points[i + 1]; | |
| 317 | + | |
| 318 | + matrix[i][0] = (double) (P2.x - P1.x) / 6; | |
| 319 | + matrix[i][1] = (double) (P3.x - P1.x) / 3; | |
| 320 | + matrix[i][2] = (double) (P3.x - P2.x) / 6; | |
| 321 | + result[i] = | |
| 322 | + (double) (P3.y - P2.y) / (P3.x - P2.x) - (double) (P2.y - P1.y) / (P2.x - P1.x); | |
| 323 | + } | |
| 324 | + | |
| 325 | + // What about result[0] and result[n-1]? Assuming 0 for now (Brad L.) | |
| 326 | + result[0] = 0; | |
| 327 | + result[n - 1] = 0; | |
| 328 | + | |
| 329 | + matrix[n - 1][1] = 1; | |
| 330 | + // What about matrix[n-1][0] and matrix[n-1][2]? For now, assuming they are 0 (Brad L.) | |
| 331 | + matrix[n - 1][0] = 0; | |
| 332 | + matrix[n - 1][2] = 0; | |
| 333 | + | |
| 334 | + // solving pass1 (up->down) | |
| 335 | + for (int i = 1; i < n; i++) { | |
| 336 | + double k = matrix[i][0] / matrix[i - 1][1]; | |
| 337 | + matrix[i][1] -= k * matrix[i - 1][2]; | |
| 338 | + matrix[i][0] = 0; | |
| 339 | + result[i] -= k * result[i - 1]; | |
| 340 | + } | |
| 341 | + // solving pass2 (down->up) | |
| 342 | + for (int i = n - 2; i >= 0; i--) { | |
| 343 | + double k = matrix[i][2] / matrix[i + 1][1]; | |
| 344 | + matrix[i][1] -= k * matrix[i + 1][0]; | |
| 345 | + matrix[i][2] = 0; | |
| 346 | + result[i] -= k * result[i + 1]; | |
| 347 | + } | |
| 348 | + | |
| 349 | + ArrayList<Double> output = new ArrayList<Double>(n); | |
| 350 | + for (int i = 0; i < n; i++) output.add(result[i] / matrix[i][1]); | |
| 351 | + | |
| 352 | + return output; | |
| 353 | + } | |
| 354 | +} | |
| 0 | 355 | \ No newline at end of file | ... | ... |
app/src/main/java/com/cnlive/demo/stream/filter/IFilter.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/filter/IFilter.java | |
| 1 | +package com.cnlive.demo.stream.filter; | |
| 2 | + | |
| 3 | +import java.nio.FloatBuffer; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * Created by jerikc on 16/2/23. | |
| 7 | + */ | |
| 8 | +public interface IFilter { | |
| 9 | + int getTextureTarget(); | |
| 10 | + | |
| 11 | + void setTextureSize(int width, int height); | |
| 12 | + | |
| 13 | + void onDraw(float[] mvpMatrix, FloatBuffer vertexBuffer, int firstVertex, int vertexCount, | |
| 14 | + int coordsPerVertex, int vertexStride, FloatBuffer texBuffer, | |
| 15 | + int textureId, int texStride); | |
| 16 | + | |
| 17 | + void releaseProgram(); | |
| 18 | +} | ... | ... |
app/src/main/java/com/cnlive/demo/stream/gles/Drawable2d.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/gles/Drawable2d.java | |
| 1 | +package com.cnlive.demo.stream.gles; | |
| 2 | + | |
| 3 | +import java.nio.FloatBuffer; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * Created by jerikc on 16/2/23. | |
| 7 | + */ | |
| 8 | +public class Drawable2d { | |
| 9 | + private static final int SIZEOF_FLOAT = 4; | |
| 10 | + | |
| 11 | + private static final float FULL_RECTANGLE_COORDS[] = { | |
| 12 | + -1.0f, -1.0f, // 0 bottom left | |
| 13 | + 1.0f, -1.0f, // 1 bottom right | |
| 14 | + -1.0f, 1.0f, // 2 top left | |
| 15 | + 1.0f, 1.0f, // 3 top right | |
| 16 | + }; | |
| 17 | + | |
| 18 | + private static final float FULL_RECTANGLE_TEX_COORDS[] = { | |
| 19 | + 0.0f, 0.0f, // 0 bottom left | |
| 20 | + 1.0f, 0.0f, // 1 bottom right | |
| 21 | + 0.0f, 1.0f, // 2 top left | |
| 22 | + 1.0f, 1.0f // 3 top right | |
| 23 | + }; | |
| 24 | + | |
| 25 | + private static final FloatBuffer FULL_RECTANGLE_BUF = | |
| 26 | + GlUtil.createFloatBuffer(FULL_RECTANGLE_COORDS); | |
| 27 | + private static final FloatBuffer FULL_RECTANGLE_TEX_BUF = | |
| 28 | + GlUtil.createFloatBuffer(FULL_RECTANGLE_TEX_COORDS); | |
| 29 | + | |
| 30 | + private FloatBuffer mVertexArray; | |
| 31 | + private FloatBuffer mTexCoordArray; | |
| 32 | + | |
| 33 | + private int mVertexCount; | |
| 34 | + private int mCoordsPerVertex; | |
| 35 | + private int mVertexStride; | |
| 36 | + private int mTexCoordStride; | |
| 37 | + | |
| 38 | + public Drawable2d() { | |
| 39 | + mVertexArray = FULL_RECTANGLE_BUF; | |
| 40 | + mTexCoordArray = FULL_RECTANGLE_TEX_BUF; | |
| 41 | + mCoordsPerVertex = 2; | |
| 42 | + mVertexStride = mCoordsPerVertex * SIZEOF_FLOAT; | |
| 43 | + mVertexCount = FULL_RECTANGLE_COORDS.length / mCoordsPerVertex; | |
| 44 | + mTexCoordStride = 2 * SIZEOF_FLOAT; | |
| 45 | + } | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * Returns the array of vertices. | |
| 49 | + * <p> | |
| 50 | + * To avoid allocations, this returns internal state. The caller must not modify it. | |
| 51 | + */ | |
| 52 | + public FloatBuffer getVertexArray() { | |
| 53 | + return mVertexArray; | |
| 54 | + } | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * Returns the array of texture coordinates. | |
| 58 | + * <p> | |
| 59 | + * To avoid allocations, this returns internal state. The caller must not modify it. | |
| 60 | + */ | |
| 61 | + public FloatBuffer getTexCoordArray() { | |
| 62 | + return mTexCoordArray; | |
| 63 | + } | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * Returns the number of vertices stored in the vertex array. | |
| 67 | + */ | |
| 68 | + public int getVertexCount() { | |
| 69 | + return mVertexCount; | |
| 70 | + } | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * Returns the width, in bytes, of the data for each vertex. | |
| 74 | + */ | |
| 75 | + public int getVertexStride() { | |
| 76 | + return mVertexStride; | |
| 77 | + } | |
| 78 | + | |
| 79 | + /** | |
| 80 | + * Returns the width, in bytes, of the data for each texture coordinate. | |
| 81 | + */ | |
| 82 | + public int getTexCoordStride() { | |
| 83 | + return mTexCoordStride; | |
| 84 | + } | |
| 85 | + | |
| 86 | + /** | |
| 87 | + * Returns the number of position coordinates per vertex. This will be 2 or 3. | |
| 88 | + */ | |
| 89 | + public int getCoordsPerVertex() { | |
| 90 | + return mCoordsPerVertex; | |
| 91 | + } | |
| 92 | +} | ... | ... |
app/src/main/java/com/cnlive/demo/stream/gles/FBO.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/gles/FBO.java | |
| 1 | +package com.cnlive.demo.stream.gles; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.opengl.GLES20; | |
| 5 | +import android.util.Log; | |
| 6 | + | |
| 7 | +import com.cnlive.demo.stream.Config; | |
| 8 | +import com.cnlive.demo.stream.R; | |
| 9 | +import com.cnlive.demo.stream.filter.CameraFilterBeauty; | |
| 10 | + | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * Created by jerikc on 16/2/23. | |
| 14 | + */ | |
| 15 | +public class FBO { | |
| 16 | + private static final String TAG = "FBO"; | |
| 17 | + private boolean mEnable = Config.FILTER_ENABLED; | |
| 18 | + | |
| 19 | + private int mSurfaceWidth; | |
| 20 | + private int mSurfaceHeight; | |
| 21 | + | |
| 22 | + private static int[] mCurveArrays = new int[] { | |
| 23 | + R.raw.cross_1, R.raw.cross_2, R.raw.cross_3, R.raw.cross_4, R.raw.cross_5, | |
| 24 | + R.raw.cross_6, R.raw.cross_7, R.raw.cross_8, R.raw.cross_9, R.raw.cross_10, | |
| 25 | + R.raw.cross_11, | |
| 26 | + }; | |
| 27 | + private int mCurveIndex = 10; | |
| 28 | + | |
| 29 | + // Used for off-screen rendering. | |
| 30 | + private int mOffscreenTexture; | |
| 31 | + private int mFramebuffer; | |
| 32 | + private FullFrameRect mFullScreen; | |
| 33 | + | |
| 34 | + public void updateSurfaceSize(int width, int height) { | |
| 35 | + if (!mEnable) { | |
| 36 | + return; | |
| 37 | + } | |
| 38 | + | |
| 39 | + mSurfaceWidth = width; | |
| 40 | + mSurfaceHeight = height; | |
| 41 | + } | |
| 42 | + | |
| 43 | + public void initialize(Context context) { | |
| 44 | + if (!mEnable) { | |
| 45 | + return; | |
| 46 | + } | |
| 47 | + | |
| 48 | + if (mFullScreen != null) { | |
| 49 | + mFullScreen.release(false); | |
| 50 | + } | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * Create a new full frame renderer with beauty filter. | |
| 54 | + * There are two another filter, you can have a try. | |
| 55 | + */ | |
| 56 | +// mFullScreen = new FullFrameRect(new CameraFilterToneCurve(context, | |
| 57 | +// context.getResources().openRawResource(mCurveArrays[mCurveIndex]))); | |
| 58 | +// mFullScreen = new FullFrameRect(new CameraFilterMosaic(context)); | |
| 59 | + mFullScreen = new FullFrameRect(new CameraFilterBeauty(context)); | |
| 60 | + | |
| 61 | + mOffscreenTexture = 0; | |
| 62 | + } | |
| 63 | + | |
| 64 | + public void release() { | |
| 65 | + if (!mEnable) { | |
| 66 | + return; | |
| 67 | + } | |
| 68 | + mFullScreen.release(true); | |
| 69 | + } | |
| 70 | + | |
| 71 | + /** | |
| 72 | + * Prepares the off-screen framebuffer. | |
| 73 | + */ | |
| 74 | + private void prepareFramebuffer(int width, int height) { | |
| 75 | + GlUtil.checkGlError("start"); | |
| 76 | + int[] values = new int[1]; | |
| 77 | + | |
| 78 | + // Create a texture object and bind it. This will be the color buffer. | |
| 79 | + GLES20.glGenTextures(1, values, 0); | |
| 80 | + GlUtil.checkGlError("glGenTextures"); | |
| 81 | + mOffscreenTexture = values[0]; // expected > 0 | |
| 82 | + Log.i(TAG, "prepareFramebuffer mOffscreenTexture:" + mOffscreenTexture); | |
| 83 | + | |
| 84 | + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mOffscreenTexture); | |
| 85 | + GlUtil.checkGlError("glBindTexture"); | |
| 86 | + | |
| 87 | + // Create texture storage. | |
| 88 | + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, | |
| 89 | + GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null); | |
| 90 | + | |
| 91 | + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, | |
| 92 | + GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); | |
| 93 | + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, | |
| 94 | + GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); | |
| 95 | + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, | |
| 96 | + GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); | |
| 97 | + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, | |
| 98 | + GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); | |
| 99 | + | |
| 100 | + GlUtil.checkGlError("glTexParameter"); | |
| 101 | + | |
| 102 | + // Create framebuffer object and bind it. | |
| 103 | + GLES20.glGenFramebuffers(1, values, 0); | |
| 104 | + GlUtil.checkGlError("glGenFramebuffers"); | |
| 105 | + mFramebuffer = values[0]; // expected > 0 | |
| 106 | + | |
| 107 | + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFramebuffer); | |
| 108 | + GlUtil.checkGlError("glBindFramebuffer " + mFramebuffer); | |
| 109 | + | |
| 110 | + GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, | |
| 111 | + GLES20.GL_TEXTURE_2D, mOffscreenTexture, 0); | |
| 112 | + | |
| 113 | + // See if GLES is happy with all this. | |
| 114 | + int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER); | |
| 115 | + if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) { | |
| 116 | + throw new RuntimeException("Framebuffer not complete, status=" + status); | |
| 117 | + } | |
| 118 | + | |
| 119 | + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); | |
| 120 | + // Switch back to the default framebuffer. | |
| 121 | + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); | |
| 122 | + GlUtil.checkGlError("glBindFramebuffer"); | |
| 123 | + } | |
| 124 | + | |
| 125 | + public int drawFrame(int texId, int texWidth, int texHeight) { | |
| 126 | + if (!mEnable) { | |
| 127 | + return texId; | |
| 128 | + } | |
| 129 | + GLES20.glViewport(0, 0, texWidth, texHeight); | |
| 130 | + if (mOffscreenTexture == 0) { | |
| 131 | + prepareFramebuffer(texWidth, texHeight); | |
| 132 | + } | |
| 133 | + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFramebuffer); | |
| 134 | + | |
| 135 | + mFullScreen.getFilter().setTextureSize(texWidth, texHeight); | |
| 136 | + mFullScreen.drawFrame(texId); | |
| 137 | + | |
| 138 | + // Blit to display. | |
| 139 | + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); | |
| 140 | + GLES20.glViewport(0, 0, mSurfaceWidth, mSurfaceHeight); | |
| 141 | + return mOffscreenTexture; | |
| 142 | + } | |
| 143 | +} | ... | ... |
app/src/main/java/com/cnlive/demo/stream/gles/FullFrameRect.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/gles/FullFrameRect.java | |
| 1 | +package com.cnlive.demo.stream.gles; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * Created by jerikc on 16/2/23. | |
| 5 | + */ | |
| 6 | +import android.opengl.Matrix; | |
| 7 | + | |
| 8 | +import com.cnlive.demo.stream.filter.IFilter; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * This class essentially represents a viewport-sized sprite that will be rendered with | |
| 12 | + * a texture, usually from an external source like the camera. | |
| 13 | + */ | |
| 14 | +public class FullFrameRect { | |
| 15 | + private final Drawable2d mRectDrawable = new Drawable2d(); | |
| 16 | + private IFilter mFilter; | |
| 17 | + public final float[] IDENTITY_MATRIX = new float[16]; | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * Prepares the object. | |
| 21 | + * | |
| 22 | + * @param program The program to use. FullFrameRect takes ownership, and will release | |
| 23 | + * the program when no longer needed. | |
| 24 | + */ | |
| 25 | + public FullFrameRect(IFilter program) { | |
| 26 | + mFilter = program; | |
| 27 | + Matrix.setIdentityM(IDENTITY_MATRIX, 0); | |
| 28 | + } | |
| 29 | + | |
| 30 | + /** | |
| 31 | + * Releases resources. | |
| 32 | + * <p> | |
| 33 | + * This must be called with the appropriate EGL context current (i.e. the one that was | |
| 34 | + * current when the constructor was called). If we're about to destroy the EGL context, | |
| 35 | + * there's no value in having the caller make it current just to do this cleanup, so you | |
| 36 | + * can pass a flag that will tell this function to skip any EGL-context-specific cleanup. | |
| 37 | + */ | |
| 38 | + public void release(boolean doEglCleanup) { | |
| 39 | + if (mFilter != null) { | |
| 40 | + if (doEglCleanup) { | |
| 41 | + mFilter.releaseProgram(); | |
| 42 | + } | |
| 43 | + mFilter = null; | |
| 44 | + } | |
| 45 | + } | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * Returns the program currently in use. | |
| 49 | + */ | |
| 50 | + public IFilter getFilter() { | |
| 51 | + return mFilter; | |
| 52 | + } | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * Changes the program. The previous program will be released. | |
| 56 | + * <p> | |
| 57 | + * The appropriate EGL context must be current. | |
| 58 | + */ | |
| 59 | + public void changeProgram(IFilter newFilter) { | |
| 60 | + mFilter.releaseProgram(); | |
| 61 | + mFilter = newFilter; | |
| 62 | + } | |
| 63 | + | |
| 64 | + /** | |
| 65 | + * Draws a viewport-filling rect, texturing it with the specified texture object. | |
| 66 | + */ | |
| 67 | + public void drawFrame(int textureId) { | |
| 68 | + // Use the identity matrix for MVP so our 2x2 FULL_RECTANGLE covers the viewport. | |
| 69 | + mFilter.onDraw(IDENTITY_MATRIX, mRectDrawable.getVertexArray(), 0, | |
| 70 | + mRectDrawable.getVertexCount(), mRectDrawable.getCoordsPerVertex(), | |
| 71 | + mRectDrawable.getVertexStride(), mRectDrawable.getTexCoordArray(), | |
| 72 | + textureId, mRectDrawable.getTexCoordStride()); | |
| 73 | + } | |
| 74 | +} | ... | ... |
app/src/main/java/com/cnlive/demo/stream/gles/GlUtil.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/gles/GlUtil.java | |
| 1 | +package com.cnlive.demo.stream.gles; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.graphics.Bitmap; | |
| 5 | +import android.opengl.GLES20; | |
| 6 | +import android.opengl.GLUtils; | |
| 7 | +import android.support.annotation.Nullable; | |
| 8 | +import android.support.annotation.RawRes; | |
| 9 | +import android.util.Log; | |
| 10 | + | |
| 11 | +import java.io.BufferedReader; | |
| 12 | +import java.io.IOException; | |
| 13 | +import java.io.InputStream; | |
| 14 | +import java.io.InputStreamReader; | |
| 15 | +import java.nio.ByteBuffer; | |
| 16 | +import java.nio.ByteOrder; | |
| 17 | +import java.nio.FloatBuffer; | |
| 18 | + | |
| 19 | +/** | |
| 20 | + * Created by jerikc on 16/2/23. | |
| 21 | + */ | |
| 22 | +public class GlUtil { | |
| 23 | + private static final String TAG = "GlDemoUtil"; | |
| 24 | + /** Identity matrix for general use. Don't modify or life will get weird. */ | |
| 25 | + | |
| 26 | + public static final int NO_TEXTURE = -1; | |
| 27 | + | |
| 28 | + private static final int SIZEOF_FLOAT = 4; | |
| 29 | + | |
| 30 | + private GlUtil() { // do not instantiate | |
| 31 | + } | |
| 32 | + | |
| 33 | + public static int createProgram(Context applicationContext, @RawRes int vertexSourceRawId, | |
| 34 | + @RawRes int fragmentSourceRawId) { | |
| 35 | + | |
| 36 | + String vertexSource = readTextFromRawResource(applicationContext, vertexSourceRawId); | |
| 37 | + String fragmentSource = readTextFromRawResource(applicationContext, fragmentSourceRawId); | |
| 38 | + | |
| 39 | + return createProgram(vertexSource, fragmentSource); | |
| 40 | + } | |
| 41 | + | |
| 42 | + public static int createProgram(String vertexSource, String fragmentSource) { | |
| 43 | + int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); | |
| 44 | + if (vertexShader == 0) { | |
| 45 | + return 0; | |
| 46 | + } | |
| 47 | + int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); | |
| 48 | + if (pixelShader == 0) { | |
| 49 | + return 0; | |
| 50 | + } | |
| 51 | + int program = GLES20.glCreateProgram(); | |
| 52 | + checkGlError("glCreateProgram"); | |
| 53 | + if (program == 0) { | |
| 54 | + Log.e(TAG, "Could not create program"); | |
| 55 | + } | |
| 56 | + GLES20.glAttachShader(program, vertexShader); | |
| 57 | + checkGlError("glAttachShader"); | |
| 58 | + GLES20.glAttachShader(program, pixelShader); | |
| 59 | + checkGlError("glAttachShader"); | |
| 60 | + GLES20.glLinkProgram(program); | |
| 61 | + int[] linkStatus = new int[1]; | |
| 62 | + GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); | |
| 63 | + if (linkStatus[0] != GLES20.GL_TRUE) { | |
| 64 | + Log.e(TAG, "Could not link program: "); | |
| 65 | + Log.e(TAG, GLES20.glGetProgramInfoLog(program)); | |
| 66 | + GLES20.glDeleteProgram(program); | |
| 67 | + program = 0; | |
| 68 | + } | |
| 69 | + Log.i(TAG, "linkStatus:" + linkStatus[0]); | |
| 70 | + return program; | |
| 71 | + } | |
| 72 | + | |
| 73 | + public static int loadShader(int shaderType, String source) { | |
| 74 | + int shader = GLES20.glCreateShader(shaderType); | |
| 75 | + checkGlError("glCreateShader type=" + shaderType); | |
| 76 | + GLES20.glShaderSource(shader, source); | |
| 77 | + GLES20.glCompileShader(shader); | |
| 78 | + int[] compiled = new int[1]; | |
| 79 | + GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); | |
| 80 | + if (compiled[0] == 0) { | |
| 81 | + Log.e(TAG, "Could not compile shader " + shaderType + ":"); | |
| 82 | + Log.e(TAG, " " + GLES20.glGetShaderInfoLog(shader)); | |
| 83 | + GLES20.glDeleteShader(shader); | |
| 84 | + shader = 0; | |
| 85 | + } | |
| 86 | + return shader; | |
| 87 | + } | |
| 88 | + | |
| 89 | + public static int createTexture(int textureTarget, @Nullable Bitmap bitmap, int minFilter, | |
| 90 | + int magFilter, int wrapS, int wrapT) { | |
| 91 | + int[] textureHandle = new int[1]; | |
| 92 | + | |
| 93 | + GLES20.glGenTextures(1, textureHandle, 0); | |
| 94 | + GlUtil.checkGlError("glGenTextures"); | |
| 95 | + GLES20.glBindTexture(textureTarget, textureHandle[0]); | |
| 96 | + GlUtil.checkGlError("glBindTexture " + textureHandle[0]); | |
| 97 | + GLES20.glTexParameterf(textureTarget, GLES20.GL_TEXTURE_MIN_FILTER, minFilter); | |
| 98 | + GLES20.glTexParameterf(textureTarget, GLES20.GL_TEXTURE_MAG_FILTER, magFilter); //线性插值 | |
| 99 | + GLES20.glTexParameteri(textureTarget, GLES20.GL_TEXTURE_WRAP_S, wrapS); | |
| 100 | + GLES20.glTexParameteri(textureTarget, GLES20.GL_TEXTURE_WRAP_T, wrapT); | |
| 101 | + | |
| 102 | + if (bitmap != null) { | |
| 103 | + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); | |
| 104 | + } | |
| 105 | + | |
| 106 | + GlUtil.checkGlError("glTexParameter"); | |
| 107 | + return textureHandle[0]; | |
| 108 | + } | |
| 109 | + | |
| 110 | + public static int createTexture(int textureTarget) { | |
| 111 | + return createTexture(textureTarget, null, GLES20.GL_LINEAR, GLES20.GL_LINEAR, | |
| 112 | + GLES20.GL_CLAMP_TO_EDGE, GLES20.GL_CLAMP_TO_EDGE); | |
| 113 | + } | |
| 114 | + | |
| 115 | + public static int createTexture(int textureTarget, Bitmap bitmap) { | |
| 116 | + return createTexture(textureTarget, bitmap, GLES20.GL_LINEAR, GLES20.GL_LINEAR, | |
| 117 | + GLES20.GL_CLAMP_TO_EDGE, GLES20.GL_CLAMP_TO_EDGE); | |
| 118 | + } | |
| 119 | + | |
| 120 | + /** | |
| 121 | + * Checks to see if a GLES error has been raised. | |
| 122 | + */ | |
| 123 | + public static void checkGlError(String op) { | |
| 124 | + int error = GLES20.glGetError(); | |
| 125 | + if (error != GLES20.GL_NO_ERROR) { | |
| 126 | + String msg = op + ": glError 0x" + Integer.toHexString(error); | |
| 127 | + Log.e(TAG, msg); | |
| 128 | + throw new RuntimeException(msg); | |
| 129 | + } | |
| 130 | + } | |
| 131 | + | |
| 132 | + /** | |
| 133 | + * Allocates a direct float buffer, and populates it with the float array data. | |
| 134 | + */ | |
| 135 | + public static FloatBuffer createFloatBuffer(float[] coords) { | |
| 136 | + // Allocate a direct ByteBuffer, using 4 bytes per float, and copy coords into it. | |
| 137 | + ByteBuffer bb = ByteBuffer.allocateDirect(coords.length * SIZEOF_FLOAT); | |
| 138 | + bb.order(ByteOrder.nativeOrder()); | |
| 139 | + FloatBuffer fb = bb.asFloatBuffer(); | |
| 140 | + fb.put(coords); | |
| 141 | + fb.position(0); | |
| 142 | + return fb; | |
| 143 | + } | |
| 144 | + | |
| 145 | + public static String readTextFromRawResource(final Context applicationContext, | |
| 146 | + @RawRes final int resourceId) { | |
| 147 | + final InputStream inputStream = | |
| 148 | + applicationContext.getResources().openRawResource(resourceId); | |
| 149 | + final InputStreamReader inputStreamReader = new InputStreamReader(inputStream); | |
| 150 | + final BufferedReader bufferedReader = new BufferedReader(inputStreamReader); | |
| 151 | + String nextLine; | |
| 152 | + final StringBuilder body = new StringBuilder(); | |
| 153 | + try { | |
| 154 | + while ((nextLine = bufferedReader.readLine()) != null) { | |
| 155 | + body.append(nextLine); | |
| 156 | + body.append('\n'); | |
| 157 | + } | |
| 158 | + } catch (IOException e) { | |
| 159 | + return null; | |
| 160 | + } | |
| 161 | + | |
| 162 | + return body.toString(); | |
| 163 | + } | |
| 164 | +} | ... | ... |
app/src/main/java/com/cnlive/demo/stream/ui/CameraPreviewFrameView.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/ui/CameraPreviewFrameView.java | |
| 1 | +package com.cnlive.demo.stream.ui; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.opengl.GLSurfaceView; | |
| 5 | +import android.util.AttributeSet; | |
| 6 | +import android.util.Log; | |
| 7 | +import android.view.GestureDetector; | |
| 8 | +import android.view.MotionEvent; | |
| 9 | +import android.view.ScaleGestureDetector; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * Created by jerikc on 16/2/5. | |
| 13 | + */ | |
| 14 | +public class CameraPreviewFrameView extends GLSurfaceView { | |
| 15 | + private static final String TAG = "CameraPreviewFrameView"; | |
| 16 | + | |
| 17 | + public interface Listener { | |
| 18 | + boolean onSingleTapUp(MotionEvent e); | |
| 19 | + boolean onZoomValueChanged(float factor); | |
| 20 | + } | |
| 21 | + | |
| 22 | + private Listener mListener; | |
| 23 | + private ScaleGestureDetector mScaleDetector; | |
| 24 | + private GestureDetector mGestureDetector; | |
| 25 | + | |
| 26 | + public CameraPreviewFrameView(Context context) { | |
| 27 | + super(context); | |
| 28 | + initialize(context); | |
| 29 | + } | |
| 30 | + | |
| 31 | + public CameraPreviewFrameView(Context context, AttributeSet attrs) { | |
| 32 | + super(context, attrs); | |
| 33 | + initialize(context); | |
| 34 | + } | |
| 35 | + | |
| 36 | + public void setListener(Listener listener) { | |
| 37 | + mListener = listener; | |
| 38 | + } | |
| 39 | + | |
| 40 | + @Override | |
| 41 | + public boolean onTouchEvent(MotionEvent event) { | |
| 42 | + if (!mGestureDetector.onTouchEvent(event)) { | |
| 43 | + return mScaleDetector.onTouchEvent(event); | |
| 44 | + } | |
| 45 | + return false; | |
| 46 | + } | |
| 47 | + | |
| 48 | + private GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() { | |
| 49 | + @Override | |
| 50 | + public boolean onSingleTapUp(MotionEvent e) { | |
| 51 | + if (mListener != null) { | |
| 52 | + mListener.onSingleTapUp(e); | |
| 53 | + } | |
| 54 | + return false; | |
| 55 | + } | |
| 56 | + }; | |
| 57 | + | |
| 58 | + private ScaleGestureDetector.SimpleOnScaleGestureListener mScaleListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() { | |
| 59 | + | |
| 60 | + private float mScaleFactor = 1.0f; | |
| 61 | + | |
| 62 | + @Override | |
| 63 | + public boolean onScaleBegin(ScaleGestureDetector detector) { | |
| 64 | + return true; | |
| 65 | + } | |
| 66 | + | |
| 67 | + @Override | |
| 68 | + public boolean onScale(ScaleGestureDetector detector) { | |
| 69 | + // factor > 1, zoom | |
| 70 | + // factor < 1, pinch | |
| 71 | + mScaleFactor *= detector.getScaleFactor(); | |
| 72 | + | |
| 73 | + // Don't let the object get too small or too large. | |
| 74 | + mScaleFactor = Math.max(0.01f, Math.min(mScaleFactor, 1.0f)); | |
| 75 | + | |
| 76 | + return mListener != null && mListener.onZoomValueChanged(mScaleFactor); | |
| 77 | + } | |
| 78 | + }; | |
| 79 | + | |
| 80 | + private void initialize(Context context) { | |
| 81 | + Log.i(TAG, "initialize"); | |
| 82 | + mScaleDetector = new ScaleGestureDetector(context, mScaleListener); | |
| 83 | + mGestureDetector = new GestureDetector(context, mGestureListener); | |
| 84 | + } | |
| 85 | +} | ... | ... |
app/src/main/java/com/cnlive/demo/stream/ui/FocusIndicatorRotateLayout.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/ui/FocusIndicatorRotateLayout.java | |
| 1 | +package com.cnlive.demo.stream.ui; | |
| 2 | + | |
| 3 | +import android.annotation.TargetApi; | |
| 4 | +import android.content.Context; | |
| 5 | +import android.os.Build; | |
| 6 | +import android.util.AttributeSet; | |
| 7 | +import android.util.Log; | |
| 8 | + | |
| 9 | +import com.cnlive.demo.stream.R; | |
| 10 | + | |
| 11 | + | |
| 12 | +// A view that indicates the focus area or the metering area. | |
| 13 | +public class FocusIndicatorRotateLayout extends RotateLayout { | |
| 14 | + private static final String TAG = "FocusIndicatorLayout"; | |
| 15 | + | |
| 16 | + // Sometimes continuous autofucus starts and stops several times quickly. | |
| 17 | + // These states are used to make sure the animation is run for at least some | |
| 18 | + // time. | |
| 19 | + private int mState; | |
| 20 | + private static final int STATE_IDLE = 0; | |
| 21 | + private static final int STATE_FOCUSING = 1; | |
| 22 | + private static final int STATE_FINISHING = 2; | |
| 23 | + | |
| 24 | + private Runnable mDisappear = new Disappear(); | |
| 25 | + private Runnable mEndAction = new EndAction(); | |
| 26 | + | |
| 27 | + private static final int SCALING_UP_TIME = 1000; | |
| 28 | + private static final int SCALING_DOWN_TIME = 200; | |
| 29 | + private static final int DISAPPEAR_TIMEOUT = 200; | |
| 30 | + | |
| 31 | + public FocusIndicatorRotateLayout(Context context, AttributeSet attrs) { | |
| 32 | + super(context, attrs); | |
| 33 | + } | |
| 34 | + | |
| 35 | + private void setDrawable(int resid) { | |
| 36 | + mChild.setBackgroundDrawable(getResources().getDrawable(resid)); | |
| 37 | + } | |
| 38 | + | |
| 39 | + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) | |
| 40 | + public void showStart() { | |
| 41 | + Log.i(TAG, "showStart"); | |
| 42 | + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { | |
| 43 | + return; | |
| 44 | + } | |
| 45 | + if (mState == STATE_IDLE) { | |
| 46 | + setDrawable(R.drawable.ic_focus_focusing); | |
| 47 | + animate().withLayer().setDuration(SCALING_UP_TIME) | |
| 48 | + .scaleX(1.5f).scaleY(1.5f); | |
| 49 | + mState = STATE_FOCUSING; | |
| 50 | + } | |
| 51 | + } | |
| 52 | + | |
| 53 | + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) | |
| 54 | + public void showSuccess(boolean timeout) { | |
| 55 | + Log.i(TAG, "showSuccess"); | |
| 56 | + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { | |
| 57 | + return; | |
| 58 | + } | |
| 59 | + if (mState == STATE_FOCUSING) { | |
| 60 | + setDrawable(R.drawable.ic_focus_focused); | |
| 61 | + animate().withLayer().setDuration(SCALING_DOWN_TIME).scaleX(1f) | |
| 62 | + .scaleY(1f).withEndAction(timeout ? mEndAction : null); | |
| 63 | + mState = STATE_FINISHING; | |
| 64 | + } | |
| 65 | + } | |
| 66 | + | |
| 67 | + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) | |
| 68 | + public void showFail(boolean timeout) { | |
| 69 | + Log.i(TAG, "showFail"); | |
| 70 | + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { | |
| 71 | + return; | |
| 72 | + } | |
| 73 | + if (mState == STATE_FOCUSING) { | |
| 74 | + setDrawable(R.drawable.ic_focus_failed); | |
| 75 | + animate().withLayer().setDuration(SCALING_DOWN_TIME).scaleX(1f) | |
| 76 | + .scaleY(1f).withEndAction(timeout ? mEndAction : null); | |
| 77 | + mState = STATE_FINISHING; | |
| 78 | + } | |
| 79 | + } | |
| 80 | + | |
| 81 | + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) | |
| 82 | + public void clear() { | |
| 83 | + Log.i(TAG, "clear"); | |
| 84 | + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { | |
| 85 | + return; | |
| 86 | + } | |
| 87 | + animate().cancel(); | |
| 88 | + removeCallbacks(mDisappear); | |
| 89 | + mDisappear.run(); | |
| 90 | + setScaleX(1f); | |
| 91 | + setScaleY(1f); | |
| 92 | + } | |
| 93 | + | |
| 94 | + private class EndAction implements Runnable { | |
| 95 | + @Override | |
| 96 | + public void run() { | |
| 97 | + // Keep the focus indicator for some time. | |
| 98 | + postDelayed(mDisappear, DISAPPEAR_TIMEOUT); | |
| 99 | + } | |
| 100 | + } | |
| 101 | + | |
| 102 | + private class Disappear implements Runnable { | |
| 103 | + @Override | |
| 104 | + public void run() { | |
| 105 | + mChild.setBackgroundDrawable(null); | |
| 106 | + mState = STATE_IDLE; | |
| 107 | + } | |
| 108 | + } | |
| 109 | +} | |
| 0 | 110 | \ No newline at end of file | ... | ... |
app/src/main/java/com/cnlive/demo/stream/ui/Rotatable.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/ui/Rotatable.java | |
| 1 | +package com.cnlive.demo.stream.ui; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * Created by jerikc on 16/2/5. | |
| 5 | + */ | |
| 6 | +public interface Rotatable { | |
| 7 | + // Set parameter 'animation' to true to have animation when rotation. | |
| 8 | + void setOrientation(int orientation, boolean animation); | |
| 9 | +} | ... | ... |
app/src/main/java/com/cnlive/demo/stream/ui/RotateLayout.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/demo/stream/ui/RotateLayout.java | |
| 1 | +package com.cnlive.demo.stream.ui; | |
| 2 | + | |
| 3 | +import android.annotation.TargetApi; | |
| 4 | +import android.content.Context; | |
| 5 | +import android.os.Build; | |
| 6 | +import android.util.AttributeSet; | |
| 7 | +import android.view.View; | |
| 8 | +import android.view.ViewGroup; | |
| 9 | + | |
| 10 | +// A RotateLayout is designed to display a single item and provides the | |
| 11 | +// capabilities to rotate the item. | |
| 12 | +public class RotateLayout extends ViewGroup implements Rotatable { | |
| 13 | + @SuppressWarnings("unused") | |
| 14 | + private static final String TAG = "RotateLayout"; | |
| 15 | + private int mOrientation; | |
| 16 | + protected View mChild; | |
| 17 | + public RotateLayout(Context context, AttributeSet attrs) { | |
| 18 | + super(context, attrs); | |
| 19 | + // The transparent background here is a workaround of the render issue | |
| 20 | + // happened when the view is rotated as the device's orientation | |
| 21 | + // changed. The view looks fine in landscape. After rotation, the view | |
| 22 | + // is invisible. | |
| 23 | + setBackgroundResource(android.R.color.transparent); | |
| 24 | + } | |
| 25 | + | |
| 26 | + @TargetApi(Build.VERSION_CODES.HONEYCOMB) | |
| 27 | + @Override | |
| 28 | + protected void onFinishInflate() { | |
| 29 | + super.onFinishInflate(); | |
| 30 | + mChild = getChildAt(0); | |
| 31 | + mChild.setPivotX(0); | |
| 32 | + mChild.setPivotY(0); | |
| 33 | + } | |
| 34 | + | |
| 35 | + @Override | |
| 36 | + protected void onLayout( | |
| 37 | + boolean change, int left, int top, int right, int bottom) { | |
| 38 | + int width = right - left; | |
| 39 | + int height = bottom - top; | |
| 40 | + switch (mOrientation) { | |
| 41 | + case 0: | |
| 42 | + case 180: | |
| 43 | + mChild.layout(0, 0, width, height); | |
| 44 | + break; | |
| 45 | + case 90: | |
| 46 | + case 270: | |
| 47 | + mChild.layout(0, 0, height, width); | |
| 48 | + break; | |
| 49 | + } | |
| 50 | + } | |
| 51 | + | |
| 52 | + @TargetApi(Build.VERSION_CODES.HONEYCOMB) | |
| 53 | + @Override | |
| 54 | + protected void onMeasure(int widthSpec, int heightSpec) { | |
| 55 | + int w = 0, h = 0; | |
| 56 | + switch(mOrientation) { | |
| 57 | + case 0: | |
| 58 | + case 180: | |
| 59 | + measureChild(mChild, widthSpec, heightSpec); | |
| 60 | + w = mChild.getMeasuredWidth(); | |
| 61 | + h = mChild.getMeasuredHeight(); | |
| 62 | + break; | |
| 63 | + case 90: | |
| 64 | + case 270: | |
| 65 | + measureChild(mChild, heightSpec, widthSpec); | |
| 66 | + w = mChild.getMeasuredHeight(); | |
| 67 | + h = mChild.getMeasuredWidth(); | |
| 68 | + break; | |
| 69 | + } | |
| 70 | + setMeasuredDimension(w, h); | |
| 71 | + switch (mOrientation) { | |
| 72 | + case 0: | |
| 73 | + mChild.setTranslationX(0); | |
| 74 | + mChild.setTranslationY(0); | |
| 75 | + break; | |
| 76 | + case 90: | |
| 77 | + mChild.setTranslationX(0); | |
| 78 | + mChild.setTranslationY(h); | |
| 79 | + break; | |
| 80 | + case 180: | |
| 81 | + mChild.setTranslationX(w); | |
| 82 | + mChild.setTranslationY(h); | |
| 83 | + break; | |
| 84 | + case 270: | |
| 85 | + mChild.setTranslationX(w); | |
| 86 | + mChild.setTranslationY(0); | |
| 87 | + break; | |
| 88 | + } | |
| 89 | + mChild.setRotation(-mOrientation); | |
| 90 | + } | |
| 91 | + | |
| 92 | + @Override | |
| 93 | + public boolean shouldDelayChildPressedState() { | |
| 94 | + return false; | |
| 95 | + } | |
| 96 | + | |
| 97 | + // Rotate the view counter-clockwise | |
| 98 | + @Override | |
| 99 | + public void setOrientation(int orientation, boolean animation) { | |
| 100 | + orientation = orientation % 360; | |
| 101 | + if (mOrientation == orientation) return; | |
| 102 | + mOrientation = orientation; | |
| 103 | + requestLayout(); | |
| 104 | + } | |
| 105 | +} | |
| 0 | 106 | \ No newline at end of file | ... | ... |
app/src/main/jniLibs/arm64-v8a/libpldroid_mmprocessing.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/arm64-v8a/libpldroid_streaming_aac_encoder.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/arm64-v8a/libpldroid_streaming_core.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/arm64-v8a/libpldroid_streaming_h264_encoder.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/libpldroid_mmprocessing.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/libpldroid_streaming_aac_encoder.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/libpldroid_streaming_core.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/libpldroid_streaming_h264_encoder.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi/libpldroid_mmprocessing.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi/libpldroid_streaming_aac_encoder.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi/libpldroid_streaming_core.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi/libpldroid_streaming_h264_encoder.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/x86/libpldroid_mmprocessing.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/x86/libpldroid_streaming_aac_encoder.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/x86/libpldroid_streaming_core.so
0 → 100644
No preview for this file type
app/src/main/jniLibs/x86/libpldroid_streaming_h264_encoder.so
0 → 100644
No preview for this file type
app/src/main/res/drawable-hdpi/cnlive_logo.png
0 → 100644
6.02 KB
app/src/main/res/drawable-hdpi/ic_focus_failed.9.png
0 → 100644
809 Bytes
app/src/main/res/drawable-hdpi/ic_focus_focused.9.png
0 → 100644
927 Bytes
app/src/main/res/drawable-hdpi/ic_focus_focusing.9.png
0 → 100644
812 Bytes
app/src/main/res/drawable-xxhdpi/icon_record_close_off.png
0 → 100644
5.67 KB
app/src/main/res/drawable-xxhdpi/icon_record_flash_off.png
0 → 100644
3.77 KB
app/src/main/res/drawable-xxhdpi/icon_record_flip_off.png
0 → 100644
4.03 KB
app/src/main/res/drawable-xxhdpi/icon_record_meiyan_off.png
0 → 100644
4.48 KB
app/src/main/res/drawable-xxhdpi/icon_record_meiyan_on.png
0 → 100644
6.14 KB
app/src/main/res/layout/activity_main.xml
0 → 100644
| 1 | +++ a/app/src/main/res/layout/activity_main.xml | |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + xmlns:tools="http://schemas.android.com/tools" | |
| 4 | + android:id="@+id/activity_main" | |
| 5 | + android:layout_width="match_parent" | |
| 6 | + android:layout_height="match_parent" | |
| 7 | + android:paddingBottom="@dimen/activity_vertical_margin" | |
| 8 | + android:paddingLeft="@dimen/activity_horizontal_margin" | |
| 9 | + android:paddingRight="@dimen/activity_horizontal_margin" | |
| 10 | + android:paddingTop="@dimen/activity_vertical_margin" | |
| 11 | + tools:context=".MainActivity"> | |
| 12 | + | |
| 13 | + <LinearLayout | |
| 14 | + android:layout_width="match_parent" | |
| 15 | + android:layout_height="wrap_content" | |
| 16 | + android:orientation="vertical"> | |
| 17 | + | |
| 18 | + <LinearLayout | |
| 19 | + android:layout_width="match_parent" | |
| 20 | + android:layout_height="wrap_content" | |
| 21 | + android:orientation="horizontal"> | |
| 22 | + | |
| 23 | + <TextView | |
| 24 | + android:layout_width="wrap_content" | |
| 25 | + android:layout_height="wrap_content" | |
| 26 | + android:text="ActivityID" | |
| 27 | + android:textColor="#000000" | |
| 28 | + android:textSize="18sp" /> | |
| 29 | + | |
| 30 | + <EditText | |
| 31 | + android:id="@+id/activityId" | |
| 32 | + android:layout_width="match_parent" | |
| 33 | + android:layout_height="wrap_content" | |
| 34 | + android:hint="请输入activityId" /> | |
| 35 | + </LinearLayout> | |
| 36 | + | |
| 37 | + <LinearLayout | |
| 38 | + android:layout_width="match_parent" | |
| 39 | + android:layout_height="wrap_content" | |
| 40 | + android:orientation="horizontal"> | |
| 41 | + | |
| 42 | + <TextView | |
| 43 | + android:layout_width="wrap_content" | |
| 44 | + android:layout_height="wrap_content" | |
| 45 | + android:text="ChannelID" | |
| 46 | + android:textColor="#000000" | |
| 47 | + android:textSize="18sp" /> | |
| 48 | + | |
| 49 | + <EditText | |
| 50 | + android:id="@+id/channelId" | |
| 51 | + android:layout_width="match_parent" | |
| 52 | + android:layout_height="wrap_content" | |
| 53 | + android:hint="请输入ChannelId" /> | |
| 54 | + </LinearLayout> | |
| 55 | + </LinearLayout> | |
| 56 | + | |
| 57 | + <Button | |
| 58 | + android:id="@+id/connectBtn" | |
| 59 | + android:layout_width="match_parent" | |
| 60 | + android:layout_height="wrap_content" | |
| 61 | + android:layout_alignParentBottom="true" | |
| 62 | + android:text="准备推流" | |
| 63 | + android:textSize="18sp" /> | |
| 64 | +</RelativeLayout> | ... | ... |
app/src/main/res/layout/activity_stream.xml
0 → 100644
| 1 | +++ a/app/src/main/res/layout/activity_stream.xml | |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + xmlns:tools="http://schemas.android.com/tools" | |
| 4 | + android:id="@+id/activity_stream" | |
| 5 | + android:layout_width="match_parent" | |
| 6 | + android:layout_height="match_parent" | |
| 7 | + tools:context=".BaseStreamActivity"> | |
| 8 | + | |
| 9 | + | |
| 10 | + <com.cnlive.libs.lib_cnstream.base.CNAspectFrameLayout | |
| 11 | + android:id="@+id/cameraPreview_afl" | |
| 12 | + android:layout_width="match_parent" | |
| 13 | + android:layout_height="match_parent" | |
| 14 | + android:layout_alignParentTop="true" | |
| 15 | + android:layout_centerHorizontal="true"> | |
| 16 | + | |
| 17 | + <com.cnlive.demo.stream.ui.CameraPreviewFrameView | |
| 18 | + android:id="@+id/cameraPreview_surfaceView" | |
| 19 | + android:layout_width="match_parent" | |
| 20 | + android:layout_height="match_parent" | |
| 21 | + android:layout_gravity="center" /> | |
| 22 | + | |
| 23 | + <include layout="@layout/focus_indicator" /> | |
| 24 | + | |
| 25 | + </com.cnlive.libs.lib_cnstream.base.CNAspectFrameLayout> | |
| 26 | + | |
| 27 | + <RelativeLayout | |
| 28 | + android:layout_width="wrap_content" | |
| 29 | + android:layout_height="wrap_content" | |
| 30 | + android:layout_alignParentRight="true" | |
| 31 | + android:layout_marginTop="8dp"> | |
| 32 | + | |
| 33 | + <ImageView | |
| 34 | + android:id="@+id/flashBtn" | |
| 35 | + android:layout_width="wrap_content" | |
| 36 | + android:layout_height="wrap_content" | |
| 37 | + android:layout_marginRight="8dp" | |
| 38 | + android:background="@drawable/icon_record_flash_off" /> | |
| 39 | + | |
| 40 | + <ImageView | |
| 41 | + android:id="@+id/flipBtn" | |
| 42 | + android:layout_width="wrap_content" | |
| 43 | + android:layout_height="wrap_content" | |
| 44 | + android:layout_marginRight="8dp" | |
| 45 | + android:layout_toRightOf="@id/flashBtn" | |
| 46 | + android:background="@drawable/icon_record_flip_off" /> | |
| 47 | + | |
| 48 | + <ImageView | |
| 49 | + android:id="@+id/beautyBtn" | |
| 50 | + android:layout_width="wrap_content" | |
| 51 | + android:layout_height="wrap_content" | |
| 52 | + android:layout_marginRight="8dp" | |
| 53 | + android:layout_toRightOf="@id/flipBtn" | |
| 54 | + android:background="@drawable/icon_record_meiyan_on" /> | |
| 55 | + | |
| 56 | + <ImageView | |
| 57 | + android:id="@+id/closeBtn" | |
| 58 | + android:layout_width="wrap_content" | |
| 59 | + android:layout_height="wrap_content" | |
| 60 | + android:layout_marginRight="8dp" | |
| 61 | + android:layout_toRightOf="@id/beautyBtn" | |
| 62 | + android:background="@drawable/icon_record_close_off" /> | |
| 63 | + </RelativeLayout> | |
| 64 | + | |
| 65 | + <SeekBar | |
| 66 | + android:id="@+id/beautyLevel_seekBar" | |
| 67 | + android:layout_width="match_parent" | |
| 68 | + android:layout_height="wrap_content" | |
| 69 | + android:layout_alignParentBottom="true" | |
| 70 | + android:layout_marginBottom="100dp" | |
| 71 | + android:max="100" | |
| 72 | + android:progress="100" /> | |
| 73 | + | |
| 74 | + <LinearLayout | |
| 75 | + android:layout_width="match_parent" | |
| 76 | + android:layout_height="wrap_content" | |
| 77 | + android:layout_alignParentBottom="true" | |
| 78 | + android:layout_alignParentLeft="true" | |
| 79 | + android:layout_alignParentStart="true" | |
| 80 | + android:orientation="horizontal"> | |
| 81 | + | |
| 82 | + <Button | |
| 83 | + android:id="@+id/orientationBtn" | |
| 84 | + android:layout_width="0dp" | |
| 85 | + android:layout_height="wrap_content" | |
| 86 | + android:layout_weight="1" | |
| 87 | + android:text="横屏" | |
| 88 | + android:textSize="14sp" /> | |
| 89 | + | |
| 90 | + <Button | |
| 91 | + android:id="@+id/startStreamBtn" | |
| 92 | + android:layout_width="0dp" | |
| 93 | + android:layout_height="wrap_content" | |
| 94 | + android:layout_marginLeft="5dp" | |
| 95 | + android:layout_weight="1" | |
| 96 | + android:text="开始推流" | |
| 97 | + android:textSize="14sp" /> | |
| 98 | + | |
| 99 | + <Button | |
| 100 | + android:id="@+id/muteBtn" | |
| 101 | + android:layout_width="0dp" | |
| 102 | + android:layout_height="wrap_content" | |
| 103 | + android:layout_marginLeft="5dp" | |
| 104 | + android:layout_weight="1" | |
| 105 | + android:text="静音" | |
| 106 | + android:textSize="14sp" /> | |
| 107 | + | |
| 108 | + <Button | |
| 109 | + android:id="@+id/captureBtn" | |
| 110 | + android:layout_width="0dp" | |
| 111 | + android:layout_height="wrap_content" | |
| 112 | + android:layout_marginLeft="5dp" | |
| 113 | + android:layout_weight="1" | |
| 114 | + android:text="截帧" | |
| 115 | + android:textSize="14sp" /> | |
| 116 | + </LinearLayout> | |
| 117 | +</RelativeLayout> | ... | ... |
app/src/main/res/layout/focus_indicator.xml
0 → 100644
| 1 | +++ a/app/src/main/res/layout/focus_indicator.xml | |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<com.cnlive.demo.stream.ui.FocusIndicatorRotateLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + android:id="@+id/focus_indicator_rotate_layout" | |
| 4 | + android:layout_width="wrap_content" | |
| 5 | + android:layout_height="wrap_content" | |
| 6 | + android:layout_centerInParent="true"> | |
| 7 | + | |
| 8 | + <View | |
| 9 | + android:id="@+id/focus_indicator" | |
| 10 | + android:layout_width="120dp" | |
| 11 | + android:layout_height="120dp" /> | |
| 12 | +</com.cnlive.demo.stream.ui.FocusIndicatorRotateLayout> | |
| 0 | 13 | \ No newline at end of file | ... | ... |
app/src/main/res/mipmap-hdpi/ic_launcher.png
0 → 100644
3.34 KB
app/src/main/res/mipmap-mdpi/ic_launcher.png
0 → 100644
2.15 KB
app/src/main/res/mipmap-xhdpi/ic_launcher.png
0 → 100644
4.73 KB
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
0 → 100644
7.54 KB
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
0 → 100644
10.2 KB
app/src/main/res/raw/cross_1.acv
0 → 100644
No preview for this file type
app/src/main/res/raw/cross_10.acv
0 → 100644
No preview for this file type
app/src/main/res/raw/cross_11.acv
0 → 100644
No preview for this file type
app/src/main/res/raw/cross_2.acv
0 → 100644
No preview for this file type
app/src/main/res/raw/cross_3.acv
0 → 100644
No preview for this file type
app/src/main/res/raw/cross_4.acv
0 → 100644
No preview for this file type
app/src/main/res/raw/cross_5.acv
0 → 100644
No preview for this file type
app/src/main/res/raw/cross_6.acv
0 → 100644
No preview for this file type
app/src/main/res/raw/cross_7.acv
0 → 100644
No preview for this file type
app/src/main/res/raw/cross_8.acv
0 → 100644
No preview for this file type
app/src/main/res/raw/cross_9.acv
0 → 100644
No preview for this file type
app/src/main/res/raw/fragment_shader_beauty.glsl
0 → 100644
| 1 | +++ a/app/src/main/res/raw/fragment_shader_beauty.glsl | |
| 1 | +#extension GL_OES_EGL_image_external : require | |
| 2 | + | |
| 3 | +precision highp float; | |
| 4 | + | |
| 5 | + uniform samplerExternalOES uTexture; | |
| 6 | + uniform vec2 singleStepOffset; | |
| 7 | + | |
| 8 | + vec4 params = vec4(0.33, 0.63, 0.4, 0.35); | |
| 9 | + | |
| 10 | + varying vec2 vTextureCoord; | |
| 11 | + | |
| 12 | + const highp vec3 W = vec3(0.299,0.587,0.114); | |
| 13 | + | |
| 14 | + const mat3 saturateMatrix = mat3( | |
| 15 | + 1.1102,-0.0598,-0.061, | |
| 16 | + -0.0774,1.0826,-0.1186, | |
| 17 | + -0.0228,-0.0228,1.1772); | |
| 18 | + | |
| 19 | + vec2 blurCoordinates[24]; | |
| 20 | + | |
| 21 | + float hardLight(float color) | |
| 22 | + { | |
| 23 | + if(color <= 0.5) | |
| 24 | + { | |
| 25 | + color = color * color * 2.0; | |
| 26 | + } | |
| 27 | + else | |
| 28 | + { | |
| 29 | + color = 1.0 - ((1.0 - color)*(1.0 - color) * 2.0); | |
| 30 | + } | |
| 31 | + return color; | |
| 32 | + } | |
| 33 | + | |
| 34 | + void main(){ | |
| 35 | + vec3 centralColor = texture2D(uTexture, vTextureCoord).rgb; | |
| 36 | + | |
| 37 | + blurCoordinates[0] = vTextureCoord.xy + singleStepOffset * vec2(0.0, -10.0); | |
| 38 | + blurCoordinates[1] = vTextureCoord.xy + singleStepOffset * vec2(0.0, 10.0); | |
| 39 | + blurCoordinates[2] = vTextureCoord.xy + singleStepOffset * vec2(-10.0, 0.0); | |
| 40 | + blurCoordinates[3] = vTextureCoord.xy + singleStepOffset * vec2(10.0, 0.0); | |
| 41 | + blurCoordinates[4] = vTextureCoord.xy + singleStepOffset * vec2(5.0, -8.0); | |
| 42 | + blurCoordinates[5] = vTextureCoord.xy + singleStepOffset * vec2(5.0, 8.0); | |
| 43 | + blurCoordinates[6] = vTextureCoord.xy + singleStepOffset * vec2(-5.0, 8.0); | |
| 44 | + blurCoordinates[7] = vTextureCoord.xy + singleStepOffset * vec2(-5.0, -8.0); | |
| 45 | + blurCoordinates[8] = vTextureCoord.xy + singleStepOffset * vec2(8.0, -5.0); | |
| 46 | + blurCoordinates[9] = vTextureCoord.xy + singleStepOffset * vec2(8.0, 5.0); | |
| 47 | + blurCoordinates[10] = vTextureCoord.xy + singleStepOffset * vec2(-8.0, 5.0); | |
| 48 | + blurCoordinates[11] = vTextureCoord.xy + singleStepOffset * vec2(-8.0, -5.0); | |
| 49 | + blurCoordinates[12] = vTextureCoord.xy + singleStepOffset * vec2(0.0, -6.0); | |
| 50 | + blurCoordinates[13] = vTextureCoord.xy + singleStepOffset * vec2(0.0, 6.0); | |
| 51 | + blurCoordinates[14] = vTextureCoord.xy + singleStepOffset * vec2(6.0, 0.0); | |
| 52 | + blurCoordinates[15] = vTextureCoord.xy + singleStepOffset * vec2(-6.0, 0.0); | |
| 53 | + blurCoordinates[16] = vTextureCoord.xy + singleStepOffset * vec2(-4.0, -4.0); | |
| 54 | + blurCoordinates[17] = vTextureCoord.xy + singleStepOffset * vec2(-4.0, 4.0); | |
| 55 | + blurCoordinates[18] = vTextureCoord.xy + singleStepOffset * vec2(4.0, -4.0); | |
| 56 | + blurCoordinates[19] = vTextureCoord.xy + singleStepOffset * vec2(4.0, 4.0); | |
| 57 | + blurCoordinates[20] = vTextureCoord.xy + singleStepOffset * vec2(-2.0, -2.0); | |
| 58 | + blurCoordinates[21] = vTextureCoord.xy + singleStepOffset * vec2(-2.0, 2.0); | |
| 59 | + blurCoordinates[22] = vTextureCoord.xy + singleStepOffset * vec2(2.0, -2.0); | |
| 60 | + blurCoordinates[23] = vTextureCoord.xy + singleStepOffset * vec2(2.0, 2.0); | |
| 61 | + | |
| 62 | + float sampleColor = centralColor.g * 22.0; | |
| 63 | + sampleColor += texture2D(uTexture, blurCoordinates[0]).g; | |
| 64 | + sampleColor += texture2D(uTexture, blurCoordinates[1]).g; | |
| 65 | + sampleColor += texture2D(uTexture, blurCoordinates[2]).g; | |
| 66 | + sampleColor += texture2D(uTexture, blurCoordinates[3]).g; | |
| 67 | + sampleColor += texture2D(uTexture, blurCoordinates[4]).g; | |
| 68 | + sampleColor += texture2D(uTexture, blurCoordinates[5]).g; | |
| 69 | + sampleColor += texture2D(uTexture, blurCoordinates[6]).g; | |
| 70 | + sampleColor += texture2D(uTexture, blurCoordinates[7]).g; | |
| 71 | + sampleColor += texture2D(uTexture, blurCoordinates[8]).g; | |
| 72 | + sampleColor += texture2D(uTexture, blurCoordinates[9]).g; | |
| 73 | + sampleColor += texture2D(uTexture, blurCoordinates[10]).g; | |
| 74 | + sampleColor += texture2D(uTexture, blurCoordinates[11]).g; | |
| 75 | + sampleColor += texture2D(uTexture, blurCoordinates[12]).g * 2.0; | |
| 76 | + sampleColor += texture2D(uTexture, blurCoordinates[13]).g * 2.0; | |
| 77 | + sampleColor += texture2D(uTexture, blurCoordinates[14]).g * 2.0; | |
| 78 | + sampleColor += texture2D(uTexture, blurCoordinates[15]).g * 2.0; | |
| 79 | + sampleColor += texture2D(uTexture, blurCoordinates[16]).g * 2.0; | |
| 80 | + sampleColor += texture2D(uTexture, blurCoordinates[17]).g * 2.0; | |
| 81 | + sampleColor += texture2D(uTexture, blurCoordinates[18]).g * 2.0; | |
| 82 | + sampleColor += texture2D(uTexture, blurCoordinates[19]).g * 2.0; | |
| 83 | + sampleColor += texture2D(uTexture, blurCoordinates[20]).g * 3.0; | |
| 84 | + sampleColor += texture2D(uTexture, blurCoordinates[21]).g * 3.0; | |
| 85 | + sampleColor += texture2D(uTexture, blurCoordinates[22]).g * 3.0; | |
| 86 | + sampleColor += texture2D(uTexture, blurCoordinates[23]).g * 3.0; | |
| 87 | + sampleColor = sampleColor / 62.0; | |
| 88 | + | |
| 89 | + float highPass = centralColor.g - sampleColor + 0.5; | |
| 90 | + | |
| 91 | + for(int i = 0; i < 5;i++) | |
| 92 | + { | |
| 93 | + highPass = hardLight(highPass); | |
| 94 | + } | |
| 95 | + float luminance = dot(centralColor, W); | |
| 96 | + float alpha = pow(luminance, params.r); | |
| 97 | + | |
| 98 | + vec3 smoothColor = centralColor + (centralColor-vec3(highPass))*alpha*0.1; | |
| 99 | + | |
| 100 | + smoothColor.r = clamp(pow(smoothColor.r, params.g),0.0,1.0); | |
| 101 | + smoothColor.g = clamp(pow(smoothColor.g, params.g),0.0,1.0); | |
| 102 | + smoothColor.b = clamp(pow(smoothColor.b, params.g),0.0,1.0); | |
| 103 | + | |
| 104 | + vec3 screen = vec3(1.0) - (vec3(1.0)-smoothColor) * (vec3(1.0)-centralColor); | |
| 105 | + vec3 lighten = max(smoothColor, centralColor); | |
| 106 | + vec3 softLight = 2.0 * centralColor*smoothColor + centralColor*centralColor | |
| 107 | + - 2.0 * centralColor*centralColor * smoothColor; | |
| 108 | + | |
| 109 | + gl_FragColor = vec4(mix(centralColor, screen, alpha), 1.0); | |
| 110 | + gl_FragColor.rgb = mix(gl_FragColor.rgb, lighten, alpha); | |
| 111 | + gl_FragColor.rgb = mix(gl_FragColor.rgb, softLight, params.b); | |
| 112 | + | |
| 113 | + vec3 satColor = gl_FragColor.rgb * saturateMatrix; | |
| 114 | + gl_FragColor.rgb = mix(gl_FragColor.rgb, satColor, params.a); | |
| 115 | + } | |
| 0 | 116 | \ No newline at end of file | ... | ... |
app/src/main/res/raw/fragment_shader_ext_tone_curve.glsl
0 → 100644
| 1 | +++ a/app/src/main/res/raw/fragment_shader_ext_tone_curve.glsl | |
| 1 | +#extension GL_OES_EGL_image_external : require | |
| 2 | +precision mediump float; | |
| 3 | + | |
| 4 | +varying vec2 vTextureCoord; | |
| 5 | +uniform samplerExternalOES uTexture; | |
| 6 | +uniform sampler2D toneCurveTexture; | |
| 7 | + | |
| 8 | +void main() { | |
| 9 | + vec4 textureColor = texture2D(uTexture, vTextureCoord); | |
| 10 | + | |
| 11 | + float redCurveValue = texture2D(toneCurveTexture, vec2(textureColor.r, 0.0)).r; | |
| 12 | + float greenCurveValue = texture2D(toneCurveTexture, vec2(textureColor.g, 0.0)).g; | |
| 13 | + float blueCurveValue = texture2D(toneCurveTexture, vec2(textureColor.b, 0.0)).b; | |
| 14 | + | |
| 15 | + gl_FragColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a); | |
| 16 | +} | |
| 0 | 17 | \ No newline at end of file | ... | ... |
app/src/main/res/raw/fragment_shader_mosaic.glsl
0 → 100644
| 1 | +++ a/app/src/main/res/raw/fragment_shader_mosaic.glsl | |
| 1 | +#extension GL_OES_EGL_image_external : require | |
| 2 | + | |
| 3 | +precision mediump float; | |
| 4 | + | |
| 5 | +varying vec2 vTextureCoord; | |
| 6 | +uniform samplerExternalOES uTexture; | |
| 7 | +uniform vec2 TexSize; | |
| 8 | +vec2 mosaicSize = vec2(2,2); | |
| 9 | + | |
| 10 | + void main() | |
| 11 | + { | |
| 12 | + vec2 intXY = vec2(vTextureCoord.x*TexSize.x, vTextureCoord.y*TexSize.y); | |
| 13 | + vec2 XYMosaic = vec2(floor(intXY.x/mosaicSize.x)*mosaicSize.x,floor(intXY.y/mosaicSize.y)*mosaicSize.y); | |
| 14 | + vec2 UVMosaic = vec2(XYMosaic.x/TexSize.x,XYMosaic.y/TexSize.y); | |
| 15 | + vec4 baseMap = texture2D(uTexture,UVMosaic); | |
| 16 | + gl_FragColor = baseMap; | |
| 17 | + } | |
| 0 | 18 | \ No newline at end of file | ... | ... |
app/src/main/res/raw/fragment_shader_no_filter.glsl
0 → 100644
| 1 | +++ a/app/src/main/res/raw/fragment_shader_no_filter.glsl | |
| 1 | +#extension GL_OES_EGL_image_external : require | |
| 2 | + | |
| 3 | +precision mediump float; | |
| 4 | + | |
| 5 | +varying vec2 vTextureCoord; | |
| 6 | +uniform samplerExternalOES uTexture; | |
| 7 | + | |
| 8 | +void main() { | |
| 9 | + gl_FragColor = texture2D(uTexture, vTextureCoord); | |
| 10 | +} | |
| 0 | 11 | \ No newline at end of file | ... | ... |
app/src/main/res/raw/vertex_shader.glsl
0 → 100644
| 1 | +++ a/app/src/main/res/raw/vertex_shader.glsl | |
| 1 | +uniform mat4 uMVPMatrix; | |
| 2 | + | |
| 3 | +attribute vec4 aPosition; | |
| 4 | +attribute vec4 aTextureCoord; | |
| 5 | + | |
| 6 | +varying vec2 vTextureCoord; | |
| 7 | + | |
| 8 | +void main() { | |
| 9 | + gl_Position = uMVPMatrix * aPosition; | |
| 10 | + vTextureCoord = aTextureCoord.xy; | |
| 11 | +} | |
| 0 | 12 | \ No newline at end of file | ... | ... |
app/src/main/res/raw/vertex_shader_two_input.glsl
0 → 100644
| 1 | +++ a/app/src/main/res/raw/vertex_shader_two_input.glsl | |
| 1 | +uniform mat4 uMVPMatrix; | |
| 2 | + | |
| 3 | +attribute vec4 aPosition; | |
| 4 | + | |
| 5 | +attribute vec4 aTextureCoord; | |
| 6 | +attribute vec4 aExtraTextureCoord; | |
| 7 | + | |
| 8 | +varying vec2 vTextureCoord; | |
| 9 | +varying vec2 vExtraTextureCoord; | |
| 10 | + | |
| 11 | +void main() { | |
| 12 | + gl_Position = uMVPMatrix * aPosition; | |
| 13 | + vExtraTextureCoord = vec2(aExtraTextureCoord.x, 1.0 - aExtraTextureCoord.y); | |
| 14 | + vTextureCoord = aTextureCoord.xy; | |
| 15 | +} | |
| 0 | 16 | \ No newline at end of file | ... | ... |
app/src/main/res/values-w820dp/dimens.xml
0 → 100644
| 1 | +++ a/app/src/main/res/values-w820dp/dimens.xml | |
| 1 | +<resources> | |
| 2 | + <!-- Example customization of dimensions originally defined in res/values/dimens.xml | |
| 3 | + (such as screen margins) for screens with more than 820dp of available width. This | |
| 4 | + would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). --> | |
| 5 | + <dimen name="activity_horizontal_margin">64dp</dimen> | |
| 6 | +</resources> | ... | ... |
app/src/main/res/values/colors.xml
0 → 100644
app/src/main/res/values/dimens.xml
0 → 100644
app/src/main/res/values/strings.xml
0 → 100644
app/src/main/res/values/styles.xml
0 → 100644
| 1 | +++ a/app/src/main/res/values/styles.xml | |
| 1 | +<resources> | |
| 2 | + | |
| 3 | + <!-- Base application theme. --> | |
| 4 | + <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> | |
| 5 | + <!-- Customize your theme here. --> | |
| 6 | + <item name="colorPrimary">@color/colorPrimary</item> | |
| 7 | + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | |
| 8 | + <item name="colorAccent">@color/colorAccent</item> | |
| 9 | + </style> | |
| 10 | + | |
| 11 | +</resources> | ... | ... |
app/src/test/java/com/cnlive/demo/stream/ExampleUnitTest.java
0 → 100644
| 1 | +++ a/app/src/test/java/com/cnlive/demo/stream/ExampleUnitTest.java | |
| 1 | +package com.cnlive.demo.stream; | |
| 2 | + | |
| 3 | +import org.junit.Test; | |
| 4 | + | |
| 5 | +import static org.junit.Assert.*; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Example local unit test, which will execute on the development machine (host). | |
| 9 | + * | |
| 10 | + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | |
| 11 | + */ | |
| 12 | +public class ExampleUnitTest { | |
| 13 | + @Test | |
| 14 | + public void addition_isCorrect() throws Exception { | |
| 15 | + assertEquals(4, 2 + 2); | |
| 16 | + } | |
| 17 | +} | |
| 0 | 18 | \ No newline at end of file | ... | ... |
build.gradle
0 → 100644
| 1 | +++ a/build.gradle | |
| 1 | +// Top-level build file where you can add configuration options common to all sub-projects/modules. | |
| 2 | + | |
| 3 | +buildscript { | |
| 4 | + repositories { | |
| 5 | + jcenter() | |
| 6 | + } | |
| 7 | + dependencies { | |
| 8 | + classpath 'com.android.tools.build:gradle:2.2.2' | |
| 9 | + | |
| 10 | + // NOTE: Do not place your application dependencies here; they belong | |
| 11 | + // in the individual module build.gradle files | |
| 12 | + } | |
| 13 | +} | |
| 14 | + | |
| 15 | +allprojects { | |
| 16 | + repositories { | |
| 17 | + jcenter() | |
| 18 | + } | |
| 19 | +} | |
| 20 | + | |
| 21 | +task clean(type: Delete) { | |
| 22 | + delete rootProject.buildDir | |
| 23 | +} | ... | ... |
gradle.properties
0 → 100644
| 1 | +++ a/gradle.properties | |
| 1 | +# Project-wide Gradle settings. | |
| 2 | + | |
| 3 | +# IDE (e.g. Android Studio) users: | |
| 4 | +# Gradle settings configured through the IDE *will override* | |
| 5 | +# any settings specified in this file. | |
| 6 | + | |
| 7 | +# For more details on how to configure your build environment visit | |
| 8 | +# http://www.gradle.org/docs/current/userguide/build_environment.html | |
| 9 | + | |
| 10 | +# Specifies the JVM arguments used for the daemon process. | |
| 11 | +# The setting is particularly useful for tweaking memory settings. | |
| 12 | +org.gradle.jvmargs=-Xmx1536m | |
| 13 | + | |
| 14 | +# When configured, Gradle will run in incubating parallel mode. | |
| 15 | +# This option should only be used with decoupled projects. More details, visit | |
| 16 | +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects | |
| 17 | +# org.gradle.parallel=true | ... | ... |
gradle/wrapper/gradle-wrapper.jar
0 → 100644
No preview for this file type
gradle/wrapper/gradle-wrapper.properties
0 → 100644
| 1 | +++ a/gradle/wrapper/gradle-wrapper.properties | |
| 1 | +#Mon Dec 28 10:00:20 PST 2015 | |
| 2 | +distributionBase=GRADLE_USER_HOME | |
| 3 | +distributionPath=wrapper/dists | |
| 4 | +zipStoreBase=GRADLE_USER_HOME | |
| 5 | +zipStorePath=wrapper/dists | |
| 6 | +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip | ... | ... |
gradlew
0 → 100644
| 1 | +++ a/gradlew | |
| 1 | +#!/usr/bin/env bash | |
| 2 | + | |
| 3 | +############################################################################## | |
| 4 | +## | |
| 5 | +## Gradle start up script for UN*X | |
| 6 | +## | |
| 7 | +############################################################################## | |
| 8 | + | |
| 9 | +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |
| 10 | +DEFAULT_JVM_OPTS="" | |
| 11 | + | |
| 12 | +APP_NAME="Gradle" | |
| 13 | +APP_BASE_NAME=`basename "$0"` | |
| 14 | + | |
| 15 | +# Use the maximum available, or set MAX_FD != -1 to use that value. | |
| 16 | +MAX_FD="maximum" | |
| 17 | + | |
| 18 | +warn ( ) { | |
| 19 | + echo "$*" | |
| 20 | +} | |
| 21 | + | |
| 22 | +die ( ) { | |
| 23 | + echo | |
| 24 | + echo "$*" | |
| 25 | + echo | |
| 26 | + exit 1 | |
| 27 | +} | |
| 28 | + | |
| 29 | +# OS specific support (must be 'true' or 'false'). | |
| 30 | +cygwin=false | |
| 31 | +msys=false | |
| 32 | +darwin=false | |
| 33 | +case "`uname`" in | |
| 34 | + CYGWIN* ) | |
| 35 | + cygwin=true | |
| 36 | + ;; | |
| 37 | + Darwin* ) | |
| 38 | + darwin=true | |
| 39 | + ;; | |
| 40 | + MINGW* ) | |
| 41 | + msys=true | |
| 42 | + ;; | |
| 43 | +esac | |
| 44 | + | |
| 45 | +# Attempt to set APP_HOME | |
| 46 | +# Resolve links: $0 may be a link | |
| 47 | +PRG="$0" | |
| 48 | +# Need this for relative symlinks. | |
| 49 | +while [ -h "$PRG" ] ; do | |
| 50 | + ls=`ls -ld "$PRG"` | |
| 51 | + link=`expr "$ls" : '.*-> \(.*\)$'` | |
| 52 | + if expr "$link" : '/.*' > /dev/null; then | |
| 53 | + PRG="$link" | |
| 54 | + else | |
| 55 | + PRG=`dirname "$PRG"`"/$link" | |
| 56 | + fi | |
| 57 | +done | |
| 58 | +SAVED="`pwd`" | |
| 59 | +cd "`dirname \"$PRG\"`/" >/dev/null | |
| 60 | +APP_HOME="`pwd -P`" | |
| 61 | +cd "$SAVED" >/dev/null | |
| 62 | + | |
| 63 | +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | |
| 64 | + | |
| 65 | +# Determine the Java command to use to start the JVM. | |
| 66 | +if [ -n "$JAVA_HOME" ] ; then | |
| 67 | + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | |
| 68 | + # IBM's JDK on AIX uses strange locations for the executables | |
| 69 | + JAVACMD="$JAVA_HOME/jre/sh/java" | |
| 70 | + else | |
| 71 | + JAVACMD="$JAVA_HOME/bin/java" | |
| 72 | + fi | |
| 73 | + if [ ! -x "$JAVACMD" ] ; then | |
| 74 | + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | |
| 75 | + | |
| 76 | +Please set the JAVA_HOME variable in your environment to match the | |
| 77 | +location of your Java installation." | |
| 78 | + fi | |
| 79 | +else | |
| 80 | + JAVACMD="java" | |
| 81 | + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |
| 82 | + | |
| 83 | +Please set the JAVA_HOME variable in your environment to match the | |
| 84 | +location of your Java installation." | |
| 85 | +fi | |
| 86 | + | |
| 87 | +# Increase the maximum file descriptors if we can. | |
| 88 | +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then | |
| 89 | + MAX_FD_LIMIT=`ulimit -H -n` | |
| 90 | + if [ $? -eq 0 ] ; then | |
| 91 | + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | |
| 92 | + MAX_FD="$MAX_FD_LIMIT" | |
| 93 | + fi | |
| 94 | + ulimit -n $MAX_FD | |
| 95 | + if [ $? -ne 0 ] ; then | |
| 96 | + warn "Could not set maximum file descriptor limit: $MAX_FD" | |
| 97 | + fi | |
| 98 | + else | |
| 99 | + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | |
| 100 | + fi | |
| 101 | +fi | |
| 102 | + | |
| 103 | +# For Darwin, add options to specify how the application appears in the dock | |
| 104 | +if $darwin; then | |
| 105 | + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | |
| 106 | +fi | |
| 107 | + | |
| 108 | +# For Cygwin, switch paths to Windows format before running java | |
| 109 | +if $cygwin ; then | |
| 110 | + APP_HOME=`cygpath --path --mixed "$APP_HOME"` | |
| 111 | + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | |
| 112 | + JAVACMD=`cygpath --unix "$JAVACMD"` | |
| 113 | + | |
| 114 | + # We build the pattern for arguments to be converted via cygpath | |
| 115 | + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | |
| 116 | + SEP="" | |
| 117 | + for dir in $ROOTDIRSRAW ; do | |
| 118 | + ROOTDIRS="$ROOTDIRS$SEP$dir" | |
| 119 | + SEP="|" | |
| 120 | + done | |
| 121 | + OURCYGPATTERN="(^($ROOTDIRS))" | |
| 122 | + # Add a user-defined pattern to the cygpath arguments | |
| 123 | + if [ "$GRADLE_CYGPATTERN" != "" ] ; then | |
| 124 | + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | |
| 125 | + fi | |
| 126 | + # Now convert the arguments - kludge to limit ourselves to /bin/sh | |
| 127 | + i=0 | |
| 128 | + for arg in "$@" ; do | |
| 129 | + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | |
| 130 | + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option | |
| 131 | + | |
| 132 | + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition | |
| 133 | + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | |
| 134 | + else | |
| 135 | + eval `echo args$i`="\"$arg\"" | |
| 136 | + fi | |
| 137 | + i=$((i+1)) | |
| 138 | + done | |
| 139 | + case $i in | |
| 140 | + (0) set -- ;; | |
| 141 | + (1) set -- "$args0" ;; | |
| 142 | + (2) set -- "$args0" "$args1" ;; | |
| 143 | + (3) set -- "$args0" "$args1" "$args2" ;; | |
| 144 | + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; | |
| 145 | + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | |
| 146 | + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | |
| 147 | + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | |
| 148 | + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | |
| 149 | + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | |
| 150 | + esac | |
| 151 | +fi | |
| 152 | + | |
| 153 | +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules | |
| 154 | +function splitJvmOpts() { | |
| 155 | + JVM_OPTS=("$@") | |
| 156 | +} | |
| 157 | +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS | |
| 158 | +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" | |
| 159 | + | |
| 160 | +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" | ... | ... |
gradlew.bat
0 → 100644
| 1 | +++ a/gradlew.bat | |
| 1 | +@if "%DEBUG%" == "" @echo off | |
| 2 | +@rem ########################################################################## | |
| 3 | +@rem | |
| 4 | +@rem Gradle startup script for Windows | |
| 5 | +@rem | |
| 6 | +@rem ########################################################################## | |
| 7 | + | |
| 8 | +@rem Set local scope for the variables with windows NT shell | |
| 9 | +if "%OS%"=="Windows_NT" setlocal | |
| 10 | + | |
| 11 | +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |
| 12 | +set DEFAULT_JVM_OPTS= | |
| 13 | + | |
| 14 | +set DIRNAME=%~dp0 | |
| 15 | +if "%DIRNAME%" == "" set DIRNAME=. | |
| 16 | +set APP_BASE_NAME=%~n0 | |
| 17 | +set APP_HOME=%DIRNAME% | |
| 18 | + | |
| 19 | +@rem Find java.exe | |
| 20 | +if defined JAVA_HOME goto findJavaFromJavaHome | |
| 21 | + | |
| 22 | +set JAVA_EXE=java.exe | |
| 23 | +%JAVA_EXE% -version >NUL 2>&1 | |
| 24 | +if "%ERRORLEVEL%" == "0" goto init | |
| 25 | + | |
| 26 | +echo. | |
| 27 | +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |
| 28 | +echo. | |
| 29 | +echo Please set the JAVA_HOME variable in your environment to match the | |
| 30 | +echo location of your Java installation. | |
| 31 | + | |
| 32 | +goto fail | |
| 33 | + | |
| 34 | +:findJavaFromJavaHome | |
| 35 | +set JAVA_HOME=%JAVA_HOME:"=% | |
| 36 | +set JAVA_EXE=%JAVA_HOME%/bin/java.exe | |
| 37 | + | |
| 38 | +if exist "%JAVA_EXE%" goto init | |
| 39 | + | |
| 40 | +echo. | |
| 41 | +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | |
| 42 | +echo. | |
| 43 | +echo Please set the JAVA_HOME variable in your environment to match the | |
| 44 | +echo location of your Java installation. | |
| 45 | + | |
| 46 | +goto fail | |
| 47 | + | |
| 48 | +:init | |
| 49 | +@rem Get command-line arguments, handling Windowz variants | |
| 50 | + | |
| 51 | +if not "%OS%" == "Windows_NT" goto win9xME_args | |
| 52 | +if "%@eval[2+2]" == "4" goto 4NT_args | |
| 53 | + | |
| 54 | +:win9xME_args | |
| 55 | +@rem Slurp the command line arguments. | |
| 56 | +set CMD_LINE_ARGS= | |
| 57 | +set _SKIP=2 | |
| 58 | + | |
| 59 | +:win9xME_args_slurp | |
| 60 | +if "x%~1" == "x" goto execute | |
| 61 | + | |
| 62 | +set CMD_LINE_ARGS=%* | |
| 63 | +goto execute | |
| 64 | + | |
| 65 | +:4NT_args | |
| 66 | +@rem Get arguments from the 4NT Shell from JP Software | |
| 67 | +set CMD_LINE_ARGS=%$ | |
| 68 | + | |
| 69 | +:execute | |
| 70 | +@rem Setup the command line | |
| 71 | + | |
| 72 | +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | |
| 73 | + | |
| 74 | +@rem Execute Gradle | |
| 75 | +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | |
| 76 | + | |
| 77 | +:end | |
| 78 | +@rem End local scope for the variables with windows NT shell | |
| 79 | +if "%ERRORLEVEL%"=="0" goto mainEnd | |
| 80 | + | |
| 81 | +:fail | |
| 82 | +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | |
| 83 | +rem the _cmd.exe /c_ return code! | |
| 84 | +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | |
| 85 | +exit /b 1 | |
| 86 | + | |
| 87 | +:mainEnd | |
| 88 | +if "%OS%"=="Windows_NT" endlocal | |
| 89 | + | |
| 90 | +:omega | ... | ... |
settings.gradle
0 → 100644