Просмотр исходного кода

剪切视频功能完成;
显示视频瀑布流优化

zengjiebin лет назад: 7
Родитель
Сommit
2b27b3a348
22 измененных файлов с 806 добавлено и 131 удалено
  1. 1 1
      RxGalleryFinal/src/main/java/cn/finalteam/rxgalleryfinal/ui/adapter/MediaGridAdapter.java
  2. 3 0
      app/src/main/java/com/sheep/gamegroup/absBase/ApiRefresh.java
  3. 9 0
      app/src/main/java/com/sheep/gamegroup/absBase/BaseActivity.java
  4. 57 0
      app/src/main/java/com/sheep/gamegroup/model/entity/Video.java
  5. 4 5
      app/src/main/java/com/sheep/gamegroup/util/Jump2View.java
  6. 359 0
      app/src/main/java/com/sheep/gamegroup/util/MediaHandleUtil.java
  7. 37 19
      app/src/main/java/com/sheep/gamegroup/util/MediaMetadataRetrieverUtil.java
  8. 20 0
      app/src/main/java/com/sheep/gamegroup/util/ViewUtil.java
  9. 82 34
      app/src/main/java/com/sheep/gamegroup/view/activity/ActEditVideo.java
  10. 2 1
      app/src/main/java/com/sheep/gamegroup/view/activity/ActPlayVideo.java
  11. 7 1
      app/src/main/java/com/sheep/gamegroup/view/activity/ActPlayVideoArticle.java
  12. 56 38
      app/src/main/java/com/sheep/gamegroup/view/activity/ActPublishArticle.java
  13. 6 1
      app/src/main/java/com/sheep/gamegroup/view/adapter/AdpVideo.java
  14. 77 19
      app/src/main/java/com/sheep/gamegroup/view/customview/VideoFramesView.java
  15. 8 1
      app/src/main/java/com/sheep/gamegroup/view/fragment/BaseListFragment.java
  16. 18 1
      app/src/main/java/com/sheep/gamegroup/view/fragment/BaseListFragment2.java
  17. 8 1
      app/src/main/java/com/sheep/gamegroup/view/fragment/BaseListFragment3.java
  18. 8 1
      app/src/main/java/com/sheep/gamegroup/view/fragment/BaseListFragment4.java
  19. 8 1
      app/src/main/java/com/sheep/gamegroup/view/fragment/BaseListFragment5.java
  20. 0 1
      app/src/main/java/com/sheep/gamegroup/view/fragment/FgtArticleVideo.java
  21. 2 6
      app/src/main/java/com/sheep/gamegroup/view/fragment/FgtDiscoveryTopic.java
  22. 34 0
      app/src/main/java/com/sheep/jiuyan/samllsheep/base/BaseFragment.java

+ 1 - 1
RxGalleryFinal/src/main/java/cn/finalteam/rxgalleryfinal/ui/adapter/MediaGridAdapter.java

@@ -109,7 +109,7 @@ public class MediaGridAdapter extends RecyclerView.Adapter<MediaGridAdapter.Grid
                 holder.tv_media_duration.setVisibility(View.VISIBLE);
                 holder.tv_media_duration.setVisibility(View.VISIBLE);
                 long second = mediaBean.getDuration() / 1000;
                 long second = mediaBean.getDuration() / 1000;
                 long m = second / 60;
                 long m = second / 60;
-                holder.tv_media_duration.setText(String.format(Locale.CHINA, "%d:%d", m, second % 60));
+                holder.tv_media_duration.setText(String.format(Locale.CHINA, "%d:%02d", m, second % 60));
             } else {
             } else {
                 holder.tv_media_duration.setVisibility(View.GONE);
                 holder.tv_media_duration.setVisibility(View.GONE);
                 holder.mCbCheck.setVisibility(View.VISIBLE);
                 holder.mCbCheck.setVisibility(View.VISIBLE);

+ 3 - 0
app/src/main/java/com/sheep/gamegroup/absBase/ApiRefresh.java

@@ -67,6 +67,9 @@ public abstract class ApiRefresh<T> {
 
 
     //还有数据没有获取
     //还有数据没有获取
     protected boolean hasMore() {
     protected boolean hasMore() {
+        if(lastMessage != null && lastMessage.getTotal() > 0){
+            return lastMessage.getTotal() > ListUtil.size(list);
+        }
         return ListUtil.size(list) >= per_page * page;
         return ListUtil.size(list) >= per_page * page;
     }
     }
 
 

+ 9 - 0
app/src/main/java/com/sheep/gamegroup/absBase/BaseActivity.java

@@ -7,6 +7,8 @@ import com.sheep.gamegroup.util.ActionUtil;
 import com.sheep.gamegroup.view.dialog.DialogLoading;
 import com.sheep.gamegroup.view.dialog.DialogLoading;
 import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;
 import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;
 
 
+import org.greenrobot.eventbus.EventBus;
+
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeUnit;
 
 
 import butterknife.ButterKnife;
 import butterknife.ButterKnife;
@@ -23,6 +25,9 @@ public abstract class BaseActivity extends RxAppCompatActivity {
 
 
     protected DialogLoading dialogLoading;
     protected DialogLoading dialogLoading;
     public Unbinder unbinder;
     public Unbinder unbinder;
+    protected boolean needRegisterEventBus(){
+        return false;
+    }
     protected boolean needButterKnife(){
     protected boolean needButterKnife(){
         return true;
         return true;
     }
     }
@@ -32,6 +37,8 @@ public abstract class BaseActivity extends RxAppCompatActivity {
         setContentView(getLayoutId());
         setContentView(getLayoutId());
         if(needButterKnife())
         if(needButterKnife())
             unbinder = ButterKnife.bind(this);
             unbinder = ButterKnife.bind(this);
+        if(needRegisterEventBus())
+            EventBus.getDefault().register(this);
         initView();
         initView();
         initListener();
         initListener();
         initData();
         initData();
@@ -111,5 +118,7 @@ public abstract class BaseActivity extends RxAppCompatActivity {
         } catch (Exception e) {
         } catch (Exception e) {
             e.printStackTrace();
             e.printStackTrace();
         }
         }
+        if(needRegisterEventBus())
+            EventBus.getDefault().unregister(this);
     }
     }
 }
 }

+ 57 - 0
app/src/main/java/com/sheep/gamegroup/model/entity/Video.java

@@ -0,0 +1,57 @@
+package com.sheep.gamegroup.model.entity;
+
+import java.io.Serializable;
+
+/**
+ * Created by realicing on 2018/11/30.
+ * realicing@sina.com
+ * 视频数据
+ */
+public class Video implements Serializable {
+
+    private int width;//视频宽
+    private int height;//视频高
+    private long duration;//视频长度,单位毫秒
+    private String filePath;//文件对应地址
+    private int topicId;//选择的话题的id
+
+    public String getFilePath() {
+        return filePath;
+    }
+
+    public void setFilePath(String filePath) {
+        this.filePath = filePath;
+    }
+
+    public int getWidth() {
+        return width;
+    }
+
+    public void setWidth(int width) {
+        this.width = width;
+    }
+
+    public int getHeight() {
+        return height;
+    }
+
+    public void setHeight(int height) {
+        this.height = height;
+    }
+
+    public long getDuration() {
+        return duration;
+    }
+
+    public void setDuration(long duration) {
+        this.duration = duration;
+    }
+
+    public int getTopicId() {
+        return topicId;
+    }
+
+    public void setTopicId(int topicId) {
+        this.topicId = topicId;
+    }
+}

+ 4 - 5
app/src/main/java/com/sheep/gamegroup/util/Jump2View.java

@@ -28,7 +28,6 @@ import com.sheep.gamegroup.model.entity.Container;
 import com.sheep.gamegroup.model.entity.CreditCard;
 import com.sheep.gamegroup.model.entity.CreditCard;
 import com.sheep.gamegroup.model.entity.DialogConfig;
 import com.sheep.gamegroup.model.entity.DialogConfig;
 import com.sheep.gamegroup.model.entity.DialogEntity;
 import com.sheep.gamegroup.model.entity.DialogEntity;
-import com.sheep.gamegroup.model.entity.DiscoveryVideo;
 import com.sheep.gamegroup.model.entity.GameListTag;
 import com.sheep.gamegroup.model.entity.GameListTag;
 import com.sheep.gamegroup.model.entity.GameListType;
 import com.sheep.gamegroup.model.entity.GameListType;
 import com.sheep.gamegroup.model.entity.HomeListEntity;
 import com.sheep.gamegroup.model.entity.HomeListEntity;
@@ -41,6 +40,7 @@ import com.sheep.gamegroup.model.entity.TaskAcceptedEty;
 import com.sheep.gamegroup.model.entity.TaskEty;
 import com.sheep.gamegroup.model.entity.TaskEty;
 import com.sheep.gamegroup.model.entity.UserEntity;
 import com.sheep.gamegroup.model.entity.UserEntity;
 import com.sheep.gamegroup.model.entity.VersionInfo;
 import com.sheep.gamegroup.model.entity.VersionInfo;
+import com.sheep.gamegroup.model.entity.Video;
 import com.sheep.gamegroup.model.entity.WebviewEntity;
 import com.sheep.gamegroup.model.entity.WebviewEntity;
 import com.sheep.gamegroup.model.entity.XianWanEntity;
 import com.sheep.gamegroup.model.entity.XianWanEntity;
 import com.sheep.gamegroup.model.util.SheepSubscriber;
 import com.sheep.gamegroup.model.util.SheepSubscriber;
