├── .gitmodules
├── settings.gradle
├── DanmakuFlameMaster
├── src
│ ├── main
│ │ ├── lint.xml
│ │ ├── libs
│ │ │ ├── mips
│ │ │ │ └── libndkbitmap.so
│ │ │ ├── x86
│ │ │ │ └── libndkbitmap.so
│ │ │ ├── armeabi
│ │ │ │ └── libndkbitmap.so
│ │ │ └── armeabi-v7a
│ │ │ │ └── libndkbitmap.so
│ │ ├── java
│ │ │ ├── master
│ │ │ │ └── flame
│ │ │ │ │ └── danmaku
│ │ │ │ │ ├── danmaku
│ │ │ │ │ ├── model
│ │ │ │ │ │ ├── AlphaValue.java
│ │ │ │ │ │ ├── IDanmakuIterator.java
│ │ │ │ │ │ ├── android
│ │ │ │ │ │ │ ├── DrawingCachePoolManager.java
│ │ │ │ │ │ │ ├── BaseCacheStuffer.java
│ │ │ │ │ │ │ ├── DrawingCache.java
│ │ │ │ │ │ │ ├── SimpleTextCacheStuffer.java
│ │ │ │ │ │ │ ├── SpannedCacheStuffer.java
│ │ │ │ │ │ │ └── DrawingCacheHolder.java
│ │ │ │ │ │ ├── IDrawingCache.java
│ │ │ │ │ │ ├── GlobalFlagValues.java
│ │ │ │ │ │ ├── Duration.java
│ │ │ │ │ │ ├── objectpool
│ │ │ │ │ │ │ ├── Pool.java
│ │ │ │ │ │ │ ├── PoolableManager.java
│ │ │ │ │ │ │ ├── Poolable.java
│ │ │ │ │ │ │ ├── SynchronizedPool.java
│ │ │ │ │ │ │ ├── Pools.java
│ │ │ │ │ │ │ └── FinitePool.java
│ │ │ │ │ │ ├── ICacheManager.java
│ │ │ │ │ │ ├── AbsDisplayer.java
│ │ │ │ │ │ ├── FBDanmaku.java
│ │ │ │ │ │ ├── DanmakuTimer.java
│ │ │ │ │ │ ├── IDanmakus.java
│ │ │ │ │ │ ├── Danmaku.java
│ │ │ │ │ │ ├── IDisplayer.java
│ │ │ │ │ │ ├── L2RDanmaku.java
│ │ │ │ │ │ ├── FTDanmaku.java
│ │ │ │ │ │ ├── R2LDanmaku.java
│ │ │ │ │ │ ├── BaseDanmaku.java
│ │ │ │ │ │ └── SpecialDanmaku.java
│ │ │ │ │ ├── util
│ │ │ │ │ │ ├── AndroidUtils.java
│ │ │ │ │ │ ├── IOUtils.java
│ │ │ │ │ │ └── DanmakuUtils.java
│ │ │ │ │ ├── loader
│ │ │ │ │ │ ├── IllegalDataException.java
│ │ │ │ │ │ ├── ILoader.java
│ │ │ │ │ │ └── android
│ │ │ │ │ │ │ ├── DanmakuLoaderFactory.java
│ │ │ │ │ │ │ ├── AcFunDanmakuLoader.java
│ │ │ │ │ │ │ └── BiliDanmakuLoader.java
│ │ │ │ │ ├── renderer
│ │ │ │ │ │ ├── Renderer.java
│ │ │ │ │ │ ├── IRenderer.java
│ │ │ │ │ │ └── android
│ │ │ │ │ │ │ └── DanmakuRenderer.java
│ │ │ │ │ └── parser
│ │ │ │ │ │ ├── IDataSource.java
│ │ │ │ │ │ ├── android
│ │ │ │ │ │ ├── JSONSource.java
│ │ │ │ │ │ ├── AndroidFileSource.java
│ │ │ │ │ │ ├── AcFunDanmakuParser.java
│ │ │ │ │ │ └── BiliDanmukuParser.java
│ │ │ │ │ │ └── BaseDanmakuParser.java
│ │ │ │ │ ├── controller
│ │ │ │ │ ├── UpdateThread.java
│ │ │ │ │ ├── IDanmakuViewController.java
│ │ │ │ │ ├── IDrawTask.java
│ │ │ │ │ ├── DrawHelper.java
│ │ │ │ │ └── IDanmakuView.java
│ │ │ │ │ └── ui
│ │ │ │ │ └── widget
│ │ │ │ │ └── DanmakuTouchHelper.java
│ │ │ └── tv
│ │ │ │ └── cjump
│ │ │ │ └── jni
│ │ │ │ ├── DeviceUtils.java
│ │ │ │ └── NativeBitmapFactory.java
│ │ ├── .settings
│ │ │ └── org.eclipse.jdt.ui.prefs
│ │ ├── .classpath
│ │ ├── project.properties
│ │ ├── proguard-project.txt
│ │ ├── .project
│ │ ├── AndroidManifest.xml
│ │ └── build.xml
│ └── androidTest
│ │ └── java
│ │ └── tv
│ │ └── cjump
│ │ └── jni
│ │ └── NativeBitmapFactoryTest.java
├── gradle.properties
└── build.gradle
├── gradle
├── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle-bintray-upload.gradle
└── gradle-mvn-push.gradle
├── Sample
├── src
│ └── main
│ │ ├── ic_launcher-web.png
│ │ ├── res
│ │ ├── drawable-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-xhdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-xxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── values
│ │ │ ├── dimens.xml
│ │ │ ├── styles.xml
│ │ │ └── strings.xml
│ │ ├── menu
│ │ │ └── main.xml
│ │ └── layout
│ │ │ ├── activity_main.xml
│ │ │ └── media_controller.xml
│ │ ├── .settings
│ │ └── org.eclipse.jdt.core.prefs
│ │ ├── .classpath
│ │ ├── project.properties
│ │ ├── .project
│ │ └── AndroidManifest.xml
└── build.gradle
├── .gitignore
├── gradle.properties
├── .travis.yml
├── README.md
├── gradlew.bat
├── gradlew
└── LICENSE
/.gitmodules:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':DanmakuFlameMaster', ':Sample'
2 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/Sample/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/HEAD/Sample/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/DanmakuFlameMaster/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_NAME=DanmakuFlameMaster
2 | BINTRAY_POM_NAME=dfm
3 | POM_ARTIFACT_ID=dfm
4 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/HEAD/Sample/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/HEAD/Sample/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/HEAD/Sample/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Sample/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/HEAD/Sample/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/libs/mips/libndkbitmap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/HEAD/DanmakuFlameMaster/src/main/libs/mips/libndkbitmap.so
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/libs/x86/libndkbitmap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/HEAD/DanmakuFlameMaster/src/main/libs/x86/libndkbitmap.so
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/libs/armeabi/libndkbitmap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/HEAD/DanmakuFlameMaster/src/main/libs/armeabi/libndkbitmap.so
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/libs/armeabi-v7a/libndkbitmap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/HEAD/DanmakuFlameMaster/src/main/libs/armeabi-v7a/libndkbitmap.so
--------------------------------------------------------------------------------
/Sample/src/main/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/Sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 0dp
4 | 0dp
5 |
6 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/AlphaValue.java:
--------------------------------------------------------------------------------
1 |
2 | package master.flame.danmaku.danmaku.model;
3 |
4 | public class AlphaValue {
5 |
6 | public static int MAX = 255;
7 |
8 | public static int TRANSPARENT = 0;
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/Sample/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #
2 | #Sat Feb 01 20:41:29 CET 2014
3 | distributionBase=GRADLE_USER_HOME
4 | distributionPath=wrapper/dists
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 | distributionUrl=http\://services.gradle.org/distributions/gradle-2.2.1-all.zip
8 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/IDanmakuIterator.java:
--------------------------------------------------------------------------------
1 | package master.flame.danmaku.danmaku.model;
2 |
3 | public interface IDanmakuIterator {
4 |
5 | public BaseDanmaku next();
6 |
7 | public boolean hasNext();
8 |
9 | public void reset();
10 |
11 | public void remove();
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/.settings/org.eclipse.jdt.ui.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | formatter_profile=_AndroidCodeStyle
3 | formatter_settings_version=12
4 | org.eclipse.jdt.ui.ignorelowercasenames=true
5 | org.eclipse.jdt.ui.importorder=android;com;dalvik;gov;junit;libcore;net;org;java;javax;
6 | org.eclipse.jdt.ui.ondemandthreshold=99
7 | org.eclipse.jdt.ui.staticondemandthreshold=99
8 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/util/AndroidUtils.java:
--------------------------------------------------------------------------------
1 |
2 | package master.flame.danmaku.danmaku.util;
3 |
4 | import android.app.ActivityManager;
5 | import android.content.Context;
6 |
7 | public class AndroidUtils {
8 |
9 | public static int getMemoryClass(final Context context) {
10 | return ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE))
11 | .getMemoryClass();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 | *.com
5 | *.class
6 | *.dll
7 | *.exe
8 | *.o
9 |
10 | # files for the dex VM
11 | *.dex
12 |
13 | # Java class files
14 | *.class
15 |
16 | # generated files
17 | bin/
18 | gen/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Intellij project files
27 | *.iml
28 | *.ipr
29 | *.iws
30 | .idea/
31 | .DS_Store
32 | .idea/
33 | .gradle
34 | build/
35 | *.iml
36 | out/
--------------------------------------------------------------------------------
/Sample/src/main/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/controller/UpdateThread.java:
--------------------------------------------------------------------------------
1 |
2 | package master.flame.danmaku.controller;
3 |
4 | public class UpdateThread extends Thread {
5 |
6 | public UpdateThread(String name) {
7 | super(name);
8 | }
9 |
10 | volatile boolean mIsQuited;
11 |
12 | public void quit() {
13 | mIsQuited = true;
14 | }
15 |
16 | public boolean isQuited() {
17 | return mIsQuited;
18 | }
19 |
20 | @Override
21 | public void run() {
22 | if (mIsQuited)
23 | return;
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/android/DrawingCachePoolManager.java:
--------------------------------------------------------------------------------
1 |
2 | package master.flame.danmaku.danmaku.model.android;
3 |
4 | import master.flame.danmaku.danmaku.model.objectpool.PoolableManager;
5 |
6 | public class DrawingCachePoolManager implements PoolableManager {
7 |
8 | @Override
9 | public DrawingCache newInstance() {
10 | return null;
11 | }
12 |
13 | @Override
14 | public void onAcquired(DrawingCache element) {
15 |
16 | }
17 |
18 | @Override
19 | public void onReleased(DrawingCache element) {
20 |
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/controller/IDanmakuViewController.java:
--------------------------------------------------------------------------------
1 | package master.flame.danmaku.controller;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * For internal control. DO NOT ACCESS this interface.
7 | */
8 | public interface IDanmakuViewController {
9 |
10 | public boolean isViewReady();
11 |
12 | public int getWidth();
13 |
14 | public int getHeight();
15 |
16 | public Context getContext();
17 |
18 | public long drawDanmakus();
19 |
20 | public void clear();
21 |
22 | public boolean isHardwareAccelerated();
23 |
24 | public boolean isDanmakuDrawingCacheEnabled();
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/IDrawingCache.java:
--------------------------------------------------------------------------------
1 |
2 | package master.flame.danmaku.danmaku.model;
3 |
4 | public interface IDrawingCache {
5 |
6 | public void build(int w, int h, int density, boolean checkSizeEquals);
7 |
8 | public void erase();
9 |
10 | public T get();
11 |
12 | public void destroy();
13 |
14 | public int size();
15 |
16 | public int width();
17 |
18 | public int height();
19 |
20 | public boolean hasReferences();
21 |
22 | public void increaseReference();
23 |
24 | public void decreaseReference();
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 | android.library=true
16 | source.dir=java
17 |
--------------------------------------------------------------------------------
/Sample/src/main/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-17
15 | android.library.reference.1=../../../DanmakuFlameMaster/src/main
16 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/GlobalFlagValues.java:
--------------------------------------------------------------------------------
1 | package master.flame.danmaku.danmaku.model;
2 |
3 | public class GlobalFlagValues {
4 |
5 | public int MEASURE_RESET_FLAG = 0;
6 | public int VISIBLE_RESET_FLAG = 0;
7 | public int FILTER_RESET_FLAG = 0;
8 |
9 | public void resetAll() {
10 | VISIBLE_RESET_FLAG = 0;
11 | MEASURE_RESET_FLAG = 0;
12 | FILTER_RESET_FLAG = 0;
13 | }
14 |
15 | public void updateVisibleFlag() {
16 | VISIBLE_RESET_FLAG++;
17 | }
18 |
19 | public void updateMeasureFlag() {
20 | MEASURE_RESET_FLAG++;
21 | }
22 |
23 | public void updateFilterFlag() {
24 | FILTER_RESET_FLAG++;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | VERSION_CODE=3900
2 | VERSION_NAME=0.3.9
3 | GROUP=com.github.ctiao
4 | POM_NAME=dfm
5 | POM_ARTIFACT_ID=common
6 | POM_PACKAGING=aar
7 |
8 | POM_DESCRIPTION=A Danmaku render library.
9 | POM_URL=https://github.com/ctiao/DanmakuFlameMaster
10 | POM_SCM_URL=https://github.com/ctiao/DanmakuFlameMaster
11 | POM_SCM_CONNECTION=scm:git:git://github.com/ctiao/DanmakuFlameMaster.git
12 | POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/ctiao/DanmakuFlameMaster.git
13 |
14 | POM_LICENCE_NAME=The Apache Software License, Version 2.0
15 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
16 | POM_LICENCE_DIST=repo
17 |
18 | POM_DEVELOPER_ID=calmer91
19 | POM_DEVELOPER_NAME=Chen Hui
20 | POM_DEVELOPER_EMAIL=calmer91@gmail.com
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | jdk: oraclejdk7
3 | env:
4 | matrix:
5 | - ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a
6 |
7 | android:
8 | components:
9 | - build-tools-19.1.0
10 |
11 | before_script:
12 | # Create and start emulator
13 | - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
14 | - emulator -avd test -no-skin -no-audio -no-window &
15 | - adb wait-for-device
16 | - adb shell input keyevent 82 &
17 |
18 | script:
19 | "./gradlew check -i"
20 |
21 | after_failure:
22 | - cat /home/travis/build/Bilibili/DanmakuFlameMaster/DanmakuFlameMaster/build/outputs/lint-results.html
23 | - cat /home/travis/build/Bilibili/DanmakuFlameMaster/DanmakuFlameMaster/build/outputs/lint-results.xml
24 |
--------------------------------------------------------------------------------
/Sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/loader/IllegalDataException.java:
--------------------------------------------------------------------------------
1 | package master.flame.danmaku.danmaku.loader;
2 | /**
3 | * Thrown when data is loading which can not be reasonably deal with.
4 | * @author yrom
5 | *
6 | */
7 | public class IllegalDataException extends Exception {
8 |
9 | private static final long serialVersionUID = 10441759254L;
10 |
11 | public IllegalDataException() {
12 | super();
13 | }
14 |
15 | public IllegalDataException(String detailMessage, Throwable throwable) {
16 | super(detailMessage, throwable);
17 | }
18 |
19 | public IllegalDataException(String detailMessage) {
20 | super(detailMessage);
21 | }
22 |
23 | public IllegalDataException(Throwable throwable) {
24 | super(throwable);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/Duration.java:
--------------------------------------------------------------------------------
1 |
2 | package master.flame.danmaku.danmaku.model;
3 |
4 | public class Duration {
5 |
6 | private long mInitialDuration;
7 |
8 | private float factor = 1.0f;
9 |
10 | public long value;
11 |
12 | public Duration(long initialDuration) {
13 | mInitialDuration = initialDuration;
14 | value = initialDuration;
15 | }
16 |
17 | public void setValue(long initialDuration) {
18 | mInitialDuration = initialDuration;
19 | value = (long) (mInitialDuration * factor);
20 | }
21 |
22 | public void setFactor(float f) {
23 | if (factor != f) {
24 | factor = f;
25 | value = (long) (mInitialDuration * f);
26 | }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/Sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Danmaku Flame Master
5 |
6 | Settings
7 |
8 |
9 | hide
10 | show
11 | pause
12 | resume
13 | 发送一条(纯文字)
14 | 发送一条(图文)
15 | 定时发送
16 | 取消定时
17 |
18 | release
19 | 旋转屏幕
20 |
21 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/renderer/Renderer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.renderer;
18 |
19 | public abstract class Renderer implements IRenderer {
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/objectpool/Pool.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model.objectpool;
18 |
19 | public interface Pool> {
20 | T acquire();
21 |
22 | void release(T element);
23 | }
24 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/ICacheManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model;
18 |
19 | /**
20 | * Created by ch on 15-11-15.
21 | */
22 | public interface ICacheManager {
23 | void addDanmaku(BaseDanmaku danmaku);
24 | }
25 |
--------------------------------------------------------------------------------
/Sample/src/main/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | Sample
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/objectpool/PoolableManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model.objectpool;
18 |
19 | public interface PoolableManager> {
20 | T newInstance();
21 |
22 | void onAcquired(T element);
23 |
24 | void onReleased(T element);
25 | }
26 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | DanmakuFlameMaster
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/objectpool/Poolable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model.objectpool;
18 |
19 | public interface Poolable {
20 | void setNextPoolable(T element);
21 |
22 | T getNextPoolable();
23 |
24 | boolean isPooled();
25 |
26 | void setPooled(boolean isPooled);
27 | }
28 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/parser/IDataSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.parser;
18 |
19 | public interface IDataSource {
20 | String SCHEME_HTTP_TAG = "http";
21 | String SCHEME_HTTPS_TAG = "https";
22 | String SCHEME_FILE_TAG = "file";
23 |
24 | public T data();
25 |
26 | public void release();
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/AbsDisplayer.java:
--------------------------------------------------------------------------------
1 | package master.flame.danmaku.danmaku.model;
2 |
3 | import master.flame.danmaku.danmaku.model.android.BaseCacheStuffer;
4 |
5 | public abstract class AbsDisplayer implements IDisplayer {
6 |
7 | public abstract T getExtraData();
8 |
9 | public abstract void setExtraData(T data);
10 |
11 | @Override
12 | public boolean isHardwareAccelerated() {
13 | return false;
14 | }
15 |
16 | public abstract void drawDanmaku(BaseDanmaku danmaku, T canvas, float left, float top, boolean quickly);
17 |
18 | public abstract void clearTextHeightCache();
19 |
20 | public abstract void setTypeFace(F font);
21 |
22 | public abstract void setFakeBoldText(boolean bold);
23 |
24 | public abstract void setTransparency(int newTransparency);
25 |
26 | public abstract void setScaleTextSizeFactor(float factor);
27 |
28 | public abstract void setCacheStuffer(BaseCacheStuffer cacheStuffer);
29 |
30 | public abstract BaseCacheStuffer getCacheStuffer();
31 | }
32 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/FBDanmaku.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model;
18 |
19 | public class FBDanmaku extends FTDanmaku {
20 |
21 | public FBDanmaku(Duration duration) {
22 | super(duration);
23 | }
24 |
25 | @Override
26 | public int getType() {
27 | return TYPE_FIX_BOTTOM;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/Sample/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | apply plugin: 'com.android.application'
18 |
19 | dependencies {
20 | compile project(':DanmakuFlameMaster')
21 | }
22 | android {
23 | compileSdkVersion 19
24 | buildToolsVersion "19.1.0"
25 |
26 | defaultConfig {
27 | minSdkVersion 7
28 | targetSdkVersion 19
29 | versionCode 1
30 | versionName "1.0"
31 | }
32 | compileOptions {
33 | sourceCompatibility JavaVersion.VERSION_1_7
34 | targetCompatibility JavaVersion.VERSION_1_7
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/DanmakuTimer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model;
18 |
19 | public class DanmakuTimer {
20 | public long currMillisecond;
21 |
22 | private long lastInterval;
23 |
24 | public long update(long curr) {
25 | lastInterval = curr - currMillisecond;
26 | currMillisecond = curr;
27 | return lastInterval;
28 | }
29 |
30 | public long add(long mills) {
31 | return update(currMillisecond + mills);
32 | }
33 |
34 | public long lastInterval() {
35 | return lastInterval;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/loader/ILoader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.loader;
18 |
19 | import java.io.InputStream;
20 |
21 | import master.flame.danmaku.danmaku.parser.IDataSource;
22 |
23 | public interface ILoader {
24 | /**
25 | * @return data source
26 | */
27 | IDataSource> getDataSource();
28 | /**
29 | * @param uri 弹幕文件地址(http:// file://)
30 | */
31 | void load(String uri) throws IllegalDataException;
32 | /**
33 | *
34 | * @param in stream from Internet or local file
35 | */
36 | void load(InputStream in) throws IllegalDataException;
37 | }
38 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/loader/android/DanmakuLoaderFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.loader.android;
18 |
19 | import master.flame.danmaku.danmaku.loader.ILoader;
20 |
21 | public class DanmakuLoaderFactory {
22 |
23 | public static String TAG_BILI = "bili";
24 | public static String TAG_ACFUN = "acfun";
25 |
26 | public static ILoader create(String tag) {
27 | if (TAG_BILI.equalsIgnoreCase(tag)) {
28 | return BiliDanmakuLoader.instance();
29 | } else if(TAG_ACFUN.equalsIgnoreCase(tag))
30 | return AcFunDanmakuLoader.instance();
31 | return null;
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/util/IOUtils.java:
--------------------------------------------------------------------------------
1 | package master.flame.danmaku.danmaku.util;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 |
8 | /**
9 | * Created by MoiTempete.
10 | */
11 | public class IOUtils {
12 | public static String getString(InputStream in){
13 | byte[] data = getBytes(in);
14 | return data == null? null:new String(data);
15 | }
16 | public static byte[] getBytes(InputStream in){
17 |
18 | try {
19 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
20 | byte[] buffer = new byte[8192];
21 | int len = 0;
22 | while ((len = in.read(buffer)) != -1)
23 | baos.write(buffer, 0, len);
24 | in.close();
25 | return baos.toByteArray();
26 | } catch (IOException e) {
27 | return null;
28 | }
29 | }
30 | public static void closeQuietly(InputStream in){
31 | try {
32 | if(in != null)
33 | in.close();
34 | } catch (IOException ignore) {}
35 | }
36 | public static void closeQuietly(OutputStream out){
37 | try {
38 | if(out != null)
39 | out.close();
40 | } catch (IOException ignore) {}
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/objectpool/SynchronizedPool.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model.objectpool;
18 |
19 | class SynchronizedPool> implements Pool {
20 | private final Pool mPool;
21 |
22 | private final Object mLock;
23 |
24 | public SynchronizedPool(Pool pool) {
25 | mPool = pool;
26 | mLock = this;
27 | }
28 |
29 | public SynchronizedPool(Pool pool, Object lock) {
30 | mPool = pool;
31 | mLock = lock;
32 | }
33 |
34 | public T acquire() {
35 | synchronized (mLock) {
36 | return mPool.acquire();
37 | }
38 | }
39 |
40 | public void release(T element) {
41 | synchronized (mLock) {
42 | mPool.release(element);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/IDanmakus.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model;
18 |
19 | public interface IDanmakus {
20 |
21 | public boolean addItem(BaseDanmaku item);
22 |
23 | public boolean removeItem(BaseDanmaku item);
24 |
25 | public IDanmakus subnew(long startTime, long endTime);
26 |
27 | public IDanmakus sub(long startTime, long endTime);
28 |
29 | public int size();
30 |
31 | public void clear();
32 |
33 | public BaseDanmaku first();
34 |
35 | public BaseDanmaku last();
36 |
37 | public IDanmakuIterator iterator();
38 |
39 | public boolean contains(BaseDanmaku item);
40 |
41 | public boolean isEmpty();
42 |
43 | public void setSubItemsDuplicateMergingEnabled(boolean enable);
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/loader/android/AcFunDanmakuLoader.java:
--------------------------------------------------------------------------------
1 | package master.flame.danmaku.danmaku.loader.android;
2 |
3 | import java.io.InputStream;
4 |
5 | import master.flame.danmaku.danmaku.loader.ILoader;
6 | import master.flame.danmaku.danmaku.loader.IllegalDataException;
7 | import master.flame.danmaku.danmaku.parser.android.JSONSource;
8 | import android.net.Uri;
9 | /**
10 | * Ac danmaku loader
11 | * @author yrom
12 | *
13 | */
14 | public class AcFunDanmakuLoader implements ILoader{
15 | private AcFunDanmakuLoader(){}
16 | private static volatile AcFunDanmakuLoader instance;
17 | private JSONSource dataSource;
18 |
19 | public static ILoader instance() {
20 | if(instance == null){
21 | synchronized (AcFunDanmakuLoader.class){
22 | if(instance == null)
23 | instance = new AcFunDanmakuLoader();
24 | }
25 | }
26 | return instance;
27 | }
28 |
29 | @Override
30 | public JSONSource getDataSource() {
31 | return dataSource;
32 | }
33 |
34 | @Override
35 | public void load(String uri) throws IllegalDataException {
36 | try {
37 | dataSource = new JSONSource(Uri.parse(uri));
38 | } catch (Exception e) {
39 | throw new IllegalDataException(e);
40 | }
41 | }
42 |
43 | @Override
44 | public void load(InputStream in) throws IllegalDataException {
45 | try {
46 | dataSource = new JSONSource(in);
47 | } catch (Exception e) {
48 | throw new IllegalDataException(e);
49 | }
50 | }
51 |
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/objectpool/Pools.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model.objectpool;
18 |
19 | public class Pools {
20 | private Pools() {
21 | }
22 |
23 | public static > Pool simplePool(PoolableManager manager) {
24 | return new FinitePool(manager);
25 | }
26 |
27 | public static > Pool finitePool(PoolableManager manager, int limit) {
28 | return new FinitePool(manager, limit);
29 | }
30 |
31 | public static > Pool synchronizedPool(Pool pool) {
32 | return new SynchronizedPool(pool);
33 | }
34 |
35 | public static > Pool synchronizedPool(Pool pool, Object lock) {
36 | return new SynchronizedPool(pool, lock);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | DanmakuFlameMaster
2 | ==================
3 |
4 | android上开源弹幕解析绘制引擎项目。[](https://travis-ci.org/Bilibili/DanmakuFlameMaster)
5 |
6 | ### DFM Inside:
7 | [](https://play.google.com/store/apps/details?id=tv.danmaku.bili)
8 |
9 | - libndkbitmap.so(ndk)源码:https://github.com/Bilibili/NativeBitmapFactory
10 | - 开发交流群:314468823 (加入请注明DFM开发交流)
11 |
12 | ### Features
13 |
14 | - 使用多种方式(View/SurfaceView/TextureView)实现高效绘制
15 |
16 | - B站xml弹幕格式解析
17 |
18 | - 基础弹幕精确还原绘制
19 |
20 | - 支持mode7特殊弹幕
21 |
22 | - 多核机型优化,高效的预缓存机制
23 |
24 | - 支持多种显示效果选项实时切换
25 |
26 | - 实时弹幕显示支持
27 |
28 | - 换行弹幕支持/运动弹幕支持
29 |
30 | - 支持自定义字体
31 |
32 | - 支持多种弹幕参数设置
33 |
34 | - 支持多种方式的弹幕屏蔽
35 |
36 | ### TODO:
37 |
38 | - 继续精确/稳定绘帧周期
39 |
40 | - 增加OpenGL ES绘制方式
41 |
42 | - 改进缓存策略和效率
43 |
44 |
45 | ### Download
46 | Download the [latest version][1] or grab via Maven:
47 |
48 | ```xml
49 |
50 | com.github.ctiao
51 | dfm
52 | 0.3.9
53 |
54 | ```
55 |
56 | or Gradle:
57 | ```groovy
58 | dependencies {
59 | compile 'com.github.ctiao:dfm:0.3.9'
60 | }
61 | ```
62 | Snapshots of the development version are available in [Sonatype's snapshots repository][2].
63 |
64 |
65 | ### License
66 | Copyright (C) 2013-2015 Chen Hui
67 | Licensed under the Apache License, Version 2.0 (the "License");
68 |
69 |
70 | [1]:https://oss.sonatype.org/#nexus-search;gav~com.github.ctiao~dfm~~~
71 | [2]:https://oss.sonatype.org/content/repositories/snapshots/
72 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | apply plugin: 'com.android.library'
18 |
19 | def SourcePath = 'src/main/'
20 |
21 | android {
22 | compileSdkVersion 19
23 | buildToolsVersion '19.1.0'
24 |
25 | defaultConfig {
26 | minSdkVersion 7
27 | targetSdkVersion 19
28 | versionName VERSION_NAME
29 | versionCode Integer.parseInt(VERSION_CODE)
30 | }
31 |
32 | sourceSets {
33 | main {
34 | manifest.srcFile "${SourcePath}AndroidManifest.xml"
35 | java.srcDirs = ["${SourcePath}java"]
36 | jniLibs.srcDirs = ["${SourcePath}libs"]
37 | }
38 | androidTest.setRoot("${SourcePath}../androidTest")
39 | }
40 | compileOptions {
41 | sourceCompatibility JavaVersion.VERSION_1_7
42 | targetCompatibility JavaVersion.VERSION_1_7
43 | }
44 | }
45 | if (rootProject.file('gradle/gradle-mvn-push.gradle').exists()) {
46 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle')
47 | }
48 | if (rootProject.file('gradle/gradle-bintray-upload.gradle').exists()) {
49 | apply from: rootProject.file('gradle/gradle-bintray-upload.gradle')
50 | }
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/Danmaku.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model;
18 |
19 | import master.flame.danmaku.danmaku.util.DanmakuUtils;
20 |
21 | public class Danmaku extends BaseDanmaku {
22 |
23 | public Danmaku(CharSequence text) {
24 | DanmakuUtils.fillText(this, text);
25 | }
26 |
27 | @Override
28 | public boolean isShown() {
29 | return false;
30 | }
31 |
32 | @Override
33 | public void layout(IDisplayer displayer, float x, float y) {
34 |
35 | }
36 |
37 | @Override
38 | public float[] getRectAtTime(IDisplayer displayer, long time) {
39 | return null;
40 | }
41 |
42 | @Override
43 | public float getLeft() {
44 | return 0;
45 | }
46 |
47 | @Override
48 | public float getTop() {
49 | return 0;
50 | }
51 |
52 | @Override
53 | public float getRight() {
54 | return 0;
55 | }
56 |
57 | @Override
58 | public float getBottom() {
59 | return 0;
60 | }
61 |
62 | @Override
63 | public int getType() {
64 | return 0;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/IDisplayer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model;
18 |
19 |
20 | public interface IDisplayer {
21 |
22 | int DANMAKU_STYLE_DEFAULT = -1; // 自动
23 | int DANMAKU_STYLE_NONE = 0; // 无
24 | int DANMAKU_STYLE_SHADOW = 1; // 阴影
25 | int DANMAKU_STYLE_STROKEN = 2; // 描边
26 | int DANMAKU_STYLE_PROJECTION = 3; // 投影
27 |
28 | int getWidth();
29 |
30 | int getHeight();
31 |
32 | float getDensity();
33 |
34 | int getDensityDpi();
35 |
36 | int draw(BaseDanmaku danmaku);
37 |
38 | float getScaledDensity();
39 |
40 | int getSlopPixel();
41 |
42 | void measure(BaseDanmaku danmaku, boolean fromWorkerThread);
43 |
44 | float getStrokeWidth();
45 |
46 | void setHardwareAccelerated(boolean enable);
47 |
48 | boolean isHardwareAccelerated();
49 |
50 | int getMaximumCacheWidth();
51 |
52 | int getMaximumCacheHeight();
53 |
54 |
55 | ////////////////// setter ///////////////////////////
56 |
57 | void resetSlopPixel(float factor);
58 |
59 | void setDensities(float density, int densityDpi, float scaledDensity);
60 |
61 | void setSize(int width, int height);
62 |
63 | void setDanmakuStyle(int style, float[] data);
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/Sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
26 |
27 |
28 |
29 |
33 |
34 |
35 |
36 |
40 |
41 |
45 |
46 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/loader/android/BiliDanmakuLoader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.loader.android;
18 |
19 | import java.io.InputStream;
20 |
21 | import master.flame.danmaku.danmaku.loader.ILoader;
22 | import master.flame.danmaku.danmaku.loader.IllegalDataException;
23 | import master.flame.danmaku.danmaku.parser.android.AndroidFileSource;
24 |
25 | public class BiliDanmakuLoader implements ILoader {
26 |
27 | private static BiliDanmakuLoader _instance;
28 |
29 | private AndroidFileSource dataSource;
30 |
31 | private BiliDanmakuLoader() {
32 |
33 | }
34 |
35 | public static BiliDanmakuLoader instance() {
36 | if (_instance == null) {
37 | _instance = new BiliDanmakuLoader();
38 | }
39 | return _instance;
40 | }
41 |
42 | public void load(String uri) throws IllegalDataException {
43 | try {
44 | dataSource = new AndroidFileSource(uri);
45 | } catch (Exception e) {
46 | throw new IllegalDataException(e);
47 | }
48 | }
49 |
50 | public void load(InputStream stream) {
51 | dataSource = new AndroidFileSource(stream);
52 | }
53 |
54 | @Override
55 | public AndroidFileSource getDataSource() {
56 | return dataSource;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/controller/IDrawTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.controller;
18 |
19 | import master.flame.danmaku.danmaku.model.AbsDisplayer;
20 | import master.flame.danmaku.danmaku.model.BaseDanmaku;
21 | import master.flame.danmaku.danmaku.model.IDanmakus;
22 | import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
23 | import master.flame.danmaku.danmaku.renderer.IRenderer.RenderingState;
24 |
25 | public interface IDrawTask {
26 |
27 | public void addDanmaku(BaseDanmaku item);
28 |
29 | public void removeAllDanmakus();
30 |
31 | public void removeAllLiveDanmakus();
32 |
33 | public void clearDanmakusOnScreen(long currMillis);
34 |
35 | public IDanmakus getVisibleDanmakusOnTime(long time);
36 |
37 | public RenderingState draw(AbsDisplayer displayer);
38 |
39 | public void reset();
40 |
41 | public void seek(long mills);
42 |
43 | public void start();
44 |
45 | public void quit();
46 |
47 | public void prepare();
48 |
49 | public void requestClear();
50 |
51 | public void setParser(BaseDanmakuParser parser);
52 |
53 | void invalidateDanmaku(BaseDanmaku item, boolean remeasure);
54 |
55 | public interface TaskListener {
56 | public void ready();
57 |
58 | public void onDanmakuAdd(BaseDanmaku danmaku);
59 |
60 | public void onDanmakuConfigChanged();
61 |
62 | public void onDanmakusDrawingFinished();
63 | }
64 |
65 | public void requestHide();
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/parser/android/JSONSource.java:
--------------------------------------------------------------------------------
1 | package master.flame.danmaku.danmaku.parser.android;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.FileNotFoundException;
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.net.URL;
9 |
10 | import master.flame.danmaku.danmaku.parser.IDataSource;
11 | import master.flame.danmaku.danmaku.util.IOUtils;
12 |
13 | import org.json.JSONArray;
14 | import org.json.JSONException;
15 |
16 | import android.net.Uri;
17 | import android.text.TextUtils;
18 |
19 | /**
20 | * a json file source
21 | * @author yrom
22 | */
23 | public class JSONSource implements IDataSource{
24 | private JSONArray mJSONArray;
25 | private InputStream mInput;
26 | public JSONSource(String json) throws JSONException{
27 | init(json);
28 | }
29 |
30 | public JSONSource(InputStream in) throws JSONException{
31 | init(in);
32 | }
33 |
34 | private void init(InputStream in) throws JSONException {
35 | if(in == null)
36 | throw new NullPointerException("input stream cannot be null!");
37 | mInput = in;
38 | String json = IOUtils.getString(mInput);
39 | init(json);
40 | }
41 |
42 | public JSONSource(URL url) throws JSONException, IOException{
43 | this(url.openStream());
44 | }
45 |
46 | public JSONSource(File file) throws FileNotFoundException, JSONException{
47 | init(new FileInputStream(file));
48 | }
49 |
50 | public JSONSource(Uri uri) throws IOException, JSONException {
51 | String scheme = uri.getScheme();
52 | if (SCHEME_HTTP_TAG.equalsIgnoreCase(scheme) || SCHEME_HTTPS_TAG.equalsIgnoreCase(scheme)) {
53 | init(new URL(uri.getPath()).openStream());
54 | } else if (SCHEME_FILE_TAG.equalsIgnoreCase(scheme)) {
55 | init(new FileInputStream(uri.getPath()));
56 | }
57 | }
58 |
59 | private void init(String json) throws JSONException {
60 | if(!TextUtils.isEmpty(json)){
61 | mJSONArray = new JSONArray(json);
62 | }
63 | }
64 | public JSONArray data(){
65 | return mJSONArray;
66 | }
67 |
68 | @Override
69 | public void release() {
70 | IOUtils.closeQuietly(mInput);
71 | mInput = null;
72 | mJSONArray = null;
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/gradle/gradle-bintray-upload.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | apply plugin: 'com.github.dcendents.android-maven'
18 | apply plugin: 'com.jfrog.bintray'
19 |
20 | group = GROUP
21 | version = VERSION_NAME
22 |
23 | bintray {
24 | user = project.hasProperty('BINTRAY_USER') ? BINTRAY_USER : ''
25 | key = project.hasProperty('BINTRAY_APIKEY') ? BINTRAY_APIKEY : ''
26 |
27 | configurations = ['archives']
28 |
29 | dryRun = false
30 | publish = true
31 |
32 | pkg {
33 | repo = 'maven'
34 | name = BINTRAY_POM_NAME
35 | desc = POM_DESCRIPTION
36 | websiteUrl = POM_URL
37 | vcsUrl = POM_SCM_URL
38 | licenses = [POM_LICENCE_NAME]
39 | labels = ['FFmpeg', 'Android', 'player']
40 | publicDownloadNumbers = true
41 | version {
42 | name = VERSION_NAME
43 | gpg {
44 | sign = true
45 | passphrase = project.hasProperty('GPG_PASSWORD') ? GPG_PASSWORD : ''
46 | }
47 | }
48 | }
49 | }
50 |
51 | install {
52 | repositories.mavenInstaller {
53 | pom.project {
54 | name BINTRAY_POM_NAME
55 | packaging POM_PACKAGING
56 | description POM_DESCRIPTION
57 | url POM_URL
58 |
59 | licenses {
60 | license {
61 | name POM_LICENCE_NAME
62 | url POM_LICENCE_URL
63 | distribution POM_LICENCE_DIST
64 | }
65 | }
66 |
67 | scm {
68 | url POM_SCM_URL
69 | connection POM_SCM_CONNECTION
70 | developerConnection POM_SCM_DEV_CONNECTION
71 | }
72 |
73 | developers {
74 | developer {
75 | id POM_DEVELOPER_ID
76 | name POM_DEVELOPER_NAME
77 | email POM_DEVELOPER_EMAIL
78 | }
79 | }
80 | }
81 | }
82 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/android/BaseCacheStuffer.java:
--------------------------------------------------------------------------------
1 | package master.flame.danmaku.danmaku.model.android;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.text.TextPaint;
6 |
7 | import master.flame.danmaku.danmaku.model.BaseDanmaku;
8 |
9 | /**
10 | * Created by ch on 15-7-16.
11 | */
12 | public abstract class BaseCacheStuffer {
13 |
14 | public static abstract class Proxy {
15 | /**
16 | * 在弹幕显示前使用新的text,使用新的text
17 | * @param danmaku
18 | * @param fromWorkerThread 是否在工作(非UI)线程,在true的情况下可以做一些耗时操作(例如更新Span的drawblae或者其他IO操作)
19 | * @return 如果不需重置,直接返回danmaku.text
20 | */
21 | public abstract void prepareDrawing(BaseDanmaku danmaku, boolean fromWorkerThread);
22 |
23 | public abstract void releaseResource(BaseDanmaku danmaku);
24 | }
25 |
26 | protected Proxy mProxy;
27 |
28 | /**
29 | * set paintWidth, paintHeight to danmaku
30 | * @param danmaku
31 | * @param fromWorkerThread
32 | */
33 | public abstract void measure(BaseDanmaku danmaku, TextPaint paint, boolean fromWorkerThread);
34 |
35 | /**
36 | * draw the danmaku-stroke on canvas with the given params
37 | * @param danmaku
38 | * @param lineText
39 | * @param canvas
40 | * @param left
41 | * @param top
42 | * @param paint
43 | */
44 | public abstract void drawStroke(BaseDanmaku danmaku, String lineText, Canvas canvas, float left, float top, Paint paint);
45 |
46 | /**
47 | * draw the danmaku-text on canvas with the given params
48 | * @param danmaku
49 | * @param lineText
50 | * @param canvas
51 | * @param left
52 | * @param top
53 | * @param paint
54 | * @param fromWorkerThread
55 | */
56 | public abstract void drawText(BaseDanmaku danmaku, String lineText, Canvas canvas, float left, float top, TextPaint paint, boolean fromWorkerThread);
57 |
58 | /**
59 | * clear caches which created by this stuffer
60 | */
61 | public abstract void clearCaches();
62 |
63 | /**
64 | * draw the background in rect (left, top, left + danmaku.paintWidth, top + danmaku.paintHeight)
65 | * @param danmaku
66 | * @param canvas
67 | * @param left
68 | * @param top
69 | */
70 | public abstract void drawBackground(BaseDanmaku danmaku, Canvas canvas, float left, float top);
71 |
72 | public void clearCache(BaseDanmaku danmaku) {
73 |
74 | }
75 |
76 | public void setProxy(Proxy adapter) {
77 | mProxy = adapter;
78 | }
79 |
80 | public void releaseResource(BaseDanmaku danmaku) {
81 | if (mProxy != null) {
82 | mProxy.releaseResource(danmaku);
83 | }
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/objectpool/FinitePool.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model.objectpool;
18 |
19 | class FinitePool> implements Pool {
20 | /** Factory used to create new pool objects */
21 | private final PoolableManager mManager;
22 |
23 | /** Maximum number of objects in the pool */
24 | private final int mLimit;
25 |
26 | /** If true, mLimit is ignored */
27 | private final boolean mInfinite;
28 |
29 | /** Next object to acquire */
30 | private T mRoot;
31 |
32 | /** Number of objects in the pool */
33 | private int mPoolCount;
34 |
35 | FinitePool(PoolableManager manager) {
36 | mManager = manager;
37 | mLimit = 0;
38 | mInfinite = true;
39 | }
40 |
41 | FinitePool(PoolableManager manager, int limit) {
42 | if (limit <= 0) {
43 | throw new IllegalArgumentException("The pool limit must be > 0");
44 | }
45 |
46 | mManager = manager;
47 | mLimit = limit;
48 | mInfinite = false;
49 | }
50 |
51 | public T acquire() {
52 | T element;
53 |
54 | if (mRoot != null) {
55 | element = mRoot;
56 | mRoot = element.getNextPoolable();
57 | mPoolCount--;
58 | } else {
59 | element = mManager.newInstance();
60 | }
61 |
62 | if (element != null) {
63 | element.setNextPoolable(null);
64 | element.setPooled(false);
65 | mManager.onAcquired(element);
66 | }
67 |
68 | return element;
69 | }
70 |
71 | public void release(T element) {
72 | if (!element.isPooled()) {
73 | if (mInfinite || mPoolCount < mLimit) {
74 | mPoolCount++;
75 | element.setNextPoolable(mRoot);
76 | element.setPooled(true);
77 | mRoot = element;
78 | }
79 | mManager.onReleased(element);
80 | } else {
81 | System.out.print("[FinitePool] Element is already in pool: " + element);
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/android/DrawingCache.java:
--------------------------------------------------------------------------------
1 |
2 | package master.flame.danmaku.danmaku.model.android;
3 |
4 | import master.flame.danmaku.danmaku.model.IDrawingCache;
5 | import master.flame.danmaku.danmaku.model.objectpool.Poolable;
6 |
7 | public class DrawingCache implements IDrawingCache, Poolable {
8 |
9 | private final DrawingCacheHolder mHolder;
10 |
11 | private int mSize = 0;
12 |
13 | private DrawingCache mNextElement;
14 |
15 | private boolean mIsPooled;
16 |
17 | private int referenceCount = 0;
18 |
19 | public DrawingCache() {
20 | mHolder = new DrawingCacheHolder();
21 | }
22 |
23 | @Override
24 | public void build(int w, int h, int density, boolean checkSizeEquals) {
25 | final DrawingCacheHolder holder = mHolder;
26 | holder.buildCache(w, h, density, checkSizeEquals);
27 | mSize = mHolder.bitmap.getRowBytes() * mHolder.bitmap.getHeight();
28 | }
29 |
30 | @Override
31 | public void erase() {
32 | mHolder.erase();
33 | }
34 |
35 | @Override
36 | public DrawingCacheHolder get() {
37 | final DrawingCacheHolder holder = mHolder;
38 | if (holder.bitmap == null) {
39 | return null;
40 | }
41 | return mHolder;
42 | }
43 |
44 | @Override
45 | public void destroy() {
46 | if (mHolder != null) {
47 | mHolder.recycle();
48 | }
49 | mSize = 0;
50 | referenceCount = 0;
51 | }
52 |
53 | @Override
54 | public int size() {
55 | return mSize;
56 | }
57 |
58 | @Override
59 | public void setNextPoolable(DrawingCache element) {
60 | mNextElement = element;
61 | }
62 |
63 | @Override
64 | public DrawingCache getNextPoolable() {
65 | return mNextElement;
66 | }
67 |
68 | @Override
69 | public boolean isPooled() {
70 | return mIsPooled;
71 | }
72 |
73 | @Override
74 | public void setPooled(boolean isPooled) {
75 | mIsPooled = isPooled;
76 | }
77 |
78 | @Override
79 | public synchronized boolean hasReferences() {
80 | return referenceCount > 0;
81 | }
82 |
83 | @Override
84 | public synchronized void increaseReference() {
85 | referenceCount++;
86 | }
87 |
88 | @Override
89 | public synchronized void decreaseReference() {
90 | referenceCount--;
91 | }
92 |
93 | @Override
94 | public int width() {
95 | return mHolder.width;
96 | }
97 |
98 | @Override
99 | public int height() {
100 | return mHolder.height;
101 | }
102 |
103 | }
--------------------------------------------------------------------------------
/Sample/src/main/res/layout/media_controller.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
13 |
19 |
20 |
26 |
27 |
33 |
34 |
40 |
41 |
47 |
48 |
54 |
55 |
61 |
62 |
68 |
69 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/L2RDanmaku.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model;
18 |
19 |
20 | public class L2RDanmaku extends R2LDanmaku {
21 |
22 | public L2RDanmaku(Duration duration) {
23 | super(duration);
24 | }
25 |
26 | @Override
27 | public void layout(IDisplayer displayer, float x, float y) {
28 | if (mTimer != null) {
29 | long currMS = mTimer.currMillisecond;
30 | long deltaDuration = currMS - time;
31 | if (deltaDuration > 0 && deltaDuration < duration.value) {
32 | this.x = getAccurateLeft(displayer, currMS);
33 | if (!this.isShown()) {
34 | this.y = y;
35 | this.setVisibility(true);
36 | }
37 | mLastTime = currMS;
38 | return;
39 | }
40 | mLastTime = currMS;
41 | }
42 | this.setVisibility(false);
43 | }
44 |
45 | @Override
46 | public float[] getRectAtTime(IDisplayer displayer, long time) {
47 | if (!isMeasured())
48 | return null;
49 | float left = getAccurateLeft(displayer, time);
50 | if (RECT == null) {
51 | RECT = new float[4];
52 | }
53 | RECT[0] = left;
54 | RECT[1] = y;
55 | RECT[2] = left + paintWidth;
56 | RECT[3] = y + paintHeight;
57 | return RECT;
58 | }
59 |
60 | protected float getAccurateLeft(IDisplayer displayer, long currTime) {
61 | long elapsedTime = currTime - time;
62 | if (elapsedTime >= duration.value) {
63 | return displayer.getWidth();
64 | }
65 | return mStepX * elapsedTime - paintWidth;
66 | }
67 |
68 | @Override
69 | public float getLeft() {
70 | return x;
71 | }
72 |
73 | @Override
74 | public float getTop() {
75 | return y;
76 | }
77 |
78 | @Override
79 | public float getRight() {
80 | return x + paintWidth;
81 | }
82 |
83 | @Override
84 | public float getBottom() {
85 | return y + paintHeight;
86 | }
87 |
88 | @Override
89 | public int getType() {
90 | return TYPE_SCROLL_LR;
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/parser/android/AndroidFileSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.parser.android;
18 |
19 | import master.flame.danmaku.danmaku.parser.IDataSource;
20 | import master.flame.danmaku.danmaku.util.IOUtils;
21 |
22 | import android.net.Uri;
23 |
24 | import java.io.*;
25 | import java.net.MalformedURLException;
26 | import java.net.URL;
27 |
28 | public class AndroidFileSource implements IDataSource {
29 |
30 | private InputStream inStream;
31 |
32 | public AndroidFileSource(String filepath) {
33 | fillStreamFromFile(new File(filepath));
34 | }
35 |
36 | public AndroidFileSource(Uri uri) {
37 | fillStreamFromUri(uri);
38 | }
39 |
40 | public AndroidFileSource(File file) {
41 | fillStreamFromFile(file);
42 | }
43 |
44 | public AndroidFileSource(InputStream stream) {
45 | this.inStream = stream;
46 | }
47 |
48 | public void fillStreamFromFile(File file) {
49 | try {
50 | inStream = new BufferedInputStream(new FileInputStream(file));
51 | } catch (FileNotFoundException e) {
52 | e.printStackTrace();
53 | }
54 | }
55 |
56 | public void fillStreamFromUri(Uri uri) {
57 | String scheme = uri.getScheme();
58 | if (SCHEME_HTTP_TAG.equalsIgnoreCase(scheme) || SCHEME_HTTPS_TAG.equalsIgnoreCase(scheme)) {
59 | fillStreamFromHttpFile(uri);
60 | } else if (SCHEME_FILE_TAG.equalsIgnoreCase(scheme)) {
61 | fillStreamFromFile(new File(uri.getPath()));
62 | }
63 | }
64 |
65 | public void fillStreamFromHttpFile(Uri uri) {
66 | try {
67 | URL url = new URL(uri.getPath());
68 | url.openConnection();
69 | inStream = new BufferedInputStream(url.openStream());
70 |
71 | } catch (MalformedURLException e) {
72 | e.printStackTrace();
73 | } catch (IOException e) {
74 | e.printStackTrace();
75 | }
76 |
77 | }
78 |
79 | @Override
80 | public void release() {
81 | IOUtils.closeQuietly(inStream);
82 | inStream = null;
83 | }
84 |
85 | @Override
86 | public InputStream data() {
87 | return inStream;
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/android/SimpleTextCacheStuffer.java:
--------------------------------------------------------------------------------
1 | package master.flame.danmaku.danmaku.model.android;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.text.TextPaint;
6 |
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | import master.flame.danmaku.danmaku.model.BaseDanmaku;
11 |
12 | /**
13 | * Created by ch on 15-7-16.
14 | */
15 | public class SimpleTextCacheStuffer extends BaseCacheStuffer {
16 |
17 | private final static Map sTextHeightCache = new HashMap();
18 |
19 | protected Float getCacheHeight(BaseDanmaku danmaku, Paint paint) {
20 | Float textSize = paint.getTextSize();
21 | Float textHeight = sTextHeightCache.get(textSize);
22 | if (textHeight == null) {
23 | Paint.FontMetrics fontMetrics = paint.getFontMetrics();
24 | textHeight = fontMetrics.descent - fontMetrics.ascent + fontMetrics.leading;
25 | sTextHeightCache.put(textSize, textHeight);
26 | }
27 | return textHeight;
28 | }
29 |
30 | @Override
31 | public void measure(BaseDanmaku danmaku, TextPaint paint, boolean fromWorkerThread) {
32 | if (mProxy != null) {
33 | mProxy.prepareDrawing(danmaku, fromWorkerThread);
34 | }
35 | float w = 0;
36 | Float textHeight = 0f;
37 | if (danmaku.lines == null) {
38 | if (danmaku.text == null) {
39 | w = 0;
40 | } else {
41 | w = paint.measureText(danmaku.text.toString());
42 | textHeight = getCacheHeight(danmaku, paint);
43 | }
44 | danmaku.paintWidth = w;
45 | danmaku.paintHeight = textHeight;
46 | } else {
47 | textHeight = getCacheHeight(danmaku, paint);
48 | for (String tempStr : danmaku.lines) {
49 | if (tempStr.length() > 0) {
50 | float tr = paint.measureText(tempStr);
51 | w = Math.max(tr, w);
52 | }
53 | }
54 | danmaku.paintWidth = w;
55 | danmaku.paintHeight = danmaku.lines.length * textHeight;
56 | }
57 | }
58 |
59 | @Override
60 | public void drawStroke(BaseDanmaku danmaku, String lineText, Canvas canvas, float left, float top, Paint paint) {
61 | if (lineText != null) {
62 | canvas.drawText(lineText, left, top, paint);
63 | } else {
64 | canvas.drawText(danmaku.text.toString(), left, top, paint);
65 | }
66 | }
67 |
68 | @Override
69 | public void drawText(BaseDanmaku danmaku, String lineText, Canvas canvas, float left, float top, TextPaint paint, boolean fromWorkerThread) {
70 | if (lineText != null) {
71 | canvas.drawText(lineText, left, top, paint);
72 | } else {
73 | canvas.drawText(danmaku.text.toString(), left, top, paint);
74 | }
75 | }
76 |
77 | @Override
78 | public void clearCaches() {
79 | sTextHeightCache.clear();
80 | }
81 |
82 | @Override
83 | public void drawBackground(BaseDanmaku danmaku, Canvas canvas, float left, float top) {
84 |
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/ui/widget/DanmakuTouchHelper.java:
--------------------------------------------------------------------------------
1 | package master.flame.danmaku.ui.widget;
2 |
3 | import android.graphics.RectF;
4 | import android.view.MotionEvent;
5 |
6 | import master.flame.danmaku.controller.IDanmakuView;
7 | import master.flame.danmaku.danmaku.model.BaseDanmaku;
8 | import master.flame.danmaku.danmaku.model.IDanmakuIterator;
9 | import master.flame.danmaku.danmaku.model.IDanmakus;
10 | import master.flame.danmaku.danmaku.model.android.Danmakus;
11 |
12 | /**
13 | * Created by kmfish on 2015/1/25.
14 | */
15 | public class DanmakuTouchHelper {
16 |
17 | private IDanmakuView danmakuView;
18 | private RectF mDanmakuBounds;
19 |
20 | private DanmakuTouchHelper(IDanmakuView danmakuView) {
21 | this.danmakuView = danmakuView;
22 | this.mDanmakuBounds = new RectF();
23 | }
24 |
25 | public static synchronized DanmakuTouchHelper instance(IDanmakuView danmakuView) {
26 | return new DanmakuTouchHelper(danmakuView);
27 | }
28 |
29 | public boolean onTouchEvent(MotionEvent event) {
30 | switch (event.getAction()) {
31 | case MotionEvent.ACTION_UP:
32 | IDanmakus clickDanmakus = touchHitDanmaku(event.getX(), event.getY());
33 | BaseDanmaku newestDanmaku = null;
34 | if (null != clickDanmakus && !clickDanmakus.isEmpty()) {
35 | performClick(clickDanmakus);
36 | newestDanmaku = fetchLatestOne(clickDanmakus);
37 | }
38 |
39 | if (null != newestDanmaku) {
40 | performClickWithlatest(newestDanmaku);
41 | }
42 | break;
43 | default:
44 | break;
45 | }
46 |
47 | return false;
48 | }
49 |
50 | private void performClickWithlatest(BaseDanmaku newest) {
51 | if (danmakuView.getOnDanmakuClickListener() != null) {
52 | danmakuView.getOnDanmakuClickListener().onDanmakuClick(newest);
53 | }
54 | }
55 |
56 | private void performClick(IDanmakus danmakus) {
57 | if (danmakuView.getOnDanmakuClickListener() != null) {
58 | danmakuView.getOnDanmakuClickListener().onDanmakuClick(danmakus);
59 | }
60 | }
61 |
62 | private IDanmakus touchHitDanmaku(float x, float y) {
63 | IDanmakus hitDanmakus = new Danmakus();
64 | mDanmakuBounds.setEmpty();
65 |
66 | IDanmakus danmakus = danmakuView.getCurrentVisibleDanmakus();
67 | if (null != danmakus && !danmakus.isEmpty()) {
68 | IDanmakuIterator iterator = danmakus.iterator();
69 | while (iterator.hasNext()) {
70 | BaseDanmaku danmaku = iterator.next();
71 | if (null != danmaku) {
72 | mDanmakuBounds.set(danmaku.getLeft(), danmaku.getTop(), danmaku.getRight(), danmaku.getBottom());
73 | if (mDanmakuBounds.contains(x, y)) {
74 | hitDanmakus.addItem(danmaku);
75 | }
76 | }
77 | }
78 | }
79 |
80 | return hitDanmakus;
81 | }
82 |
83 | private BaseDanmaku fetchLatestOne(IDanmakus danmakus) {
84 | if (danmakus.isEmpty()) {
85 | return null;
86 | }
87 |
88 | return danmakus.last();
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/controller/DrawHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.controller;
18 |
19 | import android.graphics.Canvas;
20 | import android.graphics.Color;
21 | import android.graphics.Paint;
22 | import android.graphics.PorterDuff;
23 | import android.graphics.PorterDuffXfermode;
24 | import android.graphics.RectF;
25 |
26 | public class DrawHelper {
27 |
28 | public static Paint PAINT, PAINT_FPS;
29 |
30 | public static RectF RECT;
31 |
32 | private static boolean USE_DRAWCOLOR_TO_CLEAR_CANVAS = true;
33 |
34 | private static boolean USE_DRAWCOLOR_MODE_CLEAR = true;
35 |
36 | static {
37 | PAINT = new Paint();
38 | PAINT.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
39 | PAINT.setColor(Color.TRANSPARENT);
40 | RECT = new RectF();
41 | }
42 |
43 | public static void useDrawColorToClearCanvas(boolean use, boolean useClearMode) {
44 | USE_DRAWCOLOR_TO_CLEAR_CANVAS = use;
45 | USE_DRAWCOLOR_MODE_CLEAR = useClearMode;
46 | }
47 |
48 | public static void drawFPS(Canvas canvas, String text) {
49 | if (PAINT_FPS == null) {
50 | PAINT_FPS = new Paint();
51 | PAINT_FPS.setColor(Color.RED);
52 | PAINT_FPS.setTextSize(30);
53 | }
54 | int top = canvas.getHeight() - 50;
55 |
56 | clearCanvas(canvas, 10, top - 50, (int) (PAINT_FPS.measureText(text) + 20), canvas.getHeight());
57 | canvas.drawText(text, 10, top, PAINT_FPS);
58 | }
59 |
60 | public static void clearCanvas(Canvas canvas) {
61 | if (USE_DRAWCOLOR_TO_CLEAR_CANVAS) {
62 | if(USE_DRAWCOLOR_MODE_CLEAR) {
63 | canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
64 | } else {
65 | canvas.drawColor(Color.TRANSPARENT);
66 | }
67 | } else {
68 | RECT.set(0, 0, canvas.getWidth(), canvas.getHeight());
69 | clearCanvas(canvas, RECT);
70 | }
71 | }
72 |
73 | public static void fillTransparent(Canvas canvas){
74 | canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
75 | }
76 |
77 | public static void clearCanvas(Canvas canvas, float left, float top, float right, float bottom) {
78 | RECT.set(left, top, right, bottom);
79 | clearCanvas(canvas, RECT);
80 | }
81 |
82 | private static void clearCanvas(Canvas canvas, RectF rect) {
83 | if (rect.width() <= 0 || rect.height() <= 0) {
84 | return;
85 | }
86 | canvas.drawRect(rect, PAINT);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/FTDanmaku.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model;
18 |
19 | /**
20 | * 顶部固定弹幕
21 | */
22 | public class FTDanmaku extends BaseDanmaku {
23 |
24 | private float x = 0;
25 |
26 | protected float y = -1;
27 |
28 | private float[] RECT = null;
29 |
30 | private float mLastLeft;
31 |
32 | private float mLastPaintWidth;
33 |
34 | private int mLastDispWidth;
35 |
36 | public FTDanmaku(Duration duration) {
37 | this.duration = duration;
38 | }
39 |
40 | @Override
41 | public void layout(IDisplayer displayer, float x, float y) {
42 | if (mTimer != null) {
43 | long deltaDuration = mTimer.currMillisecond - time;
44 | if (deltaDuration > 0 && deltaDuration < duration.value) {
45 | if (!this.isShown()) {
46 | this.x = getLeft(displayer);
47 | this.y = y;
48 | this.setVisibility(true);
49 | }
50 | return;
51 | }
52 |
53 | this.setVisibility(false);
54 | this.y = -1;
55 | this.x = displayer.getWidth();
56 | }
57 |
58 | }
59 |
60 | protected float getLeft(IDisplayer displayer) {
61 | if (mLastDispWidth == displayer.getWidth() && mLastPaintWidth == paintWidth) {
62 | return mLastLeft;
63 | }
64 | float left = (displayer.getWidth() - paintWidth) / 2;
65 | mLastDispWidth = displayer.getWidth();
66 | mLastPaintWidth = paintWidth;
67 | mLastLeft = left;
68 | return left;
69 | }
70 |
71 | @Override
72 | public float[] getRectAtTime(IDisplayer displayer, long time) {
73 | if (!isMeasured())
74 | return null;
75 | float left = getLeft(displayer);
76 | if (RECT == null) {
77 | RECT = new float[4];
78 | }
79 | RECT[0] = left;
80 | RECT[1] = y;
81 | RECT[2] = left + paintWidth;
82 | RECT[3] = y + paintHeight;
83 | return RECT;
84 | }
85 |
86 | @Override
87 | public float getLeft() {
88 | return x;
89 | }
90 |
91 | @Override
92 | public float getTop() {
93 | return y;
94 | }
95 |
96 | @Override
97 | public float getRight() {
98 | return x + paintWidth;
99 | }
100 |
101 | @Override
102 | public float getBottom() {
103 | return y + paintHeight;
104 | }
105 |
106 | @Override
107 | public int getType() {
108 | return TYPE_FIX_TOP;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/parser/BaseDanmakuParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.parser;
18 |
19 | import master.flame.danmaku.danmaku.model.DanmakuTimer;
20 | import master.flame.danmaku.danmaku.model.IDanmakus;
21 | import master.flame.danmaku.danmaku.model.IDisplayer;
22 | import master.flame.danmaku.danmaku.model.android.DanmakuContext;
23 |
24 | /**
25 | *
26 | */
27 | public abstract class BaseDanmakuParser {
28 | protected IDataSource> mDataSource;
29 |
30 | protected DanmakuTimer mTimer;
31 | protected int mDispWidth;
32 | protected int mDispHeight;
33 | protected float mDispDensity;
34 | protected float mScaledDensity;
35 |
36 | private IDanmakus mDanmakus;
37 |
38 | protected IDisplayer mDisp;
39 | protected DanmakuContext mContext;
40 |
41 | public BaseDanmakuParser setDisplayer(IDisplayer disp){
42 | mDisp = disp;
43 | mDispWidth = disp.getWidth();
44 | mDispHeight = disp.getHeight();
45 | mDispDensity = disp.getDensity();
46 | mScaledDensity = disp.getScaledDensity();
47 | mContext.mDanmakuFactory.updateViewportState(mDispWidth, mDispHeight, getViewportSizeFactor());
48 | mContext.mDanmakuFactory.updateMaxDanmakuDuration();
49 | return this;
50 | }
51 |
52 | /**
53 | * decide the speed of scroll-danmakus
54 | * @return
55 | */
56 | protected float getViewportSizeFactor() {
57 | return 1 / (mDispDensity - 0.6f);
58 | }
59 |
60 | public IDisplayer getDisplayer(){
61 | return mDisp;
62 | }
63 |
64 | public BaseDanmakuParser load(IDataSource> source) {
65 | mDataSource = source;
66 | return this;
67 | }
68 |
69 | public BaseDanmakuParser setTimer(DanmakuTimer timer) {
70 | mTimer = timer;
71 | return this;
72 | }
73 |
74 | public DanmakuTimer getTimer() {
75 | return mTimer;
76 | }
77 |
78 | public IDanmakus getDanmakus() {
79 | if (mDanmakus != null)
80 | return mDanmakus;
81 | mContext.mDanmakuFactory.resetDurationsData();
82 | mDanmakus = parse();
83 | releaseDataSource();
84 | mContext.mDanmakuFactory.updateMaxDanmakuDuration();
85 | return mDanmakus;
86 | }
87 |
88 | protected void releaseDataSource() {
89 | if(mDataSource!=null)
90 | mDataSource.release();
91 | mDataSource = null;
92 | }
93 |
94 | protected abstract IDanmakus parse();
95 |
96 | public void release() {
97 | releaseDataSource();
98 | }
99 |
100 | public BaseDanmakuParser setConfig(DanmakuContext config) {
101 | mContext = config;
102 | return this;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/R2LDanmaku.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model;
18 |
19 |
20 |
21 | public class R2LDanmaku extends BaseDanmaku {
22 |
23 | protected static final long MAX_RENDERING_TIME = 100;
24 |
25 | protected static final long CORDON_RENDERING_TIME = 40;
26 |
27 | protected float x = 0;
28 |
29 | protected float y = -1;
30 |
31 | protected int mDistance;
32 |
33 | protected float[] RECT = null;
34 |
35 | protected float mStepX;
36 |
37 | protected long mLastTime;
38 |
39 | public R2LDanmaku(Duration duration) {
40 | this.duration = duration;
41 | }
42 |
43 | @Override
44 | public void layout(IDisplayer displayer, float x, float y) {
45 | if (mTimer != null) {
46 | long currMS = mTimer.currMillisecond;
47 | long deltaDuration = currMS - time;
48 | if (deltaDuration > 0 && deltaDuration < duration.value) {
49 | this.x = getAccurateLeft(displayer, currMS);
50 | if (!this.isShown()) {
51 | this.y = y;
52 | this.setVisibility(true);
53 | }
54 | mLastTime = currMS;
55 | return;
56 | }
57 | mLastTime = currMS;
58 | }
59 | this.setVisibility(false);
60 | }
61 |
62 | protected float getAccurateLeft(IDisplayer displayer, long currTime) {
63 | long elapsedTime = currTime - time;
64 | if (elapsedTime >= duration.value) {
65 | return -paintWidth;
66 | }
67 |
68 | return displayer.getWidth() - elapsedTime * mStepX;
69 | }
70 |
71 | @Override
72 | public float[] getRectAtTime(IDisplayer displayer, long time) {
73 | if (!isMeasured())
74 | return null;
75 | float left = getAccurateLeft(displayer, time);
76 | if (RECT == null) {
77 | RECT = new float[4];
78 | }
79 | RECT[0] = left;
80 | RECT[1] = y;
81 | RECT[2] = left + paintWidth;
82 | RECT[3] = y + paintHeight;
83 | return RECT;
84 | }
85 |
86 | @Override
87 | public float getLeft() {
88 | return x;
89 | }
90 |
91 | @Override
92 | public float getTop() {
93 | return y;
94 | }
95 |
96 | @Override
97 | public float getRight() {
98 | return x + paintWidth;
99 | }
100 |
101 | @Override
102 | public float getBottom() {
103 | return y + paintHeight;
104 | }
105 |
106 | @Override
107 | public int getType() {
108 | return TYPE_SCROLL_RL;
109 | }
110 |
111 | @Override
112 | public void measure(IDisplayer displayer, boolean fromWorkerThread) {
113 | super.measure(displayer, fromWorkerThread);
114 | mDistance = (int) (displayer.getWidth() + paintWidth);
115 | mStepX = mDistance / (float) duration.value;
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/controller/IDanmakuView.java:
--------------------------------------------------------------------------------
1 |
2 | package master.flame.danmaku.controller;
3 |
4 | import android.view.View;
5 |
6 | import master.flame.danmaku.controller.DrawHandler.Callback;
7 | import master.flame.danmaku.danmaku.model.BaseDanmaku;
8 | import master.flame.danmaku.danmaku.model.IDanmakus;
9 | import master.flame.danmaku.danmaku.model.android.DanmakuContext;
10 | import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
11 |
12 | public interface IDanmakuView {
13 |
14 | public final static int THREAD_TYPE_NORMAL_PRIORITY = 0x0;
15 | public final static int THREAD_TYPE_MAIN_THREAD = 0x1;
16 | public final static int THREAD_TYPE_HIGH_PRIORITY = 0x2;
17 | public final static int THREAD_TYPE_LOW_PRIORITY = 0x3;
18 |
19 |
20 | public boolean isPrepared();
21 |
22 | public boolean isPaused();
23 |
24 | public boolean isHardwareAccelerated();
25 | /**
26 | *
27 | * @param type One of THREAD_TYPE_MAIN_THREAD, THREAD_TYPE_HIGH_PRIORITY, THREAD_TYPE_NORMAL_PRIORITY, or THREAD_TYPE_LOW_PRIORITY.
28 | */
29 | public void setDrawingThreadType(int type);
30 |
31 | public void enableDanmakuDrawingCache(boolean enable);
32 |
33 | public boolean isDanmakuDrawingCacheEnabled();
34 |
35 | public void showFPS(boolean show);
36 |
37 | /**
38 | * danmaku.isLive == true的情况下,请在非UI线程中使用此方法,避免可能卡住主线程
39 | * @param item
40 | */
41 | public void addDanmaku(BaseDanmaku item);
42 |
43 | public void invalidateDanmaku(BaseDanmaku item, boolean remeasure);
44 |
45 | public void removeAllDanmakus();
46 |
47 | public void removeAllLiveDanmakus();
48 |
49 | public IDanmakus getCurrentVisibleDanmakus();
50 |
51 | public void setCallback(Callback callback);
52 |
53 | /**
54 | * for getting the accurate play-time. use this method intead of parser.getTimer().currMillisecond
55 | * @return
56 | */
57 | public long getCurrentTime();
58 |
59 | public DanmakuContext getConfig();
60 |
61 | // ------------- Android View方法 --------------------
62 |
63 | public View getView();
64 |
65 | public int getWidth();
66 |
67 | public int getHeight();
68 |
69 | public void setVisibility(int visibility);
70 |
71 | public boolean isShown();
72 |
73 |
74 | // ------------- 播放控制 -------------------
75 |
76 | public void prepare(BaseDanmakuParser parser, DanmakuContext config);
77 |
78 | public void seekTo(Long ms);
79 |
80 | public void start();
81 |
82 | public void start(long postion);
83 |
84 | public void stop();
85 |
86 | public void pause();
87 |
88 | public void resume();
89 |
90 | public void release();
91 |
92 | public void toggle();
93 |
94 | public void show();
95 |
96 | public void hide();
97 |
98 | /**
99 | * show the danmakuview again if you called hideAndPauseDrawTask()
100 | * @param position The position you want to resume
101 | * @see #hideAndPauseDrawTask
102 | */
103 | public void showAndResumeDrawTask(Long position);
104 |
105 | /**
106 | * hide the danmakuview and pause the drawtask
107 | * @return the paused position
108 | * @see #showAndResumeDrawTask
109 | */
110 | public long hideAndPauseDrawTask();
111 |
112 | public void clearDanmakusOnScreen();
113 |
114 | // ------------- Click Listener -------------------
115 | public interface OnDanmakuClickListener {
116 | /**
117 | *
118 | * @param latest the latest one is clicked
119 | */
120 | void onDanmakuClick(BaseDanmaku latest);
121 |
122 | /**
123 | *
124 | * @param danmakus all to be clicked
125 | */
126 | void onDanmakuClick(IDanmakus danmakus);
127 | }
128 |
129 | public void setOnDanmakuClickListener(OnDanmakuClickListener listener);
130 | public OnDanmakuClickListener getOnDanmakuClickListener();
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/gradle/gradle-mvn-push.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Chris Banes
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | apply plugin: 'maven'
18 | apply plugin: 'signing'
19 |
20 | def isReleaseBuild() {
21 | return VERSION_NAME.contains("SNAPSHOT") == false
22 | }
23 |
24 | def getRepositoryUsername() {
25 | return hasProperty('SONATYPE_NEXUS_USERNAME') ? SONATYPE_NEXUS_USERNAME : ""
26 | }
27 |
28 | def getRepositoryPassword() {
29 | return hasProperty('SONATYPE_NEXUS_PASSWORD') ? SONATYPE_NEXUS_PASSWORD : ""
30 | }
31 |
32 | afterEvaluate { project ->
33 | uploadArchives {
34 | repositories {
35 | mavenDeployer {
36 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
37 |
38 | pom.groupId = GROUP
39 | pom.artifactId = POM_ARTIFACT_ID
40 | pom.version = VERSION_NAME
41 |
42 | repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
43 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
44 | }
45 | snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
46 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
47 | }
48 |
49 | pom.project {
50 | name POM_NAME
51 | packaging POM_PACKAGING
52 | description POM_DESCRIPTION
53 | url POM_URL
54 |
55 | scm {
56 | url POM_SCM_URL
57 | connection POM_SCM_CONNECTION
58 | developerConnection POM_SCM_DEV_CONNECTION
59 | }
60 |
61 | licenses {
62 | license {
63 | name POM_LICENCE_NAME
64 | url POM_LICENCE_URL
65 | distribution POM_LICENCE_DIST
66 | }
67 | }
68 |
69 | developers {
70 | developer {
71 | id POM_DEVELOPER_ID
72 | name POM_DEVELOPER_NAME
73 | email POM_DEVELOPER_EMAIL
74 | }
75 | }
76 | }
77 | }
78 | }
79 | }
80 |
81 | signing {
82 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
83 | sign configurations.archives
84 | }
85 |
86 | task androidJavadocs(type: Javadoc) {
87 | source = android.sourceSets.main.java.srcDirs
88 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
89 | options.encoding = 'UTF-8'
90 | if (JavaVersion.current().isJava8Compatible()) {
91 | allprojects {
92 | tasks.withType(Javadoc) {
93 | options.addStringOption('Xdoclint:none', '-quiet')
94 | }
95 | }
96 | }
97 | }
98 |
99 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
100 | classifier = 'javadoc'
101 | from androidJavadocs.destinationDir
102 | }
103 |
104 | task androidSourcesJar(type: Jar) {
105 | classifier = 'sources'
106 | from android.sourceSets.main.java.sourceFiles
107 | }
108 |
109 | artifacts {
110 | archives androidSourcesJar
111 | archives androidJavadocsJar
112 | }
113 | }
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
49 |
50 |
51 |
52 |
56 |
57 |
69 |
70 |
71 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/parser/android/AcFunDanmakuParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.parser.android;
18 |
19 | import org.json.JSONArray;
20 | import org.json.JSONException;
21 | import org.json.JSONObject;
22 |
23 | import android.graphics.Color;
24 |
25 | import master.flame.danmaku.danmaku.model.BaseDanmaku;
26 | import master.flame.danmaku.danmaku.model.android.Danmakus;
27 | import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
28 | import master.flame.danmaku.danmaku.util.DanmakuUtils;
29 |
30 | public class AcFunDanmakuParser extends BaseDanmakuParser {
31 |
32 | @Override
33 | public Danmakus parse() {
34 | if (mDataSource != null && mDataSource instanceof JSONSource) {
35 | JSONSource jsonSource = (JSONSource) mDataSource;
36 | return doParse(jsonSource.data());
37 | }
38 | return new Danmakus();
39 | }
40 |
41 | /**
42 | * @param danmakuListData 弹幕数据
43 | * 传入的数组内包含普通弹幕,会员弹幕,锁定弹幕。
44 | * @return 转换后的Danmakus
45 | */
46 | private Danmakus doParse(JSONArray danmakuListData) {
47 | Danmakus danmakus = new Danmakus();
48 | if (danmakuListData == null || danmakuListData.length() == 0) {
49 | return danmakus;
50 | }
51 | for (int i = 0; i < danmakuListData.length(); i++) {
52 | try {
53 | JSONObject danmakuArray = danmakuListData.getJSONObject(i);
54 | if (danmakuArray != null) {
55 | danmakus = _parse(danmakuArray, danmakus);
56 | }
57 | } catch (JSONException e) {
58 | e.printStackTrace();
59 | }
60 | }
61 | return danmakus;
62 | }
63 |
64 | private Danmakus _parse(JSONObject jsonObject, Danmakus danmakus) {
65 | if (danmakus == null) {
66 | danmakus = new Danmakus();
67 | }
68 | if (jsonObject == null || jsonObject.length() == 0) {
69 | return danmakus;
70 | }
71 | for (int i = 0; i < jsonObject.length(); i++) {
72 | try {
73 | JSONObject obj = jsonObject;
74 | String c = obj.getString("c");
75 | String[] values = c.split(",");
76 | if (values.length > 0) {
77 | int type = Integer.parseInt(values[2]); // 弹幕类型
78 | if (type == 7)
79 | // FIXME : hard code
80 | // TODO : parse advance danmaku json
81 | continue;
82 | long time = (long) (Float.parseFloat(values[0]) * 1000); // 出现时间
83 | int color = Integer.parseInt(values[1]) | 0xFF000000; // 颜色
84 | float textSize = Float.parseFloat(values[3]); // 字体大小
85 | BaseDanmaku item = mContext.mDanmakuFactory.createDanmaku(type, mContext);
86 | if (item != null) {
87 | item.time = time;
88 | item.textSize = textSize * (mDispDensity - 0.6f);
89 | item.textColor = color;
90 | item.textShadowColor = color <= Color.BLACK ? Color.WHITE : Color.BLACK;
91 | DanmakuUtils.fillText(item, obj.optString("m", "...."));
92 | item.index = i;
93 | item.setTimer(mTimer);
94 | danmakus.addItem(item);
95 | }
96 | }
97 | } catch (JSONException e) {
98 | } catch (NumberFormatException e) {
99 | }
100 | }
101 | return danmakus;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/android/SpannedCacheStuffer.java:
--------------------------------------------------------------------------------
1 | package master.flame.danmaku.danmaku.model.android;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.text.Layout;
6 | import android.text.Spannable;
7 | import android.text.SpannableStringBuilder;
8 | import android.text.Spanned;
9 | import android.text.SpannedString;
10 | import android.text.StaticLayout;
11 | import android.text.TextPaint;
12 |
13 | import java.lang.ref.SoftReference;
14 |
15 | import master.flame.danmaku.danmaku.model.BaseDanmaku;
16 | import master.flame.danmaku.danmaku.util.DanmakuUtils;
17 |
18 | /**
19 | * Created by ch on 15-7-16.
20 | */
21 | public class SpannedCacheStuffer extends SimpleTextCacheStuffer {
22 |
23 | @Override
24 | public void measure(BaseDanmaku danmaku, TextPaint paint, boolean fromWorkerThread) {
25 | if (danmaku.text instanceof Spanned) {
26 | if (mProxy != null) {
27 | mProxy.prepareDrawing(danmaku, fromWorkerThread);
28 | }
29 | CharSequence text = danmaku.text;
30 | if (text != null) {
31 | StaticLayout staticLayout = new StaticLayout(text, paint, (int) StaticLayout.getDesiredWidth(danmaku.text, paint), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
32 | danmaku.paintWidth = staticLayout.getWidth();
33 | danmaku.paintHeight = staticLayout.getHeight();
34 | danmaku.obj = new SoftReference<>(staticLayout);
35 | return;
36 | }
37 | }
38 | super.measure(danmaku, paint, fromWorkerThread);
39 | }
40 |
41 | @Override
42 | public void drawStroke(BaseDanmaku danmaku, String lineText, Canvas canvas, float left, float top, Paint paint) {
43 | if (danmaku.obj == null) {
44 | super.drawStroke(danmaku, lineText, canvas, left, top, paint);
45 | }
46 | }
47 |
48 | @Override
49 | public void drawText(BaseDanmaku danmaku, String lineText, Canvas canvas, float left, float top, TextPaint paint, boolean fromWorkerThread) {
50 | if (danmaku.obj == null) {
51 | super.drawText(danmaku, lineText, canvas, left, top, paint, fromWorkerThread);
52 | return;
53 | }
54 | SoftReference reference = (SoftReference) danmaku.obj;
55 | StaticLayout staticLayout = reference.get();
56 | boolean requestRemeasure = 0 != (danmaku.requestFlags & BaseDanmaku.FLAG_REQUEST_REMEASURE);
57 | boolean requestInvalidate = 0 != (danmaku.requestFlags & BaseDanmaku.FLAG_REQUEST_INVALIDATE);
58 |
59 | if (requestInvalidate || staticLayout == null) {
60 | if (requestInvalidate) {
61 | danmaku.requestFlags &= ~BaseDanmaku.FLAG_REQUEST_INVALIDATE;
62 | } else if (mProxy != null) {
63 | mProxy.prepareDrawing(danmaku, fromWorkerThread);
64 | }
65 | CharSequence text = danmaku.text;
66 | if (text != null) {
67 | if (requestRemeasure) {
68 | staticLayout = new StaticLayout(text, paint, (int) StaticLayout.getDesiredWidth(danmaku.text, paint), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
69 | danmaku.paintWidth = staticLayout.getWidth();
70 | danmaku.paintHeight = staticLayout.getHeight();
71 | danmaku.requestFlags &= ~BaseDanmaku.FLAG_REQUEST_REMEASURE;
72 | } else {
73 | staticLayout = new StaticLayout(text, paint, (int) danmaku.paintWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
74 | }
75 | danmaku.obj = new SoftReference<>(staticLayout);
76 | } else {
77 | return;
78 | }
79 | }
80 | boolean needRestore = false;
81 | if (left != 0 && top != 0) {
82 | canvas.save();
83 | canvas.translate(left, top + paint.ascent());
84 | needRestore = true;
85 | }
86 | staticLayout.draw(canvas);
87 | if (needRestore) {
88 | canvas.restore();
89 | }
90 | }
91 |
92 | @Override
93 | public void clearCaches() {
94 | super.clearCaches();
95 | System.gc();
96 | }
97 |
98 | @Override
99 | public void clearCache(BaseDanmaku danmaku) {
100 | super.clearCache(danmaku);
101 | if (danmaku.obj instanceof SoftReference>) {
102 | ((SoftReference>) danmaku.obj).clear();
103 | }
104 | }
105 |
106 | @Override
107 | public void releaseResource(BaseDanmaku danmaku) {
108 | clearCache(danmaku);
109 | super.releaseResource(danmaku);
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/tv/cjump/jni/DeviceUtils.java:
--------------------------------------------------------------------------------
1 |
2 | package tv.cjump.jni;
3 |
4 | import android.os.Build;
5 | import android.os.Environment;
6 | import android.text.TextUtils;
7 | import android.util.Log;
8 |
9 | import java.io.File;
10 | import java.io.FileNotFoundException;
11 | import java.io.IOException;
12 | import java.io.RandomAccessFile;
13 | import java.lang.reflect.Field;
14 |
15 | public class DeviceUtils {
16 |
17 | public static final String ABI_X86 = "x86";
18 |
19 | public static final String ABI_MIPS = "mips";
20 |
21 | public static enum ARCH {
22 | Unknown, ARM, X86, MIPS, ARM64,
23 | }
24 |
25 | private static ARCH sArch = ARCH.Unknown;
26 |
27 | // see include/uapi/linux/elf-em.h
28 | private static final int EM_ARM = 40;
29 | private static final int EM_386 = 3;
30 | private static final int EM_MIPS = 8;
31 | private static final int EM_AARCH64 = 183;
32 |
33 | // /system/lib/libc.so
34 | // XXX: need a runtime check
35 | public static synchronized ARCH getMyCpuArch() {
36 | byte[] data = new byte[20];
37 | File libc = new File(Environment.getRootDirectory(), "lib/libc.so");
38 | if (libc.canRead()) {
39 | RandomAccessFile fp = null;
40 | try {
41 | fp = new RandomAccessFile(libc, "r");
42 | fp.readFully(data);
43 | int machine = (data[19] << 8) | data[18];
44 | switch (machine) {
45 | case EM_ARM:
46 | sArch = ARCH.ARM;
47 | break;
48 | case EM_386:
49 | sArch = ARCH.X86;
50 | break;
51 | case EM_MIPS:
52 | sArch = ARCH.MIPS;
53 | break;
54 | case EM_AARCH64:
55 | sArch = ARCH.ARM64;
56 | break;
57 | default:
58 | Log.e("NativeBitmapFactory", "libc.so is unknown arch: " + Integer.toHexString(machine));
59 | break;
60 | }
61 | } catch (FileNotFoundException e) {
62 | e.printStackTrace();
63 | } catch (IOException e) {
64 | e.printStackTrace();
65 | } finally {
66 | if (fp != null) {
67 | try {
68 | fp.close();
69 | } catch (IOException e) {
70 | e.printStackTrace();
71 | }
72 | }
73 | }
74 | }
75 | return sArch;
76 | }
77 |
78 | public static String get_CPU_ABI() {
79 | return Build.CPU_ABI;
80 | }
81 |
82 | public static String get_CPU_ABI2() {
83 | try {
84 | Field field = Build.class.getDeclaredField("CPU_ABI2");
85 | if (field == null)
86 | return null;
87 |
88 | Object fieldValue = field.get(null);
89 | if (!(fieldValue instanceof String)) {
90 | return null;
91 | }
92 |
93 | return (String) fieldValue;
94 | } catch (Exception e) {
95 |
96 | }
97 |
98 | return null;
99 | }
100 |
101 | public static boolean supportABI(String requestAbi) {
102 | String abi = get_CPU_ABI();
103 | if (!TextUtils.isEmpty(abi) && abi.equalsIgnoreCase(requestAbi))
104 | return true;
105 |
106 | String abi2 = get_CPU_ABI2();
107 | return !TextUtils.isEmpty(abi2) && abi.equalsIgnoreCase(requestAbi);
108 |
109 | }
110 |
111 | public static boolean supportX86() {
112 | return supportABI(ABI_X86);
113 | }
114 |
115 | public static boolean supportMips() {
116 | return supportABI(ABI_MIPS);
117 | }
118 |
119 | public static boolean isARMSimulatedByX86() {
120 | ARCH arch = getMyCpuArch();
121 | return !supportX86() && ARCH.X86.equals(arch);
122 | }
123 |
124 | public static boolean isMiBox2Device() {
125 | String manufacturer = Build.MANUFACTURER;
126 | String productName = Build.PRODUCT;
127 | return manufacturer.equalsIgnoreCase("Xiaomi")
128 | && productName.equalsIgnoreCase("dredd");
129 | }
130 |
131 | public static boolean isMagicBoxDevice() {
132 | String manufacturer = Build.MANUFACTURER;
133 | String productName = Build.PRODUCT;
134 | return manufacturer.equalsIgnoreCase("MagicBox")
135 | && productName.equalsIgnoreCase("MagicBox");
136 | }
137 |
138 | public static boolean isProblemBoxDevice() {
139 | return isMiBox2Device() || isMagicBoxDevice();
140 | }
141 |
142 | public static boolean isRealARMArch() {
143 | ARCH arch = getMyCpuArch();
144 | return (supportABI("armeabi-v7a") || supportABI("armeabi")) && ARCH.ARM.equals(arch);
145 | }
146 |
147 | public static boolean isRealX86Arch() {
148 | ARCH arch = getMyCpuArch();
149 | return supportABI(ABI_X86) || ARCH.X86.equals(arch);
150 | }
151 |
152 | }
153 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/renderer/IRenderer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.renderer;
18 |
19 |
20 | import master.flame.danmaku.danmaku.model.ICacheManager;
21 | import master.flame.danmaku.danmaku.model.BaseDanmaku;
22 | import master.flame.danmaku.danmaku.model.IDanmakus;
23 | import master.flame.danmaku.danmaku.model.IDisplayer;
24 |
25 | public interface IRenderer {
26 |
27 | int NOTHING_RENDERING = 0;
28 | int CACHE_RENDERING = 1;
29 | int TEXT_RENDERING = 2;
30 |
31 | class Area {
32 |
33 | public final float[] mRefreshRect = new float[4];
34 | private int mMaxHeight;
35 | private int mMaxWidth;
36 |
37 | public void setEdge(int maxWidth, int maxHeight) {
38 | mMaxWidth = maxWidth;
39 | mMaxHeight = maxHeight;
40 | }
41 |
42 | public void reset() {
43 | set(mMaxWidth, mMaxHeight, 0, 0);
44 | }
45 |
46 | public void resizeToMax() {
47 | set(0, 0, mMaxWidth, mMaxHeight);
48 | }
49 |
50 | public void set(float left, float top, float right, float bottom) {
51 | mRefreshRect[0] = left;
52 | mRefreshRect[1] = top;
53 | mRefreshRect[2] = right;
54 | mRefreshRect[3] = bottom;
55 | }
56 |
57 | }
58 |
59 | public class RenderingState {
60 | public final static int UNKNOWN_TIME = -1;
61 |
62 | public int r2lDanmakuCount;
63 | public int l2rDanmakuCount;
64 | public int ftDanmakuCount;
65 | public int fbDanmakuCount;
66 | public int specialDanmakuCount;
67 | public int totalDanmakuCount;
68 | public int incrementCount;
69 | public long consumingTime;
70 | public long beginTime;
71 | public long endTime;
72 | public boolean nothingRendered;
73 | public long sysTime;
74 | public long cacheHitCount;
75 | public long cacheMissCount;
76 |
77 | public int addTotalCount(int count) {
78 | totalDanmakuCount += count;
79 | return totalDanmakuCount;
80 | }
81 |
82 | public int addCount(int type, int count) {
83 | switch (type) {
84 | case BaseDanmaku.TYPE_SCROLL_RL:
85 | r2lDanmakuCount += count;
86 | return r2lDanmakuCount;
87 | case BaseDanmaku.TYPE_SCROLL_LR:
88 | l2rDanmakuCount += count;
89 | return l2rDanmakuCount;
90 | case BaseDanmaku.TYPE_FIX_TOP:
91 | ftDanmakuCount += count;
92 | return ftDanmakuCount;
93 | case BaseDanmaku.TYPE_FIX_BOTTOM:
94 | fbDanmakuCount += count;
95 | return fbDanmakuCount;
96 | case BaseDanmaku.TYPE_SPECIAL:
97 | specialDanmakuCount += count;
98 | return specialDanmakuCount;
99 | }
100 | return 0;
101 | }
102 |
103 | public void reset() {
104 | r2lDanmakuCount = l2rDanmakuCount = ftDanmakuCount = fbDanmakuCount = specialDanmakuCount = totalDanmakuCount = 0;
105 | sysTime = beginTime = endTime = consumingTime = 0;
106 | nothingRendered = false;
107 | }
108 |
109 | public void set(RenderingState other) {
110 | if(other == null)
111 | return;
112 | r2lDanmakuCount = other.r2lDanmakuCount;
113 | l2rDanmakuCount = other.l2rDanmakuCount;
114 | ftDanmakuCount = other.ftDanmakuCount;
115 | fbDanmakuCount = other.fbDanmakuCount;
116 | specialDanmakuCount = other.specialDanmakuCount;
117 | totalDanmakuCount = other.totalDanmakuCount;
118 | incrementCount = other.incrementCount;
119 | consumingTime = other.consumingTime;
120 | beginTime = other.beginTime;
121 | endTime = other.endTime;
122 | nothingRendered = other.nothingRendered;
123 | sysTime = other.sysTime;
124 | cacheHitCount = other.cacheHitCount;
125 | cacheMissCount = other.cacheMissCount;
126 | }
127 | }
128 |
129 | RenderingState draw(IDisplayer disp, IDanmakus danmakus, long startRenderTime);
130 |
131 | void clear();
132 |
133 | void clearRetainer();
134 |
135 | void release();
136 |
137 | void setVerifierEnabled(boolean enabled);
138 |
139 | void setCacheManager(ICacheManager cacheManager);
140 |
141 | }
142 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/renderer/android/DanmakuRenderer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.renderer.android;
18 |
19 | import android.os.SystemClock;
20 |
21 | import master.flame.danmaku.danmaku.model.BaseDanmaku;
22 | import master.flame.danmaku.danmaku.model.DanmakuTimer;
23 | import master.flame.danmaku.danmaku.model.ICacheManager;
24 | import master.flame.danmaku.danmaku.model.IDanmakuIterator;
25 | import master.flame.danmaku.danmaku.model.IDanmakus;
26 | import master.flame.danmaku.danmaku.model.IDisplayer;
27 | import master.flame.danmaku.danmaku.model.android.DanmakuContext;
28 | import master.flame.danmaku.danmaku.renderer.IRenderer;
29 | import master.flame.danmaku.danmaku.renderer.Renderer;
30 |
31 |
32 | public class DanmakuRenderer extends Renderer {
33 |
34 | private final DanmakuTimer mStartTimer = new DanmakuTimer();
35 | private final RenderingState mRenderingState = new RenderingState();
36 | private final DanmakuContext mContext;
37 | private DanmakusRetainer.Verifier mVerifier;
38 | private final DanmakusRetainer.Verifier verifier = new DanmakusRetainer.Verifier() {
39 | @Override
40 | public boolean skipLayout(BaseDanmaku danmaku, float fixedTop, int lines, boolean willHit) {
41 | if (danmaku.priority == 0 && mContext.mDanmakuFilters.filterSecondary(danmaku, lines, 0, mStartTimer, willHit, mContext)) {
42 | danmaku.setVisibility(false);
43 | return true;
44 | }
45 | return false;
46 | }
47 | };
48 | private final DanmakusRetainer mDanmakusRetainer;
49 | private ICacheManager mCacheManager;
50 |
51 | public DanmakuRenderer(DanmakuContext config) {
52 | mContext = config;
53 | mDanmakusRetainer = new DanmakusRetainer();
54 | }
55 |
56 | @Override
57 | public void clear() {
58 | clearRetainer();
59 | mContext.mDanmakuFilters.clear();
60 | }
61 |
62 | @Override
63 | public void clearRetainer() {
64 | mDanmakusRetainer.clear();
65 | }
66 |
67 | @Override
68 | public void release() {
69 | mDanmakusRetainer.release();
70 | mContext.mDanmakuFilters.clear();
71 | }
72 |
73 | @Override
74 | public void setVerifierEnabled(boolean enabled) {
75 | mVerifier = (enabled ? verifier : null);
76 | }
77 |
78 | @Override
79 | public RenderingState draw(IDisplayer disp, IDanmakus danmakus, long startRenderTime) {
80 | int lastTotalDanmakuCount = mRenderingState.totalDanmakuCount;
81 | mRenderingState.reset();
82 | IDanmakuIterator itr = danmakus.iterator();
83 | int orderInScreen = 0;
84 | mStartTimer.update(SystemClock.uptimeMillis());
85 | int sizeInScreen = danmakus.size();
86 | BaseDanmaku drawItem = null;
87 | while (itr.hasNext()) {
88 |
89 | drawItem = itr.next();
90 |
91 | if (!drawItem.hasPassedFilter()) {
92 | mContext.mDanmakuFilters.filter(drawItem, orderInScreen, sizeInScreen, mStartTimer, false, mContext);
93 | }
94 |
95 | if (drawItem.time < startRenderTime
96 | || (drawItem.priority == 0 && drawItem.isFiltered())) {
97 | continue;
98 | }
99 |
100 | if (drawItem.isLate()) {
101 | if (mCacheManager != null && !drawItem.hasDrawingCache()) {
102 | mCacheManager.addDanmaku(drawItem);
103 | continue;
104 | }
105 | break;
106 | }
107 |
108 | if (drawItem.getType() == BaseDanmaku.TYPE_SCROLL_RL){
109 | // 同屏弹幕密度只对滚动弹幕有效
110 | orderInScreen++;
111 | }
112 |
113 | // measure
114 | if (!drawItem.isMeasured()) {
115 | drawItem.measure(disp, false);
116 | }
117 |
118 | // layout
119 | mDanmakusRetainer.fix(drawItem, disp, mVerifier);
120 |
121 | // draw
122 | if (!drawItem.isOutside() && drawItem.isShown()) {
123 | if (drawItem.lines == null && drawItem.getBottom() > disp.getHeight()) {
124 | continue; // skip bottom outside danmaku
125 | }
126 | int renderingType = drawItem.draw(disp);
127 | if(renderingType == IRenderer.CACHE_RENDERING) {
128 | mRenderingState.cacheHitCount++;
129 | } else if(renderingType == IRenderer.TEXT_RENDERING) {
130 | mRenderingState.cacheMissCount++;
131 | if (mCacheManager != null) {
132 | mCacheManager.addDanmaku(drawItem);
133 | }
134 | }
135 | mRenderingState.addCount(drawItem.getType(), 1);
136 | mRenderingState.addTotalCount(1);
137 | }
138 |
139 | }
140 |
141 | mRenderingState.nothingRendered = (mRenderingState.totalDanmakuCount == 0);
142 | mRenderingState.endTime = drawItem != null ? drawItem.time : RenderingState.UNKNOWN_TIME;
143 | if (mRenderingState.nothingRendered) {
144 | mRenderingState.beginTime = RenderingState.UNKNOWN_TIME;
145 | }
146 | mRenderingState.incrementCount = mRenderingState.totalDanmakuCount - lastTotalDanmakuCount;
147 | mRenderingState.consumingTime = mStartTimer.update(SystemClock.uptimeMillis());
148 | return mRenderingState;
149 | }
150 |
151 | public void setCacheManager(ICacheManager cacheManager) {
152 | mCacheManager = cacheManager;
153 | }
154 |
155 | }
156 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/androidTest/java/tv/cjump/jni/NativeBitmapFactoryTest.java:
--------------------------------------------------------------------------------
1 | package tv.cjump.jni;
2 |
3 | import android.app.ActivityManager;
4 | import android.app.Instrumentation;
5 | import android.content.Context;
6 | import android.graphics.Bitmap;
7 | import android.graphics.Canvas;
8 | import android.graphics.Color;
9 | import android.graphics.Paint;
10 | import android.os.Debug;
11 | import android.os.SystemClock;
12 | import android.test.InstrumentationTestCase;
13 | import android.util.Log;
14 |
15 | import junit.framework.Assert;
16 | import junit.framework.TestCase;
17 |
18 | import java.util.ArrayList;
19 | import java.util.Locale;
20 |
21 | /**
22 | * Created by ch on 15-6-12.
23 | */
24 | public class NativeBitmapFactoryTest extends InstrumentationTestCase {
25 |
26 | private static final int DEFAULT_MESSAGE_SIZE = 1024;
27 | private static final int BYTES_IN_MEGABYTE = 1024 * 1024;
28 |
29 | private static final int BITMAP_WIDTH = 200;
30 | private static final int BITMAP_HEIGHT = 200;
31 | private static final String TAG = NativeBitmapFactoryTest.class.getSimpleName();
32 |
33 | public void testLoadLibs() {
34 | NativeBitmapFactory.loadLibs();
35 | boolean isInNativeAlloc = NativeBitmapFactory.isInNativeAlloc();
36 | Assert.assertTrue("NativeBitmapFactory is not supported on your OS", isInNativeAlloc);
37 | }
38 |
39 | public void testNativeBitmap() {
40 | Bitmap bitmap = NativeBitmapFactory.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Bitmap.Config.ARGB_8888);
41 | accessBitmap(bitmap);
42 | bitmap.recycle();
43 | gcAndWait();
44 | }
45 |
46 | public void testDalvikBitmap() {
47 | Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Bitmap.Config.ARGB_8888);
48 | accessBitmap(bitmap);
49 | bitmap.recycle();
50 | gcAndWait();
51 | }
52 |
53 | public void testNativeBitmaps() {
54 | StringBuilder sb = new StringBuilder(DEFAULT_MESSAGE_SIZE);
55 | appendValue(sb, "\n\n", "===== before create 50 NativeBitmap", "\n\n");
56 | updateHeapValue(sb);
57 | final String message = sb.toString();
58 | Log.i(TAG, message);
59 | sb = new StringBuilder();
60 | ArrayList bitmaps = new ArrayList<>();
61 | for (int i = 0; i < 150; i++) {
62 | Bitmap bitmap = NativeBitmapFactory.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Bitmap.Config.ARGB_8888);
63 | accessBitmap(bitmap);
64 | bitmaps.add(bitmap);
65 | }
66 | updateHeapValue(sb);
67 | Log.d(TAG, sb.toString());
68 | for (Bitmap bitmap : bitmaps) {
69 | bitmap.recycle();
70 | }
71 | gcAndWait();
72 | }
73 |
74 | public Context getContext(){
75 | return getInstrumentation().getTargetContext();
76 | }
77 |
78 | private void updateHeapValue(StringBuilder sb) {
79 |
80 | ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
81 | ActivityManager activityManager = (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
82 | activityManager.getMemoryInfo(mi);
83 | long availableMegs = mi.availMem;
84 | final Runtime runtime = Runtime.getRuntime();
85 | final long heapMemory = runtime.totalMemory() - runtime.freeMemory();
86 | // When changing format of output below, make sure to sync "scripts/test_runner.py" as well.
87 | appendSize(sb, "System availMem: ", availableMegs, "\n");
88 | appendSize(sb, "Java heap size: ", heapMemory, "\n");
89 | appendSize(sb, "Native heap size: ", Debug.getNativeHeapSize(), "\n");
90 | }
91 |
92 | public void testDalvikBitmaps() {
93 | StringBuilder sb = new StringBuilder(DEFAULT_MESSAGE_SIZE);
94 | appendValue(sb, "\n\n", "===== before create 50 DalvikBitmap", "\n\n");
95 | updateHeapValue(sb);
96 | final String message = sb.toString();
97 | Log.i(TAG, message);
98 | sb = new StringBuilder();
99 | ArrayList bitmaps = new ArrayList<>();
100 | for (int i = 0; i < 150; i++) {
101 | Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Bitmap.Config.ARGB_8888);
102 | accessBitmap(bitmap);
103 | bitmaps.add(bitmap);
104 | }
105 | updateHeapValue(sb);
106 | Log.d(TAG, sb.toString());
107 | for (Bitmap bitmap : bitmaps) {
108 | bitmap.recycle();
109 | }
110 | gcAndWait();
111 | }
112 |
113 | public void testReleaseLibs() {
114 | NativeBitmapFactory.releaseLibs();
115 | }
116 |
117 |
118 | private void accessBitmap(Bitmap bitmap) {
119 | boolean result = (bitmap != null && bitmap.getWidth() == BITMAP_WIDTH && bitmap.getHeight() == BITMAP_HEIGHT);
120 | if (result) {
121 | if (android.os.Build.VERSION.SDK_INT >= 17 && !bitmap.isPremultiplied()) {
122 | bitmap.setPremultiplied(true);
123 | }
124 | Canvas canvas = new Canvas(bitmap);
125 | Paint paint = new Paint();
126 | paint.setColor(Color.RED);
127 | paint.setTextSize(20f);
128 | canvas.drawRect(0f, 0f, (float) bitmap.getWidth(), (float) bitmap.getHeight(),
129 | paint);
130 | canvas.drawText("TestLib", 0, 0, paint);
131 | }
132 | }
133 |
134 | private void gcAndWait() {
135 | System.gc();
136 | SystemClock.sleep(10000);
137 | // try {
138 | // Debug.dumpHprofData("/sdcard/nbf_test_dump.hprof");
139 | // } catch (IOException e) {
140 | // e.printStackTrace();
141 | // }
142 | }
143 |
144 | private static void appendSize(StringBuilder sb, String prefix, long bytes, String suffix) {
145 | String value = String.format(Locale.getDefault(), "%.2f", (float) bytes / BYTES_IN_MEGABYTE);
146 | appendValue(sb, prefix, value + " MB", suffix);
147 | }
148 |
149 | private static void appendTime(StringBuilder sb, String prefix, long timeMs, String suffix) {
150 | appendValue(sb, prefix, timeMs + " ms", suffix);
151 | }
152 |
153 | private static void appendNumber(StringBuilder sb, String prefix, long number, String suffix) {
154 | appendValue(sb, prefix, number + "", suffix);
155 | }
156 |
157 | private static void appendValue(StringBuilder sb, String prefix, String value, String suffix) {
158 | sb.append(prefix).append(value).append(suffix);
159 | }
160 |
161 | }
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/tv/cjump/jni/NativeBitmapFactory.java:
--------------------------------------------------------------------------------
1 |
2 | package tv.cjump.jni;
3 |
4 | import android.annotation.SuppressLint;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Bitmap.Config;
7 | import android.graphics.Canvas;
8 | import android.graphics.Color;
9 | import android.graphics.Paint;
10 | import android.util.Log;
11 |
12 | import java.lang.reflect.Field;
13 |
14 | public class NativeBitmapFactory {
15 |
16 | static Field nativeIntField = null;
17 |
18 | static boolean nativeLibLoaded = false;
19 | static boolean notLoadAgain = false;
20 |
21 | public static boolean isInNativeAlloc() {
22 | return android.os.Build.VERSION.SDK_INT < 11 || (nativeLibLoaded && nativeIntField != null);
23 | }
24 |
25 | public static void loadLibs() {
26 | if (notLoadAgain) {
27 | return;
28 | }
29 | if (!(DeviceUtils.isRealARMArch() || DeviceUtils.isRealX86Arch())) {
30 | nativeLibLoaded = false;
31 | return;
32 | }
33 | if (nativeLibLoaded) {
34 | return;
35 | }
36 | try {
37 | if (android.os.Build.VERSION.SDK_INT >= 11) {
38 | System.loadLibrary("ndkbitmap");
39 | nativeLibLoaded = true;
40 | } else {
41 | notLoadAgain = true;
42 | nativeLibLoaded = false;
43 | }
44 | } catch (Exception e) {
45 | e.printStackTrace();
46 | notLoadAgain = true;
47 | nativeLibLoaded = false;
48 | } catch (Error e) {
49 | e.printStackTrace();
50 | notLoadAgain = true;
51 | nativeLibLoaded = false;
52 | }
53 | if (nativeLibLoaded) {
54 | boolean libInit = init();
55 | if (!libInit) {
56 | release();
57 | notLoadAgain = true;
58 | nativeLibLoaded = false;
59 | } else {
60 | initField();
61 | boolean confirm = testLib();
62 | if (!confirm) {
63 | // 测试so文件函数是否调用失败
64 | release();
65 | notLoadAgain = true;
66 | nativeLibLoaded = false;
67 | }
68 | }
69 | }
70 |
71 | Log.e("NativeBitmapFactory", "loaded" + nativeLibLoaded);
72 | }
73 |
74 | public static void releaseLibs() {
75 | if (nativeLibLoaded) {
76 | release();
77 | }
78 | nativeIntField = null;
79 | nativeLibLoaded = false;
80 | // Log.e("NativeBitmapFactory", "released");
81 | }
82 |
83 | static void initField() {
84 | try {
85 | nativeIntField = Bitmap.Config.class.getDeclaredField("nativeInt");
86 | nativeIntField.setAccessible(true);
87 | } catch (NoSuchFieldException e) {
88 | nativeIntField = null;
89 | e.printStackTrace();
90 | }
91 | }
92 |
93 | @SuppressLint("NewApi")
94 | private static boolean testLib() {
95 | if (nativeIntField == null) {
96 | return false;
97 | }
98 | Bitmap bitmap = null;
99 | Canvas canvas = null;
100 | try {
101 | bitmap = createNativeBitmap(2, 2, Bitmap.Config.ARGB_8888, true);
102 | boolean result = (bitmap != null && bitmap.getWidth() == 2 && bitmap.getHeight() == 2);
103 | if (result) {
104 | if (android.os.Build.VERSION.SDK_INT >= 17 && !bitmap.isPremultiplied()) {
105 | bitmap.setPremultiplied(true);
106 | }
107 | canvas = new Canvas(bitmap);
108 | Paint paint = new Paint();
109 | paint.setColor(Color.RED);
110 | paint.setTextSize(20f);
111 | canvas.drawRect(0f, 0f, (float) bitmap.getWidth(), (float) bitmap.getHeight(),
112 | paint);
113 | canvas.drawText("TestLib", 0, 0, paint);
114 | if (android.os.Build.VERSION.SDK_INT >= 17) {
115 | result = bitmap.isPremultiplied();
116 | }
117 | }
118 | return result;
119 | } catch (Exception e) {
120 | Log.e("NativeBitmapFactory", "exception:" + e.toString());
121 | return false;
122 | } catch (Error e) {
123 | return false;
124 | } finally {
125 | if (bitmap != null) {
126 | bitmap.recycle();
127 | bitmap = null;
128 | }
129 | }
130 | }
131 |
132 | public static int getNativeConfig(Bitmap.Config config) {
133 | try {
134 | if (nativeIntField == null) {
135 | return 0;
136 | }
137 | return nativeIntField.getInt(config);
138 | } catch (IllegalArgumentException e) {
139 | e.printStackTrace();
140 | } catch (IllegalAccessException e) {
141 | e.printStackTrace();
142 | }
143 | return 0;
144 | }
145 |
146 | public static Bitmap createBitmap(int width, int height, Bitmap.Config config) {
147 | return createBitmap(width, height, config, config.equals(Bitmap.Config.ARGB_8888));
148 | }
149 |
150 | public static void recycle(Bitmap bitmap) {
151 | bitmap.recycle();
152 | }
153 |
154 | public static Bitmap createBitmap(int width, int height, Bitmap.Config config, boolean hasAlpha) {
155 | if (!nativeLibLoaded || nativeIntField == null) {
156 | // Log.e("NativeBitmapFactory", "ndk bitmap create failed");
157 | return Bitmap.createBitmap(width, height, config);
158 | }
159 | return createNativeBitmap(width, height, config, hasAlpha);
160 | }
161 |
162 | private static Bitmap createNativeBitmap(int width, int height, Config config, boolean hasAlpha) {
163 | int nativeConfig = getNativeConfig(config);
164 | // Log.e("NativeBitmapFactory", "nativeConfig:" + nativeConfig);
165 | // Log.e("NativeBitmapFactory", "create bitmap:" + bitmap);
166 | return android.os.Build.VERSION.SDK_INT == 19 ? createBitmap19(width, height,
167 | nativeConfig, hasAlpha) : createBitmap(width, height, nativeConfig, hasAlpha);
168 | }
169 |
170 | // ///////////native methods//////////
171 |
172 | private static native boolean init();
173 |
174 | private static native boolean release();
175 |
176 | private static native Bitmap createBitmap(int width, int height, int nativeConfig,
177 | boolean hasAlpha);
178 |
179 | private static native Bitmap createBitmap19(int width, int height, int nativeConfig,
180 | boolean hasAlpha);
181 |
182 | }
183 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/android/DrawingCacheHolder.java:
--------------------------------------------------------------------------------
1 |
2 | package master.flame.danmaku.danmaku.model.android;
3 |
4 | import android.annotation.SuppressLint;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.Paint;
9 | import android.graphics.Rect;
10 |
11 | import tv.cjump.jni.NativeBitmapFactory;
12 |
13 | public class DrawingCacheHolder {
14 |
15 | public Canvas canvas;
16 |
17 | public Bitmap bitmap;
18 |
19 | public Bitmap[][] bitmapArray;
20 |
21 | public Object extra;
22 |
23 | public int width;
24 |
25 | public int height;
26 |
27 | public boolean drawn;
28 |
29 | private int mDensity;
30 |
31 | public DrawingCacheHolder() {
32 |
33 | }
34 |
35 | public DrawingCacheHolder(int w, int h) {
36 | buildCache(w, h, 0, true);
37 | }
38 |
39 | public DrawingCacheHolder(int w, int h, int density) {
40 | mDensity = density;
41 | buildCache(w, h, density, true);
42 | }
43 |
44 | public void buildCache(int w, int h, int density, boolean checkSizeEquals) {
45 | boolean reuse = checkSizeEquals ? (w == width && h == height) : (w <= width && h <= height);
46 | if (reuse && bitmap != null) {
47 | // canvas.drawColor(Color.TRANSPARENT);
48 | canvas.setBitmap(null);
49 | bitmap.eraseColor(Color.TRANSPARENT);
50 | canvas.setBitmap(bitmap);
51 | recycleBitmapArray();
52 | return;
53 | }
54 | if (bitmap != null) {
55 | recycle();
56 | }
57 | width = w;
58 | height = h;
59 | bitmap = NativeBitmapFactory.createBitmap(w, h, Bitmap.Config.ARGB_8888);
60 | if (density > 0) {
61 | mDensity = density;
62 | bitmap.setDensity(density);
63 | }
64 | if (canvas == null){
65 | canvas = new Canvas(bitmap);
66 | canvas.setDensity(density);
67 | }else
68 | canvas.setBitmap(bitmap);
69 | }
70 |
71 | public void erase() {
72 | eraseBitmap(bitmap);
73 | eraseBitmapArray();
74 | }
75 |
76 | public synchronized void recycle() {
77 | width = height = 0;
78 | // if (canvas != null) {
79 | // canvas = null;
80 | // }
81 | if (bitmap != null) {
82 | bitmap.recycle();
83 | bitmap = null;
84 | }
85 | recycleBitmapArray();
86 | extra = null;
87 | }
88 |
89 | @SuppressLint("NewApi")
90 | public void splitWith(int dispWidth, int dispHeight, int maximumCacheWidth, int maximumCacheHeight) {
91 | recycleBitmapArray();
92 | if (width <= 0 || height <= 0 || bitmap == null) {
93 | return;
94 | }
95 | if (width <= maximumCacheWidth && height <= maximumCacheHeight) {
96 | return;
97 | }
98 | maximumCacheWidth = Math.min(maximumCacheWidth, dispWidth);
99 | maximumCacheHeight = Math.min(maximumCacheHeight, dispHeight);
100 | int xCount = width / maximumCacheWidth + (width % maximumCacheWidth == 0 ? 0 : 1);
101 | int yCount = height / maximumCacheHeight + (height % maximumCacheHeight == 0 ? 0 : 1);
102 | int averageWidth = width / xCount;
103 | int averageHeight = height / yCount;
104 | final Bitmap[][] bmpArray = new Bitmap[yCount][xCount];
105 | if (canvas == null){
106 | canvas = new Canvas();
107 | if (mDensity > 0) {
108 | canvas.setDensity(mDensity);
109 | }
110 | }
111 | Rect rectSrc = new Rect();
112 | Rect rectDst = new Rect();
113 | for (int yIndex = 0; yIndex < yCount; yIndex++) {
114 | for (int xIndex = 0; xIndex < xCount; xIndex++) {
115 | Bitmap bmp = bmpArray[yIndex][xIndex] = NativeBitmapFactory.createBitmap(
116 | averageWidth, averageHeight, Bitmap.Config.ARGB_8888);
117 | if (mDensity > 0) {
118 | bmp.setDensity(mDensity);
119 | }
120 | canvas.setBitmap(bmp);
121 | int left = xIndex * averageWidth, top = yIndex * averageHeight;
122 | rectSrc.set(left, top, left + averageWidth, top + averageHeight);
123 | rectDst.set(0, 0, bmp.getWidth(), bmp.getHeight());
124 | canvas.drawBitmap(bitmap, rectSrc, rectDst, null);
125 | }
126 | }
127 | canvas.setBitmap(bitmap);
128 | bitmapArray = bmpArray;
129 | }
130 |
131 | private void eraseBitmap(Bitmap bmp) {
132 | if (bmp != null) {
133 | bmp.eraseColor(Color.TRANSPARENT);
134 | }
135 | }
136 |
137 | private void eraseBitmapArray() {
138 | if (bitmapArray != null) {
139 | for (int i = 0; i < bitmapArray.length; i++) {
140 | for (int j = 0; j < bitmapArray[i].length; j++) {
141 | eraseBitmap(bitmapArray[i][j]);
142 | }
143 | }
144 | }
145 | }
146 |
147 | private void recycleBitmapArray() {
148 | if (bitmapArray != null) {
149 | for (int i = 0; i < bitmapArray.length; i++) {
150 | for (int j = 0; j < bitmapArray[i].length; j++) {
151 | if (bitmapArray[i][j] != null) {
152 | bitmapArray[i][j].recycle();
153 | bitmapArray[i][j] = null;
154 | }
155 | }
156 | }
157 | bitmapArray = null;
158 | }
159 | }
160 |
161 | public final synchronized boolean draw(Canvas canvas, float left, float top, Paint paint) {
162 | if (bitmapArray != null) {
163 | for (int i = 0; i < bitmapArray.length; i++) {
164 | for (int j = 0; j < bitmapArray[i].length; j++) {
165 | Bitmap bmp = bitmapArray[i][j];
166 | if (bmp != null) {
167 | float dleft = left + j * bmp.getWidth();
168 | if (dleft > canvas.getWidth() || dleft + bmp.getWidth() < 0) {
169 | continue;
170 | }
171 | float dtop = top + i * bmp.getHeight();
172 | if (dtop > canvas.getHeight() || dtop + bmp.getHeight() < 0) {
173 | continue;
174 | }
175 | canvas.drawBitmap(bmp, dleft, dtop, paint);
176 | }
177 | }
178 | }
179 | return true;
180 | } else if (bitmap != null) {
181 | canvas.drawBitmap(bitmap, left, top, paint);
182 | return true;
183 | }
184 | return false;
185 | }
186 |
187 | }
188 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/util/DanmakuUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.util;
18 |
19 | import android.text.TextUtils;
20 |
21 | import master.flame.danmaku.danmaku.model.AbsDisplayer;
22 | import master.flame.danmaku.danmaku.model.BaseDanmaku;
23 | import master.flame.danmaku.danmaku.model.IDisplayer;
24 | import master.flame.danmaku.danmaku.model.android.AndroidDisplayer;
25 | import master.flame.danmaku.danmaku.model.android.DrawingCache;
26 | import master.flame.danmaku.danmaku.model.android.DrawingCacheHolder;
27 |
28 | public class DanmakuUtils {
29 |
30 | /**
31 | * 检测两个弹幕是否会碰撞
32 | * 允许不同类型弹幕的碰撞
33 | * @param d1
34 | * @param d2
35 | * @return
36 | */
37 | public static boolean willHitInDuration(IDisplayer disp, BaseDanmaku d1, BaseDanmaku d2,
38 | long duration, long currTime) {
39 | final int type1 = d1.getType();
40 | final int type2 = d2.getType();
41 | // allow hit if different type
42 | if(type1 != type2)
43 | return false;
44 |
45 | if(d1.isOutside()){
46 | return false;
47 | }
48 | long dTime = d2.time - d1.time;
49 | if (dTime < 0)
50 | return true;
51 | if (Math.abs(dTime) >= duration || d1.isTimeOut() || d2.isTimeOut()) {
52 | return false;
53 | }
54 |
55 | if (type1 == BaseDanmaku.TYPE_FIX_TOP || type1 == BaseDanmaku.TYPE_FIX_BOTTOM) {
56 | return true;
57 | }
58 |
59 | return checkHitAtTime(disp, d1, d2, currTime)
60 | || checkHitAtTime(disp, d1, d2, d1.time + d1.getDuration());
61 | }
62 |
63 | private static boolean checkHitAtTime(IDisplayer disp, BaseDanmaku d1, BaseDanmaku d2, long time){
64 | final float[] rectArr1 = d1.getRectAtTime(disp, time);
65 | final float[] rectArr2 = d2.getRectAtTime(disp, time);
66 | if (rectArr1 == null || rectArr2 == null)
67 | return false;
68 | return checkHit(d1.getType(), d2.getType(), rectArr1, rectArr2);
69 | }
70 |
71 | private static boolean checkHit(int type1, int type2, float[] rectArr1,
72 | float[] rectArr2) {
73 | if(type1 != type2)
74 | return false;
75 | if (type1 == BaseDanmaku.TYPE_SCROLL_RL) {
76 | // hit if left2 < right1
77 | return rectArr2[0] < rectArr1[2];
78 | }
79 |
80 | if (type1 == BaseDanmaku.TYPE_SCROLL_LR){
81 | // hit if right2 > left1
82 | return rectArr2[2] > rectArr1[0];
83 | }
84 |
85 | return false;
86 | }
87 |
88 | public static DrawingCache buildDanmakuDrawingCache(BaseDanmaku danmaku, IDisplayer disp,
89 | DrawingCache cache) {
90 | if (cache == null)
91 | cache = new DrawingCache();
92 |
93 | cache.build((int) Math.ceil(danmaku.paintWidth), (int) Math.ceil(danmaku.paintHeight), disp.getDensityDpi(), false);
94 | DrawingCacheHolder holder = cache.get();
95 | if (holder != null) {
96 | ((AbsDisplayer) disp).drawDanmaku(danmaku, holder.canvas, 0, 0, true);
97 | if(disp.isHardwareAccelerated()) {
98 | holder.splitWith(disp.getWidth(), disp.getHeight(), disp.getMaximumCacheWidth(),
99 | disp.getMaximumCacheHeight());
100 | }
101 | }
102 | return cache;
103 | }
104 |
105 | public static int getCacheSize(int w, int h) {
106 | return (w) * (h) * 4;
107 | }
108 |
109 | public final static boolean isDuplicate(BaseDanmaku obj1, BaseDanmaku obj2) {
110 | if(obj1 == obj2) {
111 | return false;
112 | }
113 | // if(obj1.isTimeOut() || obj2.isTimeOut()) {
114 | // return false;
115 | // }
116 | // long dtime = Math.abs(obj1.time - obj2.time);
117 | // if(dtime > obj1.getDuration()) {
118 | // return false;
119 | // }
120 | if (obj1.text == obj2.text) {
121 | return true;
122 | }
123 | if (obj1.text != null && obj1.text.equals(obj2.text)) {
124 | return true;
125 | }
126 | return false;
127 | }
128 |
129 | public final static int compare(BaseDanmaku obj1, BaseDanmaku obj2) {
130 |
131 | if (obj1 == obj2) {
132 | return 0;
133 | }
134 |
135 | if (obj1 == null) {
136 | return -1;
137 | }
138 |
139 | if (obj2 == null) {
140 | return 1;
141 | }
142 |
143 | long val = obj1.time - obj2.time;
144 | if (val > 0) {
145 | return 1;
146 | } else if (val < 0) {
147 | return -1;
148 | }
149 |
150 | int result = obj1.index - obj2.index;
151 | if (result > 0) {
152 | return 1;
153 | } else if (result < 0) {
154 | return -1;
155 | }
156 |
157 | result = obj1.getType() - obj2.getType();
158 | if (result > 0) {
159 | return 1;
160 | } else if (result < 0) {
161 | return -1;
162 | }
163 |
164 | if (obj1.text == null) {
165 | return -1;
166 | }
167 | if (obj2.text == null) {
168 | return 1;
169 | }
170 |
171 | int r = obj1.text.toString().compareTo(obj2.text.toString());
172 | if (r != 0) {
173 | return r;
174 | }
175 |
176 | r = obj1.textColor - obj2.textColor;
177 | if (r != 0)
178 | return r < 0 ? -1 : 1;
179 |
180 | r = obj1.index - obj2.index;
181 | if (r != 0)
182 | return r < 0 ? -1 : 1;
183 |
184 | r = obj1.hashCode() - obj1.hashCode();
185 | return r;
186 | }
187 |
188 | public final static boolean isOverSize(IDisplayer disp, BaseDanmaku item) {
189 | return disp.isHardwareAccelerated() && (item.paintWidth > disp.getMaximumCacheWidth() || item.paintHeight > disp.getMaximumCacheHeight());
190 | }
191 |
192 | public static void fillText(BaseDanmaku danmaku, CharSequence text) {
193 | danmaku.text = text;
194 | if (TextUtils.isEmpty(text) || !text.toString().contains(BaseDanmaku.DANMAKU_BR_CHAR)) {
195 | return;
196 | }
197 |
198 | String[] lines = String.valueOf(danmaku.text).split(BaseDanmaku.DANMAKU_BR_CHAR, -1);
199 | if (lines.length > 1) {
200 | danmaku.lines = lines;
201 | }
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/BaseDanmaku.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model;
18 |
19 | public abstract class BaseDanmaku {
20 |
21 | public final static String DANMAKU_BR_CHAR = "/n";
22 |
23 | public final static int TYPE_SCROLL_RL = 1;
24 |
25 | public final static int TYPE_SCROLL_LR = 6;
26 |
27 | public final static int TYPE_FIX_TOP = 5;
28 |
29 | public final static int TYPE_FIX_BOTTOM = 4;
30 |
31 | public final static int TYPE_SPECIAL = 7;
32 |
33 | public final static int TYPE_MOVEABLE_XXX = 0; // TODO: add more type
34 |
35 | public final static int INVISIBLE = 0;
36 |
37 | public final static int VISIBLE = 1;
38 |
39 | public final static int FLAG_REQUEST_REMEASURE = 0x1;
40 | public final static int FLAG_REQUEST_INVALIDATE = 0x2;
41 |
42 | /**
43 | * 显示时间(毫秒)
44 | */
45 | public long time;
46 |
47 | /**
48 | * 文本
49 | */
50 | public CharSequence text;
51 |
52 | /**
53 | * 多行文本: 如果有包含换行符需事先拆分到lines
54 | */
55 | public String[] lines;
56 |
57 | /**
58 | * 可保存一些数据的引用
59 | */
60 | public Object obj;
61 |
62 | /**
63 | * 文本颜色
64 | */
65 | public int textColor;
66 |
67 | /**
68 | * Z轴角度
69 | */
70 | public float rotationZ;
71 |
72 | /**
73 | * Y轴角度
74 | */
75 | public float rotationY;
76 |
77 | /**
78 | * 阴影/描边颜色
79 | */
80 | public int textShadowColor;
81 |
82 | /**
83 | * 下划线颜色,0表示无下划线
84 | */
85 | public int underlineColor = 0;
86 |
87 | /**
88 | * 字体大小
89 | */
90 | public float textSize = -1;
91 |
92 | /**
93 | * 框的颜色,0表示无框
94 | */
95 | public int borderColor = 0;
96 |
97 | /**
98 | * 内边距(像素)
99 | */
100 | public int padding = 0;
101 |
102 | /**
103 | * 弹幕优先级,0为低优先级,>0为高优先级不会被过滤器过滤
104 | */
105 | public byte priority = 0;
106 |
107 | /**
108 | * 占位宽度
109 | */
110 | public float paintWidth = -1;
111 |
112 | /**
113 | * 占位高度
114 | */
115 | public float paintHeight = -1;
116 |
117 | /**
118 | * 存活时间(毫秒)
119 | */
120 | public Duration duration;
121 |
122 | /**
123 | * 索引/编号
124 | */
125 | public int index;
126 |
127 | /**
128 | * 是否可见
129 | */
130 | public int visibility;
131 |
132 | /**
133 | * 重置位 visible
134 | */
135 | private int visibleResetFlag = 0;
136 |
137 | /**
138 | * 重置位 measure
139 | */
140 | private int measureResetFlag = 0;
141 |
142 | /**
143 | * 绘制用缓存
144 | */
145 | public IDrawingCache> cache;
146 |
147 | /**
148 | * 是否是直播弹幕
149 | */
150 | public boolean isLive;
151 |
152 | /**
153 | * 弹幕发布者id, 0表示游客
154 | */
155 | public int userId = 0;
156 |
157 | /**
158 | * 弹幕发布者id
159 | */
160 | public String userHash;
161 |
162 | /**
163 | * 是否游客
164 | */
165 | public boolean isGuest;
166 |
167 | /**
168 | * 计时
169 | */
170 | protected DanmakuTimer mTimer;
171 |
172 | /**
173 | * 透明度
174 | */
175 | protected int alpha = AlphaValue.MAX;
176 |
177 | public int mFilterParam = 0;
178 |
179 | public int filterResetFlag = -1;
180 |
181 | public GlobalFlagValues flags = null;
182 |
183 | public int requestFlags = 0;
184 |
185 | public long getDuration() {
186 | return duration.value;
187 | }
188 |
189 | public void setDuration(Duration duration) {
190 | this.duration = duration;
191 | }
192 |
193 | public int draw(IDisplayer displayer) {
194 | return displayer.draw(this);
195 | }
196 |
197 | public boolean isMeasured() {
198 | return paintWidth > -1 && paintHeight > -1
199 | && measureResetFlag == flags.MEASURE_RESET_FLAG;
200 | }
201 |
202 | public void measure(IDisplayer displayer, boolean fromWorkerThread) {
203 | displayer.measure(this, fromWorkerThread);
204 | this.measureResetFlag = flags.MEASURE_RESET_FLAG;
205 | }
206 |
207 | public boolean hasDrawingCache() {
208 | return cache != null && cache.get() != null;
209 | }
210 |
211 | public boolean isShown() {
212 | return this.visibility == VISIBLE
213 | && visibleResetFlag == flags.VISIBLE_RESET_FLAG;
214 | }
215 |
216 | public boolean isTimeOut() {
217 | return mTimer == null || isTimeOut(mTimer.currMillisecond);
218 | }
219 |
220 | public boolean isTimeOut(long ctime) {
221 | return ctime - time >= duration.value;
222 | }
223 |
224 | public boolean isOutside() {
225 | return mTimer == null || isOutside(mTimer.currMillisecond);
226 | }
227 |
228 | public boolean isOutside(long ctime) {
229 | long dtime = ctime - time;
230 | return dtime <= 0 || dtime >= duration.value;
231 | }
232 |
233 | public boolean isLate() {
234 | return mTimer == null || mTimer.currMillisecond < time;
235 | }
236 |
237 | public boolean hasPassedFilter() {
238 | if (filterResetFlag != flags.FILTER_RESET_FLAG) {
239 | mFilterParam = 0;
240 | return false;
241 | }
242 | return true;
243 | }
244 |
245 | public boolean isFiltered() {
246 | return filterResetFlag == flags.FILTER_RESET_FLAG && mFilterParam != 0;
247 | }
248 |
249 | public boolean isFilteredBy(int flag) {
250 | return filterResetFlag == flags.FILTER_RESET_FLAG && (mFilterParam & flag) == flag;
251 | }
252 |
253 | public void setVisibility(boolean b) {
254 | if (b) {
255 | this.visibleResetFlag = flags.VISIBLE_RESET_FLAG;
256 | this.visibility = VISIBLE;
257 | } else
258 | this.visibility = INVISIBLE;
259 | }
260 |
261 | public abstract void layout(IDisplayer displayer, float x, float y);
262 |
263 | public abstract float[] getRectAtTime(IDisplayer displayer, long currTime);
264 |
265 | public abstract float getLeft();
266 |
267 | public abstract float getTop();
268 |
269 | public abstract float getRight();
270 |
271 | public abstract float getBottom();
272 |
273 | /**
274 | * return the type of Danmaku
275 | *
276 | * @return TYPE_SCROLL_RL = 0 TYPE_SCROLL_RL = 1 TYPE_SCROLL_LR = 2
277 | * TYPE_FIX_TOP = 3; TYPE_FIX_BOTTOM = 4;
278 | */
279 | public abstract int getType();
280 |
281 | public DanmakuTimer getTimer() {
282 | return mTimer;
283 | }
284 |
285 | public void setTimer(DanmakuTimer timer) {
286 | mTimer = timer;
287 | }
288 |
289 | public int getAlpha() {
290 | return alpha;
291 | }
292 |
293 | }
294 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/model/SpecialDanmaku.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.model;
18 |
19 | public class SpecialDanmaku extends BaseDanmaku {
20 |
21 | private class Point {
22 | float x, y;
23 |
24 | public Point(float x, float y) {
25 | this.x = x;
26 | this.y = y;
27 | }
28 |
29 | public float getDistance(Point p) {
30 | float _x = Math.abs(this.x - p.x);
31 | float _y = Math.abs(this.y - p.y);
32 | return (float) Math.sqrt(_x * _x + _y * _y);
33 | }
34 | }
35 |
36 | public class LinePath {
37 | Point pBegin, pEnd;
38 | public long duration,beginTime,endTime;
39 | float delatX, deltaY;
40 |
41 | public void setPoints(Point pBegin, Point pEnd) {
42 | this.pBegin = pBegin;
43 | this.pEnd = pEnd;
44 | this.delatX = pEnd.x - pBegin.x;
45 | this.deltaY = pEnd.y - pBegin.y;
46 | }
47 |
48 | public float getDistance() {
49 | return pEnd.getDistance(pBegin);
50 | }
51 |
52 | public float[] getBeginPoint() {
53 | return new float[] {
54 | pBegin.x, pBegin.y
55 | };
56 | }
57 |
58 | public float[] getEndPoint() {
59 | return new float[] {
60 | pEnd.x, pEnd.y
61 | };
62 | }
63 |
64 | }
65 |
66 | public float beginX, beginY;
67 |
68 | public float endX, endY;
69 |
70 | public float deltaX, deltaY;
71 |
72 | public long translationDuration;
73 |
74 | public long translationStartDelay;
75 |
76 | public int beginAlpha;
77 |
78 | public int endAlpha;
79 |
80 | public int deltaAlpha;
81 |
82 | public long alphaDuration;
83 |
84 | public float rotateX, rotateZ;
85 |
86 | public float pivotX, pivotY;
87 |
88 | private float[] currStateValues = new float[4];
89 |
90 | public LinePath[] linePaths;
91 |
92 |
93 | @Override
94 | public void layout(IDisplayer displayer, float x, float y) {
95 | getRectAtTime(displayer, mTimer.currMillisecond);
96 | }
97 |
98 | @Override
99 | public float[] getRectAtTime(IDisplayer displayer, long currTime) {
100 |
101 | if (!isMeasured())
102 | return null;
103 |
104 | long deltaTime = currTime - time;
105 |
106 | // caculate alpha
107 | if (alphaDuration > 0 && deltaAlpha != 0) {
108 | if(deltaTime >= alphaDuration){
109 | alpha = endAlpha;
110 | }else{
111 | float alphaProgress = deltaTime / (float) alphaDuration;
112 | int vectorAlpha = (int) (deltaAlpha * alphaProgress);
113 | alpha = beginAlpha + vectorAlpha;
114 | }
115 | }
116 |
117 | // caculate x y
118 | float currX = beginX;
119 | float currY = beginY;
120 | long dtime = deltaTime - translationStartDelay;
121 | if (translationDuration > 0 && dtime >= 0 && dtime <= translationDuration) {
122 | float tranalationProgress = dtime / (float) translationDuration;
123 | if (linePaths != null) {
124 | LinePath currentLinePath = null;
125 | for (LinePath line : linePaths) {
126 | if (dtime >= line.beginTime && dtime < line.endTime) {
127 | currentLinePath = line;
128 | break;
129 | } else {
130 | currX = line.pEnd.x;
131 | currY = line.pEnd.y;
132 | }
133 | }
134 | if (currentLinePath != null) {
135 | float deltaX = currentLinePath.delatX;
136 | float deltaY = currentLinePath.deltaY;
137 | tranalationProgress = (deltaTime - currentLinePath.beginTime)
138 | / (float) currentLinePath.duration;
139 | float beginX = currentLinePath.pBegin.x;
140 | float beginY = currentLinePath.pBegin.y;
141 | if (deltaX != 0) {
142 | float vectorX = deltaX * tranalationProgress;
143 | currX = beginX + vectorX;
144 | }
145 | if (deltaY != 0) {
146 | float vectorY = deltaY * tranalationProgress;
147 | currY = beginY + vectorY;
148 | }
149 | }
150 | } else {
151 | if (deltaX != 0) {
152 | float vectorX = deltaX * tranalationProgress;
153 | currX = beginX + vectorX;
154 | }
155 | if (deltaY != 0) {
156 | float vectorY = deltaY * tranalationProgress;
157 | currY = beginY + vectorY;
158 | }
159 | }
160 | } else if(dtime > translationDuration){
161 | currX = endX;
162 | currY = endY;
163 | }
164 |
165 | currStateValues[0] = currX;
166 | currStateValues[1] = currY;
167 | currStateValues[2] = currX + paintWidth;
168 | currStateValues[3] = currY + paintHeight;
169 |
170 | this.setVisibility(!isOutside());
171 |
172 | return currStateValues;
173 | }
174 |
175 | @Override
176 | public float getLeft() {
177 | return currStateValues[0];
178 | }
179 |
180 | @Override
181 | public float getTop() {
182 | return currStateValues[1];
183 | }
184 |
185 | @Override
186 | public float getRight() {
187 | return currStateValues[2];
188 | }
189 |
190 | @Override
191 | public float getBottom() {
192 | return currStateValues[3];
193 | }
194 |
195 | @Override
196 | public int getType() {
197 | return TYPE_SPECIAL;
198 | }
199 |
200 | public void setTranslationData(float beginX, float beginY, float endX, float endY,
201 | long translationDuration, long translationStartDelay) {
202 | this.beginX = beginX;
203 | this.beginY = beginY;
204 | this.endX = endX;
205 | this.endY = endY;
206 | this.deltaX = endX - beginX;
207 | this.deltaY = endY - beginY;
208 | this.translationDuration = translationDuration;
209 | this.translationStartDelay = translationStartDelay;
210 | }
211 |
212 | public void setAlphaData(int beginAlpha, int endAlpha, long alphaDuration) {
213 | this.beginAlpha = beginAlpha;
214 | this.endAlpha = endAlpha;
215 | this.deltaAlpha = endAlpha - beginAlpha;
216 | this.alphaDuration = alphaDuration;
217 | if(deltaAlpha != 0 && beginAlpha != AlphaValue.MAX){
218 | alpha = beginAlpha;
219 | }
220 | }
221 |
222 | public void setLinePathData(float[][] points) {
223 | if (points != null) {
224 | int length = points.length;
225 | this.beginX = points[0][0];
226 | this.beginY = points[0][1];
227 | this.endX = points[length - 1][0];
228 | this.endY = points[length - 1][1];
229 | if (points.length > 1) {
230 | linePaths = new LinePath[points.length - 1];
231 | for (int i = 0; i < linePaths.length; i++) {
232 | linePaths[i] = new LinePath();
233 | linePaths[i].setPoints(new Point(points[i][0], points[i][1]), new Point(
234 | points[i + 1][0], points[i + 1][1]));
235 | }
236 | float totalDistance = 0;
237 | for (LinePath line : linePaths) {
238 | totalDistance += line.getDistance();
239 | }
240 | LinePath lastLine = null;
241 | for (LinePath line : linePaths) {
242 | line.duration = (long) ((line.getDistance() / totalDistance) * translationDuration);
243 | line.beginTime = (lastLine == null ? 0 : lastLine.endTime);
244 | line.endTime = line.beginTime + line.duration;
245 | lastLine = line;
246 | }
247 |
248 | }
249 | }
250 | }
251 |
252 | public void updateData(float scale) {
253 |
254 | }
255 |
256 | }
257 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction, and
10 | distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright
13 | owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all other entities
16 | that control, are controlled by, or are under common control with that entity.
17 | For the purposes of this definition, "control" means (i) the power, direct or
18 | indirect, to cause the direction or management of such entity, whether by
19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 | outstanding shares, or (iii) beneficial ownership of such entity.
21 |
22 | "You" (or "Your") shall mean an individual or Legal Entity exercising
23 | permissions granted by this License.
24 |
25 | "Source" form shall mean the preferred form for making modifications, including
26 | but not limited to software source code, documentation source, and configuration
27 | files.
28 |
29 | "Object" form shall mean any form resulting from mechanical transformation or
30 | translation of a Source form, including but not limited to compiled object code,
31 | generated documentation, and conversions to other media types.
32 |
33 | "Work" shall mean the work of authorship, whether in Source or Object form, made
34 | available under the License, as indicated by a copyright notice that is included
35 | in or attached to the work (an example is provided in the Appendix below).
36 |
37 | "Derivative Works" shall mean any work, whether in Source or Object form, that
38 | is based on (or derived from) the Work and for which the editorial revisions,
39 | annotations, elaborations, or other modifications represent, as a whole, an
40 | original work of authorship. For the purposes of this License, Derivative Works
41 | shall not include works that remain separable from, or merely link (or bind by
42 | name) to the interfaces of, the Work and Derivative Works thereof.
43 |
44 | "Contribution" shall mean any work of authorship, including the original version
45 | of the Work and any modifications or additions to that Work or Derivative Works
46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work
47 | by the copyright owner or by an individual or Legal Entity authorized to submit
48 | on behalf of the copyright owner. For the purposes of this definition,
49 | "submitted" means any form of electronic, verbal, or written communication sent
50 | to the Licensor or its representatives, including but not limited to
51 | communication on electronic mailing lists, source code control systems, and
52 | issue tracking systems that are managed by, or on behalf of, the Licensor for
53 | the purpose of discussing and improving the Work, but excluding communication
54 | that is conspicuously marked or otherwise designated in writing by the copyright
55 | owner as "Not a Contribution."
56 |
57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
58 | of whom a Contribution has been received by Licensor and subsequently
59 | incorporated within the Work.
60 |
61 | 2. Grant of Copyright License.
62 |
63 | Subject to the terms and conditions of this License, each Contributor hereby
64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
65 | irrevocable copyright license to reproduce, prepare Derivative Works of,
66 | publicly display, publicly perform, sublicense, and distribute the Work and such
67 | Derivative Works in Source or Object form.
68 |
69 | 3. Grant of Patent License.
70 |
71 | Subject to the terms and conditions of this License, each Contributor hereby
72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
73 | irrevocable (except as stated in this section) patent license to make, have
74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where
75 | such license applies only to those patent claims licensable by such Contributor
76 | that are necessarily infringed by their Contribution(s) alone or by combination
77 | of their Contribution(s) with the Work to which such Contribution(s) was
78 | submitted. If You institute patent litigation against any entity (including a
79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a
80 | Contribution incorporated within the Work constitutes direct or contributory
81 | patent infringement, then any patent licenses granted to You under this License
82 | for that Work shall terminate as of the date such litigation is filed.
83 |
84 | 4. Redistribution.
85 |
86 | You may reproduce and distribute copies of the Work or Derivative Works thereof
87 | in any medium, with or without modifications, and in Source or Object form,
88 | provided that You meet the following conditions:
89 |
90 | You must give any other recipients of the Work or Derivative Works a copy of
91 | this License; and
92 | You must cause any modified files to carry prominent notices stating that You
93 | changed the files; and
94 | You must retain, in the Source form of any Derivative Works that You distribute,
95 | all copyright, patent, trademark, and attribution notices from the Source form
96 | of the Work, excluding those notices that do not pertain to any part of the
97 | Derivative Works; and
98 | If the Work includes a "NOTICE" text file as part of its distribution, then any
99 | Derivative Works that You distribute must include a readable copy of the
100 | attribution notices contained within such NOTICE file, excluding those notices
101 | that do not pertain to any part of the Derivative Works, in at least one of the
102 | following places: within a NOTICE text file distributed as part of the
103 | Derivative Works; within the Source form or documentation, if provided along
104 | with the Derivative Works; or, within a display generated by the Derivative
105 | Works, if and wherever such third-party notices normally appear. The contents of
106 | the NOTICE file are for informational purposes only and do not modify the
107 | License. You may add Your own attribution notices within Derivative Works that
108 | You distribute, alongside or as an addendum to the NOTICE text from the Work,
109 | provided that such additional attribution notices cannot be construed as
110 | modifying the License.
111 | You may add Your own copyright statement to Your modifications and may provide
112 | additional or different license terms and conditions for use, reproduction, or
113 | distribution of Your modifications, or for any such Derivative Works as a whole,
114 | provided Your use, reproduction, and distribution of the Work otherwise complies
115 | with the conditions stated in this License.
116 |
117 | 5. Submission of Contributions.
118 |
119 | Unless You explicitly state otherwise, any Contribution intentionally submitted
120 | for inclusion in the Work by You to the Licensor shall be under the terms and
121 | conditions of this License, without any additional terms or conditions.
122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of
123 | any separate license agreement you may have executed with Licensor regarding
124 | such Contributions.
125 |
126 | 6. Trademarks.
127 |
128 | This License does not grant permission to use the trade names, trademarks,
129 | service marks, or product names of the Licensor, except as required for
130 | reasonable and customary use in describing the origin of the Work and
131 | reproducing the content of the NOTICE file.
132 |
133 | 7. Disclaimer of Warranty.
134 |
135 | Unless required by applicable law or agreed to in writing, Licensor provides the
136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
138 | including, without limitation, any warranties or conditions of TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
140 | solely responsible for determining the appropriateness of using or
141 | redistributing the Work and assume any risks associated with Your exercise of
142 | permissions under this License.
143 |
144 | 8. Limitation of Liability.
145 |
146 | In no event and under no legal theory, whether in tort (including negligence),
147 | contract, or otherwise, unless required by applicable law (such as deliberate
148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be
149 | liable to You for damages, including any direct, indirect, special, incidental,
150 | or consequential damages of any character arising as a result of this License or
151 | out of the use or inability to use the Work (including but not limited to
152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or
153 | any and all other commercial damages or losses), even if such Contributor has
154 | been advised of the possibility of such damages.
155 |
156 | 9. Accepting Warranty or Additional Liability.
157 |
158 | While redistributing the Work or Derivative Works thereof, You may choose to
159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or
160 | other liability obligations and/or rights consistent with this License. However,
161 | in accepting such obligations, You may act only on Your own behalf and on Your
162 | sole responsibility, not on behalf of any other Contributor, and only if You
163 | agree to indemnify, defend, and hold each Contributor harmless for any liability
164 | incurred by, or claims asserted against, such Contributor by reason of your
165 | accepting any such warranty or additional liability.
166 |
167 | END OF TERMS AND CONDITIONS
168 |
169 | APPENDIX: How to apply the Apache License to your work
170 |
171 | To apply the Apache License to your work, attach the following boilerplate
172 | notice, with the fields enclosed by brackets "[]" replaced with your own
173 | identifying information. (Don't include the brackets!) The text should be
174 | enclosed in the appropriate comment syntax for the file format. We also
175 | recommend that a file or class name and description of purpose be included on
176 | the same "printed page" as the copyright notice for easier identification within
177 | third-party archives.
178 |
179 | Copyright [yyyy] [name of copyright owner]
180 |
181 | Licensed under the Apache License, Version 2.0 (the "License");
182 | you may not use this file except in compliance with the License.
183 | You may obtain a copy of the License at
184 |
185 | http://www.apache.org/licenses/LICENSE-2.0
186 |
187 | Unless required by applicable law or agreed to in writing, software
188 | distributed under the License is distributed on an "AS IS" BASIS,
189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190 | See the License for the specific language governing permissions and
191 | limitations under the License.
192 |
--------------------------------------------------------------------------------
/DanmakuFlameMaster/src/main/java/master/flame/danmaku/danmaku/parser/android/BiliDanmukuParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Chen Hui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package master.flame.danmaku.danmaku.parser.android;
18 |
19 | import android.graphics.Color;
20 | import android.text.TextUtils;
21 |
22 | import org.json.JSONArray;
23 | import org.json.JSONException;
24 | import org.xml.sax.Attributes;
25 | import org.xml.sax.InputSource;
26 | import org.xml.sax.SAXException;
27 | import org.xml.sax.XMLReader;
28 | import org.xml.sax.helpers.DefaultHandler;
29 | import org.xml.sax.helpers.XMLReaderFactory;
30 |
31 | import java.io.IOException;
32 | import java.util.Locale;
33 |
34 | import master.flame.danmaku.danmaku.model.AlphaValue;
35 | import master.flame.danmaku.danmaku.model.BaseDanmaku;
36 | import master.flame.danmaku.danmaku.model.Duration;
37 | import master.flame.danmaku.danmaku.model.IDisplayer;
38 | import master.flame.danmaku.danmaku.model.android.Danmakus;
39 | import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
40 | import master.flame.danmaku.danmaku.parser.DanmakuFactory;
41 | import master.flame.danmaku.danmaku.util.DanmakuUtils;
42 |
43 | public class BiliDanmukuParser extends BaseDanmakuParser {
44 |
45 | static {
46 | System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");
47 | }
48 |
49 | private float mDispScaleX;
50 | private float mDispScaleY;
51 |
52 | @Override
53 | public Danmakus parse() {
54 |
55 | if (mDataSource != null) {
56 | AndroidFileSource source = (AndroidFileSource) mDataSource;
57 | try {
58 | XMLReader xmlReader = XMLReaderFactory.createXMLReader();
59 | XmlContentHandler contentHandler = new XmlContentHandler();
60 | xmlReader.setContentHandler(contentHandler);
61 | xmlReader.parse(new InputSource(source.data()));
62 | return contentHandler.getResult();
63 | } catch (SAXException e) {
64 | e.printStackTrace();
65 | } catch (IOException e) {
66 | e.printStackTrace();
67 | }
68 |
69 | }
70 |
71 | return null;
72 | }
73 |
74 | public class XmlContentHandler extends DefaultHandler {
75 |
76 | private static final String TRUE_STRING = "true";
77 |
78 | public Danmakus result = null;
79 |
80 | public BaseDanmaku item = null;
81 |
82 | public boolean completed = false;
83 |
84 | public int index = 0;
85 |
86 | public Danmakus getResult() {
87 | return result;
88 | }
89 |
90 | @Override
91 | public void startDocument() throws SAXException {
92 | result = new Danmakus();
93 | }
94 |
95 | @Override
96 | public void endDocument() throws SAXException {
97 | completed = true;
98 | }
99 |
100 | @Override
101 | public void startElement(String uri, String localName, String qName, Attributes attributes)
102 | throws SAXException {
103 | String tagName = localName.length() != 0 ? localName : qName;
104 | tagName = tagName.toLowerCase(Locale.getDefault()).trim();
105 | if (tagName.equals("d")) {
106 | // 我从未见过如此厚颜无耻之猴
107 | // 0:时间(弹幕出现时间)
108 | // 1:类型(1从左至右滚动弹幕|6从右至左滚动弹幕|5顶端固定弹幕|4底端固定弹幕|7高级弹幕|8脚本弹幕)
109 | // 2:字号
110 | // 3:颜色
111 | // 4:时间戳 ?
112 | // 5:弹幕池id
113 | // 6:用户hash
114 | // 7:弹幕id
115 | String pValue = attributes.getValue("p");
116 | // parse p value to danmaku
117 | String[] values = pValue.split(",");
118 | if (values.length > 0) {
119 | long time = (long) (Float.parseFloat(values[0]) * 1000); // 出现时间
120 | int type = Integer.parseInt(values[1]); // 弹幕类型
121 | float textSize = Float.parseFloat(values[2]); // 字体大小
122 | int color = Integer.parseInt(values[3]) | 0xFF000000; // 颜色
123 | // int poolType = Integer.parseInt(values[5]); // 弹幕池类型(忽略
124 | item = mContext.mDanmakuFactory.createDanmaku(type, mContext);
125 | if (item != null) {
126 | item.time = time;
127 | item.textSize = textSize * (mDispDensity - 0.6f);
128 | item.textColor = color;
129 | item.textShadowColor = color <= Color.BLACK ? Color.WHITE : Color.BLACK;
130 | }
131 | }
132 | }
133 | }
134 |
135 | @Override
136 | public void endElement(String uri, String localName, String qName) throws SAXException {
137 | if (item != null) {
138 | if (item.duration != null) {
139 | String tagName = localName.length() != 0 ? localName : qName;
140 | if (tagName.equalsIgnoreCase("d")) {
141 | item.setTimer(mTimer);
142 | result.addItem(item);
143 | }
144 | }
145 | item = null;
146 | }
147 | }
148 |
149 | @Override
150 | public void characters(char[] ch, int start, int length) {
151 | if (item != null) {
152 | DanmakuUtils.fillText(item, decodeXmlString(new String(ch, start, length)));
153 | item.index = index++;
154 |
155 | // initial specail danmaku data
156 | String text = String.valueOf(item.text).trim();
157 | if (item.getType() == BaseDanmaku.TYPE_SPECIAL && text.startsWith("[")
158 | && text.endsWith("]")) {
159 | //text = text.substring(1, text.length() - 1);
160 | String[] textArr = null;//text.split(",", -1);
161 | try {
162 | JSONArray jsonArray = new JSONArray(text);
163 | textArr = new String[jsonArray.length()];
164 | for(int i=0;i 1) {
184 | endAlpha = (int) (AlphaValue.MAX * Float.parseFloat(alphaArr[1]));
185 | }
186 | long alphaDuraion = (long) (Float.parseFloat(textArr[3]) * 1000);
187 | long translationDuration = alphaDuraion;
188 | long translationStartDelay = 0;
189 | float rotateY = 0, rotateZ = 0;
190 | if (textArr.length >= 7) {
191 | rotateZ = Float.parseFloat(textArr[5]);
192 | rotateY = Float.parseFloat(textArr[6]);
193 | }
194 | if (textArr.length >= 11) {
195 | endX = Float.parseFloat(textArr[7]);
196 | endY = Float.parseFloat(textArr[8]);
197 | if(!"".equals(textArr[9])){
198 | translationDuration = Integer.parseInt(textArr[9]);
199 | }
200 | if(!"".equals(textArr[10])){
201 | translationStartDelay = (long) (Float.parseFloat(textArr[10]));
202 | }
203 | }
204 | item.duration = new Duration(alphaDuraion);
205 | item.rotationZ = rotateZ;
206 | item.rotationY = rotateY;
207 | mContext.mDanmakuFactory.fillTranslationData(item, beginX,
208 | beginY, endX, endY, translationDuration, translationStartDelay, mDispScaleX, mDispScaleY);
209 | mContext.mDanmakuFactory.fillAlphaData(item, beginAlpha, endAlpha, alphaDuraion);
210 |
211 | if (textArr.length >= 12) {
212 | // 是否有描边
213 | if (!TextUtils.isEmpty(textArr[11]) && TRUE_STRING.equals(textArr[11])) {
214 | item.textShadowColor = Color.TRANSPARENT;
215 | }
216 | }
217 | if (textArr.length >= 13) {
218 | //TODO 字体 textArr[12]
219 | }
220 | if (textArr.length >= 14) {
221 | //TODO 是否有加速
222 | }
223 | if (textArr.length >= 15) {
224 | // 路径数据
225 | if (!"".equals(textArr[14])) {
226 | String motionPathString = textArr[14].substring(1);
227 | String[] pointStrArray = motionPathString.split("L");
228 | if (pointStrArray != null && pointStrArray.length > 0) {
229 | float[][] points = new float[pointStrArray.length][2];
230 | for (int i = 0; i < pointStrArray.length; i++) {
231 | String[] pointArray = pointStrArray[i].split(",");
232 | points[i][0] = Float.parseFloat(pointArray[0]);
233 | points[i][1] = Float.parseFloat(pointArray[1]);
234 | }
235 | DanmakuFactory.fillLinePathData(item, points, mDispScaleX,
236 | mDispScaleY);
237 | }
238 | }
239 | }
240 | }
241 |
242 | }
243 | }
244 |
245 | private String decodeXmlString(String title) {
246 | if (title.contains("&")) {
247 | title = title.replace("&", "&");
248 | }
249 | if (title.contains(""")) {
250 | title = title.replace(""", "\"");
251 | }
252 | if (title.contains(">")) {
253 | title = title.replace(">", ">");
254 | }
255 | if (title.contains("<")) {
256 | title = title.replace("<", "<");
257 | }
258 | return title;
259 | }
260 |
261 | }
262 |
263 | @Override
264 | public BaseDanmakuParser setDisplayer(IDisplayer disp) {
265 | super.setDisplayer(disp);
266 | mDispScaleX = mDispWidth / DanmakuFactory.BILI_PLAYER_WIDTH;
267 | mDispScaleY = mDispHeight / DanmakuFactory.BILI_PLAYER_HEIGHT;
268 | return this;
269 | }
270 | }
271 |
--------------------------------------------------------------------------------