前言:
自从从手机应用转到RK安卓主板开发以后,发现有些手机上通用的东西在定制的主板上无法使用,比如:自定义相机录像功能
权限:
<!-- 增加文件存储和访问摄像头的权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
第一步:在布局中:
<SurfaceView android:id= "@+id/preview" android:layout_width= "match_parent" android:layout_height= "match_parent" />自定义相机的主要方法,也可以封装到一起,下一节再讲!
下一步:使用
-
-
-
import android.app.Activity
-
import android.content.Intent
-
import android.hardware.Camera
-
import android.os.Bundle
-
import android.util.Log
-
import android.view.SurfaceHolder
-
import android.view.SurfaceView
-
import app.SpeechApp
-
import com.airiche.httplibrary.http.Rk.MediaTecorderManger
-
import com.sunchip.vendingmachine.R
-
import kotlinx.android.synthetic.main.activity_open_shopping.*
-
-
import java.io.IOException
-
-
-
class TestActivity : Activity(), SurfaceHolder.Callback {
-
-
-
private
var mCamera
//声明相机(不要倒错包)
-
: Camera? =
null
-
private
var mPrevice
//声明视图
-
: SurfaceView? =
null
-
private
var mHolder
-
: SurfaceHolder? =
null
-
-
override
fun onCreate(savedInstanceState: Bundle?) {
-
super.onCreate(savedInstanceState)
-
setContentView(R.layout.activity_open_shopping)
-
-
initView()
-
}
-
-
-
private
fun initView() {
-
-
mPrevice = findViewById(R.id.preview);
-
mHolder = mPrevice!!.getHolder();
-
mHolder!!.addCallback(
this);
-
-
}
-
-
// 相机和Activity的生命周期进行绑定
-
override
fun onResume() {
-
super.onResume()
-
StartCamer()
-
}
-
-
//相机的启动
-
private
fun StartCamer() {
-
if (mCamera ==
null) {
-
mCamera = getCamera()
-
if (mHolder !=
null) {
-
setStartPrevicw(mCamera!!, mHolder!!)
-
}
-
}
-
//直接开始录像
-
var name = System.currentTimeMillis().toString()+
".mp4"
-
MediaTecorderManger.instance!!.prepareVideoRecorder(mCamera!!,
"/sdcard/", name)
-
}
-
-
-
//相机的启动和Activity的生命周期进行绑定
-
override
fun onPause() {
-
super.onPause()
-
//同时停止录像
-
MediaTecorderManger.instance!!.StopMediaRecorder(
this)
-
releaseCamera()
-
-
}
-
-
/**
-
* 打开摄像头
-
*
-
* @return
-
*/
-
fun getCamera(): Camera? {
-
var camera: Camera? =
null
-
if (camera !=
null) {
-
camera.stopPreview()
//停掉原来摄像头的预览
-
camera.release()
//释放资源
-
}
-
// Camera.getNumberOfCameras()可访问的摄像机设备总数,如果没有摄像头,则为0。
-
val cametacount = Camera.getNumberOfCameras()
-
camera = Camera.
open(cametacount -
1)
-
return camera
-
}
-
-
/**
-
* 开始预览相机内容
-
*/
-
private
fun setStartPrevicw(
-
camera: Camera,
-
holder: SurfaceHolder
-
) {
-
try {
-
val rotation =
this.windowManager.defaultDisplay.rotation
-
Log.e(
"TAG",
"rotation=============$rotation")
-
camera.setPreviewDisplay(holder)
-
//系统预览角度的调整
-
camera.setDisplayOrientation(
0)
-
//打开摄像头
-
camera.startPreview()
-
}
catch (e: IOException) {
-
Log.e(
"TAG",
"IOException==setStartPrevicw==e:" + e.message)
-
//释放摄像头
-
releaseCamera()
-
}
-
}
-
-
/**
-
* 释放相机资源
-
*/
-
private
fun releaseCamera() {
-
if (mCamera !=
null) {
-
mCamera!!.lock()
-
mCamera!!.stopPreview()
-
mCamera!!.setPreviewCallback(
null)
-
mCamera!!.setPreviewCallbackWithBuffer(
null)
-
mCamera!!.release()
-
mCamera =
null
-
}
-
}
-
-
-
override
fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
-
mCamera!!.stopPreview();
-
setStartPrevicw(mCamera!!, mHolder!!);
-
Log.e(
"TAG",
"surfaceChanged=============");
-
}
-
-
override
fun surfaceDestroyed(holder: SurfaceHolder) {
-
releaseCamera();
-
}
-
-
override
fun surfaceCreated(holder: SurfaceHolder) {
-
setStartPrevicw(mCamera!!, mHolder!!);
-
}
-
-
companion
object {
-
-
fun getTestActivity() {
-
val intent = Intent(SpeechApp.mSpeechApp, TestActivity::
class.java)
-
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
-
SpeechApp.mSpeechApp!!.startActivity(intent)
-
}
-
}
-
}
-
介绍:如果你们单独使用这个类是会有问题的:比如,
SpeechApp.mSpeechApp :这个是公共的Application
MediaTecorderManger.instance!!.prepareVideoRecorder(mCamera!!, AppConfig.path, name) 这个就是封装的录像代码
MediaTecorderManger.instance!!.StopMediaRecorder(this) 这个就是停止录像方法
-
package com.airiche.httplibrary.http.Rk
-
-
import android.content.Context
-
import android.hardware.Camera
-
import android.media.CamcorderProfile
-
import android.media.MediaRecorder
-
import android.util.Log
-
import android.widget.Toast
-
import com.airiche.httplibrary.http.manager.FileManger
-
import com.airiche.httplibrary.http.utils.FileSizeUtil
-
import com.airiche.httplibrary.http.utils.FileUtils
-
import com.airiche.httplibrary.http.utils.HttpURLUtils
-
import com.airiche.httplibrary.http.utils.SingletonUtils
-
import java.io.IOException
-
-
/**
-
*
-
* 录像 仅仅在Rk系统上使用 这是定制系统 google原生录像跑不起来
-
* MediaRecorder的一些参数有些系统不支持
-
*/
-
class MediaTecorderManger {
-
-
private
var mVideoFilename =
""
-
-
//摄像机
-
private
var mMediaRecorder: MediaRecorder? =
null
-
-
var fileManger = FileManger()
-
-
var mProfile: CamcorderProfile? =
null
-
-
//开始录像
-
fun prepareVideoRecorder(mCamera: Camera?, Path: String, name: String):
Boolean {
-
Log.v(TAG,
"开始录制视频========")
-
FileSizeUtil.ConfirmFile(Path)
-
mVideoFilename = Path + name
-
fileManger.updateStorageSpaceAndHint(FileManger.OnStorageUpdateDoneListener {
-
initializeRecorder(mCamera)
-
if (mMediaRecorder ==
null) {
-
Log.e(
-
TAG,
-
"Fail to initialize media recorder"
-
)
-
return
@OnStorageUpdateDoneListener
-
}
-
try {
-
mMediaRecorder!!.start()
// Recording is now started
-
}
catch (e: RuntimeException) {
-
Log.e(TAG,
"Could not start media recorder. " + e)
-
releaseMediaRecorder()
-
mCamera!!.lock()
-
return
@OnStorageUpdateDoneListener
-
}
-
})
-
return
true
-
}
-
-
//初始化录像参数
-
fun initializeRecorder(mCamera: Camera?) {
-
mProfile = CamcorderProfile.
get(
0, CamcorderProfile.QUALITY_HIGH)
-
mMediaRecorder = MediaRecorder()
-
mCamera!!.unlock()
-
mMediaRecorder!!.setCamera(mCamera)
-
mMediaRecorder!!.setAudioSource(MediaRecorder.AudioSource.CAMCORDER)
-
mMediaRecorder!!.setVideoSource(MediaRecorder.VideoSource.CAMERA)
-
mMediaRecorder!!.setProfile(mProfile)
-
mMediaRecorder!!.setVideoSize(
-
mProfile!!.videoFrameWidth,
-
mProfile!!.videoFrameHeight
-
)
-
mMediaRecorder!!.setMaxDuration(
5 *
60 *
1000)
-
mMediaRecorder!!.setOutputFile(mVideoFilename)
-
-
var maxFileSize:
Long =
1024 *
1024 *
1024.toLong()
//最大一个G
-
try {
-
mMediaRecorder!!.setMaxFileSize(maxFileSize)
-
}
catch (exception: java.lang.RuntimeException) {
-
// We are going to ignore failure of setMaxFileSize here, as
-
// a) The composer selected may simply not support it, or
-
// b) The underlying media framework may not handle 64-bit range
-
// on the size restriction.
-
}
-
-
mMediaRecorder!!.setOrientationHint(
0)
-
try {
-
mMediaRecorder!!.prepare()
-
}
catch (e: IOException) {
-
Log.e(TAG,
"prepare failed for $mVideoFilename" + e)
-
releaseMediaRecorder()
-
throw RuntimeException(e)
-
}
-
mMediaRecorder!!.setOnErrorListener(
object : MediaRecorder.OnErrorListener {
-
override
fun onError(mr: MediaRecorder?, what: Int, extra: Int) {
-
mMediaRecorder!!.setOnErrorListener(
null)
-
mMediaRecorder!!.setOnInfoListener(
null)
-
mMediaRecorder!!.stop()
-
}
-
})
-
mMediaRecorder!!.setOnInfoListener(
object : MediaRecorder.OnInfoListener {
-
override
fun onInfo(mr: MediaRecorder?, what: Int, extra: Int) {
-
-
}
-
})
-
}
-
-
fun releaseMediaRecorder() {
-
Log.i(TAG,
"Releasing media recorder.")
-
if (mMediaRecorder !=
null) {
-
mMediaRecorder!!.reset()
-
mMediaRecorder!!.release()
-
mMediaRecorder =
null
-
}
-
mVideoFilename =
""
-
}
-
-
fun StopMediaRecorder(mContext: Context) {
-
mMediaRecorder!!.setOnErrorListener(
null)
-
mMediaRecorder!!.setOnInfoListener(
null)
-
mMediaRecorder!!.setPreviewDisplay(
null)
-
try {
-
mMediaRecorder!!.stop()
-
}
catch (e: RuntimeException) {
-
Toast.makeText(mContext,
"录制时间太短!", Toast.LENGTH_SHORT).show()
-
}
-
//重置和释放 mediaRecorder
-
mMediaRecorder!!.reset()
-
mMediaRecorder!!.release()
-
mMediaRecorder =
null
-
Log.v(TAG,
"停止录制,文件已保存====" + mVideoFilename)
-
}
-
-
companion
object {
-
var TAG =
"MediaTecorderManger"
-
private
val mMediaTecorderManger: SingletonUtils<MediaTecorderManger?,
Void?> =
-
object : SingletonUtils<MediaTecorderManger?,
Void?>() {
-
override
fun create(var1: Void?): MediaTecorderManger? {
-
return MediaTecorderManger()
-
}
-
}
-
val instance: MediaTecorderManger?
-
get() = mMediaTecorderManger[
null]
-
}
-
}
-
package com.airiche.httplibrary.http.utils
-
-
/**
-
* Created by yuon 2020/11/28.
-
*/
-
abstract
class SingletonUtils<T, P> {
-
-
@Volatile
-
private
var mInstance: T? =
null
-
-
protected
abstract
fun create(var1: P): T
-
-
operator
fun get(p: P): T {
-
if (mInstance ==
null) {
-
if (mInstance ==
null) {
-
mInstance = create(p)
-
}
-
}
-
return mInstance!!
-
}
-
}
FileManger:
-
package com.airiche.httplibrary.http.manager;
-
-
import android.os.AsyncTask;
-
import android.os.Environment;
-
import android.os.StatFs;
-
import android.util.Log;
-
-
import java.io.File;
-
-
import
static android.content.ContentValues.TAG;
-
-
/**
-
* Created by Administrator on 2020/12/05.
-
*/
-
-
public
class FileManger {
-
-
public
static
final
long LOW_STORAGE_THRESHOLD_BYTES =
50000000;
-
private
final Object mStorageSpaceLock =
new Object();
-
private
long mStorageSpaceBytes = LOW_STORAGE_THRESHOLD_BYTES;
-
-
public
interface OnStorageUpdateDoneListener {
-
public void onStorageUpdateDone(long bytes);
-
}
-
-
private
boolean mPaused =
false;
-
-
public void updateStorageSpaceAndHint(final OnStorageUpdateDoneListener callback) {
-
/*
-
* We execute disk operations on a background thread in order to
-
* free up the UI thread. Synchronizing on the lock below ensures
-
* that when getStorageSpaceBytes is called, the main thread waits
-
* until this method has completed.
-
*
-
* However, .execute() does not ensure this execution block will be
-
* run right away (.execute() schedules this AsyncTask for sometime
-
* in the future. executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
-
* tries to execute the task in parellel with other AsyncTasks, but
-
* there's still no guarantee).
-
* e.g. don't call this then immediately call getStorageSpaceBytes().
-
* Instead, pass in an OnStorageUpdateDoneListener.
-
*/
-
(
new AsyncTask<Void, Void, Long>() {
-
@Override
-
protected Long doInBackground(Void... arg) {
-
synchronized (mStorageSpaceLock) {
-
mStorageSpaceBytes = getAvailableSpace();
-
return mStorageSpaceBytes;
-
}
-
}
-
-
@Override
-
protected void onPostExecute(Long bytes) {
-
// updateStorageHint(bytes);
-
// This callback returns after I/O to check disk, so we could be
-
// pausing and shutting down. If so, don't bother invoking.
-
if (callback !=
null && !mPaused) {
-
callback.onStorageUpdateDone(bytes);
-
}
else {
-
Log.v(TAG,
"ignoring storage callback after activity pause");
-
}
-
}
-
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-
}
-
-
public
static
final String DCIM =
-
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString();
-
public
static
final String DIRECTORY = DCIM +
"/Camera";
-
public
static
final
long PREPARING = -
2L;
-
public
static
final
long UNAVAILABLE = -
1L;
-
public
static
final
long UNKNOWN_SIZE = -
3L;
-
-
public static long getAvailableSpace() {
-
String state = Environment.getExternalStorageState();
-
if (Environment.MEDIA_CHECKING.equals(state)) {
-
return PREPARING;
-
}
-
if (!Environment.MEDIA_MOUNTED.equals(state)) {
-
return UNAVAILABLE;
-
}
-
-
File dir =
new File(DIRECTORY);
-
dir.mkdirs();
-
if (!dir.isDirectory() || !dir.canWrite()) {
-
return UNAVAILABLE;
-
}
-
-
try {
-
StatFs stat =
new StatFs(DIRECTORY);
-
return stat.getAvailableBlocks() * (
long) stat.getBlockSize();
-
}
catch (Exception e) {
-
Log.i(TAG,
"Fail to access external storage", e);
-
}
-
return UNKNOWN_SIZE;
-
}
-
}
-
-
FileSizeUtil.ConfirmFile(Path)
-
-
-
/**
-
* 创建目录和文件
-
*/
-
fun ConfirmFile(filePath: String?) {
-
try {
-
val f = File(filePath)
-
val parent = f.parentFile
-
if (!parent.exists()) parent.mkdirs()
-
if (!f.exists()) f.createNewFile()
-
}
catch (ex: Exception) {
-
ex.printStackTrace()
-
}
-
}
基本源码都在这了, 录像也跟原生有点像,毕竟还是安卓,只不过RK的需要多配置一些东西!有用的话请点个赞,要demo(RK主板)的可以找我!
转载:https://blog.csdn.net/qq_36333309/article/details/111505818
查看评论