@@ -2261,13 +2261,12 @@ public class Jump2View {
     /**
     /**
      * 编辑视频
      * 编辑视频
      *
      *
-     * @param url 播放地址
+     * @param data 视频数据,包括地址与时长,宽高等
      */
      */
-    public void goActEditVideo(String url, long duration) {
+    public void goActEditVideo(Video data) {
         Activity activity = ActivityManager.getInstance().currentActivity();
         Activity activity = ActivityManager.getInstance().currentActivity();
         Intent intent = new Intent(activity, ActEditVideo.class);
         Intent intent = new Intent(activity, ActEditVideo.class);
-        DataUtil.putObject(intent, url);
-        DataUtil.putObject(intent, duration);
+        DataUtil.putObject(intent, data);
         activity.startActivity(intent);
         activity.startActivity(intent);
     }
     }
 
 

+ 359 - 0
app/src/main/java/com/sheep/gamegroup/util/MediaHandleUtil.java

@@ -0,0 +1,359 @@
+package com.sheep.gamegroup.util;
+
+import android.media.MediaCodec;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+import android.util.Log;
+
+import com.sheep.gamegroup.absBase.AbsObserver;
+import com.sheep.gamegroup.model.entity.Video;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.util.Locale;
+
+import io.reactivex.Observable;
+import io.reactivex.ObservableEmitter;
+import io.reactivex.ObservableOnSubscribe;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * Created by realicing on 2018/11/30.
+ * realicing@sina.com
+ */
+public class MediaHandleUtil {
+    public static final String TAG = "MediaHandleUtil";
+    private String url;
+    private long clipPoint;
+    private long clipDuration;
+
+    public MediaHandleUtil(String url, long clipPoint, long clipDuration) {
+        this.url = url;
+        this.clipPoint = clipPoint;
+        this.clipDuration = clipDuration;
+    }
+
+    public void tryCutVideo(AbsObserver<Video> absObserver) {
+        Observable.create(new ObservableOnSubscribe<Video>() {
+            @Override
+            public void subscribe(ObservableEmitter<Video> emitter) throws Exception {
+                long time = System.currentTimeMillis();
+                Video video = cutVideo(url, clipPoint, clipDuration);
+                if (video == null) {
+                    emitter.onError(new Throwable("剪切失败"));
+                } else {
+                    emitter.onNext(video);
+                }
+                long curTime = System.currentTimeMillis();
+                LogUtil.println(TAG, time, curTime, curTime - time, (curTime - time) / 1000);
+            }
+        })
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(absObserver);
+    }
+
+    /**
+     * 获取可以剪切出的视频的地址
+     *
+     * @param url          源文本地址
+     * @param clipPoint    开始位置
+     * @param clipDuration 要剪切的长度
+     * @return 返回可以剪切出来的文件的地址
+     */
+    public static String getCutVideoFilePath(String url, long clipPoint, long clipDuration) {
+        if (clipPoint < 0) {
+            Log.e(TAG, "clipPoint is error! but reset clipPoint " + clipPoint + "0 ");
+            clipPoint = 0;
+        }
+        return String.format(Locale.CHINA, "%s_%d_%d.%s", url.substring(0, url.lastIndexOf(".")), clipPoint, clipDuration, FileUtil.getExtensionName(url));
+    }
+
+    /**
+     * 剪切视频
+     *
+     * @param url          源文本地址
+     * @param clipPoint    开始位置
+     * @param clipDuration 要剪切的长度
+     * @return 返回剪切出来的文件的地址
+     */
+    public static Video cutVideo(String url, long clipPoint, long clipDuration) {
+        Video video = new Video();
+        if (clipPoint < 0) {
+            Log.e(TAG, "clipPoint is error! but reset clipPoint " + clipPoint + "0 ");
+            clipPoint = 0;
+        }
+        LogUtil.println(TAG, url, clipPoint, clipDuration);
+        String outFilePath = getCutVideoFilePath(url, clipPoint, clipDuration);
+        video.setFilePath(outFilePath);
+        int videoTrackIndex = -1;
+        int audioTrackIndex = -1;
+        int videoMaxInputSize = 0;
+        int audioMaxInputSize = 0;
+        int sourceVTrack = 0;
+        int sourceATrack = 0;
+        long videoDuration, audioDuration;
+        //创建分离器
+        MediaExtractor mediaExtractor = new MediaExtractor();
+        MediaMuxer mediaMuxer = null;
+        MediaFormat mediaFormat;
+
+        try {
+            //设置文件路径
+            mediaExtractor.setDataSource(url);
+            //创建合成器
+            mediaMuxer = new MediaMuxer(outFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+            String mime;
+            //获取每个轨道的信息
+            for (int i = 0; i < mediaExtractor.getTrackCount(); i++) {
+                mediaFormat = mediaExtractor.getTrackFormat(i);
+                mime = mediaFormat.getString(MediaFormat.KEY_MIME);
+                if (mime.startsWith("video/")) {
+                    sourceVTrack = i;
+                    int width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);
+                    int height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
+                    videoMaxInputSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
+                    videoDuration = mediaFormat.getLong(MediaFormat.KEY_DURATION);
+                    //检测剪辑点和剪辑时长是否正确
+                    if (clipPoint >= videoDuration) {
+                        Log.e(TAG, "clip point is error! but reset clipPoint " + clipPoint + " 0 ");
+                        clipPoint = 0;
+                    }
+                    if ((clipDuration + clipPoint) > videoDuration) {
+                        if (clipPoint == 0) {
+                            Log.e(TAG, "clip duration is error!"
+                                    + ";duration is " + videoDuration
+                                    + ";clipPoint is " + clipPoint
+                                    + ";clipDuration is " + clipDuration
+                                    + ";totalDuration is " + (clipDuration + clipPoint)
+                            );
+                            return null;
+                        }
+                        Log.e(TAG, "clip duration is error! but reset clipDuration " + clipDuration + "  " + (videoDuration - clipPoint));
+                        clipDuration = videoDuration - clipPoint;
+                    }
+                    Log.d(TAG, "width and height is " + width + " " + height
+                            + ";maxInputSize is " + videoMaxInputSize
+                            + ";duration is " + videoDuration
+                            + ";clipPoint is " + clipPoint
+                            + ";clipDuration is " + clipDuration
+                            + ";totalDuration is " + (clipDuration + clipPoint)
+                    );
+                    video.setWidth(width);
+                    video.setHeight(height);
+                    video.setDuration(clipDuration / 1000);//微秒转换为毫秒
+                    //向合成器添加视频轨
+                    videoTrackIndex = mediaMuxer.addTrack(mediaFormat);
+                } else if (mime.startsWith("audio/")) {
+                    sourceATrack = i;
+                    int sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+                    int channelCount = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+                    audioMaxInputSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
+                    audioDuration = mediaFormat.getLong(MediaFormat.KEY_DURATION);
+                    Log.d(TAG, "sampleRate is " + sampleRate
+                            + ";channelCount is " + channelCount
+                            + ";audioMaxInputSize is " + audioMaxInputSize
+                            + ";audioDuration is " + audioDuration
+                    );
+                    //添加音轨
+                    audioTrackIndex = mediaMuxer.addTrack(mediaFormat);
+                }
+                Log.d(TAG, "file mime is " + mime);
+            }
+            //分配缓冲
+            ByteBuffer inputBuffer = ByteBuffer.allocate(videoMaxInputSize);
+            //根据官方文档的解释MediaMuxer的start一定要在addTrack之后
+            mediaMuxer.start();
+            //视频处理部分
+            mediaExtractor.selectTrack(sourceVTrack);
+            MediaCodec.BufferInfo videoInfo = new MediaCodec.BufferInfo();
+            videoInfo.presentationTimeUs = 0;
+            long videoSampleTime;
+            //获取源视频相邻帧之间的时间间隔。(1)
+            {
+                mediaExtractor.readSampleData(inputBuffer, 0);
+                //skip first I frame
+                if (mediaExtractor.getSampleFlags() == MediaExtractor.SAMPLE_FLAG_SYNC)
+                    mediaExtractor.advance();
+                mediaExtractor.readSampleData(inputBuffer, 0);
+                long firstVideoPTS = mediaExtractor.getSampleTime();
+                mediaExtractor.advance();
+                mediaExtractor.readSampleData(inputBuffer, 0);
+                long SecondVideoPTS = mediaExtractor.getSampleTime();
+                videoSampleTime = Math.abs(SecondVideoPTS - firstVideoPTS);
+                Log.d(TAG, "videoSampleTime is " + videoSampleTime);
+            }
+            //选择起点
+            mediaExtractor.seekTo(clipPoint, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
+            while (true) {
+                int sampleSize = mediaExtractor.readSampleData(inputBuffer, 0);
+                if (sampleSize < 0) {
+                    //这里一定要释放选择的轨道,不然另一个轨道就无法选中了
+                    mediaExtractor.unselectTrack(sourceVTrack);
+                    break;
+                }
+                int trackIndex = mediaExtractor.getSampleTrackIndex();
+                //获取时间戳
+                long presentationTimeUs = mediaExtractor.getSampleTime();
+                //获取帧类型,只能识别是否为I帧
+                int sampleFlag = mediaExtractor.getSampleFlags();
+                Log.d(TAG, "trackIndex is " + trackIndex
+                        + ";presentationTimeUs is " + presentationTimeUs
+                        + ";sampleFlag is " + sampleFlag
+                        + ";sampleSize is " + sampleSize);
+                //剪辑时间到了就跳出
+                if ((clipDuration != 0) && (presentationTimeUs > (clipPoint + clipDuration))) {
+                    mediaExtractor.unselectTrack(sourceVTrack);
+                    break;
+                }
+                mediaExtractor.advance();
+                videoInfo.offset = 0;
+                videoInfo.size = sampleSize;
+                videoInfo.flags = sampleFlag;
+                mediaMuxer.writeSampleData(videoTrackIndex, inputBuffer, videoInfo);
+                videoInfo.presentationTimeUs += videoSampleTime;//presentationTimeUs;
+            }
+            //音频部分
+            mediaExtractor.selectTrack(sourceATrack);
+            MediaCodec.BufferInfo audioInfo = new MediaCodec.BufferInfo();
+            audioInfo.presentationTimeUs = 0;
+            long audioSampleTime;
+            //获取音频帧时长
+            {
+                mediaExtractor.readSampleData(inputBuffer, 0);
+                //skip first sample
+                if (mediaExtractor.getSampleTime() == 0)
+                    mediaExtractor.advance();
+                mediaExtractor.readSampleData(inputBuffer, 0);
+                long firstAudioPTS = mediaExtractor.getSampleTime();
+                mediaExtractor.advance();
+                mediaExtractor.readSampleData(inputBuffer, 0);
+                long SecondAudioPTS = mediaExtractor.getSampleTime();
+                audioSampleTime = Math.abs(SecondAudioPTS - firstAudioPTS);
+                Log.d(TAG, "AudioSampleTime is " + audioSampleTime);
+            }
+            mediaExtractor.seekTo(clipPoint, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+            while (true) {
+                int sampleSize = mediaExtractor.readSampleData(inputBuffer, 0);
+                if (sampleSize < 0) {
+                    mediaExtractor.unselectTrack(sourceATrack);
+                    break;
+                }
+                int trackIndex = mediaExtractor.getSampleTrackIndex();
+                long presentationTimeUs = mediaExtractor.getSampleTime();
+                Log.d(TAG, "trackIndex is " + trackIndex
+                        + ";presentationTimeUs is " + presentationTimeUs);
+                if ((clipDuration != 0) && (presentationTimeUs > (clipPoint + clipDuration))) {
+                    mediaExtractor.unselectTrack(sourceATrack);
+                    break;
+                }
+                mediaExtractor.advance();
+                audioInfo.offset = 0;
+                audioInfo.size = sampleSize;
+                mediaMuxer.writeSampleData(audioTrackIndex, inputBuffer, audioInfo);
+                audioInfo.presentationTimeUs += audioSampleTime;//presentationTimeUs;
+            }
+        } catch (Exception e) {
+            Log.e(TAG, " read error " + e.getMessage());
+        } finally {
+            //全部写完后释放MediaMuxer和MediaExtractor
+            if (mediaMuxer != null) {
+                mediaMuxer.stop();
+                mediaMuxer.release();
+            }
+            mediaExtractor.release();
+        }
+        return video;
+    }
+
+    public static void mixVideAndAudio(File outVideoPath, File outAudioPath, File outMergeVideoPath) throws Exception {
+        //分别初始化视频、音频的Extractor
+        MediaExtractor videoExtractor = new MediaExtractor();
+        videoExtractor.setDataSource(outVideoPath.getAbsolutePath());
+        MediaExtractor audioExtractor = new MediaExtractor();
+        audioExtractor.setDataSource(outAudioPath.getAbsolutePath());
+        int videoTrack = getTrack(videoExtractor, "video/");
+        int audioTrack = getTrack(audioExtractor, "audio/");
+        videoExtractor.selectTrack(videoTrack);
+        audioExtractor.selectTrack(audioTrack);
+        MediaCodec.BufferInfo videoBufferInfo = new MediaCodec.BufferInfo();
+        MediaCodec.BufferInfo audioBufferInfo = new MediaCodec.BufferInfo();
+        //写入新的视频
+        if (outMergeVideoPath.exists() && outMergeVideoPath.createNewFile())
+            ;
+        ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024);
+
+        MediaMuxer mediaMuxer = new MediaMuxer(outMergeVideoPath.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+        int writeVideoTrackIndex = mediaMuxer.addTrack(videoExtractor.getTrackFormat(videoTrack));
+        int writeAudioTrackIndex = mediaMuxer.addTrack(audioExtractor.getTrackFormat(audioTrack));
+        mediaMuxer.start();
+        long videoSampleTime = getSampleTime(videoExtractor, byteBuffer, videoTrack);
+        while (true) {
+            int data = videoExtractor.readSampleData(byteBuffer, 0);
+            if (data < 0) {
+                break;
+            }
+            videoBufferInfo.size = data;
+            videoBufferInfo.offset = 0;
+            videoBufferInfo.flags = videoExtractor.getSampleFlags();
+            videoBufferInfo.presentationTimeUs += videoSampleTime;
+            mediaMuxer.writeSampleData(writeVideoTrackIndex, byteBuffer, videoBufferInfo);
+            videoExtractor.advance();
+        }
+        long audioSampleTime = getSampleTime(audioExtractor, byteBuffer, audioTrack);
+        while (true) {
+            int data = audioExtractor.readSampleData(byteBuffer, 0);
+            if (data < 0) {
+                break;
+            }
+            audioBufferInfo.size = data;
+            audioBufferInfo.offset = 0;
+            audioBufferInfo.flags = audioExtractor.getSampleFlags();
+            audioBufferInfo.presentationTimeUs += audioSampleTime;
+            mediaMuxer.writeSampleData(writeAudioTrackIndex, byteBuffer, audioBufferInfo);
+            audioExtractor.advance();
+        }
+        Log.i("video", "合并完成");
+        mediaMuxer.stop();
+        mediaMuxer.release();
+        videoExtractor.release();
+        audioExtractor.release();
+    }
+
+    public static long getSampleTime(MediaExtractor mediaExtractor, ByteBuffer byteBuffer, int videoTrack) {
+        mediaExtractor.readSampleData(byteBuffer, 0);
+        //跳过I帧,要P帧(视频是由个别I帧和很多P帧组成)h264编码中有IBP帧 I为关键帧。
+        if (mediaExtractor.getSampleFlags() == MediaExtractor.SAMPLE_FLAG_SYNC) {
+            mediaExtractor.advance();
+        }
+        mediaExtractor.readSampleData(byteBuffer, 0);
+
+        // 得到第一帧的PTS
+        long firstVideoPTS = mediaExtractor.getSampleTime();
+        //下一帧
+        mediaExtractor.advance();
+        mediaExtractor.readSampleData(byteBuffer, 0);
+        long secondVideoPTS = mediaExtractor.getSampleTime();
+        long sampleTime = Math.abs(secondVideoPTS - firstVideoPTS);
+
+        // 重新切换此信道,不然上面跳过了3帧,造成前面的帧数模糊
+        mediaExtractor.unselectTrack(videoTrack);
+        mediaExtractor.selectTrack(videoTrack);
+        return sampleTime;
+    }
+
+    public static int getTrack(MediaExtractor extractor, String willFormat) {
+        //获得信道数
+        int trackCount = extractor.getTrackCount();
+        for (int i = 0; i < trackCount; i++) {
+            MediaFormat trackFormat = extractor.getTrackFormat(i);
+            String format = trackFormat.getString(MediaFormat.KEY_MIME);
+            if (format.startsWith(willFormat)) {
+                return i;
+            }
+        }
+        return 0;
+    }
+}

+ 37 - 19
app/src/main/java/com/sheep/gamegroup/util/MediaMetadataRetrieverUtil.java

@@ -3,11 +3,8 @@ package com.sheep.gamegroup.util;
 import android.content.Context;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap;
 import android.media.MediaMetadataRetriever;
 import android.media.MediaMetadataRetriever;
-import android.support.annotation.NonNull;
 import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView;
-import android.view.View;
 import android.widget.ImageView;
 import android.widget.ImageView;
 
 
 import com.chad.library.adapter.base.BaseQuickAdapter;
 import com.chad.library.adapter.base.BaseQuickAdapter;
@@ -26,9 +23,7 @@ import java.util.Locale;
 import io.reactivex.Observable;
 import io.reactivex.Observable;
 import io.reactivex.ObservableEmitter;
 import io.reactivex.ObservableEmitter;
 import io.reactivex.ObservableOnSubscribe;
 import io.reactivex.ObservableOnSubscribe;
-import io.reactivex.ObservableSource;
 import io.reactivex.android.schedulers.AndroidSchedulers;
 import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.functions.Function;
 import io.reactivex.schedulers.Schedulers;
 import io.reactivex.schedulers.Schedulers;
 
 
 /**
 /**
@@ -88,32 +83,26 @@ public class MediaMetadataRetrieverUtil {
      * 取出视频文件中的图片帧列表
      * 取出视频文件中的图片帧列表
      */
      */
     public void initRv(final RecyclerView recyclerView) {
     public void initRv(final RecyclerView recyclerView) {
-        Observable.create(new ObservableOnSubscribe<List<String>>() {
+        Observable.create(new ObservableOnSubscribe<List<Bitmap>>() {
             @Override
             @Override
-            public void subscribe(ObservableEmitter<List<String>> emitter) throws Exception {
-                emitter.onNext(getFrameFileList(fromFile, outDir, duration, size));
+            public void subscribe(ObservableEmitter<List<Bitmap>> emitter) throws Exception {
+                emitter.onNext(getFrameBitmapList(fromFile, duration, size));
             }
             }
         })
         })
                 .subscribeOn(Schedulers.io())
                 .subscribeOn(Schedulers.io())
                 .observeOn(AndroidSchedulers.mainThread())
                 .observeOn(AndroidSchedulers.mainThread())
-                .subscribe(new AbsObserver<List<String>>() {
+                .subscribe(new AbsObserver<List<Bitmap>>() {
                     @Override
                     @Override
-                    public void onNext(final List<String> strings) {
+                    public void onNext(final List<Bitmap> strings) {
                         recyclerView.setLayoutManager(new GridLayoutManager(SheepApp.getInstance(), size));
                         recyclerView.setLayoutManager(new GridLayoutManager(SheepApp.getInstance(), size));
-                        BaseQuickAdapter<String, BaseViewHolder> baseQuickAdapter = new BaseQuickAdapter<String, BaseViewHolder>(R.layout.item_iv_mh, strings) {
+                        BaseQuickAdapter<Bitmap, BaseViewHolder> baseQuickAdapter = new BaseQuickAdapter<Bitmap, BaseViewHolder>(R.layout.item_iv_mh, strings) {
                             @Override
                             @Override
-                            protected void convert(BaseViewHolder helper, String item) {
+                            protected void convert(BaseViewHolder helper, Bitmap item) {
                                 ImageView imageView = helper.getView(R.id.item_iv);
                                 ImageView imageView = helper.getView(R.id.item_iv);
-                                ViewUtil.setImagePath(imageView, item);
+                                imageView.setImageBitmap(item);
                             }
                             }
                         };
                         };
                         recyclerView.setAdapter(baseQuickAdapter);
                         recyclerView.setAdapter(baseQuickAdapter);
-                        baseQuickAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
-                            @Override
-                            public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
-                                Jump2View.getInstance().showImgList(ActivityManager.getInstance().currentActivity(), position, (ArrayList<String>) strings);
-                            }
-                        });
                     }
                     }
                 });
                 });
 
 
@@ -128,6 +117,35 @@ public class MediaMetadataRetrieverUtil {
      * 取出视频文件中的图片帧列表
      * 取出视频文件中的图片帧列表
      *
      *
      * @param fromFile 要操作的本地视频文件
      * @param fromFile 要操作的本地视频文件
+     * @param duration 视频文件的总时长,单位毫秒
+     * @param size     需要的图片个数
+     * @return
+     */
+    public static List<Bitmap> getFrameBitmapList(String fromFile, long duration, int size) {
+        if (duration < size || size < 1) {
+            return null;
+        }
+        long per = duration * 1000L / (size - 1);
+        List<Bitmap> resultList = new ArrayList<>();
+        long time = System.currentTimeMillis();
+        MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();
+        metadataRetriever.setDataSource(fromFile);
+
+        for (int i = 0; i < size; i++) {
+            //这里单位为微秒
+            long atTime = i + 1 == size ? (duration * 1000L) : i * per;
+            Bitmap bitmap = metadataRetriever.getFrameAtTime(atTime, MediaMetadataRetriever.OPTION_CLOSEST);
+            resultList.add(bitmap);
+        }
+        long curTime = System.currentTimeMillis();
+        LogUtil.println(TAG, time, curTime, curTime - time, (curTime - time) / 1000, (curTime - time) / 10000);
+        return resultList;
+    }
+
+    /**
+     * 取出视频文件中的图片帧列表
+     *
+     * @param fromFile 要操作的本地视频文件
      * @param outDir   输出路径
      * @param outDir   输出路径
      * @param duration 视频文件的总时长,单位毫秒
      * @param duration 视频文件的总时长,单位毫秒
      * @param size     需要的图片个数
      * @param size     需要的图片个数

+ 20 - 0
app/src/main/java/com/sheep/gamegroup/util/ViewUtil.java

@@ -69,11 +69,13 @@ import com.sheep.gamegroup.model.entity.Container;
 import com.sheep.gamegroup.model.entity.DialogConfig;
 import com.sheep.gamegroup.model.entity.DialogConfig;
 import com.sheep.gamegroup.model.entity.GameAccountEntity;
 import com.sheep.gamegroup.model.entity.GameAccountEntity;
 import com.sheep.gamegroup.model.entity.GiftBagApp;
 import com.sheep.gamegroup.model.entity.GiftBagApp;
+import com.sheep.gamegroup.model.entity.Lp;
 import com.sheep.gamegroup.model.entity.PayEntity;
 import com.sheep.gamegroup.model.entity.PayEntity;
 import com.sheep.gamegroup.model.entity.RobTask;
 import com.sheep.gamegroup.model.entity.RobTask;
 import com.sheep.gamegroup.model.entity.TaskEty;
 import com.sheep.gamegroup.model.entity.TaskEty;
 import com.sheep.gamegroup.util.glide.RoundedCornersTransformation;
 import com.sheep.gamegroup.util.glide.RoundedCornersTransformation;
 import com.sheep.gamegroup.util.share.ShareLinkConfig;
 import com.sheep.gamegroup.util.share.ShareLinkConfig;
+import com.sheep.gamegroup.util.viewHelper.LayoutParamsUtil;
 import com.sheep.gamegroup.view.activity.ActMain;
 import com.sheep.gamegroup.view.activity.ActMain;
 import com.sheep.gamegroup.view.activity.PersonalInfoAct;
 import com.sheep.gamegroup.view.activity.PersonalInfoAct;
 import com.sheep.gamegroup.view.activity.SplashAct;
 import com.sheep.gamegroup.view.activity.SplashAct;
@@ -1587,6 +1589,24 @@ public class ViewUtil {
             }
             }
         }
         }
     }
     }
+    public static void setImageWH(ImageView imageView, String pictures, int width) {
+        if (imageView != null) {
+            if (TextUtils.isEmpty(pictures)) {
+                imageView.setImageResource(R.mipmap.icon);
+            } else {
+                if (pictures.contains(";")) {
+                    pictures = pictures.split(";")[0];
+                }
+                Uri uri = Uri.parse(pictures);
+                int w = NumberFormatUtils.parseInteger(uri.getQueryParameter("w"));
+                int h = NumberFormatUtils.parseInteger(uri.getQueryParameter("h"));
+                if(w > 0 && h > 0){
+                    LayoutParamsUtil.resetLayoutParams(imageView, new Lp().setWidth(width).setHeight((int) (width * h * 1.0f / w)));
+                }
+                GlideImageLoader.setImage(imageView, pictures);
+            }
+        }
+    }
     public static void setImagePath(ImageView imageView, String paths) {
     public static void setImagePath(ImageView imageView, String paths) {
         if (imageView != null){
         if (imageView != null){
             if(TextUtils.isEmpty(paths)) {
             if(TextUtils.isEmpty(paths)) {

+ 82 - 34
app/src/main/java/com/sheep/gamegroup/view/activity/ActEditVideo.java

@@ -18,12 +18,14 @@ import android.widget.VideoView;
 
 
 import com.kfzs.duanduan.utils.NumberFormatUtils;
 import com.kfzs.duanduan.utils.NumberFormatUtils;
 import com.kfzs.duanduan.utils.StatusBarUtils;
 import com.kfzs.duanduan.utils.StatusBarUtils;
+import com.sheep.gamegroup.absBase.AbsObserver;
 import com.sheep.gamegroup.absBase.BaseContainerActivity;
 import com.sheep.gamegroup.absBase.BaseContainerActivity;
 import com.sheep.gamegroup.model.entity.DiscoveryTopic;
 import com.sheep.gamegroup.model.entity.DiscoveryTopic;
-import com.sheep.gamegroup.util.ActionUtil;
+import com.sheep.gamegroup.model.entity.Video;
 import com.sheep.gamegroup.util.DataUtil;
 import com.sheep.gamegroup.util.DataUtil;
 import com.sheep.gamegroup.util.KeyEventUtil;
 import com.sheep.gamegroup.util.KeyEventUtil;
 import com.sheep.gamegroup.util.LogUtil;
 import com.sheep.gamegroup.util.LogUtil;
+import com.sheep.gamegroup.util.MediaHandleUtil;
 import com.sheep.gamegroup.util.TestUtil;
 import com.sheep.gamegroup.util.TestUtil;
 import com.sheep.gamegroup.util.ViewUtil;
 import com.sheep.gamegroup.util.ViewUtil;
 import com.sheep.gamegroup.view.customview.VideoFramesView;
 import com.sheep.gamegroup.view.customview.VideoFramesView;
@@ -31,6 +33,11 @@ import com.sheep.gamegroup.view.fragment.FgtDiscoveryTopic;
 import com.sheep.jiuyan.samllsheep.R;
 import com.sheep.jiuyan.samllsheep.R;
 import com.sheep.jiuyan.samllsheep.utils.G;
 import com.sheep.jiuyan.samllsheep.utils.G;
 
 
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+
+import java.util.Locale;
+
 import butterknife.BindView;
 import butterknife.BindView;
 import rx.functions.Action1;
 import rx.functions.Action1;
 
 
@@ -61,13 +68,15 @@ public class ActEditVideo extends BaseContainerActivity implements MediaPlayer.O
         return R.layout.act_edit_video;
         return R.layout.act_edit_video;
     }
     }
 
 
+    public static final long MAX_VIDEO_DURATION = 15_000L;//视频最大时长,超过需要剪切
+    private Video data;
+
     @Override
     @Override
     public void initView() {
     public void initView() {
         super.initView();
         super.initView();
         initVolume();
         initVolume();
-        String url = DataUtil.getObject(getIntent(), String.class);
-        final long duration = DataUtil.getObject(getIntent(), Long.class);
-        Uri uri = Uri.parse(url);
+        data = DataUtil.getObject(getIntent(), Video.class);
+        Uri uri = Uri.parse(data.getFilePath());
         videoView.setOnInfoListener(this);
         videoView.setOnInfoListener(this);
         videoView.setOnPreparedListener(this);
         videoView.setOnPreparedListener(this);
         videoView.setOnErrorListener(this);
         videoView.setOnErrorListener(this);
@@ -75,11 +84,13 @@ public class ActEditVideo extends BaseContainerActivity implements MediaPlayer.O
         videoView.addOnLayoutChangeListener(this);
         videoView.addOnLayoutChangeListener(this);
 //        videoView.setMediaController(new MediaController(this));
 //        videoView.setMediaController(new MediaController(this));
         videoView.setVideoURI(uri);
         videoView.setVideoURI(uri);
-        videoFramesView.initVideo(url, duration).showVideoList().setOnTimeChangeListener(new Action1<Float>() {
+        videoFramesView.initVideo(data).setMaxDuration(MAX_VIDEO_DURATION).showVideoList().setOnTimeChangeListener(new Action1<Float>() {
             @Override
             @Override
-            public void call(Float percent) {
-                ViewUtil.setText(edit_video_time_tv, R.string.has_choose_x_second, NumberFormatUtils.retainMost1(duration * percent / 1000));
-                if(TestUtil.isDev()) {
+            public void call(Float duration) {
+                ViewUtil.setText(edit_video_time_tv, R.string.has_choose_x_second, NumberFormatUtils.retainMost1(duration / 1000.0f));
+                if (TestUtil.isDev()) {
+                    edit_video_time_tv.append("\t");
+                    edit_video_time_tv.append(String.format(Locale.CHINA, "%.1f秒-%.1f秒", videoFramesView.getStartPoint() / 1000.0f, videoFramesView.getEndPoint() / 1000.0f));
                     edit_video_time_tv.append("\t");
                     edit_video_time_tv.append("\t");
                     edit_video_time_tv.append(videoFramesView.getLineInfo());
                     edit_video_time_tv.append(videoFramesView.getLineInfo());
                 }
                 }
@@ -104,33 +115,37 @@ public class ActEditVideo extends BaseContainerActivity implements MediaPlayer.O
         };
         };
         videoView.setOnTouchListener(listener);
         videoView.setOnTouchListener(listener);
     }
     }
+
     private GestureDetector mGestureDetector;
     private GestureDetector mGestureDetector;
 
 
     //播放或者暂停
     //播放或者暂停
     private void playOrPause() {
     private void playOrPause() {
-        if(videoView.isPlaying()){
+        if (videoView.isPlaying()) {
             pause();
             pause();
         } else {
         } else {
             play();
             play();
         }
         }
     }
     }
+
     //播放
     //播放
-    private void play(){
-        if(videoView == null){
+    private void play() {
+        if (videoView == null) {
             return;
             return;
         }
         }
         videoView.start();
         videoView.start();
     }
     }
+
     //暂停
     //暂停
-    private void pause(){
-        if(videoView == null){
+    private void pause() {
+        if (videoView == null) {
             return;
             return;
         }
         }
         videoView.pause();
         videoView.pause();
     }
     }
+
     //销毁
     //销毁
-    private void destroy(){
-        if(videoView == null){
+    private void destroy() {
+        if (videoView == null) {
             return;
             return;
         }
         }
         videoView.stopPlayback();
         videoView.stopPlayback();
@@ -145,28 +160,33 @@ public class ActEditVideo extends BaseContainerActivity implements MediaPlayer.O
     @Override
     @Override
     protected void onResume() {
     protected void onResume() {
         super.onResume();
         super.onResume();
-        if(!isPauseByUser)
+        if (!isPauseByUser)
             play();
             play();
     }
     }
+
     //是否是用户手机暂停
     //是否是用户手机暂停
     private boolean isPauseByUser;
     private boolean isPauseByUser;
+
     @Override
     @Override
     protected void onPause() {
     protected void onPause() {
         super.onPause();
         super.onPause();
-        if(videoView != null && videoView.isPlaying())
+        if (videoView != null && videoView.isPlaying())
             isPauseByUser = false;
             isPauseByUser = false;
-        if(video_loading != null)
+        if (video_loading != null)
             video_loading.setVisibility(View.VISIBLE);
             video_loading.setVisibility(View.VISIBLE);
         pause();
         pause();
     }
     }
 
 
     @Override
     @Override
     protected void onDestroy() {
     protected void onDestroy() {
-        super.onDestroy();
         destroy();
         destroy();
+        if (videoFramesView != null)
+            videoFramesView.onDestroy();
+        super.onDestroy();
+        mAudioManager = null;
     }
     }
 
 
-//    //滑动方向
+    //    //滑动方向
 //    private int direction = 0;
 //    private int direction = 0;
 //    //左右滑动
 //    //左右滑动
 //    public static final int DIRECTION_LEFT_RIGHT = 1;
 //    public static final int DIRECTION_LEFT_RIGHT = 1;
@@ -194,6 +214,7 @@ public class ActEditVideo extends BaseContainerActivity implements MediaPlayer.O
 //            playOrPause();
 //            playOrPause();
             return super.onSingleTapConfirmed(e);
             return super.onSingleTapConfirmed(e);
         }
         }
+
         @Override
         @Override
         public boolean onScroll(MotionEvent e1, MotionEvent e2,
         public boolean onScroll(MotionEvent e1, MotionEvent e2,
                                 float distanceX, float distanceY) {
                                 float distanceX, float distanceY) {
@@ -269,11 +290,13 @@ public class ActEditVideo extends BaseContainerActivity implements MediaPlayer.O
     private AudioManager mAudioManager;
     private AudioManager mAudioManager;
     private int mMaxVolume;//最大音量
     private int mMaxVolume;//最大音量
     private int mVolume;//当前音量
     private int mVolume;//当前音量
-    private void initVolume(){
+
+    private void initVolume() {
         mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
         mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-        if(mAudioManager != null)
+        if (mAudioManager != null)
             mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
             mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
     }
     }
+
     //滑动改变音量
     //滑动改变音量
     private void onVolumeSlide(float percent) {
     private void onVolumeSlide(float percent) {
         if (mVolume == -1) {
         if (mVolume == -1) {
@@ -299,7 +322,9 @@ public class ActEditVideo extends BaseContainerActivity implements MediaPlayer.O
 //            lp.width = findViewById(R.id.operation_full).getLayoutParams().width * index / mMaxVolume;
 //            lp.width = findViewById(R.id.operation_full).getLayoutParams().width * index / mMaxVolume;
 //            mOperationPercent.setLayoutParams(lp);
 //            mOperationPercent.setLayoutParams(lp);
     }
     }
+
     private float mBrightness = -1;
     private float mBrightness = -1;
+
     //滑动改变亮度
     //滑动改变亮度
     private void onBrightnessSlide(float percent) {
     private void onBrightnessSlide(float percent) {
         if (mBrightness < 0) {
         if (mBrightness < 0) {
@@ -325,6 +350,7 @@ public class ActEditVideo extends BaseContainerActivity implements MediaPlayer.O
 //            lp.width = (int) (findViewById(R.id.operation_full).getLayoutParams().width * lpa.screenBrightness);
 //            lp.width = (int) (findViewById(R.id.operation_full).getLayoutParams().width * lpa.screenBrightness);
 //            mOperationPercent.setLayoutParams(lp);
 //            mOperationPercent.setLayoutParams(lp);
     }
     }
+
     @Override
     @Override
     public boolean onInfo(MediaPlayer mediaPlayer, int what, int extra) {
     public boolean onInfo(MediaPlayer mediaPlayer, int what, int extra) {
         LogUtil.println("ActPlayVideo", "onInfo what = " + what + " extra = " + extra);
         LogUtil.println("ActPlayVideo", "onInfo what = " + what + " extra = " + extra);
@@ -333,23 +359,24 @@ public class ActEditVideo extends BaseContainerActivity implements MediaPlayer.O
         switch (what) {
         switch (what) {
             case MediaPlayer.MEDIA_INFO_BUFFERING_START:
             case MediaPlayer.MEDIA_INFO_BUFFERING_START:
                 LogUtil.println("ActPlayVideo", "onInfo", "正在缓冲");
                 LogUtil.println("ActPlayVideo", "onInfo", "正在缓冲");
-                if(video_loading != null)
+                if (video_loading != null)
                     video_loading.setVisibility(View.VISIBLE);
                     video_loading.setVisibility(View.VISIBLE);
                 break;
                 break;
             case MediaPlayer.MEDIA_INFO_BUFFERING_END:
             case MediaPlayer.MEDIA_INFO_BUFFERING_END:
             case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
             case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
                 LogUtil.println("ActPlayVideo", "onInfo", "缓冲完成");
                 LogUtil.println("ActPlayVideo", "onInfo", "缓冲完成");
                 //缓存完成,继续播放
                 //缓存完成,继续播放
-                if(video_loading != null)
+                if (video_loading != null)
                     video_loading.setVisibility(View.GONE);
                     video_loading.setVisibility(View.GONE);
                 break;
                 break;
         }
         }
         return false;
         return false;
     }
     }
+
     @Override
     @Override
     public void onPrepared(MediaPlayer mediaPlayer) {
     public void onPrepared(MediaPlayer mediaPlayer) {
         LogUtil.println("ActPlayVideo", "onPrepared");
         LogUtil.println("ActPlayVideo", "onPrepared");
-        if(video_loading != null)
+        if (video_loading != null)
             video_loading.setVisibility(View.GONE);
             video_loading.setVisibility(View.GONE);
     }
     }
 
 
@@ -366,6 +393,7 @@ public class ActEditVideo extends BaseContainerActivity implements MediaPlayer.O
 
 
     private int windowWidth = G.WIDTH;
     private int windowWidth = G.WIDTH;
     private int windowHeight = G.HEIGHT;
     private int windowHeight = G.HEIGHT;
+
     @Override
     @Override
     public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
     public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
         LogUtil.println("ActPlayVideo", "onLayoutChange", left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom);
         LogUtil.println("ActPlayVideo", "onLayoutChange", left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom);
@@ -381,17 +409,20 @@ public class ActEditVideo extends BaseContainerActivity implements MediaPlayer.O
     @BindView(R.id.frame_container)
     @BindView(R.id.frame_container)
     View frame_container;
     View frame_container;
 
 
-    //添加话题
     @Override
     @Override
-    public void doNextAction(Object action) {
-        if(action instanceof DiscoveryTopic){
-            ViewUtil.setText(edit_video_topic_tv, "#%s#", ((DiscoveryTopic) action).getTopic());
-        }
+    protected boolean needRegisterEventBus() {
+        return true;
+    }
+
+    @Subscribe
+    public void onEventMainThread(DiscoveryTopic result) {
+        ViewUtil.setText(edit_video_topic_tv, "#%s#", result.getTopic());
+        data.setTopicId(result.getId());
     }
     }
 
 
     //点击话题进行切换
     //点击话题进行切换
     public void onClickTopic(View view) {
     public void onClickTopic(View view) {
-        if(ViewUtil.isVisible(frame_container)){
+        if (ViewUtil.isVisible(frame_container)) {
             ViewUtil.setText(edit_video_sure_tv, "完成");
             ViewUtil.setText(edit_video_sure_tv, "完成");
         } else {
         } else {
             ViewUtil.setText(edit_video_sure_tv, "下一步");
             ViewUtil.setText(edit_video_sure_tv, "下一步");
@@ -402,16 +433,33 @@ public class ActEditVideo extends BaseContainerActivity implements MediaPlayer.O
     //点击返回
     //点击返回
     public void onClickBackImg(View view) {
     public void onClickBackImg(View view) {
         KeyEventUtil.sendKeyDownUp(KeyEvent.KEYCODE_BACK);
         KeyEventUtil.sendKeyDownUp(KeyEvent.KEYCODE_BACK);
-        ActionUtil.getInstance().getAction(ActPublishArticle.class.getSimpleName());//清除掉选中的话题
     }
     }
 
 
     //点击确定
     //点击确定
     public void onClickSure(View view) {
     public void onClickSure(View view) {
-        if(ViewUtil.isVisible(frame_container)){//首先隐藏话题列表
+        if (ViewUtil.isVisible(frame_container)) {//首先隐藏话题列表
             ViewUtil.setVisibility(frame_container, false);
             ViewUtil.setVisibility(frame_container, false);
             ViewUtil.setText(edit_video_sure_tv, "完成");
             ViewUtil.setText(edit_video_sure_tv, "完成");
         } else {//其次完成编辑
         } else {//其次完成编辑
-            G.showToast("完成操作");
+            G.showToast("开始剪切");
+            new MediaHandleUtil(data.getFilePath(), videoFramesView.getStartPoint() * 1000, videoFramesView.getLineDuration() * 1000)
+                    .tryCutVideo(new AbsObserver<Video>() {
+                        @Override
+                        public void onNext(Video video) {
+                            data.setFilePath(video.getFilePath());
+                            data.setWidth(video.getWidth());
+                            data.setHeight(video.getHeight());
+                            data.setDuration(video.getDuration());
+                            EventBus.getDefault().post(data);
+                            G.showToast("完成剪切");
+                            finish();
+                        }
+
+                        @Override
+                        public void onError(Throwable e) {
+                            G.showToast(e.getMessage());
+                        }
+                    });
         }
         }
     }
     }
 }
 }

+ 2 - 1
app/src/main/java/com/sheep/gamegroup/view/activity/ActPlayVideo.java

@@ -130,8 +130,9 @@ public class ActPlayVideo extends BaseActivity implements MediaPlayer.OnInfoList
 
 
     @Override
     @Override
     protected void onDestroy() {
     protected void onDestroy() {
-        super.onDestroy();
         destroy();
         destroy();
+        super.onDestroy();
+        mAudioManager = null;
     }
     }
 
 
 //    //滑动方向
 //    //滑动方向

+ 7 - 1
app/src/main/java/com/sheep/gamegroup/view/activity/ActPlayVideoArticle.java

@@ -21,9 +21,11 @@ import android.widget.VideoView;
 
 
 import com.kfzs.duanduan.utils.StatusBarUtils;
 import com.kfzs.duanduan.utils.StatusBarUtils;
 import com.sheep.gamegroup.absBase.BaseActivity;
 import com.sheep.gamegroup.absBase.BaseActivity;
+import com.sheep.gamegroup.absBase.IRefresh;
 import com.sheep.gamegroup.model.entity.BaseMessage;
 import com.sheep.gamegroup.model.entity.BaseMessage;
 import com.sheep.gamegroup.model.entity.DiscoveryVideo;
 import com.sheep.gamegroup.model.entity.DiscoveryVideo;
 import com.sheep.gamegroup.model.util.SheepSubscriber;
 import com.sheep.gamegroup.model.util.SheepSubscriber;
+import com.sheep.gamegroup.util.ActionUtil;
 import com.sheep.gamegroup.util.ApiUtil;
 import com.sheep.gamegroup.util.ApiUtil;
 import com.sheep.gamegroup.util.DataUtil;
 import com.sheep.gamegroup.util.DataUtil;
 import com.sheep.gamegroup.util.Jump2View;
 import com.sheep.gamegroup.util.Jump2View;
@@ -32,6 +34,7 @@ import com.sheep.gamegroup.util.TestUtil;
 import com.sheep.gamegroup.util.ViewUtil;
 import com.sheep.gamegroup.util.ViewUtil;
 import com.sheep.gamegroup.util.share.CommonUMShareListener;
 import com.sheep.gamegroup.util.share.CommonUMShareListener;
 import com.sheep.gamegroup.util.share.ShareLinkConfig;
 import com.sheep.gamegroup.util.share.ShareLinkConfig;
+import com.sheep.gamegroup.view.fragment.FgtArticleVideo;
 import com.sheep.jiuyan.samllsheep.R;
 import com.sheep.jiuyan.samllsheep.R;
 import com.sheep.jiuyan.samllsheep.SheepApp;
 import com.sheep.jiuyan.samllsheep.SheepApp;
 import com.sheep.jiuyan.samllsheep.utils.G;
 import com.sheep.jiuyan.samllsheep.utils.G;
@@ -262,6 +265,8 @@ public class ActPlayVideoArticle extends BaseActivity implements MediaPlayer.OnI
                             }
                             }
                             loadVideoData(newVideo);
                             loadVideoData(newVideo);
                         }
                         }
+                        //回去视频列表后需要刷新界面
+                        ActionUtil.getInstance().addNextAction(FgtArticleVideo.class.getSimpleName(), IRefresh.class.getSimpleName());
                     }
                     }
 
 
                     @Override
                     @Override
@@ -334,8 +339,9 @@ public class ActPlayVideoArticle extends BaseActivity implements MediaPlayer.OnI
 
 
     @Override
     @Override
     protected void onDestroy() {
     protected void onDestroy() {
-        super.onDestroy();
         destroy();
         destroy();
+        super.onDestroy();
+        mAudioManager = null;
     }
     }
 
 
     //    //滑动方向
     //    //滑动方向

+ 56 - 38
app/src/main/java/com/sheep/gamegroup/view/activity/ActPublishArticle.java

@@ -14,24 +14,28 @@ import com.chad.library.adapter.base.BaseViewHolder;
 import com.qiniu.android.http.ResponseInfo;
 import com.qiniu.android.http.ResponseInfo;
 import com.qiniu.android.storage.UpCompletionHandler;
 import com.qiniu.android.storage.UpCompletionHandler;
 import com.qiniu.android.storage.UpProgressHandler;
 import com.qiniu.android.storage.UpProgressHandler;
+import com.sheep.gamegroup.absBase.AbsObserver;
 import com.sheep.gamegroup.absBase.BaseActivity;
 import com.sheep.gamegroup.absBase.BaseActivity;
+import com.sheep.gamegroup.absBase.IRefresh;
 import com.sheep.gamegroup.model.entity.BaseMessage;
 import com.sheep.gamegroup.model.entity.BaseMessage;
 import com.sheep.gamegroup.model.entity.CreateUserVideoReq;
 import com.sheep.gamegroup.model.entity.CreateUserVideoReq;
-import com.sheep.gamegroup.model.entity.DiscoveryTopic;
 import com.sheep.gamegroup.model.entity.InputAndUrlList;
 import com.sheep.gamegroup.model.entity.InputAndUrlList;
+import com.sheep.gamegroup.model.entity.Video;
 import com.sheep.gamegroup.model.util.SheepSubscriber;
 import com.sheep.gamegroup.model.util.SheepSubscriber;
+import com.sheep.gamegroup.util.ActionUtil;
 import com.sheep.gamegroup.util.Jump2View;
 import com.sheep.gamegroup.util.Jump2View;
 import com.sheep.gamegroup.util.ListUtil;
 import com.sheep.gamegroup.util.ListUtil;
 import com.sheep.gamegroup.util.LogUtil;
 import com.sheep.gamegroup.util.LogUtil;
 import com.sheep.gamegroup.util.QiNiuUploadUtil;
 import com.sheep.gamegroup.util.QiNiuUploadUtil;
 import com.sheep.gamegroup.util.ViewUtil;
 import com.sheep.gamegroup.util.ViewUtil;
-import com.sheep.gamegroup.view.dialog.DialogLoading;
 import com.sheep.gamegroup.view.dialog.DialogProgress;
 import com.sheep.gamegroup.view.dialog.DialogProgress;
+import com.sheep.gamegroup.view.fragment.FgtArticleVideo;
 import com.sheep.jiuyan.samllsheep.R;
 import com.sheep.jiuyan.samllsheep.R;
 import com.sheep.jiuyan.samllsheep.SheepApp;
 import com.sheep.jiuyan.samllsheep.SheepApp;
 import com.sheep.jiuyan.samllsheep.utils.G;
 import com.sheep.jiuyan.samllsheep.utils.G;
 import com.sheep.jiuyan.samllsheep.utils.TitleBarUtils;
 import com.sheep.jiuyan.samllsheep.utils.TitleBarUtils;
 
 
+import org.greenrobot.eventbus.Subscribe;
 import org.json.JSONException;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.json.JSONObject;
 
 
@@ -40,12 +44,9 @@ import java.util.Locale;
 
 
 import butterknife.BindView;
 import butterknife.BindView;
 import cn.finalteam.rxgalleryfinal.RxGalleryFinalApi;
 import cn.finalteam.rxgalleryfinal.RxGalleryFinalApi;
-import cn.finalteam.rxgalleryfinal.bean.ImageCropBean;
-import cn.finalteam.rxgalleryfinal.bean.MediaBean;
 import cn.finalteam.rxgalleryfinal.rxbus.RxBusResultDisposable;
 import cn.finalteam.rxgalleryfinal.rxbus.RxBusResultDisposable;
 import cn.finalteam.rxgalleryfinal.rxbus.event.ImageRadioResultEvent;
 import cn.finalteam.rxgalleryfinal.rxbus.event.ImageRadioResultEvent;
 import io.reactivex.android.schedulers.AndroidSchedulers;
 import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.functions.Function;
 import io.reactivex.schedulers.Schedulers;
 import io.reactivex.schedulers.Schedulers;
 
 
 import static android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE;
 import static android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE;
@@ -104,8 +105,8 @@ public class ActPublishArticle extends BaseActivity {
                     helper.itemView.setOnClickListener(new View.OnClickListener() {
                     helper.itemView.setOnClickListener(new View.OnClickListener() {
                         @Override
                         @Override
                         public void onClick(View view) {
                         public void onClick(View view) {
-                            if(imageCropBean != null)
-                                Jump2View.getInstance().goActEditVideo(imageCropBean.getOriginalPath(), imageCropBean.getDuration());
+                            if (video != null)
+                                Jump2View.getInstance().goActEditVideo(video);
                         }
                         }
                     });
                     });
                 }
                 }
@@ -127,31 +128,29 @@ public class ActPublishArticle extends BaseActivity {
     private void addVideo() {
     private void addVideo() {
         RxGalleryFinalApi
         RxGalleryFinalApi
                 .getInstance(ActPublishArticle.this)
                 .getInstance(ActPublishArticle.this)
-                .setFilter(new Function<MediaBean, Boolean>() {
-                    @Override
-                    public Boolean apply(MediaBean mediaBean) throws Exception {
-                        boolean result = mediaBean.getDuration() > 15_000L;
-                        if (result) {
-                            G.showToast(R.string.need_picker_video_dur_15);
-                        }
-                        return result;
-                    }
-                })
+//                .setFilter(new Function<MediaBean, Boolean>() {
+//                    @Override
+//                    public Boolean apply(MediaBean mediaBean) throws Exception {
+//                        boolean result = mediaBean.getDuration() > 15_000L;
+//                        if (result) {
+//                            G.showToast(R.string.need_picker_video_dur_15);
+//                        }
+//                        return result;
+//                    }
+//                })
                 .setType(RxGalleryFinalApi.SelectRXType.TYPE_VIDEO, RxGalleryFinalApi.SelectRXType.TYPE_SELECT_RADIO)
                 .setType(RxGalleryFinalApi.SelectRXType.TYPE_VIDEO, RxGalleryFinalApi.SelectRXType.TYPE_SELECT_RADIO)
                 .setVDRadioResultEvent(new RxBusResultDisposable<ImageRadioResultEvent>() {
                 .setVDRadioResultEvent(new RxBusResultDisposable<ImageRadioResultEvent>() {
                     @Override
                     @Override
                     protected void onEvent(ImageRadioResultEvent imageRadioResultEvent) throws Exception {
                     protected void onEvent(ImageRadioResultEvent imageRadioResultEvent) throws Exception {
-                        ListUtil.removeNull(inputAndUrlList.getList());
-                        inputAndUrlList.getList().add(imageRadioResultEvent.getResult().getOriginalPath());
-                        ViewUtil.notifyDataSetChanged(recyclerView);
-                        imageCropBean = imageRadioResultEvent.getResult();
-                        Jump2View.getInstance().goActEditVideo(imageCropBean.getOriginalPath(), imageCropBean.getDuration());
+                        Video data = new Video();
+                        data.setFilePath(imageRadioResultEvent.getResult().getOriginalPath());
+                        data.setDuration(imageRadioResultEvent.getResult().getDuration());
+                        Jump2View.getInstance().goActEditVideo(data);
                     }
                     }
                 })
                 })
                 .open();
                 .open();
     }
     }
 
 
-    private ImageCropBean imageCropBean;
     private int uploadType = UPLOAD_TYPE_NONE;
     private int uploadType = UPLOAD_TYPE_NONE;
 
 
     //点击确定按钮
     //点击确定按钮
@@ -165,13 +164,14 @@ public class ActPublishArticle extends BaseActivity {
 //            G.showToast(R.string.nedd_picker_img);
 //            G.showToast(R.string.nedd_picker_img);
 //            return;
 //            return;
 //        }
 //        }
-        if (imageCropBean == null) {
+        if (isErrorVideo()) {
             G.showToast(R.string.need_picker_video);
             G.showToast(R.string.need_picker_video);
             return;
             return;
         }
         }
         jsonObject.put("resource_type", CreateUserVideoReq.TYPE_VIDEO);
         jsonObject.put("resource_type", CreateUserVideoReq.TYPE_VIDEO);
         jsonObject.put("title", input);
         jsonObject.put("title", input);
-        jsonObject.put("duration", imageCropBean.getDuration() / 1000);
+        jsonObject.put("duration", video.getDuration() / 1000);
+        jsonObject.put("topic_id", video.getTopicId());
         inputAndUrlList.setInput(input);
         inputAndUrlList.setInput(input);
         switch (uploadType) {
         switch (uploadType) {
             case UPLOAD_TYPE_NONE:
             case UPLOAD_TYPE_NONE:
@@ -190,14 +190,19 @@ public class ActPublishArticle extends BaseActivity {
         }
         }
     }
     }
 
 
+    //
+    private boolean isErrorVideo() {
+        return video == null || video.getFilePath() == null || !new File(video.getFilePath()).exists();
+    }
+
     private void uploadFile() {
     private void uploadFile() {
         final DialogProgress dialogProgress = DialogProgress.showDialog(this);
         final DialogProgress dialogProgress = DialogProgress.showDialog(this);
         uploadType = UPLOAD_TYPE_START;
         uploadType = UPLOAD_TYPE_START;
-        QiNiuUploadUtil.getInstance().uploadFile(imageCropBean.getOriginalPath()/*, QiNiuUploadUtil.TAG_VIDEO*/, new UpCompletionHandler() {
+        QiNiuUploadUtil.getInstance().uploadFile(video.getFilePath()/*, QiNiuUploadUtil.TAG_VIDEO*/, new UpCompletionHandler() {
             @Override
             @Override
             public void complete(String key, ResponseInfo info, JSONObject response) {
             public void complete(String key, ResponseInfo info, JSONObject response) {
                 LogUtil.println("qiniu", key, info, response);
                 LogUtil.println("qiniu", key, info, response);
-                if(info == null){
+                if (info == null) {
                     ViewUtil.setText(dialogProgress.getTextView(), "上传失败");
                     ViewUtil.setText(dialogProgress.getTextView(), "上传失败");
                     ViewUtil.dismiss(dialogProgress, 1);
                     ViewUtil.dismiss(dialogProgress, 1);
                     uploadType = UPLOAD_TYPE_FAIL;
                     uploadType = UPLOAD_TYPE_FAIL;
@@ -214,7 +219,7 @@ public class ActPublishArticle extends BaseActivity {
                         e.printStackTrace();
                         e.printStackTrace();
                     }
                     }
                     jsonObject.put("resource", url);
                     jsonObject.put("resource", url);
-                    jsonObject.put("cover", url + "?vframe/jpg/offset/0");
+                    jsonObject.put("cover", String.format(Locale.CHINA, "%s?vframe/jpg/offset/0&w=%d&h=%d", url, video.getWidth(), video.getHeight()));
                     publishArticle(dialogProgress);
                     publishArticle(dialogProgress);
                 } else {
                 } else {
                     ViewUtil.setText(dialogProgress.getTextView(), "上传失败");
                     ViewUtil.setText(dialogProgress.getTextView(), "上传失败");
@@ -224,12 +229,12 @@ public class ActPublishArticle extends BaseActivity {
                 }
                 }
                 LogUtil.println("qiniu", key + ",\r\n " + info + ",\r\n " + response);
                 LogUtil.println("qiniu", key + ",\r\n " + info + ",\r\n " + response);
             }
             }
-        },new UpProgressHandler(){
-                    public void progress(String key, double percent){
-                        LogUtil.println("qiniu", key + ": " + percent);
-                        ViewUtil.setText(dialogProgress.getTextView(), String.format(Locale.CHINA, "%d%%", (int)(percent * 100)));
-                    }
-                });
+        }, new UpProgressHandler() {
+            public void progress(String key, double percent) {
+                LogUtil.println("qiniu", key + ": " + percent);
+                ViewUtil.setText(dialogProgress.getTextView(), String.format(Locale.CHINA, "%d%%", (int) (percent * 100)));
+            }
+        });
     }
     }
 
 
     private com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
     private com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
