├── .gitignore ├── .gitmodules ├── .travis.yml ├── DanmakuFlameMaster ├── build.gradle ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── tv │ │ └── cjump │ │ └── jni │ │ └── NativeBitmapFactoryTest.java │ └── main │ ├── .classpath │ ├── .project │ ├── .settings │ ├── org.eclipse.jdt.core.prefs │ └── org.eclipse.jdt.ui.prefs │ ├── AndroidManifest.xml │ ├── build.xml │ ├── java │ ├── master │ │ └── flame │ │ │ └── danmaku │ │ │ ├── controller │ │ │ ├── CacheManagingDrawTask.java │ │ │ ├── DanmakuFilters.java │ │ │ ├── DrawHandler.java │ │ │ ├── DrawHelper.java │ │ │ ├── DrawTask.java │ │ │ ├── IDanmakuView.java │ │ │ ├── IDanmakuViewController.java │ │ │ ├── IDrawTask.java │ │ │ └── UpdateThread.java │ │ │ ├── danmaku │ │ │ ├── loader │ │ │ │ ├── ILoader.java │ │ │ │ ├── IllegalDataException.java │ │ │ │ └── android │ │ │ │ │ ├── AcFunDanmakuLoader.java │ │ │ │ │ ├── BiliDanmakuLoader.java │ │ │ │ │ └── DanmakuLoaderFactory.java │ │ │ ├── model │ │ │ │ ├── AbsDisplayer.java │ │ │ │ ├── AlphaValue.java │ │ │ │ ├── BaseDanmaku.java │ │ │ │ ├── Danmaku.java │ │ │ │ ├── DanmakuTimer.java │ │ │ │ ├── Duration.java │ │ │ │ ├── FBDanmaku.java │ │ │ │ ├── FTDanmaku.java │ │ │ │ ├── GlobalFlagValues.java │ │ │ │ ├── ICacheManager.java │ │ │ │ ├── IDanmakuIterator.java │ │ │ │ ├── IDanmakus.java │ │ │ │ ├── IDisplayer.java │ │ │ │ ├── IDrawingCache.java │ │ │ │ ├── L2RDanmaku.java │ │ │ │ ├── R2LDanmaku.java │ │ │ │ ├── SpecialDanmaku.java │ │ │ │ ├── android │ │ │ │ │ ├── AndroidDisplayer.java │ │ │ │ │ ├── BaseCacheStuffer.java │ │ │ │ │ ├── DanmakuContext.java │ │ │ │ │ ├── Danmakus.java │ │ │ │ │ ├── DrawingCache.java │ │ │ │ │ ├── DrawingCacheHolder.java │ │ │ │ │ ├── DrawingCachePoolManager.java │ │ │ │ │ ├── SimpleTextCacheStuffer.java │ │ │ │ │ └── SpannedCacheStuffer.java │ │ │ │ └── objectpool │ │ │ │ │ ├── FinitePool.java │ │ │ │ │ ├── Pool.java │ │ │ │ │ ├── Poolable.java │ │ │ │ │ ├── PoolableManager.java │ │ │ │ │ ├── Pools.java │ │ │ │ │ └── SynchronizedPool.java │ │ │ ├── parser │ │ │ │ ├── BaseDanmakuParser.java │ │ │ │ ├── DanmakuFactory.java │ │ │ │ ├── IDataSource.java │ │ │ │ └── android │ │ │ │ │ ├── AcFunDanmakuParser.java │ │ │ │ │ ├── AndroidFileSource.java │ │ │ │ │ ├── BiliDanmukuParser.java │ │ │ │ │ └── JSONSource.java │ │ │ ├── renderer │ │ │ │ ├── IRenderer.java │ │ │ │ ├── Renderer.java │ │ │ │ └── android │ │ │ │ │ ├── DanmakuRenderer.java │ │ │ │ │ └── DanmakusRetainer.java │ │ │ └── util │ │ │ │ ├── AndroidUtils.java │ │ │ │ ├── DanmakuUtils.java │ │ │ │ └── IOUtils.java │ │ │ └── ui │ │ │ └── widget │ │ │ ├── DanmakuSurfaceView.java │ │ │ ├── DanmakuTextureView.java │ │ │ ├── DanmakuTouchHelper.java │ │ │ └── DanmakuView.java │ └── tv │ │ └── cjump │ │ └── jni │ │ ├── DeviceUtils.java │ │ └── NativeBitmapFactory.java │ ├── libs │ ├── armeabi-v7a │ │ └── libndkbitmap.so │ ├── armeabi │ │ └── libndkbitmap.so │ ├── mips │ │ └── libndkbitmap.so │ └── x86 │ │ └── libndkbitmap.so │ ├── lint.xml │ ├── proguard-project.txt │ └── project.properties ├── LICENSE ├── README.md ├── Sample ├── build.gradle └── src │ └── main │ ├── .classpath │ ├── .project │ ├── .settings │ └── org.eclipse.jdt.core.prefs │ ├── AndroidManifest.xml │ ├── assets │ └── comment.json │ ├── ic_launcher-web.png │ ├── java │ └── com │ │ └── sample │ │ └── MainActivity.java │ ├── project.properties │ └── res │ ├── drawable-hdpi │ └── ic_launcher.png │ ├── drawable-mdpi │ └── ic_launcher.png │ ├── drawable-xhdpi │ └── ic_launcher.png │ ├── drawable-xxhdpi │ └── ic_launcher.png │ ├── layout │ ├── activity_main.xml │ └── media_controller.xml │ ├── menu │ └── main.xml │ ├── raw │ └── comments.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle ├── gradle-bintray-upload.gradle ├── gradle-mvn-push.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.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/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=DanmakuFlameMaster 2 | BINTRAY_POM_NAME=dfm 3 | POM_ARTIFACT_ID=dfm 4 | POM_PACKAGING=aar -------------------------------------------------------------------------------- /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/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /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/.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/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 22 | 23 | 26 | 27 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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/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 | } -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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/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/libs/armeabi-v7a/libndkbitmap.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/7f44bcb6ed50bfb577ca5c51ec91638056808be5/DanmakuFlameMaster/src/main/libs/armeabi-v7a/libndkbitmap.so -------------------------------------------------------------------------------- /DanmakuFlameMaster/src/main/libs/armeabi/libndkbitmap.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/7f44bcb6ed50bfb577ca5c51ec91638056808be5/DanmakuFlameMaster/src/main/libs/armeabi/libndkbitmap.so -------------------------------------------------------------------------------- /DanmakuFlameMaster/src/main/libs/mips/libndkbitmap.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/7f44bcb6ed50bfb577ca5c51ec91638056808be5/DanmakuFlameMaster/src/main/libs/mips/libndkbitmap.so -------------------------------------------------------------------------------- /DanmakuFlameMaster/src/main/libs/x86/libndkbitmap.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/7f44bcb6ed50bfb577ca5c51ec91638056808be5/DanmakuFlameMaster/src/main/libs/x86/libndkbitmap.so -------------------------------------------------------------------------------- /DanmakuFlameMaster/src/main/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DanmakuFlameMaster 2 | ================== 3 | 4 | android上开源弹幕解析绘制引擎项目。[![Build Status](https://travis-ci.org/Bilibili/DanmakuFlameMaster.png?branch=master)](https://travis-ci.org/Bilibili/DanmakuFlameMaster) 5 | 6 | ### DFM Inside: 7 | [![bili](https://raw.github.com/ctiao/ctiao.github.io/master/images/apps/bili.png?raw=true)](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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Sample/src/main/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Sample/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/7f44bcb6ed50bfb577ca5c51ec91638056808be5/Sample/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Sample/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/7f44bcb6ed50bfb577ca5c51ec91638056808be5/Sample/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Sample/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/7f44bcb6ed50bfb577ca5c51ec91638056808be5/Sample/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Sample/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/7f44bcb6ed50bfb577ca5c51ec91638056808be5/Sample/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Sample/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctiao/DanmakuFlameMaster/7f44bcb6ed50bfb577ca5c51ec91638056808be5/Sample/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 26 | 27 | 28 | 29 | 33 | 34 | 35 | 36 | 40 | 41 | 45 | 46 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/media_controller.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 13 | 19 | 20 |