最近一直在做和视频有关的工作,今天大体上功能已经完成,今天总结一下android多媒体应用中的视频有关的
操作了,之间一篇博客介绍了视频的录制,最主要的使用的Camera和MediaRecorder这两个类来预览和录制视频,
然后增加了存储录制的视频到本地和播放已经录制好的视频,已经从新写的一些view类,使界面更加好看。
然后做了一个简单的Demo。
下载链接:http://download.csdn.net/detail/a296777513/8438437
首先上几张效果图吧:
第一张图片就是这个Demo的主界面,我已经录制了一段视频,所有第三个会显示有视频,然后没有录制视频
的则显示为胶片的图像,第二张图片是录制视频的页面,首先是调用Camera来预览视频,当想要开始录制视频时,
点击中间的按钮,会出现图三的界面,我设定的是录制一个8秒的小视频,随着时间的增加,按钮会随之改变.录制
完成后,按钮会显示成红色,并且中间有完成的字,如图四所示。
点击完成,返回主界面,可以看到第一个已经有视频,并且也写上了录制的时间。点击右上角的删除按钮,
可以看到每张视频里的右上角出现了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;
@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的代码我就不贴出来了,感兴趣的朋友下载下来看,连接前面已经给过了。