ImageUtil.java
import android.graphics.ImageFormat;
import android.media.Image;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.Log; import java.nio.ByteBuffer; public class ImageUtil {
public static final int YUV420P = 0;
public static final int YUV420SP = 1;
public static final int NV21 = 2;
private static final String TAG = "ImageUtil"; /***
* 此方法内注释以640*480为例
* 未考虑CropRect的
*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static byte[] getBytesFromImageAsType(Image image, int type) {
try {
//获取源数据,如果是YUV格式的数据planes.length = 3
//plane[i]里面的实际数据可能存在byte[].length <= capacity (缓冲区总大小)
final Image.Plane[] planes = image.getPlanes(); //数据有效宽度,一般的,图片width <= rowStride,这也是导致byte[].length <= capacity的原因
// 所以我们只取width部分
int width = image.getWidth();
int height = image.getHeight(); //此处用来装填最终的YUV数据,需要1.5倍的图片大小,因为Y U V 比例为 4:1:1
byte[] yuvBytes = new byte[width * height * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8];
//目标数组的装填到的位置
int dstIndex = 0; //临时存储uv数据的
byte uBytes[] = new byte[width * height / 4];
byte vBytes[] = new byte[width * height / 4];
int uIndex = 0;
int vIndex = 0; int pixelsStride, rowStride;
for (int i = 0; i < planes.length; i++) {
pixelsStride = planes[i].getPixelStride();
rowStride = planes[i].getRowStride(); ByteBuffer buffer = planes[i].getBuffer(); //如果pixelsStride==2,一般的Y的buffer长度=640*480,UV的长度=640*480/2-1
//源数据的索引,y的数据是byte中连续的,u的数据是v向左移以为生成的,两者都是偶数位为有效数据
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes); int srcIndex = 0;
if (i == 0) {
//直接取出来所有Y的有效区域,也可以存储成一个临时的bytes,到下一步再copy
for (int j = 0; j < height; j++) {
System.arraycopy(bytes, srcIndex, yuvBytes, dstIndex, width);
srcIndex += rowStride;
dstIndex += width;
}
} else if (i == 1) {
//根据pixelsStride取相应的数据
for (int j = 0; j < height / 2; j++) {
for (int k = 0; k < width / 2; k++) {
uBytes[uIndex++] = bytes[srcIndex];
srcIndex += pixelsStride;
}
if (pixelsStride == 2) {
srcIndex += rowStride - width;
} else if (pixelsStride == 1) {
srcIndex += rowStride - width / 2;
}
}
} else if (i == 2) {
//根据pixelsStride取相应的数据
for (int j = 0; j < height / 2; j++) {
for (int k = 0; k < width / 2; k++) {
vBytes[vIndex++] = bytes[srcIndex];
srcIndex += pixelsStride;
}
if (pixelsStride == 2) {
srcIndex += rowStride - width;
} else if (pixelsStride == 1) {
srcIndex += rowStride - width / 2;
}
}
}
} // image.close(); //根据要求的结果类型进行填充
switch (type) {
case YUV420P:
System.arraycopy(uBytes, 0, yuvBytes, dstIndex, uBytes.length);
System.arraycopy(vBytes, 0, yuvBytes, dstIndex + uBytes.length, vBytes.length);
break;
case YUV420SP:
for (int i = 0; i < vBytes.length; i++) {
yuvBytes[dstIndex++] = uBytes[i];
yuvBytes[dstIndex++] = vBytes[i];
}
break;
case NV21:
for (int i = 0; i < vBytes.length; i++) {
yuvBytes[dstIndex++] = vBytes[i];
yuvBytes[dstIndex++] = uBytes[i];
}
break;
}
return yuvBytes;
} catch (final Exception e) {
if (image != null) {
image.close();
}
Log.i(TAG, e.toString());
}
return null;
} /***
* YUV420 转化成 RGB
*/
public static int[] decodeYUV420SP(byte[] yuv420sp, int width, int height)
{
final int frameSize = width * height;
int rgb[] = new int[frameSize];
for (int j = 0, yp = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0)
y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0)
r = 0;
else if (r > 262143)
r = 262143;
if (g < 0)
g = 0;
else if (g > 262143)
g = 262143;
if (b < 0)
b = 0;
else if (b > 262143)
b = 262143;
rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000)
| ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
}
}
return rgb;
}
}

回调OnImageReader

    private ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage(); int imageWidth = image.getWidth();
int imageHeight = image.getHeight(); byte[] data68 = ImageUtil.getBytesFromImageAsType(image,2); if(time==5) {
int rgb[] = ImageUtil.decodeYUV420SP(data68, imageWidth, imageHeight);
Bitmap bitmap2 = Bitmap.createBitmap(rgb, 0, imageWidth,
imageWidth, imageHeight,
android.graphics.Bitmap.Config.ARGB_8888);
try {
File newFile = new File(Environment.getExternalStorageDirectory(), "345.png");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile));
bitmap2.compress(Bitmap.CompressFormat.PNG, 100, bos);
bos.flush();
bos.close();
bitmap2.recycle();
} catch (Exception e) { }
} // Message msg = Message.obtain();
// msg.obj = bitmap2;
// msg.what = 003;
// runHandler.sendMessage(msg); image.close();
}
};

Android camera2 回调imagereader 从Image拿到YUV数据转化成RGB,生成bitmap并保存的更多相关文章

  1. Android Camera2拍照(一)——使用SurfaceView

    原文:Android Camera2拍照(一)--使用SurfaceView Camera2 API简介 Android 从5.0(21)开始,引入了新的Camera API Camera2,原来的a ...

  2. Android Camera2 拍照(二)——使用TextureView

    原文:Android Camera2 拍照(二)--使用TextureView 上一篇博文简单介绍了使用Camera2 API拍摄照片,并使用SurfaceView作为预览界面.实际上,相对于Surf ...

  3. android Camera2 API使用详解

    原文:android Camera2 API使用详解 由于最近需要使用相机拍照等功能,鉴于老旧的相机API问题多多,而且新的设备都是基于安卓5.0以上的,于是本人决定研究一下安卓5.0新引入的Came ...

  4. Android Camera2 拍照入门学习

    原文:Android Camera2 拍照入门学习 学习资料: 肾虚将军android camera2 详解说明 极客学院android.hardware.camera2 使用指南 Android 5 ...

  5. Android Camera2采集摄像头原始数据并手动预览

    Android Camera2采集摄像头原始数据并手动预览 最近研究了一下android摄像头开发相关的技术,也看了Google提供的Camera2Basic调用示例,以及网上一部分代码,但都是在Te ...

  6. Android异步回调中的UI同步性问题

    Android程序编码过程中,回调无处不在.从最常见的Activity生命周期回调开始,到BroadcastReceiver.Service以及Sqlite等.Activity.BroadcastRe ...

  7. Android中回调接口的使用

    MainActivity如下: package cn.testcallback; import android.os.Bundle; import android.app.Activity; /** ...

  8. 弄明白Android 接口回调机制

    以前对于这个机制理解不够深刻,现在重新整理下思路. 一.建模 我理解的接口回调就是,我这个类实现了一个接口里的方法doSomething,然后注册到你这里,然后我就去做别的事情去了,你在某个触发的时机 ...

  9. Android笔记二十四.Android基于回调的事件处理机制

        假设说事件监听机制是一种托付式的事件处理,那么回调机制则与之相反,对于基于回调的事件处理模型来说,事件源和事件监听器是统一的,或者说事件监听器全然消失了,当用户在GUI控件上激发某个事件时,控 ...

随机推荐

  1. 尚硅谷redis学习2-redis的安装和HelloWorld

    Reids: remote dictionary server redis特点:支持持久化,支持复杂数据类型,支持备份 下载: 解压: 执行make, make install 可能会需要安装make ...

  2. Hibernate 再接触 关系映射 一对一单向外键联合主键关联

    例子: Husband.java package com.bjsxt.hibernate; import javax.persistence.Entity; import javax.persiste ...

  3. 基于Java SE集合的图书管理系统

    图书管理系统一.需求说明1.功能:登录,注册,忘记密码,管理员管理,图书管理.2.管理员管理:管理员的增删改查.3.图书管理:图书的增删改查.4.管理员属性包括:id,姓名,性别,年龄,家庭住址,手机 ...

  4. 做好Unity4.x开发项目规划

    1. 是否要用lua 2. (对于需操作的游戏)客户端游戏如何做战斗验证 下面列举小坑吧.不建议都绕开,毕竟没有那么多时间做前期调研的. 对应版本Unity4.x 1. 客户端程序层面 总的来说C#超 ...

  5. Java学习04 (第一遍)

    封装.抽象.继承和多态.封装:在面向对象语言中,封装特性是由类来体现的,我们将现实生活中的一类实体定义成类,其中包括属性和行为(在Java中就是方法),就好像人类,可以具有name,sex,age等属 ...

  6. django中使用mysql数据库的事务

    django中怎么使用mysql数据库的事务   Mysql数据库事务: 在进行后端业务开始操作修改数据库时,可能会涉及到多张表的数据修改,对这些数据的修改应该是一个整体事务,即要么一起成功,要么一起 ...

  7. 历届试题 大臣的旅费-(树的直径+dfs)

    问题描述 很久以前,T王国空前繁荣.为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市. 为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首 ...

  8. float double

    float : 单精度浮点数 double : 双精度浮点数 两者的主要区别如下: 01.在内存中占有的字节数不同 单精度浮点数在机内存占4个字节 双精度浮点数在机内存占8个字节 02.有效数字位数不 ...

  9. KMP与AC自动机模板

    HDU 1711 Number Sequence(KMP模板题) http://acm.hdu.edu.cn/showproblem.php?pid=1711 #include<bits/std ...

  10. 递归算法结合数据库 解析 java树形结构

    1.准备表结构及对应的表数据a.表结构: create table TB_TREE ( CID NUMBER not null, CNAME VARCHAR2(50), PID NUMBER //父节 ...