Commit f97881e6a78a1a8f75f097a3f2836732a4a6b713

Authored by 王琳
1 parent c39ca37a

更新推流SDK, 添加悬浮窗预览、截屏、背景图推流、音频滤镜、滤镜等功能

Showing 104 changed files with 1609 additions and 124 deletions
app/build.gradle
@@ -43,7 +43,11 @@ repositories { @@ -43,7 +43,11 @@ repositories {
43 43
44 dependencies { 44 dependencies {
45 compile fileTree(include: ['*.jar'], dir: 'libs') 45 compile fileTree(include: ['*.jar'], dir: 'libs')
  46 + compile 'com.cnlive:lib_cnlive:2.1.0'
46 compile 'com.android.support:appcompat-v7:25.2.0' 47 compile 'com.android.support:appcompat-v7:25.2.0'
47 compile 'com.android.support.constraint:constraint-layout:1.0.1' 48 compile 'com.android.support.constraint:constraint-layout:1.0.1'
48 - compile 'com.cnlive:lib_cnlive:2.0.0' 49 +
  50 + compile 'com.facebook.fresco:fresco:1.4.0'
  51 + compile 'com.facebook.fresco:animated-gif:1.4.0'
  52 + compile 'com.facebook.fresco:animated-webp:1.4.0'
49 } 53 }
app/src/main/AndroidManifest.xml
@@ -35,7 +35,8 @@ @@ -35,7 +35,8 @@
35 android:name=".StreamActivity" 35 android:name=".StreamActivity"
36 android:configChanges="orientation|keyboardHidden|screenSize" 36 android:configChanges="orientation|keyboardHidden|screenSize"
37 android:launchMode="singleTop" 37 android:launchMode="singleTop"
38 - android:screenOrientation="portrait" /> 38 + android:screenOrientation="portrait"
  39 + android:theme="@style/Theme.RiseAnimation" />
39 <activity 40 <activity
40 android:name=".CNStreamActivity" 41 android:name=".CNStreamActivity"
41 android:configChanges="orientation|keyboardHidden|screenSize" 42 android:configChanges="orientation|keyboardHidden|screenSize"
@@ -46,6 +47,11 @@ @@ -46,6 +47,11 @@
46 android:configChanges="orientation|keyboardHidden|screenSize" 47 android:configChanges="orientation|keyboardHidden|screenSize"
47 android:launchMode="singleTop" 48 android:launchMode="singleTop"
48 android:screenOrientation="portrait" /> 49 android:screenOrientation="portrait" />
  50 + <activity
  51 + android:name=".FloatActivity"
  52 + android:configChanges="orientation|keyboardHidden|screenSize"
  53 + android:launchMode="singleTop"
  54 + android:theme="@style/Theme.RiseAnimation"></activity>
49 </application> 55 </application>
50 56
51 </manifest> 57 </manifest>
52 \ No newline at end of file 58 \ No newline at end of file
app/src/main/assets/KSYResource/0_pink.png 0 → 100644

158 KB

app/src/main/assets/KSYResource/0_ruddy2.png 0 → 100644

131 KB

app/src/main/assets/KSYResource/10_sunshine_night.png 0 → 100644

197 KB

app/src/main/assets/KSYResource/11_ruddy.png 0 → 100644

132 KB

app/src/main/assets/KSYResource/12_sunshine.png 0 → 100644

204 KB

app/src/main/assets/KSYResource/13_nature.png 0 → 100644

771 KB

app/src/main/assets/KSYResource/14_amatorka.png 0 → 100644

35.5 KB

app/src/main/assets/KSYResource/15_elegance_1.png 0 → 100644

126 KB

app/src/main/assets/KSYResource/1_freshy.png 0 → 100644

196 KB

app/src/main/assets/KSYResource/2_beauty.png 0 → 100644

64.4 KB

app/src/main/assets/KSYResource/3_sweety.png 0 → 100644

50.3 KB

app/src/main/assets/KSYResource/4_sepia.png 0 → 100644

35.5 KB

app/src/main/assets/KSYResource/5_blue.png 0 → 100644

198 KB

app/src/main/assets/KSYResource/6_nostalgia.png 0 → 100644

136 KB

app/src/main/assets/KSYResource/7_sakura.png 0 → 100644

241 KB

app/src/main/assets/KSYResource/8_sakura_night.png 0 → 100644

226 KB

app/src/main/assets/KSYResource/9_ruddy_night.png 0 → 100644

125 KB

app/src/main/assets/KSYResource/amaro_map.png 0 → 100644

2.95 KB

app/src/main/assets/KSYResource/blackboard_1024.png 0 → 100644

103 KB

app/src/main/assets/KSYResource/blowout_1977.png 0 → 100644

6.62 KB

app/src/main/assets/KSYResource/brannan_blowout.png 0 → 100644

174 Bytes

app/src/main/assets/KSYResource/brannan_contrast.png 0 → 100644

199 Bytes

app/src/main/assets/KSYResource/brannan_luma.png 0 → 100644

229 Bytes

app/src/main/assets/KSYResource/brannan_process.png 0 → 100644

285 Bytes

app/src/main/assets/KSYResource/brannan_screen.png 0 → 100644

217 Bytes

app/src/main/assets/KSYResource/early_bird_curves.png 0 → 100644

156 Bytes

app/src/main/assets/KSYResource/earlybird_blowout.png 0 → 100644

159 Bytes

app/src/main/assets/KSYResource/earlybird_map.png 0 → 100644

208 Bytes

app/src/main/assets/KSYResource/earlybird_overlay_map.png 0 → 100644

187 Bytes

app/src/main/assets/KSYResource/edge_burn.png 0 → 100644

30.5 KB

app/src/main/assets/KSYResource/hefe_gradient_map.png 0 → 100644

2.85 KB

app/src/main/assets/KSYResource/hefe_map.png 0 → 100644

2.93 KB

app/src/main/assets/KSYResource/hefe_metal.png 0 → 100644

109 KB

app/src/main/assets/KSYResource/hefe_soft_light.png 0 → 100644

5.63 KB

app/src/main/assets/KSYResource/hudson_background.png 0 → 100644

85.1 KB

app/src/main/assets/KSYResource/hudson_map.png 0 → 100644

2.82 KB

app/src/main/assets/KSYResource/inkwell_map.png 0 → 100644

2.8 KB

app/src/main/assets/KSYResource/kelvin_map.png 0 → 100644

2.94 KB

app/src/main/assets/KSYResource/lomo_map.png 0 → 100644

2.83 KB

app/src/main/assets/KSYResource/map_1977.png 0 → 100644

279 Bytes

app/src/main/assets/KSYResource/nashville_map.png 0 → 100644

2.95 KB

app/src/main/assets/KSYResource/nashwi.png 0 → 100644

2.95 KB

app/src/main/assets/KSYResource/overlay_map.png 0 → 100644

6.3 KB

app/src/main/assets/KSYResource/rise_map.png 0 → 100644

2.98 KB

app/src/main/assets/KSYResource/sierra_map.png 0 → 100644

237 Bytes

app/src/main/assets/KSYResource/sierra_vignette.png 0 → 100644

69.9 KB

app/src/main/assets/KSYResource/soft_light.png 0 → 100644

5.69 KB

app/src/main/assets/KSYResource/sutro_curves.png 0 → 100644

2.84 KB

app/src/main/assets/KSYResource/sutro_edge_burn.png 0 → 100644

91.8 KB

app/src/main/assets/KSYResource/sutro_metal.png 0 → 100644

89.4 KB

app/src/main/assets/KSYResource/toaster_color_shift.png 0 → 100644

322 Bytes

app/src/main/assets/KSYResource/toaster_curves.png 0 → 100644

297 Bytes

app/src/main/assets/KSYResource/toaster_metal.png 0 → 100644

104 KB

app/src/main/assets/KSYResource/toaster_overlay_map_warm.png 0 → 100644

22.5 KB

app/src/main/assets/KSYResource/toaster_soft_light.png 0 → 100644

4.24 KB

app/src/main/assets/KSYResource/valencia_gradient_map.png 0 → 100644

12.4 KB

app/src/main/assets/KSYResource/valencia_map.png 0 → 100644

2.91 KB

app/src/main/assets/KSYResource/vignette_map.png 0 → 100644

7.51 KB

app/src/main/assets/KSYResource/walden_map.png 0 → 100644

3 KB

app/src/main/assets/KSYResource/xpro_map.png 0 → 100644

236 Bytes

app/src/main/assets/bg.jpg 0 → 100644

126 KB

app/src/main/assets/cnlive_logo.gif 0 → 100644

111 KB

app/src/main/java/com/cnlive/demo/stream/AnimatedImageCapture.java 0 → 100644
  1 +package com.cnlive.demo.stream;
  2 +
  3 +import android.content.Context;
  4 +import android.graphics.Bitmap;
  5 +import android.graphics.Canvas;
  6 +import android.graphics.Color;
  7 +import android.graphics.Rect;
  8 +import android.net.Uri;
  9 +import android.util.Log;
  10 +
  11 +import com.cnlive.libs.stream.Streamer;
  12 +import com.cnlive.libs.stream.capture.CNImgTexSrcPin;
  13 +import com.facebook.common.executors.CallerThreadExecutor;
  14 +import com.facebook.common.references.CloseableReference;
  15 +import com.facebook.datasource.BaseDataSubscriber;
  16 +import com.facebook.datasource.DataSource;
  17 +import com.facebook.datasource.DataSubscriber;
  18 +import com.facebook.drawee.backends.pipeline.Fresco;
  19 +import com.facebook.imagepipeline.animated.base.AnimatedDrawableFrameInfo;
  20 +import com.facebook.imagepipeline.animated.base.AnimatedImage;
  21 +import com.facebook.imagepipeline.animated.base.AnimatedImageFrame;
  22 +import com.facebook.imagepipeline.core.ImagePipeline;
  23 +import com.facebook.imagepipeline.image.CloseableAnimatedImage;
  24 +import com.facebook.imagepipeline.image.CloseableBitmap;
  25 +import com.facebook.imagepipeline.image.CloseableImage;
  26 +import com.facebook.imagepipeline.request.ImageRequest;
  27 +import com.facebook.imagepipeline.request.ImageRequestBuilder;
  28 +
  29 +import java.util.Date;
  30 +import java.util.Timer;
  31 +import java.util.TimerTask;
  32 +import java.util.stream.Stream;
  33 +
  34 +/**
  35 + * Created by Lynn on 2017/9/19.
  36 + */
  37 +
  38 +public class AnimatedImageCapture {
  39 + private static final String TAG = "AnimatedImageCapture";
  40 + private static final boolean VERBOSE = false;
  41 +
  42 + private int mIndex;
  43 + private Date mLastDate;
  44 + private int mRepeatCount; // TODO: handle gif/webp repeat count
  45 + private Bitmap mBitmap;
  46 + private Canvas mCanvas;
  47 + private Bitmap mTempBitmap;
  48 + private Timer mTimer;
  49 + private CloseableReference<? extends CloseableImage> mCloseableReference;
  50 +
  51 + private Streamer mStreamer;
  52 +
  53 + private CNImgTexSrcPin cnImgTexSrcPin;
  54 + private Context context;
  55 +
  56 + public AnimatedImageCapture(Context context, Streamer streamer) {
  57 + this.context = context;
  58 + this.mStreamer = streamer;
  59 + cnImgTexSrcPin = new CNImgTexSrcPin(streamer.getGLRender());
  60 + }
  61 +
  62 + public void showAnimatedWaterMard(String url, float x, float y, float w, float h, float a) {
  63 + cnImgTexSrcPin.connect(mStreamer.getImgTexPreviewMixer().getSinkPin(3));
  64 + cnImgTexSrcPin.connect(mStreamer.getImgTexMixer().getSinkPin(3));
  65 + mStreamer.getImgTexPreviewMixer().setRenderRect(3, x, y, w, h, a);
  66 + mStreamer.getImgTexMixer().setRenderRect(3, x, y, w, h, a);
  67 + start(context, url);
  68 + }
  69 +
  70 + public void hideAnimatedWaterMark() {
  71 + stop();
  72 + cnImgTexSrcPin.disconnect(false);
  73 + }
  74 +
  75 + public void start(Context context, String url) {
  76 + if (url == null) {
  77 + return;
  78 + }
  79 +
  80 + Uri uri = Uri.parse(assets2Asset(url));
  81 + ImagePipeline imagePipeline = Fresco.getImagePipeline();
  82 + ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri).build();
  83 + DataSource<CloseableReference<CloseableImage>> dataSource =
  84 + imagePipeline.fetchDecodedImage(request, context);
  85 + dataSource.subscribe(mDataSubscriber, CallerThreadExecutor.getInstance());
  86 + }
  87 +
  88 + private String assets2Asset(String url) {
  89 + if (url.startsWith("assets://")) {
  90 + url = url.replaceFirst("assets://", "asset:///");
  91 + }
  92 + return url;
  93 + }
  94 +
  95 + public void stop() {
  96 + if (mTimer != null) {
  97 + mTimer.cancel();
  98 + mTimer = null;
  99 + }
  100 + if (mCloseableReference != null) {
  101 + CloseableReference.closeSafely(mCloseableReference);
  102 + mCloseableReference = null;
  103 + }
  104 + cnImgTexSrcPin.updateFrame(null, false);
  105 + }
  106 +
  107 + private void updateFrame() {
  108 + if (mCloseableReference == null) {
  109 + return;
  110 + }
  111 + try {
  112 + CloseableImage closeableImage = mCloseableReference.get();
  113 + if (closeableImage instanceof CloseableBitmap) {
  114 + Bitmap bitmap = ((CloseableBitmap) closeableImage).getUnderlyingBitmap();
  115 + if (bitmap != null && !bitmap.isRecycled()) {
  116 + mBitmap = Bitmap.createBitmap(bitmap);
  117 + cnImgTexSrcPin.updateFrame(mBitmap, false);
  118 + }
  119 + return;
  120 + }
  121 +
  122 + if (!(closeableImage instanceof CloseableAnimatedImage)) {
  123 + return;
  124 + }
  125 + AnimatedImage animatedImage = ((CloseableAnimatedImage) closeableImage).getImage();
  126 + int w = animatedImage.getWidth();
  127 + int h = animatedImage.getHeight();
  128 + if (mBitmap == null || mBitmap.isRecycled()) {
  129 + Log.d(TAG, "Got animated image " + w + "x" + h);
  130 + mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  131 + mTempBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  132 + mCanvas = new Canvas(mBitmap);
  133 + }
  134 + if (mIndex >= animatedImage.getFrameCount()) {
  135 + mRepeatCount++;
  136 + mIndex = 0;
  137 + int loopCount = animatedImage.getLoopCount();
  138 + if (loopCount > 0 && mRepeatCount >= loopCount) {
  139 + Log.d(TAG, "repeat ended, repeat times: " + mRepeatCount);
  140 + return;
  141 + }
  142 + }
  143 +
  144 + AnimatedImageFrame imageFrame = animatedImage.getFrame(mIndex);
  145 + int duration = imageFrame.getDurationMs();
  146 + AnimatedDrawableFrameInfo frameInfo = animatedImage.getFrameInfo(mIndex);
  147 + imageFrame.renderFrame(frameInfo.width, frameInfo.height, mTempBitmap);
  148 + if (VERBOSE) {
  149 + Log.d(TAG, "blend: " + frameInfo.blendOperation.name() +
  150 + " dispose: " + frameInfo.disposalMethod.name() +
  151 + " x=" + frameInfo.xOffset + " y=" + frameInfo.yOffset +
  152 + " " + frameInfo.width + "x" + frameInfo.height);
  153 + }
  154 + if (frameInfo.blendOperation == AnimatedDrawableFrameInfo.BlendOperation.NO_BLEND) {
  155 + mBitmap.eraseColor(Color.TRANSPARENT);
  156 + }
  157 + Rect srcRect = new Rect(0, 0, frameInfo.width, frameInfo.height);
  158 + Rect dstRect = new Rect(frameInfo.xOffset, frameInfo.yOffset,
  159 + frameInfo.xOffset + frameInfo.width, frameInfo.yOffset + frameInfo.height);
  160 + mCanvas.drawBitmap(mTempBitmap, srcRect, dstRect, null);
  161 + if (VERBOSE) {
  162 + Log.d(TAG, "frame " + mIndex + " got, duration=" + duration);
  163 + }
  164 + cnImgTexSrcPin.updateFrame(mBitmap, false);
  165 + imageFrame.dispose();
  166 +
  167 + mIndex++;
  168 + if (mLastDate == null) {
  169 + mLastDate = new Date();
  170 + }
  171 + mLastDate = new Date(mLastDate.getTime() + duration);
  172 + mTimer.schedule(new TimerTask() {
  173 + @Override
  174 + public void run() {
  175 + updateFrame();
  176 + }
  177 + }, mLastDate);
  178 + } catch (Exception e) {
  179 + e.printStackTrace();
  180 + }
  181 + }
  182 +
  183 + private DataSubscriber mDataSubscriber =
  184 + new BaseDataSubscriber<CloseableReference<? extends CloseableImage>>() {
  185 +
  186 + @Override
  187 + public void onNewResultImpl(
  188 + DataSource<CloseableReference<? extends CloseableImage>> dataSource) {
  189 + if (!dataSource.isFinished()) {
  190 + return;
  191 + }
  192 +
  193 + // get ref
  194 + mCloseableReference = dataSource.getResult();
  195 +
  196 + // reset
  197 + mIndex = 0;
  198 + mRepeatCount = 0;
  199 + mLastDate = null;
  200 + mBitmap = null;
  201 + mTempBitmap = null;
  202 + mCanvas = null;
  203 +
  204 + // create timer
  205 + mTimer = new Timer("AnimatedImage");
  206 + mTimer.schedule(new TimerTask() {
  207 + @Override
  208 + public void run() {
  209 + updateFrame();
  210 + }
  211 + }, 0);
  212 + }
  213 +
  214 + @Override
  215 + public void onFailureImpl(DataSource dataSource) {
  216 + Throwable throwable = dataSource.getFailureCause();
  217 + // handle failure
  218 + if (throwable != null) {
  219 + throwable.printStackTrace();
  220 + }
  221 + }
  222 + };
  223 +}
app/src/main/java/com/cnlive/demo/stream/AudioActivity.java
@@ -15,9 +15,15 @@ import android.widget.Toast; @@ -15,9 +15,15 @@ import android.widget.Toast;
15 15
16 import com.cnlive.libs.stream.Streamer; 16 import com.cnlive.libs.stream.Streamer;
17 import com.cnlive.libs.stream.base.IStreamer; 17 import com.cnlive.libs.stream.base.IStreamer;
  18 +import com.cnlive.libs.stream.filter.CNAudioFilterBase;
  19 +import com.cnlive.libs.stream.filter.CNAudioReverbFilter;
18 import com.cnlive.libs.stream.model.ActivityConfig; 20 import com.cnlive.libs.stream.model.ActivityConfig;
19 21
20 22
  23 +import java.util.LinkedList;
  24 +import java.util.List;
  25 +
  26 +import static com.cnlive.libs.stream.base.IStreamer.AUDIO_REVERB_LEVEL_1;
21 import static com.cnlive.libs.stream.base.IStreamer.ENCODE_METHOD_HARDWARE; 27 import static com.cnlive.libs.stream.base.IStreamer.ENCODE_METHOD_HARDWARE;
22 import static com.cnlive.libs.stream.base.IStreamer.ENCODE_METHOD_SOFTWARE_COMPAT; 28 import static com.cnlive.libs.stream.base.IStreamer.ENCODE_METHOD_SOFTWARE_COMPAT;
23 import static com.cnlive.libs.stream.base.IStreamer.VIDEO_RESOLUTION_360P; 29 import static com.cnlive.libs.stream.base.IStreamer.VIDEO_RESOLUTION_360P;
@@ -434,18 +440,30 @@ public class AudioActivity extends AppCompatActivity implements View.OnClickList @@ -434,18 +440,30 @@ public class AudioActivity extends AppCompatActivity implements View.OnClickList
434 }).setPositiveButton("确定", new DialogInterface.OnClickListener() { 440 }).setPositiveButton("确定", new DialogInterface.OnClickListener() {
435 @Override 441 @Override
436 public void onClick(DialogInterface dialogInterface, int which) { 442 public void onClick(DialogInterface dialogInterface, int which) {
  443 + List<CNAudioFilterBase> filterBases = new LinkedList<CNAudioFilterBase>();
437 switch (which) { 444 switch (which) {
438 case 0: 445 case 0:
439 - mStreamer.setAudioFilter(IStreamer.AUDIO_REVERB_LEVEL_1); 446 + CNAudioReverbFilter reverbFilter = new CNAudioReverbFilter();
  447 + reverbFilter.setReverbLevel(IStreamer.AUDIO_REVERB_LEVEL_1);
  448 + filterBases.add(reverbFilter);
440 break; 449 break;
441 case 1: 450 case 1:
442 - mStreamer.setAudioFilter(IStreamer.AUDIO_REVERB_LEVEL_2); 451 + CNAudioReverbFilter reverbFilter1 = new CNAudioReverbFilter();
  452 + reverbFilter1.setReverbLevel(IStreamer.AUDIO_REVERB_LEVEL_2);
  453 + filterBases.add(reverbFilter1);
443 break; 454 break;
444 case 2: 455 case 2:
445 - mStreamer.setAudioFilter(IStreamer.AUDIO_REVERB_LEVEL_3); 456 + CNAudioReverbFilter reverbFilter2 = new CNAudioReverbFilter();
  457 + reverbFilter2.setReverbLevel(IStreamer.AUDIO_REVERB_LEVEL_3);
  458 + filterBases.add(reverbFilter2);
446 break; 459 break;
447 case 3: 460 case 3:
448 - mStreamer.setAudioFilter(IStreamer.AUDIO_REVERB_LEVEL_4); 461 + CNAudioReverbFilter reverbFilter3 = new CNAudioReverbFilter();
  462 + reverbFilter3.setReverbLevel(IStreamer.AUDIO_REVERB_LEVEL_4);
  463 + filterBases.add(reverbFilter3);
  464 + break;
  465 + default:
  466 + mStreamer.getAudioFilterMgt().setFilter(filterBases);
449 break; 467 break;
450 } 468 }
451 } 469 }
app/src/main/java/com/cnlive/demo/stream/CNGlobalStreamer.java 0 → 100644
  1 +package com.cnlive.demo.stream;
  2 +
  3 +import android.annotation.SuppressLint;
  4 +
  5 +import com.cnlive.libs.stream.Streamer;
  6 +
  7 +/**
  8 + * Created by Lynn on 2017/9/19.
  9 + */
  10 +
  11 +public class CNGlobalStreamer {
  12 +
  13 + @SuppressLint("StaticFieldLeak")
  14 + private static Streamer sStreamer;
  15 +
  16 + private CNGlobalStreamer() {
  17 +
  18 + }
  19 +
  20 + public static void setInstance(Streamer streamer) {
  21 + sStreamer = streamer;
  22 + }
  23 +
  24 + public static Streamer getInstance() {
  25 + return sStreamer;
  26 + }
  27 +}
app/src/main/java/com/cnlive/demo/stream/CNStreamApplication.java
@@ -3,6 +3,7 @@ package com.cnlive.demo.stream; @@ -3,6 +3,7 @@ package com.cnlive.demo.stream;
3 import android.app.Application; 3 import android.app.Application;
4 4
5 import com.cnlive.libs.util.Config; 5 import com.cnlive.libs.util.Config;
  6 +import com.facebook.drawee.backends.pipeline.Fresco;
6 7
7 /** 8 /**
8 * Created by xiansong on 2016/7/22. 9 * Created by xiansong on 2016/7/22.
@@ -14,5 +15,8 @@ public class CNStreamApplication extends Application { @@ -14,5 +15,8 @@ public class CNStreamApplication extends Application {
14 super.onCreate(); 15 super.onCreate();
15 16
16 Config.init(this, "60_irn9gh9d49", "f7b6db55616d207fd5c07e2b580b5650c690aff58fb36d",true); 17 Config.init(this, "60_irn9gh9d49", "f7b6db55616d207fd5c07e2b580b5650c690aff58fb36d",true);
  18 +
  19 + // 初始化fresco库,用来支持动态水印功能
  20 + Fresco.initialize(this);
17 } 21 }
18 } 22 }
app/src/main/java/com/cnlive/demo/stream/FloatActivity.java 0 → 100644
  1 +package com.cnlive.demo.stream;
  2 +
  3 +import android.app.Activity;
  4 +import android.app.Application;
  5 +import android.content.Intent;
  6 +import android.graphics.Color;
  7 +import android.graphics.PixelFormat;
  8 +import android.hardware.SensorManager;
  9 +import android.net.Uri;
  10 +import android.opengl.GLSurfaceView;
  11 +import android.os.Build;
  12 +import android.provider.Settings;
  13 +import android.support.annotation.Nullable;
  14 +import android.support.v7.app.AppCompatActivity;
  15 +import android.os.Bundle;
  16 +import android.util.Log;
  17 +import android.view.Gravity;
  18 +import android.view.KeyEvent;
  19 +import android.view.LayoutInflater;
  20 +import android.view.OrientationEventListener;
  21 +import android.view.Surface;
  22 +import android.view.View;
  23 +import android.view.Window;
  24 +import android.view.WindowManager;
  25 +import android.widget.ImageView;
  26 +import android.widget.RelativeLayout;
  27 +import android.widget.Toast;
  28 +
  29 +import com.cnlive.libs.stream.Streamer;
  30 +
  31 +public class FloatActivity extends Activity {
  32 +
  33 + private static final String TAG = "FloatViewActivity";
  34 +
  35 + private final static int OVERLAY_PERMISSION_RESULT_CODE = 10;
  36 +
  37 + private GLSurfaceView mCameraView;
  38 + private int mLastRotation;
  39 + private OrientationEventListener mOrientationEventListener;
  40 +
  41 + //preview window just demo
  42 + private FloatView mFloatLayout; //悬浮窗口的layout, 可以是xml,也可以在代码中创建
  43 + private ImageView mFloatClose; //关闭悬浮窗口
  44 + private ImageView mFloatBack; //跳转到上一个页面,不停止推流
  45 + private WindowManager.LayoutParams mWmParams; //layout的布局
  46 + private WindowManager mWindowManager;
  47 + private volatile boolean mPreviewWindowShow = false; //悬浮摄像头预览window是否正在显示
  48 +
  49 + //ButtonListener
  50 + private ButtonObserver mObserverButton; //所有按键响应
  51 +
  52 + // logo path
  53 + private String mLogoPath = "file:///sdcard/test.png";
  54 +
  55 + @Override
  56 + protected void onCreate(@Nullable Bundle savedInstanceState) {
  57 + Log.d(TAG, "onCreate");
  58 + super.onCreate(savedInstanceState);
  59 + requestWindowFeature(Window.FEATURE_NO_TITLE);
  60 + setContentView(R.layout.activity_float);
  61 + mObserverButton = new ButtonObserver();
  62 + mLastRotation = getDisplayRotation();
  63 + mFloatBack = (ImageView) findViewById(R.id.float_back);
  64 + mFloatBack.setOnClickListener(mObserverButton);
  65 +
  66 + mOrientationEventListener = new OrientationEventListener(this,
  67 + SensorManager.SENSOR_DELAY_NORMAL) {
  68 + @Override
  69 + public void onOrientationChanged(int orientation) {
  70 + int rotation = getDisplayRotation();
  71 + if (rotation != mLastRotation) {
  72 + Log.d(TAG, "Rotation changed " + mLastRotation + "->" + rotation);
  73 + onSwitchRotate();
  74 + mLastRotation = rotation;
  75 + }
  76 + }
  77 + };
  78 + if (mOrientationEventListener.canDetectOrientation()) {
  79 + mOrientationEventListener.enable();
  80 + }
  81 +
  82 + addFloatViewWithPermCheck();
  83 + }
  84 +
  85 + @Override
  86 + protected void onResume() {
  87 + Log.d(TAG, "onResume");
  88 + super.onResume();
  89 + }
  90 +
  91 + @Override
  92 + protected void onPause() {
  93 + Log.d(TAG, "onPause");
  94 + super.onPause();
  95 + }
  96 +
  97 + @Override
  98 + protected void onDestroy() {
  99 + Log.d(TAG, "onDestroy");
  100 + super.onDestroy();
  101 + if (mOrientationEventListener != null) {
  102 + mOrientationEventListener.disable();
  103 + }
  104 + removeSurfaceWindow();
  105 + CNGlobalStreamer.setInstance(null);
  106 + }
  107 +
  108 + @Override
  109 + public boolean onKeyDown(int keyCode, KeyEvent event) {
  110 + switch (keyCode) {
  111 + case KeyEvent.KEYCODE_BACK:
  112 + onBackoffClick();
  113 + return true;
  114 + default:
  115 + break;
  116 + }
  117 + return super.onKeyDown(keyCode, event);
  118 + }
  119 +
  120 + private void onBackoffClick() {
  121 + CNGlobalStreamer.getInstance().pause();
  122 + CNGlobalStreamer.getInstance().setDisplayPreview((GLSurfaceView) null);
  123 + FloatActivity.this.finish();
  124 + }
  125 +
  126 + /**
  127 + * 初始化悬浮窗口示例
  128 + */
  129 + private void initSurfaceWindow() {
  130 + if (mWindowManager == null) {
  131 + mWmParams = new WindowManager.LayoutParams();
  132 + mWindowManager = (WindowManager) getApplication().
  133 + getSystemService(Application.WINDOW_SERVICE);
  134 +
  135 + //设置window type
  136 + mWmParams.type = WindowManager.LayoutParams.TYPE_TOAST;
  137 +
  138 + //设置图片格式,效果为背景透明
  139 + mWmParams.format = PixelFormat.RGBA_8888;
  140 +
  141 + //设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作)
  142 + mWmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
  143 + //开启硬件加速,以支持TextureView
  144 + mWmParams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
  145 + //接收touch事件
  146 + mWmParams.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
  147 + //排版不受限制
  148 + mWmParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
  149 + //调整悬浮窗显示的停靠位置为右侧底部
  150 + mWmParams.gravity = Gravity.RIGHT | Gravity.BOTTOM;
  151 +
  152 + // 以屏幕左上角为原点,设置x、y初始值,相对于gravity
  153 + mWmParams.x = 0;
  154 + mWmParams.y = 0;
  155 +
  156 + //设置悬浮窗口长宽数据(这里取屏幕长宽的等比率缩小值作为悬浮窗口的长宽)
  157 + int screenWidth = mWindowManager.getDefaultDisplay().getWidth();
  158 + int screenHeight = mWindowManager.getDefaultDisplay().getHeight();
  159 + int width;
  160 + int height;
  161 +
  162 + boolean isLandscape = (getDisplayRotation() % 180) != 0;
  163 + if ((isLandscape && screenWidth < screenHeight) ||
  164 + (!isLandscape) && screenWidth > screenHeight) {
  165 + screenWidth = mWindowManager.getDefaultDisplay().getHeight();
  166 + screenHeight = mWindowManager.getDefaultDisplay().getWidth();
  167 + }
  168 +
  169 + if (screenWidth < screenHeight) {
  170 + width = align(screenWidth / 3, 8);
  171 + height = align(screenHeight / 3, 8);
  172 + } else {
  173 + width = align(screenWidth / 3, 8);
  174 + height = align(screenHeight / 3, 8);
  175 + }
  176 + mWmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
  177 + mWmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
  178 +
  179 + LayoutInflater inflater = LayoutInflater.from(getApplication());
  180 +
  181 + //获取浮动窗口视图所在布局
  182 + mFloatLayout = (FloatView) inflater.inflate(R.layout.float_preview, null);
  183 +
  184 + mFloatClose = new ImageView(this);
  185 + mFloatClose.setImageResource(R.drawable.float_close);
  186 + mFloatClose.setOnClickListener(new View.OnClickListener() {
  187 + @Override
  188 + public void onClick(View v) {
  189 + onBackoffClick();
  190 + }
  191 + });
  192 +
  193 + mCameraView = new GLSurfaceView(this);
  194 + CNGlobalStreamer.getInstance().setDisplayPreview(mCameraView);
  195 + RelativeLayout.LayoutParams previewLayoutParams =
  196 + new RelativeLayout.LayoutParams(width, height);
  197 + mFloatLayout.addView(mCameraView, previewLayoutParams);
  198 + RelativeLayout.LayoutParams closeParams =
  199 + new RelativeLayout.LayoutParams(50, 50);
  200 + closeParams.setMargins(10,10,0,0);
  201 + mFloatLayout.addView(mFloatClose, closeParams);
  202 +
  203 + mFloatLayout.setWmParams(mWmParams);
  204 + }
  205 + }
  206 +
  207 + private class ButtonObserver implements View.OnClickListener {
  208 + @Override
  209 + public void onClick(View view) {
  210 + switch (view.getId()) {
  211 + case R.id.float_back:
  212 + onBackoffClick();
  213 + break;
  214 + default:
  215 + break;
  216 + }
  217 + }
  218 + }
  219 +
  220 + private void addSurfaceWindow() {
  221 + if (mWindowManager != null) {
  222 + //添加mFloatLayout
  223 + mWindowManager.addView(mFloatLayout, mWmParams);
  224 + }
  225 + mPreviewWindowShow = true;
  226 + }
  227 +
  228 + private void removeSurfaceWindow() {
  229 + if (mWindowManager != null) {
  230 + mWindowManager.removeViewImmediate(mFloatLayout);
  231 + }
  232 + mPreviewWindowShow = false;
  233 + }
  234 +
  235 + private void updateViewPosition() {
  236 + if (mWmParams != null && mWindowManager != null) {
  237 + mWmParams.gravity = Gravity.RIGHT | Gravity.BOTTOM;
  238 +
  239 + // 以屏幕左上角为原点,设置x、y初始值,相对于gravity
  240 + mWmParams.x = 0;
  241 + mWmParams.y = 0;
  242 + mWindowManager.updateViewLayout(mFloatLayout, mWmParams); //刷新显示
  243 + }
  244 + }
  245 +
  246 + private int align(int val, int align) {
  247 + return (val + align - 1) / align * align;
  248 + }
  249 +
  250 + private int getDisplayRotation() {
  251 + int rotation = getWindowManager().getDefaultDisplay().getRotation();
  252 + switch (rotation) {
  253 + case Surface.ROTATION_0:
  254 + return 0;
  255 + case Surface.ROTATION_90:
  256 + return 90;
  257 + case Surface.ROTATION_180:
  258 + return 180;
  259 + case Surface.ROTATION_270:
  260 + return 270;
  261 + }
  262 + return 0;
  263 + }
  264 +
  265 + private void addFloatViewWithPermCheck() {
  266 + // 6.0 需要检查overlay权限
  267 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
  268 + Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
  269 + Uri.parse("package:" + getPackageName()));
  270 + startActivityForResult(intent, OVERLAY_PERMISSION_RESULT_CODE);
  271 + } else {
  272 + initSurfaceWindow();
  273 + addSurfaceWindow();
  274 + }
  275 + }
  276 +
  277 + /**
  278 + * 申请overlay权限窗口返回
  279 + *
  280 + * @param requestCode
  281 + * @param resultCode
  282 + * @param data
  283 + */
  284 + @Override
  285 + protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  286 + if (requestCode == OVERLAY_PERMISSION_RESULT_CODE) {
  287 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  288 + if (!Settings.canDrawOverlays(this)) {
  289 + // SYSTEM_ALERT_WINDOW permission not granted...
  290 + Toast.makeText(FloatActivity.this, "SYSTEM_ALERT_WINDOW not granted",
  291 + Toast.LENGTH_SHORT).show();
  292 + } else {
  293 + initSurfaceWindow();
  294 + addSurfaceWindow();
  295 + }
  296 + }
  297 + }
  298 + }
  299 +
  300 + /**
  301 + * 旋转摄像头预览示例代码
  302 + */
  303 + private void onSwitchRotate() {
  304 + if (mPreviewWindowShow) {
  305 + int rotation = getDisplayRotation();
  306 + Log.i(TAG, "onSwitchRotate: " + mLastRotation + "->" + rotation);
  307 + CNGlobalStreamer.getInstance().setRotateDegrees(rotation);
  308 +
  309 + boolean isLastLandscape = (mLastRotation % 180) != 0;
  310 + boolean isLandscape = (rotation % 180) != 0;
  311 + if (isLastLandscape != isLandscape) {
  312 + int width = mCameraView.getHeight();
  313 + int height = mCameraView.getWidth();
  314 + RelativeLayout.LayoutParams previewLayoutParams =
  315 + (RelativeLayout.LayoutParams) mCameraView.getLayoutParams();
  316 + previewLayoutParams.width = width;
  317 + previewLayoutParams.height = height;
  318 + //更新CameraPreview布局
  319 + mFloatLayout.updateViewLayout(mCameraView, previewLayoutParams);
  320 +
  321 + updateViewPosition();
  322 + updateWaterMark(isLandscape);
  323 + }
  324 + }
  325 + }
  326 +
  327 + // update water mark position while screen orientation changed
  328 + private void updateWaterMark(boolean isLandscape) {
  329 + Streamer streamer = CNGlobalStreamer.getInstance();
  330 + streamer.hideWaterMarkLogo();
  331 + streamer.hideWaterMarkTime();
  332 + if (!isLandscape) {
  333 + streamer.showWaterMarkLogo(mLogoPath, 0.08f, 0.04f, 0.20f, 0, 0.8f);
  334 + streamer.showWaterMarkTime(0.03f, 0.01f, 0.35f, Color.WHITE, 1.0f);
  335 + } else {
  336 + streamer.showWaterMarkLogo(mLogoPath, 0.05f, 0.09f, 0, 0.20f, 0.8f);
  337 + streamer.showWaterMarkTime(0.01f, 0.03f, 0.22f, Color.WHITE, 1.0f);
  338 + }
  339 + }
  340 +}
