package net.ag.lib.gallery.ui; import java.io.File; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import net.ag.lib.gallery.R; import net.ag.lib.gallery.util.MediaConstants; import net.ag.lib.gallery.util.MediaInfo; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.hardware.Camera; import android.hardware.Camera.CameraInfo; import android.hardware.Camera.PictureCallback; import android.hardware.Camera.Size; import android.media.MediaRecorder; import android.media.MediaScannerConnection; import android.media.MediaScannerConnection.MediaScannerConnectionClient; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.SystemClock; import android.support.v4.app.FragmentActivity; import android.text.format.DateFormat; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.View.OnClickListener; import android.view.WindowManager; import android.widget.Chronometer; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import android.widget.ToggleButton; /*** * 拍摄视频 * * @author AG * */ @SuppressLint("InlinedApi") public class MediaShootActivity extends FragmentActivity implements OnClickListener, SurfaceHolder.Callback, MediaScannerConnectionClient { private SurfaceView mSurfaceView; private SurfaceHolder mSurfaceHolder; private TextView mFacing; private ImageView mShoot; private MediaRecorder mMediaRecorder; private Camera camera; private int Model = 0; // 0 照片 1视频 2 视频和照片 private ToggleButton toggle_model; private ToggleButton toggle_facing; private boolean SHOOTMODEL = true; // 视频 or 拍照 private boolean isRecording = false; private boolean isCamOpen = false; private int defaultCam = CameraInfo.CAMERA_FACING_BACK; private int defaultVideoWidth = 640; private int defaultVideoHeight = 480; private int defaultVideoFrameRate = 25; private int defaultOrientation = 90; private int mVideoWidth = -1; private int mVideoHeight = -1; private int mPreviewWidth = -1; private int mPreviewHeight = -1; private int mVideoFrameRate = -1; private File video; private File picture; private ArrayList<CameraInfo> mCameras = new ArrayList<CameraInfo>(); private Chronometer mChronometer; private MediaScannerConnection mConnection; private boolean sendVideo = true; @SuppressWarnings("deprecation") @Override protected void onCreate(Bundle savedInstanceState) { getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); super.onCreate(savedInstanceState); setContentView(R.layout.zg_activity_video_shoot); mFacing = (TextView) findViewById(R.id.tv_facing); mSurfaceView = (SurfaceView) findViewById(R.id.surfaceview_shoot); mShoot = (ImageView) findViewById(R.id.img_shoot); mChronometer = (Chronometer) findViewById(R.id.video_chronometer); mFacing.setOnClickListener(this); mShoot.setOnClickListener(this); initToggle(); findViewById(R.id.iv_left).setOnClickListener(this); SurfaceHolder mHolder = mSurfaceView.getHolder(); mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void initToggle() { Model = getIntent().getIntExtra("Model", 1); toggle_model = (ToggleButton) findViewById(R.id.toggle_model); toggle_facing = (ToggleButton) findViewById(R.id.toggle_facing); toggle_model.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { SHOOTMODEL = isChecked; } }); toggle_facing.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { switchCamera(); } }); if (Model == 0) { toggle_model.setVisibility(View.GONE); SHOOTMODEL = false; } else if (Model == 1) { toggle_model.setVisibility(View.GONE); SHOOTMODEL = true; } else if (Model == 2) { toggle_model.setVisibility(View.VISIBLE); SHOOTMODEL = false; toggle_model.setChecked(SHOOTMODEL); } } @Override public void onClick(View v) { if (v.getId() == R.id.img_shoot) { if (SHOOTMODEL) { if (!isRecording) { initMediaRecorder(); startShoot(); } else { stopShoot(); } } else { takePicture(); } } else if (v.getId() == R.id.tv_facing) { switchCamera(); } else if (v.getId() == R.id.iv_left) { finish(); } } @SuppressLint("NewApi") public void initMediaRecorder() { try { video = new File(getDCIM(), "TomatoTown_" + DateFormat.format("yyyyMMdd_hhmmss", System.currentTimeMillis()).toString() + ".mp4"); } catch (Exception e) { e.printStackTrace(); } if (video == null) { Toast.makeText(this, "空间不足", Toast.LENGTH_SHORT).show(); // TODO return; } mMediaRecorder = new MediaRecorder(); mMediaRecorder.reset(); if (camera != null) { camera.unlock(); mMediaRecorder.setCamera(camera); } mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); mMediaRecorder.setAudioChannels(1); mMediaRecorder.setAudioSamplingRate(44100); mMediaRecorder.setAudioEncodingBitRate(64); if (mVideoWidth != -1 && mVideoHeight != -1) mMediaRecorder.setVideoSize(mVideoWidth, mVideoHeight); if (mVideoFrameRate != -1) mMediaRecorder.setVideoFrameRate(mVideoFrameRate); mMediaRecorder.setVideoEncodingBitRate(1 * 768 * 1024); mMediaRecorder.setOrientationHint(defaultOrientation); mMediaRecorder.setMaxDuration(MediaConstants.MAX_DURATION_MS); mMediaRecorder.setOutputFile(video.getAbsolutePath()); mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); mMediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() { @Override public void onError(MediaRecorder mr, int what, int extra) { Log.d("MediaRecorder", "onError what " + what + " extra " + extra); } }); // mMediaRecorder.setProfile(CamcorderProfile // .get(CamcorderProfile.QUALITY_HIGH)); mMediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() { @Override public void onInfo(MediaRecorder mr, int what, int extra) { Log.d("MediaRecorder", "onInfo what " + what + " extra " + extra); if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) { stopShoot(); } } }); } public void takePicture() { camera.autoFocus(new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { try { picture = new File(getDCIM(), "TomatoTown_" + DateFormat.format("yyyyMMdd_hhmmss", System.currentTimeMillis()).toString() + ".jpg"); } catch (Exception e) { e.printStackTrace(); } if (picture == null) { Toast.makeText(MediaShootActivity.this, "空间不足", Toast.LENGTH_SHORT).show(); // TODO return; } if (success) { camera.takePicture(null, null, new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { try { FileOutputStream fos = new FileOutputStream( picture); Bitmap p = BitmapFactory.decodeByteArray(data, 0, data.length); p.compress(Bitmap.CompressFormat.JPEG, 100, fos); if (fos != null) { fos.close(); } SendPictureDialog(); } catch (Exception e) { e.printStackTrace(); } } }); } } }); } public void startShoot() { if (isRecording) return; try { if (mMediaRecorder != null) { // TODO mShoot.setImageResource(R.drawable.ic_launcher); isRecording = true; mMediaRecorder.prepare(); mMediaRecorder.start(); mChronometer.setVisibility(View.VISIBLE); mChronometer.setBase(SystemClock.elapsedRealtime()); mChronometer.start(); } } catch (Exception e) { e.printStackTrace(); isRecording = false; } } public void stopShoot() { if (!isRecording) return; try { if (mMediaRecorder != null) { // TODO mShoot.setImageResource(R.drawable.ic_launcher); isRecording = false; mChronometer.stop(); mMediaRecorder.stop(); } } catch (Exception e) { e.printStackTrace(); } try { if (camera != null) { isCamOpen = false; camera.stopPreview(); } } catch (Exception e) { e.printStackTrace(); } showSendVideoDialog(); } public void switchCamera() { if (mCameras.size() > 1) { if (defaultCam == CameraInfo.CAMERA_FACING_BACK) { defaultCam = CameraInfo.CAMERA_FACING_FRONT; mSurfaceView.setVisibility(View.GONE); mSurfaceView.setVisibility(View.VISIBLE); } else if (defaultCam == CameraInfo.CAMERA_FACING_FRONT) { defaultCam = CameraInfo.CAMERA_FACING_BACK; mSurfaceView.setVisibility(View.GONE); mSurfaceView.setVisibility(View.VISIBLE); } } } @SuppressLint("NewApi") public void openCamera() { try { mCameras.clear(); int numberOfCameras = Camera.getNumberOfCameras(); if (numberOfCameras == 1) { mFacing.setVisibility(View.GONE); toggle_facing.setVisibility(View.GONE); } else if (numberOfCameras > 1) { mFacing.setVisibility(View.VISIBLE); toggle_facing.setVisibility(View.VISIBLE); } for (int i = 0; i < numberOfCameras; i++) { CameraInfo cameraInfo = new CameraInfo(); Camera.getCameraInfo(i, cameraInfo); mCameras.add(cameraInfo); } if (camera == null) { openCameraByType(); } if (defaultCam == CameraInfo.CAMERA_FACING_BACK) { mFacing.setText("前置"); } else if (defaultCam == CameraInfo.CAMERA_FACING_FRONT) { mFacing.setText("后置"); } if (camera != null) { isCamOpen = true; initVideoSize(); initFrameRates(); camera.setDisplayOrientation(90); camera.stopPreview(); camera.setPreviewDisplay(mSurfaceHolder); camera.startPreview(); } else { Toast.makeText(this, "摄像头打开失败!", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "摄像头打开失败!", Toast.LENGTH_SHORT).show(); } } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void initVideoSize() { CameraSizeComparator sizeComparator = new CameraSizeComparator(); boolean hasdef = false; Camera.Parameters mParameters = camera.getParameters(); List<Size> list = mParameters.getSupportedVideoSizes(); List<Size> list1 = mParameters.getSupportedPreviewSizes(); if (list != null && list.size() > 0) { Collections.sort(list, sizeComparator); for (int i = 0; i < list.size(); i++) { Size size = list.get(i); if (size.width == defaultVideoWidth && size.height == defaultVideoHeight) { mVideoWidth = defaultVideoWidth; mVideoHeight = defaultVideoHeight; hasdef = true; } } if (!hasdef) { int pos = list.size() / 2; if (pos >= list.size()) pos = list.size() - 1; Size size = list.get(pos); mVideoWidth = size.width; mVideoHeight = size.height; } } if (defaultCam == CameraInfo.CAMERA_FACING_FRONT && list1 != null && list1.size() > 0) { Collections.sort(list1, sizeComparator); for (int i = 0; i < list1.size(); i++) { Size size = list1.get(i); if (size.width == defaultVideoWidth && size.height == defaultVideoHeight) { mPreviewWidth = defaultVideoWidth; mPreviewHeight = defaultVideoHeight; hasdef = true; } } if (!hasdef) { int pos = list1.size() / 2; if (pos >= list1.size()) pos = list1.size() - 1; Size size = list1.get(pos); mPreviewWidth = size.width; mPreviewHeight = size.height; } if (mPreviewWidth > 0 && mPreviewHeight > 0) { mParameters.setPreviewSize(mPreviewWidth, mPreviewHeight); camera.setParameters(mParameters); } } } @SuppressWarnings("deprecation") public void initFrameRates() { boolean hasdef = false; Camera.Parameters mParameters = camera.getParameters(); List<Integer> list = mParameters.getSupportedPreviewFrameRates(); if (list == null || list.size() == 0) return; for (int i = 0; i < list.size(); i++) { int mFrameRate = list.get(i); if (mFrameRate == defaultVideoFrameRate) { mVideoFrameRate = defaultVideoFrameRate; hasdef = true; } } if (!hasdef) { int pos = list.size() / 2; if (pos >= list.size()) pos = list.size() - 1; mVideoFrameRate = list.get(pos); } } @SuppressLint("NewApi") public void openCameraByType() { try { if (defaultCam == CameraInfo.CAMERA_FACING_BACK) { camera = Camera.open(CameraInfo.CAMERA_FACING_BACK); CameraInfo cameraInfo = new CameraInfo(); Camera.getCameraInfo(CameraInfo.CAMERA_FACING_BACK, cameraInfo); defaultCam = cameraInfo.facing; defaultOrientation = cameraInfo.orientation; } else if (defaultCam == CameraInfo.CAMERA_FACING_FRONT) { camera = Camera.open(CameraInfo.CAMERA_FACING_FRONT); CameraInfo cameraInfo = new CameraInfo(); Camera.getCameraInfo(CameraInfo.CAMERA_FACING_FRONT, cameraInfo); defaultCam = cameraInfo.facing; defaultOrientation = cameraInfo.orientation; } } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "摄像头打开失败!", Toast.LENGTH_SHORT).show(); } } public File getDCIM() { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { File mCamera = new File( Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "Camera"); if (!mCamera.exists()) { mCamera.mkdirs(); } return mCamera; } return null; } @Override public void surfaceCreated(SurfaceHolder holder) { mSurfaceHolder = holder; openCamera(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { mSurfaceHolder = holder; } @Override public void surfaceDestroyed(SurfaceHolder holder) { mSurfaceHolder = null; release(); } public void showSendVideoDialog() { if (video == null) { Log.e("sendVideo", "video is not null!"); return; } AlertDialog.Builder mBuilder = new AlertDialog.Builder(this); mBuilder.setMessage("发送视频"); mBuilder.setCancelable(false); mBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { sendVideo = true; sendMedia(); } }); mBuilder.setNegativeButton("失败", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { showSaveDialog(); } }); mBuilder.show(); } public void showSaveDialog() { AlertDialog.Builder mBuilder = new AlertDialog.Builder(this); mBuilder.setMessage("保存" + (SHOOTMODEL ? "视频" : "图片")); mBuilder.setCancelable(false); mBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { sendVideo = false; sendMedia(); } }); mBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { if (video != null) video.delete(); if (picture != null) picture.delete(); setResult(RESULT_CANCELED); finish(); } }); mBuilder.show(); } public void SendPictureDialog() { if (picture == null) { Log.e("sendVideo", "video is not null!"); return; } AlertDialog.Builder mBuilder = new AlertDialog.Builder(this); mBuilder.setMessage("发送图片"); mBuilder.setCancelable(false); mBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { sendVideo = true; sendMedia(); } }); mBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { showSaveDialog(); } }); mBuilder.show(); } public void sendMedia() { mConnection = new MediaScannerConnection(this, this); mConnection.connect(); } public int getDuration() { String str = mChronometer.getText().toString(); String[] duration = str.split(":"); if (duration.length == 2) { int m = Integer.parseInt(duration[0]) * 60 * 1000; int s = Integer.parseInt(duration[1]) * 1000; return m + s; } if (duration.length == 3) { int h = Integer.parseInt(duration[0]) * 60 * 60 * 1000; int m = Integer.parseInt(duration[1]) * 60 * 1000; int s = Integer.parseInt(duration[2]) * 1000; return h + m + s; } return 0; } public void release() { try { if (mMediaRecorder != null) { if (isRecording) { // TODO mShoot.setImageResource(R.drawable.ic_launcher); mChronometer.setVisibility(View.GONE); isRecording = false; mChronometer.stop(); mMediaRecorder.stop(); if (video != null && video.exists()) video.delete(); } mMediaRecorder.release(); mMediaRecorder = null; } } catch (Exception e) { e.printStackTrace(); } try { if (camera != null) { if (isCamOpen) { isCamOpen = false; camera.stopPreview(); } camera.release(); camera = null; } } catch (Exception e) { e.printStackTrace(); } } @Override public void onMediaScannerConnected() { mConnection.scanFile( SHOOTMODEL ? video.getAbsolutePath() : picture .getAbsolutePath(), SHOOTMODEL ? "video/mp4" : "image/jpeg"); } @Override public void onScanCompleted(String path, Uri uri) { mConnection.disconnect(); if (sendVideo) { Intent result = getIntent(); result.putExtra(MediaConstants.MEDIA_RESULT_TYPE, SHOOTMODEL ? MediaConstants.TYPE_VIDEO : MediaConstants.TYPE_PIC); ArrayList<MediaInfo> list = new ArrayList<MediaInfo>(); MediaInfo info = new MediaInfo(); info.filePath = SHOOTMODEL ? video.getAbsolutePath() : picture .getAbsolutePath(); info.duration = SHOOTMODEL ? getDuration() : 0; list.add(info); result.putExtra(MediaConstants.MEDIA_RESULT_DATAS, list); setResult(MediaConstants.MEDIA_RESULT_VIDEO_CODE, result); } else { setResult(RESULT_CANCELED); } finish(); } public class CameraSizeComparator implements Comparator<Camera.Size> { public int compare(Size lhs, Size rhs) { if (lhs.width == rhs.width) { return 0; } else if (lhs.width > rhs.width) { return 1; } else { return -1; } } } }