@@ -243,6 +248,13 @@ public class ActPublishArticle extends BaseActivity {
                     public void onNext(BaseMessage baseMessage) {
                     public void onNext(BaseMessage baseMessage) {
                         ViewUtil.setText(dialogProgress.getTextView(), "发布成功");
                         ViewUtil.setText(dialogProgress.getTextView(), "发布成功");
                         ViewUtil.dismiss(dialogProgress, 1);
                         ViewUtil.dismiss(dialogProgress, 1);
+                        ViewUtil.delay(new AbsObserver<Integer>() {
+                            @Override
+                            public void onNext(Integer integer) {
+                                ActionUtil.getInstance().addNextAction(FgtArticleVideo.class.getSimpleName(), IRefresh.class.getSimpleName());
+                                ActPublishArticle.this.finish();
+                            }
+                        },1);
                     }
                     }
 
 
                     @Override
                     @Override
@@ -257,10 +269,16 @@ public class ActPublishArticle extends BaseActivity {
     public @interface Type {
     public @interface Type {
     }
     }
 
 
-    //添加话题
     @Override
     @Override
-    public void doNextAction(Object action) {
-        if(action instanceof DiscoveryTopic)
-            jsonObject.put("topic_id", ((DiscoveryTopic) action).getId());
+    protected boolean needRegisterEventBus() {
+        return true;
+    }
+    private Video video;
+    @Subscribe
+    public void onEventMainThread(Video data) {
+        this.video = data;
+        ListUtil.removeNull(inputAndUrlList.getList());
+        inputAndUrlList.getList().add(video.getFilePath());
+        ViewUtil.notifyDataSetChanged(recyclerView);
     }
     }
 }
 }