app/src/main/java/com/cnlive/demo/stream/FloatView.java 0 → 100644
  1 +package com.cnlive.demo.stream;
  2 +
  3 +import android.content.Context;
  4 +import android.util.AttributeSet;
  5 +import android.view.Gravity;
  6 +import android.view.MotionEvent;
  7 +import android.view.WindowManager;
  8 +import android.widget.RelativeLayout;
  9 +
  10 +/**
  11 + * Created by Lynn on 2017/9/19.
  12 + */
  13 +
  14 +public class FloatView extends RelativeLayout {
  15 + private float mTouchStartX;
  16 + private float mTouchStartY;
  17 + private float mLastX;
  18 + private float mLastY;
  19 + private float mMaxX = 0;
  20 + private float mMaxY = 0;
  21 +
  22 + private WindowManager mWindowManager;
  23 + private WindowManager.LayoutParams mWmParams;
  24 +
  25 + public FloatView(Context context) {
  26 + super(context);
  27 + init();
  28 + }
  29 +
  30 + public FloatView(Context context, AttributeSet attrs) {
  31 + super(context, attrs);
  32 + init();
  33 + }
  34 +
  35 + public FloatView(Context context, AttributeSet attrs, int defStyleAttr) {
  36 + super(context, attrs, defStyleAttr);
  37 + init();
  38 + }
  39 +
  40 + public void setWmParams(WindowManager.LayoutParams params) {
  41 + mWmParams = params;
  42 + }
  43 +
  44 + @Override
  45 + public boolean onTouchEvent(MotionEvent event) {
  46 + //获取相对屏幕的坐标,即以屏幕左上角为原点
  47 + mLastX = event.getRawX();
  48 + mLastY = event.getRawY();
  49 +
  50 + switch (event.getAction()) {
  51 + case MotionEvent.ACTION_DOWN:
  52 + //获取相对View的坐标,即以此View左上角为原点
  53 + mTouchStartX = event.getX();
  54 + mTouchStartY = event.getY();
  55 + break;
  56 + case MotionEvent.ACTION_MOVE:
  57 + updateViewPosition();
  58 + break;
  59 + case MotionEvent.ACTION_UP:
  60 + mTouchStartX = 0;
  61 + mTouchStartY = 0;
  62 + break;
  63 + }
  64 + return true;
  65 + }
  66 +
  67 + private void init() {
  68 + mWindowManager = (WindowManager) getContext().getApplicationContext()
  69 + .getSystemService(Context.WINDOW_SERVICE);
  70 + }
  71 +
  72 + private void updateViewPosition() {
  73 + if (mWmParams != null) {
  74 + mMaxX = mWindowManager.getDefaultDisplay().getWidth() - this.getWidth();
  75 + mMaxY = mWindowManager.getDefaultDisplay().getHeight() - this.getHeight();
  76 +
  77 + //更新浮动窗口位置参数
  78 + float newX = (mLastX - mTouchStartX);
  79 + float newY = (mLastY - mTouchStartY);
  80 + //以屏幕左上角为原点
  81 + mWmParams.gravity = Gravity.LEFT | Gravity.TOP;
  82 +
  83 + //不能移除屏幕最左边和最上边
  84 + if (newX < 0) {
  85 + newX = 0;
  86 + }
  87 +
  88 + if (newY < 0) {
  89 + newY = 0;
  90 + }
  91 +
  92 + //不能移出屏幕最右边和最下边
  93 + if (newX > mMaxX) {
  94 + newX = mMaxX;
  95 + }
  96 +
  97 + if (newY > mMaxY) {
  98 + newY = mMaxY;
  99 + }
  100 + mWmParams.x = (int) newX;
  101 + mWmParams.y = (int) newY;
  102 + mWindowManager.updateViewLayout(this, mWmParams); //刷新显示
  103 +
  104 + }
  105 + }
  106 +}
