Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
ac13
GSYVideoPlayer
提交
62943836
G
GSYVideoPlayer
项目概览
ac13
/
GSYVideoPlayer
与 Fork 源项目一致
从无法访问的项目Fork
通知
7
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
GSYVideoPlayer
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
62943836
编写于
2月 17, 2017
作者:
S
shuyu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
* update ijk to 0.7.7.1
* 增加弹幕控件,未完成
上级
d293c5a5
变更
21
展开全部
隐藏空白更改
内联
并排
Showing
21 changed file
with
2322 addition
and
4 deletion
+2322
-4
app/build.gradle
app/build.gradle
+11
-0
app/src/main/java/com/example/gsyvideoplayer/DetailPlayer.java
...rc/main/java/com/example/gsyvideoplayer/DetailPlayer.java
+3
-2
app/src/main/java/com/example/gsyvideoplayer/adapter/DanamakuAdapter.java
...a/com/example/gsyvideoplayer/adapter/DanamakuAdapter.java
+96
-0
app/src/main/java/com/example/gsyvideoplayer/utils/BiliDanmukuParser.java
...a/com/example/gsyvideoplayer/utils/BiliDanmukuParser.java
+291
-0
app/src/main/java/com/example/gsyvideoplayer/video/DanmakuVideoPlayer.java
.../com/example/gsyvideoplayer/video/DanmakuVideoPlayer.java
+240
-0
app/src/main/res/layout/activity_detail_player.xml
app/src/main/res/layout/activity_detail_player.xml
+1
-1
app/src/main/res/layout/danmaku_layout.xml
app/src/main/res/layout/danmaku_layout.xml
+169
-0
app/src/main/res/raw/comments.xml
app/src/main/res/raw/comments.xml
+1501
-0
dependencies.gradle
dependencies.gradle
+6
-1
gsyVideoPlayer/libs/arm64-v8a/libijkplayer.so
gsyVideoPlayer/libs/arm64-v8a/libijkplayer.so
+0
-0
gsyVideoPlayer/libs/arm64-v8a/libijksdl.so
gsyVideoPlayer/libs/arm64-v8a/libijksdl.so
+0
-0
gsyVideoPlayer/libs/armeabi-v7a/libijkplayer.so
gsyVideoPlayer/libs/armeabi-v7a/libijkplayer.so
+0
-0
gsyVideoPlayer/libs/armeabi-v7a/libijksdl.so
gsyVideoPlayer/libs/armeabi-v7a/libijksdl.so
+0
-0
gsyVideoPlayer/libs/armeabi/libijkplayer.so
gsyVideoPlayer/libs/armeabi/libijkplayer.so
+0
-0
gsyVideoPlayer/libs/armeabi/libijksdl.so
gsyVideoPlayer/libs/armeabi/libijksdl.so
+0
-0
gsyVideoPlayer/libs/x86/libijkffmpeg.so
gsyVideoPlayer/libs/x86/libijkffmpeg.so
+0
-0
gsyVideoPlayer/libs/x86/libijkplayer.so
gsyVideoPlayer/libs/x86/libijkplayer.so
+0
-0
gsyVideoPlayer/libs/x86/libijksdl.so
gsyVideoPlayer/libs/x86/libijksdl.so
+0
-0
gsyVideoPlayer/libs/x86_64/libijkplayer.so
gsyVideoPlayer/libs/x86_64/libijkplayer.so
+0
-0
gsyVideoPlayer/libs/x86_64/libijksdl.so
gsyVideoPlayer/libs/x86_64/libijksdl.so
+0
-0
gsyVideoPlayer/src/main/java/com/shuyu/gsyvideoplayer/video/StandardGSYVideoPlayer.java
...om/shuyu/gsyvideoplayer/video/StandardGSYVideoPlayer.java
+4
-0
未找到文件。
app/build.gradle
浏览文件 @
62943836
...
...
@@ -36,6 +36,12 @@ android {
proguardFiles
getDefaultProguardFile
(
'proguard-android.txt'
),
'proguard-rules.pro'
}
}
sourceSets
{
main
{
jniLibs
.
srcDirs
=
[
'libs'
]
}
}
}
dependencies
{
...
...
@@ -46,6 +52,11 @@ dependencies {
apt
viewDependencies
.
apt_butterKnife
compile
viewDependencies
.
butterKnife
compile
androidDependencies
.
recyclerView
compile
viewDependencies
.
DanmakuFlameMaster
compile
viewDependencies
.
ndkbitmap_armv7a
compile
viewDependencies
.
ndkbitmap_armv5
compile
viewDependencies
.
ndkbitmap_x86
//debugCompile dataDependencies.leakcanary
compile
project
(
':gsyVideoPlayer'
)
}
app/src/main/java/com/example/gsyvideoplayer/DetailPlayer.java
浏览文件 @
62943836
...
...
@@ -10,6 +10,7 @@ import android.widget.ImageView;
import
android.widget.RelativeLayout
;
import
com.example.gsyvideoplayer.listener.SampleListener
;
import
com.example.gsyvideoplayer.video.DanmakuVideoPlayer
;
import
com.example.gsyvideoplayer.video.LandLayoutVideo
;
import
com.shuyu.gsyvideoplayer.GSYPreViewManager
;
import
com.shuyu.gsyvideoplayer.GSYVideoPlayer
;
...
...
@@ -32,7 +33,7 @@ public class DetailPlayer extends AppCompatActivity {
//推荐使用StandardGSYVideoPlayer,功能一致
//CustomGSYVideoPlayer部分功能处于试验阶段
@BindView
(
R
.
id
.
detail_player
)
LandLayoutVideo
detailPlayer
;
DanmakuVideoPlayer
detailPlayer
;
@BindView
(
R
.
id
.
activity_detail_player
)
RelativeLayout
activityDetailPlayer
;
...
...
@@ -71,7 +72,7 @@ public class DetailPlayer extends AppCompatActivity {
detailPlayer
.
setLockLand
(
false
);
detailPlayer
.
setShowFullAnimation
(
false
);
detailPlayer
.
setNeedLockFull
(
true
);
detailPlayer
.
setOpenPreView
(
true
);
//
detailPlayer.setOpenPreView(true);
detailPlayer
.
getFullscreenButton
().
setOnClickListener
(
new
View
.
OnClickListener
()
{
@Override
public
void
onClick
(
View
v
)
{
...
...
app/src/main/java/com/example/gsyvideoplayer/adapter/DanamakuAdapter.java
0 → 100644
浏览文件 @
62943836
package
com.example.gsyvideoplayer.adapter
;
import
android.graphics.Color
;
import
android.graphics.drawable.BitmapDrawable
;
import
android.graphics.drawable.Drawable
;
import
android.text.Spannable
;
import
android.text.SpannableStringBuilder
;
import
android.text.Spanned
;
import
android.text.style.BackgroundColorSpan
;
import
android.text.style.ImageSpan
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.net.MalformedURLException
;
import
java.net.URL
;
import
java.net.URLConnection
;
import
master.flame.danmaku.controller.IDanmakuView
;
import
master.flame.danmaku.danmaku.model.BaseDanmaku
;
import
master.flame.danmaku.danmaku.model.android.BaseCacheStuffer
;
import
master.flame.danmaku.danmaku.util.IOUtils
;
/**
* Created by guoshuyu on 2017/2/16.
*/
public
class
DanamakuAdapter
extends
BaseCacheStuffer
.
Proxy
{
private
Drawable
mDrawable
;
private
IDanmakuView
mDanmakuView
;
public
DanamakuAdapter
(
IDanmakuView
mDanmakuView
)
{
super
();
this
.
mDanmakuView
=
mDanmakuView
;
}
@Override
public
void
prepareDrawing
(
final
BaseDanmaku
danmaku
,
boolean
fromWorkerThread
)
{
if
(
danmaku
.
text
instanceof
Spanned
)
{
// 根据你的条件检查是否需要需要更新弹幕
// FIXME 这里只是简单启个线程来加载远程url图片,请使用你自己的异步线程池,最好加上你的缓存池
new
Thread
()
{
@Override
public
void
run
()
{
String
url
=
"http://www.bilibili.com/favicon.ico"
;
InputStream
inputStream
=
null
;
Drawable
drawable
=
mDrawable
;
if
(
drawable
==
null
)
{
try
{
URLConnection
urlConnection
=
new
URL
(
url
).
openConnection
();
inputStream
=
urlConnection
.
getInputStream
();
drawable
=
BitmapDrawable
.
createFromStream
(
inputStream
,
"bitmap"
);
mDrawable
=
drawable
;
}
catch
(
MalformedURLException
e
)
{
e
.
printStackTrace
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
finally
{
IOUtils
.
closeQuietly
(
inputStream
);
}
}
if
(
drawable
!=
null
)
{
drawable
.
setBounds
(
0
,
0
,
100
,
100
);
SpannableStringBuilder
spannable
=
createSpannable
(
drawable
);
danmaku
.
text
=
spannable
;
if
(
mDanmakuView
!=
null
)
{
mDanmakuView
.
invalidateDanmaku
(
danmaku
,
false
);
}
return
;
}
}
}.
start
();
}
}
@Override
public
void
releaseResource
(
BaseDanmaku
danmaku
)
{
// TODO 重要:清理含有ImageSpan的text中的一些占用内存的资源 例如drawable
}
private
SpannableStringBuilder
createSpannable
(
Drawable
drawable
)
{
String
text
=
"bitmap"
;
SpannableStringBuilder
spannableStringBuilder
=
new
SpannableStringBuilder
(
text
);
ImageSpan
span
=
new
ImageSpan
(
drawable
);
//ImageSpan.ALIGN_BOTTOM);
spannableStringBuilder
.
setSpan
(
span
,
0
,
text
.
length
(),
Spannable
.
SPAN_INCLUSIVE_EXCLUSIVE
);
spannableStringBuilder
.
append
(
"图文混排"
);
spannableStringBuilder
.
setSpan
(
new
BackgroundColorSpan
(
Color
.
parseColor
(
"#8A2233B1"
)),
0
,
spannableStringBuilder
.
length
(),
Spannable
.
SPAN_INCLUSIVE_INCLUSIVE
);
return
spannableStringBuilder
;
}
}
app/src/main/java/com/example/gsyvideoplayer/utils/BiliDanmukuParser.java
0 → 100644
浏览文件 @
62943836
/*
* Copyright (C) 2013 Chen Hui <calmer91@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.example.gsyvideoplayer.utils
;
import
android.graphics.Color
;
import
android.text.TextUtils
;
import
org.json.JSONArray
;
import
org.json.JSONException
;
import
org.xml.sax.Attributes
;
import
org.xml.sax.InputSource
;
import
org.xml.sax.SAXException
;
import
org.xml.sax.XMLReader
;
import
org.xml.sax.helpers.DefaultHandler
;
import
org.xml.sax.helpers.XMLReaderFactory
;
import
java.io.IOException
;
import
java.util.Locale
;
import
master.flame.danmaku.danmaku.model.AlphaValue
;
import
master.flame.danmaku.danmaku.model.BaseDanmaku
;
import
master.flame.danmaku.danmaku.model.Duration
;
import
master.flame.danmaku.danmaku.model.IDisplayer
;
import
master.flame.danmaku.danmaku.model.android.DanmakuFactory
;
import
master.flame.danmaku.danmaku.model.android.Danmakus
;
import
master.flame.danmaku.danmaku.parser.BaseDanmakuParser
;
import
master.flame.danmaku.danmaku.parser.android.AndroidFileSource
;
import
master.flame.danmaku.danmaku.util.DanmakuUtils
;
public
class
BiliDanmukuParser
extends
BaseDanmakuParser
{
static
{
System
.
setProperty
(
"org.xml.sax.driver"
,
"org.xmlpull.v1.sax2.Driver"
);
}
protected
float
mDispScaleX
;
protected
float
mDispScaleY
;
@Override
public
Danmakus
parse
()
{
if
(
mDataSource
!=
null
)
{
AndroidFileSource
source
=
(
AndroidFileSource
)
mDataSource
;
try
{
XMLReader
xmlReader
=
XMLReaderFactory
.
createXMLReader
();
XmlContentHandler
contentHandler
=
new
XmlContentHandler
();
xmlReader
.
setContentHandler
(
contentHandler
);
xmlReader
.
parse
(
new
InputSource
(
source
.
data
()));
return
contentHandler
.
getResult
();
}
catch
(
SAXException
e
)
{
e
.
printStackTrace
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
return
null
;
}
public
class
XmlContentHandler
extends
DefaultHandler
{
private
static
final
String
TRUE_STRING
=
"true"
;
public
Danmakus
result
=
new
Danmakus
();
public
BaseDanmaku
item
=
null
;
public
boolean
completed
=
false
;
public
int
index
=
0
;
public
Danmakus
getResult
()
{
return
result
;
}
@Override
public
void
startDocument
()
throws
SAXException
{
}
@Override
public
void
endDocument
()
throws
SAXException
{
completed
=
true
;
}
@Override
public
void
startElement
(
String
uri
,
String
localName
,
String
qName
,
Attributes
attributes
)
throws
SAXException
{
String
tagName
=
localName
.
length
()
!=
0
?
localName
:
qName
;
tagName
=
tagName
.
toLowerCase
(
Locale
.
getDefault
()).
trim
();
if
(
tagName
.
equals
(
"d"
))
{
// <d p="23.826000213623,1,25,16777215,1422201084,0,057075e9,757076900">我从未见过如此厚颜无耻之猴</d>
// 0:时间(弹幕出现时间)
// 1:类型(1从右至左滚动弹幕|6从左至右滚动弹幕|5顶端固定弹幕|4底端固定弹幕|7高级弹幕|8脚本弹幕)
// 2:字号
// 3:颜色
// 4:时间戳 ?
// 5:弹幕池id
// 6:用户hash
// 7:弹幕id
String
pValue
=
attributes
.
getValue
(
"p"
);
// parse p value to danmaku
String
[]
values
=
pValue
.
split
(
","
);
if
(
values
.
length
>
0
)
{
long
time
=
(
long
)
(
Float
.
parseFloat
(
values
[
0
])
*
1000
);
// 出现时间
int
type
=
Integer
.
parseInt
(
values
[
1
]);
// 弹幕类型
float
textSize
=
Float
.
parseFloat
(
values
[
2
]);
// 字体大小
int
color
=
(
int
)
((
0x00000000ff000000
|
Long
.
parseLong
(
values
[
3
]))
&
0x00000000ffffffff
);
// 颜色
// int poolType = Integer.parseInt(values[5]); // 弹幕池类型(忽略
item
=
mContext
.
mDanmakuFactory
.
createDanmaku
(
type
,
mContext
);
if
(
item
!=
null
)
{
item
.
setTime
(
time
);
item
.
textSize
=
textSize
*
(
mDispDensity
-
0.6f
);
item
.
textColor
=
color
;
item
.
textShadowColor
=
color
<=
Color
.
BLACK
?
Color
.
WHITE
:
Color
.
BLACK
;
}
}
}
}
@Override
public
void
endElement
(
String
uri
,
String
localName
,
String
qName
)
throws
SAXException
{
if
(
item
!=
null
&&
item
.
text
!=
null
)
{
if
(
item
.
duration
!=
null
)
{
String
tagName
=
localName
.
length
()
!=
0
?
localName
:
qName
;
if
(
tagName
.
equalsIgnoreCase
(
"d"
))
{
item
.
setTimer
(
mTimer
);
item
.
flags
=
mContext
.
mGlobalFlagValues
;
Object
lock
=
result
.
obtainSynchronizer
();
synchronized
(
lock
)
{
result
.
addItem
(
item
);
}
}
}
item
=
null
;
}
}
@Override
public
void
characters
(
char
[]
ch
,
int
start
,
int
length
)
{
if
(
item
!=
null
)
{
DanmakuUtils
.
fillText
(
item
,
decodeXmlString
(
new
String
(
ch
,
start
,
length
)));
item
.
index
=
index
++;
// initial specail danmaku data
String
text
=
String
.
valueOf
(
item
.
text
).
trim
();
if
(
item
.
getType
()
==
BaseDanmaku
.
TYPE_SPECIAL
&&
text
.
startsWith
(
"["
)
&&
text
.
endsWith
(
"]"
))
{
//text = text.substring(1, text.length() - 1);
String
[]
textArr
=
null
;
//text.split(",", -1);
try
{
JSONArray
jsonArray
=
new
JSONArray
(
text
);
textArr
=
new
String
[
jsonArray
.
length
()];
for
(
int
i
=
0
;
i
<
textArr
.
length
;
i
++)
{
textArr
[
i
]
=
jsonArray
.
getString
(
i
);
}
}
catch
(
JSONException
e
)
{
e
.
printStackTrace
();
}
if
(
textArr
==
null
||
textArr
.
length
<
5
||
TextUtils
.
isEmpty
(
textArr
[
4
]))
{
item
=
null
;
return
;
}
item
.
text
=
textArr
[
4
];
float
beginX
=
Float
.
parseFloat
(
textArr
[
0
]);
float
beginY
=
Float
.
parseFloat
(
textArr
[
1
]);
float
endX
=
beginX
;
float
endY
=
beginY
;
String
[]
alphaArr
=
textArr
[
2
].
split
(
"-"
);
int
beginAlpha
=
(
int
)
(
AlphaValue
.
MAX
*
Float
.
parseFloat
(
alphaArr
[
0
]));
int
endAlpha
=
beginAlpha
;
if
(
alphaArr
.
length
>
1
)
{
endAlpha
=
(
int
)
(
AlphaValue
.
MAX
*
Float
.
parseFloat
(
alphaArr
[
1
]));
}
long
alphaDuraion
=
(
long
)
(
Float
.
parseFloat
(
textArr
[
3
])
*
1000
);
long
translationDuration
=
alphaDuraion
;
long
translationStartDelay
=
0
;
float
rotateY
=
0
,
rotateZ
=
0
;
if
(
textArr
.
length
>=
7
)
{
rotateZ
=
Float
.
parseFloat
(
textArr
[
5
]);
rotateY
=
Float
.
parseFloat
(
textArr
[
6
]);
}
if
(
textArr
.
length
>=
11
)
{
endX
=
Float
.
parseFloat
(
textArr
[
7
]);
endY
=
Float
.
parseFloat
(
textArr
[
8
]);
if
(!
""
.
equals
(
textArr
[
9
]))
{
translationDuration
=
Integer
.
parseInt
(
textArr
[
9
]);
}
if
(!
""
.
equals
(
textArr
[
10
]))
{
translationStartDelay
=
(
long
)
(
Float
.
parseFloat
(
textArr
[
10
]));
}
}
if
(
isPercentageNumber
(
beginX
))
{
beginX
*=
DanmakuFactory
.
BILI_PLAYER_WIDTH
;
}
if
(
isPercentageNumber
(
beginY
))
{
beginY
*=
DanmakuFactory
.
BILI_PLAYER_HEIGHT
;
}
if
(
isPercentageNumber
(
endX
))
{
endX
*=
DanmakuFactory
.
BILI_PLAYER_WIDTH
;
}
if
(
isPercentageNumber
(
endY
))
{
endY
*=
DanmakuFactory
.
BILI_PLAYER_HEIGHT
;
}
item
.
duration
=
new
Duration
(
alphaDuraion
);
item
.
rotationZ
=
rotateZ
;
item
.
rotationY
=
rotateY
;
mContext
.
mDanmakuFactory
.
fillTranslationData
(
item
,
beginX
,
beginY
,
endX
,
endY
,
translationDuration
,
translationStartDelay
,
mDispScaleX
,
mDispScaleY
);
mContext
.
mDanmakuFactory
.
fillAlphaData
(
item
,
beginAlpha
,
endAlpha
,
alphaDuraion
);
if
(
textArr
.
length
>=
12
)
{
// 是否有描边
if
(!
TextUtils
.
isEmpty
(
textArr
[
11
])
&&
TRUE_STRING
.
equals
(
textArr
[
11
]))
{
item
.
textShadowColor
=
Color
.
TRANSPARENT
;
}
}
if
(
textArr
.
length
>=
13
)
{
//TODO 字体 textArr[12]
}
if
(
textArr
.
length
>=
14
)
{
//TODO 是否有动画缓冲(easing)
}
if
(
textArr
.
length
>=
15
)
{
// 路径数据
if
(!
""
.
equals
(
textArr
[
14
]))
{
String
motionPathString
=
textArr
[
14
].
substring
(
1
);
String
[]
pointStrArray
=
motionPathString
.
split
(
"L"
);
if
(
pointStrArray
!=
null
&&
pointStrArray
.
length
>
0
)
{
float
[][]
points
=
new
float
[
pointStrArray
.
length
][
2
];
for
(
int
i
=
0
;
i
<
pointStrArray
.
length
;
i
++)
{
String
[]
pointArray
=
pointStrArray
[
i
].
split
(
","
);
points
[
i
][
0
]
=
Float
.
parseFloat
(
pointArray
[
0
]);
points
[
i
][
1
]
=
Float
.
parseFloat
(
pointArray
[
1
]);
}
mContext
.
mDanmakuFactory
.
fillLinePathData
(
item
,
points
,
mDispScaleX
,
mDispScaleY
);
}
}
}
}
}
}
private
String
decodeXmlString
(
String
title
)
{
if
(
title
.
contains
(
"&"
))
{
title
=
title
.
replace
(
"&"
,
"&"
);
}
if
(
title
.
contains
(
"""
))
{
title
=
title
.
replace
(
"""
,
"\""
);
}
if
(
title
.
contains
(
">"
))
{
title
=
title
.
replace
(
">"
,
">"
);
}
if
(
title
.
contains
(
"<"
))
{
title
=
title
.
replace
(
"<"
,
"<"
);
}
return
title
;
}
}
private
boolean
isPercentageNumber
(
float
number
)
{
return
number
>=
0
f
&&
number
<=
1
f
;
}
@Override
public
BaseDanmakuParser
setDisplayer
(
IDisplayer
disp
)
{
super
.
setDisplayer
(
disp
);
mDispScaleX
=
mDispWidth
/
DanmakuFactory
.
BILI_PLAYER_WIDTH
;
mDispScaleY
=
mDispHeight
/
DanmakuFactory
.
BILI_PLAYER_HEIGHT
;
return
this
;
}
}
app/src/main/java/com/example/gsyvideoplayer/video/DanmakuVideoPlayer.java
0 → 100644
浏览文件 @
62943836
package
com.example.gsyvideoplayer.video
;
import
android.content.Context
;
import
android.graphics.Color
;
import
android.graphics.drawable.BitmapDrawable
;
import
android.graphics.drawable.Drawable
;
import
android.text.Spannable
;
import
android.text.SpannableStringBuilder
;
import
android.text.Spanned
;
import
android.text.style.BackgroundColorSpan
;
import
android.text.style.ImageSpan
;
import
android.util.AttributeSet
;
import
android.util.Log
;
import
com.example.gsyvideoplayer.R
;
import
com.example.gsyvideoplayer.utils.BiliDanmukuParser
;
import
com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.net.MalformedURLException
;
import
java.net.URL
;
import
java.net.URLConnection
;
import
java.util.HashMap
;
import
master.flame.danmaku.controller.IDanmakuView
;
import
master.flame.danmaku.danmaku.loader.ILoader
;
import
master.flame.danmaku.danmaku.loader.IllegalDataException
;
import
master.flame.danmaku.danmaku.loader.android.DanmakuLoaderFactory
;
import
master.flame.danmaku.danmaku.model.BaseDanmaku
;
import
master.flame.danmaku.danmaku.model.DanmakuTimer
;
import
master.flame.danmaku.danmaku.model.IDanmakus
;
import
master.flame.danmaku.danmaku.model.IDisplayer
;
import
master.flame.danmaku.danmaku.model.android.BaseCacheStuffer
;
import
master.flame.danmaku.danmaku.model.android.DanmakuContext
;
import
master.flame.danmaku.danmaku.model.android.Danmakus
;
import
master.flame.danmaku.danmaku.model.android.SpannedCacheStuffer
;
import
master.flame.danmaku.danmaku.parser.BaseDanmakuParser
;
import
master.flame.danmaku.danmaku.parser.IDataSource
;
import
master.flame.danmaku.danmaku.util.IOUtils
;
import
master.flame.danmaku.ui.widget.DanmakuView
;
/**
* Created by guoshuyu on 2017/2/16.
*/
public
class
DanmakuVideoPlayer
extends
StandardGSYVideoPlayer
{
private
BaseDanmakuParser
mParser
;
//解析器对象
private
IDanmakuView
mDanmakuView
;
//弹幕view
private
DanmakuContext
mDanmakuContext
;
public
DanmakuVideoPlayer
(
Context
context
,
Boolean
fullFlag
)
{
super
(
context
,
fullFlag
);
}
public
DanmakuVideoPlayer
(
Context
context
)
{
super
(
context
);
}
public
DanmakuVideoPlayer
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
}
@Override
public
int
getLayoutId
()
{
return
R
.
layout
.
danmaku_layout
;
}
private
BaseCacheStuffer
.
Proxy
mCacheStufferAdapter
=
new
BaseCacheStuffer
.
Proxy
()
{
private
Drawable
mDrawable
;
@Override
public
void
prepareDrawing
(
final
BaseDanmaku
danmaku
,
boolean
fromWorkerThread
)
{
if
(
danmaku
.
text
instanceof
Spanned
)
{
// 根据你的条件检查是否需要需要更新弹幕
// FIXME 这里只是简单启个线程来加载远程url图片,请使用你自己的异步线程池,最好加上你的缓存池
new
Thread
()
{
@Override
public
void
run
()
{
String
url
=
"http://www.bilibili.com/favicon.ico"
;
InputStream
inputStream
=
null
;
Drawable
drawable
=
mDrawable
;
if
(
drawable
==
null
)
{
try
{
URLConnection
urlConnection
=
new
URL
(
url
).
openConnection
();
inputStream
=
urlConnection
.
getInputStream
();
drawable
=
BitmapDrawable
.
createFromStream
(
inputStream
,
"bitmap"
);
mDrawable
=
drawable
;
}
catch
(
MalformedURLException
e
)
{
e
.
printStackTrace
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
finally
{
IOUtils
.
closeQuietly
(
inputStream
);
}
}
if
(
drawable
!=
null
)
{
drawable
.
setBounds
(
0
,
0
,
100
,
100
);
SpannableStringBuilder
spannable
=
createSpannable
(
drawable
);
danmaku
.
text
=
spannable
;
if
(
mDanmakuView
!=
null
)
{
mDanmakuView
.
invalidateDanmaku
(
danmaku
,
false
);
}
return
;
}
}
}.
start
();
}
}
@Override
public
void
releaseResource
(
BaseDanmaku
danmaku
)
{
// TODO 重要:清理含有ImageSpan的text中的一些占用内存的资源 例如drawable
}
};
@Override
protected
void
init
(
Context
context
)
{
super
.
init
(
context
);
mDanmakuView
=
(
DanmakuView
)
findViewById
(
R
.
id
.
danmaku_view
);
// 设置最大显示行数
HashMap
<
Integer
,
Integer
>
maxLinesPair
=
new
HashMap
<
Integer
,
Integer
>();
maxLinesPair
.
put
(
BaseDanmaku
.
TYPE_SCROLL_RL
,
5
);
// 滚动弹幕最大显示5行
// 设置是否禁止重叠
HashMap
<
Integer
,
Boolean
>
overlappingEnablePair
=
new
HashMap
<
Integer
,
Boolean
>();
overlappingEnablePair
.
put
(
BaseDanmaku
.
TYPE_SCROLL_RL
,
true
);
overlappingEnablePair
.
put
(
BaseDanmaku
.
TYPE_FIX_TOP
,
true
);
mDanmakuContext
=
DanmakuContext
.
create
();
mDanmakuContext
.
setDanmakuStyle
(
IDisplayer
.
DANMAKU_STYLE_STROKEN
,
3
).
setDuplicateMergingEnabled
(
false
).
setScrollSpeedFactor
(
1.2f
).
setScaleTextSize
(
1.2f
)
.
setCacheStuffer
(
new
SpannedCacheStuffer
(),
mCacheStufferAdapter
)
// 图文混排使用SpannedCacheStuffer
// .setCacheStuffer(new BackgroundCacheStuffer()) // 绘制背景使用BackgroundCacheStuffer
.
setMaximumLines
(
maxLinesPair
)
.
preventOverlapping
(
overlappingEnablePair
);
if
(
mDanmakuView
!=
null
)
{
mParser
=
createParser
(
this
.
getResources
().
openRawResource
(
R
.
raw
.
comments
));
mDanmakuView
.
setCallback
(
new
master
.
flame
.
danmaku
.
controller
.
DrawHandler
.
Callback
()
{
@Override
public
void
updateTimer
(
DanmakuTimer
timer
)
{
}
@Override
public
void
drawingFinished
()
{
}
@Override
public
void
danmakuShown
(
BaseDanmaku
danmaku
)
{
// Log.d("DFM", "danmakuShown(): text=" + danmaku.text);
}
@Override
public
void
prepared
()
{
mDanmakuView
.
start
();
}
});
mDanmakuView
.
setOnDanmakuClickListener
(
new
IDanmakuView
.
OnDanmakuClickListener
()
{
@Override
public
boolean
onDanmakuClick
(
IDanmakus
danmakus
)
{
Log
.
d
(
"DFM"
,
"onDanmakuClick: danmakus size:"
+
danmakus
.
size
());
BaseDanmaku
latest
=
danmakus
.
last
();
if
(
null
!=
latest
)
{
Log
.
d
(
"DFM"
,
"onDanmakuClick: text of latest danmaku:"
+
latest
.
text
);
return
true
;
}
return
false
;
}
@Override
public
boolean
onViewClick
(
IDanmakuView
view
)
{
// mMediaController.setVisibility(View.VISIBLE);
return
false
;
}
});
mDanmakuView
.
showFPS
(
true
);
mDanmakuView
.
enableDanmakuDrawingCache
(
true
);
}
}
@Override
public
void
onPrepared
()
{
super
.
onPrepared
();
setDanmuKuUp
();
}
private
void
setDanmuKuUp
()
{
mDanmakuView
.
prepare
(
mParser
,
mDanmakuContext
);
//mDanmakuView.showFPS(true);
//mDanmakuView.enableDanmakuDrawingCache(true);
}
/**
* 创建解析器对象,解析输入流
*
* @param stream
* @return
*/
private
BaseDanmakuParser
createParser
(
InputStream
stream
)
{
if
(
stream
==
null
)
{
return
new
BaseDanmakuParser
()
{
@Override
protected
Danmakus
parse
()
{
return
new
Danmakus
();
}
};
}
ILoader
loader
=
DanmakuLoaderFactory
.
create
(
DanmakuLoaderFactory
.
TAG_BILI
);
try
{
loader
.
load
(
stream
);
}
catch
(
IllegalDataException
e
)
{
e
.
printStackTrace
();
}
BaseDanmakuParser
parser
=
new
BiliDanmukuParser
();
IDataSource
<?>
dataSource
=
loader
.
getDataSource
();
parser
.
load
(
dataSource
);
return
parser
;
}
private
SpannableStringBuilder
createSpannable
(
Drawable
drawable
)
{
String
text
=
"bitmap"
;
SpannableStringBuilder
spannableStringBuilder
=
new
SpannableStringBuilder
(
text
);
ImageSpan
span
=
new
ImageSpan
(
drawable
);
//ImageSpan.ALIGN_BOTTOM);
spannableStringBuilder
.
setSpan
(
span
,
0
,
text
.
length
(),
Spannable
.
SPAN_INCLUSIVE_EXCLUSIVE
);
spannableStringBuilder
.
append
(
"图文混排"
);
spannableStringBuilder
.
setSpan
(
new
BackgroundColorSpan
(
Color
.
parseColor
(
"#8A2233B1"
)),
0
,
spannableStringBuilder
.
length
(),
Spannable
.
SPAN_INCLUSIVE_INCLUSIVE
);
return
spannableStringBuilder
;
}
}
app/src/main/res/layout/activity_detail_player.xml
浏览文件 @
62943836
...
...
@@ -29,7 +29,7 @@
</android.support.v4.widget.NestedScrollView>
<com.example.gsyvideoplayer.video.
LandLayoutVideo
<com.example.gsyvideoplayer.video.
DanmakuVideoPlayer
android:id=
"@+id/detail_player"
android:layout_width=
"match_parent"
android:layout_height=
"@dimen/post_media_height"
/>
...
...
app/src/main/res/layout/danmaku_layout.xml
0 → 100644
浏览文件 @
62943836
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:background=
"@android:color/black"
>
<RelativeLayout
android:id=
"@+id/surface_container"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:gravity=
"center"
>
</RelativeLayout>
<com.shuyu.gsyvideoplayer.GSYImageCover
android:id=
"@+id/cover"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:layout_centerInParent=
"true"
android:scaleType=
"fitXY"
/>
<master.flame.danmaku.ui.widget.DanmakuView
android:id=
"@+id/danmaku_view"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
/>
<RelativeLayout
android:id=
"@+id/thumb"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:layout_alignParentBottom=
"true"
android:layout_alignParentEnd=
"true"
android:layout_alignParentLeft=
"true"
android:layout_alignParentRight=
"true"
android:layout_alignParentStart=
"true"
android:layout_alignParentTop=
"true"
android:background=
"#000000"
android:scaleType=
"fitCenter"
/>
<LinearLayout
android:id=
"@+id/layout_bottom"
android:layout_width=
"match_parent"
android:layout_height=
"40dp"
android:layout_alignParentBottom=
"true"
android:background=
"#99000000"
android:gravity=
"center_vertical"
android:orientation=
"horizontal"
android:visibility=
"invisible"
>
<TextView
android:id=
"@+id/current"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginLeft=
"16dp"
android:text=
"00:00"
android:textColor=
"#ffffff"
/>
<SeekBar
android:id=
"@+id/progress"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center_vertical"
android:layout_weight=
"1.0"
android:background=
"@null"
android:max=
"100"
android:maxHeight=
"4dp"
android:minHeight=
"4dp"
android:paddingBottom=
"8dp"
android:paddingTop=
"8dp"
android:progressDrawable=
"@drawable/video_seek_progress"
android:thumb=
"@drawable/video_seek_thumb"
/>
<TextView
android:id=
"@+id/total"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginRight=
"16dp"
android:text=
"00:00"
android:textColor=
"#ffffff"
/>
<ImageView
android:id=
"@+id/fullscreen"
android:layout_width=
"wrap_content"
android:layout_height=
"fill_parent"
android:paddingRight=
"16dp"
android:scaleType=
"center"
android:src=
"@drawable/video_enlarge"
/>
</LinearLayout>
<ProgressBar
android:id=
"@+id/bottom_progressbar"
style=
"?android:attr/progressBarStyleHorizontal"
android:layout_width=
"match_parent"
android:layout_height=
"1.5dp"
android:layout_alignParentBottom=
"true"
android:max=
"100"
android:progressDrawable=
"@drawable/video_progress"
/>
<ImageView
android:id=
"@+id/back_tiny"
android:layout_width=
"24dp"
android:layout_height=
"24dp"
android:layout_marginLeft=
"6dp"
android:layout_marginTop=
"6dp"
android:visibility=
"gone"
/>
<LinearLayout
android:id=
"@+id/layout_top"
android:layout_width=
"match_parent"
android:layout_height=
"48dp"
android:background=
"@drawable/video_title_bg"
android:gravity=
"center_vertical"
>
<ImageView
android:id=
"@+id/back"
android:layout_width=
"48dp"
android:layout_height=
"48dp"
android:paddingLeft=
"10dp"
android:scaleType=
"centerInside"
android:src=
"@drawable/video_back"
/>
<TextView
android:id=
"@+id/title"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:paddingLeft=
"10dp"
android:textColor=
"@android:color/white"
android:textSize=
"18sp"
/>
</LinearLayout>
<moe.codeest.enviews.ENDownloadView
android:id=
"@+id/loading"
android:layout_width=
"28dp"
android:layout_height=
"28dp"
android:layout_centerHorizontal=
"true"
android:layout_centerVertical=
"true"
android:visibility=
"invisible"
/>
<moe.codeest.enviews.ENPlayView
android:id=
"@+id/start"
android:layout_width=
"60dp"
android:layout_height=
"60dp"
android:layout_centerHorizontal=
"true"
android:layout_centerVertical=
"true"
android:layout_gravity=
"center_vertical"
/>
<ImageView
android:id=
"@+id/small_close"
android:layout_width=
"30dp"
android:layout_height=
"30dp"
android:paddingLeft=
"10dp"
android:paddingTop=
"10dp"
android:scaleType=
"centerInside"
android:src=
"@drawable/video_small_close"
android:visibility=
"gone"
/>
<ImageView
android:id=
"@+id/lock_screen"
android:layout_width=
"30dp"
android:layout_height=
"30dp"
android:layout_alignParentRight=
"true"
android:layout_centerVertical=
"true"
android:layout_marginRight=
"50dp"
android:visibility=
"gone"
android:scaleType=
"centerInside"
android:src=
"@drawable/unlock"
/>
</RelativeLayout>
app/src/main/res/raw/comments.xml
0 → 100644
浏览文件 @
62943836
此差异已折叠。
点击以展开。
dependencies.gradle
浏览文件 @
62943836
...
...
@@ -16,7 +16,8 @@ ext {
//ViewLibraries
butterKnifeVersion
=
'8.2.1'
ijkplayer
=
'0.7.7'
ijkplayer
=
'0.7.7.1'
DanmakuFlameMaster
=
'0.6.4'
transitionseverywhere
=
'1.7.0'
...
...
@@ -43,6 +44,10 @@ ext {
ijkplayer_x86
:
"tv.danmaku.ijk.media:ijkplayer-x86:${ijkplayer}"
,
ijkplayer_exo
:
"tv.danmaku.ijk.media:ijkplayer-exo:${ijkplayer}"
,
transitionseverywhere:
"com.andkulikov:transitionseverywhere:${transitionseverywhere}"
,
DanmakuFlameMaster
:
"com.github.ctiao:DanmakuFlameMaster:${DanmakuFlameMaster}"
,
ndkbitmap_armv7a
:
"com.github.ctiao:ndkbitmap-armv7a:${DanmakuFlameMaster}"
,
ndkbitmap_armv5
:
"com.github.ctiao:ndkbitmap-armv5:${DanmakuFlameMaster}"
,
ndkbitmap_x86
:
"com.github.ctiao:ndkbitmap-x86:${DanmakuFlameMaster}"
,
]
dataDependencies
=
[
...
...
gsyVideoPlayer/libs/arm64-v8a/libijkplayer.so
浏览文件 @
62943836
无法预览此类型文件
gsyVideoPlayer/libs/arm64-v8a/libijksdl.so
浏览文件 @
62943836
无法预览此类型文件
gsyVideoPlayer/libs/armeabi-v7a/libijkplayer.so
浏览文件 @
62943836
无法预览此类型文件
gsyVideoPlayer/libs/armeabi-v7a/libijksdl.so
浏览文件 @
62943836
无法预览此类型文件
gsyVideoPlayer/libs/armeabi/libijkplayer.so
浏览文件 @
62943836
无法预览此类型文件
gsyVideoPlayer/libs/armeabi/libijksdl.so
浏览文件 @
62943836
无法预览此类型文件
gsyVideoPlayer/libs/x86/libijkffmpeg.so
浏览文件 @
62943836
无法预览此类型文件
gsyVideoPlayer/libs/x86/libijkplayer.so
浏览文件 @
62943836
无法预览此类型文件
gsyVideoPlayer/libs/x86/libijksdl.so
浏览文件 @
62943836
无法预览此类型文件
gsyVideoPlayer/libs/x86_64/libijkplayer.so
浏览文件 @
62943836
无法预览此类型文件
gsyVideoPlayer/libs/x86_64/libijksdl.so
浏览文件 @
62943836
无法预览此类型文件
gsyVideoPlayer/src/main/java/com/shuyu/gsyvideoplayer/video/StandardGSYVideoPlayer.java
浏览文件 @
62943836
...
...
@@ -448,6 +448,10 @@ public class StandardGSYVideoPlayer extends GSYVideoPlayer {
mTopContainer
.
setVisibility
(
View
.
INVISIBLE
);
mBottomContainer
.
setVisibility
(
View
.
INVISIBLE
);
mStartButton
.
setVisibility
(
View
.
INVISIBLE
);
mLoadingProgressBar
.
setVisibility
(
View
.
INVISIBLE
);
if
(
mLoadingProgressBar
instanceof
ENDownloadView
)
{
((
ENDownloadView
)
mLoadingProgressBar
).
reset
();
}
mThumbImageViewLayout
.
setVisibility
(
View
.
INVISIBLE
);
mBottomProgressBar
.
setVisibility
(
View
.
INVISIBLE
);
mCoverImageView
.
setVisibility
(
View
.
VISIBLE
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录