Android多媒体应用:视频存储和播放

最近一直在做和视频有关的工作,今天大体上功能已经完成,今天总结一下android多媒体应用中的视频有关的

操作了,之间一篇博客介绍了视频的录制,最主要的使用的Camera和MediaRecorder这两个类来预览和录制视频,

然后增加了存储录制的视频到本地和播放已经录制好的视频,已经从新写的一些view类,使界面更加好看。

然后做了一个简单的Demo。

下载链接:

首先上几张效果图吧:

第一张图片就是这个Demo的主界面,我已经录制了一段视频,所有第三个会显示有视频,然后没有录制视频

的则显示为胶片的图像,第二张图片是录制视频的页面,首先是调用Camera来预览视频,当想要开始录制视频时,

完成后,按钮会显示成红色,并且中间有完成的字,如图四所示。

点击完成,返回主界面,可以看到第一个已经有视频,并且也写上了录制的时间。点击右上角的删除按钮,

可以看到每张视频里的右上角出现了checkbox(复选框),当然,没有录制视频的ImageView是没有checkbox的。

点击删除,会出现一个对话框,提示你是否删除,点击是,会删除选中的视频。

最后,点击你要播放的视频,如下图所示。

功能大概就介绍完了,然后下来贴出一些代码。可能注释比较少,,大家见谅。

主界面MainActivity代码

