|
@@ -0,0 +1,210 @@
|
|
|
|
|
+package com.sheep.gamegroup.view.customview;
|
|
|
|
|
+
|
|
|
|
|
+import android.annotation.SuppressLint;
|
|
|
|
|
+import android.content.Context;
|
|
|
|
|
+import android.support.v7.widget.RecyclerView;
|
|
|
|
|
+import android.util.AttributeSet;
|
|
|
|
|
+import android.view.LayoutInflater;
|
|
|
|
|
+import android.view.MotionEvent;
|
|
|
|
|
+import android.view.View;
|
|
|
|
|
+import android.widget.RelativeLayout;
|
|
|
|
|
+
|
|
|
|
|
+import com.sheep.gamegroup.util.LogUtil;
|
|
|
|
|
+import com.sheep.gamegroup.util.MediaMetadataRetrieverUtil;
|
|
|
|
|
+import com.sheep.jiuyan.samllsheep.R;
|
|
|
|
|
+
|
|
|
|
|
+import java.io.File;
|
|
|
|
|
+import java.util.Locale;
|
|
|
|
|
+
|
|
|
|
|
+import rx.functions.Action1;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Created by realicing on 2018/11/29.
|
|
|
|
|
+ * realicing@sina.com
|
|
|
|
|
+ * 显示本地视频文件对应的视频帧
|
|
|
|
|
+ */
|
|
|
|
|
+public class VideoFramesView extends RelativeLayout {
|
|
|
|
|
+ public VideoFramesView(Context context) {
|
|
|
|
|
+ super(context);
|
|
|
|
|
+ initView();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public VideoFramesView(Context context, AttributeSet attrs) {
|
|
|
|
|
+ super(context, attrs);
|
|
|
|
|
+ initView();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public VideoFramesView(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
|
|
|
+ super(context, attrs, defStyleAttr);
|
|
|
|
|
+ initView();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private RecyclerView recyclerView;
|
|
|
|
|
+ private View line_start;
|
|
|
|
|
+ private View line_end;
|
|
|
|
|
+
|
|
|
|
|
+ private void initView() {
|
|
|
|
|
+ LayoutInflater.from(getContext()).inflate(R.layout.custom_video_frames_view, this, true);
|
|
|
|
|
+ recyclerView = findViewById(R.id.recyclerView);
|
|
|
|
|
+ line_start = findViewById(R.id.line_start);
|
|
|
|
|
+ line_end = findViewById(R.id.line_end);
|
|
|
|
|
+ line_start.setOnTouchListener(new OnTouchListener() {
|
|
|
|
|
+ private float lastEventX;
|
|
|
|
|
+
|
|
|
|
|
+ @SuppressLint("ClickableViewAccessibility")
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public boolean onTouch(View view, MotionEvent event) {
|
|
|
|
|
+ float maxX = line_end.getX();
|
|
|
|
|
+ switch (event.getAction()) {
|
|
|
|
|
+ case MotionEvent.ACTION_DOWN:
|
|
|
|
|
+ lastEventX = event.getX();
|
|
|
|
|
+ break;
|
|
|
|
|
+ case MotionEvent.ACTION_MOVE:
|
|
|
|
|
+ float mx = view.getX() + event.getX() - lastEventX;
|
|
|
|
|
+ if (mx < firstStartX)
|
|
|
|
|
+ mx = firstStartX;
|
|
|
|
|
+ if (mx > maxX)
|
|
|
|
|
+ mx = maxX;
|
|
|
|
|
+ view.setX(mx);
|
|
|
|
|
+ if (onTimeChangeListener != null) {
|
|
|
|
|
+ onTimeChangeListener.call((maxX - mx) / (rvW - lineW));
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ case MotionEvent.ACTION_UP:
|
|
|
|
|
+ break;
|
|
|
|
|
+ case MotionEvent.ACTION_CANCEL:
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ view.invalidate();
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ line_end.setOnTouchListener(new OnTouchListener() {
|
|
|
|
|
+ private float lastEventX;
|
|
|
|
|
+
|
|
|
|
|
+ @SuppressLint("ClickableViewAccessibility")
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public boolean onTouch(View view, MotionEvent event) {
|
|
|
|
|
+ float minX = line_start.getX();
|
|
|
|
|
+ switch (event.getAction()) {
|
|
|
|
|
+ case MotionEvent.ACTION_DOWN:
|
|
|
|
|
+ lastEventX = event.getX();
|
|
|
|
|
+ break;
|
|
|
|
|
+ case MotionEvent.ACTION_MOVE:
|
|
|
|
|
+ float mx = view.getX() + event.getX() - lastEventX;
|
|
|
|
|
+ if (mx < minX)
|
|
|
|
|
+ mx = minX;
|
|
|
|
|
+ if (mx > firstEndX)
|
|
|
|
|
+ mx = firstEndX;
|
|
|
|
|
+ view.setX(mx);
|
|
|
|
|
+ if (onTimeChangeListener != null) {
|
|
|
|
|
+ onTimeChangeListener.call((mx - minX) / (rvW - lineW));
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ case MotionEvent.ACTION_UP:
|
|
|
|
|
+ break;
|
|
|
|
|
+ case MotionEvent.ACTION_CANCEL:
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ view.invalidate();
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //开头线的进度
|
|
|
|
|
+ public float getStartPercent() {
|
|
|
|
|
+ if (line_start != null && recyclerView != null) {
|
|
|
|
|
+ return (line_start.getX() - firstStartX) / (rvW - lineW);
|
|
|
|
|
+ }
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private float firstStartX;//初始时开头的x位置
|
|
|
|
|
+ private float firstEndX;//初始时结尾的x位置
|
|
|
|
|
+ private int lineW;//开头与结尾线的宽度
|
|
|
|
|
+ private int rvW;//图片列表的长度,减去lineW后==总进度的长度
|
|
|
|
|
+
|
|
|
|
|
+ //结尾线的进度
|
|
|
|
|
+ public float getEndPercent() {
|
|
|
|
|
+ if (line_end != null && recyclerView != null) {
|
|
|
|
|
+ return 1.0f - ((firstEndX - line_end.getX()) / (rvW - lineW));
|
|
|
|
|
+ }
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //总的进度
|
|
|
|
|
+ public float getPercent() {
|
|
|
|
|
+ if (line_end != null && recyclerView != null) {
|
|
|
|
|
+ return (line_end.getX() - line_start.getX()) / (rvW - lineW);
|
|
|
|
|
+ }
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public String getLineInfo() {
|
|
|
|
|
+ return String.format(Locale.CHINA, "firstStartX = %f, firstEndX = %f, startX = %f, endX = %f, lineW = %d, rvW = %d, startPercent = %f, endPercent = %f, percent = %f", firstStartX, firstEndX, line_start.getX(), line_end.getX(), line_end.getWidth(), recyclerView.getWidth(), getStartPercent(), getEndPercent(), getPercent());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private MediaMetadataRetrieverUtil mediaMetadataRetrieverUtil;
|
|
|
|
|
+
|
|
|
|
|
+ public MediaMetadataRetrieverUtil getMediaMetadataRetrieverUtil() {
|
|
|
|
|
+ return mediaMetadataRetrieverUtil;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 显示视频帧图片列表
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param videoPath 视频文件路径
|
|
|
|
|
+ * @param duration 视频文件时长
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public VideoFramesView initVideo(String videoPath, long duration) {
|
|
|
|
|
+ if (videoPath == null) {
|
|
|
|
|
+ LogUtil.println(VideoFramesView.class.getSimpleName(), "showList", "error", "videoPath is null");
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+ File videoFile = new File(videoPath);
|
|
|
|
|
+ if (!videoFile.exists()) {
|
|
|
|
|
+ LogUtil.println(VideoFramesView.class.getSimpleName(), "showList", "error", "videoFile not exists");
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!videoFile.canRead()) {
|
|
|
|
|
+ LogUtil.println(VideoFramesView.class.getSimpleName(), "showList", "error", "videoFile cant read");
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (duration < 1) {
|
|
|
|
|
+ LogUtil.println(VideoFramesView.class.getSimpleName(), "showList", "error", "duration < 1");
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (mediaMetadataRetrieverUtil == null) {
|
|
|
|
|
+ mediaMetadataRetrieverUtil = new MediaMetadataRetrieverUtil(videoPath, duration);
|
|
|
|
|
+ }
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 显示视频帧图片列表
|
|
|
|
|
+ */
|
|
|
|
|
+ public VideoFramesView showVideoList() {
|
|
|
|
|
+ if (mediaMetadataRetrieverUtil != null)
|
|
|
|
|
+ mediaMetadataRetrieverUtil.initRv(recyclerView);
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Action1<Float> onTimeChangeListener;
|
|
|
|
|
+
|
|
|
|
|
+ public void setOnTimeChangeListener(Action1<Float> action1) {
|
|
|
|
|
+ onTimeChangeListener = action1;
|
|
|
|
|
+ postDelayed(new Runnable() {
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void run() {
|
|
|
|
|
+ firstStartX = line_start.getX();
|
|
|
|
|
+ firstEndX = line_end.getX();
|
|
|
|
|
+ lineW = line_start.getWidth();
|
|
|
|
|
+ rvW = recyclerView.getWidth();
|
|
|
|
|
+ onTimeChangeListener.call(1.0f);
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 100);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|