297 lines
10 KiB
Java
297 lines
10 KiB
Java
|
|
package com.qxcm.moduleutil.widget;
|
||
|
|
|
||
|
|
import android.content.Context;
|
||
|
|
import android.graphics.SurfaceTexture;
|
||
|
|
import android.net.Uri;
|
||
|
|
import android.opengl.GLES11Ext;
|
||
|
|
import android.opengl.GLES20;
|
||
|
|
import android.opengl.GLSurfaceView;
|
||
|
|
import android.os.Handler;
|
||
|
|
import android.os.Looper;
|
||
|
|
import android.util.AttributeSet;
|
||
|
|
import android.util.Log;
|
||
|
|
import android.view.LayoutInflater;
|
||
|
|
import android.view.Surface;
|
||
|
|
import android.view.View;
|
||
|
|
import android.widget.FrameLayout;
|
||
|
|
|
||
|
|
import androidx.annotation.NonNull;
|
||
|
|
import androidx.annotation.Nullable;
|
||
|
|
import androidx.databinding.DataBindingUtil;
|
||
|
|
|
||
|
|
import com.blankj.utilcode.util.PathUtils;
|
||
|
|
import com.google.android.exoplayer2.ExoPlayer;
|
||
|
|
import com.google.android.exoplayer2.MediaItem;
|
||
|
|
import com.google.android.exoplayer2.ui.PlayerView;
|
||
|
|
import com.liulishuo.okdownload.DownloadTask;
|
||
|
|
import com.liulishuo.okdownload.StatusUtil;
|
||
|
|
import com.liulishuo.okdownload.core.cause.EndCause;
|
||
|
|
import com.liulishuo.okdownload.core.cause.ResumeFailedCause;
|
||
|
|
import com.liulishuo.okdownload.core.listener.DownloadListener1;
|
||
|
|
import com.liulishuo.okdownload.core.listener.assist.Listener1Assist;
|
||
|
|
import com.opensource.svgaplayer.SVGADrawable;
|
||
|
|
import com.opensource.svgaplayer.SVGADynamicEntity;
|
||
|
|
import com.opensource.svgaplayer.SVGAImageView;
|
||
|
|
import com.opensource.svgaplayer.SVGAParser;
|
||
|
|
import com.opensource.svgaplayer.SVGAVideoEntity;
|
||
|
|
import com.qxcm.moduleutil.R;
|
||
|
|
import com.qxcm.moduleutil.databinding.RoomViewSvgaAnimBinding;
|
||
|
|
import com.qxcm.moduleutil.utils.Md5Utils;
|
||
|
|
import com.qxcm.moduleutil.utils.logger.Logger;
|
||
|
|
import com.tencent.bugly.idasc.crashreport.CrashReport;
|
||
|
|
import com.tencent.qgame.animplayer.AnimConfig;
|
||
|
|
import com.tencent.qgame.animplayer.inter.IAnimListener;
|
||
|
|
|
||
|
|
import java.io.File;
|
||
|
|
import java.net.URL;
|
||
|
|
|
||
|
|
|
||
|
|
public class AvatarFrameView extends FrameLayout implements IAnimListener {
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void onFailed(int i, @Nullable String s) {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public boolean onVideoConfigReady(@NonNull AnimConfig animConfig) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void onVideoStart() {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void onVideoRender(int i, @Nullable AnimConfig animConfig) {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void onVideoComplete() {
|
||
|
|
if (mType == 1) {
|
||
|
|
mBinding.playView.startPlay(mFile);
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void onVideoDestroy() {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
public enum RenderType {SVGA, MP4}
|
||
|
|
|
||
|
|
private RenderType renderType;
|
||
|
|
private ExoPlayer exoPlayer;
|
||
|
|
private PlayerView playerView;
|
||
|
|
private SVGAImageView svgaSurface;
|
||
|
|
private GLSurfaceView glSurfaceView;
|
||
|
|
private final Handler mainHandler = new Handler(Looper.getMainLooper());
|
||
|
|
private ChannelSplitRenderer1 renderer;
|
||
|
|
private int mType;//1:循环播放 2:播放一次停止播放
|
||
|
|
private File mFile;
|
||
|
|
|
||
|
|
private RoomViewSvgaAnimBinding mBinding;
|
||
|
|
|
||
|
|
public AvatarFrameView(@NonNull Context context) {
|
||
|
|
this(context, null);
|
||
|
|
}
|
||
|
|
|
||
|
|
public AvatarFrameView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||
|
|
this(context, attrs, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
public AvatarFrameView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||
|
|
super(context, attrs, defStyleAttr);
|
||
|
|
mBinding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.room_view_svga_anim, this, true);
|
||
|
|
initViews();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void initViews() {
|
||
|
|
// 初始化 ExoPlayer View
|
||
|
|
playerView = new PlayerView(getContext());
|
||
|
|
playerView.setUseController(false);
|
||
|
|
playerView.setVisibility(View.GONE);
|
||
|
|
addView(playerView);
|
||
|
|
|
||
|
|
// 初始化 SVGA View
|
||
|
|
svgaSurface = new SVGAImageView(getContext());
|
||
|
|
svgaSurface.setVisibility(View.GONE);
|
||
|
|
addView(svgaSurface);
|
||
|
|
|
||
|
|
// // 初始化 GLSurfaceView
|
||
|
|
// glSurfaceView = new GLSurfaceView(getContext());
|
||
|
|
// glSurfaceView.setEGLContextClientVersion(2);
|
||
|
|
// renderer = new ChannelSplitRenderer1();
|
||
|
|
// glSurfaceView.setRenderer(renderer);
|
||
|
|
// glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
|
||
|
|
// glSurfaceView.setVisibility(View.GONE); // 默认隐藏
|
||
|
|
// addView(glSurfaceView);
|
||
|
|
|
||
|
|
// 初始化 ExoPlayer
|
||
|
|
exoPlayer = new ExoPlayer.Builder(getContext()).build();
|
||
|
|
playerView.setPlayer(exoPlayer);
|
||
|
|
|
||
|
|
mBinding.playView.setAnimListener(this);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void setSource(String url, RenderType type, int type2) {
|
||
|
|
clearPrevious();
|
||
|
|
renderType = type;
|
||
|
|
mType = type2;
|
||
|
|
switch (type) {
|
||
|
|
case SVGA:
|
||
|
|
mBinding.playView.stopPlay();
|
||
|
|
mBinding.playView.setVisibility(View.GONE);
|
||
|
|
loadSVGA(url);
|
||
|
|
break;
|
||
|
|
case MP4:
|
||
|
|
// loadMP4(url);
|
||
|
|
mBinding.playView.setVisibility(View.VISIBLE);
|
||
|
|
downloadAndPlayMp4(url);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void downloadAndPlayMp4(String url) {
|
||
|
|
DownloadTask task = new DownloadTask.Builder(url, PathUtils.getInternalAppCachePath()
|
||
|
|
, Md5Utils.getStringMD5(url) + ".mp4")
|
||
|
|
// the minimal interval millisecond for callback progress
|
||
|
|
.setMinIntervalMillisCallbackProcess(100)
|
||
|
|
// do re-download even if the task has already been completed in the past.
|
||
|
|
.setPassIfAlreadyCompleted(false)
|
||
|
|
.setAutoCallbackToUIThread(true)
|
||
|
|
.build();
|
||
|
|
if (StatusUtil.isCompleted(task)) {
|
||
|
|
playMp4(task.getFile());
|
||
|
|
mFile = task.getFile();
|
||
|
|
} else {
|
||
|
|
task.enqueue(new DownloadListener1() {
|
||
|
|
@Override
|
||
|
|
public void taskStart(@NonNull DownloadTask task, @NonNull Listener1Assist.Listener1Model model) {
|
||
|
|
Logger.e("taskStart", model);
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void retry(@NonNull DownloadTask task, @NonNull ResumeFailedCause cause) {
|
||
|
|
Logger.e("retry", cause);
|
||
|
|
CrashReport.postCatchedException(new RuntimeException("下载文件重试:" + cause == null ? "" : cause.name()));
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void connected(@NonNull DownloadTask task, int blockCount, long currentOffset, long totalLength) {
|
||
|
|
Logger.e("connected", blockCount);
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void progress(@NonNull DownloadTask task, long currentOffset, long totalLength) {
|
||
|
|
Logger.e("progress", currentOffset);
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void taskEnd(@NonNull DownloadTask task, @NonNull EndCause cause, @Nullable Exception realCause, @NonNull Listener1Assist.Listener1Model model) {
|
||
|
|
Logger.e("taskEnd", model);
|
||
|
|
playMp4(task.getFile());
|
||
|
|
mFile = task.getFile();
|
||
|
|
if (cause != null && cause != EndCause.COMPLETED) {
|
||
|
|
// CrashReport.postCatchedException(new RuntimeException("下载任务结束:" + cause == null ? "" : cause.name() + "_realCause:" + realCause == null ? "" : realCause.getMessage()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void playMp4(File file) {
|
||
|
|
if (file != null) {
|
||
|
|
mBinding.playView.startPlay(file);
|
||
|
|
|
||
|
|
} else {
|
||
|
|
// showAnim();
|
||
|
|
// playMp4(file);
|
||
|
|
CrashReport.postCatchedException(new RuntimeException("播放MP4失败:File is null"));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void loadSVGA(String url) {
|
||
|
|
svgaSurface.setVisibility(View.VISIBLE);
|
||
|
|
try {
|
||
|
|
new SVGAParser(getContext()).parse(new URL(url), new SVGAParser.ParseCompletion() {
|
||
|
|
@Override
|
||
|
|
public void onComplete(SVGAVideoEntity videoItem) {
|
||
|
|
SVGADrawable drawable = new SVGADrawable(videoItem, new SVGADynamicEntity());
|
||
|
|
svgaSurface.setImageDrawable(drawable);
|
||
|
|
svgaSurface.startAnimation();
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public void onError() {
|
||
|
|
}
|
||
|
|
});
|
||
|
|
} catch (Exception e) {
|
||
|
|
e.printStackTrace();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void loadMP4(String url) {
|
||
|
|
svgaSurface.setVisibility(View.GONE);
|
||
|
|
playerView.setVisibility(View.GONE);
|
||
|
|
|
||
|
|
glSurfaceView.setVisibility(View.VISIBLE);
|
||
|
|
glSurfaceView.onResume();
|
||
|
|
glSurfaceView.requestRender();
|
||
|
|
// 使用 post 确保 GLSurfaceView 已完成 layout
|
||
|
|
glSurfaceView.post(() -> {
|
||
|
|
Log.d("@@@", "GLSurfaceView size after layout: " + glSurfaceView.getWidth() + "x" + glSurfaceView.getHeight());
|
||
|
|
|
||
|
|
glSurfaceView.onResume();
|
||
|
|
glSurfaceView.requestRender();
|
||
|
|
|
||
|
|
renderer.setOnSurfaceTextureReadyListener(surfaceTexture -> {
|
||
|
|
mainHandler.post(() -> {
|
||
|
|
Surface surface = new Surface(surfaceTexture);
|
||
|
|
|
||
|
|
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(url));
|
||
|
|
exoPlayer.setMediaItem(mediaItem);
|
||
|
|
exoPlayer.setVideoSurface(surface);
|
||
|
|
exoPlayer.prepare();
|
||
|
|
exoPlayer.play();
|
||
|
|
Log.d("@@@", "ExoPlayer state after play: " + exoPlayer.getPlaybackState());
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private void clearPrevious() {
|
||
|
|
if (exoPlayer != null) {
|
||
|
|
exoPlayer.stop();
|
||
|
|
exoPlayer.clearVideoSurface();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (svgaSurface.getDrawable() instanceof SVGADrawable) {
|
||
|
|
((SVGADrawable) svgaSurface.getDrawable()).stop();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (playerView != null) playerView.setVisibility(View.GONE);
|
||
|
|
if (svgaSurface != null) svgaSurface.setVisibility(View.GONE);
|
||
|
|
// if (glSurfaceView != null) glSurfaceView.setVisibility(View.GONE);
|
||
|
|
mBinding.playView.setVisibility(View.GONE);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void release() {
|
||
|
|
if (exoPlayer != null) {
|
||
|
|
exoPlayer.release();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (svgaSurface.getDrawable() instanceof SVGADrawable) {
|
||
|
|
((SVGADrawable) svgaSurface.getDrawable()).stop();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (glSurfaceView != null) {
|
||
|
|
glSurfaceView.onPause(); // 必须调用生命周期方法
|
||
|
|
// glSurfaceView.requestRender();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|