视频切换横竖屏参考文章: https://blog.youkuaiyun.com/csdnwr/article/details/121141056
第一步:圈定画布为 宽400像素. 高度videoScale计算出实际像素
public static float videoScale = 16f / 9f;
float videoX = 400f;
String videoy = (videoX / videoScale) + "";
double videoHeight = Math.round(Double.parseDouble(videoy));
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams((int) videoX, (int) videoHeight);
// lp.addRule(RelativeLayout.CENTER_IN_PARENT);
lp.addRule(RelativeLayout.BELOW, R.id.left_video_title_view);
mVideoView.setLayoutParams(lp);
第二步:拿到视频实际宽高
mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
if (mSurfaceView != null) {
changeVideoSize(mSurfaceView, width, height);
}
}
});
第三步:计算mSurfaceView实际视频宽高和画布宽度比例(不需要描点的到此结束)
public void changeVideoSize(SurfaceView mSurfaceView, int videoWidth, int videoHeight) {
//视频容器宽度以400像素计算比例
float surfaceWidth = 400f;
float max = (float) videoWidth / (float) surfaceWidth;
//视频宽高分别/最大倍数值 计算出放大后的视频尺寸
videoWidth = (int) Math.ceil((float) videoWidth / max);
videoHeight = (int) Math.ceil((float) videoHeight / max);
//无法直接设置视频尺寸,将计算出的视频尺寸设置到surfaceView 让视频自动填充。
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(videoWidth, videoHeight);
lp.gravity = Gravity.CENTER;
mSurfaceView.setLayoutParams(lp);
}
第四步:视频添加等比例tag标记
视频需要用Frameview单独包裹,否则某些机型无法正常显隐藏 mVideoFrameview.getChildAt(0).setVisibility(View.GONE); 此处给的是第一步拿到的画布宽高 mVideoTagView.setVideoXY((int) videoX, (int) videoHeight);
自定义标记View
public class TagTextView extends View {
private Paint bgPaint = new Paint();
private Paint innerBgPaint = new Paint();
private Paint textPaint = new Paint();
private float bgRadius = 12; //外圆半径
private float innerBgRadius = 8; //内圆半径
private float testSize = 4; //内容字号
private int bgColor = R.color.dot_color_trans_25;
private int innerBgColor = R.color.dot_color;
private List<IotVideo.RelCoordinateList> mTagInfoBean = new ArrayList<>();
public TagTextView(Context context, List<IotVideo.RelCoordinateList> tagInfoBean) {
this(context, null, 0);
if (tagInfoBean != null) {
mTagInfoBean = tagInfoBean;
}
initView(context);
}
public TagTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TagTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
public void setData(List<IotVideo.RelCoordinateList> tagInfoBean) {
mTagInfoBean.clear();
mTagInfoBean.addAll(tagInfoBean);
invalidate();
}
private void initView(Context context) {
bgPaint = new Paint();
bgPaint.setColor(context.getResources().getColor(bgColor));
bgPaint.setAntiAlias(true);
innerBgPaint = new Paint();
innerBgPaint.setColor(context.getResources().getColor(innerBgColor));
innerBgPaint.setAntiAlias(true);
textPaint = new Paint();
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(DisplayUtil.dip2px(context, testSize));
textPaint.setAntiAlias(true);
}
//文本坐标偏移量
private float textD_X = 3.5f;
private float textD_y = 3.5f;
//视频尺寸
public float videoX = -1;
public float videoy = -1;
public void setVideoXY(float videoX, float videoy) {
this.videoX = videoX;
this.videoy = videoy;
}
@Override
protected void onDraw(Canvas canvas) {
if (videoy > 0) {
for (int i = 0; i < mTagInfoBean.size(); i++) {
IotVideo.RelCoordinateList tag = mTagInfoBean.get(i);
float itemX = Float.parseFloat(tag.getX()) * videoX;
float itemY = Float.parseFloat(tag.getY()) * videoy;
String id = "" + (i + 1);
canvas.drawCircle(itemX, itemY, bgRadius, bgPaint);
canvas.drawCircle(itemX, itemY, innerBgRadius, innerBgPaint);
//根据字符位数 做编号偏移量
float textd = textD_X + (id.length() - 1) * 4;
float textX = itemX - textd;
canvas.drawText(id, textX, itemY + textD_y, textPaint);
}
}
super.onDraw(canvas);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
视频工具类
public class VideoPlayer {
public static float videoScale = 16f / 9f;
private String url;
private MediaPlayer player;
private static volatile VideoPlayer instance;
private TimerTask mTimerTask;
private Handler mMainHandler = new Handler(Looper.getMainLooper());
private OnPlayerStatus status;
private boolean isPrepare;
private int durationTime;
private boolean isPaused;
private ScheduledThreadPoolExecutor executorService;
public static VideoPlayer getInstance() {
if (instance == null) {
synchronized (VideoPlayer.class) {
if (instance == null) {
instance = new VideoPlayer();
}
}
}
return instance;
}
private SoftReference<Context> mContext;
private Context mContextx;
public void init(Context context, String url, SurfaceView mSurfaceView) {
this.url = url;
mContextx = context;
mContext = new SoftReference<>(context);
initPlayer(context, mSurfaceView);
}
public void addPlayerStatus(OnPlayerStatus status) {
this.status = status;
}
private void initPlayer(Context context, SurfaceView mSurfaceView) {
player = new MediaPlayer();
try {
player.setDataSource(context, Uri.parse(url));
} catch (IOException e) {
e.printStackTrace();
// LogUtil.e("player:",e.toString());
status.onError(-1, -1);
}
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
isPrepare = true;
durationTime = mp.getDuration();
mMainHandler.post(new Runnable() {
@Override
public void run() {
status.onPrepare(durationTime);
}
});
}
});
player.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, final int what, int extra) {
isPrepare = false;
mMainHandler.post(new Runnable() {
@Override
public void run() {
status.onError(what, extra);
}
});
return false;
}
});
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
isPrepare = false;
mMainHandler.post(new Runnable() {
@Override
public void run() {
status.onCompletion();
}
});
}
});
player.setOnTimedTextListener(new MediaPlayer.OnTimedTextListener() {
@Override
public void onTimedText(MediaPlayer mp, TimedText text) {
Log.i("tag", "onTimedText");
String time = text.getText().toString();
if (time != null) {
Log.i("TAG", "The time:" + time);
}
}
});
player.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
Log.i("TAG", "The wath:" + what + "extra:" + extra);
return false;
}
});
player.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
if (mSurfaceView != null) {
changeVideoSize(mSurfaceView, width, height);
}
}
});
player.setLooping(true);
player.prepareAsync();
timer();
}
public void changeVideoSize(SurfaceView mSurfaceView, int videoWidth, int videoHeight) {
// float surfaceWidth = DisplayUtil.dip2px(mContextx, 140f);
// float surfaceHeight = surfaceWidth / videoScale;
// //根据视频尺寸去计算->视频可以在sufaceView中放大的最大倍数。
// float max;
// if (mContextx.getResources().getConfiguration().orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
// //竖屏模式下按视频宽度计算放大倍数值
// max = Math.max((float) videoWidth / (float) surfaceWidth, (float) videoHeight / (float) surfaceHeight);
// } else {
// //横屏模式下按视频高度计算放大倍数值
// max = Math.max(((float) videoWidth / (float) surfaceHeight), (float) videoHeight / (float) surfaceWidth);
// }
//视频容器宽度以400像素计算比例
float surfaceWidth = 400f;
float max = (float) videoWidth / (float) surfaceWidth;
//视频宽高分别/最大倍数值 计算出放大后的视频尺寸
videoWidth = (int) Math.ceil((float) videoWidth / max);
videoHeight = (int) Math.ceil((float) videoHeight / max);
//无法直接设置视频尺寸,将计算出的视频尺寸设置到surfaceView 让视频自动填充。
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(videoWidth, videoHeight);
lp.gravity = Gravity.CENTER;
mSurfaceView.setLayoutParams(lp);
}
public boolean isPrepare() {
return isPrepare;
}
private void timer() {
executorService = new ScheduledThreadPoolExecutor(1);
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
mMainHandler.post(new Runnable() {
@Override
public void run() {
if (isPlaying()) {
status.onTime(player.getCurrentPosition());
}
}
});
}
}, 0, 1000, TimeUnit.MILLISECONDS);
}
public boolean isPlaying() {
if (player != null) {
return player.isPlaying();
}
return false;
}
public void startPlayer() {
isPaused = false;
player.start();
}
public void addDisplay(SurfaceHolder holder) {
if (player != null && holder != null && holder.getSurface().isValid()) {
player.setDisplay(holder);
}
}
public void stopPlayer() {
if (player != null && isPlaying()) {
player.stop();
}
}
public int getCurrentPosition() {
if (player != null) {
return player.getCurrentPosition();
}
return 0;
}
public void pausedPlayer() {
if (player != null) {
isPaused = true;
player.pause();
}
}
public boolean isPaused() {
return isPaused;
}
public void seekTo(int time) {
if (player.isPlaying()) {
player.seekTo(time);
}
}
public void onDestory() {
isPaused = false;
if (executorService != null) {
executorService.shutdown();
executorService = null;
}
if (player != null) {
player.stop();
player.release();
player = null;
}
}
/**
* 时间转换
*
* @param timeMs
* @return
*/
public String durationForTime(int timeMs) {
StringBuilder mFormatBuilder = new StringBuilder();
Formatter mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
int totalSeconds = timeMs / 1000;
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
mFormatBuilder.setLength(0);
if (hours > 0) {
return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
} else {
return mFormatter.format("%02d:%02d", minutes, seconds).toString();
}
}
/**
* 播放回调
*/
public interface OnPlayerStatus {
/**
* 文件已load
*
* @param duration 总时长
*/
void onPrepare(int duration);
/**
* 播放已结束
*/
void onCompletion();
/**
* 播放时间
*
* @param time 已播放时间
*/
void onTime(int time);
/**
* 错误提示
*
* @param what
* @param extra
*/
void onError(int what, int extra);
}
}
本文介绍了如何在Android中使用SurfaceView和MediaPlayer实现视频按比例缩放,并添加同比例描点标记。通过获取视频实际宽高,计算SurfaceView与视频的比例,然后自定义标记View来实现这一功能。

2955

被折叠的 条评论
为什么被折叠?