+ 6 - 1
app/src/main/java/com/sheep/gamegroup/view/adapter/AdpVideo.java

@@ -4,6 +4,8 @@ import android.view.View;
 import android.widget.ImageView;
 import android.widget.ImageView;
 import android.widget.TextView;
 import android.widget.TextView;
 
 
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
 import com.kfzs.appstore.utils.adapter.recyclerview.RecyclerViewAdapter;
 import com.kfzs.appstore.utils.adapter.recyclerview.RecyclerViewAdapter;
 import com.kfzs.appstore.utils.adapter.recyclerview.ViewHolder;
 import com.kfzs.appstore.utils.adapter.recyclerview.ViewHolder;
 import com.kfzs.duanduan.utils.NumberFormatUtils;
 import com.kfzs.duanduan.utils.NumberFormatUtils;
@@ -13,6 +15,7 @@ import com.sheep.gamegroup.util.TimeUtil;
 import com.sheep.gamegroup.util.ViewUtil;
 import com.sheep.gamegroup.util.ViewUtil;
 import com.sheep.jiuyan.samllsheep.R;
 import com.sheep.jiuyan.samllsheep.R;
 import com.sheep.jiuyan.samllsheep.SheepApp;
 import com.sheep.jiuyan.samllsheep.SheepApp;
