Android SurfaceView+MediaPlayer视频按比例缩放,视频添加同比例描点标记tag

本文介绍了如何在Android中使用SurfaceView和MediaPlayer实现视频按比例缩放,并添加同比例描点标记。通过获取视频实际宽高,计算SurfaceView与视频的比例,然后自定义标记View来实现这一功能。
视频切换横竖屏参考文章:
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);
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值