app/src/main/java/com/cnlive/demo/stream/StreamActivity.java
@@ -8,7 +8,9 @@ import android.content.DialogInterface; @@ -8,7 +8,9 @@ import android.content.DialogInterface;
8 import android.content.Intent; 8 import android.content.Intent;
9 import android.content.pm.ActivityInfo; 9 import android.content.pm.ActivityInfo;
10 import android.content.pm.PackageManager; 10 import android.content.pm.PackageManager;
  11 +import android.graphics.Bitmap;
11 import android.graphics.Color; 12 import android.graphics.Color;
  13 +import android.hardware.Camera;
12 import android.opengl.GLSurfaceView; 14 import android.opengl.GLSurfaceView;
13 import android.os.Build; 15 import android.os.Build;
14 import android.os.Bundle; 16 import android.os.Bundle;
@@ -23,35 +25,42 @@ import android.view.Window; @@ -23,35 +25,42 @@ import android.view.Window;
23 import android.view.WindowManager; 25 import android.view.WindowManager;
24 import android.widget.AdapterView; 26 import android.widget.AdapterView;
25 import android.widget.ArrayAdapter; 27 import android.widget.ArrayAdapter;
  28 +import android.widget.Button;
26 import android.widget.CheckBox; 29 import android.widget.CheckBox;
27 import android.widget.Chronometer; 30 import android.widget.Chronometer;
28 import android.widget.CompoundButton; 31 import android.widget.CompoundButton;
  32 +import android.widget.ImageView;
