android自定義Camera實(shí)現(xiàn)錄像和拍照
本文實(shí)例為大家分享了android自定義Camera實(shí)現(xiàn)錄像和拍照的具體代碼,供大家參考,具體內(nèi)容如下
源碼:
package com.example.myvideocamera;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
/**
* 視頻錄制
*/
@SuppressWarnings("deprecation")
public class MainActivity extends Activity implements OnClickListener,
SensorEventListener, Callback {
private SurfaceView surfaceView; // 用于繪制緩沖圖像的
private Button luXiang_bt; // 開(kāi)始錄制的按鈕
private Button tingZhi_bt; // 停止錄制的按鈕
private Button auto_focus; // 進(jìn)行對(duì)焦
private Button screenshot; // 截圖
private TextView time_tv; // 顯示時(shí)間的文本框
private MediaRecorder mRecorder;
private boolean recording; // 記錄是否正在錄像,fasle為未錄像, true 為正在錄像
private File videoFolder; // 存放視頻的文件夾
private File videFile; // 視頻文件
private Handler handler;
private int time; // 時(shí)間
private Camera myCamera; // 相機(jī)聲明
private SurfaceHolder holder; // 用來(lái)訪問(wèn)surfaceview的接口
private SensorManager sManager; // 傳感器管理者
private Sensor sensor; // 傳感器對(duì)象
private int mX, mY, mZ; // x y z 坐標(biāo)
private Calendar calendar; // 日歷
private long lasttimestamp = 0; // 上一次用時(shí)的標(biāo)志
/**
* 錄制過(guò)程中,時(shí)間變化
*/
private Runnable timeRun = new Runnable() {
@Override
public void run() {
time++;
time_tv.setText(time + "秒");
handler.postDelayed(timeRun, 1000);
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);// 強(qiáng)制橫屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
initView();
initSensor();
initCreateFile();
}
/**
* 對(duì)傳感器進(jìn)行初始化
*/
private void initSensor() {
sManager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensor = sManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (sManager == null) {
// throw new IllegalArgumentException("SensorManager is null");
}
sManager.registerListener(this, sensor,
SensorManager.SENSOR_DELAY_NORMAL);
}
/**
* 文件的創(chuàng)建
*/
private void initCreateFile() {
// 判斷sd卡是否存在
boolean sdCardExist = Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED);
if (sdCardExist) {
// 設(shè)定存放視頻的文件夾的路徑
String path = Environment.getExternalStorageDirectory()
.getAbsolutePath()
+ File.separator
+ "VideoFolder"
+ File.separator;
// 聲明存放視頻的文件夾的File對(duì)象
videoFolder = new File(path);
// 如果不存在此文件夾,則創(chuàng)建
if (!videoFolder.exists()) {
videoFolder.mkdirs();
}
// 設(shè)置surfaceView不管理的緩沖區(qū)
surfaceView.getHolder().setType(
SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
// 設(shè)置surfaceView分辨率
//surfaceView.getHolder().setFixedSize(1000, 500);
luXiang_bt.setOnClickListener(this);
} else
Toast.makeText(this, "未找到sdCard!", Toast.LENGTH_LONG).show();
}
/**
* 初始化工作
*/
private void initView() {
// 獲取控件
surfaceView = (SurfaceView) findViewById(R.id.surfaceview);
luXiang_bt = (Button) findViewById(R.id.luXiang_bt);
tingZhi_bt = (Button) findViewById(R.id.tingZhi_bt);
time_tv = (TextView) findViewById(R.id.time);
auto_focus = (Button) findViewById(R.id.auto_focus);
screenshot = (Button) findViewById(R.id.screenshot);
handler = new Handler();
holder = surfaceView.getHolder();
tingZhi_bt.setOnClickListener(this);
auto_focus.setOnClickListener(this);
screenshot.setOnClickListener(this);
// 添加回調(diào)
holder.addCallback(this);
}
/**
* 將Camera和mediaRecoder釋放
*/
@Override
protected void onDestroy() {
handler.removeCallbacks(timeRun);
if (mRecorder != null) {
mRecorder.release();
}
if (myCamera != null) {
myCamera.stopPreview();
myCamera.release();
}
super.onDestroy();
}
/**
* 控件點(diǎn)擊事件的監(jiān)聽(tīng)
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.luXiang_bt: // 錄像點(diǎn)擊事件
if (!recording) {
try {
// 獲取當(dāng)前時(shí)間,作為視頻文件的文件名
String nowTime = java.text.MessageFormat.format(
"{0,date,yyyyMMdd_HHmmss}",
new Object[] { new java.sql.Date(System
.currentTimeMillis()) });
// 聲明視頻文件對(duì)象
videFile = new File(videoFolder.getAbsoluteFile()
+ File.separator + "video" + nowTime + ".mp4");
// 關(guān)閉預(yù)覽并釋放資源
myCamera.unlock();
mRecorder = new MediaRecorder();
mRecorder.setCamera(myCamera);
// 創(chuàng)建此視頻文件
videFile.createNewFile();
mRecorder.setPreviewDisplay(surfaceView.getHolder()
.getSurface()); // 預(yù)覽
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // 視頻源
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 錄音源為麥克風(fēng)
mRecorder
.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); // 輸出格式為mp4
/**
*引用android.util.DisplayMetrics 獲取分辨率
*/
// DisplayMetrics dm = new DisplayMetrics();
// getWindowManager().getDefaultDisplay().getMetrics(dm);
mRecorder.setVideoSize(800, 480); // 視頻尺寸
mRecorder.setVideoEncodingBitRate(2*1280*720); //設(shè)置視頻編碼幀率
mRecorder.setVideoFrameRate(30); // 視頻幀頻率
mRecorder
.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP); // 視頻編碼
mRecorder
.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); // 音頻編碼
mRecorder.setMaxDuration(1800000); // 設(shè)置最大錄制時(shí)間
mRecorder.setOutputFile(videFile.getAbsolutePath()); // 設(shè)置錄制文件源
mRecorder.prepare(); // 準(zhǔn)備錄像
mRecorder.start(); // 開(kāi)始錄像
time_tv.setVisibility(View.VISIBLE); // 設(shè)置文本框可見(jiàn)
handler.post(timeRun); // 調(diào)用Runable
recording = true; // 改變錄制狀態(tài)為正在錄制
setAutofocus();
} catch (IOException e1) {
e1.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
} else
Toast.makeText(MainActivity.this, "視頻正在錄制中...",
Toast.LENGTH_LONG).show();
break;
case R.id.tingZhi_bt: // 停止點(diǎn)擊事件
if (recording) {
mRecorder.stop();
mRecorder.release();
handler.removeCallbacks(timeRun);
time_tv.setVisibility(View.GONE);
int videoTimeLength = time;
time = 0;
recording = false;
Toast.makeText(
MainActivity.this,
videFile.getAbsolutePath() + " " + videoTimeLength
+ "秒", Toast.LENGTH_LONG).show();
}
// 開(kāi)啟相機(jī)
if (myCamera == null) {
myCamera = Camera.open();
try {
myCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
myCamera.startPreview(); // 開(kāi)啟預(yù)覽
break;
case R.id.auto_focus:
setAutofocus();
break;
case R.id.screenshot:
myCamera.autoFocus(new AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (success) {
camera.takePicture(null, null, jpegCallBack);
}
}
});
break;
}
}
/**
* 設(shè)置自動(dòng)對(duì)焦
*/
private void setAutofocus() {
if (myCamera != null) {
myCamera.autoFocus(new AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (success) {
}
}
});
}
}
/**
* 傳感器改變調(diào)用的方法
*/
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor == null) {
return;
}
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
int x = (int) event.values[0];
int y = (int) event.values[1];
int z = (int) event.values[2];
calendar = Calendar.getInstance();
long stamp = calendar.getTimeInMillis();
int px = Math.abs(mX - x);
int py = Math.abs(mY - y);
int pz = Math.abs(mZ - z);
int maxValue = getMaxValue(px, py, pz);
if (maxValue > 2 && (stamp - lasttimestamp) > 30) {
lasttimestamp = stamp;
setAutofocus();
}
mX = x;
mY = y;
mZ = z;
}
}
/**
* 獲取最大改變的值
*/
private int getMaxValue(int px, int py, int pz) {
int max = 0;
if (px > py && px > pz) {
max = px;
} else if (py > px && py > pz) {
max = py;
} else if (pz > px && pz > py) {
max = pz;
}
return max;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
/**
* suraceView 創(chuàng)建執(zhí)行的操作
*/
@Override
public void surfaceCreated(SurfaceHolder holder) {
// 開(kāi)啟相機(jī)
if (myCamera == null) {
myCamera = Camera.open();
try {
myCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* suraceView 狀態(tài)改變執(zhí)行的操作
*/
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// 開(kāi)始預(yù)覽
myCamera.startPreview();
Parameters parameters = myCamera.getParameters();// 獲取mCamera的參數(shù)對(duì)象
Size largestSize = getBestSupportedSize(parameters
.getSupportedPreviewSizes());
parameters.setPreviewSize(largestSize.width, largestSize.height);// 設(shè)置預(yù)覽圖片尺寸
largestSize = getBestSupportedSize(parameters
.getSupportedPictureSizes());// 設(shè)置捕捉圖片尺寸
parameters.setPictureSize(largestSize.width, largestSize.height);
myCamera.setParameters(parameters);
}
private Size getBestSupportedSize(List<Size> sizes) {
// 取能適用的最大的SIZE
Size largestSize = sizes.get(0);
int largestArea = sizes.get(0).height * sizes.get(0).width;
for (Size s : sizes) {
int area = s.width * s.height;
if (area > largestArea) {
largestArea = area;
largestSize = s;
}
}
return largestSize;
}
/**
* suraceView 銷毀執(zhí)行的操作
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// 關(guān)閉預(yù)覽并釋放資源
if (myCamera != null) {
myCamera.stopPreview();
myCamera.release();
myCamera = null;
}
}
/**
* 創(chuàng)建jpeg圖片回調(diào)數(shù)據(jù)對(duì)象
*/
private String filepath = "";
private PictureCallback jpegCallBack = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Bitmap oldBitmap = BitmapFactory.decodeByteArray(data, 0,
data.length);
Matrix matrix = new Matrix();
matrix.setRotate(90);
Bitmap newBitmap = Bitmap.createBitmap(oldBitmap, 0, 0,
oldBitmap.getWidth(), oldBitmap.getHeight(),
matrix, true);
filepath = Environment.getExternalStorageDirectory()
+ File.separator
+ new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())
+ ".jpg";
File file = new File(filepath);
try {
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(file));
newBitmap.compress(Bitmap.CompressFormat.JPEG, 85, bos);
bos.flush();
bos.close();
camera.stopPreview();
camera.startPreview();
newBitmap.recycle();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};
}
xml布局:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#ffffff" > <SurfaceView android:id="@+id/surfaceview" android:layout_width="fill_parent" android:layout_height="fill_parent"/> <Button android:id="@+id/tingZhi_bt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentBottom="true" android:text="停止"/> <Button android:id="@+id/luXiang_bt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_toLeftOf="@id/tingZhi_bt" android:text="錄像"/> <Button android:id="@+id/auto_focus" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_toLeftOf="@id/luXiang_bt" android:text="調(diào)焦"/> <Button android:id="@+id/screenshot" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_toLeftOf="@id/auto_focus" android:text="拍照"/> <TextView android:id="@+id/time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FF0000" android:text="1秒" android:visibility="gone" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="10dp"/> </RelativeLayout>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android自定義Camera實(shí)現(xiàn)拍照功能
- Android實(shí)現(xiàn)Camera2預(yù)覽和拍照效果
- android自定義Camera拍照并查看圖片
- Android Camera實(shí)現(xiàn)毫秒級(jí)拍照實(shí)例
- Android中使用Camera類編寫(xiě)手機(jī)拍照App的實(shí)例教程
- android系統(tǒng)在靜音模式下關(guān)閉camera拍照聲音的方法
- Android實(shí)現(xiàn)拍照、選擇圖片并裁剪圖片功能
- Android啟動(dòng)相機(jī)拍照并返回圖片
- Android拍照保存在系統(tǒng)相冊(cè)不顯示的問(wèn)題解決方法
- Android自定義Camera實(shí)現(xiàn)拍照小功能
相關(guān)文章
android handler.post和handler.sendMessage的區(qū)別和聯(lián)系
handler.post和handler.sendMessage本質(zhì)上是沒(méi)有區(qū)別的,都是發(fā)送一個(gè)消息到消息隊(duì)列中,而且消息隊(duì)列和handler都是依賴于同一個(gè)線程的。接下來(lái)通過(guò)本文給大家分享android handler.post和handler.sendMessage的區(qū)別和聯(lián)系,一起看看吧2017-08-08
Android Handler 原理分析及實(shí)例代碼
這篇文章主要介紹了Android Handler 原理分析及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-02-02
Android獲取手機(jī)通訊錄、sim卡聯(lián)系人及調(diào)用撥號(hào)界面方法
這篇文章主要介紹了Android獲取手機(jī)通訊錄、sim卡聯(lián)系人及調(diào)用撥號(hào)界面方法,本文分別給出實(shí)現(xiàn)代碼實(shí)現(xiàn)獲取通訊錄和sim卡的聯(lián)系人,以及權(quán)限配置和調(diào)用系統(tǒng)撥打電話的界面的實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-04-04
Android仿抖音主頁(yè)效果實(shí)現(xiàn)代碼
這篇文章主要介紹了Android仿抖音主頁(yè)效果實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
Android開(kāi)發(fā)之繪制平面上的多邊形功能分析
這篇文章主要介紹了Android開(kāi)發(fā)之繪制平面上的多邊形功能,結(jié)合實(shí)例形式分析了Android多邊形圖形繪制的原理、步驟、相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2017-09-09
Android自動(dòng)化測(cè)試處理各種彈窗的操作方法
這篇文章主要介紹了Android自動(dòng)化測(cè)試中如何處理各種彈窗,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-07-07
Android如何利用RecyclerView實(shí)現(xiàn)列表倒計(jì)時(shí)效果實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于Android如何利用RecyclerView實(shí)現(xiàn)列表倒計(jì)時(shí)效果的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02
Android SeekBar在刷新使用中需要注意的問(wèn)題
SeekBar在刷新使用中需要注意的問(wèn)題:在使用SeekBar的過(guò)程中需要注意刷新頻率,避免頻繁刷新造成的性能問(wèn)題;同時(shí),需要對(duì)SeekBar的監(jiān)聽(tīng)事件進(jìn)行適當(dāng)?shù)膬?yōu)化,減少回調(diào)次數(shù),提高響應(yīng)速度2023-05-05

