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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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
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