29 import android.widget.LinearLayout; 33 import android.widget.LinearLayout;
30 import android.widget.SeekBar; 34 import android.widget.SeekBar;
31 import android.widget.TextView; 35 import android.widget.TextView;
32 import android.widget.Toast; 36 import android.widget.Toast;
33 37
34 import com.cnlive.libs.stream.Streamer; 38 import com.cnlive.libs.stream.Streamer;
  39 +import com.cnlive.libs.stream.base.ICNAudioEffectFilter;
35 import com.cnlive.libs.stream.base.IStreamer; 40 import com.cnlive.libs.stream.base.IStreamer;
36 import com.cnlive.libs.stream.base.ImgBeautyProFilter; 41 import com.cnlive.libs.stream.base.ImgBeautyProFilter;
37 import com.cnlive.libs.stream.base.ImgFilterBase; 42 import com.cnlive.libs.stream.base.ImgFilterBase;
  43 +import com.cnlive.libs.stream.filter.CNAudioEffectFilter;
  44 +import com.cnlive.libs.stream.filter.CNAudioFilterBase;
  45 +import com.cnlive.libs.stream.filter.CNAudioReverbFilter;
38 import com.cnlive.libs.stream.model.ActivityConfig; 46 import com.cnlive.libs.stream.model.ActivityConfig;
39 -import com.ksyun.media.player.IMediaPlayer;  
40 47
  48 +import java.io.BufferedOutputStream;
  49 +import java.io.FileNotFoundException;
  50 +import java.io.FileOutputStream;
  51 +import java.io.IOException;
  52 +import java.text.SimpleDateFormat;
  53 +import java.util.Date;
  54 +import java.util.LinkedList;
41 import java.util.List; 55 import java.util.List;
42 56
43 import static com.cnlive.libs.stream.base.IStreamer.ENCODE_METHOD_HARDWARE; 57 import static com.cnlive.libs.stream.base.IStreamer.ENCODE_METHOD_HARDWARE;
44 import static com.cnlive.libs.stream.base.IStreamer.ENCODE_METHOD_SOFTWARE_COMPAT; 58 import static com.cnlive.libs.stream.base.IStreamer.ENCODE_METHOD_SOFTWARE_COMPAT;
  59 +import static com.cnlive.libs.stream.base.IStreamer.ENCODE_PROFILE_BALANCE;
  60 +import static com.cnlive.libs.stream.base.IStreamer.ENCODE_PROFILE_HIGH_PERFORMANCE;
  61 +import static com.cnlive.libs.stream.base.IStreamer.ENCODE_PROFILE_LOW_POWER;