public class MainActivity extends Activity implements OnClickListener,OnCheckedChangeListener {private MyImageViewFrameLayout pic1, pic2, pic3;private MyImageViewFrameLayout pic[] = { pic1, pic2, pic3 };private String str[] = new String[3];private String str1[] = new String[3];private String deleteStr[] = new String[3];private String deleteStr1[] = new String[3];private File file;private Button upload;private ImageView delete;// private TextView text1, text2, text3;// private TextView[] texts = { text1, text2, text3 };private CheckBox checkBox1, checkBox2, checkBox3;private CheckBox[] checkBoxs = { checkBox1, checkBox2, checkBox3 };private boolean flag = true;private boolean flag1 = true;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_main);pic[0] = (MyImageViewFrameLayout) findViewById(R.id.pic1);pic[1] = (MyImageViewFrameLayout) findViewById(R.id.pic2);pic[2] = (MyImageViewFrameLayout) findViewById(R.id.pic3);// texts[0] = (TextView) findViewById(R.id.text1);// texts[1] = (TextView) findViewById(R.id.text2);// texts[2] = (TextView) findViewById(R.id.text3);checkBoxs[0] = (CheckBox) findViewById(R.id.delete1);checkBoxs[1] = (CheckBox) findViewById(R.id.delete2);checkBoxs[2] = (CheckBox) findViewById(R.id.delete3);for (CheckBox checkBox : checkBoxs) {checkBox.setOnCheckedChangeListener(this);}upload = (Button) findViewById(R.id.transport);delete = (ImageView) findViewById(R.id.btn_delete);upload.setOnClickListener(this);delete.setOnClickListener(this);setData();}@Overrideprotected void onResume() {super.onResume();setData();for (int i = 0; i < 3; i++) {pic[i].setClickable(true);// texts[i].setVisibility(View.VISIBLE);checkBoxs[i].setVisibility(View.GONE);}upload.setText("上传视频");delete.setImageResource(R.drawable.delete_btn_1);flag = true;flag1 = true;}private void setData() {file = new File(Environment.getExternalStorageDirectory().toString()+ "/recordtest");if (!file.exists()) {file.mkdir();}File file1 = new File(Environment.getExternalStorageDirectory().toString() + "/recordtest1");if (!file1.exists()) {file1.mkdir();}File[] files1 = file1.listFiles();File[] files = file.listFiles();for (int i = 0; i < 3; i++) {str[i] = null;str1[i] = null;pic[i].setImageResource(R.drawable.pic);pic[i].setOnClickListener(this);}for (int i = 0; i < files.length; i++) {Bitmap ret = null;for (int j = 0; j < 3; j++) {if (files[i].getName().equals((j + 1) + ".mp4")) {String path = files[i].getPath();str[j] = path;Bitmap b = ThumbnailUtils.createVideoThumbnail(path,MediaStore.Images.Thumbnails.MINI_KIND);ret = ThumbnailUtils.extractThumbnail(b, dip2px(this, 250),b.getHeight(),ThumbnailUtils.OPTIONS_RECYCLE_INPUT);pic[j].setImageBitmap(ret);}// Toast.makeText(this, (j + 1) + "", Toast.LENGTH_LONG)// .show();if (files1[i].getName().subSequence(0, 1).equals((j + 1) + "")) {String path1 = files1[i].getPath();str1[j] = path1;pic[j].setData(files1[i].getName().substring(2), true);}}}}@Overridepublic void onClick(View v) {String str1 = null;Intent intent = null;switch (v.getId()) {case R.id.pic1:str1 = str[0];if (str1 != null) {intent = new Intent(this, Player.class);intent.putExtra("path", str1);} else {intent = new Intent(this, VedioREC.class);intent.putExtra("path", getSDPath() + "/recordtest/1.mp4");intent.putExtra("date", getSDPath() + "/recordtest1/1.");}startActivity(intent);break;case R.id.pic2:str1 = str[1];if (str1 != null) {intent = new Intent(this, Player.class);intent.putExtra("path", str1);} else {intent = new Intent(this, VedioREC.class);intent.putExtra("path", getSDPath() + "/recordtest/2.mp4");intent.putExtra("date", getSDPath() + "/recordtest1/2.");}startActivity(intent);break;case R.id.pic3:str1 = str[2];if (str1 != null) {intent = new Intent(this, Player.class);intent.putExtra("path", str1);} else {intent = new Intent(this, VedioREC.class);intent.putExtra("path", getSDPath() + "/recordtest/3.mp4");intent.putExtra("date", getSDPath() + "/recordtest1/3.");}startActivity(intent);break;case R.id.btn_delete:if (flag) {for (int i = 0; i < 3; i++) {if (str[i] != null) {checkBoxs[i].setVisibility(View.VISIBLE);}// texts[i].setVisibility(View.GONE);pic[i].setClickable(false);}upload.setText("删除视频");delete.setImageResource(R.drawable.delete_btn_2);flag = false;flag1 = false;} else {for (int i = 0; i < 3; i++) {pic[i].setClickable(true);// texts[i].setVisibility(View.VISIBLE);checkBoxs[i].setVisibility(View.GONE);}upload.setText("上传视频");delete.setImageResource(R.drawable.delete_btn_1);flag = true;flag1 = true;}break;case R.id.transport:if (flag1 == false) {AlertDialog.Builder dialog = new AlertDialog.Builder(this);if (checkBoxs[0].isChecked() || checkBoxs[1].isChecked()|| checkBoxs[2].isChecked()) {dialog.setMessage("是否确认删除该视频?");dialog.setPositiveButton("确认",new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface arg0,int arg1) {for (int i = 0; i < 3; i++) {if (deleteStr[i] != null) {File dFile = new File(deleteStr[i]);dFile.delete();dFile = new File(deleteStr1[i]);dFile.delete();pic[i].setData("", false);}// texts[i].setVisibility(View.VISIBLE);checkBoxs[i].setVisibility(View.GONE);}upload.setText("上传视频");delete.setImageResource(R.drawable.delete_btn_2);flag = true;flag1 = true;setData();}});dialog.setNegativeButton("取消", null);dialog.show();} else {dialog.setMessage("请选择要删除的视频");dialog.setNegativeButton("确认", null);dialog.show();}}break;}}public String getSDPath() {File sdDir = null;boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED); // 判断sd卡是否存在if (sdCardExist) {sdDir = Environment.getExternalStorageDirectory();// 获取跟目录// Toast.makeText(this,sdDir.toString(),Toast.LENGTH_LONG).show();return sdDir.toString();} else {Toast.makeText(this, "没有SD卡", Toast.LENGTH_LONG).show();}return null;}@Overridepublic void onCheckedChanged(CompoundButton arg0, boolean arg1) {for (int i = 0; i < checkBoxs.length; i++) {if (checkBoxs[i].isChecked()) {deleteStr[i] = str[i];deleteStr1[i] = str1[i];} else {deleteStr[i] = null;deleteStr1[i] = null;}}}public static int dip2px(Context context, float dipValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dipValue * scale + 0.5f);}}播放器Player的代码public class Player extends Activity {private VideoView videoView;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);/* 设置全屏 */setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);/* 设置屏幕常亮 *//* flag:标记 ; */getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);setContentView(R.layout.player);videoView = (VideoView) findViewById(R.id.player);Intent intent = getIntent();String data = intent.getStringExtra("path");videoView.setVideoPath(data);MediaController mc = new MediaController(this);videoView.setMediaController(mc);videoView.start();videoView.requestFocus();}}录制视频VedioREC代码:public class VedioREC extends Activity implements Callback {private MySurfaceViewFrameLayout mSurfaceview;private CircleBar btnCircleBar;// 开始停止录制按键private MediaRecorder mRecorder;// 录制视频的类private SurfaceHolder mSurfaceHolder;// 显示视频private Camera camera;private int time = 0;private boolean flag = true;int bestWidth = 0;int bestHeight = 0;@SuppressLint("HandlerLeak")private Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {switch (msg.what) {case 1:// 开始录制btnCircleBar.setClickable(false);break;case 2:// 录制8s结束mRecorder.stop();mRecorder.reset(); // You can reuse the object bybtnCircleBar.setClickable(true);time = 0;flag = false;break;}};};@SuppressWarnings("deprecation")@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题栏getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏getWindow().setFormat(PixelFormat.TRANSLUCENT); // 选择支持半透明模式,在有surfaceview的activity中使用。setContentView(R.layout.vediorec);// 加载布局mSurfaceview = (MySurfaceViewFrameLayout) findViewById(R.id.surfaceview);btnCircleBar = (CircleBar) findViewById(R.id.circleBar);btnCircleBar.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View arg0) {if (flag) {// 开始if (mRecorder == null) {mRecorder = new MediaRecorder(); // 创建mediarecorder的对象}try {camera.unlock();mRecorder.setCamera(camera);mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);// 这两项需要放在setOutputFormat之前mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);// 设置录制视频源为Camera(相机)mRecorder.setOrientationHint(90);// Set output file formatmRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);// 设置录制完成后视频的封装格式THREE_GPP为3gp.MPEG_4为mp4// 这两项需要放在setOutputFormat之后mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);// 设置录制的视频编码h263Toast.makeText(VedioREC.this,bestWidth + "======" + bestHeight, Toast.LENGTH_LONG).show();mRecorder.setVideoSize(bestWidth, bestHeight);//设置视频录制的分辨率。必须放在设置编码和格式的后面,否则报错mRecorder.setVideoFrameRate(30);// 设置录制的视频帧率。必须放在设置编码和格式的后面,否则报错mRecorder.setMaxDuration(8000);// 设置最大的录制时间mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());// Set output file pathIntent intent = getIntent();String path = intent.getStringExtra("path");String date = intent.getStringExtra("date");// Toast.makeText(VedioREC.this, path,// Toast.LENGTH_LONG)// .show();if (path != null) {File dir = new File(path);// if (!dir.exists()) {// dir.mkdir();// }File dateFile = new File(date + getDate());dateFile.createNewFile();path = dir.toString();mRecorder.setOutputFile(path);mRecorder.prepare();// 准备录制mRecorder.start(); // 开始录制btnCircleBar.startMyAnimation();new Thread(new Runnable() {@Overridepublic void run() {while (time < 8) {try {time++;Thread.sleep(1000);handler.sendEmptyMessage(1);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}handler.sendEmptyMessage(2);}}).start();}} catch (Exception e) {e.printStackTrace();}} else {VedioREC.this.finish();}}});SurfaceHolder holder = mSurfaceview.getHolder();// 取得holderholder.addCallback(this); // holder加入回调接口holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置,要不出错.}/** * 使用时间对录像起名 * * @return */public static String getDate() {Calendar ca = Calendar.getInstance();SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");String date = sdf.format(ca.getTimeInMillis());return date;}//// /**// * 获取SD path// *// * @return// */// public String getSDPath() {// File sdDir = null;// boolean sdCardExist = Environment.getExternalStorageState().equals(// android.os.Environment.MEDIA_MOUNTED); // 判断sd卡是否存在// if (sdCardExist) {// sdDir = Environment.getExternalStorageDirectory();// 获取跟目录// // Toast.makeText(this,sdDir.toString(),Toast.LENGTH_LONG).show();// return sdDir.toString();// } else {// Toast.makeText(this, "没有SD卡", Toast.LENGTH_LONG).show();// }//// return null;// }@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {camera = Camera.open(); // 获取Camera实例try {camera.setPreviewDisplay(holder);mSurfaceview.setLayoutParams(new LinearLayout.LayoutParams(width,height));} catch (Exception e) {// 如果出现异常,则释放Camera对象camera.release();}/** * 在显示了预览后,我们有时候希望限制预览的Size 我们并不是自己指定一个SIze而是指定一个Size,然后 * 获取系统支持的SIZE,然后选择一个比指定SIZE小且最接近所指定SIZE的一个 Camera.Size对象就是该SIZE。 **/Camera.Parameters param = camera.getParameters();List<Camera.Size> sizeList = param.getSupportedPreviewSizes();// 如果sizeList只有一个我们也没有必要做什么了,因为就他一个别无选择if (sizeList.size() > 1) {Iterator<Camera.Size> itor = sizeList.iterator();while (itor.hasNext()) {Camera.Size cur = itor.next();if (cur.width > bestWidth && cur.height > bestHeight&& cur.width < 900 && cur.height < 500) {bestWidth = cur.width;bestHeight = cur.height;}}}camera.setDisplayOrientation(90);// 设置预览视频时时竖屏// 启动预览功能camera.startPreview();// 将holder,这个holder为开始在onCreate里面取得的holder,将它赋给mSurfaceHoldermSurfaceHolder = holder;}@Overridepublic void surfaceCreated(SurfaceHolder holder) {// 将holder,这个holder为开始在onCreate里面取得的holder,将它赋给mSurfaceHoldermSurfaceHolder = holder;}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {// TODO Auto-generated method stub// surfaceDestroyed的时候同时对象设置为nullmSurfaceview = null;mSurfaceHolder = null;if (mRecorder != null) {mRecorder.release(); // Now the object cannot be reusedmRecorder = null;}if (camera != null) {camera.release();camera = null;}}}这些是主要的Activity的代码,还有一些widget的代码我就不贴出来了,感兴趣的朋友下载下来看,连接前面已经给过了。

人之所以有一张嘴,而有两只耳朵,原因是听的要比说的多一倍。

Android多媒体应用:视频存储和播放

相关文章:

你感兴趣的文章:

标签云: