首先看下VINE在iphone上的界面, 这次我们主要实现的功能就是最左边这个界面。
功能列表如下:
1. 触摸屏幕开始录制,松开后录制结束,接着触摸屏幕继续录制,直到录满6秒位置。
2. 录制完毕后,点击向右的箭头讲刚录制的视频进行播放。
3. 支持前后摄像头的切换。
界面部分完全是copy vine的实现,包括其中的图片。 看下layout文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/solid_black"
tools:context=".MainActivity" >
<RelativeLayout
android:id="@id/root_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<RelativeLayout
android:id="@id/top_mask"
android:layout_width="fill_parent"
android:layout_height="@dimen/capture_top_mask" >
<cn.wodong.capturevideo.ProgressView
android:id="@id/progress"
android:layout_width="fill_parent"
android:layout_height="48.0dip"
android:background="@color/bg_capture_progress" />
<LinearLayout
android:id="@id/cancel"
android:layout_width="56.0dip"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:gravity="center"
android:onClick="onBackPressed" >
<Button
android:layout_width="32.0dip"
android:layout_height="32.0dip"
android:background="@drawable/btn_capture_x"
android:onClick="onBackPressed" />
</LinearLayout>
<LinearLayout
android:layout_width="56.0dip"
android:layout_height="fill_parent"
android:layout_centerInParent="true"
android:layout_centerVertical="true"
android:gravity="center" >
<!--
TextView
android:id="@id/press"
android:layout_width="32.0dip"
android:layout_height="32.0dip"
android:background="@drawable/btn_capture_ghost">
-->
<Button
android:id="@id/switchCamera"
android:layout_width="32.dip"
android:layout_height="32dip"
android:background="@drawable/btn_capture_front_facing_camera"
android:onClick="onCameraSwitchPressed" />
</LinearLayout>
<LinearLayout
android:id="@id/finishLayOut"
android:layout_width="56.0dip"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="center"
android:onClick="onFinishPressed"
android:visibility="visible" >
<Button
android:id="@id/finishButton"
android:layout_width="32.0dip"
android:layout_height="32.0dip"
android:background="@drawable/btn_capture_arrow"
android:onClick="onFinishPressed" />
</LinearLayout>
</RelativeLayout>
<cn.wodong.capturevideo.MySurfaceView
android:id="@id/cameraView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@id/top_mask"
android:layout_centerInParent="true" />
<VideoView
android:id="@id/mediaShow"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@id/top_mask"
android:layout_centerInParent="true" />
<RelativeLayout
android:id="@id/bottom_mask"
android:layout_width="fill_parent"
android:layout_height="100.0dip"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom"
android:background="@color/capture_background" >
<LinearLayout
android:id="@id/camera_features"
style="@style/CameraFeatureLayout"
android:layout_width="fill_parent"
android:layout_height="51.0dip"
android:orientation="horizontal"
android:paddingTop="9.0dip" >
<Button
android:layout_width="32.dip"
android:layout_height="32dip"
android:background="@drawable/btn_capture_front_facing_camera"
android:onClick="onCameraSwitchPressed"
android:visibility="invisible" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
启动相机:
public void startCamera(SurfaceHolder holder) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
for (int i = 0; i < camera.getNumberOfCameras(); i++) {
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == cameraFacingType) {
camera = Camera.open(i);
break;
}
}
} else {
camera = Camera.open();
}
Parameters parameters = camera.getParameters();
try {
List<Size> sizeList = parameters.getSupportedPreviewSizes();
int width = 0;
for (Size s : sizeList) {
System.out.println(s.width + "," + s.height);
if (s.width > width && s.width <= 800) {
width = s.width;
defaultSize = s;
}
}
camera.setDisplayOrientation(90);
camera.setPreviewDisplay(holder);
} catch (IOException e) {
camera.release();
camera = null;
}
try {
parameters.setPreviewSize(640, 480);
camera.setParameters(parameters);
defaultSize = null;
} catch (Exception e) {
e.printStackTrace();
parameters.setPreviewSize(defaultSize.width, defaultSize.height);
camera.setParameters(parameters);
}
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (this.shouldBeWidth > 0) {
canvas.drawRect(0.0F, 0.0F, this.shouldBeWidth,
getMeasuredHeight(), mPaint);
}
};
录制视频参考实现:
public void startRecord(boolean isFirst) {
if (isMax) {
return;
}
semp.acquireUninterruptibly();
getCamera().stopPreview();
mediaRecorder = new MediaRecorder();
cameraManager.getCamera().unlock();
mediaRecorder.setCamera(cameraManager.getCamera());
if (cameraManager.isUseBackCamera()) {
mediaRecorder.setOrientationHint(90);
} else {
mediaRecorder.setOrientationHint(90 + 180);
}
Size defaultSize = cameraManager.getDefaultSize();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile
.get(CameraProfile.QUALITY_HIGH));
if (defaultSize != null) {
mediaRecorder.setVideoSize(defaultSize.width, defaultSize.height);
} else {
mediaRecorder.setVideoSize(640, 480);
}
// camera.getParameters().setPictureSize(cameraSize.width,
// cameraSize.height);
// camera.setParameters(parameters);
String fileName = parentPath + "/" + videoTempFiles.size() + ".mp4";
mediaRecorder.setOutputFile(fileName);
videoTempFiles.add(fileName);
mediaRecorder.setPreviewDisplay(mySurfaceView.getHolder().getSurface());
try {
mediaRecorder.prepare();
} catch (Exception e) {
e.printStackTrace();
stopRecord();
}
try {
mediaRecorder.start();
isStart = true;
videoStartTime = new Date().getTime();
} catch (Exception e) {
e.printStackTrace();
if (isFirst) {
startRecord(false);
} else {
stopRecord();
}
}
}
每次录制生成一个小的视频文件,最后要把所有的视频文件进行合并,合并成一个整体的视频文件。 采用了一个开源组件isoviewer实现此功能,参考代码如下:
private void combineFiles() {
try {
List<Track> videoTracks = new LinkedList<Track>();
List<Track> audioTracks = new LinkedList<Track>();
for (String fileName : recorderManager.getVideoTempFiles()) {
try {
Movie movie = MovieCreator.build(fileName);
for (Track t : movie.getTracks()) {
if (t.getHandler().equals("soun")) {
audioTracks.add(t);
}
if (t.getHandler().equals("vide")) {
videoTracks.add(t);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
Movie result = new Movie();
if (audioTracks.size() > 0) {
result.addTrack(new AppendTrack(audioTracks
.toArray(new Track[audioTracks.size()])));
}
if (videoTracks.size() > 0) {
result.addTrack(new AppendTrack(videoTracks
.toArray(new Track[videoTracks.size()])));
}
Container out = new DefaultMp4Builder().build(result);
FileChannel fc = new RandomAccessFile(
String.format(getFinalVideoFileName()), "rw").getChannel();
out.writeContainer(fc);
fc.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
视频的播放采用videoView
public void startPlay() {
combineFiles();
recorderManager.reset();
videoSurface.setVisibility(SurfaceView.GONE);
videoView.setVisibility(SurfaceView.VISIBLE);
videoView.setVideoPath(getFinalVideoFileName());
videoView.start();
}
源码如下: