package com.yixia.camera.demo.ui.record;
import java.io.File;
import java.util.ArrayList;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.CheckBox;
import android.widget.CheckedTextView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.example.wechat01.R;
import com.yixia.camera.MediaRecorderBase;
import com.yixia.camera.MediaRecorderBase.OnErrorListener;
import com.yixia.camera.MediaRecorderBase.OnPreparedListener;
import com.yixia.camera.MediaRecorderNative;
import com.yixia.camera.MediaRecorderSystem;
import com.yixia.camera.VCamera;
import com.yixia.camera.demo.VCameraDemoApplication;
import com.yixia.camera.demo.common.CommonIntentExtra;
import com.yixia.camera.demo.log.Logger;
import com.yixia.camera.demo.ui.BaseActivity;
import com.yixia.camera.demo.ui.record.views.ProgressView;
import com.yixia.camera.demo.utils.ConvertToUtils;
import com.yixia.camera.model.MediaObject;
import com.yixia.camera.util.DeviceUtils;
import com.yixia.camera.util.FileUtils;
import com.yixia.videoeditor.adapter.UtilityAdapter;
/**
* 视频录制
*
* @author tangjun@yixia.com
*
*/
public class MediaRecorderActivity extends BaseActivity implements
OnErrorListener, OnClickListener, OnPreparedListener,
MediaRecorderBase.OnEncodeListener {
/** 录制最长时间 */
public final static int RECORD_TIME_MAX = 10 * 1000;
/** 录制最小时间 */
public final static int RECORD_TIME_MIN = 3 * 1000;
/** 刷新进度条 */
private static final int HANDLE_INVALIDATE_PROGRESS = 0;
/** 延迟拍摄停止 */
private static final int HANDLE_STOP_RECORD = 1;
/** 对焦 */
private static final int HANDLE_HIDE_RECORD_FOCUS = 2;
/** 下一步 */
private ImageView mTitleNext;
/** 对焦图标-带动画效果 */
private ImageView mFocusImage;
/** 前后摄像头切换 */
private CheckBox mCameraSwitch;
/** 回删按钮、延时按钮、滤镜按钮 */
private CheckedTextView mRecordDelete;
/** 闪光灯 */
private CheckBox mRecordLed;
/** 拍摄按钮 */
private ImageView mRecordController;
/** 底部条 */
private RelativeLayout mBottomLayout;
/** 摄像头数据显示画布 */
private SurfaceView mSurfaceView;
/** 录制进度 */
private ProgressView mProgressView;
/** 对焦动画 */
private Animation mFocusAnimation;
/** SDK视频录制对象 */
private MediaRecorderBase mMediaRecorder;
/** 视频信息 */
private MediaObject mMediaObject;
/** 需要重新编译(拍摄新的或者回删) */
private boolean mRebuild;
/** on */
private boolean mCreated;
/** 是否是点击状态 */
private volatile boolean mPressedStatus;
/** 是否已经释放 */
private volatile boolean mReleased;
/** 对焦图片宽度 */
private int mFocusWidth;
/** 底部背景色 */
private int mBackgroundColorNormal, mBackgroundColorPress;
/** 屏幕宽度 */
private int mWindowWidth;
@Override
protected void onCreate(Bundle savedInstanceState) {
mCreated = false;
super.onCreate(savedInstanceState);
VCameraDemoApplication.getInstance().addActivity(this);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // 防止锁屏
loadIntent();
loadViews();
mCreated = true;
}
/** 加载传入的参数 */
private void loadIntent() {
mWindowWidth = DeviceUtils.getScreenWidth(this);
mFocusWidth = ConvertToUtils.dipToPX(this, 64);
mBackgroundColorNormal = getResources().getColor(R.color.black);// camera_bottom_bg
mBackgroundColorPress = getResources().getColor(
R.color.camera_bottom_press_bg);
}
/** 加载视图 */
private void loadViews() {
setContentView(R.layout.activity_media_recorder);
// ~~~ 绑定控件
mSurfaceView = (SurfaceView) findViewById(R.id.record_preview);
mCameraSwitch = (CheckBox) findViewById(R.id.record_camera_switcher);
mTitleNext = (ImageView) findViewById(R.id.title_next);
mFocusImage = (ImageView) findViewById(R.id.record_focusing);
mProgressView = (ProgressView) findViewById(R.id.record_progress);
mRecordDelete = (CheckedTextView) findViewById(R.id.record_delete);
mRecordController = (ImageView) findViewById(R.id.record_controller);
mBottomLayout = (RelativeLayout) findViewById(R.id.bottom_layout);
mRecordLed = (CheckBox) findViewById(R.id.record_camera_led);
// ~~~ 绑定事件
if (DeviceUtils.hasICS())
mSurfaceView.setOnTouchListener(mOnSurfaveViewTouchListener);
mTitleNext.setOnClickListener(this);
findViewById(R.id.title_back).setOnClickListener(this);
mRecordDelete.setOnClickListener(this);
mBottomLayout.setOnTouchListener(mOnVideoControllerTouchListener);
// ~~~ 设置数据
// 是否支持前置摄像头
if (MediaRecorderBase.isSupportFrontCamera()) {
mCameraSwitch.setOnClickListener(this);
} else {
mCameraSwitch.setVisibility(View.GONE);
}
// 是否支持闪光灯
if (DeviceUtils.isSupportCameraLedFlash(getPackageManager())) {
mRecordLed.setOnClickListener(this);
} else {
mRecordLed.setVisibility(View.GONE);
}
try {
mFocusImage.setImageResource(R.drawable.video_focus);
} catch (OutOfMemoryError e) {
Logger.e(e);
}
mProgressView.setMaxDuration(RECORD_TIME_MAX);
initSurfaceView();
}
/** 初始化画布 */
private void initSurfaceView() {
final int w = DeviceUtils.getScreenWidth(this);
((RelativeLayout.LayoutParams) mBottomLayout.getLayoutParams()).topMargin = w;
int width = w;
int height = w * 4 / 3;
//
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mSurfaceView
.getLayoutParams();
lp.width = width;
lp.height = height;
mSurfaceView.setLayoutParams(lp);
}
/** 初始化拍摄SDK */
private void initMediaRecorder() {
mMediaRecorder = new MediaRecorderNative();
mRebuild = true;
mMediaRecorder.setOnErrorListener(this);
mMediaRecorder.setOnEncodeListener(this);
File f = new File(VCamera.getVideoCachePath());
if (!FileUtils.checkFile(f)) {
f.mkdirs();
}
String key = String.valueOf(System.currentTimeMillis());
mMediaObject = mMediaRecorder.setOutputDirectory(key,
VCamera.getVideoCachePath() + key);
mMediaRecorder.setSurfaceHolder(mSurfaceView.getHolder());
mMediaRecorder.prepare();
}
/** 点击屏幕录制 */
private View.OnTouchListener mOnSurfaveViewTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mMediaRecorder == null || !mCreated) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 检测是否手动对焦
if (checkCameraFocus(event))
return true;
break;
}
return true;
}
};
/** 点击屏幕录制 */
private View.OnTouchListener mOnVideoControllerTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mMediaRecorder == null) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 检测是否手动对焦
// 判断是否已经超时
if (mMediaObject.getDuration() >= RECORD_TIME_MAX) {
return true;
}
// 取消回删
if (cancelDelete())
return true;
startRecord();
break;
case MotionEvent.ACTION_UP:
// 暂停
if (mPressedStatus) {
stopRecord();
// 检测是否已经完成
if (mMediaObject.getDuration() >= RECORD_TIME_MAX) {
mTitleNext.performClick();
}
}
break;
}
return true;
}
};
@Override
public void onResume() {
super.onResume();
UtilityAdapter.freeFilterParser();
UtilityAdapter.initFilterParser();
if (mMediaRecorder == null) {
initMediaRecorder();
} else {
mRecordLed.setChecked(false);
mMediaRecorder.prepare();
mProgressView.setData(mMediaObject);
}
}
@Override
public void onPause() {
super.onPause();
stopRecord();
UtilityAdapter.freeFilterParser();
if (!mReleased) {
if (mMediaRecorder != null)
mMediaRecorder.release();
}
mReleased = false;
}
/** 手动对焦 */
@SuppressLint("NewApi")
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private boolean checkCameraFocus(MotionEvent event) {
mFocusImage.setVisibility(View.GONE);
float x = event.getX();
float y = event.getY();
float touchMajor = event.getTouchMajor();
float touchMinor = event.getTouchMinor();
Rect touchRect = new Rect((int) (x - touchMajor / 2),
(int) (y - touchMinor / 2), (int) (x + touchMajor / 2),
(int) (y + touchMinor / 2));
// The direction is relative to the sensor orientation, that is, what
// the sensor sees. The direction is not affected by the rotation or
// mirroring of setDisplayOrientation(int). Coordinates of the rectangle
// range from -1000 to 1000. (-1000, -1000) is the upper left point.
// (1000, 1000) is the lower right point. The width and height of focus
// areas cannot be 0 or negative.
// No matter what the zoom level is, (-1000,-1000) represents the top of
// the currently visible camera frame
if (touchRect.right > 1000)
touchRect.right = 1000;
if (touchRect.bottom > 1000)
touchRect.bottom = 1000;
if (touchRect.left < 0)
touchRect.left = 0;
if (touchRect.right < 0)
touchRect.right = 0;
if (touchRect.left >= touchRect.right
|| touchRect.top >= touchRect.bottom)
return false;
ArrayList<Camera.Area> focusAreas = new ArrayList<Camera.Area>();
focusAreas.add(new Camera.Area(touchRect, 1000));
if (!mMediaRecorder.manualFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
// if (success) {
mFocusImage.setVisibility(View.GONE);
// }
}
}, focusAreas)) {
mFocusImage.setVisibility(View.GONE);
}
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mFocusImage
.getLayoutParams();
int left = touchRect.left - (mFocusWidth / 2);// (int) x -
// (focusingImage.getWidth()
// / 2);
int top = touchRect.top - (mFocusWidth / 2);// (int) y -
// (focusingImage.getHeight()
// / 2);
if (left < 0)
left = 0;
else if (left + mFocusWidth > mWindowWidth)
left = mWindowWidth - mFocusWidth;
if (top + mFocusWidth > mWindowWidth)
top = mWindowWidth - mFocusWidth;
lp.leftMargin = left;
lp.topMargin = top;
mFocusImage.setLayoutParams(lp);
mFocusImage.setVisibility(View.VISIBLE);
if (mFocusAnimation == null)
mFocusAnimation = AnimationUtils.loadAnimation(this,
R.anim.record_focus);
mFocusImage.startAnimation(mFocusAnimation);
mHandler.sendEmptyMessageDelayed(HANDLE_HIDE_RECORD_FOCUS, 3500);// 最多3.5秒也要消失
return true;
}
/** 开始录制 */
private void startRecord() {
if (mMediaRecorder != null) {
MediaObject.MediaPart part = mMediaRecorder.startRecord();
if (part == null) {
return;
}
// 如果使用MediaRecorderSystem,不能在中途切换前后摄像头,否则有问题
if (mMediaRecorder instanceof MediaRecorderSystem) {
mCameraSwitch.setVisibility(View.GONE);
}
mProgressView.setData(mMediaObject);
}
mRebuild = true;
mPressedStatus = true;
mRecordController.setImageResource(R.drawable.record_controller_press);
mBottomLayout.setBackgroundColor(mBackgroundColorPress);
if (mHandler != null) {
mHandler.removeMessages(HANDLE_INVALIDATE_PROGRESS);
mHandler.sendEmptyMessage(HANDLE_INVALIDATE_PROGRESS);
mHandler.removeMessages(HANDLE_STOP_RECORD);
mHandler.sendEmptyMessageDelayed(HANDLE_STOP_RECORD,
RECORD_TIME_MAX - mMediaObject.getDuration());
}
mRecordDelete.setVisibility(View.GONE);
mCameraSwitch.setEnabled(false);
mRecordLed.setEnabled(false);
}
@Override
public void onBackPressed() {
if (mRecordDelete != null && mRecordDelete.isChecked()) {
cancelDelete();
return;
}
if (mMediaObject != null && mMediaObject.getDuration() > 1) {
// 未转码
new AlertDialog.Builder(this)
.setTitle(R.string.hint)
.setMessage(R.string.record_camera_exit_dialog_message)
.setNegativeButton(
R.string.record_camera_cancel_dialog_yes,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
mMediaObject.delete();
finish();
overridePendingTransition(
R.anim.push_bottom_in,
R.anim.push_bottom_out);
}
})
.setPositiveButton(R.string.record_camera_cancel_dialog_no,
null).setCancelable(false).show();
return;
}
if (mMediaObject != null)
mMediaObject.delete();
finish();
overridePendingTransition(R.anim.push_bottom_in, R.anim.push_bottom_out);
}
/** 停止录制 */
private void stopRecord() {
mPressedStatus = false;
mRecordController.setImageResource(R.drawable.record_controller_normal);
mBottomLayout.setBackgroundColor(mBackgroundColorNormal);
if (mMediaRecorder != null) {
mMediaRecorder.stopRecord();
}
mRecordDelete.setVisibility(View.VISIBLE);
mCameraSwitch.setEnabled(true);
mRecordLed.setEnabled(true);
mHandler.removeMessages(HANDLE_STOP_RECORD);
checkStatus();
}
@Override
public void onClick(View v) {
final int id = v.getId();
if (mHandler.hasMessages(HANDLE_STOP_RECORD)) {
mHandler.removeMessages(HANDLE_STOP_RECORD);
}
// 处理开启回删后其他点击操作
if (id != R.id.record_delete) {
if (mMediaObject != null) {
MediaObject.MediaPart part = mMediaObject.getCurrentPart();
if (part != null) {
if (part.remove) {
part.remove = false;
mRecordDelete.setChecked(false);
if (mProgressView != null)
mProgressView.invalidate();
}
}
}
}
switch (id) {
case R.id.title_back:
onBackPressed();
break;
case R.id.record_camera_switcher:// 前后摄像头切换
if (mRecordLed.isChecked()) {
if (mMediaRecorder != null) {
mMediaRecorder.toggleFlashMode();
}
mRecordLed.setChecked(false);
}
if (mMediaRecorder != null) {
mMediaRecorder.switchCamera();
}
if (mMediaRecorder.isFrontCamera()) {
mRecordLed.setEnabled(false);
} else {
mRecordLed.setEnabled(true);
}
break;
case R.id.record_camera_led:// 闪光灯
// 开启前置摄像头以后不支持开启闪光灯
if (mMediaRecorder != null) {
if (mMediaRecorder.isFrontCamera()) {
return;
}
}
if (mMediaRecorder != null) {
mMediaRecorder.toggleFlashMode();
}
break;
case R.id.title_next:// 停止录制
mMediaRecorder.startEncoding();
finish();
overridePendingTransition(R.anim.push_bottom_in,
R.anim.push_bottom_out);
break;
case R.id.record_delete:
// 取消回删
if (mMediaObject != null) {
MediaObject.MediaPart part = mMediaObject.getCurrentPart();
if (part != null) {
if (part.remove) {
mRebuild = true;
part.remove = false;
mMediaObject.removePart(part, true);
mRecordDelete.setChecked(false);
} else {
part.remove = true;
mRecordDelete.setChecked(true);
}
}
if (mProgressView != null)
mProgressView.invalidate();
// 检测按钮状态
checkStatus();
}
break;
}
}
/** 取消回删 */
private boolean cancelDelete() {
if (mMediaObject != null) {
MediaObject.MediaPart part = mMediaObject.getCurrentPart();
if (part != null && part.remove) {
part.remove = false;
mRecordDelete.setChecked(false);
if (mProgressView != null)
mProgressView.invalidate();
return true;
}
}
return false;
}
/** 检查录制时间,显示/隐藏下一步按钮 */
private int checkStatus() {
int duration = 0;
if (!isFinishing() && mMediaObject != null) {
duration = mMediaObject.getDuration();
if (duration < RECORD_TIME_MIN) {
if (duration == 0) {
mCameraSwitch.setVisibility(View.VISIBLE);
mRecordDelete.setVisibility(View.GONE);
}
// 视频必须大于3秒
if (mTitleNext.getVisibility() != View.INVISIBLE)
mTitleNext.setVisibility(View.INVISIBLE);
} else {
// 下一步
if (mTitleNext.getVisibility() != View.VISIBLE) {
mTitleNext.setVisibility(View.VISIBLE);
}
}
}
return duration;
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case HANDLE_INVALIDATE_PROGRESS:
if (mMediaRecorder != null && !isFinishing()) {
if (mProgressView != null)
mProgressView.invalidate();
// if (mPressedStatus)
// titleText.setText(String.format("%.1f",
// mMediaRecorder.getDuration() / 1000F));
if (mPressedStatus)
sendEmptyMessageDelayed(0, 30);
}
break;
}
}
};
@Override
public void onEncodeStart() {
showProgress("", getString(R.string.record_camera_progress_message));
}
@Override
public void onEncodeProgress(int progress) {
Logger.e("[MediaRecorderActivity]onEncodeProgress..." + progress);
}
/** 转码完成 */
@Override
public void onEncodeComplete() {
hideProgress();
Intent intent = new Intent(this, MediaPreviewActivity.class);
Bundle bundle = getIntent().getExtras();
if (bundle == null)
bundle = new Bundle();
bundle.putSerializable(CommonIntentExtra.EXTRA_MEDIA_OBJECT,
mMediaObject);
bundle.putString("output", mMediaObject.getOutputTempVideoPath());
bundle.putBoolean("Rebuild", mRebuild);
intent.putExtras(bundle);
startActivity(intent);
mRebuild = false;
// finish();
// overridePendingTransition(R.anim.push_bottom_in,
// R.anim.push_bottom_out);
}
/**
* 转码失败 检查sdcard是否可用,检查分块是否存在
*/
@Override
public void onEncodeError() {
hideProgress();
Toast.makeText(this, R.string.record_video_transcoding_faild,
Toast.LENGTH_SHORT).show();
}
@Override
public void onVideoError(int what, int extra) {
}
@Override
public void onAudioError(int what, String message) {
}
@Override
public void onPrepared() {
}
public void onFinished() {
finish();
overridePendingTransition(R.anim.push_bottom_in, R.anim.push_bottom_out);
}
}