45 import static com.cnlive.libs.stream.base.IStreamer.VIDEO_RESOLUTION_360P; 62 import static com.cnlive.libs.stream.base.IStreamer.VIDEO_RESOLUTION_360P;
46 -import static com.cnlive.libs.stream.model.Filters.BEAUTY_DISABLE;  
47 -import static com.cnlive.libs.stream.model.Filters.BEAUTY_ILLUSION;  
48 -import static com.cnlive.libs.stream.model.Filters.BEAUTY_PRO;  
49 -import static com.cnlive.libs.stream.model.Filters.BEAUTY_SMOOTH;  
50 -import static com.cnlive.libs.stream.model.Filters.BEAUTY_SOFT;  
51 -import static com.cnlive.libs.stream.model.Filters.BEAUTY_SOFT_EXT;  
52 -import static com.cnlive.libs.stream.model.Filters.BEAUTY_SOFT_SHARPEN;  
53 -import static com.cnlive.libs.stream.model.Filters.DENOISE;  
54 -import static com.cnlive.libs.stream.model.Filters.SKIN_WHITEN; 63 +import static com.cnlive.libs.stream.model.Filters.*;
55 64
56 /** 65 /**
57 * Created by Administrator on 2016/8/29. 66 * Created by Administrator on 2016/8/29.
@@ -66,6 +75,8 @@ public class StreamActivity extends Activity { @@ -66,6 +75,8 @@ public class StreamActivity extends Activity {
66 private View mDeleteView; 75 private View mDeleteView;
67 private View mSwitchCameraView; 76 private View mSwitchCameraView;
68 private View mFlashView; 77 private View mFlashView;
  78 + private ImageView mExposureView;
  79 + private ImageView mAddView;
69 private TextView mShootingText; 80 private TextView mShootingText;
70 private CheckBox mWaterMarkCheckBox; 81 private CheckBox mWaterMarkCheckBox;
71 private CheckBox mBeautyCheckBox; 82 private CheckBox mBeautyCheckBox;
@@ -74,6 +85,12 @@ public class StreamActivity extends Activity { @@ -74,6 +85,12 @@ public class StreamActivity extends Activity {
74 private CheckBox mMuteCheckBox; 85 private CheckBox mMuteCheckBox;
75 private CheckBox mAudioOnlyCheckBox; 86 private CheckBox mAudioOnlyCheckBox;
76 private CheckBox mFrontMirrorCheckBox; 87 private CheckBox mFrontMirrorCheckBox;
  88 + private CheckBox mBgImg;
  89 + private Button mAudioMix;
  90 + private Button mBgmFilter;
  91 + private Button mCaptureScreen;
  92 +
  93 + private VerticalSeekBar mExposureSeekBar;
77 94
78 private ButtonObserver mObserverButton; 95 private ButtonObserver mObserverButton;
79 private CheckBoxObserver mCheckBoxObserver; 96 private CheckBoxObserver mCheckBoxObserver;
@@ -86,12 +103,16 @@ public class StreamActivity extends Activity { @@ -86,12 +103,16 @@ public class StreamActivity extends Activity {
86 private boolean isFlashOpened = false; 103 private boolean isFlashOpened = false;
87 private String mBgmPath = "/sdcard/test.mp3"; 104 private String mBgmPath = "/sdcard/test.mp3";
88 private String mLogoPath = "file:///sdcard/cnlive_logo.png"; 105 private String mLogoPath = "file:///sdcard/cnlive_logo.png";
  106 + private String mAnimatedLogoPath = "assets://cnlive_logo.gif";
  107 + private String mBgImagePath = "assets://bg.jpg";
89 108
90 private String activityId; 109 private String activityId;
91 private String channelId; 110 private String channelId;
92 111
93 private int isHorizontalScreen = 0; 112 private int isHorizontalScreen = 0;
94 113
  114 + private boolean mShowAnimatedLogo;
  115 +
95 private final static int PERMISSION_REQUEST_CAMERA_AUDIOREC = 1; 116 private final static int PERMISSION_REQUEST_CAMERA_AUDIOREC = 1;
96 private static final String START_STRING = "开始直播"; 117 private static final String START_STRING = "开始直播";
97 private static final String STOP_STRING = "停止直播"; 118 private static final String STOP_STRING = "停止直播";
@@ -112,6 +133,8 @@ public class StreamActivity extends Activity { @@ -112,6 +133,8 @@ public class StreamActivity extends Activity {
112 private TextView mRuddyText; 133 private TextView mRuddyText;
113 private AppCompatSeekBar mRuddySeekBar; 134 private AppCompatSeekBar mRuddySeekBar;
114 135
  136 + private AnimatedImageCapture animatedImageCapture;
  137 +
115 public static void startActivity(Context context, 138 public static void startActivity(Context context,
116 String activityID, 139 String activityID,
117 String channelID, 140 String channelID,
@@ -142,6 +165,7 @@ public class StreamActivity extends Activity { @@ -142,6 +165,7 @@ public class StreamActivity extends Activity {
142 channelId = bundle.getString(CHANNELID); 165 channelId = bundle.getString(CHANNELID);
143 mIsLandscape = bundle.getBoolean(LANDSCAPE, false); 166 mIsLandscape = bundle.getBoolean(LANDSCAPE, false);
144 initStreamer(); 167 initStreamer();
  168 + startCameraPreviewWithPermCheck();
145 169
146 } 170 }
147 171
@@ -163,8 +187,15 @@ public class StreamActivity extends Activity { @@ -163,8 +187,15 @@ public class StreamActivity extends Activity {
163 //闪光灯 187 //闪光灯
164 mFlashView = findViewById(R.id.flash); 188 mFlashView = findViewById(R.id.flash);
165 mFlashView.setOnClickListener(mObserverButton); 189 mFlashView.setOnClickListener(mObserverButton);
  190 + //亮度
  191 + mExposureView = (ImageView) findViewById(R.id.exposure);
  192 + mExposureView.setOnClickListener(mObserverButton);
  193 + //悬浮窗
  194 + mAddView = (ImageView) findViewById(R.id.add);
  195 + mAddView.setOnClickListener(mObserverButton);
  196 +
166 mCheckBoxObserver = new CheckBoxObserver(); 197 mCheckBoxObserver = new CheckBoxObserver();
167 - //美 198 + //美
168 mBeautyCheckBox = (CheckBox) findViewById(R.id.click_to_switch_beauty); 199 mBeautyCheckBox = (CheckBox) findViewById(R.id.click_to_switch_beauty);
169 mBeautyCheckBox.setOnCheckedChangeListener(mCheckBoxObserver); 200 mBeautyCheckBox.setOnCheckedChangeListener(mCheckBoxObserver);
170 //背景音乐 201 //背景音乐
@@ -186,6 +217,28 @@ public class StreamActivity extends Activity { @@ -186,6 +217,28 @@ public class StreamActivity extends Activity {
186 mAudioOnlyCheckBox = (CheckBox) findViewById(R.id.audio_only); 217 mAudioOnlyCheckBox = (CheckBox) findViewById(R.id.audio_only);
187 mAudioOnlyCheckBox.setOnCheckedChangeListener(mCheckBoxObserver); 218 mAudioOnlyCheckBox.setOnCheckedChangeListener(mCheckBoxObserver);
188 219
  220 + //音频滤镜
  221 + mAudioMix = (Button) findViewById(R.id.audio_mix);
  222 + mAudioMix.setOnClickListener(mObserverButton);
  223 +
  224 + //bgm升降调
  225 + mBgmFilter = (Button) findViewById(R.id.bgm_filter);
  226 + mBgmFilter.setOnClickListener(mObserverButton);
  227 +
  228 + //截屏
  229 + mCaptureScreen = (Button) findViewById(R.id.click_to_capture_screenshot);
  230 + mCaptureScreen.setOnClickListener(mObserverButton);
  231 +
  232 + //背景图推流
  233 + mBgImg = (CheckBox) findViewById(R.id.bg_img);
  234 + mBgImg.setOnCheckedChangeListener(mCheckBoxObserver);
  235 +
  236 + //亮度调节seekbar
  237 + mExposureSeekBar = (VerticalSeekBar) findViewById(R.id.exposure_seekBar);
  238 + mExposureSeekBar.setProgress(50);
  239 + mExposureSeekBar.setSecondaryProgress(50);
  240 + mExposureSeekBar.setOnSeekBarChangeListener(verticalSeekBarlistener);
  241 +
189 mBeautyChooseView = findViewById(R.id.beauty_choose); 242 mBeautyChooseView = findViewById(R.id.beauty_choose);
190 mBeautySpinner = (AppCompatSpinner) findViewById(R.id.beauty_spin); 243 mBeautySpinner = (AppCompatSpinner) findViewById(R.id.beauty_spin);
191 mBeautyGrindLayout = (LinearLayout) findViewById(R.id.beauty_grind); 244 mBeautyGrindLayout = (LinearLayout) findViewById(R.id.beauty_grind);
@@ -213,8 +266,27 @@ public class StreamActivity extends Activity { @@ -213,8 +266,27 @@ public class StreamActivity extends Activity {
213 //分别设置预览和推流分辨率 266 //分别设置预览和推流分辨率
214 mStreamer.setPreviewResolution(VIDEO_RESOLUTION_360P); 267 mStreamer.setPreviewResolution(VIDEO_RESOLUTION_360P);
215 mStreamer.setTargetResolution(VIDEO_RESOLUTION_360P); 268 mStreamer.setTargetResolution(VIDEO_RESOLUTION_360P);
  269 +// //采集分辨率
  270 +// mStreamer.setCameraCaptureResolution(VIDEO_RESOLUTION_360P);
216 //设置编码模式(硬编/软编/软编兼容) 271 //设置编码模式(硬编/软编/软编兼容)
217 - mStreamer.setEncodeMethod(ENCODE_METHOD_SOFTWARE_COMPAT); 272 + mStreamer.setEncodeMethod(ENCODE_METHOD_HARDWARE);
  273 +
  274 +// //设置场景
  275 +// mStreamer.setVideoEncodeScene(IStreamer.ENCODE_SCENE_GAME);
  276 +
  277 +// //H265
  278 +// mStreamer.setVideoCodecId(IStreamer.CODEC_ID_HEVC);
  279 +// //H264
  280 +// mStreamer.setVideoCodecId(IStreamer.CODEC_ID_AVC);
  281 +
  282 +// //功耗
  283 +// mStreamer.setVideoEncodeProfile(ENCODE_PROFILE_LOW_POWER);低
  284 +// mStreamer.setVideoEncodeProfile(ENCODE_PROFILE_BALANCE);平衡
  285 +// mStreamer.setVideoEncodeProfile(ENCODE_PROFILE_HIGH_PERFORMANCE);高性能
  286 +
  287 +// //双声道推流
  288 +// mStreamer.setAudioChannels(2);
  289 +
218 290
219 //设置横竖屏方向 291 //设置横竖屏方向
220 mStreamer.setRotateDegrees(mIsLandscape ? 90 : 0);//设置屏幕旋转角度 292 mStreamer.setRotateDegrees(mIsLandscape ? 90 : 0);//设置屏幕旋转角度
@@ -243,22 +315,35 @@ public class StreamActivity extends Activity { @@ -243,22 +315,35 @@ public class StreamActivity extends Activity {
243 //设置错误回调,收到该回调后,一般是发生了严重错误,比如网络断开等 315 //设置错误回调,收到该回调后,一般是发生了严重错误,比如网络断开等
244 mStreamer.setOnErrorListener(mOnErrorListener); 316 mStreamer.setOnErrorListener(mOnErrorListener);
245 //设置美颜滤镜 317 //设置美颜滤镜
246 - mStreamer.getImgTexFilterMgt().setFilter(mStreamer.getGLRender(), DENOISE.getFilter()); 318 + mStreamer.getImgTexFilterMgt().setFilter(mStreamer.getGLRender(), CN_FILTER_BEAUTY_DENOISE.getFilter());
247 mStreamer.setEnableImgBufBeauty(true); 319 mStreamer.setEnableImgBufBeauty(true);
248 320
249 initBeautyUI(); 321 initBeautyUI();
250 322
  323 + mStreamer.setFilterOnErrorListener(new ImgFilterBase.OnErrorListener() {
  324 + @Override
  325 + public void onError(int i) {
  326 + Toast.makeText(StreamActivity.this, "当前机型不支持该滤镜", Toast.LENGTH_SHORT).show();
  327 + mStreamer.setFilter(CN_FILTER_BEAUTY_DISABLE.getFilter());
  328 + }
  329 + });
  330 +
251 //手动变焦 331 //手动变焦
252 mStreamer.setCameraCapture(mStreamer.getCameraCapture()); 332 mStreamer.setCameraCapture(mStreamer.getCameraCapture());
253 mCameraPreviewView.setOnTouchListener(mStreamer.getCameraTouchHelper()); 333 mCameraPreviewView.setOnTouchListener(mStreamer.getCameraTouchHelper());
254 mStreamer.setCameraHintView(mCameraHintView); 334 mStreamer.setCameraHintView(mCameraHintView);
255 mStreamer.setEnableTouchFocus(true); 335 mStreamer.setEnableTouchFocus(true);
256 mStreamer.setEnableZoom(true); 336 mStreamer.setEnableZoom(true);
  337 +
  338 + animatedImageCapture = new AnimatedImageCapture(this, mStreamer);
257 } 339 }
258 340
259 private void initBeautyUI() { 341 private void initBeautyUI() {
260 String[] items = new String[]{"DISABLE", "BEAUTY_SOFT", "SKIN_WHITEN", "BEAUTY_ILLUSION", 342 String[] items = new String[]{"DISABLE", "BEAUTY_SOFT", "SKIN_WHITEN", "BEAUTY_ILLUSION",
261 - "BEAUTY_DENOISE", "BEAUTY_SMOOTH", "BEAUTY_SOFT_EXT", "BEAUTY_SOFT_SHARPEN", "BEAUTY_PRO"}; 343 + "BEAUTY_DENOISE", "BEAUTY_SMOOTH", "BEAUTY_PRO", "BEAUTY_PRO1", "BEAUTY_PRO2", "BEAUTY_PRO3",
  344 + "BEAUTY_PRO4", "ToneCurve", "复古", "胶片", "Amatorka",
  345 + "ELEGANCE", "1977", "Amaro", "Brannan", "EarlyBird", "Hefe", "Hudson", "ink",
  346 + "Lomo", "LordKelvin", "Nash", "Rise", "Sierra", "Sutro", "Toaster", "Valencia", "Walden", "XproII"};
262 ArrayAdapter<String> adapter = new ArrayAdapter<>(this, 347 ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
263 android.R.layout.simple_spinner_item, items); 348 android.R.layout.simple_spinner_item, items);
264 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 349 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
@@ -270,34 +355,35 @@ public class StreamActivity extends Activity { @@ -270,34 +355,35 @@ public class StreamActivity extends Activity {
270 if (textView != null) { 355 if (textView != null) {
271 textView.setTextColor(getResources().getColor(R.color.colorAccent)); 356 textView.setTextColor(getResources().getColor(R.color.colorAccent));
272 } 357 }
273 - switch (position) {  
274 - case 0:  
275 - mStreamer.setFilter(BEAUTY_DISABLE.getFilter());  
276 - break;  
277 - case 1:  
278 - mStreamer.setFilter(BEAUTY_SOFT.getFilter());  
279 - break;  
280 - case 2:  
281 - mStreamer.setFilter(SKIN_WHITEN.getFilter());  
282 - break;  
283 - case 3:  
284 - mStreamer.setFilter(BEAUTY_ILLUSION.getFilter());  
285 - break;  
286 - case 4:  
287 - mStreamer.setFilter(DENOISE.getFilter());  
288 - break;  
289 - case 5:  
290 - mStreamer.setFilter(BEAUTY_SMOOTH.getFilter());  
291 - break;  
292 - case 6:  
293 - mStreamer.setFilter(BEAUTY_SOFT_EXT.getFilter());  
294 - break;  
295 - case 7:  
296 - mStreamer.setFilter(BEAUTY_SOFT_SHARPEN.getFilter());  
297 - break;  
298 - case 8:  
299 - mStreamer.setFilter(BEAUTY_PRO.getFilter());  
300 - break; 358 +
  359 + if (position == 0) {
  360 + mStreamer.setFilter(CN_FILTER_BEAUTY_DISABLE.getFilter());
  361 + } else if (position <= 5) {
  362 + mStreamer.setFilter(position + 15);
  363 + } else if (position == 6) {
  364 + mStreamer.setFilter(CN_FILTER_BEAUTY_PRO.getFilter());
  365 + } else if (position == 7) {
  366 + mStreamer.setFilter(CN_FILTER_BEAUTY_PRO1.getFilter());
  367 + } else if (position == 8) {
  368 + mStreamer.setFilter(CN_FILTER_BEAUTY_PRO2.getFilter());
  369 + } else if (position == 9) {
  370 + mStreamer.setFilter(CN_FILTER_BEAUTY_PRO3.getFilter());
  371 + } else if (position == 10) {
  372 + mStreamer.setFilter(CN_FILTER_BEAUTY_PRO4.getFilter());
  373 + } else if (position == 11) {
  374 + mStreamer.setToneCurveFilterStream(StreamActivity.this.getResources().openRawResource(R.raw.tone_cuver_sample));
  375 + } else if (position == 12) {
  376 + mStreamer.setToneCurveFilterStream(StreamActivity.this.getResources().openRawResource(R.raw.fugu));
  377 + } else if (position == 13) {
  378 + mStreamer.setToneCurveFilterStream(StreamActivity.this.getResources().openRawResource(R.raw.jiaopian));
  379 + } else if (position == 14) {
  380 + //设置风格滤镜
  381 + mStreamer.setSpecialEffectsFilter(CN_SPECIAL_EFFECT_AMATORKA.getFilter());
  382 + } else if (position == 15) {
  383 + mStreamer.setSpecialEffectsFilter(CN_SPECIAL_EFFECT_ELEGANCE.getFilter());
  384 + } else if (position >= 16 && position <= 32) {
  385 + int diff = position - 16;
  386 + mStreamer.setFilter(CN_FILTER_BEAUTY_1977.getFilter() + diff);
301 } 387 }
302 List<ImgFilterBase> filters = mStreamer.getFilter(); 388 List<ImgFilterBase> filters = mStreamer.getFilter();
303 if (filters != null && !filters.isEmpty()) { 389 if (filters != null && !filters.isEmpty()) {
@@ -363,10 +449,81 @@ public class StreamActivity extends Activity { @@ -363,10 +449,81 @@ public class StreamActivity extends Activity {
363 mBeautySpinner.setSelection(4); 449 mBeautySpinner.setSelection(4);
364 } 450 }
365 451
  452 + private boolean[] mChooseFilter = {false, false, false, false
  453 + , false, false, false, false, false, false};
  454 +
  455 + private void showChooseAudioFilter() {
  456 + AlertDialog alertDialog;
  457 + alertDialog = new AlertDialog.Builder(this)
  458 + .setTitle("音频滤镜")
  459 + .setMultiChoiceItems(new String[]{"录音棚", "KTV", "小舞台", "演唱会", "萝莉",
  460 + "大叔", "庄严", "机器人"}, mChooseFilter,
  461 + new DialogInterface.OnMultiChoiceClickListener() {
  462 + @Override
  463 + public void onClick(DialogInterface dialog, int which, boolean isChecked) {
  464 + if (isChecked) {
  465 + mChooseFilter[which] = true;
  466 + }
  467 + }
  468 + }).setPositiveButton("确定", new DialogInterface.OnClickListener() {
  469 + @Override
  470 + public void onClick(DialogInterface dialog, int which) {
  471 + List<CNAudioFilterBase> filterBases = new LinkedList<CNAudioFilterBase>();
  472 + if (mChooseFilter[0]) {
  473 + CNAudioReverbFilter reverbFilter = new CNAudioReverbFilter();
  474 + reverbFilter.setReverbLevel(IStreamer.AUDIO_REVERB_LEVEL_1);
  475 + filterBases.add(reverbFilter);
  476 + }
  477 + if (mChooseFilter[1]) {
  478 + CNAudioReverbFilter reverbFilter = new CNAudioReverbFilter();
  479 + reverbFilter.setReverbLevel(IStreamer.AUDIO_REVERB_LEVEL_2);
  480 + filterBases.add(reverbFilter);
  481 + }
  482 + if (mChooseFilter[2]) {
  483 + CNAudioReverbFilter reverbFilter = new CNAudioReverbFilter();
  484 + reverbFilter.setReverbLevel(IStreamer.AUDIO_REVERB_LEVEL_3);
  485 + filterBases.add(reverbFilter);
  486 + }
  487 + if (mChooseFilter[3]) {
  488 + CNAudioReverbFilter reverbFilter = new CNAudioReverbFilter();
  489 + reverbFilter.setReverbLevel(IStreamer.AUDIO_REVERB_LEVEL_4);
  490 + filterBases.add(reverbFilter);
  491 + }
  492 + if (mChooseFilter[4]) {
  493 + CNAudioEffectFilter effectFilter = new CNAudioEffectFilter(ICNAudioEffectFilter.AUDIO_EFFECT_TYPE_FEMALE);
  494 + filterBases.add(effectFilter);
  495 + }
  496 + if (mChooseFilter[5]) {
  497 + CNAudioEffectFilter effectFilter = new CNAudioEffectFilter(ICNAudioEffectFilter.AUDIO_EFFECT_TYPE_MALE);
  498 + filterBases.add(effectFilter);
  499 + }
  500 +
  501 + if (mChooseFilter[6]) {
  502 + CNAudioEffectFilter effectFilter = new CNAudioEffectFilter(ICNAudioEffectFilter.AUDIO_EFFECT_TYPE_HEROIC);
  503 + filterBases.add(effectFilter);
  504 + }
  505 +
  506 + if (mChooseFilter[7]) {
  507 + CNAudioEffectFilter effectFilter = new CNAudioEffectFilter(ICNAudioEffectFilter.AUDIO_EFFECT_TYPE_ROBOT);
  508 + filterBases.add(effectFilter);
  509 + }
  510 +
  511 + if (!mChooseFilter[0] && !mChooseFilter[1] && !mChooseFilter[2] && !mChooseFilter[3] && !mChooseFilter[4] && !mChooseFilter[5] && !mChooseFilter[6] && !mChooseFilter[7]) {
  512 + filterBases = null;
  513 + }
  514 + mStreamer.getAudioFilterMgt().setFilter(filterBases);
  515 +
  516 + dialog.dismiss();
  517 + }
  518 + }).create();
  519 + alertDialog.setCancelable(false);
  520 + alertDialog.show();
  521 + }
  522 +
366 @Override 523 @Override
367 public void onResume() { 524 public void onResume() {
368 super.onResume(); 525 super.onResume();
369 - startCameraPreviewWithPermCheck(); 526 + mStreamer.setDisplayPreview(mCameraPreviewView);
370 mStreamer.resume(); 527 mStreamer.resume();
371 if (mStreamer.isRecording() && !mAudioOnlyCheckBox.isChecked()) { 528 if (mStreamer.isRecording() && !mAudioOnlyCheckBox.isChecked()) {
372 mStreamer.setAudioOnly(false); 529 mStreamer.setAudioOnly(false);
@@ -380,17 +537,18 @@ public class StreamActivity extends Activity { @@ -380,17 +537,18 @@ public class StreamActivity extends Activity {
380 public void onPause() { 537 public void onPause() {
381 super.onPause(); 538 super.onPause();
382 mStreamer.pause(); 539 mStreamer.pause();
383 - mStreamer.stopCameraPreview();  
384 - if (mStreamer.isRecording() && !mAudioOnlyCheckBox.isChecked()) {  
385 - mStreamer.setAudioOnly(true);  
386 - mStreamer.setMuteAudio(true);  
387 - } 540 +// mStreamer.stopCameraPreview();
  541 +// if (mStreamer.isRecording() && !mAudioOnlyCheckBox.isChecked()) {
  542 +// mStreamer.setAudioOnly(true);
  543 +// mStreamer.setMuteAudio(true);
  544 +// }
388 hideWaterMark(); 545 hideWaterMark();
389 } 546 }
390 547
391 @Override 548 @Override
392 public void onDestroy() { 549 public void onDestroy() {
393 super.onDestroy(); 550 super.onDestroy();
  551 + animatedImageCapture.stop();
394 if (mMainHandler != null) { 552 if (mMainHandler != null) {
395 mMainHandler.removeCallbacksAndMessages(null); 553 mMainHandler.removeCallbacksAndMessages(null);
396 mMainHandler = null; 554 mMainHandler = null;
@@ -429,6 +587,87 @@ public class StreamActivity extends Activity { @@ -429,6 +587,87 @@ public class StreamActivity extends Activity {
429 mRecording = false; 587 mRecording = false;
430 } 588 }
431 589
  590 + private int mChooseBGMFilter = 3;
  591 + private String[] mBGMFilterName = {"-3", "-2", "-1", "0", "1", "2", "3"};
  592 +
  593 + //bgm升降调
  594 + private void onChooseBGMFilter() {
  595 + AlertDialog alertDialog;
  596 + alertDialog = new AlertDialog.Builder(this)
  597 + .setTitle("请选择背景音乐变调等级")
  598 + .setSingleChoiceItems(mBGMFilterName, mChooseBGMFilter, new DialogInterface.OnClickListener() {
  599 + @Override
  600 + public void onClick(DialogInterface dialog, int which) {
  601 + mChooseBGMFilter = which;
  602 + }
  603 + })
  604 + .setPositiveButton("确定", new DialogInterface.OnClickListener() {
  605 + @Override
  606 + public void onClick(DialogInterface dialog, int which) {
  607 + int level = Integer.parseInt(mBGMFilterName[mChooseBGMFilter]);
  608 + CNAudioEffectFilter audioEffectFilter = new CNAudioEffectFilter(ICNAudioEffectFilter.AUDIO_EFFECT_TYPE_PITCH);
  609 + audioEffectFilter.setPitchLevel(level);
  610 + mStreamer.getBGMAudioFilterMgt().setFilter(audioEffectFilter);
  611 + dialog.dismiss();
  612 + }
  613 + })
  614 + .create();
  615 + alertDialog.setCancelable(false);
  616 + alertDialog.show();
  617 + }
  618 +
  619 + //截屏
  620 + private void onCaptureScreenShotClick() {
  621 + mStreamer.requestScreenShot(new IStreamer.ScreenShotListener() {
  622 + @Override
  623 + public void onBitmapAvailable(Bitmap bitmap) {
  624 + BufferedOutputStream bos = null;
  625 + try {
  626 + Date date = new Date();
  627 + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
  628 + final String fileName = "/sdcard/screenshot" + dateFormat.format(date) + ".jpg";
  629 +
  630 + bos = new BufferedOutputStream(new FileOutputStream(fileName));
  631 +
  632 + if (bitmap != null) {
  633 + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, bos);
  634 + runOnUiThread(new Runnable() {
  635 + @Override
  636 + public void run() {
  637 + Toast.makeText(StreamActivity.this, "保存截图到" + fileName, Toast.LENGTH_SHORT).show();
  638 + }
  639 + });
  640 + }
  641 + } catch (FileNotFoundException e) {
  642 + e.printStackTrace();
  643 + } finally {
  644 + if (bos != null)
  645 + try {
  646 + bos.close();
  647 + } catch (IOException e) {
  648 + e.printStackTrace();
  649 + }
  650 + }
  651 + }
  652 + });
  653 + }
  654 +
  655 + //亮度调节
  656 + private void onExposureClick() {
  657 + if (mExposureSeekBar.getVisibility() == View.VISIBLE) {
  658 + mExposureSeekBar.setVisibility(View.GONE);
  659 + } else {
  660 + mExposureSeekBar.setVisibility(View.VISIBLE);
  661 + }
  662 + }
  663 +
  664 + private void onAddClick() {
  665 + Intent intent = new Intent(getApplicationContext(), FloatActivity.class);
  666 + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  667 + CNGlobalStreamer.setInstance(mStreamer);
  668 + startActivity(intent);
  669 + }
  670 +
432 private class ButtonObserver implements View.OnClickListener { 671 private class ButtonObserver implements View.OnClickListener {
433 @Override 672 @Override
434 public void onClick(View view) { 673 public void onClick(View view) {
@@ -445,12 +684,28 @@ public class StreamActivity extends Activity { @@ -445,12 +684,28 @@ public class StreamActivity extends Activity {
445 case R.id.click_to_shoot: 684 case R.id.click_to_shoot:
446 onShootClick(); 685 onShootClick();
447 break; 686 break;
  687 + case R.id.audio_mix:
  688 + showChooseAudioFilter();
  689 + break;
  690 + case R.id.bgm_filter:
  691 + onChooseBGMFilter();
  692 + break;
  693 + case R.id.click_to_capture_screenshot:
  694 + onCaptureScreenShotClick();
  695 + break;
  696 + case R.id.exposure:
  697 + onExposureClick();
  698 + break;
  699 + case R.id.add:
  700 + onAddClick();
  701 + break;
448 default: 702 default:
449 break; 703 break;
450 } 704 }
451 } 705 }
452 } 706 }
453 707
  708 +
454 private class CheckBoxObserver implements CompoundButton.OnCheckedChangeListener { 709 private class CheckBoxObserver implements CompoundButton.OnCheckedChangeListener {
455 710
456 @Override 711 @Override
@@ -477,6 +732,9 @@ public class StreamActivity extends Activity { @@ -477,6 +732,9 @@ public class StreamActivity extends Activity {
477 case R.id.audio_only: 732 case R.id.audio_only:
478 onAudioOnlyChecked(isChecked); 733 onAudioOnlyChecked(isChecked);
479 break; 734 break;
  735 + case R.id.bg_img:
  736 + onBgImageChecked(isChecked);
  737 + break;
480 default: 738 default:
481 break; 739 break;
482 } 740 }
@@ -484,6 +742,17 @@ public class StreamActivity extends Activity { @@ -484,6 +742,17 @@ public class StreamActivity extends Activity {
484 742
485 } 743 }
486 744
  745 + //背景图推流
  746 + private void onBgImageChecked(boolean isChecked) {
  747 + if (isChecked) {
  748 + mStreamer.stopCameraPreview();
  749 + mStreamer.startImageCapture(mBgImagePath);
  750 + } else {
  751 + mStreamer.startCameraPreview();
  752 + mStreamer.stopImageCapture();
  753 + }
  754 + }
  755 +
487 //转换摄像头 756 //转换摄像头
488 private void onSwitchCamera() { 757 private void onSwitchCamera() {
489 mStreamer.switchCamera(); 758 mStreamer.switchCamera();
@@ -536,11 +805,11 @@ public class StreamActivity extends Activity { @@ -536,11 +805,11 @@ public class StreamActivity extends Activity {
536 private void onBeautyChecked(boolean isChecked) { 805 private void onBeautyChecked(boolean isChecked) {
537 if (mStreamer.getVideoEncodeMethod() == 806 if (mStreamer.getVideoEncodeMethod() ==
538 IStreamer.ENCODE_METHOD_SOFTWARE_COMPAT) { 807 IStreamer.ENCODE_METHOD_SOFTWARE_COMPAT) {
539 - mStreamer.getImgTexFilterMgt().setFilter(mStreamer.getGLRender(),  
540 - DENOISE.getFilter());  
541 - mStreamer.setEnableImgBufBeauty(true); 808 + mStreamer.getImgTexFilterMgt().setFilter(mStreamer.getGLRender(), isChecked ?
  809 + CN_FILTER_BEAUTY_DENOISE.getFilter() :
  810 + CN_FILTER_BEAUTY_DISABLE.getFilter());
  811 + mStreamer.setEnableImgBufBeauty(isChecked);
542 } else { 812 } else {
543 -// showChooseFilter();  
544 mBeautyChooseView.setVisibility(isChecked ? View.VISIBLE : View.INVISIBLE); 813 mBeautyChooseView.setVisibility(isChecked ? View.VISIBLE : View.INVISIBLE);
545 } 814 }
546 } 815 }
@@ -587,17 +856,21 @@ public class StreamActivity extends Activity { @@ -587,17 +856,21 @@ public class StreamActivity extends Activity {
587 //显示水印 856 //显示水印
588 private void showWaterMark() { 857 private void showWaterMark() {
589 if (!mIsLandscape) { 858 if (!mIsLandscape) {
590 - /**  
591 - * 设置并显示logo水印  
592 - *  
593 - * @param path logo图片文件的路径  
594 - * @param x logo的显示位置,0-1之间,相对于视频  
595 - * @param y logo的显示位置,0-1之间,相对于视频  
596 - * @param w logo的显示宽度,0-1之间,相对于视频,为0时会根据h及logo图片的比例自适应  
597 - * @param h logo的显示高度,0-1之间,相对于视频,为0时会根据w及logo图片的比例自适应  
598 - * @param alpha logo的透明度,0-1之间  
599 - */  
600 - mStreamer.showWaterMarkLogo(mLogoPath, 0.08f, 0.04f, 0.20f, 0, 0.8f); 859 + if (!mShowAnimatedLogo) {
  860 + /**
  861 + * 设置并显示logo水印
  862 + *
  863 + * @param path logo图片文件的路径
  864 + * @param x logo的显示位置,0-1之间,相对于视频
  865 + * @param y logo的显示位置,0-1之间,相对于视频
  866 + * @param w logo的显示宽度,0-1之间,相对于视频,为0时会根据h及logo图片的比例自适应
  867 + * @param h logo的显示高度,0-1之间,相对于视频,为0时会根据w及logo图片的比例自适应
  868 + * @param alpha logo的透明度,0-1之间
  869 + */
  870 + mStreamer.showWaterMarkLogo(mLogoPath, 0.08f, 0.04f, 0.20f, 0, 0.8f);
  871 + } else {
  872 + animatedImageCapture.showAnimatedWaterMard(mAnimatedLogoPath, 0.08f, 0.04f, 0.25f, 0, 0.8f);
  873 + }
