前言:抱着最起码的要求尽力去做好每一件事 ! ——秋不白
记录学习音视频的过程,目前到 了音视频的录制,后面再学习openGl ES,FFmpeg等
前面有使用SurfaceView 来预览Camera以及拍照,根据重力传感器来动态设置Camera.setRotation(degree),横着拍摄的照片,应该是横着的,竖着拍摄的照片应该竖着的,对吧,符合常识。后来用TextureView GLSurfaceView 来预览Camera,我对CameraUtil进行了更改。TextureView GLSurfaceView来预览,工具类操作相同,主要是TextureView GLSurfaceView对应的回调处理方法不同,道理都是一样的,直接上代码吧
效果图:
先说明,预览和保存的分辨率都是写死的,保存照片的分辨率可以修改,有兴趣去码云上获取完整代码,查看对应的代码https://gitee.com/redrose/Demo。
package com.redrose.videodemo.camera;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.view.SurfaceHolder;
import com.redrose.videodemo.utils.LogUtils;
import java.io.IOException;
import java.util.List;
/**
* Desc: Camera 工具类
* @author: RedRose
* Date: 2019/5/3
* Email: [email protected]
*/
public class CameraUtil2 {
public static final String TAG = "CameraUtil2";
private static CameraUtil2 mInstance;
private static boolean isPreviewing = false;
/**
* 相机参数对象
*/
private Camera.Parameters mParams;
private Camera.Parameters mParameters;
/**
* 闪光灯自动
*/
public static final int FLASH_AUTO = 0;
/**
* 闪光灯关闭
*/
public static final int FLASH_OFF = 1;
/**
* 闪光灯开启
*/
public static final int FLASH_ON = 2;
private CameraUtil2() {
}
private static final Object o = new Object();
public static CameraUtil2 getInstance() {
if (mInstance == null) {
synchronized (o) {
if (mInstance == null) {
mInstance = new CameraUtil2();
}
}
}
return mInstance;
}
private Camera mCamera;
public void doStartPreview(SurfaceTexture surface) {
LogUtils.i(TAG, "doStartPreview...");
if (isPreviewing) {
mCamera.stopPreview();
return;
}
if (mCamera != null) {
try {
mCamera.setPreviewTexture(surface);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setProperty();
}
}
public void doStartPreview(SurfaceHolder holder) {
LogUtils.i(TAG, "doStartPreview...");
if (isPreviewing) {
mCamera.stopPreview();
return;
}
if (mCamera != null) {
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setProperty();
}
}
public Camera openCamera() {
// 0 表示开启后置相机
return openCamera(0);
}
private Camera openCamera(int id) {
if (mCamera == null) {
mCamera = Camera.open(id);
}
// setProperty();
return mCamera;
}
/**
* 相机属性设置
*/
private void setProperty() {
//设置相机预览页面旋转90°,(默认是横屏)
mCamera.setDisplayOrientation(90);
mParameters = mCamera.getParameters();
//设置将保存的图片旋转90°(竖着拍摄的时候)
mParameters.setRotation(90);
mParameters.setPictureFormat(ImageFormat.NV21);
mParameters.setPreviewFormat(ImageFormat.NV21);
mParameters.setPreviewSize(1920, 1080);
mParameters.setPictureSize(1920, 1080);
// mParameters.setPictureSize(4608, 3456);
mParameters.setPictureFormat(ImageFormat.JPEG);
mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// mParameters.set(ImageFormat.YUV_444_888);
mCamera.setParameters(mParameters);
mCamera.startPreview();
isRelease = false;
isPreviewing = true;
}
/**
* 选装图片的角度
*/
public void setRotateDegree(int degree) {
// boolean result = degree == 0 || degree == 90
// mParameters.setRotation(90);
if (mCamera != null) {
mParameters = mCamera.getParameters();
mParameters.setRotation(degree);
mCamera.setParameters(mParameters);
}
}
public boolean getIsPreview(){
return isPreviewing;
}
/**
* 获取支持的预览分辨率
*/
public List getPreviewSizeList() {
if (mCamera == null) {
throw new NullPointerException("Camera can not be null");
}
return mCamera.getParameters().getSupportedPreviewSizes();
}
/**
* 获取保存图片支持的分辨率
*/
public List getPictureSizeList() {
if (mCamera == null) {
throw new NullPointerException("Camera can not be null");
}
return mCamera.getParameters().getSupportedPictureSizes();
}
/**
* 设置闪光灯模式
*/
public void setFlashMode(int mode) {
if (mCamera == null) {
return;
}
mParameters = mCamera.getParameters();
String flashMode = mParameters.getFlashMode();
switch (mode) {
case FLASH_AUTO:
mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
break;
case FLASH_OFF:
mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
break;
case FLASH_ON:
mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
break;
default:
break;
}
mCamera.setParameters(mParameters);
}
/**
* 释放相机资源
*/
public void releaseCamera() {
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.lock();
mCamera.release();
mCamera = null;
isRelease = true;
isPreviewing = false;
}
}
/**
* 是否旋转图片 true 选装
*/
private boolean isRelease = false;
public boolean getIsRelease() {
return isRelease;
}
/**
* 设置保存图片的分辨率
*/
public void setSaveSize(Camera.Size saveSize) {
mParameters.setPictureSize(saveSize.width, saveSize.height);
mCamera.setParameters(mParameters);
}
}
CameraGLSurfaceViewActivity(看名字就知道哦,这几个Activity 代码冗余量很大,也是本人懒,也是在学习阶段,有音频PCM录制和编码wav播放,有视频简易录制编码,会持续更新)
package com.redrose.videodemo.camera;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.hardware.Camera;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.TextView;
import com.redrose.videodemo.R;
import com.redrose.videodemo.base.BaseActivity;
import com.redrose.videodemo.bean.Photo;
import com.redrose.videodemo.bean.Time;
import com.redrose.videodemo.utils.BitmapCallBack;
import com.redrose.videodemo.utils.GlideUtils;
import com.redrose.videodemo.utils.IntentUtils;
import com.redrose.videodemo.utils.LogUtils;
import com.redrose.videodemo.utils.MySensorHelper;
import com.redrose.videodemo.utils.SPUtils;
import com.redrose.videodemo.utils.ToastUtil;
import com.redrose.videodemo.utils.ToolUtils;
import com.redrose.videodemo.view.PreViewGlsurfaceView;
import com.redrose.videodemo.view.PreviewTextureView;
import com.zhy.adapter.recyclerview.CommonAdapter;
import com.zhy.adapter.recyclerview.base.ViewHolder;
import org.litepal.crud.DataSupport;
import org.xutils.view.annotation.ContentView;
import org.xutils.view.annotation.Event;
import org.xutils.view.annotation.ViewInject;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
/**
* Desc:
* Author: RedRose
* Date: 2019/3/20
* Email: [email protected]
*/
@ContentView(R.layout.activity_camera_glsurfaceview)
public class CameraGLSurfaceViewActivity extends BaseActivity implements BitmapCallBack {
@ViewInject(R.id.pre_text)
private TextView mPreSize;
@ViewInject(R.id.save_text)
private TextView mSaveSize;
@ViewInject(R.id.flashlight)
private ImageView mFlashView;
@ViewInject(R.id.photo_list)
private ImageView mPreImageView;
@ViewInject(R.id.take_photo)
private View mTakePhoto;
@ViewInject(R.id.camera_preview)
private PreViewGlsurfaceView mPreview;
private boolean showLocation = false;
private PopupWindow mPopWindow;
private List mPhotoList;
private Time mTime;
private boolean isTakePhoto = true;
/**
* 重力传感器监听
* 横着 竖着状态
*/
private MySensorHelper mMySensor;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置全屏
// getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
initData();
}
private void initData() {
mMySensor = new MySensorHelper(this);
mMySensor.enable();
int mode = SPUtils.getInt("Flash_mode");
initFlashMode(mode);
mPreview.setBitmapCallback(this);
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Calendar calendar = Calendar.getInstance();
String format = sdf.format(calendar.getTime());
mTime = new Time();
mTime.setClassId(Long.parseLong(format));
mTime.setDay(calendar.get(Calendar.DAY_OF_MONTH));
mTime.setYear(calendar.get(Calendar.YEAR));
mTime.setMonth(calendar.get(Calendar.MONTH) + 1);
mPhotoList = new ArrayList<>();
}
private void showPopWindow(View view) {
mPopWindow = new PopupWindow(view, ToolUtils.dp2px(mContext.getApplicationContext(),
200), ToolUtils.dp2px(mContext.getApplicationContext(), 200));
mPopWindow.setFocusable(true);
// popupWindow.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#3F51B5")));
mPopWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
mPopWindow.setOutsideTouchable(true);
mPopWindow.update();
if (showLocation) {
mPopWindow.showAsDropDown(mSaveSize);
} else {
mPopWindow.showAsDropDown(mPreSize);
}
}
@Override
protected void onResume() {
super.onResume();
mPreview.onResume();
}
@Override
protected void onPause() {
super.onPause();
mPreview.onPause();
}
/**
* 显示支持保存的分辨率
*/
private void showSupportSize(List list) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.pop_size_layout, null);
RecyclerView recycleView = view.findViewById(R.id.recycle_size);
initRecycle(recycleView);
SizeAdapter mAdapter = new SizeAdapter(mContext, R.layout.size_item, list);
recycleView.setAdapter(mAdapter);
showPopWindow(view);
}
@Event(value = {R.id.pre_text, R.id.save_text, R.id.flashlight, R.id.take_photo, R.id.photo_list,
R.id.videoStop,
R.id.videoStart,
R.id.all_list})
private void onclickView(View view) {
int id = view.getId();
switch (id) {
/*暂时注释 动态设置预览分辨率*/
case R.id.pre_text:
/*预览分辨率,建议设置成屏幕分辨率,经测试,支持的最高就是屏幕分辨率 */
showLocation = false;
showSupportSize(CameraUtil.getInstance().getPreviewSizeList());
break;
//设置保存图片的分辨率
case R.id.save_text:
showLocation = true;
showSupportSize(CameraUtil2.getInstance().getPictureSizeList());
break;
//切换闪光灯模式
case R.id.flashlight:
int mode = SPUtils.getInt("Flash_mode");
if (mode == CameraUtil.FLASH_AUTO) {
mode = CameraUtil.FLASH_OFF;
} else if (mode == CameraUtil.FLASH_OFF) {
mode = CameraUtil.FLASH_ON;
} else if (mode == CameraUtil.FLASH_ON) {
mode = CameraUtil.FLASH_AUTO;
}
SPUtils.put("Flash_mode", mode);
initFlashMode(mode);
break;
//拍照
case R.id.take_photo:
mPreview.takePhoto();
break;
//打开当前拍摄的照片图库
case R.id.photo_list:
int size = mPhotoList.size();
if (size == 0) {
ToastUtil.show(mContext, "还未拍摄照片,可以点击右侧查看所有照片");
return;
}
Bundle bundle = new Bundle();
bundle.putSerializable("photoList", (ArrayList) mPhotoList);
IntentUtils.goToPreviewActivity(mContext, bundle);
break;
//打开图库
case R.id.all_list:
IntentUtils.goToImageActivity(mContext, null);
break;
case R.id.videoStart:
mPreview.startVideo();
break;
case R.id.videoStop:
mPreview.stopVideo();
break;
default:
break;
}
}
@Event(type = View.OnLongClickListener.class, value = R.id.take_photo)
private boolean onLongClickView(View view) {
int id = view.getId();
switch (id) {
case R.id.take_photo:
// mPreview.startVideo();
break;
default:
break;
}
return false;
}
private void initRecycle(RecyclerView recyclerView) {
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
//设置布局管理器
recyclerView.setLayoutManager(layoutManager);
//设置为垂直布局,这也是默认的
layoutManager.setOrientation(OrientationHelper.VERTICAL);
//设置Adapter
// recyclerView.setAdapter(recycleAdapter);
//设置分隔线
// recyclerView.addItemDecoration(new DividerGridItemDecoration(this));
//设置增加或删除条目的动画
recyclerView.setItemAnimator(new DefaultItemAnimator());
}
@Override
public void backByte(byte[] data) {
GlideUtils.loadByte(mPreImageView, data);
ToolUtils.saveImageFile(data, mPhotoList, mIsRotate);
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Calendar calendar = Calendar.getInstance();
String format = sdf.format(calendar.getTime());
List
PreViewGlsurfaceView
package com.redrose.videodemo.view;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import com.redrose.videodemo.camera.CameraUtil2;
import com.redrose.videodemo.camera.DirectDrawer;
import com.redrose.videodemo.camera.H264Encoder;
import com.redrose.videodemo.utils.BitmapCallBack;
import com.redrose.videodemo.utils.LogUtils;
import com.redrose.videodemo.utils.ToastUtil;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/**
* Desc:
*
* @author: RedRose
* Date: 2019/4/17
* Email: [email protected]
*/
public class PreViewGlsurfaceView extends GLSurfaceView implements GLSurfaceView.Renderer,
Camera.PictureCallback, Camera.PreviewCallback,
SurfaceTexture.OnFrameAvailableListener {
public static final String TAG = "PreViewGlsurfaceView";
private Context mContext;
/**
* 以OpenGL ES纹理的形式从图像流中捕获帧,我把叫做纹理层
*/
SurfaceTexture mSurface;
/**
* 使用的纹理id
*/
int mTextureID = -1;
DirectDrawer mDirectDrawer;
private Camera mCamera;
private BitmapCallBack mBitmapCallback;
// int width = 1280;
// int height = 720;
int width = 1920;
int height = 1080;
int framerate = 30; //一秒30帧
H264Encoder encoder; //自定义的编码操作类
public PreViewGlsurfaceView(Context context) {
this(context, null);
}
public PreViewGlsurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
setEGLContextClientVersion(2);
setRenderer(this);
//根据纹理层的监听,有数据就绘制 渲染模式
//RENDERMODE_WHEN_DIRTY表示被动渲染,只有在调用requestRender或者onResume等方法时才会进行渲染。
// RENDERMODE_CONTINUOUSLY表示持续渲染
setRenderMode(RENDERMODE_WHEN_DIRTY);
mCamera = CameraUtil2.getInstance().openCamera();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
LogUtils.d(TAG, "--onSurfaceCreated--");
//得到view表面的纹理id
mTextureID = createTextureID();
//使用这个纹理id得到纹理层SurfaceTexture
mSurface = new SurfaceTexture(mTextureID);
//监听纹理层
mSurface.setOnFrameAvailableListener(this);
mDirectDrawer = new DirectDrawer(mTextureID);
//打开相机,并未预览
CameraUtil2.getInstance().doStartPreview(mSurface);
mCamera.setPreviewCallback(this);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
LogUtils.d(TAG, "--onSurfaceChanged--");
GLES20.glViewport(0, 0, width, height);
// 渲染窗口大小发生改变或者屏幕方法发生变化时候回调
//如果还未预览,就开始预览
if (CameraUtil2.getInstance().getIsRelease()) {
mCamera = CameraUtil2.getInstance().openCamera();
CameraUtil2.getInstance().doStartPreview(mSurface);
}
}
@Override
public void onDrawFrame(GL10 gl) {
//系统在每次重画GLSurfaceView时调用这个方法
//执行渲染工作
LogUtils.d(TAG, "--onDrawFrame--");
GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
//从图像流中将纹理图像更新为最近的帧
mSurface.updateTexImage();
mDirectDrawer.draw();
}
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
LogUtils.d(TAG, "--onFrameAvailable--");
//回调接口,用于通知新的流帧可用
//纹理层有新数据,就通知view绘制
this.requestRender();
}
private int createTextureID() {
int[] texture = new int[1];
GLES20.glGenTextures(1, texture, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[0]);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
return texture[0];
}
@Override
public void onPause() {
super.onPause();
LogUtils.d(TAG, "--onPause--");
//停止预览
CameraUtil2.getInstance().releaseCamera();
}
public void setBitmapCallback(BitmapCallBack bitmapCallback) {
this.mBitmapCallback = bitmapCallback;
}
public void takePhoto() {
if (mCamera != null) {
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
//设置聚焦成功后再拍照,其实可以不用。看需求吧,可以直接调用takePicture()
//有些手机会聚焦失败,也就是success是false
if (success) {
camera.cancelAutoFocus();
mCamera.takePicture(null, null, PreViewGlsurfaceView.this);
}
}
});
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
/**
* 触摸聚焦
*/
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (success) {
ToastUtil.show(getContext(), "聚焦成功");
camera.cancelAutoFocus();
}
}
});
return super.onTouchEvent(event);
}
private boolean isStartVideo = false;
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
//这里就是预览返回的 NV21数据
LogUtils.d(TAG, "--onPreviewFrame--");
if (encoder != null && isStartVideo){
encoder.putDate(data); //将一帧的数据传过去处理
}
}
@Override
public void onPictureTaken(byte[] data, Camera camera) {
if (mBitmapCallback != null) {
mBitmapCallback.backByte(data);
}
camera.startPreview();
}
public void startVideo() {
isStartVideo = true;
ToastUtil.show(getContext(), "开始录像");
encoder = new H264Encoder(width,height,framerate);
encoder.startEncoder(); //开始编码
}
public void stopVideo() {
isStartVideo = false;
ToastUtil.show(getContext(), "停止录像");
if (encoder != null){
encoder.stopEncoder();
}
}
}
CameraTextureActivity
package com.redrose.videodemo.camera;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.hardware.Camera;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.TextView;
import com.redrose.videodemo.R;
import com.redrose.videodemo.base.BaseActivity;
import com.redrose.videodemo.bean.Photo;
import com.redrose.videodemo.bean.Time;
import com.redrose.videodemo.utils.BitmapCallBack;
import com.redrose.videodemo.utils.GlideUtils;
import com.redrose.videodemo.utils.IntentUtils;
import com.redrose.videodemo.utils.LogUtils;
import com.redrose.videodemo.utils.MySensorHelper;
import com.redrose.videodemo.utils.SPUtils;
import com.redrose.videodemo.utils.ToastUtil;
import com.redrose.videodemo.utils.ToolUtils;
import com.redrose.videodemo.view.PreviewTextureView;
import com.zhy.adapter.recyclerview.CommonAdapter;
import com.zhy.adapter.recyclerview.base.ViewHolder;
import org.litepal.crud.DataSupport;
import org.xutils.view.annotation.ContentView;
import org.xutils.view.annotation.Event;
import org.xutils.view.annotation.ViewInject;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
/**
* Desc:
* Author: RedRose
* Date: 2019/3/20
* Email: [email protected]
*/
@ContentView(R.layout.activity_camera_texture)
public class CameraTextureActivity extends BaseActivity implements BitmapCallBack {
@ViewInject(R.id.pre_text)
private TextView mPreSize;
@ViewInject(R.id.save_text)
private TextView mSaveSize;
@ViewInject(R.id.flashlight)
private ImageView mFlashView;
@ViewInject(R.id.photo_list)
private ImageView mPreImageView;
@ViewInject(R.id.take_photo)
private View mTakePhoto;
@ViewInject(R.id.camera_preview)
private PreviewTextureView mPreview;
private boolean showLocation = false;
private PopupWindow mPopWindow;
private List mPhotoList;
private Time mTime;
private boolean isTakePhoto = true;
/**
* 重力传感器监听
* 横着 竖着状态
*/
private MySensorHelper mMySensor;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置全屏
// getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
initData();
}
private void initData() {
mMySensor = new MySensorHelper(this);
mMySensor.enable();
int mode = SPUtils.getInt("Flash_mode");
initFlashMode(mode);
mPreview.setBitmapCallback(this);
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Calendar calendar = Calendar.getInstance();
String format = sdf.format(calendar.getTime());
mTime = new Time();
mTime.setClassId(Long.parseLong(format));
mTime.setDay(calendar.get(Calendar.DAY_OF_MONTH));
mTime.setYear(calendar.get(Calendar.YEAR));
mTime.setMonth(calendar.get(Calendar.MONTH) + 1);
mPhotoList = new ArrayList<>();
}
private void showPopWindow(View view) {
mPopWindow = new PopupWindow(view, ToolUtils.dp2px(mContext.getApplicationContext(),
200), ToolUtils.dp2px(mContext.getApplicationContext(), 200));
mPopWindow.setFocusable(true);
// popupWindow.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#3F51B5")));
mPopWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
mPopWindow.setOutsideTouchable(true);
mPopWindow.update();
if (showLocation) {
mPopWindow.showAsDropDown(mSaveSize);
} else {
mPopWindow.showAsDropDown(mPreSize);
}
}
/**
* 显示支持保存的分辨率
*/
private void showSupportSize(List list) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.pop_size_layout, null);
RecyclerView recycleView = view.findViewById(R.id.recycle_size);
initRecycle(recycleView);
SizeAdapter mAdapter = new SizeAdapter(mContext, R.layout.size_item, list);
recycleView.setAdapter(mAdapter);
showPopWindow(view);
}
@Event(value = {R.id.pre_text, R.id.save_text, R.id.flashlight, R.id.take_photo, R.id.photo_list,
R.id.videoSwtich,
R.id.all_list})
private void onclickView(View view) {
int id = view.getId();
switch (id) {
/*暂时注释 动态设置预览分辨率*/
case R.id.pre_text:
/*预览分辨率,建议设置成屏幕分辨率,经测试,支持的最高就是屏幕分辨率 */
showLocation = false;
showSupportSize(CameraUtil.getInstance().getPreviewSizeList());
break;
//设置保存图片的分辨率
case R.id.save_text:
showLocation = true;
showSupportSize(CameraUtil2.getInstance().getPictureSizeList());
break;
//切换闪光灯模式
case R.id.flashlight:
int mode = SPUtils.getInt("Flash_mode");
if (mode == CameraUtil.FLASH_AUTO) {
mode = CameraUtil.FLASH_OFF;
} else if (mode == CameraUtil.FLASH_OFF) {
mode = CameraUtil.FLASH_ON;
} else if (mode == CameraUtil.FLASH_ON) {
mode = CameraUtil.FLASH_AUTO;
}
SPUtils.put("Flash_mode", mode);
initFlashMode(mode);
break;
//拍照
case R.id.take_photo:
mPreview.takePhoto();
break;
//打开当前拍摄的照片图库
case R.id.photo_list:
int size = mPhotoList.size();
if (size == 0) {
ToastUtil.show(mContext, "还未拍摄照片,可以点击右侧查看所有照片");
return;
}
Bundle bundle = new Bundle();
bundle.putSerializable("photoList", (ArrayList) mPhotoList);
IntentUtils.goToPreviewActivity(mContext, bundle);
break;
//打开图库
case R.id.all_list:
IntentUtils.goToImageActivity(mContext, null);
break;
case R.id.videoSwtich:
if (isTakePhoto) {
isTakePhoto = false;
} else {
isTakePhoto = true;
}
break;
default:
break;
}
}
@Event(type = View.OnLongClickListener.class, value = R.id.take_photo)
private boolean onLongClickView(View view) {
int id = view.getId();
switch (id) {
case R.id.take_photo:
mPreview.startVideo();
break;
default:
break;
}
return false;
}
private void initRecycle(RecyclerView recyclerView) {
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
//设置布局管理器
recyclerView.setLayoutManager(layoutManager);
//设置为垂直布局,这也是默认的
layoutManager.setOrientation(OrientationHelper.VERTICAL);
//设置Adapter
// recyclerView.setAdapter(recycleAdapter);
//设置分隔线
// recyclerView.addItemDecoration(new DividerGridItemDecoration(this));
//设置增加或删除条目的动画
recyclerView.setItemAnimator(new DefaultItemAnimator());
}
@Override
public void backByte(byte[] data) {
GlideUtils.loadByte(mPreImageView, data);
ToolUtils.saveImageFile(data, mPhotoList, mIsRotate);
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Calendar calendar = Calendar.getInstance();
String format = sdf.format(calendar.getTime());
List
PreviewTextureView
package com.redrose.videodemo.view;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.TextureView;
import com.redrose.videodemo.camera.CameraTextureActivity;
import com.redrose.videodemo.camera.CameraUtil;
import com.redrose.videodemo.camera.CameraUtil2;
import com.redrose.videodemo.camera.Preview;
import com.redrose.videodemo.utils.BitmapCallBack;
import com.redrose.videodemo.utils.LogUtils;
import com.redrose.videodemo.utils.ToastUtil;
import java.io.IOException;
/**
* Desc: TextureView 预览Camera
*
* @author: RedRose
* Date: 2019/4/16 0016
* Email: [email protected]
*/
public class PreviewTextureView extends TextureView implements TextureView.SurfaceTextureListener,
Camera.PictureCallback ,Camera.PreviewCallback{
private static final String TAG = PreviewTextureView.class.getClass().getSimpleName();
private BitmapCallBack mBitmapBack;
private SurfaceTexture mSurfaceTexture;
private Camera mCamera;
public PreviewTextureView(Context context) {
this(context, null);
}
public PreviewTextureView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PreviewTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setSurfaceTextureListener(this);
mCamera = CameraUtil2.getInstance().openCamera();
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
LogUtils.d(TAG, "--onSurfaceTextureAvailable--");
mSurfaceTexture = surface;
if (CameraUtil2.getInstance().getIsRelease()) {
mCamera = CameraUtil2.getInstance().openCamera();
}
CameraUtil2.getInstance().doStartPreview(surface);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
LogUtils.d(TAG, "--onSurfaceTextureSizeChanged--");
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
LogUtils.d(TAG, "--onSurfaceTextureDestroyed--");
CameraUtil2.getInstance().releaseCamera();
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
LogUtils.d(TAG, "--onSurfaceTextureUpdated--");
}
public void takePhoto() {
if (mCamera != null) {
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
//设置聚焦成功后再拍照,其实可以不用。看需求吧,可以直接调用takePicture()
//有些手机会聚焦失败,也就是success是false
if (success) {
camera.cancelAutoFocus();
mCamera.takePicture(null, null, PreviewTextureView.this);
}
}
});
}
}
public void setBitmapCallback(BitmapCallBack bitmapCallback) {
this.mBitmapBack = bitmapCallback;
}
@Override
public void onPictureTaken(byte[] data, Camera camera) {
if (mBitmapBack != null) {
mBitmapBack.backByte(data);
}
camera.startPreview();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
/**
* 触摸聚焦
*/
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (success) {
ToastUtil.show(getContext(), "聚焦成功");
camera.cancelAutoFocus();
}
}
});
return super.onTouchEvent(event);
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
//这里就是预览返回的 NV21数据
}
private boolean isStartVideo = false;
public void startVideo() {
isStartVideo = false;
ToastUtil.show(getContext(),"长按监听,开始录像");
}
}
另外在
PreViewGlsurfaceView中有bug,在拍照界面进入查看图片返回的时候,会闪到主界面或者崩溃,这个问题原因是没有释放Camera资源的问题,这个地方比较简单,我先把代码提交,下次我改了再提交到码云,仅供参考,完整代码可以去我的码云上去看,欢迎指正。