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

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

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

然后做了一个简单的Demo。


首先上几张效果图吧:

android 保存视频文件 安卓手机保存视频_android

android 保存视频文件 安卓手机保存视频_多媒体_02

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

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

点击中间的按钮,会出现图三的界面,我设定的是录制一个8秒的小视频,随着时间的增加,按钮会随之改变.录制

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

android 保存视频文件 安卓手机保存视频_多媒体_03

android 保存视频文件 安卓手机保存视频_ide_04

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

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

android 保存视频文件 安卓手机保存视频_android 保存视频文件_05

android 保存视频文件 安卓手机保存视频_ide_06

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

android 保存视频文件 安卓手机保存视频_视频_07

android 保存视频文件 安卓手机保存视频_android 保存视频文件_08

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

android 保存视频文件 安卓手机保存视频_ide_09

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

主界面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;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.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();
	}

	@Override
	protected 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);
				}
			}

		}
	}

	@Override
	public 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() {
								@Override
								public 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;
	}

	@Override
	public 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;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.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 by
				btnCircleBar.setClickable(true);
				time = 0;
				flag = false;
				break;
			}
		}

		;
	};

	@SuppressWarnings("deprecation")
	@Override
	public 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() {
			@Override
			public 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 format
						mRecorder
								.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);// 设置录制的视频编码h263
						Toast.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 path
						Intent 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() {
								@Override
								public void run() {
									while (time < 8) {
										try {
											time++;
											Thread.sleep(1000);
											handler.sendEmptyMessage(1);
										} catch (InterruptedException e) {
											// TODO Auto-generated catch block
											e.printStackTrace();
										}
									}
									handler.sendEmptyMessage(2);
								}
							}).start();

						}
					} catch (Exception e) {
						e.printStackTrace();
					}

				} else {
					VedioREC.this.finish();
				}
			}
		});

		SurfaceHolder holder = mSurfaceview.getHolder();// 取得holder

		holder.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;
	// }

	@Override
	public 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,将它赋给mSurfaceHolder
		mSurfaceHolder = holder;

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {

		// 将holder,这个holder为开始在onCreate里面取得的holder,将它赋给mSurfaceHolder
		mSurfaceHolder = holder;
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		// surfaceDestroyed的时候同时对象设置为null
		mSurfaceview = null;
		mSurfaceHolder = null;
		if (mRecorder != null) {
			mRecorder.release(); // Now the object cannot be reused
			mRecorder = null;
		}
		if (camera != null) {
			camera.release();
			camera = null;
		}
	}
}



这些是主要的Activity的代码,还有一些widget的代码我就不贴出来了,感兴趣的朋友下载下来看,连接前面已经给过了。