Browse Source

处理作品视频选帧问题

Pq 4 months ago
parent
commit
5c1642c179

+ 1 - 0
musicMerge/build.gradle

@@ -66,4 +66,5 @@ dependencies {
     annotationProcessor("com.alibaba:arouter-compiler:$rootProject.ext.android.arouter_api_version")
     implementation 'com.alibaba:arouter-api:1.5.2'
     kapt 'com.alibaba:arouter-compiler:1.5.2'
+    implementation 'com.google.android.exoplayer:exoplayer:2.15.0'
 }

+ 1 - 1
musicMerge/src/main/java/com/cooleshow/musicmerge/manager/ICoverSelector.java

@@ -16,7 +16,7 @@ public interface ICoverSelector {
     }
 
     interface OnSliderMoveListener {
-        void onSliderMove(long startTime, int type, int moveX);
+        void onSliderMove(long startTime, float type, int moveX);
     }
 
 }

+ 10 - 5
musicMerge/src/main/java/com/cooleshow/musicmerge/ui/MusicHandleActivity_.java

@@ -722,11 +722,16 @@ public class MusicHandleActivity_ extends BaseMVPActivity<AcMusicHandleLayoutBin
 
             @Override
             public void onPrepare(long totalDuration) {
-                audioPlayDuration = totalDuration;
-                setDurationText();
-                if (isVideo) {
-                    toRealPlayVideo();
-                }
+                runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        audioPlayDuration = totalDuration;
+                        setDurationText();
+                        if (isVideo) {
+                            toRealPlayVideo();
+                        }
+                    }
+                });
             }
 
             @Override

+ 9 - 2
musicMerge/src/main/java/com/cooleshow/musicmerge/widget/cover/CoverSliderView.java

@@ -41,6 +41,7 @@ public class CoverSliderView extends RelativeLayout implements RangeSlider.OnRan
     private ICoverSelector.OnSliderMoveListener mSliderMoveListener;
     private int position;
     private float mViewRate;
+    private int max_tick_count= 100;
 
     public CoverSliderView(Context context) {
         super(context);
@@ -65,6 +66,7 @@ public class CoverSliderView extends RelativeLayout implements RangeSlider.OnRan
         inflate(getContext(), R.layout.item_sv_cover_view, this);
 
         mRangeSlider = (RangeSlider) findViewById(R.id.range_slider);
+        mRangeSlider.setTickCount(max_tick_count);
         mRangeSlider.setRangeChangeListener(this);
 
         LinearLayoutManager manager = new LinearLayoutManager(mContext);
@@ -133,8 +135,8 @@ public class CoverSliderView extends RelativeLayout implements RangeSlider.OnRan
 
 
     @Override
-    public void onKeyMove(int type, int leftPinIndex, int moveX) {
-        mSelectTime = (int) (mViewMaxDuration * leftPinIndex * mViewRate / 100); //ms
+    public void onKeyMove(int type, float leftPinIndex, int moveX) {
+        mSelectTime = (int) (mViewMaxDuration * leftPinIndex * mViewRate / max_tick_count); //ms
         onTimeChangedMove(moveX);
     }
 
@@ -224,4 +226,9 @@ public class CoverSliderView extends RelativeLayout implements RangeSlider.OnRan
         return mCurrentScroll;
     }
 
+    public void release() {
+        if (mRangeSlider != null) {
+            mRangeSlider.release();
+        }
+    }
 }

+ 122 - 0
musicMerge/src/main/java/com/cooleshow/musicmerge/widget/cover/MyExoPlayer.java