601 874
602 /** 875 /**
603 * 在推流视频中显示时间水印 876 * 在推流视频中显示时间水印
@@ -610,15 +883,21 @@ public class StreamActivity extends Activity { @@ -610,15 +883,21 @@ public class StreamActivity extends Activity {
610 */ 883 */
611 mStreamer.showWaterMarkTime(0.03f, 0.01f, 0.35f, Color.RED, 1.0f); 884 mStreamer.showWaterMarkTime(0.03f, 0.01f, 0.35f, Color.RED, 1.0f);
612 } else { 885 } else {
613 - mStreamer.showWaterMarkLogo(mLogoPath, 0.05f, 0.09f, 0, 0.08f, 0.8f); 886 + if (!mShowAnimatedLogo) {
  887 + mStreamer.showWaterMarkLogo(mLogoPath, 0.05f, 0.09f, 0, 0.08f, 0.8f);
  888 + } else {
  889 + animatedImageCapture.showAnimatedWaterMard(mAnimatedLogoPath, 0.05f, 0.09f, 0, 0.25f, 0.8f);
  890 + }
614 mStreamer.showWaterMarkTime(0.01f, 0.03f, 0.22f, Color.RED, 1.0f); 891 mStreamer.showWaterMarkTime(0.01f, 0.03f, 0.22f, Color.RED, 1.0f);
615 } 892 }
  893 + mShowAnimatedLogo = !mShowAnimatedLogo;
