commit e2dc633112d3e23be2e28fcfae19423f730435cc Author: wuxiang Date: Tue Sep 28 16:25:05 2021 +0800 init diff --git a/package.json b/package.json new file mode 100644 index 0000000..bc4929b --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "capture-cordova-plugin", + "version": "1.0.0", + "description": "Video or Photo Capture Cordova Plugin", + "cordova": { + "id": "capture-cordova-plugin", + "platforms": [ + "android" + ] + }, + "repository": { + "type": "git", + "url": "https://m.shuto.cn:8680/center/capture-cordova-plugin.git" + }, + "keywords": [ + "ecosystem:cordova", + "cordova-android" + ], + "author": "shuto", + "license": "ISC" +} diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..4b7aaef --- /dev/null +++ b/plugin.xml @@ -0,0 +1,35 @@ + + + Capture Plugin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/android/CaptureCordovaPlugin.java b/src/android/CaptureCordovaPlugin.java new file mode 100644 index 0000000..58bc4af --- /dev/null +++ b/src/android/CaptureCordovaPlugin.java @@ -0,0 +1,31 @@ +package cn.shuto.plugin.capture; + +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.CallbackContext; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * This class echoes a string called from JavaScript. + */ +public class CaptureCordovaPlugin extends CordovaPlugin { + public static final int REQUEST_CODE = 0x777578; + private CallbackContext callbackContext; + + @Override + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { + this.callbackContext = callbackContext; + JSONObject param = args.optJSONObject(0); + if (action.equals("capture")) { + this.capture(param, callbackContext); + return true; + } + return false; + } + + private void capture(JSONObject param, CallbackContext callbackContext) { + } + +} diff --git a/src/android/MediaRecorderActivity.java b/src/android/MediaRecorderActivity.java new file mode 100644 index 0000000..781aea4 --- /dev/null +++ b/src/android/MediaRecorderActivity.java @@ -0,0 +1,704 @@ +package com.mabeijianxi.smallvideorecord2; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.Intent; +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.Window; +import android.view.WindowManager; +import android.widget.CheckBox; +import android.widget.CheckedTextView; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.mabeijianxi.smallvideorecord2.model.MediaObject; +import com.mabeijianxi.smallvideorecord2.model.MediaRecorderConfig; + +import java.io.File; + +import static com.mabeijianxi.smallvideorecord2.R.id.bottom_layout; + + +/** + * 视频录制 + */ +public class MediaRecorderActivity extends Activity implements + MediaRecorderBase.OnErrorListener, OnClickListener, MediaRecorderBase.OnPreparedListener, + MediaRecorderBase.OnEncodeListener { + + private int RECORD_TIME_MIN = (int) (1.5f * 1000); + /** + * 录制最长时间 + */ + private int RECORD_TIME_MAX = 6 * 1000; + /** + * 刷新进度条 + */ + private static final int HANDLE_INVALIDATE_PROGRESS = 0; + /** + * 延迟拍摄停止 + */ + private static final int HANDLE_STOP_RECORD = 1; + + /** + * 下一步 + */ + private ImageView mTitleNext; + /** + * 前后摄像头切换 + */ + private CheckBox mCameraSwitch; + /** + * 回删按钮、延时按钮、滤镜按钮 + */ + private CheckedTextView mRecordDelete; + /** + * 闪光灯 + */ + private CheckBox mRecordLed; + /** + * 拍摄按钮 + */ + private TextView mRecordController; + + /** + * 底部条 + */ + private RelativeLayout mBottomLayout; + /** + * 摄像头数据显示画布 + */ + private SurfaceView mSurfaceView; + /** + * 录制进度 + */ + private ProgressView mProgressView; + + /** + * SDK视频录制对象 + */ + private MediaRecorderBase mMediaRecorder; + /** + * 视频信息 + */ + private MediaObject mMediaObject; + + /** + * 是否是点击状态 + */ + private volatile boolean mPressedStatus; + /** + * 是否已经释放 + */ + private volatile boolean mReleased; + /** + * 视屏地址 + */ + public final static String VIDEO_URI = "video_uri"; + /** + * 本次视频保存的文件夹地址 + */ + public final static String OUTPUT_DIRECTORY = "output_directory"; + /** + * 视屏截图地址 + */ + public final static String VIDEO_SCREENSHOT = "video_screenshot"; + /** + * 录制完成后需要跳转的activity + */ + public final static String OVER_ACTIVITY_NAME = "over_activity_name"; + /** + * 最大录制时间的key + */ + public final static String MEDIA_RECORDER_MAX_TIME_KEY = "media_recorder_max_time_key"; + /** + * 最小录制时间的key + */ + public final static String MEDIA_RECORDER_MIN_TIME_KEY = "media_recorder_min_time_key"; + /** + * 录制配置key + */ + public final static String MEDIA_RECORDER_CONFIG_KEY = "media_recorder_config_key"; + + private boolean GO_HOME; + private boolean startState; + private boolean NEED_FULL_SCREEN = false; + private RelativeLayout title_layout; + + /** + * @param context + * @param overGOActivityName 录制结束后需要跳转的Activity全类名 + */ + public static void goSmallVideoRecorder(Activity context, String overGOActivityName, MediaRecorderConfig mediaRecorderConfig) { + context.startActivity(new Intent(context, MediaRecorderActivity.class).putExtra(OVER_ACTIVITY_NAME, overGOActivityName).putExtra(MEDIA_RECORDER_CONFIG_KEY, mediaRecorderConfig)); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // 防止锁屏 + initData(); + loadViews(); + } + + private void initData() { + Intent intent = getIntent(); + MediaRecorderConfig mediaRecorderConfig = intent.getParcelableExtra(MEDIA_RECORDER_CONFIG_KEY); + if (mediaRecorderConfig == null) { + return; + } + NEED_FULL_SCREEN = mediaRecorderConfig.getFullScreen(); + RECORD_TIME_MAX = mediaRecorderConfig.getRecordTimeMax(); + RECORD_TIME_MIN = mediaRecorderConfig.getRecordTimeMin(); + MediaRecorderBase.MAX_FRAME_RATE = mediaRecorderConfig.getMaxFrameRate(); + MediaRecorderBase.NEED_FULL_SCREEN = NEED_FULL_SCREEN; + MediaRecorderBase.MIN_FRAME_RATE = mediaRecorderConfig.getMinFrameRate(); + MediaRecorderBase.SMALL_VIDEO_HEIGHT = mediaRecorderConfig.getSmallVideoHeight(); + MediaRecorderBase.SMALL_VIDEO_WIDTH = mediaRecorderConfig.getSmallVideoWidth(); + MediaRecorderBase.mVideoBitrate = mediaRecorderConfig.getVideoBitrate(); + MediaRecorderBase.CAPTURE_THUMBNAILS_TIME = mediaRecorderConfig.getCaptureThumbnailsTime(); + GO_HOME = mediaRecorderConfig.isGO_HOME(); + } + + /** + * 加载视图 + */ + private void loadViews() { + setContentView(R.layout.activity_media_recorder); + // ~~~ 绑定控件 + mSurfaceView = (SurfaceView) findViewById(R.id.record_preview); + title_layout = (RelativeLayout) findViewById(R.id.title_layout); + mCameraSwitch = (CheckBox) findViewById(R.id.record_camera_switcher); + mTitleNext = (ImageView) findViewById(R.id.title_next); + mProgressView = (ProgressView) findViewById(R.id.record_progress); + mRecordDelete = (CheckedTextView) findViewById(R.id.record_delete); + mRecordController = (TextView) findViewById(R.id.record_controller); + mBottomLayout = (RelativeLayout) findViewById(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); + mRecordController.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); + } + + + mProgressView.setMaxDuration(RECORD_TIME_MAX); + mProgressView.setMinTime(RECORD_TIME_MIN); + } + + /** + * 初始化画布 + */ + private void initSurfaceView() { + if (NEED_FULL_SCREEN) { + mBottomLayout.setBackgroundColor(0); + title_layout.setBackgroundColor(getResources().getColor(R.color.full_title_color)); + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mSurfaceView + .getLayoutParams(); + lp.setMargins(0,0,0,0); + mSurfaceView.setLayoutParams(lp); + mProgressView.setBackgroundColor(getResources().getColor(R.color.full_progress_color)); + } else { + final int w = DeviceUtils.getScreenWidth(this); + ((RelativeLayout.LayoutParams) mBottomLayout.getLayoutParams()).topMargin = (int) (w / (MediaRecorderBase.SMALL_VIDEO_HEIGHT / (MediaRecorderBase.SMALL_VIDEO_WIDTH * 1.0f))); + int width = w; + int height = (int) (w * ((MediaRecorderBase.mSupportedPreviewWidth * 1.0f) / MediaRecorderBase.SMALL_VIDEO_HEIGHT)); + // + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mSurfaceView + .getLayoutParams(); + lp.width = width; + lp.height = height; + mSurfaceView.setLayoutParams(lp); + } + } + + /** + * 初始化拍摄SDK + */ + private void initMediaRecorder() { + mMediaRecorder = new MediaRecorderNative(); + + mMediaRecorder.setOnErrorListener(this); + mMediaRecorder.setOnEncodeListener(this); + mMediaRecorder.setOnPreparedListener(this); + + File f = new File(JianXiCamera.getVideoCachePath()); + if (!FileUtils.checkFile(f)) { + f.mkdirs(); + } + String key = String.valueOf(System.currentTimeMillis()); + mMediaObject = mMediaRecorder.setOutputDirectory(key, + JianXiCamera.getVideoCachePath() + key); + mMediaRecorder.setSurfaceHolder(mSurfaceView.getHolder()); + mMediaRecorder.prepare(); + } + + + /** + * 点击屏幕录制 + */ + 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; + if (!startState) { + startState = true; + startRecord(); + } else { + mMediaObject.buildMediaPart(mMediaRecorder.mCameraId); + mProgressView.setData(mMediaObject); + setStartUI(); + mMediaRecorder.setRecordState(true); + } + + break; + + case MotionEvent.ACTION_UP: + + mMediaRecorder.setRecordState(false); + if (mMediaObject.getDuration() >= RECORD_TIME_MAX) { + mTitleNext.performClick(); + } else { + mMediaRecorder.setStopDate(); + setStopUI(); + } + + + // 暂停 +/* if (mPressedStatus) { + + // 检测是否已经完成 + if (mMediaObject.getDuration() >= RECORD_TIME_MAX) { + mTitleNext.performClick(); + } + }*/ + break; + } + return true; + } + + }; + + @Override + public void onResume() { + super.onResume(); + + if (mMediaRecorder == null) { + initMediaRecorder(); + } else { + mRecordLed.setChecked(false); + mMediaRecorder.prepare(); + mProgressView.setData(mMediaObject); + } + } + + /*@Override + public void onPause() { + super.onPause(); + stopRecord(); + if (!mReleased) { + if (mMediaRecorder != null) + mMediaRecorder.release(); + } + mReleased = false; + }*/ + + + /** + * 开始录制 + */ + private void startRecord() { + if (mMediaRecorder != null) { + + MediaObject.MediaPart part = mMediaRecorder.startRecord(); + if (part == null) { + return; + } + + mProgressView.setData(mMediaObject); + } + + setStartUI(); + } + + private void setStartUI() { + mPressedStatus = true; +// TODO 开始录制的图标 + mRecordController.animate().scaleX(0.8f).scaleY(0.8f).setDuration(500).start(); + + + 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(); + } + + }) + .setPositiveButton(R.string.record_camera_cancel_dialog_no, + null).setCancelable(false).show(); + return; + } + + if (mMediaObject != null) + mMediaObject.delete(); + finish(); + } + + /** + * 停止录制 + */ + private void stopRecord() { + if (mMediaRecorder != null) { + mMediaRecorder.stopRecord(); + } + setStopUI(); + } + + private void setStopUI() { + mPressedStatus = false; + mRecordController.animate().scaleX(1).scaleY(1).setDuration(500).start(); + + +// 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(); + } + } + } + } + + if (id == R.id.title_back) { + onBackPressed(); + } else if (id == 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); + } + } else if (id == R.id.record_camera_led) {// 闪光灯 + // 开启前置摄像头以后不支持开启闪光灯 + if (mMediaRecorder != null) { + if (mMediaRecorder.isFrontCamera()) { + return; + } + } + + if (mMediaRecorder != null) { + mMediaRecorder.toggleFlashMode(); + } + } else if (id == R.id.title_next) {// 停止录制 + stopRecord(); + /*finish(); + overridePendingTransition(R.anim.push_bottom_in, + R.anim.push_bottom_out);*/ + } else if (id == R.id.record_delete) { + // 取消回删 + if (mMediaObject != null) { + MediaObject.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(); + } + } + } + + + /** + * 取消回删 + */ + 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); + } else { + mCameraSwitch.setVisibility(View.GONE); + } + // 视频必须大于3秒 + if (mTitleNext.getVisibility() != View.INVISIBLE) + mTitleNext.setVisibility(View.INVISIBLE); + } else { + // 下一步 + if (mTitleNext.getVisibility() != View.VISIBLE) { + mTitleNext.setVisibility(View.VISIBLE); + } + } + } + return 0; + } + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case HANDLE_INVALIDATE_PROGRESS: + if (mMediaRecorder != null && !isFinishing()) { + if (mMediaObject != null && mMediaObject.getMedaParts() != null && mMediaObject.getDuration() >= RECORD_TIME_MAX) { + mTitleNext.performClick(); + return; + } + 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) { + } + + /** + * 转码完成 + */ + @Override + public void onEncodeComplete() { + hideProgress(); + Intent intent = null; + try { + intent = new Intent(this, Class.forName(getIntent().getStringExtra(OVER_ACTIVITY_NAME))); + intent.putExtra(MediaRecorderActivity.OUTPUT_DIRECTORY, mMediaObject.getOutputDirectory()); + intent.putExtra(MediaRecorderActivity.VIDEO_URI, mMediaObject.getOutputTempTranscodingVideoPath()); + intent.putExtra(MediaRecorderActivity.VIDEO_SCREENSHOT, mMediaObject.getOutputVideoThumbPath()); + intent.putExtra("go_home", GO_HOME); + startActivity(intent); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("需要传入录制完成后跳转的Activity的全类名"); + } + + finish(); + } + + /** + * 转码失败 检查sdcard是否可用,检查分块是否存在 + */ + @Override + public void onEncodeError() { + hideProgress(); + Toast.makeText(this, R.string.record_video_transcoding_faild, + Toast.LENGTH_SHORT).show(); + finish(); + } + + @Override + public void onVideoError(int what, int extra) { + + } + + @Override + public void onAudioError(int what, String message) { + + } + + @Override + public void onPrepared() { + initSurfaceView(); + } + + public void onFinished() { + finish(); + } + + protected ProgressDialog mProgressDialog; + + public ProgressDialog showProgress(String title, String message) { + return showProgress(title, message, -1); + } + + public ProgressDialog showProgress(String title, String message, int theme) { + if (mProgressDialog == null) { + if (theme > 0) + mProgressDialog = new ProgressDialog(this, theme); + else + mProgressDialog = new ProgressDialog(this); + mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); + mProgressDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + mProgressDialog.setCanceledOnTouchOutside(false);// 不能取消 + mProgressDialog.setCancelable(false); + mProgressDialog.setIndeterminate(true);// 设置进度条是否不明确 + } + + if (!StringUtils.isEmpty(title)) + mProgressDialog.setTitle(title); + mProgressDialog.setMessage(message); + mProgressDialog.show(); + return mProgressDialog; + } + + public void hideProgress() { + if (mProgressDialog != null) { + mProgressDialog.dismiss(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mMediaRecorder.release(); + } + + @Override + protected void onStop() { + super.onStop(); + if (mMediaRecorder instanceof MediaRecorderNative) { + ((MediaRecorderNative) mMediaRecorder).activityStop(); + } + hideProgress(); + mProgressDialog = null; + + } + +} diff --git a/src/android/MediaRecorderConfig.java b/src/android/MediaRecorderConfig.java new file mode 100644 index 0000000..b663dd3 --- /dev/null +++ b/src/android/MediaRecorderConfig.java @@ -0,0 +1,285 @@ +package com.mabeijianxi.smallvideorecord2.model; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Created by jian on 2016/8/25 17:03 + * https://github.com/mabeijianxi + * mabeijianxi@gmail.com + */ +public final class MediaRecorderConfig implements Parcelable { + + private final boolean FULL_SCREEN; + /** + * 录制时间 + */ + private final int RECORD_TIME_MAX; + /** + * 最少录制时间 + */ + private final int RECORD_TIME_MIN; + + /** + * 小视频高度 + *

注意:宽度不能随意传,需要传送手机摄像头手支持录制的视频高度,注意是高度(因为会选择,具体原因不多解释)。 + * 获取摄像头所支持的尺寸的方式是{@link android.graphics.Camera#getSupportedPreviewSizes()} + * 一般支持的尺寸的高度有:240、480、720、1080等,具体值请用以上方法获取

+ */ + private final int SMALL_VIDEO_HEIGHT; + /** + * 小视频宽度 + */ + private final int SMALL_VIDEO_WIDTH; + /** + * 最大帧率 + */ + private final int MAX_FRAME_RATE; + /** + * 最小帧率 + */ + private final int MIN_FRAME_RATE; + /** + * 视频码率 + */ + private final int VIDEO_BITRATE; + /** + * 录制后会剪切一帧缩略图并保存,就是取时间轴上这个时间的画面 + */ + private final int captureThumbnailsTime; + + private final boolean GO_HOME; + + private MediaRecorderConfig(Buidler buidler) { + this.FULL_SCREEN = buidler.FULL_SCREEN; + this.RECORD_TIME_MAX = buidler.RECORD_TIME_MAX; + this.RECORD_TIME_MIN = buidler.RECORD_TIME_MIN; + this.MAX_FRAME_RATE = buidler.MAX_FRAME_RATE; + this.captureThumbnailsTime = buidler.captureThumbnailsTime; + this.MIN_FRAME_RATE = buidler.MIN_FRAME_RATE; + this.SMALL_VIDEO_HEIGHT = buidler.SMALL_VIDEO_HEIGHT; + this.SMALL_VIDEO_WIDTH = buidler.SMALL_VIDEO_WIDTH; + this.VIDEO_BITRATE = buidler.VIDEO_BITRATE; + this.GO_HOME=buidler.GO_HOME; + + } + + protected MediaRecorderConfig(Parcel in) { + FULL_SCREEN = in.readByte() != 0; + RECORD_TIME_MAX = in.readInt(); + RECORD_TIME_MIN = in.readInt(); + SMALL_VIDEO_HEIGHT = in.readInt(); + SMALL_VIDEO_WIDTH = in.readInt(); + MAX_FRAME_RATE = in.readInt(); + MIN_FRAME_RATE = in.readInt(); + VIDEO_BITRATE = in.readInt(); + captureThumbnailsTime = in.readInt(); + GO_HOME = in.readByte() != 0; + } + + public static final Creator CREATOR = new Creator() { + @Override + public MediaRecorderConfig createFromParcel(Parcel in) { + return new MediaRecorderConfig(in); + } + + @Override + public MediaRecorderConfig[] newArray(int size) { + return new MediaRecorderConfig[size]; + } + }; + + public boolean isGO_HOME() { + return GO_HOME; + } + public boolean getFullScreen() { + return FULL_SCREEN; + } + public int getCaptureThumbnailsTime() { + return captureThumbnailsTime; + } + + + public int getMaxFrameRate() { + return MAX_FRAME_RATE; + } + + public int getMinFrameRate() { + return MIN_FRAME_RATE; + } + + public int getRecordTimeMax() { + return RECORD_TIME_MAX; + } + public int getRecordTimeMin() { + return RECORD_TIME_MIN; + } + + public int getSmallVideoHeight() { + return SMALL_VIDEO_HEIGHT; + } + + public int getSmallVideoWidth() { + return SMALL_VIDEO_WIDTH; + } + + + + public int getVideoBitrate() { + return VIDEO_BITRATE; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeByte((byte) (FULL_SCREEN ? 1 : 0)); + dest.writeInt(RECORD_TIME_MAX); + dest.writeInt(RECORD_TIME_MIN); + dest.writeInt(SMALL_VIDEO_HEIGHT); + dest.writeInt(SMALL_VIDEO_WIDTH); + dest.writeInt(MAX_FRAME_RATE); + dest.writeInt(MIN_FRAME_RATE); + dest.writeInt(VIDEO_BITRATE); + dest.writeInt(captureThumbnailsTime); + dest.writeByte((byte) (GO_HOME ? 1 : 0)); + } + + + public static class Buidler { + /** + * 录制时间 + */ + private int RECORD_TIME_MAX = 6 * 1000; + + /** + * 小视频高度 + *

注意:宽度不能随意传,需要传送手机摄像头手支持录制的视频高度,注意是高度(因为会选择,具体原因不多解释)。 + * 获取摄像头所支持的尺寸的方式是{@link android.graphics.Camera#getSupportedPreviewSizes()} + * 一般支持的尺寸的高度有:240、480、720、1080等,具体值请用以上方法获取

+ */ + private int SMALL_VIDEO_HEIGHT = 480; + + /** + * 小视频宽度 + */ + private int SMALL_VIDEO_WIDTH = 360; + /** + * 最大帧率 + */ + private int MAX_FRAME_RATE = 20; + /** + * 最小帧率 + */ + private int MIN_FRAME_RATE = 8; + /** + * 视频码率//todo 注意传入>0的值后码率模式将从VBR变成CBR + */ + private int VIDEO_BITRATE; + /** + * 录制后会剪切一帧缩略图并保存,就是取时间轴上这个时间的画面 + */ + private int captureThumbnailsTime = 1; + + + private boolean GO_HOME=false; + + public int RECORD_TIME_MIN= (int) (1.5*1000); + + private boolean FULL_SCREEN =false; + + + public MediaRecorderConfig build() { + return new MediaRecorderConfig(this); + } + + /** + * @param captureThumbnailsTime 录制后会剪切一帧缩略图并保存,就是取时间轴上这个时间的画面 + * @return + */ + public Buidler captureThumbnailsTime(int captureThumbnailsTime) { + this.captureThumbnailsTime = captureThumbnailsTime; + return this; + } + + + /** + * @param MAX_FRAME_RATE 最大帧率(与视频清晰度、大小息息相关) + * @return + */ + public Buidler maxFrameRate(int MAX_FRAME_RATE) { + this.MAX_FRAME_RATE = MAX_FRAME_RATE; + return this; + } + + /** + * @param MIN_FRAME_RATE 最小帧率(与视频清晰度、大小息息相关) + * @return + */ + public Buidler minFrameRate(int MIN_FRAME_RATE) { + this.MIN_FRAME_RATE = MIN_FRAME_RATE; + return this; + } + + /** + * @param RECORD_TIME_MAX 录制时间 + * @return + */ + public Buidler recordTimeMax(int RECORD_TIME_MAX) { + this.RECORD_TIME_MAX = RECORD_TIME_MAX; + return this; + } + + /** + * @param RECORD_TIME_MIN 最少录制时间 + * @return + */ + public Buidler recordTimeMin(int RECORD_TIME_MIN) { + this.RECORD_TIME_MIN = RECORD_TIME_MIN; + return this; + } + + + /** + * @param SMALL_VIDEO_HEIGHT + * @return + */ + public Buidler smallVideoHeight(int SMALL_VIDEO_HEIGHT) { + this.SMALL_VIDEO_HEIGHT = SMALL_VIDEO_HEIGHT; + return this; + } + + /** + * @param SMALL_VIDEO_WIDTH + * + * @return + */ + public Buidler smallVideoWidth(int SMALL_VIDEO_WIDTH) { + this.SMALL_VIDEO_WIDTH = SMALL_VIDEO_WIDTH; + return this; + } + + /** + * @param VIDEO_BITRATE 视频码率 + * @return + */ + public Buidler videoBitrate(int VIDEO_BITRATE) { + this.VIDEO_BITRATE = VIDEO_BITRATE; + return this; + } + + public Buidler goHome(boolean GO_HOME) { + this.GO_HOME = GO_HOME; + return this; + } + + public Buidler fullScreen(boolean full) { + this.FULL_SCREEN =full; + return this; + } + } + +} diff --git a/src/android/mobile-ffmpeg-x2.gradle b/src/android/mobile-ffmpeg-x2.gradle new file mode 100644 index 0000000..e8fc069 --- /dev/null +++ b/src/android/mobile-ffmpeg-x2.gradle @@ -0,0 +1,3 @@ +dependencies { + implementation 'com.arthenica:mobile-ffmpeg-full:4.4' +} \ No newline at end of file diff --git a/www/capture.js b/www/capture.js new file mode 100644 index 0000000..875a611 --- /dev/null +++ b/www/capture.js @@ -0,0 +1,7 @@ +var exec = require('cordova/exec'); + +module.exports = { + capture(option, success, error) { + exec(success, error, 'capture-cordova-plugin', 'capture', [option]); + } +};