+import com.sheep.jiuyan.samllsheep.utils.G;
 
 
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
@@ -27,12 +30,14 @@ public class AdpVideo extends RecyclerViewAdapter<DiscoveryVideo> {
         super(SheepApp.getInstance(), layoutId, datas);
         super(SheepApp.getInstance(), layoutId, datas);
     }
     }
 
 
+    private int width = (G.WIDTH - G.getRealPix(48)) / 2;
+
     @Override
     @Override
     public void convert(ViewHolder viewHolder, final DiscoveryVideo item, int position) {
     public void convert(ViewHolder viewHolder, final DiscoveryVideo item, int position) {
         ImageView item_video_cover = viewHolder.itemView.findViewById(R.id.item_video_cover);
         ImageView item_video_cover = viewHolder.itemView.findViewById(R.id.item_video_cover);
         TextView item_video_play_no_tv = viewHolder.itemView.findViewById(R.id.item_video_play_no_tv);
         TextView item_video_play_no_tv = viewHolder.itemView.findViewById(R.id.item_video_play_no_tv);
         TextView item_video_time_tv = viewHolder.itemView.findViewById(R.id.item_video_time_tv);
         TextView item_video_time_tv = viewHolder.itemView.findViewById(R.id.item_video_time_tv);
-        ViewUtil.setImage(item_video_cover, item.getCover());
+        ViewUtil.setImageWH(item_video_cover, item.getCover(), width);
         ViewUtil.setVisibility(item_video_play_no_tv, item.getPlay() > 0);
         ViewUtil.setVisibility(item_video_play_no_tv, item.getPlay() > 0);
         ViewUtil.setText(item_video_play_no_tv, String.format(Locale.CHINA, "%s次播放", NumberFormatUtils.getText(item.getPlay())));
         ViewUtil.setText(item_video_play_no_tv, String.format(Locale.CHINA, "%s次播放", NumberFormatUtils.getText(item.getPlay())));
         ViewUtil.setText(item_video_time_tv, TimeUtil.getDurationText(item.getDuration()));
         ViewUtil.setText(item_video_time_tv, TimeUtil.getDurationText(item.getDuration()));

+ 77 - 19
app/src/main/java/com/sheep/gamegroup/view/customview/VideoFramesView.java

@@ -2,6 +2,7 @@ package com.sheep.gamegroup.view.customview;
 
 
 import android.annotation.SuppressLint;
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.LayoutInflater;
@@ -9,6 +10,9 @@ import android.view.MotionEvent;
 import android.view.View;
 import android.view.View;
 import android.widget.RelativeLayout;
 import android.widget.RelativeLayout;
 
 
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.BaseViewHolder;
+import com.sheep.gamegroup.model.entity.Video;
 import com.sheep.gamegroup.util.LogUtil;
 import com.sheep.gamegroup.util.LogUtil;
 import com.sheep.gamegroup.util.MediaMetadataRetrieverUtil;
 import com.sheep.gamegroup.util.MediaMetadataRetrieverUtil;
 import com.sheep.jiuyan.samllsheep.R;
 import com.sheep.jiuyan.samllsheep.R;
@@ -56,19 +60,24 @@ public class VideoFramesView extends RelativeLayout {
             @Override
             @Override
             public boolean onTouch(View view, MotionEvent event) {
             public boolean onTouch(View view, MotionEvent event) {
                 float maxX = line_end.getX();
                 float maxX = line_end.getX();
+                float minX = maxX - (firstEndX - firstStartX);//结束位置 - 可以设置的长度
                 switch (event.getAction()) {
                 switch (event.getAction()) {
                     case MotionEvent.ACTION_DOWN:
                     case MotionEvent.ACTION_DOWN:
                         lastEventX = event.getX();
                         lastEventX = event.getX();
                         break;
                         break;
                     case MotionEvent.ACTION_MOVE:
                     case MotionEvent.ACTION_MOVE:
-                        float mx = view.getX() + event.getX() - lastEventX;
-                        if (mx < firstStartX)
-                            mx = firstStartX;
+                        float mx = Math.max(firstStartX, view.getX() + event.getX() - lastEventX);
                         if (mx > maxX)
                         if (mx > maxX)
                             mx = maxX;
                             mx = maxX;
-                        view.setX(mx);
+                        if (mx < minX) {
+                            maxX += mx - minX;
+                            line_end.setX(maxX);
+                            view.setX(mx);
+                        } else {
+                            view.setX(mx);
+                        }
                         if (onTimeChangeListener != null) {
                         if (onTimeChangeListener != null) {
-                            onTimeChangeListener.call((maxX - mx) / (rvW - lineW));
+                            onTimeChangeListener.call((maxX - mx) * video.getDuration() / (rvW - lineW));
                         }
                         }
                         break;
                         break;
                     case MotionEvent.ACTION_UP:
                     case MotionEvent.ACTION_UP:
@@ -87,19 +96,25 @@ public class VideoFramesView extends RelativeLayout {
             @Override
             @Override
             public boolean onTouch(View view, MotionEvent event) {
             public boolean onTouch(View view, MotionEvent event) {
                 float minX = line_start.getX();
                 float minX = line_start.getX();
+                float maxX = firstEndX - firstStartX + minX;
+                float endX = firstStartX + rvW - lineW;
                 switch (event.getAction()) {
                 switch (event.getAction()) {
                     case MotionEvent.ACTION_DOWN:
                     case MotionEvent.ACTION_DOWN:
                         lastEventX = event.getX();
                         lastEventX = event.getX();
                         break;
                         break;
                     case MotionEvent.ACTION_MOVE:
                     case MotionEvent.ACTION_MOVE:
-                        float mx = view.getX() + event.getX() - lastEventX;
+                        float mx = Math.min(view.getX() + event.getX() - lastEventX, endX);
                         if (mx < minX)
                         if (mx < minX)
                             mx = minX;
                             mx = minX;
-                        if (mx > firstEndX)
-                            mx = firstEndX;
-                        view.setX(mx);
+                        if (mx > maxX) {
+                            minX += mx - maxX;
+                            line_start.setX(minX);
+                            view.setX(mx);
+                        } else {
+                            view.setX(mx);
+                        }
                         if (onTimeChangeListener != null) {
                         if (onTimeChangeListener != null) {
-                            onTimeChangeListener.call((mx - minX) / (rvW - lineW));
+                            onTimeChangeListener.call((mx - minX) * video.getDuration() / (rvW - lineW));
                         }
                         }
                         break;
                         break;
                     case MotionEvent.ACTION_UP:
                     case MotionEvent.ACTION_UP:
@@ -129,7 +144,7 @@ public class VideoFramesView extends RelativeLayout {
     //结尾线的进度
     //结尾线的进度
     public float getEndPercent() {
     public float getEndPercent() {
         if (line_end != null && recyclerView != null) {
         if (line_end != null && recyclerView != null) {
-            return 1.0f - ((firstEndX - line_end.getX()) / (rvW - lineW));
+            return 1.0f - ((firstStartX + rvW - lineW - line_end.getX()) / (rvW - lineW));
         }
         }
         return 0;
         return 0;
     }
     }
@@ -152,19 +167,19 @@ public class VideoFramesView extends RelativeLayout {
         return mediaMetadataRetrieverUtil;
         return mediaMetadataRetrieverUtil;
     }
     }
 
 
+    private Video video;
     /**
     /**
      * 显示视频帧图片列表
      * 显示视频帧图片列表
      *
      *
-     * @param videoPath 视频文件路径
-     * @param duration  视频文件时长
+     * @param data 视频数据,包括地址与时长,宽高等
      * @return
      * @return
      */
      */
-    public VideoFramesView initVideo(String videoPath, long duration) {
-        if (videoPath == null) {
+    public VideoFramesView initVideo(Video data) {
+        if (data == null || data.getFilePath() == null) {
             LogUtil.println(VideoFramesView.class.getSimpleName(), "showList", "error", "videoPath is null");
             LogUtil.println(VideoFramesView.class.getSimpleName(), "showList", "error", "videoPath is null");
             return this;
             return this;
         }
         }
-        File videoFile = new File(videoPath);
+        File videoFile = new File(data.getFilePath());
         if (!videoFile.exists()) {
         if (!videoFile.exists()) {
             LogUtil.println(VideoFramesView.class.getSimpleName(), "showList", "error", "videoFile not exists");
             LogUtil.println(VideoFramesView.class.getSimpleName(), "showList", "error", "videoFile not exists");
             return this;
             return this;
@@ -173,13 +188,14 @@ public class VideoFramesView extends RelativeLayout {
             LogUtil.println(VideoFramesView.class.getSimpleName(), "showList", "error", "videoFile cant read");
             LogUtil.println(VideoFramesView.class.getSimpleName(), "showList", "error", "videoFile cant read");
             return this;
             return this;
         }
         }
-        if (duration < 1) {
+        if (data.getDuration() < 1) {
             LogUtil.println(VideoFramesView.class.getSimpleName(), "showList", "error", "duration < 1");
             LogUtil.println(VideoFramesView.class.getSimpleName(), "showList", "error", "duration < 1");
             return this;
             return this;
         }
         }
         if (mediaMetadataRetrieverUtil == null) {
         if (mediaMetadataRetrieverUtil == null) {
-            mediaMetadataRetrieverUtil = new MediaMetadataRetrieverUtil(videoPath, duration);
+            mediaMetadataRetrieverUtil = new MediaMetadataRetrieverUtil(data.getFilePath(), data.getDuration());
         }
         }
+        this.video = data;
         return this;
         return this;
     }
     }
 
 
@@ -203,8 +219,50 @@ public class VideoFramesView extends RelativeLayout {
                 firstEndX = line_end.getX();
                 firstEndX = line_end.getX();
                 lineW = line_start.getWidth();
                 lineW = line_start.getWidth();
                 rvW = recyclerView.getWidth();
                 rvW = recyclerView.getWidth();
-                onTimeChangeListener.call(1.0f);
+                long duration = mediaMetadataRetrieverUtil.getDuration();
+                if(maxVideoDuration > 0) {
+                    if(duration > maxVideoDuration) {
+                        firstEndX = firstStartX + ((maxVideoDuration * 1.0f / duration) * (rvW - lineW));
+                        line_end.setX(firstEndX);
+                    }
+                }
+                onTimeChangeListener.call((float) duration);
             }
             }
         }, 100);
         }, 100);
     }
     }
+
+    //开始的时间,单位秒
+    public long getStartPoint() {
+        return (long) (getStartPercent() * mediaMetadataRetrieverUtil.getDuration());
+    }
+
+    //总共的时长,单位秒
+    public long getLineDuration() {
+        return (long) (getPercent() * mediaMetadataRetrieverUtil.getDuration());
+    }
+    //结束的时间,单位秒
+    public long getEndPoint() {
+        return (long) (getEndPercent() * mediaMetadataRetrieverUtil.getDuration());
+    }
+
+    //最大剪切视频时长
+    private long maxVideoDuration;
+    public VideoFramesView setMaxDuration(long maxVideoDuration) {
+        this.maxVideoDuration = maxVideoDuration;
+        return this;
+    }
+    public void onDestroy(){
+        if(recyclerView != null && recyclerView.getAdapter() instanceof BaseQuickAdapter){
+            for (int i = 0; i < recyclerView.getAdapter().getItemCount(); i++) {
+                Object object = ((BaseQuickAdapter) recyclerView.getAdapter()).getItem(i);
+                if(object instanceof Bitmap){
+                    try {
+                        ((Bitmap) object).recycle();
+                    } catch (Exception e){
+                        e.printStackTrace();
+                    }
+                }
+            }
+        }
+    }
 }
 }

+ 8 - 1
app/src/main/java/com/sheep/gamegroup/view/fragment/BaseListFragment.java

@@ -98,7 +98,7 @@ public abstract class BaseListFragment<T> extends BaseFragment implements IRefre
     public void loadMoreData() {
     public void loadMoreData() {
         if (!loadMore) {
         if (!loadMore) {
             loadMore = true;
             loadMore = true;
-            if (ListUtil.size(list) >= per_page * page) {
+            if (hasMore()) {
                 page += 1;
                 page += 1;
                 initNetAndData();
                 initNetAndData();
             } else {
             } else {
@@ -109,6 +109,13 @@ public abstract class BaseListFragment<T> extends BaseFragment implements IRefre
             view_list.loadMoreComplete();
             view_list.loadMoreComplete();
         }
         }
     }
     }
+    //还有数据没有获取
+    protected boolean hasMore() {
+        if(lastMessage != null && lastMessage.getTotal() > 0){
+            return lastMessage.getTotal() > ListUtil.size(list);
+        }
+        return ListUtil.size(list) >= per_page * page;
+    }
 
 
     public void setNoMore(boolean noMore) {
     public void setNoMore(boolean noMore) {
         this.noMore = noMore;
         this.noMore = noMore;

+ 18 - 1
app/src/main/java/com/sheep/gamegroup/view/fragment/BaseListFragment2.java

@@ -3,6 +3,7 @@ package com.sheep.gamegroup.view.fragment;
 import android.app.Activity;
 import android.app.Activity;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView;
+import android.text.TextUtils;
 import android.view.View;
 import android.view.View;
 
 
 import com.jcodecraeer.xrecyclerview.XRecyclerView;
 import com.jcodecraeer.xrecyclerview.XRecyclerView;
@@ -108,7 +109,7 @@ public abstract class BaseListFragment2<T> extends BaseFragment implements IRefr
     public void loadMoreData() {
     public void loadMoreData() {
         if (!loadMore) {
         if (!loadMore) {
             loadMore = true;
             loadMore = true;
-            if (ListUtil.size(list) >= per_page * page) {
+            if (hasMore()) {
                 page += 1;
                 page += 1;
                 initData();
                 initData();
             } else {
             } else {
@@ -119,6 +120,14 @@ public abstract class BaseListFragment2<T> extends BaseFragment implements IRefr
             view_list.loadMoreComplete();
             view_list.loadMoreComplete();
         }
         }
     }
     }
+    //还有数据没有获取
+    protected boolean hasMore() {
+        if(lastMessage != null && lastMessage.getTotal() > 0){
+            return lastMessage.getTotal() > ListUtil.size(list);
+        }
+        return ListUtil.size(list) >= per_page * page;
+    }
+
 
 
     public void setNoMore(boolean noMore) {
     public void setNoMore(boolean noMore) {
         this.noMore = noMore;
         this.noMore = noMore;
@@ -270,4 +279,12 @@ public abstract class BaseListFragment2<T> extends BaseFragment implements IRefr
     public void notifyData(){
     public void notifyData(){
 
 
     }
     }
+    @Override
+    public void doNextAction(Object action) {
+        if(action instanceof String) {
+            if(TextUtils.equals((String) action, IRefresh.class.getSimpleName())){
+                refreshData();
+            }
+        }
+    }
 }
 }

+ 8 - 1
app/src/main/java/com/sheep/gamegroup/view/fragment/BaseListFragment3.java

@@ -88,7 +88,7 @@ public abstract class BaseListFragment3<T> extends BaseRefreshLoadMoreFragment{
 
 
     //加载更多数据
     //加载更多数据
     public void loadMoreData() {
     public void loadMoreData() {
-        if (ListUtil.size(list) >= per_page * page) {
+        if (hasMore()) {
             page += 1;
             page += 1;
             initData();
             initData();
         } else {
         } else {
@@ -96,6 +96,13 @@ public abstract class BaseListFragment3<T> extends BaseRefreshLoadMoreFragment{
             refreshOrLoadMoreComplete();
             refreshOrLoadMoreComplete();
         }
         }
     }
     }
+    //还有数据没有获取
+    protected boolean hasMore() {
+        if(lastMessage != null && lastMessage.getTotal() > 0){
+            return lastMessage.getTotal() > ListUtil.size(list);
+        }
+        return ListUtil.size(list) >= per_page * page;
+    }
 
 
     protected List<T> list = ListUtil.emptyList();
     protected List<T> list = ListUtil.emptyList();
     protected List<T> lastCacheList = ListUtil.emptyList();
     protected List<T> lastCacheList = ListUtil.emptyList();

+ 8 - 1
app/src/main/java/com/sheep/gamegroup/view/fragment/BaseListFragment4.java

@@ -55,13 +55,20 @@ public abstract class BaseListFragment4<T> extends BaseFragment {
 
 
     //加载更多数据
     //加载更多数据
     public void loadMoreData() {
     public void loadMoreData() {
-        if (ListUtil.size(list) >= per_page * page) {
+        if (hasMore()) {
             page += 1;
             page += 1;
             initData();
             initData();
         } else {
         } else {
             setNoMore(true);
             setNoMore(true);
         }
         }
     }
     }
+    //还有数据没有获取
+    protected boolean hasMore() {
+        if(lastMessage != null && lastMessage.getTotal() > 0){
+            return lastMessage.getTotal() > ListUtil.size(list);
+        }
+        return ListUtil.size(list) >= per_page * page;
+    }
 
 
     protected void setNoMore(boolean noMore) {
     protected void setNoMore(boolean noMore) {
         if (noMore)
         if (noMore)

+ 8 - 1
app/src/main/java/com/sheep/gamegroup/view/fragment/BaseListFragment5.java

@@ -115,7 +115,7 @@ public abstract class BaseListFragment5<T> extends BaseFragment implements IRefr
     public void loadMoreData() {
     public void loadMoreData() {
         if (!loadMore) {
         if (!loadMore) {
             loadMore = true;
             loadMore = true;
-            if (ListUtil.size(list) >= per_page * page) {
+            if (hasMore()) {
                 page += 1;
                 page += 1;
                 initData();
                 initData();
             } else {
             } else {
@@ -125,6 +125,13 @@ public abstract class BaseListFragment5<T> extends BaseFragment implements IRefr
             finishRefresh();
             finishRefresh();
         }
         }
     }
     }
+    //还有数据没有获取
+    protected boolean hasMore() {
+        if(lastMessage != null && lastMessage.getTotal() > 0){
+            return lastMessage.getTotal() > ListUtil.size(list);
+        }
+        return ListUtil.size(list) >= per_page * page;
+    }
 
 
     protected void setNoMore(boolean noMore) {
     protected void setNoMore(boolean noMore) {
         if (noMore) {
         if (noMore) {

+ 0 - 1
app/src/main/java/com/sheep/gamegroup/view/fragment/FgtArticleVideo.java

@@ -76,5 +76,4 @@ public class FgtArticleVideo extends BaseListFragment2<DiscoveryVideo> {
         }
         }
     }
     }
 
 
-
 }
 }

+ 2 - 6
app/src/main/java/com/sheep/gamegroup/view/fragment/FgtDiscoveryTopic.java

@@ -5,15 +5,13 @@ import android.view.View;
 import com.chad.library.adapter.base.BaseQuickAdapter;
 import com.chad.library.adapter.base.BaseQuickAdapter;
 import com.chad.library.adapter.base.BaseViewHolder;
 import com.chad.library.adapter.base.BaseViewHolder;
 import com.sheep.gamegroup.absBase.ApiRefresh;
 import com.sheep.gamegroup.absBase.ApiRefresh;
-import com.sheep.gamegroup.absBase.BaseActivity;
 import com.sheep.gamegroup.model.api.ApiService;
 import com.sheep.gamegroup.model.api.ApiService;
 import com.sheep.gamegroup.model.entity.BaseMessage;
 import com.sheep.gamegroup.model.entity.BaseMessage;
 import com.sheep.gamegroup.model.entity.DiscoveryTopic;
 import com.sheep.gamegroup.model.entity.DiscoveryTopic;
-import com.sheep.gamegroup.util.ActionUtil;
-import com.sheep.gamegroup.view.activity.ActPublishArticle;
 import com.sheep.jiuyan.samllsheep.R;
 import com.sheep.jiuyan.samllsheep.R;
 
 
 import org.afinal.simplecache.ApiKey;
 import org.afinal.simplecache.ApiKey;
+import org.greenrobot.eventbus.EventBus;
 
 
 import java.util.List;
 import java.util.List;
 
 
@@ -77,9 +75,7 @@ public class FgtDiscoveryTopic extends BaseListFragment6<DiscoveryTopic> {
             public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
             public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
                 DiscoveryTopic item = mApiRefresh.getItem(position);
                 DiscoveryTopic item = mApiRefresh.getItem(position);
                 if(item != null) {
                 if(item != null) {
-                    ActionUtil.getInstance().addNextAction(ActPublishArticle.class.getSimpleName(), item);
-                    if(activity instanceof BaseActivity)
-                        ((BaseActivity) activity).doNextAction(item);
+                    EventBus.getDefault().post(item);
                 }
                 }
             }
             }
         });
         });

+ 34 - 0
app/src/main/java/com/sheep/jiuyan/samllsheep/base/BaseFragment.java

@@ -7,11 +7,18 @@ import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup;
 
 
+import com.sheep.gamegroup.absBase.AbsObserver;
+import com.sheep.gamegroup.util.ActionUtil;
 import com.sheep.gamegroup.view.dialog.DialogLoading;
 import com.sheep.gamegroup.view.dialog.DialogLoading;
 import com.trello.rxlifecycle2.components.support.RxFragment;
 import com.trello.rxlifecycle2.components.support.RxFragment;
 
 
+import java.util.concurrent.TimeUnit;
+
 import butterknife.ButterKnife;
 import butterknife.ButterKnife;
 import butterknife.Unbinder;
 import butterknife.Unbinder;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
 
 
 /**
 /**
  * @ Created by Dlg
  * @ Created by Dlg
@@ -163,4 +170,31 @@ public abstract class BaseFragment extends RxFragment {
     public boolean userButterKnife() {
     public boolean userButterKnife() {
         return true;
         return true;
     }
     }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        checkNextAction(this.getClass().getSimpleName());
+    }
+
+    protected boolean checkNextAction(String key) {
+        final Object action = ActionUtil.getInstance().getAction(key);
+        if (action != null) {
+            //延时一会儿,不然有可能操作会无效
+            Observable.just(1).delay(50L, TimeUnit.MILLISECONDS)
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .subscribe(new AbsObserver<Integer>() {
+                        @Override
+                        public void onNext(Integer integer) {
+                            doNextAction(action);
+                        }
+                    });
+            return true;
+        }
+        return false;
+    }
+    public void doNextAction(Object action) {
+
+    }
 }
 }