616 } 894 }
617 895
618 //隐藏水印 896 //隐藏水印
619 private void hideWaterMark() { 897 private void hideWaterMark() {
620 mStreamer.hideWaterMarkLogo(); 898 mStreamer.hideWaterMarkLogo();
621 mStreamer.hideWaterMarkTime(); 899 mStreamer.hideWaterMarkTime();
  900 + animatedImageCapture.hideAnimatedWaterMark();
622 } 901 }
623 902
624 //摄像头权限检测 903 //摄像头权限检测
@@ -643,50 +922,6 @@ public class StreamActivity extends Activity { @@ -643,50 +922,6 @@ public class StreamActivity extends Activity {
643 } 922 }
644 } 923 }
645 924
646 - //选择美颜滤镜  
647 - private void showChooseFilter() {  
648 - AlertDialog alertDialog;  
649 - alertDialog = new AlertDialog.Builder(this)  
650 - .setTitle("请选择美颜滤镜")  
651 - .setSingleChoiceItems(  
652 - /**  
653 - * BEAUTY_DISABLE 禁用美颜 无  
654 - * DENOISE 自然 美白(中)+磨皮(低)+红润(低)  
655 - * SKIN_WHITEN 白肤 美白(强)+磨皮(中)+红润(低)  
656 - * BEAUTY_ILLUSION 柔肤 美白(中)+磨皮(中)+红润(低)  
657 - * BEAUTY_SMOOTH 粉嫩 美白(中)+磨皮(强)+红润(中)  
658 - * BEAUTY_SOFT 嫩肤 美白(中)+磨皮(中)+红润(强)  
659 - */  
660 - new String[]{"BEAUTY_SOFT", "SKIN_WHITEN", "BEAUTY_ILLUSION", "DENOISE",  
661 - "BEAUTY_SMOOTH"}, -1,  
662 - new DialogInterface.OnClickListener() {  
663 - @Override  
664 - public void onClick(DialogInterface dialog, int which) {  
665 - switch (which) {  
666 - case 0:  
667 - mStreamer.getImgTexFilterMgt().setFilter(mStreamer.getGLRender(), BEAUTY_SOFT.getFilter());  
668 - break;  
669 - case 1:  
670 - mStreamer.getImgTexFilterMgt().setFilter(mStreamer.getGLRender(), SKIN_WHITEN.getFilter());  
671 - break;  
672 - case 2:  
673 - mStreamer.getImgTexFilterMgt().setFilter(mStreamer.getGLRender(), BEAUTY_ILLUSION.getFilter());  
674 - break;  
675 - case 3:  
676 - mStreamer.getImgTexFilterMgt().setFilter(mStreamer.getGLRender(), DENOISE.getFilter());  
677 - break;  
678 - case 4:  
679 - mStreamer.getImgTexFilterMgt().setFilter(mStreamer.getGLRender(), BEAUTY_SMOOTH.getFilter());  
680 - break;  
681 - }  
682 - dialog.dismiss();  
683 - }  
684 - })  
685 - .create();  
686 - alertDialog.setCancelable(false);  
687 - alertDialog.show();  
688 - }  
689 -  
690 private IStreamer.OnInfoListener mOnInfoListener = new IStreamer.OnInfoListener() { 925 private IStreamer.OnInfoListener mOnInfoListener = new IStreamer.OnInfoListener() {
691 @Override 926 @Override
692 public void onInfo(int what, int msg1, int msg2) { 927 public void onInfo(int what, int msg1, int msg2) {
@@ -894,4 +1129,33 @@ public class StreamActivity extends Activity { @@ -894,4 +1129,33 @@ public class StreamActivity extends Activity {
894 return ""; 1129 return "";
895 } 1130 }
896 }; 1131 };
  1132 +
  1133 + private VerticalSeekBar.OnSeekBarChangeListener verticalSeekBarlistener = new VerticalSeekBar.OnSeekBarChangeListener() {
  1134 + @Override
  1135 + public void onProgressChanged(VerticalSeekBar seekBar, int progress, boolean fromUser) {
  1136 + Camera.Parameters parameters = mStreamer.getCameraCapture().getCameraParameters();
  1137 + if (parameters != null) {
  1138 + int minValue = parameters.getMinExposureCompensation();
  1139 + int maxValue = parameters.getMaxExposureCompensation();
  1140 + int range = 100 / (maxValue - minValue);
  1141 + parameters.setExposureCompensation(progress / range - maxValue);
  1142 + }
  1143 + mStreamer.getCameraCapture().setCameraParameters(parameters);
  1144 + }
  1145 +
  1146 + @Override
  1147 + public void onStartTrackingTouch(VerticalSeekBar seekBar) {
  1148 +
  1149 + }
  1150 +
  1151 + @Override
  1152 + public void onStopTrackingTouch(VerticalSeekBar seekBar) {
  1153 +
  1154 + }
  1155 +
  1156 + @Override
  1157 + public void onRequestDisallowInterceptTouchEvent(boolean enable) {
  1158 +
  1159 + }
  1160 + };
897 } 1161 }
app/src/main/java/com/cnlive/demo/stream/VerticalSeekBar.java 0 → 100644
  1 +package com.cnlive.demo.stream;
  2 +
  3 +import android.content.Context;
  4 +import android.graphics.drawable.Drawable;
  5 +import android.graphics.drawable.GradientDrawable;
  6 +import android.util.AttributeSet;
  7 +import android.view.Gravity;
  8 +import android.view.MotionEvent;
  9 +import android.view.View;
  10 +import android.widget.FrameLayout;
  11 +import android.widget.TextView;
  12 +
  13 +/**
  14 + * 自定义竖直SeekBar.
  15 + */
  16 +
  17 +public class VerticalSeekBar extends FrameLayout {
  18 + public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
  19 + super(context, attrs, defStyle);
  20 + initialize(context);
  21 + }
  22 +
  23 + public VerticalSeekBar(Context context, AttributeSet attrs) {
  24 + super(context, attrs);
  25 + initialize(context);
  26 + }
  27 +
  28 + public VerticalSeekBar(Context context) {
  29 + super(context);
  30 + initialize(context);
  31 + }
  32 +
  33 + private View mProgressBg;
  34 + private View mSecondaryProgressBg;
  35 + private View mBg;
  36 + private FrameLayout mSlider;
  37 + private int mProgress = 50;
  38 + private int mSecondaryProgress = 50;
  39 + private int mMax = 100;
  40 + private boolean mTrackingTouch = false;
  41 + private OnSeekBarChangeListener mOnSeekBarChangeListener;
  42 + private int mBGSize = 6; //进度条大小
  43 + private int mBGRadius = 20; //进度条圆角
  44 + private int mCircleSize = 50; //圆的大小
  45 + private TextView mTextView; //字
  46 +
  47 +
  48 + public interface OnSeekBarChangeListener {
  49 + void onProgressChanged(VerticalSeekBar seekBar, int progress, boolean fromUser);
  50 +
  51 + void onStartTrackingTouch(VerticalSeekBar seekBar);
  52 +
  53 + void onStopTrackingTouch(VerticalSeekBar seekBar);
  54 +
  55 + void onRequestDisallowInterceptTouchEvent(boolean enable);
  56 + }
  57 +
  58 + private void initialize(Context context) {
  59 + LayoutParams params = new LayoutParams(mBGSize, LayoutParams.MATCH_PARENT);
  60 + params.gravity = Gravity.CENTER_HORIZONTAL;
  61 + mBg = new View(context);
  62 + addView(mBg, params);
  63 +
  64 + GradientDrawable drawable = new GradientDrawable();
  65 + drawable.setColor(0xffbcbab8);
  66 + drawable.setCornerRadius(mBGRadius);
  67 + mBg.setBackgroundDrawable(drawable);
  68 +
  69 + params = new LayoutParams(mBGSize, 0);
  70 + params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
  71 + mSecondaryProgressBg = new View(context);
  72 + addView(mSecondaryProgressBg, params);
  73 +
  74 + drawable = new GradientDrawable();
  75 + drawable.setColor(0xffff5959);
  76 + drawable.setCornerRadius(mBGRadius);
  77 + mSecondaryProgressBg.setBackgroundDrawable(drawable);
  78 +
  79 + params = new LayoutParams(mBGSize, 0);
  80 + params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
  81 + mProgressBg = new View(context);
  82 + addView(mProgressBg, params);
  83 +
  84 + drawable = new GradientDrawable();
  85 + drawable.setColor(0xffff5959);
  86 + drawable.setCornerRadius(mBGRadius);
  87 + mProgressBg.setBackgroundDrawable(drawable);
  88 +
  89 + params = new LayoutParams(mCircleSize, mCircleSize);
  90 + params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
  91 + mSlider = new FrameLayout(context);
  92 + addView(mSlider, params);
  93 +
  94 + drawable = new GradientDrawable();
  95 + drawable.setColor(0xffdddddd);
  96 + drawable.setShape(GradientDrawable.OVAL);
  97 +
  98 + params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
  99 + params.gravity = Gravity.CENTER;
  100 + mTextView = new TextView(context);
  101 + mTextView.setGravity(Gravity.CENTER);
  102 + mTextView.setTextSize(12);
  103 + mTextView.setIncludeFontPadding(false);
  104 + mTextView.setText("0");
  105 + mTextView.setTextColor(0xff666666);
  106 + //mSlider.addView(mTextView, params);
  107 +
  108 + mSlider.setBackgroundDrawable(drawable);
  109 +
  110 + setClickable(true);
  111 + }
  112 +
  113 + public String getText() {
  114 + return mTextView.getText().toString();
  115 + }
  116 +
  117 + public void setmText(String mText) {
  118 + mTextView.setText(mText);
  119 + }
  120 +
  121 + public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) {
  122 + mOnSeekBarChangeListener = l;
  123 + }
  124 +
  125 + public void setThumb(Drawable d) {
  126 + mSlider.setBackgroundDrawable(d);
  127 + }
  128 +
  129 + public void setThumbSize(int w, int h) {
  130 + LayoutParams params = (LayoutParams) mSlider.getLayoutParams();
  131 + params.width = w;
  132 + params.height = h;
  133 + mSlider.setLayoutParams(params);
  134 + }
  135 +
  136 + public void setProgressSize(int size) {
  137 + LayoutParams params = (LayoutParams) mProgressBg.getLayoutParams();
  138 + params.width = size;
  139 + mProgressBg.setLayoutParams(params);
  140 +
  141 + params = (LayoutParams) mSecondaryProgressBg.getLayoutParams();
  142 + params.width = size;
  143 + mSecondaryProgressBg.setLayoutParams(params);
  144 +
  145 + params = (LayoutParams) mBg.getLayoutParams();
  146 + params.width = size;
  147 + mBg.setLayoutParams(params);
  148 + }
  149 +
  150 + public void setProgressBackground(Drawable drawable) {
  151 + mBg.setBackgroundDrawable(drawable);
  152 + }
  153 +
  154 + public void setProgressDrawable(Drawable drawable) {
  155 + mProgressBg.setBackgroundDrawable(drawable);
  156 + }
  157 +
  158 + public void setSecondaryProgressDrawable(Drawable drawable) {
  159 + mSecondaryProgressBg.setBackgroundDrawable(drawable);
  160 + }
  161 +
  162 + public void setMax(int max) {
  163 + mMax = max;
  164 + }
  165 +
  166 + public void setProgress(int progress) {
  167 + setProgress(progress, false);
  168 + }
  169 +
  170 + public int getProgress() {
  171 + return mProgress;
  172 + }
  173 +
  174 + private void setProgress(int progress, boolean fromUser) {
  175 + if (progress < 0)
  176 + progress = 0;
  177 + if (progress > mMax)
  178 + progress = mMax;
  179 +
  180 + if (mProgress != progress) {
  181 + mProgress = progress;
  182 + updateProgress(fromUser);
  183 + }
  184 + mTextView.setText(progress + "");
  185 + }
  186 +
  187 + private void updateProgress(boolean fromUser) {
  188 + int paddingTop = getPaddingTop();
  189 + int paddingBottom = getPaddingBottom();
  190 + int h = getHeight() - paddingTop - paddingBottom;
  191 + if (h > 0) {
  192 + LayoutParams params = (LayoutParams) mProgressBg.getLayoutParams();
  193 + params.height = h * mProgress / mMax;
  194 + mProgressBg.setLayoutParams(params);
  195 +
  196 + params = (LayoutParams) mSlider.getLayoutParams();
  197 + params.bottomMargin = (h - params.height) * mProgress / mMax;
  198 + mSlider.setLayoutParams(params);
  199 + }
  200 + if (mOnSeekBarChangeListener != null) {
  201 + mOnSeekBarChangeListener.onProgressChanged(this, mProgress, fromUser);
  202 + }
  203 + }
  204 +
  205 + public void setSecondaryProgress(int progress) {
  206 + if (progress < 0)
  207 + progress = 0;
  208 + if (progress > mMax)
  209 + progress = mMax;
  210 +
  211 + mSecondaryProgress = progress;
  212 + updateSecondaryProgress();
  213 + }
  214 +
  215 + private void updateSecondaryProgress() {
  216 + int paddingTop = getPaddingTop();
  217 + int paddingBottom = getPaddingBottom();
  218 + int h = getHeight() - paddingTop - paddingBottom;
  219 + if (h > 0) {
  220 + LayoutParams params = (LayoutParams) mSecondaryProgressBg.getLayoutParams();
  221 + params.height = h * mSecondaryProgress / mMax;
  222 + mSecondaryProgressBg.setLayoutParams(params);
  223 + }
  224 + }
  225 +
  226 +
  227 + @Override
  228 + public boolean dispatchTouchEvent(MotionEvent ev) {
  229 + int action = ev.getAction();
  230 + int y = (int) ev.getY();
  231 + int paddingTop = getPaddingTop();
  232 + int paddingBottom = getPaddingBottom();
  233 + int h = getHeight() - paddingTop - paddingBottom;
  234 + if (y < paddingTop) {
  235 + y = paddingTop;
  236 + }
  237 + if (y > h + paddingTop) {
  238 + y = h + paddingTop;
  239 + }
  240 + y -= paddingTop;
  241 + if (action == MotionEvent.ACTION_DOWN) {
  242 + if (mOnSeekBarChangeListener != null) {
  243 + mOnSeekBarChangeListener.onRequestDisallowInterceptTouchEvent(true);
  244 + }
  245 + int progress = mMax * (h - y) / h;
  246 + if (progress != mProgress) {
  247 + if (mTrackingTouch == false) {
  248 + mTrackingTouch = true;
  249 + if (mOnSeekBarChangeListener != null) {
  250 + mOnSeekBarChangeListener.onStartTrackingTouch(this);
  251 + }
  252 + }
  253 + setProgress(progress, true);
  254 + }
  255 + } else if (action == MotionEvent.ACTION_MOVE) {
  256 + int progress = mMax * (h - y) / h;
  257 + if (progress != mProgress) {
  258 + if (mTrackingTouch == false) {
  259 + mTrackingTouch = true;
  260 + if (mOnSeekBarChangeListener != null) {
  261 + mOnSeekBarChangeListener.onStartTrackingTouch(this);
  262 + }
  263 + }
  264 + setProgress(progress, true);
  265 + }
  266 + } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
  267 + if (mOnSeekBarChangeListener != null) {
  268 + mOnSeekBarChangeListener.onRequestDisallowInterceptTouchEvent(false);
  269 + }
  270 + mTrackingTouch = false;
  271 + if (mOnSeekBarChangeListener != null) {
  272 + mOnSeekBarChangeListener.onStopTrackingTouch(this);
  273 + }
  274 + }
  275 + return super.dispatchTouchEvent(ev);
  276 + }
  277 +
  278 + @Override
  279 + protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  280 + updateProgress(false);
  281 + //updateSecondaryProgress();
  282 + super.onSizeChanged(w, h, oldw, oldh);
  283 + }
  284 +
  285 +}
app/src/main/res/anim/slide_in_bottom.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:android="http://schemas.android.com/apk/res/android">
  3 + <translate android:fromYDelta="100%" android:toYDelta="0%"
  4 + android:duration="300" android:startOffset="0" />
  5 +</set>
0 \ No newline at end of file 6 \ No newline at end of file
app/src/main/res/anim/slide_in_top.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:android="http://schemas.android.com/apk/res/android">
  3 + <translate android:fromYDelta="-100%" android:toYDelta="0%"
  4 + android:duration="300" android:startOffset="0" />
  5 +</set>
0 \ No newline at end of file 6 \ No newline at end of file
app/src/main/res/anim/slide_left_in.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set
  3 + xmlns:android="http://schemas.android.com/apk/res/android">
  4 + <translate android:duration="300" android:fromXDelta="-100.0%p" android:toXDelta="0.0" />
  5 +</set>
app/src/main/res/anim/slide_left_out.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set
  3 + xmlns:android="http://schemas.android.com/apk/res/android">
  4 + <translate android:duration="300" android:fromXDelta="0.0" android:toXDelta="-100.0%p" />
  5 +</set>
app/src/main/res/anim/slide_out_bottom.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:android="http://schemas.android.com/apk/res/android">
  3 + <translate android:fromYDelta="0%" android:toYDelta="100%"
  4 + android:duration="300" android:startOffset="0" />
  5 +</set>
0 \ No newline at end of file 6 \ No newline at end of file
app/src/main/res/anim/slide_out_top.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:android="http://schemas.android.com/apk/res/android">
  3 + <translate android:fromYDelta="0%" android:toYDelta="-100%"
  4 + android:duration="300" android:startOffset="0" />
  5 +</set>
