最近在搞视频分析类的项目,android默认视频采集格式是NV21,Y Cr Cb格式,4.2.0.方式采样
还有其他采样方式,默认使用NV21
Sets the image format for preview pictures.
If this is never called, the default format will be NV21
, which uses the NV21 encoding format.
int |
JPEG |
Encoded formats. |
int |
NV16 |
YCbCr format, used for video. |
int |
NV21 |
YCrCb format used for images, which uses the NV21 encoding format. |
int |
RGB_565 |
RGB format used for pictures encoded as RGB_565 see setPictureFormat(int) . |
int |
UNKNOWN |
|
int |
YUY2 |
YCbCr format used for images, which uses YUYV (YUY2) encoding format. |
int |
YV12 |
Android YUV format: This format is exposed to software decoders and applications. |
具体参见 http://developer.android.com/reference/android/graphics/ImageFormat.html
-----------------------------------------------------------------------------------------------------------
首先是其数据是怎样存储的
// 我们通过下列方式获取数据
class Buf implements Camera.PreviewCallback {
public byte[] yuv420sp =null;
public void onPreviewFrame(byte[] data, Camera camera) {
// 这里出来的data和tackPic出来的有区别,这边是NV21格式
yuv420sp=data;
}
}
420这种格式采样方式如下
X X X X
O O
X X X X
即每4个Y对应一个U和一个V
Y0U0V0 Y1 Y2U2V2 Y3
Y4 Y5 Y6 Y7
Y8U8V8 Y9 Y10U10V10 Y11
Y12 Y13 Y14 Y15
通过对采样数组的研究其存放规律是
YYYYY...(采样宽度width)...YYYYY
...
...(采样高度height)
...
YYYYY...(采样宽度width)...YYYYY
(vu)(vu)(vu)...(采样宽度)...(vu)(vu)(vu)
...(采样高度除以2,height/2,遇单加1)
(vu)(vu)(vu)...(采样宽度)...(vu)(vu)(vu)
即width=320,height=480,采样Y值长度320×480,采样VU长度320×480/2.yuv420sp=data;总长度为宽高乘积的一点五倍
// YUV转RGB rgb长度即width×heght
static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
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);
}
}
}
以上是android自带的YUV420SP转RGB的函数,但是坑爹的问题在于函数处理数据的能力有限,我们有的时候并不需要全部转完毕再解析。
以下是更改后的方法,用于取值某点的RGB,在一些实时性要求的应用中可以用到
// 自定义RGB
static public int myDecodeYUV420SP(byte[] yuv420sp, int width, int height,
int mWidth, int mHeight) {
// Y矩阵长度frameSize , V和U矩阵第一位即frameSize
final int frameSize = width * height;
// yp为Y在矩阵中的位置,yph为所需要点的高mHeight-1,ypw为所需要点的宽mWidth
int yp, yph = mHeight - 1, ypw = mWidth;
yp = width * yph + ypw;
// uvp为
// uv在数组中的位置,V和U矩阵第一位即frameSize,yph>>1取值范围(0,0,1,1,2,2...)yph从0开始,即UV数组为Y数组的1/2.
int uvp = frameSize + (yph >> 1) * width, u = 0, v = 0;
// 获取Y的数值
int y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0)
y = 0;
if ((ypw & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp]) - 128;
} else {
u = (0xff & yuv420sp[uvp--]) - 128;
v = (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;
return (0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff));
}
两套函数出来的数据int型需要转换成r/g/b。亮点就是转换方式
public static int red (int color)
Return the red component of a color int. This is the same as saying (color >> 16) & 0xFF
public static int green (int color)
Return the green component of a color int. This is the same as saying (color >> 8) & 0xFF
public static int blue (int color)
Return the blue component of a color int. This is the same as saying color & 0xFF
至此yuv取点rgb完成
1 需要代码的童鞋可以留下你的email
2 如果描述有误请指正
3 感谢 幸福的起点 博主,更多视频格式说明请参照 http://hi.baidu.com/joygogo0130/blog/item/04b707529efbec090df3e345.html
4 更多视频问题 请参照 http://developer.android.com/reference/android/graphics/Camera.html
http://ai4work.blog.163.com/blog/static/189873306201171883316264/