package com.example.videotest; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.media.AudioManager; import android.media.MediaMetadataRetriever; import android.media.MediaPlayer; import android.media.MediaPlayer.OnBufferingUpdateListener; import android.os.Bundle; import android.os.Environment; import android.util.DisplayMetrics; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup.LayoutParams; import android.widget.Button; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Calendar; public class SurfaceViewTestActivity extends Activity implements MediaPlayer.OnCompletionListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, OnBufferingUpdateListener, OnClickListener { /** * */ private SurfaceView surfaceView; /** * surfaceView播放控制 */ private SurfaceHolder surfaceHolder; /** * 播放控制条 */ private SeekBar seekBar; /** * 暂停播放按钮 */ private Button playButton; /** * 重新播放按钮 */ private Button replayButton; /** * 截图按钮 */ private Button screenShotButton; /** * 改变视频大小button */ private Button videoSizeButton; /** * 加载进度显示条 */ private ProgressBar progressBar; /** * 播放视频 */ private MediaPlayer mediaPlayer; /** * 记录当前播放的位置 */ private int playPosition = -1; /** * seekBar是否自动拖动 */ private boolean seekBarAutoFlag = false; /** * 视频时间显示 */ private TextView vedioTiemTextView; /** * 播放总时间 */ private String videoTimeString; private long videoTimeLong; /** * 播放路径 */ private String pathString = "http://10.0.2.2:8080/oppo.mp4"; /** * 屏幕的宽度和高度 */ private int screenWidth, screenHeight; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_surface_view_test); // 获取屏幕的宽度和高度 DisplayMetrics displayMetrics = new DisplayMetrics(); this.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); screenWidth = displayMetrics.widthPixels; screenHeight = displayMetrics.heightPixels; initViews(); } public void initViews() { String path = null; if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { // 存在获取外部文件路径 path = Environment.getExternalStorageDirectory().getPath(); } else { // 不存在获取内部存储 path = Environment.getDataDirectory().getPath(); } // pathString = path + "/shen/x0200hkt1cg.p202.1.mp4"; // 初始化控件 surfaceView = (SurfaceView) findViewById(R.id.surfaceView); progressBar = (ProgressBar) findViewById(R.id.progressBar); seekBar = (SeekBar) findViewById(R.id.seekbar); playButton = (Button) findViewById(R.id.button_play); replayButton = (Button) findViewById(R.id.button_replay); vedioTiemTextView = (TextView) findViewById(R.id.textView_showTime); screenShotButton = (Button) findViewById(R.id.button_screenShot); videoSizeButton = (Button) findViewById(R.id.button_videoSize); // 设置surfaceHolder surfaceHolder = surfaceView.getHolder(); // 设置Holder类型,该类型表示surfaceView自己不管理缓存区,虽然提示过时,但最好还是要设置 surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // 设置surface回调 surfaceHolder.addCallback(new SurfaceCallback()); } // SurfaceView的callBack private class SurfaceCallback implements SurfaceHolder.Callback { public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } public void surfaceCreated(SurfaceHolder holder) { // surfaceView被创建 // 设置播放资源 playVideo(); } public void surfaceDestroyed(SurfaceHolder holder) { // surfaceView销毁,同时销毁mediaPlayer if (null != mediaPlayer) { mediaPlayer.release(); mediaPlayer = null; } } } /** * 播放视频 */ public void playVideo() { // 初始化MediaPlayer mediaPlayer = new MediaPlayer(); // 重置mediaPaly,建议在初始滑mediaplay立即调用。 mediaPlayer.reset(); // 设置声音效果 mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); // 设置播放完成监听 mediaPlayer.setOnCompletionListener(this); // 设置媒体加载完成以后回调函数。 mediaPlayer.setOnPreparedListener(this); // 错误监听回调函数 mediaPlayer.setOnErrorListener(this); // 设置缓存变化监听 mediaPlayer.setOnBufferingUpdateListener(this); try { // mediaPlayer.reset(); mediaPlayer.setDataSource(pathString); // mediaPlayer.setDataSource(this, uri); // mediaPlayer.setDataSource(SurfaceViewTestActivity.this, uri); // 设置异步加载视频,包括两种方式 prepare()同步,prepareAsync()异步 mediaPlayer.prepareAsync(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "加载视频错误!", Toast.LENGTH_LONG).show(); } } /** * 视频加载完毕监听 * * @param mp */ @Override public void onPrepared(MediaPlayer mp) { // 当视频加载完毕以后,隐藏加载进度条 progressBar.setVisibility(View.GONE); // 判断是否有保存的播放位置,防止屏幕旋转时,界面被重新构建,播放位置丢失。 if (Constants.playPosition >= 0) { mediaPlayer.seekTo(Constants.playPosition); Constants.playPosition = -1; // surfaceHolder.unlockCanvasAndPost(Constants.getCanvas()); } seekBarAutoFlag = true; // 设置控制条,放在加载完成以后设置,防止获取getDuration()错误 seekBar.setMax(mediaPlayer.getDuration()); // 设置播放时间 videoTimeLong = mediaPlayer.getDuration(); videoTimeString = getShowTime(videoTimeLong); vedioTiemTextView.setText("00:00:00/" + videoTimeString); // 设置拖动监听事件 seekBar.setOnSeekBarChangeListener(new SeekBarChangeListener()); // 设置按钮监听事件 // 重新播放 replayButton.setOnClickListener(SurfaceViewTestActivity.this); // 暂停和播放 playButton.setOnClickListener(SurfaceViewTestActivity.this); // 截图按钮 screenShotButton.setOnClickListener(SurfaceViewTestActivity.this); // 视频大小 videoSizeButton.setOnClickListener(SurfaceViewTestActivity.this); // 播放视频 mediaPlayer.start(); // 设置显示到屏幕 mediaPlayer.setDisplay(surfaceHolder); // 开启线程 刷新进度条 new Thread(runnable).start(); // 设置surfaceView保持在屏幕上 mediaPlayer.setScreenOnWhilePlaying(true); surfaceHolder.setKeepScreenOn(true); } /** * 滑动条变化线程 */ private Runnable runnable = new Runnable() { public void run() { // TODO Auto-generated method stub // 增加对异常的捕获,防止在判断mediaPlayer.isPlaying的时候,报IllegalStateException异常 try { while (seekBarAutoFlag) { /* * mediaPlayer不为空且处于正在播放状态时,使进度条滚动。 * 通过指定类名的方式判断mediaPlayer防止状态发生不一致 */ if (null != SurfaceViewTestActivity.this.mediaPlayer && SurfaceViewTestActivity.this.mediaPlayer.isPlaying()) { seekBar.setProgress(mediaPlayer.getCurrentPosition()); } } } catch (Exception e) { e.printStackTrace(); } } }; /** * seekBar拖动监听类 * * @author shenxiaolei */ @SuppressWarnings("unused") private class SeekBarChangeListener implements OnSeekBarChangeListener { public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { // TODO Auto-generated method stub if (progress >= 0) { // 如果是用户手动拖动控件,则设置视频跳转。 if (fromUser) { mediaPlayer.seekTo(progress); } // 设置当前播放时间 vedioTiemTextView.setText(getShowTime(progress) + "/" + videoTimeString); } } public void onStartTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub } public void onStopTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub } } /** * 按钮点击事件监听 */ public void onClick(View v) { // TODO Auto-generated method stub // 重新播放 if (v == replayButton) { // mediaPlayer不空,则直接跳转 if (null != mediaPlayer) { // MediaPlayer和进度条都跳转到开始位置 mediaPlayer.seekTo(0); seekBar.setProgress(0); // 如果不处于播放状态,则开始播放 if (!mediaPlayer.isPlaying()) { mediaPlayer.start(); } } else { // 为空则重新设置mediaPlayer playVideo(); } } // 播放、暂停按钮 if (v == playButton) { if (null != mediaPlayer) { // 正在播放 if (mediaPlayer.isPlaying()) { Constants.playPosition = mediaPlayer.getCurrentPosition(); // seekBarAutoFlag = false; mediaPlayer.pause(); playButton.setText("播放"); } else { if (Constants.playPosition >= 0) { // seekBarAutoFlag = true; mediaPlayer.seekTo(Constants.playPosition); mediaPlayer.start(); playButton.setText("暂停"); Constants.playPosition = -1; } } } } // 视频截图 if (v == screenShotButton) { if (null != mediaPlayer) { // 视频正在播放, if (mediaPlayer.isPlaying()) { // 获取播放位置 Constants.playPosition = mediaPlayer.getCurrentPosition(); // 暂停播放 mediaPlayer.pause(); // playButton.setText("播放"); } // 视频截图 savaScreenShot(Constants.playPosition); } else { Toast.makeText(SurfaceViewTestActivity.this, "视频暂未播放!", Toast.LENGTH_SHORT).show(); } } if (v == videoSizeButton) { // 调用改变大小的方法 changeVideoSize(); } } /** * 播放完毕监听 * * @param mp */ @Override public void onCompletion(MediaPlayer mp) { // 设置seeKbar跳转到最后位置 seekBar.setProgress(Integer.parseInt(String.valueOf(videoTimeLong))); // 设置播放标记为false seekBarAutoFlag = false; } /** * 视频缓存大小监听,当视频播放以后 在started状态会调用 */ public void onBufferingUpdate(MediaPlayer mp, int percent) { // TODO Auto-generated method stub // percent 表示缓存加载进度,0为没开始,100表示加载完成,在加载完成以后也会一直调用该方法 Log.e("text", "onBufferingUpdate-->" + percent); // 可以根据大小的变化来 } /** * 错误监听 * * @param mp * @param what * @param extra * @return */ @Override public boolean onError(MediaPlayer mp, int what, int extra) { switch (what) { case MediaPlayer.MEDIA_ERROR_UNKNOWN: Toast.makeText(this, "MEDIA_ERROR_UNKNOWN", Toast.LENGTH_SHORT).show(); break; case MediaPlayer.MEDIA_ERROR_SERVER_DIED: Toast.makeText(this, "MEDIA_ERROR_SERVER_DIED", Toast.LENGTH_SHORT).show(); break; default: break; } switch (extra) { case MediaPlayer.MEDIA_ERROR_IO: Toast.makeText(this, "MEDIA_ERROR_IO", Toast.LENGTH_SHORT).show(); break; case MediaPlayer.MEDIA_ERROR_MALFORMED: Toast.makeText(this, "MEDIA_ERROR_MALFORMED", Toast.LENGTH_SHORT).show(); break; case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK: Toast.makeText(this, "MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK", Toast.LENGTH_SHORT).show(); break; case MediaPlayer.MEDIA_ERROR_TIMED_OUT: Toast.makeText(this, "MEDIA_ERROR_TIMED_OUT", Toast.LENGTH_SHORT).show(); break; case MediaPlayer.MEDIA_ERROR_UNSUPPORTED: Toast.makeText(this, "MEDIA_ERROR_UNSUPPORTED", Toast.LENGTH_SHORT).show(); break; } return false; } /** * 从暂停中恢复 */ protected void onResume() { // TODO Auto-generated method stub super.onResume(); // 判断播放位置 if (Constants.playPosition >= 0) { if (null != mediaPlayer) { seekBarAutoFlag = true; mediaPlayer.seekTo(Constants.playPosition); mediaPlayer.start(); } else { playVideo(); } } } /** * 页面处于暂停状态 */ @Override protected void onPause() { super.onPause(); try { if (null != mediaPlayer && mediaPlayer.isPlaying()) { Constants.playPosition = mediaPlayer.getCurrentPosition(); mediaPlayer.pause(); seekBarAutoFlag = false; } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } /** * 发生屏幕旋转时调用 */ protected void onSaveInstanceState(Bundle outState) { // TODO Auto-generated method stub super.onSaveInstanceState(outState); if (null != mediaPlayer) { // 保存播放位置 Constants.playPosition = mediaPlayer.getCurrentPosition(); } } /** * 屏幕旋转完成时调用 */ protected void onRestoreInstanceState(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onRestoreInstanceState(savedInstanceState); } public void onConfigurationChanged(Configuration newConfig) { // TODO Auto-generated method stub super.onConfigurationChanged(newConfig); } /** * 屏幕销毁时调用 */ @Override protected void onDestroy() { super.onDestroy(); // 由于MediaPlay非常占用资源,所以建议屏幕当前activity销毁时,则直接销毁 try { if (null != SurfaceViewTestActivity.this.mediaPlayer) { // 提前标志为false,防止在视频停止时,线程仍在运行。 seekBarAutoFlag = false; // 如果正在播放,则停止。 if (mediaPlayer.isPlaying()) { mediaPlayer.stop(); } Constants.playPosition = -1; // 释放mediaPlayer SurfaceViewTestActivity.this.mediaPlayer.release(); SurfaceViewTestActivity.this.mediaPlayer = null; } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } /** * 转换播放时间 * * @param milliseconds 传入毫秒值 * @return 返回 hh:mm:ss或mm:ss格式的数据 */ @SuppressLint("SimpleDateFormat") public String getShowTime(long milliseconds) { // 获取日历函数 Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(milliseconds); SimpleDateFormat dateFormat = null; // 判断是否大于60分钟,如果大于就显示小时。设置日期格式 if (milliseconds / 60000 > 60) { dateFormat = new SimpleDateFormat("hh:mm:ss"); } else { dateFormat = new SimpleDateFormat("mm:ss"); } return dateFormat.format(calendar.getTime()); } /** * 保存视频截图.该方法只能支持本地视频文件 * * @param time 视频当前位置 */ public void savaScreenShot(long time) { // 标记是否保存成功 boolean isSave = false; // 获取文件路径 String path = null; // 文件名称 String fileName = null; if (time >= 0) { try { MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever(); mediaMetadataRetriever.setDataSource(pathString); // 获取视频的播放总时长单位为毫秒 String timeString = mediaMetadataRetriever .extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); // 转换格式为微秒 long timelong = Long.parseLong(timeString) * 1000; // 计算当前视频截取的位置 long index = (time * timelong) / mediaPlayer.getDuration(); // 获取当前视频指定位置的截图,时间参数的单位是微秒,做了*1000处理 // 第二个参数为指定位置,意思接近的位置截图 Bitmap bitmap = mediaMetadataRetriever.getFrameAtTime(time * 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC); // 释放资源 mediaMetadataRetriever.release(); // 判断外部设备SD卡是否存在 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { // 存在获取外部文件路径 path = Environment.getExternalStorageDirectory().getPath(); } else { // 不存在获取内部存储 path = Environment.getDataDirectory().getPath(); } // 设置文件名称 ,以事件毫秒为名称 fileName = Calendar.getInstance().getTimeInMillis() + ".jpg"; // 设置保存文件 File file = new File(path + "/shen/" + fileName); if (!file.exists()) { file.createNewFile(); } FileOutputStream fileOutputStream = new FileOutputStream(file); bitmap.compress(CompressFormat.JPEG, 100, fileOutputStream); isSave = true; } catch (Exception e) { e.printStackTrace(); } // 保存成功以后,展示图片 if (isSave) { ImageView imageView = new ImageView(this); imageView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); imageView.setImageBitmap(BitmapFactory.decodeFile(path + "/shen/" + fileName)); new AlertDialog.Builder(this).setView(imageView).show(); } } } /** * 改变视频的显示大小,全屏,窗口,内容 */ public void changeVideoSize() { // 改变视频大小 String videoSizeString = videoSizeButton.getText().toString(); // 获取视频的宽度和高度 int width = mediaPlayer.getVideoWidth(); int height = mediaPlayer.getVideoHeight(); // 如果按钮文字为窗口则设置为窗口模式 if ("窗口".equals(videoSizeString)) { /* * 如果为全屏模式则改为适应内容的,前提是视频宽高小于屏幕宽高,如果大于宽高 我们要做缩放 * 如果视频的宽高度有一方不满足我们就要进行缩放. 如果视频的大小都满足就直接设置并居中显示。 */ if (width > screenWidth || height > screenHeight) { // 计算出宽高的倍数 float vWidth = (float) width / (float) screenWidth; float vHeight = (float) height / (float) screenHeight; // 获取最大的倍数值,按大数值进行缩放 float max = Math.max(vWidth, vHeight); // 计算出缩放大小,取接近的正值 width = (int) Math.ceil((float) width / max); height = (int) Math.ceil((float) height / max); } // 设置SurfaceView的大小并居中显示 RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(width, height); layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT); surfaceView.setLayoutParams(layoutParams); videoSizeButton.setText("全屏"); } else if ("全屏".equals(videoSizeString)) { // 设置全屏 // 设置SurfaceView的大小并居中显示 RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(screenWidth, screenHeight); layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT); surfaceView.setLayoutParams(layoutParams); videoSizeButton.setText("窗口"); } } }