0 \ No newline at end of file 6 \ No newline at end of file
app/src/main/res/anim/slide_right_in.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set
  3 + xmlns:android="http://schemas.android.com/apk/res/android">
  4 + <translate android:duration="300" android:fromXDelta="100.0%p" android:toXDelta="0.0" />
  5 +</set>
app/src/main/res/anim/slide_right_out.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set
  3 + xmlns:android="http://schemas.android.com/apk/res/android">
  4 + <translate android:duration="300" android:fromXDelta="0.0" android:toXDelta="100.0%p" />
  5 +</set>
app/src/main/res/anim/slide_stand.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:android="http://schemas.android.com/apk/res/android">
  3 + <translate
  4 + android:duration="300"
  5 + android:fromYDelta="0%"
  6 + android:startOffset="0"
  7 + android:toYDelta="0%" />
  8 +</set>
0 \ No newline at end of file 9 \ No newline at end of file
app/src/main/res/drawable-xxhdpi/close.png 0 → 100644

498 Bytes

app/src/main/res/drawable-xxhdpi/exposure.png 0 → 100644

1.04 KB

app/src/main/res/drawable-xxhdpi/flash.png 0 → 100644

750 Bytes

app/src/main/res/drawable-xxhdpi/float_back.png 0 → 100644

1.2 KB

app/src/main/res/drawable-xxhdpi/float_close.png 0 → 100644

1.1 KB

app/src/main/res/drawable-xxhdpi/float_view.png 0 → 100644

688 Bytes

app/src/main/res/drawable-xxhdpi/icon_record_close_off.png deleted 100644 → 0

5.67 KB

app/src/main/res/drawable-xxhdpi/icon_record_flash_off.png deleted 100644 → 0

3.77 KB

app/src/main/res/drawable-xxhdpi/icon_record_flip_off.png deleted 100644 → 0

4.03 KB

app/src/main/res/drawable-xxhdpi/switch_camera.png 0 → 100644

975 Bytes

app/src/main/res/layout/activity_float.xml 0 → 100644
  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:layout_width="match_parent"
  5 + android:layout_height="match_parent"
  6 + android:background="#00000000"
  7 + tools:context="com.cnlive.demo.stream.FloatActivity">
  8 +
  9 + <LinearLayout
  10 + android:layout_width="match_parent"
  11 + android:layout_height="48dp"
  12 + android:background="@color/colorAccent">
  13 +
  14 + <ImageView
  15 + android:id="@+id/float_back"
  16 + android:layout_width="25dp"
  17 + android:layout_height="25dp"
  18 + android:layout_alignParentLeft="true"
  19 + android:layout_alignParentTop="true"
  20 + android:layout_gravity="center_vertical"
  21 + android:layout_marginLeft="10dp"
  22 + android:scaleType="centerCrop"
  23 + android:src="@drawable/float_back" />
  24 +
  25 + </LinearLayout>
  26 +</RelativeLayout>
app/src/main/res/layout/activity_stream.xml
@@ -19,6 +19,18 @@ @@ -19,6 +19,18 @@
19 android:layout_alignParentBottom="true" 19 android:layout_alignParentBottom="true"
20 android:layout_alignParentTop="true" /> 20 android:layout_alignParentTop="true" />
21 21
  22 + <com.cnlive.demo.stream.VerticalSeekBar
  23 + android:id="@+id/exposure_seekBar"
  24 + android:layout_width="wrap_content"
  25 + android:layout_height="200dp"
  26 + android:layout_alignParentRight="true"
  27 + android:layout_marginRight="20dp"
  28 + android:layout_marginTop="100dp"
  29 + android:progressBackgroundTint="#9b9b9b"
  30 + android:progressTint="@color/colorAccent"
  31 + android:thumbTint="#C0303030"
  32 + android:visibility="gone" />
  33 +
22 <include 34 <include
23 android:id="@+id/actionbar" 35 android:id="@+id/actionbar"
24 layout="@layout/titlebar" 36 layout="@layout/titlebar"
app/src/main/res/layout/bottombar.xml
@@ -21,6 +21,56 @@ @@ -21,6 +21,56 @@
21 android:layout_marginBottom="10dp" 21 android:layout_marginBottom="10dp"
22 android:orientation="horizontal"> 22 android:orientation="horizontal">
23 23
  24 + <Button
  25 + android:id="@+id/audio_mix"
  26 + android:layout_width="0dp"
  27 + android:layout_height="wrap_content"
  28 + android:layout_marginLeft="10dp"
  29 + android:layout_weight="1"
  30 + android:background="#11123456"
  31 + android:text="音频滤镜"
  32 + android:textColor="@android:color/white"
  33 + android:textSize="14sp" />
  34 +
  35 + <Button
  36 + android:id="@+id/bgm_filter"
  37 + android:layout_width="0dp"
  38 + android:layout_height="wrap_content"
  39 + android:layout_marginLeft="10dp"
  40 + android:layout_weight="1"
  41 + android:background="#11123456"
  42 + android:text="bgm升降调"
  43 + android:textColor="@android:color/white" />
  44 +
  45 + <Button
  46 + android:id="@+id/click_to_capture_screenshot"
  47 + android:layout_width="0dp"
  48 + android:layout_height="wrap_content"
  49 + android:layout_marginLeft="10dp"
  50 + android:layout_weight="1"
  51 + android:background="#11123456"
  52 + android:text="截屏"
  53 + android:textColor="@android:color/white" />
  54 +
  55 + <CheckBox
  56 + android:id="@+id/bg_img"
  57 + android:layout_width="0dp"
  58 + android:layout_height="wrap_content"
  59 + android:layout_gravity="center"
  60 + android:layout_marginLeft="10dp"
  61 + android:layout_weight="1"
  62 + android:background="#11123456"
  63 + android:text="背景图推流"
  64 + android:textColor="@android:color/white"
  65 + android:textSize="14sp" />
  66 + </LinearLayout>
  67 +
  68 + <LinearLayout
  69 + android:layout_width="match_parent"
  70 + android:layout_height="wrap_content"
  71 + android:layout_marginBottom="10dp"
  72 + android:orientation="horizontal">
  73 +
24 <CheckBox 74 <CheckBox
25 android:id="@+id/watermark" 75 android:id="@+id/watermark"
26 android:layout_width="0dp" 76 android:layout_width="0dp"
@@ -126,7 +176,7 @@ @@ -126,7 +176,7 @@
126 android:layout_weight="1" 176 android:layout_weight="1"
127 android:background="#11123456" 177 android:background="#11123456"
128 android:checked="true" 178 android:checked="true"
129 - android:text="美颜" 179 + android:text="美颜滤镜"
130 android:textColor="@android:color/white" 180 android:textColor="@android:color/white"
131 android:textSize="14sp"></CheckBox> 181 android:textSize="14sp"></CheckBox>
132 182
app/src/main/res/layout/float_preview.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<com.cnlive.demo.stream.FloatView
  3 + xmlns:android="http://schemas.android.com/apk/res/android"
  4 + android:layout_width="wrap_content"
  5 + android:layout_height="wrap_content"
  6 + android:orientation="horizontal">
  7 +
  8 +</com.cnlive.demo.stream.FloatView>
0 \ No newline at end of file 9 \ No newline at end of file
app/src/main/res/layout/titlebar.xml
@@ -17,36 +17,56 @@ @@ -17,36 +17,56 @@
17 android:textSize="19sp" /> 17 android:textSize="19sp" />
18 18
19 <ImageView 19 <ImageView
  20 + android:id="@+id/add"
  21 + android:layout_width="22dp"
  22 + android:layout_height="22dp"
  23 + android:layout_gravity="center_vertical"
  24 + android:layout_marginRight="10dp"
  25 + android:layout_marginTop="8dp"
  26 + android:layout_toLeftOf="@+id/exposure"
  27 + android:background="@drawable/float_view" />
  28 +
  29 + <ImageView
  30 + android:id="@+id/exposure"
  31 + android:layout_width="22dp"
  32 + android:layout_height="22dp"
  33 + android:layout_gravity="center_vertical"
  34 + android:layout_marginRight="10dp"
  35 + android:layout_marginTop="8dp"
  36 + android:layout_toLeftOf="@+id/flash"
  37 + android:background="@drawable/exposure" />
  38 +
  39 + <ImageView
20 android:id="@+id/flash" 40 android:id="@+id/flash"
21 - android:layout_width="wrap_content"  
22 - android:layout_height="wrap_content" 41 + android:layout_width="22dp"
  42 + android:layout_height="22dp"
23 android:layout_gravity="center_vertical" 43 android:layout_gravity="center_vertical"
24 android:layout_marginRight="12dp" 44 android:layout_marginRight="12dp"
25 android:layout_marginTop="8dp" 45 android:layout_marginTop="8dp"
26 android:layout_toLeftOf="@+id/switch_cam" 46 android:layout_toLeftOf="@+id/switch_cam"
27 - android:background="@drawable/icon_record_flash_off"></ImageView> 47 + android:background="@drawable/flash"></ImageView>
28 48
29 <ImageView 49 <ImageView
30 android:id="@+id/switch_cam" 50 android:id="@+id/switch_cam"
31 - android:layout_width="wrap_content"  
32 - android:layout_height="wrap_content" 51 + android:layout_width="22dp"
  52 + android:layout_height="22dp"
33 android:layout_alignParentTop="true" 53 android:layout_alignParentTop="true"
34 android:layout_gravity="center_vertical" 54 android:layout_gravity="center_vertical"
35 android:layout_marginRight="12dp" 55 android:layout_marginRight="12dp"
36 android:layout_marginTop="8dp" 56 android:layout_marginTop="8dp"
37 android:layout_toLeftOf="@+id/backoff" 57 android:layout_toLeftOf="@+id/backoff"
38 - android:background="@drawable/icon_record_flip_off" /> 58 + android:background="@drawable/switch_camera" />
39 59
40 <ImageView 60 <ImageView
41 android:id="@+id/backoff" 61 android:id="@+id/backoff"
42 - android:layout_width="wrap_content"  
43 - android:layout_height="wrap_content" 62 + android:layout_width="22dp"
  63 + android:layout_height="22dp"
44 android:layout_alignParentEnd="true" 64 android:layout_alignParentEnd="true"
45 android:layout_alignParentRight="true" 65 android:layout_alignParentRight="true"
46 android:layout_alignParentTop="true" 66 android:layout_alignParentTop="true"
47 android:layout_gravity="center_vertical" 67 android:layout_gravity="center_vertical"
48 android:layout_marginRight="2dp" 68 android:layout_marginRight="2dp"
49 android:layout_marginTop="8dp" 69 android:layout_marginTop="8dp"
50 - android:background="@drawable/icon_record_close_off" /> 70 + android:background="@drawable/close" />
51 71
52 </RelativeLayout> 72 </RelativeLayout>
53 \ No newline at end of file 73 \ No newline at end of file
app/src/main/res/raw/beep.ogg 0 → 100644
No preview for this file type
app/src/main/res/raw/fragment_sharder.glsl 0 → 100644
  1 +#extension GL_OES_EGL_image_external : require
  2 +precision mediump float;
  3 +uniform samplerExternalOES texture;
  4 +varying vec2 v_TexCoordinate;
  5 +
  6 +void main () {
  7 + vec4 color = texture2D(texture, v_TexCoordinate);
  8 + gl_FragColor = color;
  9 +}
0 \ No newline at end of file 10 \ No newline at end of file
app/src/main/res/raw/fugu.acv 0 → 100644
No preview for this file type
app/src/main/res/raw/jiaopian.acv 0 → 100644
No preview for this file type
app/src/main/res/raw/realm_properties 0 → 100644
  1 +test: test
  2 +admin: OBF:1u2a1toa1w8v1tok1u30,admin
app/src/main/res/raw/tone_cuver_sample.acv 0 → 100644
No preview for this file type
app/src/main/res/raw/vetext_sharder.glsl 0 → 100644
  1 +attribute vec4 vPosition;
  2 +attribute vec4 vTexCoordinate;
  3 +uniform mat4 textureTransform;
  4 +varying vec2 v_TexCoordinate;
  5 +
  6 +void main () {
  7 + v_TexCoordinate = (textureTransform * vTexCoordinate).xy;
  8 + gl_Position = vPosition;
  9 +}
0 \ No newline at end of file 10 \ No newline at end of file
app/src/main/res/values/styles.xml
@@ -8,4 +8,28 @@ @@ -8,4 +8,28 @@
8 <item name="colorAccent">@color/colorAccent</item> 8 <item name="colorAccent">@color/colorAccent</item>
9 </style> 9 </style>
10 10
  11 + <style name="DefaultAnimation" parent="@android:style/Animation.Activity">
  12 + <item name="android:activityOpenEnterAnimation">@anim/slide_right_in</item>
  13 + <item name="android:activityOpenExitAnimation">@anim/slide_left_out</item>
  14 + <item name="android:activityCloseEnterAnimation">@anim/slide_left_in</item>
  15 + <item name="android:activityCloseExitAnimation">@anim/slide_right_out</item>
  16 + </style>
  17 +
  18 +
  19 + <style name="Theme.NoTitleBar" parent="Theme.AppCompat.Light.NoActionBar">
  20 + <item name="android:windowContentOverlay">@null</item>
  21 + <item name="android:windowAnimationStyle">@style/DefaultAnimation</item>
  22 + </style>
  23 +
  24 + <style name="RiseAnimation" parent="@android:style/Animation.Activity">
  25 + <item name="android:activityOpenEnterAnimation">@anim/slide_in_bottom</item>
  26 + <item name="android:activityOpenExitAnimation">@anim/slide_stand</item>
  27 + <item name="android:activityCloseEnterAnimation">@anim/slide_left_in</item>
  28 + <item name="android:activityCloseExitAnimation">@anim/slide_right_out</item>
  29 + </style>
  30 +
  31 + <style name="Theme.RiseAnimation" parent="@style/Theme.NoTitleBar">
  32 + <item name="android:windowAnimationStyle">@style/RiseAnimation</item>
  33 + </style>
  34 +
11 </resources> 35 </resources>