Open li504799868 opened 8 years ago
加载图片是在哪个线程做的
加载图片是用的imageloader,但是这段代码我现在给注释掉了,现在用的就是包里的图片,另外我刚刚还发现一个蛋疼的问题,我开启fps显示,我的app的那个time,竟然不是一秒一秒累加的,可能是几秒
public void addDanmaku(final String url, final String text) { NDConfigs.executeTask(new Runnable() {
@Override
public void run() {
BaseDanmaku danmaku = mContext.mDanmakuFactory
.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
if (danmaku == null) {
return;
}
Drawable drawable = null;
drawable = context.getResources().getDrawable(
R.drawable.default_picture_oval);
drawable.setBounds(0, 0, imageSize, imageSize);
danmaku.text = createSpannable(drawable, text);
// 设置弹幕时间
danmaku.duration = new Duration(5000);
danmaku.padding = 5;
danmaku.priority = 1; // 一定会显示, 一般用于本机发送的弹幕
danmaku.isLive = false;
danmaku.setTime(getCurrentTime() + 1000);
danmaku.textSize = textSize;
danmaku.textColor = Color.WHITE;
danmaku.textShadowColor = 0; //
// 重要:如果有图文混排,最好不要设置描边(设textShadowColor=0),否则会进行两次复杂的绘制导致运行效率降低
addDanmaku(danmaku);
}
});
}
我在详细的说一下我这里的情况吧 , 弹幕是浮在视频的上面, 视频的控件是使用的ijkplayer ,不知道是不是这两个在一起有互相影响了呢
能否提供能重现的demo代码看看 另外不要对duration赋值
danmaku.duration = new Duration(5000);
恩 我现在试试 稍等一会
我把demo怎么发给你呢 我现在把ijkplayer放进去播放视频,然后不停的点击图文 ,卡顿就很明显了
package com.sample;
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 java.util.Timer; import java.util.TimerTask;
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.parser.android.BiliDanmukuParser; import master.flame.danmaku.danmaku.util.IOUtils; import master.flame.danmaku.danmaku.util.SystemClock; import tv.danmaku.ijk.media.player.IMediaPlayer; import tv.danmaku.ijk.media.player.IMediaPlayer.OnPreparedListener; import tv.danmaku.ijk.media.player.IjkMediaPlayer; import android.app.Activity; import android.content.pm.ActivityInfo; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextPaint; import android.text.style.BackgroundColorSpan; import android.text.style.ImageSpan; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.Button; import android.widget.PopupWindow;
public class MainActivity extends Activity implements View.OnClickListener {
private IDanmakuView mDanmakuView;
private View mMediaController;
public PopupWindow mPopupWindow;
private Button mBtnRotate;
private Button mBtnHideDanmaku;
private Button mBtnShowDanmaku;
private BaseDanmakuParser mParser;
private Button mBtnPauseDanmaku;
private Button mBtnResumeDanmaku;
private Button mBtnSendDanmaku;
private Button mBtnSendDanmakuTextAndImage;
private Button mBtnSendDanmakus;
private DanmakuContext mContext;
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
}
};
/**
* 绘制背景(自定义弹幕样式)
*/
private static class BackgroundCacheStuffer extends SpannedCacheStuffer {
// 通过扩展SimpleTextCacheStuffer或SpannedCacheStuffer个性化你的弹幕样式
final Paint paint = new Paint();
@Override
public void measure(BaseDanmaku danmaku, TextPaint paint,
boolean fromWorkerThread) {
danmaku.padding = 10; // 在背景绘制模式下增加padding
super.measure(danmaku, paint, fromWorkerThread);
}
@Override
public void drawBackground(BaseDanmaku danmaku, Canvas canvas,
float left, float top) {
paint.setColor(0x8125309b);
canvas.drawRect(left + 2, top + 2, left + danmaku.paintWidth - 2,
top + danmaku.paintHeight - 2, paint);
}
@Override
public void drawStroke(BaseDanmaku danmaku, String lineText,
Canvas canvas, float left, float top, Paint paint) {
// 禁用描边绘制
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViews();
}
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 void findViews() {
mMediaController = findViewById(R.id.media_controller);
mBtnRotate = (Button) findViewById(R.id.rotate);
mBtnHideDanmaku = (Button) findViewById(R.id.btn_hide);
mBtnShowDanmaku = (Button) findViewById(R.id.btn_show);
mBtnPauseDanmaku = (Button) findViewById(R.id.btn_pause);
mBtnResumeDanmaku = (Button) findViewById(R.id.btn_resume);
mBtnSendDanmaku = (Button) findViewById(R.id.btn_send);
mBtnSendDanmakuTextAndImage = (Button) findViewById(R.id.btn_send_image_text);
mBtnSendDanmakus = (Button) findViewById(R.id.btn_send_danmakus);
mBtnRotate.setOnClickListener(this);
mBtnHideDanmaku.setOnClickListener(this);
mMediaController.setOnClickListener(this);
mBtnShowDanmaku.setOnClickListener(this);
mBtnPauseDanmaku.setOnClickListener(this);
mBtnResumeDanmaku.setOnClickListener(this);
mBtnSendDanmaku.setOnClickListener(this);
mBtnSendDanmakuTextAndImage.setOnClickListener(this);
mBtnSendDanmakus.setOnClickListener(this);
// init player
IjkMediaPlayer.loadLibrariesOnce(null);
IjkMediaPlayer.native_profileBegin("libijkplayer.so");
// VideoView
final IjkVideoView mVideoView = (IjkVideoView) findViewById(R.id.videoview);
// DanmakuView
// 设置最大显示行数
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);
mDanmakuView = (IDanmakuView) findViewById(R.id.sv_danmaku);
mContext = DanmakuContext.create();
mContext.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.prepare(mParser, mContext);
mDanmakuView.showFPS(true);
mDanmakuView.enableDanmakuDrawingCache(true);
}
if (mVideoView != null) {
mVideoView.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(IMediaPlayer mp) {
mVideoView.start();
}
});
mVideoView
.setVideoPath("http://bj.video.baladiguo.com/video_480/4bd706ed230deebe5696dde3b592b851.mp4?OSSAccessKeyId=0EBRRPeWqt4QcQ7s&Expires=1477558360&Signature=6rtvkZFeVxuuCTPNXp4wKCHKXiQ%3D");
}
}
@Override
protected void onPause() {
super.onPause();
if (mDanmakuView != null && mDanmakuView.isPrepared()) {
mDanmakuView.pause();
}
}
@Override
protected void onResume() {
super.onResume();
if (mDanmakuView != null && mDanmakuView.isPrepared()
&& mDanmakuView.isPaused()) {
mDanmakuView.resume();
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
if (mDanmakuView != null) {
// dont forget release!
mDanmakuView.release();
mDanmakuView = null;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public void onClick(View v) {
if (v == mMediaController) {
mMediaController.setVisibility(View.GONE);
}
if (mDanmakuView == null || !mDanmakuView.isPrepared())
return;
if (v == mBtnRotate) {
setRequestedOrientation(getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
: ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else if (v == mBtnHideDanmaku) {
mDanmakuView.hide();
// mPausedPosition = mDanmakuView.hideAndPauseDrawTask();
} else if (v == mBtnShowDanmaku) {
mDanmakuView.show();
// mDanmakuView.showAndResumeDrawTask(mPausedPosition); // sync to
// the video time in your practice
} else if (v == mBtnPauseDanmaku) {
mDanmakuView.pause();
} else if (v == mBtnResumeDanmaku) {
mDanmakuView.resume();
} else if (v == mBtnSendDanmaku) {
addDanmaku(false);
} else if (v == mBtnSendDanmakuTextAndImage) {
addDanmaKuShowTextAndImage(false);
} else if (v == mBtnSendDanmakus) {
Boolean b = (Boolean) mBtnSendDanmakus.getTag();
timer.cancel();
if (b == null || !b) {
mBtnSendDanmakus.setText(R.string.cancel_sending_danmakus);
timer = new Timer();
timer.schedule(new AsyncAddTask(), 0, 1000);
mBtnSendDanmakus.setTag(true);
} else {
mBtnSendDanmakus.setText(R.string.send_danmakus);
mBtnSendDanmakus.setTag(false);
}
}
}
Timer timer = new Timer();
class AsyncAddTask extends TimerTask {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
addDanmaku(true);
SystemClock.sleep(20);
}
}
};
private void addDanmaku(boolean islive) {
BaseDanmaku danmaku = mContext.mDanmakuFactory
.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
if (danmaku == null || mDanmakuView == null) {
return;
}
// for(int i=0;i<100;i++){
// }
danmaku.text = "这是一条弹幕" + System.nanoTime();
danmaku.padding = 5;
danmaku.priority = 0; // 可能会被各种过滤器过滤并隐藏显示
danmaku.isLive = islive;
danmaku.setTime(mDanmakuView.getCurrentTime() + 1200);
danmaku.textSize = 25f * (mParser.getDisplayer().getDensity() - 0.6f);
danmaku.textColor = Color.RED;
danmaku.textShadowColor = Color.WHITE;
// danmaku.underlineColor = Color.GREEN;
danmaku.borderColor = Color.GREEN;
mDanmakuView.addDanmaku(danmaku);
}
private void addDanmaKuShowTextAndImage(boolean islive) {
BaseDanmaku danmaku = mContext.mDanmakuFactory
.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
Drawable drawable = getResources().getDrawable(R.drawable.ic_launcher);
drawable.setBounds(0, 0, 100, 100);
SpannableStringBuilder spannable = createSpannable(drawable);
danmaku.text = spannable;
danmaku.padding = 5;
danmaku.priority = 1; // 一定会显示, 一般用于本机发送的弹幕
danmaku.isLive = islive;
danmaku.setTime(mDanmakuView.getCurrentTime() + 1200);
danmaku.textSize = 25f * (mParser.getDisplayer().getDensity() - 0.6f);
danmaku.textColor = Color.RED;
danmaku.textShadowColor = 0; // 重要:如果有图文混排,最好不要设置描边(设textShadowColor=0),否则会进行两次复杂的绘制导致运行效率降低
danmaku.underlineColor = Color.GREEN;
mDanmakuView.addDanmaku(danmaku);
}
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;
}
@Override
protected void onDestroy() {
super.onDestroy();
IjkMediaPlayer.native_profileEnd();
if (mDanmakuView != null) {
// dont forget release!
mDanmakuView.release();
mDanmakuView = null;
}
}
}
里面使用的ijkplayer就是官方的ijkplayer的demo里的文件 ,直接复制过来的,如果需要demo加我的qq就是我的名字的号码
我刚刚又仔细测试了一下 发现了一个问题 如果ijkplayer使用了 // init player IjkMediaPlayer.loadLibrariesOnce(null); IjkMediaPlayer.native_profileBegin("libijkplayer.so");
弹幕的卡顿就会明显很多 ,希望能够帮助你们排查问题
ijk开启硬解码了吗
这个方法是开启硬解码的吗 ……我也不清楚 但是确实是调用了之后卡顿明显
不是,我的意思是开启ijk硬解码,会减少弹幕卡顿。 你的情况很有可能是因为软解播放耗性能影响了弹幕
……低调的问一句怎么开启硬解码
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
是这个设置吗
我这里是在做把聊天消息当做弹幕的形式发送出去 ,是带有用户 头像的图文混排, 我把所有的弹幕都设置了danmaku.priority = 1; 但是当数量多一些的时候就会发生卡顿,看fps的话 会降到20多,我直接把demo的代码复制过来还是会卡,但是demo的fps却很稳定,都是在60左右。 我看了其他朋友提的问题,把添加弹幕放到子线程,但是还是会卡顿,求大神帮帮忙,解决这个蛋疼的问题