2012-02-08 68 views
20

在我的应用程序中,我们需要显示视频帧从服务器接收到我们的android应用程序,
服务器正在发送每秒50帧的视频数据,在WebM中编码,即使用libvpx编码和解码图像,在Android中显示YUV图像

现在从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 - 我相信,我总是创造的形象,但我想我应该只有一次创建位图,并做/总是提供新的缓冲区,当我们收到时。
请分享您的观点。

+0

'bitmap.copyPixelsFromBuffer(ByteBuffer.wrap(位));'并从YUV变换为RGB?或者你说这就是你在本地做的事情? – weston 2012-02-08 12:11:10

+0

这是一种方法。检查出http://stackoverflow.com/questions/9192982/displaying-yuv-image-in-android – bob 2012-06-30 20:34:43

回答

30

下面的代码解决了您的问题,因为YuvImage类是随Android-SDK提供的,所以它可能需要更少的时间在Yuv格式数据上。

你可以试试这个,

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(byte[] data, int mWidth, int mHeight) 
{ 

int[] mIntArray = new int[mWidth*mHeight]; 

// Decode Yuv data to integer array 
decodeYUV420SP(mIntArray, data, mWidth, mHeight); 

//Initialize the bitmap, with the replaced color 
Bitmap bmp = Bitmap.createBitmap(mIntArray, mWidth, mHeight, Bitmap.Config.ARGB_8888); 

// Draw the bitmap with the replaced color 
iv.setImageBitmap(bmp); 

} 

static public void decodeYUV420SP(int[] rgba, 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); 
     // rgba, divide 2^10 (>> 10) 
     rgba[yp] = ((r << 14) & 0xff000000) | ((g << 6) & 0xff0000) 
       | ((b >> 2) | 0xff00); 
    } 
} 
} 
+2

我试过你的方法decodeYUV420SP()但它创建的图像不好。它充满了黄色和绿色的波浪。我做了这一个,它的工作原理:http:// stackoverflow。com/questions/5272388/need-help-with-androids-nv21-format/12702836#12702836 – Derzu 2012-10-05 14:24:35

+1

我不明白为什么rgba [yp] = ...被移位了8位。注释掉的线更加正确。我得到一个旋转的图像。 – 2013-04-02 14:15:55

+5

是否有无损压缩(即不是JPEG)的方式? – 2013-08-01 17:48:32

-2

创建越来越宽度和高度的onCreate后的位图。

editedBitmap = Bitmap.createBitmap(widthPreview, heightPreview, 
       android.graphics.Bitmap.Config.ARGB_8888); 

而且在onPreviewFrame.

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; 
} 

和奖金。

if(cameraId==CameraInfo.CAMERA_FACING_FRONT) 
{ 
    matrix.setRotate(270F); 
} 

finalBitmap = Bitmap.createBitmap(editedBitmap, 0, 0, widthPreview, heightPreview, matrix, true);