最近接受运动dv用到很多格式转换的需求,收信以下算法。
uvc提供支持的开源软件:
camorama cheese luvcview mjpg-streamer streamer uvcvideo
camorama:使用vlc + ubuntu 12.10使用直接编译就可以使用
代码下载方法:
sudo apt-cache camorama
sudo apt-get source camorama
================================================================
YUV与RGB相互转换的公式如下(RGB取值范围均为0-255)︰
Y = 0.299R + 0.587G + 0.114BB = Y + 2.03U
================================================================
==rgb24
static public void decodeYUV420SP(byte[] rgbBuf,byte[] yuv420sp,int width,int height) {
//定义单通道数据长度
final int frameSize = width * height;
//如果传进来的rgbBuf 为空,则抛出空指针异常
if (rgbBuf == null)
throw new NullPointerException("buffer 'rgbBuf' is null");
//如果传进来的rgbBuf 为比三通道数据长度小,则抛出异常,并打出相应信息
if (rgbBuf.length < frameSize * 3)
throw new IllegalArgumentException("buffer 'rgbBuf' size "
+ rgbBuf.length + " < minimum " + frameSize * 3);
//如果传进来的yuv420sp 为空,则抛出空指针异常
if (yuv420sp == null)
throw new NullPointerException("buffer 'yuv420sp' is null");
//如果传进来的rgbBuf 为比三通道数据长度的一半小,则抛出异常,并打出相应信息
if (yuv420sp.length < frameSize * 3 / 2)
throw new IllegalArgumentException("buffer 'yuv420sp' size "
+ yuv420sp.length+ " < minimum " + frameSize * 3 / 2);
//经过上面的叛断,我们正式进行解码了
int i = 0, y = 0;
int uvp = 0, u = 0, v = 0;
//r g b 三元色初始化
int y1192 = 0, r = 0, g = 0, b = 0;
//下面的两个for循环都只是为了把第一个像素点的的R G B读取出来,就是一行一行循环读取.
for (int j = 0, yp = 0; j < height; j++) {
uvp = frameSize + (j >> 1) * width;
u = 0;
v = 0;
for (i = 0; i < width; i++, yp++) {
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;
}
y1192 = 1192 * y;
r = (y1192 + 1634 * v);
g = (y1192 - 833 * v - 400 * u);
b = (y1192 + 2066 * u);
//始终持 r g b在0 - 262143
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;
//安位运算,分别将一个像素点中的r g b 存贮在rgbBuf中
rgbBuf[yp * 3] = (byte)(r >> 10);
rgbBuf[yp * 3 + 1] = (byte)(g >> 10);
rgbBuf[yp * 3 + 2] = (byte)(b >> 10);
}
}
}
=========================================================
static public void rgb24_to_rgb565(byte[] rgb24,byte[] rgb16,int width,int height){
int i=0,j=0;
for(i=0;i<width*height*3;i+=3)
{
rgb16[j] = (byte)(rgb24[i] >> 3);//B
rgb16[j] |= (byte)(rgb24[i+1] & 0x1C) << 3;//G
rgb16[j+1] = (byte)(rgb24[i+2] & 0xf8); //R
rgb16[j+1]|=(byte)(rgb24[i+1] >> 5); // G
j += 2;
}
}
========================================================================
NV21->NV12
public byte[] convert(byte[] data) {
// A buffer large enough for every case
if (mBuffer==null || mBuffer.length != 3*mSliceHeight*mStride/2+mYPadding) {
mBuffer = new byte[3*mSliceHeight*mStride/2+mYPadding];
}
if (!mPlanar) {
if (mSliceHeight==mHeight && mStride==mWidth) {
// Swaps U and V
if (!mPanesReversed) {
for (int i = mSize; i < mSize+mSize/2; i += 2) {
mBuffer[0] = data[i+1];
data[i+1] = data[i];
data[i] = mBuffer[0];
}
}
if (mYPadding>0) {
System.arraycopy(data, 0, mBuffer, 0, mSize);
System.arraycopy(data, mSize, mBuffer, mSize+mYPadding, mSize/2);
return mBuffer;
}
return data;
}
} else {
if (mSliceHeight==mHeight && mStride==mWidth) {
// De-interleave U and V
if (!mPanesReversed) {
for (int i = 0; i < mSize/4; i+=1) {
mBuffer[i] = data[mSize+2*i+1];
mBuffer[mSize/4+i] = data[mSize+2*i];
}
} else {
for (int i = 0; i < mSize/4; i+=1) {
mBuffer[i] = data[mSize+2*i];
mBuffer[mSize/4+i] = data[mSize+2*i+1];
}
}
if (mYPadding == 0) {
System.arraycopy(mBuffer, 0, data, mSize, mSize/2);
} else {
System.arraycopy(data, 0, mBuffer, 0, mSize);
System.arraycopy(mBuffer, 0, mBuffer, mSize+mYPadding, mSize/2);
return mBuffer;
}
return data;
}
}
return data;
}
===========================================================================
* Converts YUV420 NV21 to ARGB8888
*
* @param data byte array on YUV420 NV21 format.
* @param width pixels width
* @param height pixels height
* @retur a ARGB8888 pixels int array. Where each int is a pixels ARGB.
*/
public static int[] convertYUV420_NV21toARGB8888(byte [] data, int width, int height) {
int size = width*height;
int offset = size;
int[] pixels = new int[size];
int u, v, y1, y2, y3, y4;
// i along Y and the final pixels
// k along pixels U and V
for(int i=0, k=0; i < size; i+=2, k+=1) {
y1 = data[i ]&0xff;
y2 = data[i+1]&0xff;
y3 = data[width+i ]&0xff;
y4 = data[width+i+1]&0xff;
v = data[offset+k ]&0xff;
u = data[offset+k+1]&0xff;
v = v-128;
u = u-128;
pixels[i ] = convertYUVtoARGB(y1, u, v);
pixels[i+1] = convertYUVtoARGB(y2, u, v);
pixels[width+i ] = convertYUVtoARGB(y3, u, v);
pixels[width+i+1] = convertYUVtoARGB(y4, u, v);
if (i!=0 && (i+2)%width==0)
i+=width;
}
return pixels;
}
private static int convertYUVtoARGB(int y, int u, int v) {
int r,g,b;
r = y + (int)(1.402f*u);
g = y - (int)(0.344f*v + 0.714f*u);
b = y + (int)(1.772f*v);
r = r>255? 255 : r<0 ? 0 : r;
g = g>255? 255 : g<0 ? 0 : g;
b = b>255? 255 : b<0 ? 0 : b;
return 0xff000000 | (r<<16) | (g<<8) | b;
}