android 无缝连续播放视频
最近在做视频合成的时候要求把用户选择的视频能够连续预览,第一想的是用户在预览的时候把视频拼接后在预览,结果发现拼接的时间太久了,这种方式不行,结果搞了一天用mediaplayer多少个视频生成多少个mediaplayer然后预备起,这样就可以无缝播放视频了。
看图说话
下面是代码 话不多说
public class VideoPreviewView extends SurfaceView implements MediaPlayerWrapper.IMediaCallback,SurfaceHolder.Callback {
private MediaPlayerWrapper mMediaPlayer;
/**视频播放状态的回调*/
private MediaPlayerWrapper.IMediaCallback callback;
public VideoPreviewView(Context context) {
this(context,null);
}
public VideoPreviewView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
mMediaPlayer = new MediaPlayerWrapper();
mMediaPlayer.setOnCompletionListener(this);
getHolder().addCallback(this);
}
/**设置视频的播放地址*/
public void setVideoPath(List<String> paths){
mMediaPlayer.setDataSource(paths);
}
/**是否循环播放*/
public void setLooping(boolean isLooping) {
mMediaPlayer.setLooping(isLooping);
}
public void play(){
mMediaPlayer.play();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Surface surface = holder.getSurface();
mMediaPlayer.setSurface(surface);
try {
mMediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
// mMediaPlayer.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void onDestroy(){
if (mMediaPlayer != null) {
if(mMediaPlayer.isPlaying()){
mMediaPlayer.stop();
}
mMediaPlayer.release();
}
}
public void onTouch(final MotionEvent event){
}
@Override
public void onVideoPrepare() {
if (callback!= null){
callback.onVideoPrepare();
}
}
@Override
public void onVideoStart() {
if(callback!=null){
callback.onVideoStart();
}
}
public int getVideoWidth(){
return mMediaPlayer.getVideoWidth();
}
public int getVideoHeight(){
return mMediaPlayer.getVideoHeight();
}
@Override
public void onVideoPause() {
if (callback != null){
callback.onVideoPause();
}
}
@Override
public void onCompletion(MediaPlayer mp) {
if (callback != null){
callback.onCompletion(mp);
}
}
@Override
public void onVideoChanged(final VideoInfo info) {
if(callback!=null){
callback.onVideoChanged(info);
}
}
/**
* isPlaying now
* */
public boolean isPlaying(){
return mMediaPlayer.isPlaying();
}
/**
* pause play
* */
public void pause(){
if (mMediaPlayer != null) {
mMediaPlayer.pause();
}
}
/**
* start play video
* */
public void setVolume(float leftVolume, float rightVolume){
mMediaPlayer.setVolume(leftVolume);
}
/**
* start play video
* */
public void start(){
mMediaPlayer.start();
}
/**
* 跳转到指定的时间点
* */
public void seekTo(int time) {
mMediaPlayer.seekTo(time);
}
/**
* 获取视频的长度
* */
public int getVideoDuration(){
return mMediaPlayer.getVideoDuration();
}
/**
* 获取当前视频的长度
* */
public int getCurPosition(){
return mMediaPlayer.getCurPosition();
}
public void setIMediaCallback(MediaPlayerWrapper.IMediaCallback callback){
this.callback=callback;
}
}
下面是播放控制器
/**
* Created by Administrator on 2020/6/29 0029.
* desc:MediaPlayer的代理类 支持循环播放多个视频
*/
public class MediaPlayerWrapper implements MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, MediaPlayer.OnPreparedListener {
private MediaPlayer mCurMediaPlayer; //current player
private List<MediaPlayer> mPlayerList; //player list
private List<String> mSrcList; //video src list
private List<VideoInfo> mInfoList; //video info list
private Surface surface;
private IMediaCallback mCallback;
private int curIndex; //current player index
public MediaPlayerWrapper() {
mPlayerList = new ArrayList<>();
mInfoList = new ArrayList<>();
}
public void setOnCompletionListener(IMediaCallback callback) {
this.mCallback = callback;
}
/**
* 设置播放源
*
* @param dataSource
*/
public void setDataSource(List<String> dataSource) {
this.mSrcList = dataSource;
MediaMetadataRetriever retr = new MediaMetadataRetriever();
for (int i = 0; i < dataSource.size(); i++) {
VideoInfo info = new VideoInfo();
String path = dataSource.get(i);
retr.setDataSource(path);
String rotation = retr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
String width = retr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
String height = retr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
String duration = retr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
info.path = path;
try {
info.rotation = Integer.parseInt(rotation);
info.width = Integer.parseInt(width);
info.height = Integer.parseInt(height);
info.duration = Integer.parseInt(duration);
} catch (NumberFormatException e) {
e.printStackTrace();
} finally {
mInfoList.add(info);
}
}
}
public List<VideoInfo> getVideoInfo() {
return mInfoList;
}
public void setSurface(Surface surface) {
this.surface = surface;
}
public void prepare() throws IOException {
for (int i = 0; i < mSrcList.size(); i++) {
MediaPlayer player = new MediaPlayer();
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnCompletionListener(this);
player.setOnErrorListener(this);
player.setOnPreparedListener(this);
player.setDataSource(mSrcList.get(i));
player.prepare();
mPlayerList.add(player);
if (i == 0) {
mCurMediaPlayer = player;
if (mCallback != null) {
mCallback.onVideoChanged(mInfoList.get(0));
}
}
}
}
public VideoInfo getPlayInfo() {
return mInfoList.get(curIndex);
}
public void play() {
mCurMediaPlayer.start();
}
public void start() {
if (surface.isValid()) {
mCurMediaPlayer.setSurface(surface);
mCurMediaPlayer.start();
if (mCallback != null) {
mCallback.onVideoStart();
}
}
}
public void setLooping(boolean isLooping) {
mCurMediaPlayer.setLooping(isLooping);
}
public void setSpeed(int speed) {
if (AndroidUtil.isMarshMallowOrLater()) {
PlaybackParams playbackParams = mCurMediaPlayer.getPlaybackParams();
playbackParams.setSpeed(speed);
mCurMediaPlayer.setPlaybackParams(playbackParams);
} else {
ToastUtils.showToast("手机版本过低,暂不支持倍速播放预览");
}
}
public void pause() {
if (mCurMediaPlayer != null) {
mCurMediaPlayer.pause();
if (mCallback != null) {
mCallback.onVideoPause();
}
}
}
public int getVideoDuration() {
if (mSrcList.size() == 0) {
throw new IllegalStateException("please set video src first");
}
int duration = 0;
for (int i = 0; i < mSrcList.size(); i++) {
duration += mInfoList.get(i).duration;
}
return duration;
}
public int getCurPosition() {
int position = 0;
for (int i = 0; i < curIndex; i++) {
position += mInfoList.get(i).duration;
}
position += mCurMediaPlayer.getCurrentPosition();
return position;
}
public int getVideoWidth() {
return mCurMediaPlayer.getVideoWidth();
}
public int getVideoHeight() {
return mCurMediaPlayer.getVideoHeight();
}
public void seekTo(int time) {
int posTime = 0;
for (int i = 0; i < mInfoList.size(); i++) {
VideoInfo mVideoInfo = mInfoList.get(i);
if (mVideoInfo.duration + posTime > time) {
curIndex = i;
if (mPlayerList.get(curIndex) != mCurMediaPlayer) {
mCurMediaPlayer.pause();
}
switchPlayer(mCurMediaPlayer);
mCurMediaPlayer.seekTo(time - posTime);
break;
}
posTime += mVideoInfo.duration;
}
}
public boolean isPlaying() {
if (mCurMediaPlayer != null) {
return mCurMediaPlayer.isPlaying();
} else {
return false;
}
}
@Override
public void onCompletion(MediaPlayer mp) {
curIndex++;
if (curIndex >= mSrcList.size()) {
curIndex = 0;
if (mCallback != null) {
mCallback.onCompletion(mp);
}
}
if (mSrcList.size() >= 2) {
switchPlayer(mp);
mCurMediaPlayer.seekTo(0);
}
}
private void switchPlayer(MediaPlayer mp) {
mp.setSurface(null);
if (mCallback != null) {
mCallback.onVideoChanged(mInfoList.get(curIndex));
}
mCurMediaPlayer = mPlayerList.get(curIndex);
mCurMediaPlayer.setSurface(surface);
mCurMediaPlayer.start();
}
public void stop() {
mCurMediaPlayer.stop();
}
public void release() {
for (int i = 0; i < mPlayerList.size(); i++) {
mPlayerList.get(i).release();
}
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
return false;
}
@Override
public void onPrepared(MediaPlayer mp) {
if (mCallback != null) {
mCallback.onVideoPrepare();
}
}
public void setVolume(float volume) {
for (int i = 0; i < mPlayerList.size(); i++) {
MediaPlayer mediaPlayer = mPlayerList.get(i);
mediaPlayer.setVolume(volume, volume);
}
}
public int[] getVideoWH() {
int[] ints = new int[2];
int videoWidth = mCurMediaPlayer.getVideoWidth();
int videoHeight = mCurMediaPlayer.getVideoHeight();
ints[0] = videoWidth;
ints[1] = videoHeight;
return ints;
}
public interface IMediaCallback {
/**
* callback when all the player prepared
*/
void onVideoPrepare();
/**
* callback when player start
*/
void onVideoStart();
/**
* callback when player pause
*/
void onVideoPause();
/**
* callback when all the videos have been played
*
* @param mp
*/
void onCompletion(MediaPlayer mp);
/**
* callback when video changed
*
* @param info
*/
void onVideoChanged(VideoInfo info);
}
}