@@ -0,0 +1,122 @@
+package com.cooleshow.musicmerge.widget.cover;
+
+import com.cooleshow.base.utils.LOG;
+import com.cooleshow.base.utils.Utils;
+import com.google.android.exoplayer2.MediaItem;
+import com.google.android.exoplayer2.Player;
+import com.google.android.exoplayer2.SeekParameters;
+import com.google.android.exoplayer2.SimpleExoPlayer;
+import com.google.android.exoplayer2.ui.PlayerView;
+import com.google.android.exoplayer2.video.VideoSize;
+
+/**
+ * Author by pq, Date on 2024/9/24.
+ * 特殊的exoplayer,只prepare,不调用start,初始原因是因为MediaPlayer无法快进到准确帧,所以更换成exoPlayer
+ */
+public class MyExoPlayer {
+    public static final String TAG = "MyExoPlayer";
+    private SimpleExoPlayer mSimpleExoPlayer;
+    private OnStateChangeListener mListener;
+    private int mState = Player.STATE_IDLE;
+    private boolean isSeeking = false;
+
+    public MyExoPlayer() {
+        init();
+    }
+
+    private void init() {
+        mSimpleExoPlayer = new SimpleExoPlayer.Builder(Utils.getApp())
+                .setSeekParameters(SeekParameters.EXACT)
+                .setSeekForwardIncrementMs(3000)
+                .build();
+        mSimpleExoPlayer.addListener(new Player.Listener() {
+            @Override
+            public void onPlaybackStateChanged(int playbackState) {
+                if (playbackState == Player.STATE_READY) {
+                    isSeeking = false;
+                    if (mState != Player.STATE_READY) {
+                        mState = Player.STATE_READY;
+                        if (mListener != null) {
+                            mListener.onPrepared();
+                        }
+                    }
+                }
+            }
+        });
+
+    }
+
+    public void setPlayerView(PlayerView playerView) {
+        if (playerView != null) {
+            playerView.setPlayer(mSimpleExoPlayer);
+        }
+    }
+
+    public void setDataSource(String url) {
+        // 设置媒体源
+        MediaItem mediaItem = MediaItem.fromUri(url);
+        mSimpleExoPlayer.setMediaItem(mediaItem);
+    }
+
+    public void prepare() {
+        mSimpleExoPlayer.prepare();
+    }
+
+    public boolean isSeeking() {
+        return isSeeking;
+    }
+
+    public void seekTo(long startTime) {
+        if (isSeeking) {
+            return;
+        }
+        LOG.i(TAG, "seekTo:" + startTime);
+        mSimpleExoPlayer.seekTo(startTime);
+        isSeeking = true;
+    }
+
+    public void reset() {
+        mState = Player.STATE_IDLE;
+    }
+
+    public void setOnStateChangeListener(OnStateChangeListener listener) {
+        mListener = listener;
+    }
+
+    public long getDuration() {
+        long duration = mSimpleExoPlayer.getDuration();
+        return duration;
+    }
+
+    public int getVideoWidth() {
+        VideoSize videoSize = mSimpleExoPlayer.getVideoSize();
+        return videoSize != null ? videoSize.width : 0;
+    }
+
+    public int getVideoHeight() {
+        VideoSize videoSize = mSimpleExoPlayer.getVideoSize();
+        return videoSize != null ? videoSize.height : 0;
+    }
+
+    public void release() {
+        if (mSimpleExoPlayer != null) {
+            mSimpleExoPlayer.release();
+        }
+    }
+
+    public interface OnStateChangeListener {
+        void onPrepared();
+
+        void onReset();
+
+        void onRenderingStart();
+
+        void onProgressUpdate(float per);
+
+        void onPause();
+
+        void onStop();
+
+        void onComplete();
+    }
+}

+ 35 - 15
musicMerge/src/main/java/com/cooleshow/musicmerge/widget/cover/RangeSlider.java

@@ -9,15 +9,17 @@ import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.Gravity;
+import android.view.LayoutInflater;
 import android.view.MotionEvent;
-import android.view.TextureView;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import com.cooleshow.base.utils.LOG;
 import com.cooleshow.musicmerge.R;
 import com.cooleshow.musicmerge.constants.MusicMergeConfig;
