实例介绍
【实例简介】 有点仿 微信拍短视频的感觉,按住屏幕任何位置拍摄
【实例截图】
【核心代码】
package com.yixia.camera.demo.ui.record; import java.io.File; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.database.Cursor; import android.graphics.drawable.BitmapDrawable; import android.hardware.Camera; import android.hardware.Camera.AutoFocusCallback; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.provider.MediaStore; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup.LayoutParams; import android.view.WindowManager; import android.widget.CheckedTextView; import android.widget.ImageView; import android.widget.PopupWindow; import android.widget.RadioGroup; import android.widget.TextView; import android.widget.Toast; import com.yixia.camera.FFMpegUtils; import com.yixia.camera.MediaRecorder; import com.yixia.camera.MediaRecorder.OnErrorListener; import com.yixia.camera.MediaRecorder.OnPreparedListener; import com.yixia.camera.MediaRecorderFilter; import com.yixia.camera.VCamera; import com.yixia.camera.demo.R; 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.ui.record.views.ThemeRadioButton; import com.yixia.camera.demo.utils.ConvertToUtils; import com.yixia.camera.demo.utils.NetworkUtils; import com.yixia.camera.model.MediaObject; import com.yixia.camera.model.MediaObject.MediaPart; import com.yixia.camera.util.DeviceUtils; import com.yixia.camera.util.FileUtils; import com.yixia.camera.util.StringUtils; import com.yixia.camera.view.CameraNdkView; /** * 视频录制 * * @author tangjun@yixia.com * */ public class MediaRecorderActivity extends BaseActivity implements OnErrorListener, OnClickListener, OnPreparedListener { /** 滤镜图标 */ private final static int[] FILTER_ICONS = new int[] { R.drawable.filter_original, R.drawable.filter_black_white, R.drawable.filter_sharpen, R.drawable.filter_old_film, R.drawable.filter_edge, R.drawable.filter_anti_color, R.drawable.filter_radial, R.drawable.filter_8bit, R.drawable.filter_lomo }; /** 滤镜枚举值 */ private final static String[] FILTER_VALUES = new String[] { MediaRecorderFilter.CAMERA_FILTER_NO, MediaRecorderFilter.CAMERA_FILTER_BLACKWHITE, MediaRecorderFilter.CAMERA_FILTER_SHARPEN, MediaRecorderFilter.CAMERA_FILTER_OLD_PHOTOS, MediaRecorderFilter.CAMERA_FILTER_NEON_LIGHT, MediaRecorderFilter.CAMERA_FILTER_ANTICOLOR, MediaRecorderFilter.CAMERA_FILTER_PASS_THROUGH, MediaRecorderFilter.CAMERA_FILTER_MOSAICS, MediaRecorderFilter.CAMERA_FILTER_REMINISCENCE }; /** 导入图片 */ public final static int REQUEST_CODE_IMPORT_IMAGE = 999; /** 导入视频 */ public final static int REQUEST_CODE_IMPORT_VIDEO = 998; /** 导入视频截取 */ public final static int REQUEST_CODE_IMPORT_VIDEO_EDIT = 997; /** 录制最长时间 */ public final static int RECORD_TIME_MAX = 10 * 1000; /** 录制最小时间 */ public final static int RECORD_TIME_MIN = 3 * 1000; private CheckedTextView mRecordDelete, mRecordDelay, mRecordFilter; private ProgressView mProgressView; private CameraNdkView mSurfaceView; private TextView mTitleText, mTitleNext, mRecordImport; private ImageView mPressText; /** 滤镜容器 */ private RadioGroup mRecordFilterContainer; private View mRecordFilterLayout; private PopupWindow mPopupWindow; private MediaRecorderFilter mMediaRecorder; private MediaObject mMediaObject; private int mWindowWidth; /** 是否是点击状态 */ private volatile boolean mPressedStatus, mReleased, mStartEncoding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);// 防止锁屏 mWindowWidth = DeviceUtils.getScreenWidth(this); setContentView(R.layout.activity_media_recorder); // ~~~ 绑定控件 mSurfaceView = (CameraNdkView) findViewById(R.id.record_preview); mProgressView = (ProgressView) findViewById(R.id.record_progress); mTitleText = (TextView) findViewById(R.id.title_text); mTitleNext = (TextView) findViewById(R.id.title_right); mRecordDelay = (CheckedTextView) findViewById(R.id.record_delay); mRecordDelete = (CheckedTextView) findViewById(R.id.record_delete); mRecordFilter = (CheckedTextView) findViewById(R.id.record_filter); mPressText = (ImageView) findViewById(R.id.record_tips_text); mRecordFilterContainer = (RadioGroup) findViewById(R.id.record_filter_container); mRecordFilterLayout = findViewById(R.id.record_filter_layout); mRecordImport = (TextView) findViewById(R.id.record_import); // ~~~ 绑定事件 findViewById(R.id.record_layout).setOnTouchListener(mOnSurfaceViewTouchListener); mTitleNext.setOnClickListener(this); mRecordDelete.setOnClickListener(this); mRecordFilter.setOnClickListener(this); mRecordDelay.setOnClickListener(this); mRecordImport.setOnClickListener(this); // ~~~ 初始数据 mSurfaceView.getLayoutParams().height = mWindowWidth;//(int) (mWindowWidth * 3F / 2);//视频为640x480,后期裁剪成1:1的视频 findViewById(R.id.record_layout).getLayoutParams().height = mWindowWidth;//设置1:1预览范围 mProgressView.invalidate(); // mDelayAnimation = AnimationUtils.loadAnimation(this, R.anim.record_delay_anim); } @Override protected void onStart() { super.onStart(); if (mMediaRecorder == null) initMediaRecorder(); else { mMediaRecorder.setSurfaceHolder(mSurfaceView.getHolder()); mMediaRecorder.prepare(); } checkStatus(); } @Override protected void onStop() { super.onStop(); if (mMediaRecorder != null && !mReleased) { mMediaRecorder.release(); } } @Override public void onBackPressed() { if (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.dialog_yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mMediaObject.delete(); finish(); } }).setPositiveButton(R.string.dialog_no, null).setCancelable(false).show(); return; } if (mMediaObject != null) mMediaObject.delete(); super.onBackPressed(); } private void initMediaRecorder() { mMediaRecorder = new MediaRecorderFilter(); mMediaRecorder.setOnErrorListener(this); mMediaRecorder.setOnPreparedListener(this); //WIFI下800k码率,其他情况(4G/3G/2G)600K码率 mMediaRecorder.setVideoBitRate(NetworkUtils.isWifiAvailable(this) ? MediaRecorder.VIDEO_BITRATE_MEDIUM : MediaRecorder.VIDEO_BITRATE_NORMAL); // mMediaRecorder.setSurfaceHolder(mSurfaceView.getHolder()); mMediaRecorder.setSurfaceView(mSurfaceView); String key = String.valueOf(System.currentTimeMillis()); mMediaObject = mMediaRecorder.setOutputDirectory(key, VCamera.getVideoCachePath() key); if (mMediaObject != null) { mMediaRecorder.prepare(); mMediaRecorder.setCameraFilter(MediaRecorderFilter.CAMERA_FILTER_NO); mProgressView.setData(mMediaObject); } else { Toast.makeText(this, R.string.record_camera_init_faild, Toast.LENGTH_SHORT).show(); finish(); } } private View.OnTouchListener mOnSurfaceViewTouchListener = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (mMediaRecorder == null || mMediaObject == null) { return false; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //检测是否手动对焦 // if (checkCameraFocus(event)) // return true; //取消回删 if (cancelDelete()) return true; //取消延时拍摄 // if (mRecordDelay.isChecked()) { // stopRecord(); // return true; // } //判断是否已经超时 if (mMediaObject.getDuration() >= RECORD_TIME_MAX) { return true; } //显示当前时间 mTitleText.setText(String.format("%.1f", mMediaObject.getDuration() / 1000F)); startRecord(); break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: // 暂停 if (mPressedStatus) { stopRecord(); //检测是否已经完成 if (mMediaObject.getDuration() >= RECORD_TIME_MAX) { mTitleNext.performClick(); } } mTitleText.setText(R.string.record_camera_title); break; } return true; } }; /** 开始拍摄 */ private void startRecord() { mPressedStatus = true; if (mMediaRecorder != null) { mMediaRecorder.startRecord(); } if (mHandler != null) { mHandler.sendEmptyMessage(HANDLE_INVALIDATE_PROGRESS); mHandler.sendEmptyMessageDelayed(HANDLE_STOP_RECORD, RECORD_TIME_MAX - mMediaObject.getDuration()); } mHandler.removeMessages(HANDLE_SHOW_TIPS); mHandler.sendEmptyMessage(HANDLE_SHOW_TIPS); mRecordDelete.setEnabled(false); if (!mRecordDelay.isChecked()) mRecordDelay.setEnabled(false); mPressText.setImageResource(R.drawable.record_tips_pause); } private void stopRecord() { mPressedStatus = false; //提示完成 mPressText.setImageResource(R.drawable.record_tips_press); if (mMediaRecorder != null) mMediaRecorder.stopRecord(); //取消倒计时 mHandler.removeMessages(HANDLE_STOP_RECORD); mRecordDelay.setChecked(false); mRecordDelay.setEnabled(true); mRecordDelete.setEnabled(true); } /** 是否可回删 */ private boolean cancelDelete() { if (mMediaObject != null) { 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 static final int HANDLE_INVALIDATE_PROGRESS = 0; /** 延迟拍摄停止 */ private static final int HANDLE_STOP_RECORD = 1; /** 显示下一步 */ private static final int HANDLE_SHOW_TIPS = 2; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case HANDLE_INVALIDATE_PROGRESS: if (mMediaObject != null && !isFinishing()) { if (mProgressView != null) mProgressView.invalidate(); if (mPressedStatus) mTitleText.setText(String.format("%.1f", mMediaObject.getDuration() / 1000F)); if (mPressedStatus) sendEmptyMessageDelayed(0, 30); } break; case HANDLE_SHOW_TIPS: if (mMediaRecorder != null && !isFinishing()) { int duration = checkStatus(); if (mPressedStatus) { if (duration < RECORD_TIME_MAX) { sendEmptyMessageDelayed(HANDLE_SHOW_TIPS, 200); } else { sendEmptyMessageDelayed(HANDLE_SHOW_TIPS, 500); } } } break; case HANDLE_STOP_RECORD: stopRecord(); startEncoding(); break; } } }; /** 导入图片或视频 */ private void importImageOrVideo(final String path) { if (!isFinishing() && mMediaObject != null && StringUtils.isNotEmpty(path) && new File(path).exists()) { new AsyncTask<Void, Void, Boolean>() { @Override protected void onPreExecute() { super.onPreExecute(); showProgress("", getString(R.string.record_camera_progress_message)); } @Override protected Boolean doInBackground(Void... params) { MediaPart part = mMediaObject.buildMediaPart(path, 1000, MediaObject.MEDIA_PART_TYPE_IMPORT_IMAGE); if (part != null) { return FFMpegUtils.convertImage2Video(part); } return false; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); hideProgress(); if (result) { mProgressView.setData(mMediaObject); } else { Toast.makeText(MediaRecorderActivity.this, R.string.record_video_transcoding_faild, Toast.LENGTH_SHORT).show(); } } }.execute(); } } private void startEncoding() { //检测磁盘空间 if (FileUtils.showFileAvailable() < 200) { Toast.makeText(this, R.string.record_camera_check_available_faild, Toast.LENGTH_SHORT).show(); return; } if (!isFinishing() && mMediaRecorder != null && mMediaObject != null && !mStartEncoding) { mStartEncoding = true; new AsyncTask<Void, Void, Boolean>() { @Override protected void onPreExecute() { super.onPreExecute(); showProgress("", getString(R.string.record_camera_progress_message)); } @Override protected Boolean doInBackground(Void... params) { boolean result = FFMpegUtils.videoTranscoding(mMediaObject, mMediaObject.getOutputTempVideoPath(), mWindowWidth, false); if (result && mMediaRecorder != null) { mMediaRecorder.release(); mReleased = true; } return result; } @Override protected void onCancelled() { super.onCancelled(); mStartEncoding = false; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); hideProgress(); if (result) { /** 序列化保存数据 */ if (saveMediaObject(mMediaObject)) { Intent intent = new Intent(MediaRecorderActivity.this, MediaPreviewActivity.class); intent.putExtra("obj", mMediaObject.getObjectFilePath()); startActivity(intent); } else { Toast.makeText(MediaRecorderActivity.this, R.string.record_camera_save_faild, Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(MediaRecorderActivity.this, R.string.record_video_transcoding_faild, Toast.LENGTH_SHORT).show(); } mStartEncoding = false; } }.execute(); } } /** 检测是否超过三秒 */ private int checkStatus() { int duration = 0; if (!isFinishing() && mMediaObject != null) { duration = mMediaObject.getDuration(); if (duration < RECORD_TIME_MIN) { //视频必须大于3秒 if (mTitleNext.getVisibility() != View.INVISIBLE) mTitleNext.setVisibility(View.INVISIBLE); } else { //下一步 if (mTitleNext.getVisibility() != View.VISIBLE) { mTitleNext.setVisibility(View.VISIBLE); mTitleNext.setText(R.string.record_camera_next); } } } return duration; } @Override public void onVideoError(int what, int extra) { Logger.e("[MediaRecorderActvity]onVideoError: what" what " extra:" extra); } @Override public void onAudioError(int what, String message) { Logger.e("[MediaRecorderActvity]onAudioError: what" what " message:" message); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MediaRecorderActivity.this, R.string.record_camera_open_audio_faild, Toast.LENGTH_SHORT).show(); } }); } @Override public void onClick(View v) { final int id = v.getId(); //处理开启回删后其他点击操作 if (id != R.id.record_delete) { if (mMediaObject != null) { MediaPart part = mMediaObject.getCurrentPart(); if (part != null) { if (part.remove) { part.remove = false; mRecordDelete.setChecked(false); if (mProgressView != null) mProgressView.invalidate(); } } } } if (id != R.id.record_filter) { if (mRecordFilter.isChecked()) { mRecordFilterLayout.setVisibility(View.GONE); mRecordFilter.setChecked(false); } } switch (v.getId()) { case R.id.record_import://导入 showImportMenu(); break; case R.id.title_right: startEncoding(); break; case R.id.record_delete: if (mMediaObject != null) { MediaPart part = mMediaObject.getCurrentPart(); if (part != null) { if (part.remove) { //确认删除分块 part.remove = false; mMediaObject.removePart(part, true); mRecordDelete.setChecked(false); } else { part.remove = true; mRecordDelete.setChecked(true); } } if (mProgressView != null) mProgressView.invalidate(); //检测按钮状态 checkStatus(); } break; case R.id.record_filter: if (mRecordFilter.isChecked()) { mRecordFilterLayout.setVisibility(View.GONE); mRecordFilter.setChecked(false); } else { loadFilter(); mRecordFilterLayout.setVisibility(View.VISIBLE); mRecordFilter.setChecked(true); } break; case R.id.import_image: { if (mPopupWindow != null) { mPopupWindow.dismiss(); mPopupWindow = null; } Intent intent = new Intent(); intent.setAction(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); startActivityForResult(Intent.createChooser(intent, getString(R.string.record_camera_import_image_choose)), REQUEST_CODE_IMPORT_IMAGE); } break; case R.id.import_video: { if (mPopupWindow != null) { mPopupWindow.dismiss(); mPopupWindow = null; } Intent intent = new Intent(); intent.setAction(Intent.ACTION_GET_CONTENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("video/*"); startActivityForResult(Intent.createChooser(intent, getString(R.string.record_camera_import_video_choose)), REQUEST_CODE_IMPORT_VIDEO); } break; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { if (requestCode == REQUEST_CODE_IMPORT_VIDEO_EDIT) { mMediaObject = restoneMediaObject(mMediaObject.getObjectFilePath()); mProgressView.setData(mMediaObject); } else { //处理导入图片和视频 if (data != null) { Uri uri = data.getData(); if (uri != null) { String columnName; switch (requestCode) { case REQUEST_CODE_IMPORT_IMAGE://导入图片 columnName = MediaStore.Images.Media.DATA; break; case REQUEST_CODE_IMPORT_VIDEO: columnName = MediaStore.Video.Media.DATA; break; default: return; } if (StringUtils.isNotEmpty(columnName)) { Cursor cursor = getContentResolver().query(uri, new String[] { columnName }, null, null, null); if (cursor != null) { String path = ""; if (cursor.moveToNext()) { path = cursor.getString(0); } cursor.close(); switch (requestCode) { case REQUEST_CODE_IMPORT_IMAGE://导入图片 importImageOrVideo(path); break; case REQUEST_CODE_IMPORT_VIDEO: if (saveMediaObject(mMediaObject)) { startActivityForResult(new Intent(this, ImportVideoActivity.class).putExtra("obj", mMediaObject.getObjectFilePath()).putExtra("path", path), REQUEST_CODE_IMPORT_VIDEO_EDIT); } break; } } } } } } } super.onActivityResult(requestCode, resultCode, data); } @SuppressWarnings("deprecation") private void showImportMenu() { View view = LayoutInflater.from(this).inflate(R.layout.menu_record_import, null); mPopupWindow = new PopupWindow(view, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, true); view.findViewById(R.id.import_image).setOnClickListener(this); view.findViewById(R.id.import_video).setOnClickListener(this); mPopupWindow.setFocusable(true); mPopupWindow.setOutsideTouchable(true); mPopupWindow.setBackgroundDrawable(new BitmapDrawable()); view.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); mPopupWindow.showAsDropDown(mRecordImport, 0, -view.getMeasuredHeight() - mRecordImport.getHeight()); } /** 加载滤镜 */ private void loadFilter() { if (!isFinishing() && mRecordFilterContainer.getChildCount() == 0) { final String[] filterNames = getResources().getStringArray(R.array.record_filter); int leftMargin = ConvertToUtils.dipToPX(this, 10); LayoutInflater mInflater = LayoutInflater.from(this); for (int i = 0; i < FILTER_ICONS.length; i ) { ThemeRadioButton filterView = (ThemeRadioButton) mInflater.inflate(R.layout.view_radio_item, null); filterView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int index = ConvertToUtils.toInt(v.getTag().toString()); if (mMediaRecorder != null) mMediaRecorder.setCameraFilter(FILTER_VALUES[index]); } }); filterView.setCompoundDrawablesWithIntrinsicBounds(0, FILTER_ICONS[i], 0, 0); filterView.setText(filterNames[i]); filterView.setTag(i); RadioGroup.LayoutParams lp = new RadioGroup.LayoutParams(RadioGroup.LayoutParams.WRAP_CONTENT, RadioGroup.LayoutParams.WRAP_CONTENT); lp.leftMargin = leftMargin; mRecordFilterContainer.addView(filterView, lp); } mRecordFilterContainer.getChildAt(0).performClick(); } } @Override public void onPrepared() { if (mMediaRecorder != null) { //自动对焦 mMediaRecorder.autoFocus(new AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { if (success) { } } }); } } }
标签: 视频
网友评论
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
支持(0) 盖楼(回复)
支持(0) 盖楼(回复)
支持(0) 盖楼(回复)
支持(0) 盖楼(回复)