在Android中显示YUV图像
在我的应用程序中,我们需要将从服务器接收到的视频帧显示到android应用程序,在Android中显示YUV图像,android,image-processing,imageview,yuv,Android,Image Processing,Imageview,Yuv,在我的应用程序中,我们需要将从服务器接收到的视频帧显示到android应用程序, 服务器正在以每秒50帧的速度发送视频数据,已在WebM中编码,即使用libvpx对图像进行编码和解码 现在从libvpx解码后,它得到了YUV数据,我们可以在图像布局上显示 目前的实施是这样的, JNI /本地C++代码,我们将YUV数据转换为RGB数据 在Android框架中,调用 public Bitmap createImgae(byte[] bits, int width, int height, int
服务器正在以每秒50帧的速度发送视频数据,已在WebM中编码,即使用libvpx对图像进行编码和解码 现在从libvpx解码后,它得到了YUV数据,我们可以在图像布局上显示 目前的实施是这样的,
JNI /本地C++代码,我们将YUV数据转换为RGB数据 在Android框架中,调用
public Bitmap createImgae(byte[] bits, int width, int height, int scan) {
Bitmap bitmap=null;
System.out.println("video: creating bitmap");
//try{
bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(ByteBuffer.wrap(bits));
//}catch(OutOfMemoryError ex){
//}
System.out.println("video: bitmap created");
return bitmap;
}
要创建位图图像
要使用以下代码在imageView上显示图像
img = createImgae(imgRaw, imgInfo[0], imgInfo[1], 1);
if(img!=null && !img.isRecycled()){
iv.setImageBitmap(img);
//img.recycle();
img=null;
System.out.println("video: image displayed");
}
我的问题是,总的来说,这个功能大约需要40毫秒,有没有办法对它进行优化,1--是否有任何方法将YUV数据显示到imageView 2--是否有其他方法从RGB数据创建图像(位图图像) 3--我相信我一直在创建图像,但我想我应该只创建一次位图,并在收到时始终提供新的缓冲区。
请分享你的观点 下面的代码解决了您的问题,并且可能需要更少的时间处理Yuv格式的数据,因为YuvImage类是随Android SDK提供的 你可以试试这个
ByteArrayOutputStream out = new ByteArrayOutputStream();
YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, width, height, null);
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 50, out);
byte[] imageBytes = out.toByteArray();
Bitmap image = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
iv.setImageBitmap(image);
或
void yourFunction(字节[]数据,整数mWidth,整数mHeight)
{
int[]mIntArray=新int[mWidth*mHeight];
//将Yuv数据解码为整数数组
decodeYUV420SP(最小数组、数据、最大宽度、最大高度);
//使用替换的颜色初始化位图
位图bmp=Bitmap.createBitmap(mIntArray、mWidth、mHeight、Bitmap.Config.ARGB_8888);
//用替换的颜色绘制位图
iv.设置图像位图(bmp);
}
静态公共无效解码yuv420sp(int[]rgba,字节[]yuv420sp,int-width,
整数高度){
最终整数帧大小=宽度*高度;
对于(int j=0,yp=0;j>1)*宽度,u=0,v=0;
对于(int i=0;i262143)
r=262143;
if(g<0)
g=0;
否则,如果(g>262143)
g=262143;
if(b<0)
b=0;
否则,如果(b>262143)
b=262143;
//rgb[yp]=0xff000000|((r>2)&
//0xff00)|((b>>10)和0xff);
//rgba,除以2^10(>>10)
rgba[yp]=((r2)| 0xff00);
}
}
}
在onCreate中获取宽度和高度后创建位图
在预览框架上的中。
int[] rgbData = decodeGreyscale(aNv21Byte,widthPreview,heightPreview);
editedBitmap.setPixels(rgbData, 0, widthPreview, 0, 0, widthPreview, heightPreview);
和
private int[] decodeGreyscale(byte[] nv21, int width, int height) {
int pixelCount = width * height;
int[] out = new int[pixelCount];
for (int i = 0; i < pixelCount; ++i) {
int luminance = nv21[i] & 0xFF;
// out[i] = Color.argb(0xFF, luminance, luminance, luminance);
out[i] = 0xff000000 | luminance <<16 | luminance <<8 | luminance;//No need to create Color object for each.
}
return out;
}
基于公认的答案,我可以找到一种使用RenderScript intrinsict转换方法进行YUV到RGB转换的更快方法。我在这里找到了直接的例子: 它可以像复制RenderScriptHelper类中的convertYuvToRgbIntrinsic方法一样简单,以替换Hitesh Patel在回答中给出的decodeYUV420SP。此外,还需要初始化RenderScript对象(示例位于MainActivity类中)
别忘了在project graddle中添加渲染脚本的使用(在android页面中,您可以找到执行此操作的方法)。另一种方法是使用,这比每次JPEG压缩时编码(和解码)更有效
fun yuvByteArrayToBitmap(bytes: ByteArray, width: Int, height: Int): Bitmap {
val rs = RenderScript.create(this)
val yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
val yuvType = Type.Builder(rs, Element.U8(rs)).setX(bytes.size);
val input = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);
val rgbaType = Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height);
val output = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
input.copyFrom(bytes);
yuvToRgbIntrinsic.setInput(input);
yuvToRgbIntrinsic.forEach(output);
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
output.copyTo(bitmap)
input.destroy()
output.destroy()
yuvToRgbIntrinsic.destroy()
rs.destroy()
return bitmap
}
bitmap.copyPixelsFromBuffer(ByteBuffer.wrap(位))代码>是否将YUV转换为RGB?或者你是说这就是你在母语中所做的吗?这里有一种方法。我尝试了你的decodeYUV420SP()方法,但是它创建的图像不好。它充满了黄色和绿色的波浪。我做了这一个,它的作品:我不明白为什么rgba[yp]=。。。被移位8位。注释掉的行更正确。我得到了一个旋转的图像。有没有一种无损压缩(即不是JPEG)的方法?也看看我的问题,YuvImage对于这个目的是非常无用的,转换为JPG并返回到RGB每帧对于视频播放来说太慢了,更不用说JPG是有损格式,所以视频看起来会比原始视频更糟。实际上,这回答了一个不同的问题。
private int[] decodeGreyscale(byte[] nv21, int width, int height) {
int pixelCount = width * height;
int[] out = new int[pixelCount];
for (int i = 0; i < pixelCount; ++i) {
int luminance = nv21[i] & 0xFF;
// out[i] = Color.argb(0xFF, luminance, luminance, luminance);
out[i] = 0xff000000 | luminance <<16 | luminance <<8 | luminance;//No need to create Color object for each.
}
return out;
}
if(cameraId==CameraInfo.CAMERA_FACING_FRONT)
{
matrix.setRotate(270F);
}
finalBitmap = Bitmap.createBitmap(editedBitmap, 0, 0, widthPreview, heightPreview, matrix, true);
fun yuvByteArrayToBitmap(bytes: ByteArray, width: Int, height: Int): Bitmap {
val rs = RenderScript.create(this)
val yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
val yuvType = Type.Builder(rs, Element.U8(rs)).setX(bytes.size);
val input = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);
val rgbaType = Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height);
val output = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
input.copyFrom(bytes);
yuvToRgbIntrinsic.setInput(input);
yuvToRgbIntrinsic.forEach(output);
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
output.copyTo(bitmap)
input.destroy()
output.destroy()
yuvToRgbIntrinsic.destroy()
rs.destroy()
return bitmap
}