+import com.google.android.exoplayer2.ui.PlayerView;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -35,8 +37,8 @@ public class RangeSlider extends ViewGroup {
     @NonNull
     private final ThumbView mThumb;
     private final Paint mBgPaint;
-    private final VideoPlayer videoPlayer;
-    private final TextureView textureView;
+    private final MyExoPlayer videoPlayer;
+    private final PlayerView textureView;
     @Nullable
     private Drawable mIcon;
 
@@ -83,12 +85,12 @@ public class RangeSlider extends ViewGroup {
         setRangeIndex(array.getInteger(R.styleable.RangeSlider_leftThumbIndex, DEFAULT_TICK_START),
                 array.getInteger(R.styleable.RangeSlider_rightThumbIndex, mTickCount));
         array.recycle();
-        videoPlayer = new VideoPlayer();
+        videoPlayer = new MyExoPlayer();
         View borderView = new View(getContext());
         borderView.setBackground(mIcon);
-        textureView = new TextureView(getContext());
-        textureView.setVisibility(VISIBLE);
-        videoPlayer.setTextureView(textureView);
+
+        textureView = (PlayerView) LayoutInflater.from(getContext()).inflate(R.layout.video_default_playerveiew, null);
+        videoPlayer.setPlayerView(textureView);
 
         int videoWith = (int) (mThumbWidth * percent);
         int videoHeight = (int) (MusicMergeConfig.getHeightAtRatio16_9(mThumbWidth) * percent);
@@ -227,11 +229,11 @@ public class RangeSlider extends ViewGroup {
         return getRangeLength() / mTickCount;
     }
 
-    public int getNearestIndex(float x) {
-        return Math.round(x / getIntervalLength());
+    public float getNearestIndex(float x) {
+        return x / getIntervalLength();
     }
 
-    public int getLeftIndex() {
+    public float getLeftIndex() {
         return mThumb.getRangeIndex();
     }
 
@@ -282,7 +284,7 @@ public class RangeSlider extends ViewGroup {
         }
     }
 
-    private boolean moveThumbByIndex(@NonNull ThumbView view, int index) {
+    private boolean moveThumbByIndex(@NonNull ThumbView view, float index) {
         view.setX(index * getIntervalLength());
         if (view.getRangeIndex() != index) {
             view.setTickIndex(index);
@@ -293,13 +295,21 @@ public class RangeSlider extends ViewGroup {
 
     private void moveLeftThumbByPixel(int pixel) {
         float x = mThumb.getX() + pixel;
+        if (x < 0) {
+            x = 0;
+        }
+        LOG.i("RangeSlider", "getWidth():" + getWidth());
+        LOG.i("RangeSlider", "mThumb getWidth():" + mThumb.getWidth());
+        if (x > getWidth() - mThumb.getWidth()) {
+            x = getWidth() - mThumb.getWidth();
+        }
         float interval = getIntervalLength();
         float start = mTickStart / mTickInterval * interval;
         float end = mTickEnd / mTickInterval * interval;
 
-        if (x > start && x < end) {
+        if (x >= start && x <= end) {
             mThumb.setX(x);
-            int index = getNearestIndex(x);
+            float index = getNearestIndex(x);
             if (mThumb.getRangeIndex() != index) {
                 mThumb.setTickIndex(index);
                 notifyRangeChange(TYPE_LEFT);
@@ -317,7 +327,7 @@ public class RangeSlider extends ViewGroup {
 
     public void playVideo(final String videoUrl) {
         videoPlayer.reset();
-        videoPlayer.setOnStateChangeListener(new VideoPlayer.OnStateChangeListener() {
+        videoPlayer.setOnStateChangeListener(new MyExoPlayer.OnStateChangeListener() {
             @Override
             public void onPrepared() {
                 videoPlayer.seekTo(mStartTime);
@@ -360,10 +370,20 @@ public class RangeSlider extends ViewGroup {
         videoPlayer.seekTo(startTime);
     }
 
+    public boolean isSeeking() {
+        return videoPlayer.isSeeking();
+    }
+
+    public void release() {
+        if (videoPlayer != null) {
+            videoPlayer.release();
+        }
+    }
+
     public interface OnRangeChangeListener {
         void onKeyDown(int type);
 
-        void onKeyMove(int typeLeft, int rangeIndex, int moveX);
+        void onKeyMove(int typeLeft, float rangeIndex, int moveX);
     }
 
 }

+ 41 - 24
musicMerge/src/main/java/com/cooleshow/musicmerge/widget/cover/ShortVideoSelectCover.java

@@ -3,9 +3,10 @@ package com.cooleshow.musicmerge.widget.cover;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.Gravity;
+import android.view.LayoutInflater;
 import android.view.TextureView;
+import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.RelativeLayout;
@@ -17,6 +18,7 @@ import com.cooleshow.musicmerge.R;
 import com.cooleshow.musicmerge.bean.VideoInfo;
 import com.cooleshow.musicmerge.manager.CoverSelectorManager;
 import com.cooleshow.musicmerge.manager.ICoverSelector;
+import com.google.android.exoplayer2.ui.PlayerView;
 
 
 public class ShortVideoSelectCover extends RelativeLayout {
@@ -25,8 +27,8 @@ public class ShortVideoSelectCover extends RelativeLayout {
     private ImageView mImgCover;
     private String mVideoPath = "";
     private long mStartTime;
-    private VideoPlayer videoPlayer;
-    private TextureView textureView;
+    private MyExoPlayer videoPlayer;
+    private PlayerView textureView;
     private FrameLayout flVideo;
     private VideoInfo mVideoInfo;
     private CoverSelectorManager mCoverSelectorManager;
@@ -49,9 +51,9 @@ public class ShortVideoSelectCover extends RelativeLayout {
     private void initViews() {
         inflate(getContext(), R.layout.video_selector_layout, this);
         mCoverSelectorManager = new CoverSelectorManager();
-        videoPlayer = new VideoPlayer();
-        textureView = new TextureView(getContext());
-        videoPlayer.setTextureView(textureView);
+        videoPlayer = new MyExoPlayer();
+        textureView = (PlayerView) LayoutInflater.from(getContext()).inflate(R.layout.video_default_playerveiew, null);
+        videoPlayer.setPlayerView(textureView);
         flVideo = findViewById(R.id.flVideo);
         flVideo.addView(textureView);
         mVideoCutLayout = findViewById(R.id.video_cut_layout);
@@ -64,7 +66,7 @@ public class ShortVideoSelectCover extends RelativeLayout {
         mVideoInfo.videoPath = mVideoPath;
         playVideo(mVideoPath);
         mVideoCutLayout.getRangeSlider().playVideo(mVideoPath);
-        Log.i("pq", "mVideoPath:" + mVideoPath);
+        LOG.i("pq", "mVideoPath:" + mVideoPath);
     }
 
     private void loadVideoInfo(VideoInfo videoInfo) {
@@ -74,16 +76,18 @@ public class ShortVideoSelectCover extends RelativeLayout {
         mVideoCutLayout.setSliderMoveListener(new ICoverSelector.OnSliderMoveListener() {
 
             @Override
-            public void onSliderMove(long startTime, int type, int moveX) {
-                LOG.i("onSliderMove type:" + type + " moveX:" + moveX);
+            public void onSliderMove(long startTime, float type, int moveX) {
+                LOG.i("onSliderMove startTime" + startTime + " type:" + type + " moveX:" + moveX);
                 mStartTime = startTime;
-                videoPlayer.seekTo(startTime);
-                mVideoCutLayout.getRangeSlider().seekTo(startTime);
-                mImgCover.setVisibility(GONE);
-                if (type > 80 && moveX > 0) {
-                    mVideoCutLayout.startScrollBy(SizeUtils.dp2px(150));
-                } else if (type < 20 && moveX < 0) {
-                    mVideoCutLayout.startScrollBy(-SizeUtils.dp2px(150));
+                if (!videoPlayer.isSeeking() && !mVideoCutLayout.getRangeSlider().isSeeking()) {
+                    videoPlayer.seekTo(startTime);
+                    mVideoCutLayout.getRangeSlider().seekTo(startTime);
+                    mImgCover.setVisibility(GONE);
+                    if (type > 80 && moveX > 0) {
+                        mVideoCutLayout.startScrollBy(SizeUtils.dp2px(150));
+                    } else if (type < 20 && moveX < 0) {
+                        mVideoCutLayout.startScrollBy(-SizeUtils.dp2px(150));
+                    }
                 }
             }
         });
@@ -153,25 +157,35 @@ public class ShortVideoSelectCover extends RelativeLayout {
         if (onGetSampleImageListener != null) {
             onGetSampleImageListener.start();
         }
-        mCoverSelectorManager.setOnFrameAtTimeListener(new ICoverSelector.OnFrameAtTimeListener() {
-            @Override
-            public void onFrameAtTime(Bitmap bitmap) {
-                if (onGetSampleImageListener != null) {
+        if (textureView != null) {
+            if (onGetSampleImageListener != null) {
+                View videoSurfaceView = textureView.getVideoSurfaceView();
+                TextureView textureView1 = (TextureView) videoSurfaceView;
+                if (textureView1 != null) {
+                    Bitmap bitmap = textureView1.getBitmap();
                     onGetSampleImageListener.complete(bitmap);
                 }
             }
-        });
-        mCoverSelectorManager.getFrameAtTime2(mStartTime);
+        }
+//        mCoverSelectorManager.setOnFrameAtTimeListener(new ICoverSelector.OnFrameAtTimeListener() {
+//            @Override
+//            public void onFrameAtTime(Bitmap bitmap) {
+//                if (onGetSampleImageListener != null) {
+//                    onGetSampleImageListener.complete(bitmap);
+//                }
+//            }
+//        });
+//        mCoverSelectorManager.getFrameAtTime2(mStartTime);
     }
 
     private void playVideo(final String videoUrl) {
         videoPlayer.reset();
-        videoPlayer.setOnStateChangeListener(new VideoPlayer.OnStateChangeListener() {
+        videoPlayer.setOnStateChangeListener(new MyExoPlayer.OnStateChangeListener() {
             @Override
             public void onPrepared() {
                 mComplete = false;
                 videoPlayer.seekTo(0);
-                int duration = videoPlayer.getDuration();
+                long duration = videoPlayer.getDuration();
                 LOG.i("duration :" + duration);
                 mVideoInfo.duration = duration;
                 mVideoInfo.setVideoWidth(videoPlayer.getVideoWidth());
@@ -223,6 +237,9 @@ public class ShortVideoSelectCover extends RelativeLayout {
         if (mCoverSelectorManager != null) {
             mCoverSelectorManager.release();
         }
+        if (mVideoCutLayout != null) {
+            mVideoCutLayout.release();
+        }
         if (videoPlayer != null) {
             videoPlayer.release();
         }

+ 6 - 3
musicMerge/src/main/java/com/cooleshow/musicmerge/widget/cover/ThumbView.java

@@ -4,6 +4,8 @@ import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.widget.FrameLayout;
 
+import com.cooleshow.base.utils.LOG;
+
 import androidx.annotation.NonNull;
 
 public class ThumbView extends FrameLayout {
@@ -15,7 +17,7 @@ public class ThumbView extends FrameLayout {
     private boolean mPressed;
 
     private int mThumbWidth;
-    private int mTickIndex;
+    private float mTickIndex;
 
     public ThumbView(@NonNull Context context, int thumbWidth, Drawable drawable) {
         super(context);
@@ -35,11 +37,12 @@ public class ThumbView extends FrameLayout {
         mThumbWidth = thumbWidth;
     }
 
-    public int getRangeIndex() {
+    public float getRangeIndex() {
         return mTickIndex;
     }
 
-    public void setTickIndex(int tickIndex) {
+    public void setTickIndex(float tickIndex) {
+        LOG.i("RangeSlider","setTickIndex:"+tickIndex);
         mTickIndex = tickIndex;
     }
 

+ 5 - 1
musicMerge/src/main/java/com/cooleshow/musicmerge/widget/cover/VideoPlayer.java

@@ -8,12 +8,15 @@ import android.util.Log;
 import android.view.Surface;
 import android.view.TextureView;
 
+import com.cooleshow.base.utils.LOG;
+
 import java.io.IOException;
 
 /**
  * Video Player
  */
 public class VideoPlayer {
+    public static final String TAG  = "VideoPlayer";
     private MediaPlayer mediaPlayer;
     private State state = State.IDLE;
     private OnStateChangeListener onStateChangeListener;
@@ -142,8 +145,9 @@ public class VideoPlayer {
     }
 
     public void seekTo(long startTime) {
+        LOG.i(TAG,"seekTo:"+startTime);
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            mediaPlayer.seekTo(startTime, MediaPlayer.SEEK_CLOSEST);
+            mediaPlayer.seekTo(startTime, MediaPlayer.SEEK_CLOSEST_SYNC);
         } else {
             mediaPlayer.seekTo((int) (startTime / 1000));
         }

+ 10 - 0
musicMerge/src/main/res/layout/video_default_playerveiew.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.google.android.exoplayer2.ui.PlayerView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:surface_type="texture_view"
+    android:id="@+id/player_view"
+    app:use_controller="false"
+    android:layout_height="match_parent">
+
+</com.google.android.exoplayer2.ui.PlayerView>

+ 12 - 11
musicMerge/src/main/res/layout/video_selector_layout.xml

@@ -1,41 +1,42 @@
 <?xml version="1.0" encoding="utf-8"?>
 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:background="@color/black"
     android:orientation="vertical">
 
     <FrameLayout
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_weight="1">
+        android:layout_weight="1"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent">
 
         <FrameLayout
             android:id="@+id/flVideo"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:keepScreenOn="true" />
+            android:keepScreenOn="true"/>
 
         <ImageView
             android:id="@+id/img_cover"
             android:layout_width="match_parent"
+            android:layout_height="match_parent"
             android:scaleType="centerCrop"
-            android:visibility="gone"
-            android:layout_height="match_parent" />
+            android:visibility="gone" />
 
     </FrameLayout>
 
 
     <com.cooleshow.musicmerge.widget.cover.CoverSliderView
         android:id="@+id/video_cut_layout"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent"
         android:layout_width="0dp"
         android:layout_height="87dp"
-        android:layout_gravity="center_horizontal" />
+        android:layout_gravity="center_horizontal"
+        android:layout_marginBottom="32dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>