前段时间拿到需求,需要在视频编辑模块中增加一个视频逆序播放的功能,就是从视频的最后一帧往前播放到第一帧。拿到需求时一脸懵逼,使用普通简洁的方式根本做不了,编码后的视频都是由I帧、P帧、B帧三种格式的帧组成的。思索良久后发现可以使用视频原始数据YUV数据来一帧帧绘制完成,废话不多说,直接上代码。
package com.yi.moments.capture;
import android.content.Intent;
import android.graphics.Bitmap;
import android.opengl.GLSurfaceView;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.yi.moments.constants.ConstKey;
import com.yi.moments.spore.ImageUtilEngine;
import com.yi.moments.spore.SporeRender;
import com.yi.moments.R;
import com.yi.moments.activity.BaseActivity;
import com.yi.moments.log.YiLog;
import com.yi.moments.util.ImageCompressUtil;
import com.yi.moments.util.ScreenUtil;
import com.yi.moments.util.ToastHelper;
import com.yi.moments.util.YUVUtils;
import com.yi.moments.view.VideoTimeSelectBar;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
public class VideoRecyclerPlayerActivity extends BaseActivity implements View.OnClickListener {
private static final String TAG = "VideoRecyclerPlayerActivity";
private static final int PICTURE_COUNT = 9; //截取图片的数量
private static final int VIDEO_PLAY_NORMAL = 0; //正序
private static final int VIDEO_PLAY_REVERSE = 1; //逆序
private static final int VIDEO_PLAY_RECYCLER = 2; //循环
private ImageView btnVideoPlayState;
private GLSurfaceView mProcessView;
private FrameLayout mProcessView_Layout;
private LinearLayout recyclerBackgroundLayout;
private VideoTimeSelectBar videoTimeSelectBar;
private int width = 720;
private int height = 1280;
private int videoPlayOrder;
private int sizePreFrame;
private int playStartIndex;
private int playEndIndex;
private int frameRate = 15;
private boolean isComposeVideo;
private String sourceDataPath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/yuvData.yuv";
private SporeRender mRender;
private ImageUtilEngine imageEngine;
private RecyclerThread recyclerThread;
private List<Bitmap> backgroundList = new ArrayList<>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_video_recycler_player);
imageEngine = new ImageUtilEngine();
btnVideoPlayState = findView(R.id.btnVideoPlayState);
mProcessView_Layout = findView(R.id.process_view_layout);
videoTimeSelectBar = findView(R.id.videoTimeSelectBar);
recyclerBackgroundLayout = findView(R.id.recyclerBackgroundLayout);
mProcessView = new GLSurfaceView(this);
mProcessView_Layout.addView(mProcessView, 0);
mRender = new SporeRender();
mProcessView.setRenderer(mRender);
btnVideoPlayState.setOnClickListener(this);
findView(R.id.imgEditBack).setOnClickListener(this);
findView(R.id.btnEditFinish).setOnClickListener(this);
videoTimeSelectBar.setOnSelectTimeLiatener(new VideoTimeSelectBar.OnSelectTimeListener() {
@Override
public void onUpdate(int startIndex, int endIndex) {
playStartIndex = startIndex;
playEndIndex = endIndex;
recyclerThread.setFrameIndex(playStartIndex);
}
});
Intent intent = getIntent();
width = intent.getIntExtra(ConstKey.KEY_YUV_DATA_WIDTH, width);
height = intent.getIntExtra(ConstKey.KEY_YUV_DATA_HEIGHT, height);
int mFrameRate = intent.getIntExtra(ConstKey.KEY_YUV_DATA_FRAME_RATE, frameRate);
if(mFrameRate > 0){
frameRate = mFrameRate;
}
String mSourceDataPath = intent.getStringExtra(ConstKey.KEY_YUV_DATA_PATH);
if(!TextUtils.isEmpty(mSourceDataPath)){
sourceDataPath = mSourceDataPath;
}
sizePreFrame = (int)(width * height * 1.5);
PictureAsyncTask asyncTask = new PictureAsyncTask();
asyncTask.execute(sourceDataPath);
}
private void showYUV(){
recyclerThread = new RecyclerThread(sizePreFrame);
recyclerThread.start();
}
@Override
protected void onResume() {
super.onResume();
if(recyclerThread != null){
recyclerThread.setSuspend(false);
}else {
showYUV();
}
}
@Override
protected void onPause() {
super.onPause()